summaryrefslogtreecommitdiffstats
path: root/contrib/openbsm/bin/auditdistd
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/openbsm/bin/auditdistd')
-rw-r--r--contrib/openbsm/bin/auditdistd/Makefile.am29
-rw-r--r--contrib/openbsm/bin/auditdistd/Makefile.in753
-rw-r--r--contrib/openbsm/bin/auditdistd/auditdistd.8106
-rw-r--r--contrib/openbsm/bin/auditdistd/auditdistd.c798
-rw-r--r--contrib/openbsm/bin/auditdistd/auditdistd.conf.5364
-rw-r--r--contrib/openbsm/bin/auditdistd/auditdistd.h274
-rw-r--r--contrib/openbsm/bin/auditdistd/faccessat.h67
-rw-r--r--contrib/openbsm/bin/auditdistd/fstatat.h67
-rw-r--r--contrib/openbsm/bin/auditdistd/openat.h73
-rw-r--r--contrib/openbsm/bin/auditdistd/parse.y854
-rw-r--r--contrib/openbsm/bin/auditdistd/pjdlog.c619
-rw-r--r--contrib/openbsm/bin/auditdistd/pjdlog.h117
-rw-r--r--contrib/openbsm/bin/auditdistd/proto.c527
-rw-r--r--contrib/openbsm/bin/auditdistd/proto.h61
-rw-r--r--contrib/openbsm/bin/auditdistd/proto_common.c231
-rw-r--r--contrib/openbsm/bin/auditdistd/proto_impl.h82
-rw-r--r--contrib/openbsm/bin/auditdistd/proto_socketpair.c264
-rw-r--r--contrib/openbsm/bin/auditdistd/proto_tcp.c721
-rw-r--r--contrib/openbsm/bin/auditdistd/proto_tls.c1074
-rw-r--r--contrib/openbsm/bin/auditdistd/proto_uds.c360
-rw-r--r--contrib/openbsm/bin/auditdistd/receiver.c712
-rw-r--r--contrib/openbsm/bin/auditdistd/renameat.h66
-rw-r--r--contrib/openbsm/bin/auditdistd/sandbox.c232
-rw-r--r--contrib/openbsm/bin/auditdistd/sandbox.h37
-rw-r--r--contrib/openbsm/bin/auditdistd/sender.c845
-rw-r--r--contrib/openbsm/bin/auditdistd/sigtimedwait.h90
-rw-r--r--contrib/openbsm/bin/auditdistd/strndup.h53
-rw-r--r--contrib/openbsm/bin/auditdistd/subr.c304
-rw-r--r--contrib/openbsm/bin/auditdistd/subr.h58
-rw-r--r--contrib/openbsm/bin/auditdistd/synch.h204
-rw-r--r--contrib/openbsm/bin/auditdistd/token.l82
-rw-r--r--contrib/openbsm/bin/auditdistd/trail.c609
-rw-r--r--contrib/openbsm/bin/auditdistd/trail.h60
-rw-r--r--contrib/openbsm/bin/auditdistd/unlinkat.h66
34 files changed, 10859 insertions, 0 deletions
diff --git a/contrib/openbsm/bin/auditdistd/Makefile.am b/contrib/openbsm/bin/auditdistd/Makefile.am
new file mode 100644
index 0000000..263cb2d
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/Makefile.am
@@ -0,0 +1,29 @@
+if USE_NATIVE_INCLUDES
+INCLUDES = -I$(top_builddir) -I$(top_srcdir)
+else
+INCLUDES = -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/sys
+endif
+
+sbin_PROGRAMS = auditdistd
+man5_MANS = auditdistd.conf.5
+man8_MANS = auditdistd.8
+CFLAGS = -Wno-format
+YFLAGS = -d
+auditdistd_LDFLAGS = -lcrypto
+
+auditdistd_SOURCES = \
+ auditdistd.c \
+ parse.y \
+ pjdlog.c \
+ proto.c \
+ proto_common.c \
+ proto_socketpair.c \
+ proto_tcp.c \
+ proto_tls.c \
+ proto_uds.c \
+ receiver.c \
+ sandbox.c \
+ sender.c \
+ subr.c \
+ token.l \
+ trail.c
diff --git a/contrib/openbsm/bin/auditdistd/Makefile.in b/contrib/openbsm/bin/auditdistd/Makefile.in
new file mode 100644
index 0000000..b6228fd
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/Makefile.in
@@ -0,0 +1,753 @@
+# Makefile.in generated by automake 1.12.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2012 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__make_dryrun = \
+ { \
+ am__dry=no; \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
+ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+ *) \
+ for am__flg in $$MAKEFLAGS; do \
+ case $$am__flg in \
+ *=*|--*) ;; \
+ *n*) am__dry=yes; break;; \
+ esac; \
+ done;; \
+ esac; \
+ test $$am__dry = yes; \
+ }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+sbin_PROGRAMS = auditdistd$(EXEEXT)
+subdir = bin/auditdistd
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/config/depcomp $(top_srcdir)/config/ylwrap \
+ parse.c parse.h token.c
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \
+ "$(DESTDIR)$(man8dir)"
+PROGRAMS = $(sbin_PROGRAMS)
+am_auditdistd_OBJECTS = auditdistd.$(OBJEXT) parse.$(OBJEXT) \
+ pjdlog.$(OBJEXT) proto.$(OBJEXT) proto_common.$(OBJEXT) \
+ proto_socketpair.$(OBJEXT) proto_tcp.$(OBJEXT) \
+ proto_tls.$(OBJEXT) proto_uds.$(OBJEXT) receiver.$(OBJEXT) \
+ sandbox.$(OBJEXT) sender.$(OBJEXT) subr.$(OBJEXT) \
+ token.$(OBJEXT) trail.$(OBJEXT)
+auditdistd_OBJECTS = $(am_auditdistd_OBJECTS)
+auditdistd_LDADD = $(LDADD)
+auditdistd_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(auditdistd_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/config
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ ||
+LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS)
+YLWRAP = $(top_srcdir)/config/ylwrap
+@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ ||
+am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
+ -e s/c++$$/h++/ -e s/c$$/h/
+YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
+SOURCES = $(auditdistd_SOURCES)
+DIST_SOURCES = $(auditdistd_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(man5_MANS) $(man8_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = -Wno-format
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIG = @MIG@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = -d
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+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@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@USE_NATIVE_INCLUDES_FALSE@INCLUDES = -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/sys
+@USE_NATIVE_INCLUDES_TRUE@INCLUDES = -I$(top_builddir) -I$(top_srcdir)
+man5_MANS = auditdistd.conf.5
+man8_MANS = auditdistd.8
+auditdistd_LDFLAGS = -lcrypto
+auditdistd_SOURCES = \
+ auditdistd.c \
+ parse.y \
+ pjdlog.c \
+ proto.c \
+ proto_common.c \
+ proto_socketpair.c \
+ proto_tcp.c \
+ proto_tls.c \
+ proto_uds.c \
+ receiver.c \
+ sandbox.c \
+ sender.c \
+ subr.c \
+ token.l \
+ trail.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign bin/auditdistd/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign bin/auditdistd/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: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+parse.h: parse.c
+ @if test ! -f $@; then rm -f parse.c; else :; fi
+ @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) parse.c; else :; fi
+auditdistd$(EXEEXT): $(auditdistd_OBJECTS) $(auditdistd_DEPENDENCIES) $(EXTRA_auditdistd_DEPENDENCIES)
+ @rm -f auditdistd$(EXEEXT)
+ $(auditdistd_LINK) $(auditdistd_OBJECTS) $(auditdistd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auditdistd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pjdlog.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto_common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto_socketpair.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto_tcp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto_tls.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto_uds.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/receiver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sandbox.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sender.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/token.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trail.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+.l.c:
+ $(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+.y.c:
+ $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man5: $(man5_MANS)
+ @$(NORMAL_INSTALL)
+ @list1='$(man5_MANS)'; \
+ list2=''; \
+ test -n "$(man5dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.5[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man5:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir)
+install-man8: $(man8_MANS)
+ @$(NORMAL_INSTALL)
+ @list1='$(man8_MANS)'; \
+ list2=''; \
+ test -n "$(man8dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.8[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir)
+
+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; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+cscopelist: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @list='$(MANS)'; if test -n "$$list"; then \
+ list=`for p in $$list; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
+ if test -n "$$list" && \
+ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
+ echo "error: found man pages containing the 'missing help2man' replacement text:" >&2; \
+ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \
+ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \
+ echo " typically 'make maintainer-clean' will remove them" >&2; \
+ exit 1; \
+ else :; fi; \
+ else :; fi
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$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)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; 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:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -rm -f parse.c
+ -rm -f parse.h
+ -rm -f token.c
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man5 install-man8
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-man uninstall-sbinPROGRAMS
+
+uninstall-man: uninstall-man5 uninstall-man8
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-sbinPROGRAMS cscopelist ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man5 install-man8 install-pdf install-pdf-am \
+ install-ps install-ps-am install-sbinPROGRAMS 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-man uninstall-man5 \
+ uninstall-man8 uninstall-sbinPROGRAMS
+
+
+# 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/contrib/openbsm/bin/auditdistd/auditdistd.8 b/contrib/openbsm/bin/auditdistd/auditdistd.8
new file mode 100644
index 0000000..71a6575
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/auditdistd.8
@@ -0,0 +1,106 @@
+.\" Copyright (c) 2012 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Pawel Jakub Dawidek under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 5, 2012
+.Dt AUDITDISTD 8
+.Os
+.Sh NAME
+.Nm auditdistd
+.Nd "Audit trail files distribution daemon"
+.Sh SYNOPSIS
+.Nm
+.Op Fl dFhl
+.Op Fl c Ar config
+.Op Fl P Ar pidfile
+.Sh DESCRIPTION
+The
+.Nm
+daemon is responsible for distributing audit trail files over a TCP/IP network in
+a secure and reliable way.
+.Pp
+The
+.Nm
+daemon can be started with the following command line arguments:
+.Bl -tag -width ".Fl P Ar pidfile"
+.It Fl c Ar config
+Specify an alternative location of the configuration file.
+The default location is
+.Pa /etc/security/auditdistd.conf .
+Note: the configuration file may contain passwords.
+Care should be taken to configure proper permissions on this file
+.Li ( eg. 0600 ) .
+.It Fl d
+Print or log debugging information.
+This option can be specified multiple times to raise the verbosity
+level.
+.It Fl F
+Start the
+.Nm
+daemon in the foreground.
+By default
+.Nm
+starts in the background.
+.It Fl h
+Print the
+.Nm
+usage message.
+.It Fl l
+Start in a launchd-friendly mode, ie. do not use
+.Xr daemon 3 .
+.It Fl P Ar pidfile
+Specify an alternative location of a file where main process PID will be
+stored.
+The default location is
+.Pa /var/run/auditdistd.pid .
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/security/auditdistd.conf" -compact
+.It Pa /etc/security/auditdistd.conf
+The configuration file for
+.Nm .
+.It Pa /var/run/auditdistd.pid
+The default location of the
+.Nm
+PID file.
+.El
+.Sh EXIT STATUS
+Exit status is 0 on success, or one of the values described in
+.Xr sysexits 3
+on failure.
+.Sh SEE ALSO
+.Xr sysexits 3 ,
+.Xr audit 4 ,
+.Xr auditdistd.conf 5 ,
+.Xr auditd 8
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Pawel Jakub Dawidek Aq pawel@dawidek.net
+under sponsorship of the FreeBSD Foundation.
diff --git a/contrib/openbsm/bin/auditdistd/auditdistd.c b/contrib/openbsm/bin/auditdistd/auditdistd.c
new file mode 100644
index 0000000..696f048
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/auditdistd.c
@@ -0,0 +1,798 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config/config.h>
+
+#include <sys/param.h>
+#if defined(HAVE_SYS_ENDIAN_H) && defined(HAVE_BSWAP)
+#include <sys/endian.h>
+#else /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include <machine/endian.h>
+#else /* !HAVE_MACHINE_ENDIAN_H */
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#else /* !HAVE_ENDIAN_H */
+#error "No supported endian.h"
+#endif /* !HAVE_ENDIAN_H */
+#endif /* !HAVE_MACHINE_ENDIAN_H */
+#include <compat/endian.h>
+#endif /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
+#include <sys/queue.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <openssl/hmac.h>
+
+#ifndef HAVE_PIDFILE_OPEN
+#include <compat/pidfile.h>
+#endif
+#ifndef HAVE_STRLCPY
+#include <compat/strlcpy.h>
+#endif
+#ifndef HAVE_SIGTIMEDWAIT
+#include "sigtimedwait.h"
+#endif
+
+#include "auditdistd.h"
+#include "pjdlog.h"
+#include "proto.h"
+#include "subr.h"
+#include "synch.h"
+
+/* Path to configuration file. */
+const char *cfgpath = ADIST_CONFIG;
+/* Auditdistd configuration. */
+static struct adist_config *adcfg;
+/* Was SIGINT or SIGTERM signal received? */
+bool sigexit_received = false;
+/* PID file handle. */
+struct pidfh *pfh;
+
+/* How often check for hooks running for too long. */
+#define SIGNALS_CHECK_INTERVAL 5
+
+static void
+usage(void)
+{
+
+ errx(EX_USAGE, "[-dFhl] [-c config] [-P pidfile]");
+}
+
+void
+descriptors_cleanup(struct adist_host *adhost)
+{
+ struct adist_host *adh;
+ struct adist_listen *lst;
+
+ TAILQ_FOREACH(adh, &adcfg->adc_hosts, adh_next) {
+ if (adh == adhost)
+ continue;
+ if (adh->adh_remote != NULL) {
+ proto_close(adh->adh_remote);
+ adh->adh_remote = NULL;
+ }
+ }
+ TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
+ if (lst->adl_conn != NULL)
+ proto_close(lst->adl_conn);
+ }
+ (void)pidfile_close(pfh);
+ pjdlog_fini();
+}
+
+static void
+child_cleanup(struct adist_host *adhost)
+{
+
+ if (adhost->adh_conn != NULL) {
+ PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER);
+ proto_close(adhost->adh_conn);
+ adhost->adh_conn = NULL;
+ }
+ adhost->adh_worker_pid = 0;
+}
+
+static void
+child_exit_log(const char *type, unsigned int pid, int status)
+{
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ pjdlog_debug(1, "%s process exited gracefully (pid=%u).",
+ type, pid);
+ } else if (WIFSIGNALED(status)) {
+ pjdlog_error("%s process killed (pid=%u, signal=%d).",
+ type, pid, WTERMSIG(status));
+ } else {
+ pjdlog_error("%s process exited ungracefully (pid=%u, exitcode=%d).",
+ type, pid, WIFEXITED(status) ? WEXITSTATUS(status) : -1);
+ }
+}
+
+static void
+child_exit(void)
+{
+ struct adist_host *adhost;
+ bool restart;
+ int status;
+ pid_t pid;
+
+ restart = false;
+ while ((pid = wait3(&status, WNOHANG, NULL)) > 0) {
+ /* Find host related to the process that just exited. */
+ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
+ if (pid == adhost->adh_worker_pid)
+ break;
+ }
+ if (adhost == NULL) {
+ child_exit_log("Sandbox", pid, status);
+ } else {
+ if (adhost->adh_role == ADIST_ROLE_SENDER)
+ restart = true;
+ pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
+ role2str(adhost->adh_role));
+ child_exit_log("Worker", pid, status);
+ child_cleanup(adhost);
+ pjdlog_prefix_set("%s", "");
+ }
+ }
+ if (!restart)
+ return;
+ /* We have some sender processes to restart. */
+ sleep(1);
+ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
+ if (adhost->adh_role != ADIST_ROLE_SENDER)
+ continue;
+ if (adhost->adh_worker_pid != 0)
+ continue;
+ pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
+ role2str(adhost->adh_role));
+ pjdlog_info("Restarting sender process.");
+ adist_sender(adcfg, adhost);
+ pjdlog_prefix_set("%s", "");
+ }
+}
+
+/* TODO */
+static void
+adist_reload(void)
+{
+
+ pjdlog_info("Reloading configuration is not yet implemented.");
+}
+
+static void
+terminate_workers(void)
+{
+ struct adist_host *adhost;
+
+ pjdlog_info("Termination signal received, exiting.");
+ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
+ if (adhost->adh_worker_pid == 0)
+ continue;
+ pjdlog_info("Terminating worker process (adhost=%s, role=%s, pid=%u).",
+ adhost->adh_name, role2str(adhost->adh_role),
+ adhost->adh_worker_pid);
+ if (kill(adhost->adh_worker_pid, SIGTERM) == 0)
+ continue;
+ pjdlog_errno(LOG_WARNING,
+ "Unable to send signal to worker process (adhost=%s, role=%s, pid=%u).",
+ adhost->adh_name, role2str(adhost->adh_role),
+ adhost->adh_worker_pid);
+ }
+}
+
+static void
+listen_accept(struct adist_listen *lst)
+{
+ unsigned char rnd[32], hash[32], resp[32];
+ struct adist_host *adhost;
+ struct proto_conn *conn;
+ char adname[ADIST_HOSTSIZE];
+ char laddr[256], raddr[256];
+ char welcome[8];
+ int status, version;
+ pid_t pid;
+
+ proto_local_address(lst->adl_conn, laddr, sizeof(laddr));
+ pjdlog_debug(1, "Accepting connection to %s.", laddr);
+
+ if (proto_accept(lst->adl_conn, &conn) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to accept connection to %s",
+ laddr);
+ return;
+ }
+
+ proto_local_address(conn, laddr, sizeof(laddr));
+ proto_remote_address(conn, raddr, sizeof(raddr));
+ pjdlog_info("Connection from %s to %s.", raddr, laddr);
+
+ /* Error in setting timeout is not critical, but why should it fail? */
+ if (proto_timeout(conn, ADIST_TIMEOUT) < 0)
+ pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");
+
+ /*
+ * Before receiving any data see if remote host is known.
+ */
+ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
+ if (adhost->adh_role != ADIST_ROLE_RECEIVER)
+ continue;
+ if (!proto_address_match(conn, adhost->adh_remoteaddr))
+ continue;
+ break;
+ }
+ if (adhost == NULL) {
+ pjdlog_error("Client %s is not known.", raddr);
+ goto close;
+ }
+ /* Ok, remote host is known. */
+
+ /* Exchange welcome message, which include version number. */
+ bzero(welcome, sizeof(welcome));
+ if (proto_recv(conn, welcome, sizeof(welcome)) == -1) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to receive welcome message from %s",
+ adhost->adh_remoteaddr);
+ goto close;
+ }
+ if (strncmp(welcome, "ADIST", 5) != 0 || !isdigit(welcome[5]) ||
+ !isdigit(welcome[6]) || welcome[7] != '\0') {
+ pjdlog_warning("Invalid welcome message from %s.",
+ adhost->adh_remoteaddr);
+ goto close;
+ }
+
+ version = MIN(ADIST_VERSION, atoi(welcome + 5));
+
+ (void)snprintf(welcome, sizeof(welcome), "ADIST%02d", version);
+ if (proto_send(conn, welcome, sizeof(welcome)) == -1) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to send welcome message to %s",
+ adhost->adh_remoteaddr);
+ goto close;
+ }
+
+ if (proto_recv(conn, adname, sizeof(adhost->adh_name)) < 0) {
+ pjdlog_errno(LOG_ERR, "Unable to receive hostname from %s",
+ raddr);
+ goto close;
+ }
+
+ /* Find host now that we have hostname. */
+ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
+ if (adhost->adh_role != ADIST_ROLE_RECEIVER)
+ continue;
+ if (!proto_address_match(conn, adhost->adh_remoteaddr))
+ continue;
+ if (strcmp(adhost->adh_name, adname) != 0)
+ continue;
+ break;
+ }
+ if (adhost == NULL) {
+ pjdlog_error("No configuration for host %s from address %s.",
+ adname, raddr);
+ goto close;
+ }
+
+ adhost->adh_version = version;
+ pjdlog_debug(1, "Version %d negotiated with %s.", adhost->adh_version,
+ adhost->adh_remoteaddr);
+
+ /* Now that we know host name setup log prefix. */
+ pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
+ role2str(adhost->adh_role));
+
+ if (adist_random(rnd, sizeof(rnd)) == -1) {
+ pjdlog_error("Unable to generate challenge.");
+ goto close;
+ }
+ pjdlog_debug(1, "Challenge generated.");
+
+ if (proto_send(conn, rnd, sizeof(rnd)) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to send challenge to %s",
+ adhost->adh_remoteaddr);
+ goto close;
+ }
+ pjdlog_debug(1, "Challenge sent.");
+
+ if (proto_recv(conn, resp, sizeof(resp)) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to receive response from %s",
+ adhost->adh_remoteaddr);
+ goto close;
+ }
+ pjdlog_debug(1, "Response received.");
+
+ if (HMAC(EVP_sha256(), adhost->adh_password,
+ (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash,
+ NULL) == NULL) {
+ pjdlog_error("Unable to generate hash.");
+ goto close;
+ }
+ pjdlog_debug(1, "Hash generated.");
+
+ if (memcmp(resp, hash, sizeof(hash)) != 0) {
+ pjdlog_error("Invalid response from %s (wrong password?).",
+ adhost->adh_remoteaddr);
+ goto close;
+ }
+ pjdlog_info("Sender authenticated.");
+
+ if (proto_recv(conn, rnd, sizeof(rnd)) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to receive challenge from %s",
+ adhost->adh_remoteaddr);
+ goto close;
+ }
+ pjdlog_debug(1, "Challenge received.");
+
+ if (HMAC(EVP_sha256(), adhost->adh_password,
+ (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash,
+ NULL) == NULL) {
+ pjdlog_error("Unable to generate response.");
+ goto close;
+ }
+ pjdlog_debug(1, "Response generated.");
+
+ if (proto_send(conn, hash, sizeof(hash)) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to send response to %s",
+ adhost->adh_remoteaddr);
+ goto close;
+ }
+ pjdlog_debug(1, "Response sent.");
+
+ if (adhost->adh_worker_pid != 0) {
+ pjdlog_debug(1,
+ "Receiver process exists (pid=%u), stopping it.",
+ (unsigned int)adhost->adh_worker_pid);
+ /* Stop child process. */
+ if (kill(adhost->adh_worker_pid, SIGINT) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to stop worker process (pid=%u)",
+ (unsigned int)adhost->adh_worker_pid);
+ /*
+ * Other than logging the problem we
+ * ignore it - nothing smart to do.
+ */
+ }
+ /* Wait for it to exit. */
+ else if ((pid = waitpid(adhost->adh_worker_pid,
+ &status, 0)) != adhost->adh_worker_pid) {
+ /* We can only log the problem. */
+ pjdlog_errno(LOG_ERR,
+ "Waiting for worker process (pid=%u) failed",
+ (unsigned int)adhost->adh_worker_pid);
+ } else {
+ child_exit_log("Worker", adhost->adh_worker_pid,
+ status);
+ }
+ child_cleanup(adhost);
+ }
+
+ adhost->adh_remote = conn;
+ adist_receiver(adcfg, adhost);
+
+ pjdlog_prefix_set("%s", "");
+ return;
+close:
+ proto_close(conn);
+ pjdlog_prefix_set("%s", "");
+}
+
+static void
+connection_migrate(struct adist_host *adhost)
+{
+ struct proto_conn *conn;
+ int16_t val = 0;
+
+ pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
+ role2str(adhost->adh_role));
+
+ PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER);
+
+ if (proto_recv(adhost->adh_conn, &val, sizeof(val)) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to receive connection command");
+ return;
+ }
+ if (proto_set("tls:fingerprint", adhost->adh_fingerprint) == -1) {
+ val = errno;
+ pjdlog_errno(LOG_WARNING, "Unable to set fingerprint");
+ goto out;
+ }
+ if (proto_connect(adhost->adh_localaddr[0] != '\0' ?
+ adhost->adh_localaddr : NULL,
+ adhost->adh_remoteaddr, -1, &conn) < 0) {
+ val = errno;
+ pjdlog_errno(LOG_WARNING, "Unable to connect to %s",
+ adhost->adh_remoteaddr);
+ goto out;
+ }
+ val = 0;
+out:
+ if (proto_send(adhost->adh_conn, &val, sizeof(val)) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to send reply to connection request");
+ }
+ if (val == 0 && proto_connection_send(adhost->adh_conn, conn) < 0)
+ pjdlog_errno(LOG_WARNING, "Unable to send connection");
+
+ pjdlog_prefix_set("%s", "");
+}
+
+static void
+check_signals(void)
+{
+ struct timespec sigtimeout;
+ sigset_t mask;
+ int signo;
+
+ sigtimeout.tv_sec = 0;
+ sigtimeout.tv_nsec = 0;
+
+ PJDLOG_VERIFY(sigemptyset(&mask) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGCHLD) == 0);
+
+ while ((signo = sigtimedwait(&mask, NULL, &sigtimeout)) != -1) {
+ switch (signo) {
+ case SIGINT:
+ case SIGTERM:
+ sigexit_received = true;
+ terminate_workers();
+ exit(EX_OK);
+ break;
+ case SIGCHLD:
+ child_exit();
+ break;
+ case SIGHUP:
+ adist_reload();
+ break;
+ default:
+ PJDLOG_ABORT("Unexpected signal (%d).", signo);
+ }
+ }
+}
+
+static void
+main_loop(void)
+{
+ struct adist_host *adhost;
+ struct adist_listen *lst;
+ struct timeval seltimeout;
+ int fd, maxfd, ret;
+ fd_set rfds;
+
+ seltimeout.tv_sec = SIGNALS_CHECK_INTERVAL;
+ seltimeout.tv_usec = 0;
+
+ pjdlog_info("Started successfully.");
+
+ for (;;) {
+ check_signals();
+
+ /* Setup descriptors for select(2). */
+ FD_ZERO(&rfds);
+ maxfd = -1;
+ TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
+ if (lst->adl_conn == NULL)
+ continue;
+ fd = proto_descriptor(lst->adl_conn);
+ PJDLOG_ASSERT(fd >= 0);
+ FD_SET(fd, &rfds);
+ maxfd = fd > maxfd ? fd : maxfd;
+ }
+ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
+ if (adhost->adh_role == ADIST_ROLE_SENDER) {
+ /* Only sender workers asks for connections. */
+ PJDLOG_ASSERT(adhost->adh_conn != NULL);
+ fd = proto_descriptor(adhost->adh_conn);
+ PJDLOG_ASSERT(fd >= 0);
+ FD_SET(fd, &rfds);
+ maxfd = fd > maxfd ? fd : maxfd;
+ } else {
+ PJDLOG_ASSERT(adhost->adh_conn == NULL);
+ }
+ }
+
+ PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE);
+ ret = select(maxfd + 1, &rfds, NULL, NULL, &seltimeout);
+ if (ret == 0) {
+ /*
+ * select(2) timed out, so there should be no
+ * descriptors to check.
+ */
+ continue;
+ } else if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(EX_OSERR, "select() failed");
+ }
+ PJDLOG_ASSERT(ret > 0);
+
+ /*
+ * Check for signals before we do anything to update our
+ * info about terminated workers in the meantime.
+ */
+ check_signals();
+
+ TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
+ if (lst->adl_conn == NULL)
+ continue;
+ if (FD_ISSET(proto_descriptor(lst->adl_conn), &rfds))
+ listen_accept(lst);
+ }
+ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
+ if (adhost->adh_role == ADIST_ROLE_SENDER) {
+ PJDLOG_ASSERT(adhost->adh_conn != NULL);
+ if (FD_ISSET(proto_descriptor(adhost->adh_conn),
+ &rfds)) {
+ connection_migrate(adhost);
+ }
+ } else {
+ PJDLOG_ASSERT(adhost->adh_conn == NULL);
+ }
+ }
+ }
+}
+
+static void
+adist_config_dump(struct adist_config *cfg)
+{
+ struct adist_host *adhost;
+ struct adist_listen *lst;
+
+ pjdlog_debug(2, "Configuration:");
+ pjdlog_debug(2, " Global:");
+ pjdlog_debug(2, " pidfile: %s", cfg->adc_pidfile);
+ pjdlog_debug(2, " timeout: %d", cfg->adc_timeout);
+ if (TAILQ_EMPTY(&cfg->adc_listen)) {
+ pjdlog_debug(2, " Sender only, not listening.");
+ } else {
+ pjdlog_debug(2, " Listening on:");
+ TAILQ_FOREACH(lst, &cfg->adc_listen, adl_next) {
+ pjdlog_debug(2, " listen: %s", lst->adl_addr);
+ pjdlog_debug(2, " conn: %p", lst->adl_conn);
+ }
+ }
+ pjdlog_debug(2, " Hosts:");
+ TAILQ_FOREACH(adhost, &cfg->adc_hosts, adh_next) {
+ pjdlog_debug(2, " name: %s", adhost->adh_name);
+ pjdlog_debug(2, " role: %s", role2str(adhost->adh_role));
+ pjdlog_debug(2, " version: %d", adhost->adh_version);
+ pjdlog_debug(2, " localaddr: %s", adhost->adh_localaddr);
+ pjdlog_debug(2, " remoteaddr: %s", adhost->adh_remoteaddr);
+ pjdlog_debug(2, " remote: %p", adhost->adh_remote);
+ pjdlog_debug(2, " directory: %s", adhost->adh_directory);
+ pjdlog_debug(2, " compression: %d", adhost->adh_compression);
+ pjdlog_debug(2, " checksum: %d", adhost->adh_checksum);
+ pjdlog_debug(2, " pid: %ld", (long)adhost->adh_worker_pid);
+ pjdlog_debug(2, " conn: %p", adhost->adh_conn);
+ }
+}
+
+static void
+dummy_sighandler(int sig __unused)
+{
+ /* Nothing to do. */
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct adist_host *adhost;
+ struct adist_listen *lst;
+ const char *execpath, *pidfile;
+ bool foreground, launchd;
+ pid_t otherpid;
+ int debuglevel;
+ sigset_t mask;
+
+ execpath = argv[0];
+ if (execpath[0] != '/') {
+ errx(EX_USAGE,
+ "auditdistd requires execution with an absolute path.");
+ }
+
+ /*
+ * We are executed from proto to create sandbox.
+ */
+ if (argc > 1 && strcmp(argv[1], "proto") == 0) {
+ argc -= 2;
+ argv += 2;
+ if (proto_exec(argc, argv) == -1)
+ err(EX_USAGE, "Unable to execute proto");
+ }
+
+ foreground = false;
+ debuglevel = 0;
+ launchd = false;
+ pidfile = NULL;
+
+ for (;;) {
+ int ch;
+
+ ch = getopt(argc, argv, "c:dFhlP:");
+ if (ch == -1)
+ break;
+ switch (ch) {
+ case 'c':
+ cfgpath = optarg;
+ break;
+ case 'd':
+ debuglevel++;
+ break;
+ case 'F':
+ foreground = true;
+ break;
+ case 'l':
+ launchd = true;
+ break;
+ case 'P':
+ pidfile = optarg;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ pjdlog_init(PJDLOG_MODE_STD);
+ pjdlog_debug_set(debuglevel);
+
+ if (proto_set("execpath", execpath) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "Unable to set executable name");
+ if (proto_set("user", ADIST_USER) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "Unable to set proto user");
+ if (proto_set("tcp:port", ADIST_TCP_PORT) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "Unable to set default TCP port");
+
+ /*
+ * When path to the configuration file is relative, obtain full path,
+ * so we can always find the file, even after daemonizing and changing
+ * working directory to /.
+ */
+ if (cfgpath[0] != '/') {
+ const char *newcfgpath;
+
+ newcfgpath = realpath(cfgpath, NULL);
+ if (newcfgpath == NULL) {
+ pjdlog_exit(EX_CONFIG,
+ "Unable to obtain full path of %s", cfgpath);
+ }
+ cfgpath = newcfgpath;
+ }
+
+ adcfg = yy_config_parse(cfgpath, true);
+ PJDLOG_ASSERT(adcfg != NULL);
+ adist_config_dump(adcfg);
+
+ if (proto_set("tls:certfile", adcfg->adc_certfile) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "Unable to set certfile path");
+ if (proto_set("tls:keyfile", adcfg->adc_keyfile) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "Unable to set keyfile path");
+
+ if (pidfile != NULL) {
+ if (strlcpy(adcfg->adc_pidfile, pidfile,
+ sizeof(adcfg->adc_pidfile)) >=
+ sizeof(adcfg->adc_pidfile)) {
+ pjdlog_exitx(EX_CONFIG, "Pidfile path is too long.");
+ }
+ }
+ if (foreground && pidfile == NULL) {
+ pfh = NULL;
+ } else {
+ pfh = pidfile_open(adcfg->adc_pidfile, 0600, &otherpid);
+ if (pfh == NULL) {
+ if (errno == EEXIST) {
+ pjdlog_exitx(EX_TEMPFAIL,
+ "Another auditdistd is already running, pid: %jd.",
+ (intmax_t)otherpid);
+ }
+ /*
+ * If we cannot create pidfile from other reasons,
+ * only warn.
+ */
+ pjdlog_errno(LOG_WARNING,
+ "Unable to open or create pidfile %s",
+ adcfg->adc_pidfile);
+ }
+ }
+
+ /*
+ * Restore default actions for interesting signals in case parent
+ * process (like init(8)) decided to ignore some of them (like SIGHUP).
+ */
+ PJDLOG_VERIFY(signal(SIGHUP, SIG_DFL) != SIG_ERR);
+ PJDLOG_VERIFY(signal(SIGINT, SIG_DFL) != SIG_ERR);
+ PJDLOG_VERIFY(signal(SIGTERM, SIG_DFL) != SIG_ERR);
+ /*
+ * Because SIGCHLD is ignored by default, setup dummy handler for it,
+ * so we can mask it.
+ */
+ PJDLOG_VERIFY(signal(SIGCHLD, dummy_sighandler) != SIG_ERR);
+
+ PJDLOG_VERIFY(sigemptyset(&mask) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGCHLD) == 0);
+ PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
+
+ /* Listen for remote connections. */
+ TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
+ if (proto_server(lst->adl_addr, &lst->adl_conn) == -1) {
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(EX_OSERR, "Unable to listen on address %s",
+ lst->adl_addr);
+ }
+ }
+
+ if (!foreground) {
+ if (!launchd && daemon(0, 0) == -1) {
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(EX_OSERR, "Unable to daemonize");
+ }
+
+ /* Start logging to syslog. */
+ pjdlog_mode_set(PJDLOG_MODE_SYSLOG);
+ }
+ if (pfh != NULL) {
+ /* Write PID to a file. */
+ if (pidfile_write(pfh) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to write PID to a file");
+ }
+ }
+
+ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
+ if (adhost->adh_role == ADIST_ROLE_SENDER)
+ adist_sender(adcfg, adhost);
+ }
+
+ main_loop();
+
+ exit(0);
+}
diff --git a/contrib/openbsm/bin/auditdistd/auditdistd.conf.5 b/contrib/openbsm/bin/auditdistd/auditdistd.conf.5
new file mode 100644
index 0000000..c6ed2b5
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/auditdistd.conf.5
@@ -0,0 +1,364 @@
+.\" Copyright (c) 2012 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Pawel Jakub Dawidek under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 1, 2015
+.Dt AUDITDISTD.CONF 5
+.Os
+.Sh NAME
+.Nm auditdistd.conf
+.Nd configuration file for the
+.Xr auditdistd 8
+daemon.
+.Sh DESCRIPTION
+Note: the configuration file may contain passwords.
+Care should be taken to configure proper permissions for this file
+.Li ( e.g., 0600 ) .
+.Pp
+Every line starting with
+.Li #
+gets treated as a comment and is ignored.
+.Sh CONFIGURATION FILE SYNTAX
+The general syntax of the
+.Nm
+file is as follows:
+.Bd -literal
+## Global section.
+
+# Our name.
+# The default is the first part of the hostname.
+name "<name>"
+
+# Connection timeout.
+# The default is 5.
+timeout <seconds>
+
+# Path to pidfile.
+# The default is "/var/run/auditdistd.pid".
+pidfile "<path>"
+
+sender {
+ ## Sender section.
+
+ # Source address for connections.
+ # Optional.
+ source "<addr>"
+
+ # Directory with audit trail files managed by auditdistd.
+ # The default is /var/audit/dist.
+ directory "<dir>"
+.\"
+.\" # Checksum algorithm for data sent over the wire.
+.\" # The default is none.
+.\" checksum "<algorithm>"
+.\"
+.\" # Compression algorithm for data sent over the wire.
+.\" # The default is none.
+.\" compression "<algorithm>"
+
+ # Configuration for the target system we want to send audit trail
+ # files to.
+ host "<name>" {
+ # Source address for connections.
+ # Optional.
+ source "<addr>"
+
+ # Address of the auditdistd receiver.
+ # No default. Obligatory.
+ remote "<addr>"
+
+ # Directory with audit trail files managed by auditdistd.
+ # The default is /var/audit/dist.
+ directory "<dir>"
+
+ # Fingerprint of the receiver's public key when using TLS
+ # for connections.
+ # Example fingerprint:
+ # SHA256=8F:0A:FC:8A:3D:09:80:AF:D9:AA:38:CC:8A:86:53:E6:8F:B6:1C:55:30:14:D7:F9:AA:8B:3E:73:CD:F5:76:2B
+ fingerprint "<algorithm=hash>"
+
+ # Password used to authenticate in front of the receiver.
+ password "<password>"
+.\"
+.\" # Checksum algorithm for data sent over the wire.
+.\" # The default is none.
+.\" checksum "<algorithm>"
+.\"
+.\" # Compression algorithm for data sent over the wire.
+.\" # The default is none.
+.\" compression "<algorithm>"
+ }
+
+ # Currently local audit trail files can be sent only to one remote
+ # auditdistd receiver, but this can change in the future.
+}
+
+receiver {
+ ## Receiver section.
+
+ # Address to listen on. Multiple listen addresses may be specified.
+ # The defaults are "tcp4://0.0.0.0:7878" and "tcp6://[::]:7878".
+ listen "<addr>"
+
+ # Base directory.
+ # If the directory in the host section is not absolute, it will be
+ # concatenated with this base directory.
+ # The default is "/var/audit/remote".
+ directory "<basedir>"
+
+ # Path to the receiver's certificate file.
+ # The default is "/etc/security/auditdistd.cert.pem".
+ certfile "<path>"
+
+ # Path to the receiver's private key file.
+ # The default is "/etc/security/auditdistd.key.pem".
+ keyfile "<path>"
+
+ # Configuration for a source system we want to receive audit trail
+ # files from.
+ host "<name>" {
+ # Sender address.
+ # No default. Obligatory.
+ remote "<addr>"
+
+ # Directory where to store audit trail files received
+ # from system <name>.
+ # The default is "<basedir>/<name>".
+ directory "<dir>"
+
+ # Password used by the sender to authenticate.
+ password "<password>"
+ }
+
+ # Multiple hosts to receive from can be configured.
+}
+.Ed
+.Pp
+Most of the various available configuration parameters are optional.
+If a parameter is not defined in the particular section, it will be
+inherited from the parent section if possible.
+For example, if the
+.Ic source
+parameter is not defined in the
+.Ic host
+section, it will be inherited from the
+.Ic sender
+section.
+In case the
+.Ic global
+section does not define the
+.Ic source
+parameter at all, the default value will be used.
+.Sh CONFIGURATION OPTION DESCRIPTION
+The following statements are available:
+.Bl -tag -width ".Ic xxxx"
+.It Ic name Aq name
+.Pp
+This host's name.
+It is sent to the receiver, so it can properly recognize us if there are
+multiple senders coming from the same IP address.
+.It Ic timeout Aq seconds
+.Pp
+Connection timeout in seconds.
+The default value is
+.Va 5 .
+.It Ic pidfile Aq path
+.Pp
+File in which to store the process ID of the main
+.Xr auditdistd 8
+process.
+.Pp
+The default value is
+.Pa /var/run/auditdistd.pid .
+.It Ic source Aq addr
+.Pp
+Local address to bind to before connecting to the remote
+.Nm auditdistd
+daemon.
+The format is the same as for the
+.Ic listen
+statement.
+.It Ic directory Aq path
+.Pp
+The directory where to look for audit trail files in case of sender mode, or
+the directory where to store received audit trail files.
+The provided path has to be an absolute path.
+The only exception is when the directory is provided in the
+.Ic receiver
+section; then the path provided in the
+.Ic host
+subsections can be relative to the directory in the
+.Ic receiver
+section.
+The default value is
+.Pa /var/audit/dist
+for the entire
+.Ic sender
+section,
+.Pa /var/audit/remote
+for the non-host
+.Ic receiver
+section and
+.Pa /var/audit/remote/<name>
+for the
+.Ic host
+subsections in the
+.Ic receiver
+section where
+.Aq name
+is the host's name.
+.\".It Ic checksum Aq algorithm
+.\".Pp
+.\"Checksum algorithm should be one of the following:
+.\".Bl -tag -width ".Ic sha256"
+.\".It Ic none
+.\"No checksum will be calculated for the data being sent over the network.
+.\"This is the default setting.
+.\".It Ic crc32
+.\"CRC32 checksum will be calculated.
+.\".It Ic sha256
+.\"SHA256 checksum will be calculated.
+.\".El
+.\".It Ic compression Aq algorithm
+.\".Pp
+.\"Compression algorithm should be one of the following:
+.\".Bl -tag -width ".Ic none"
+.\".It Ic none
+.\"Data sent over the network will not be compressed.
+.\"This is the default setting.
+.\".It Ic lzf
+.\"The
+.\".Nm LZF
+.\"algorithm by
+.\".An Marc Alexander Lehmann
+.\"will be used to compress the data sent over the network.
+.\".Nm LZF
+.\"is a very fast, general purpose compression algorithm.
+.\".El
+.It Ic remote Aq addr
+.Pp
+Address of the remote
+.Nm auditdistd
+daemon.
+The format is the same as for the
+.Ic listen
+statement.
+When operating in
+.Ic sender
+mode this address will be used to connect to the
+.Ic receiver .
+When operating in
+.Ic receiver
+mode only connections from this address will be accepted.
+.It Ic listen Aq addr
+.Pp
+Address to listen on in form of:
+.Bd -literal -offset indent
+protocol://protocol-specific-address
+.Ed
+.Pp
+Each of the following examples defines the same listen address:
+.Bd -literal -offset indent
+0.0.0.0
+0.0.0.0:7878
+tcp://0.0.0.0
+tcp://0.0.0.0:7878
+tcp4://0.0.0.0
+tcp4://0.0.0.0:7878
+.Ed
+.Pp
+Multiple listen addresses can be specified.
+By default
+.Nm auditdistd
+listens on
+.Pa tcp4://0.0.0.0:7878
+and
+.Pa tcp6://[::]:7878 ,
+if the kernel supports IPv4 and IPv6 respectively.
+.It Ic keyfile Aq path
+.Pp
+Path to a file that contains the private key for TLS communication.
+.It Ic certfile Aq path
+.Pp
+Path to a file that contains the certificate for TLS communication.
+.It Ic fingerprint Aq algo=hash
+.Pp
+Fingerprint of the receiver's public key.
+Currently only the SHA256 algorithm is supported.
+The certificate public key's fingerprint ready to be pasted into the
+.Nm auditdistd
+configuration file can be obtained by running:
+.Bd -literal
+# openssl x509 -in /etc/security/auditdistd.cert.pem -noout -fingerprint -sha256 | awk -F '[ =]' '{printf("%s=%s\\n", $1, $3)}'
+.Ed
+.It Ic password Aq password
+.Pp
+Password used to authenticate the sender in front of the receiver.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/security/auditdistd.conf" -compact
+.It Pa /etc/security/auditdistd.conf
+The default
+.Nm auditdistd
+configuration file.
+.El
+.Sh EXAMPLES
+The example configuration files can look as follows.
+.Pp
+Web server:
+.Bd -literal -offset indent
+sender {
+ host backup {
+ remote 10.0.0.4
+ }
+}
+.Ed
+.Pp
+Audit backup server:
+.Bd -literal -offset indent
+receiver {
+ host webserv {
+ remote 10.0.0.1
+ }
+ host mailserv {
+ remote 10.0.0.2
+ }
+ host dnsserv {
+ remote 10.0.0.3
+ }
+}
+.Ed
+.Sh SEE ALSO
+.Xr audit 4 ,
+.Xr auditdistd 8
+.Sh AUTHORS
+The
+.Nm auditdistd
+daemon was developed by
+.An Pawel Jakub Dawidek Aq pawel@dawidek.net
+under sponsorship of the FreeBSD Foundation.
diff --git a/contrib/openbsm/bin/auditdistd/auditdistd.h b/contrib/openbsm/bin/auditdistd/auditdistd.h
new file mode 100644
index 0000000..d0594f2
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/auditdistd.h
@@ -0,0 +1,274 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _AUDITDISTD_H_
+#define _AUDITDISTD_H_
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+
+#include <dirent.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <compat/compat.h>
+
+#include "proto.h"
+
+/*
+ * Version history:
+ * 0 - initial version
+ */
+#define ADIST_VERSION 0
+
+#define ADIST_ROLE_UNDEF 0
+#define ADIST_ROLE_SENDER 1
+#define ADIST_ROLE_RECEIVER 2
+
+#define ADIST_USER "auditdistd"
+#define ADIST_TIMEOUT 20
+#define ADIST_CONFIG "/etc/security/auditdistd.conf"
+#define ADIST_TCP_PORT "7878"
+#define ADIST_LISTEN_TLS_TCP4 "tls://0.0.0.0:" ADIST_TCP_PORT
+#define ADIST_LISTEN_TLS_TCP6 "tls://[::]:" ADIST_TCP_PORT
+#define ADIST_PIDFILE "/var/run/auditdistd.pid"
+#define ADIST_DIRECTORY_SENDER "/var/audit/dist"
+#define ADIST_DIRECTORY_RECEIVER "/var/audit/remote"
+#define ADIST_CERTFILE "/etc/security/auditdistd.cert.pem"
+#define ADIST_KEYFILE "/etc/security/auditdistd.key.pem"
+
+#define ADIST_ERROR_WRONG_ORDER 1
+#define ADIST_ERROR_INVALID_NAME 2
+#define ADIST_ERROR_OPEN_OLD 3
+#define ADIST_ERROR_CREATE 4
+#define ADIST_ERROR_OPEN 5
+#define ADIST_ERROR_READ 6
+#define ADIST_ERROR_WRITE 7
+#define ADIST_ERROR_RENAME 8
+
+#define ADIST_ADDRSIZE 1024
+#define ADIST_HOSTSIZE 256
+#define ADIST_PATHSIZE 256
+#define ADIST_PASSWORDSIZE 128
+#define ADIST_FINGERPRINTSIZE 256
+
+/* Number of seconds to sleep between reconnect retries or keepalive packets. */
+#define ADIST_KEEPALIVE 10
+
+struct adist_listen {
+ /* Address to listen on. */
+ char adl_addr[ADIST_ADDRSIZE];
+ /* Protocol-specific data. */
+ struct proto_conn *adl_conn;
+ TAILQ_ENTRY(adist_listen) adl_next;
+};
+
+struct adist_config {
+ /* Our name. */
+ char adc_name[ADIST_HOSTSIZE];
+ /* PID file path. */
+ char adc_pidfile[PATH_MAX];
+ /* Connection timeout. */
+ int adc_timeout;
+ /* Path to receiver's certificate file. */
+ char adc_certfile[PATH_MAX];
+ /* Path to receiver's private key file. */
+ char adc_keyfile[PATH_MAX];
+ /* List of addresses to listen on. */
+ TAILQ_HEAD(, adist_listen) adc_listen;
+ /* List of hosts. */
+ TAILQ_HEAD(, adist_host) adc_hosts;
+};
+
+#define ADIST_COMPRESSION_NONE 0
+#define ADIST_COMPRESSION_LZF 1
+
+#define ADIST_CHECKSUM_NONE 0
+#define ADIST_CHECKSUM_CRC32 1
+#define ADIST_CHECKSUM_SHA256 2
+
+/*
+ * Structure that describes single host (either sender or receiver).
+ */
+struct adist_host {
+ /* Host name. */
+ char adh_name[ADIST_HOSTSIZE];
+ /* Host role: ADIST_ROLE_{SENDER,RECEIVER}. */
+ int adh_role;
+ /* Protocol version negotiated. */
+ int adh_version;
+
+ /* Local address to bind to. */
+ char adh_localaddr[ADIST_ADDRSIZE];
+ /* Address of the remote component. */
+ char adh_remoteaddr[ADIST_ADDRSIZE];
+ /* Connection with remote host. */
+ struct proto_conn *adh_remote;
+ /* Connection was reestablished, reset the state. */
+ bool adh_reset;
+
+ /*
+ * Directory from which audit trail files should be send in
+ * ADIST_ROLE_SENDER case or stored into in ADIST_ROLE_RECEIVER case.
+ */
+ char adh_directory[PATH_MAX];
+ /* Compression algorithm. Currently unused. */
+ int adh_compression;
+ /* Checksum algorithm. Currently unused. */
+ int adh_checksum;
+
+ /* Sender's password. */
+ char adh_password[ADIST_PASSWORDSIZE];
+ /* Fingerprint of receiver's public key. */
+ char adh_fingerprint[ADIST_FINGERPRINTSIZE];
+
+ /* PID of child worker process. 0 - no child. */
+ pid_t adh_worker_pid;
+ /* Connection requests from sender to main. */
+ struct proto_conn *adh_conn;
+
+ /* Receiver-specific fields. */
+ char adh_trail_name[ADIST_PATHSIZE];
+ int adh_trail_fd;
+ int adh_trail_dirfd;
+ DIR *adh_trail_dirfp;
+ /* Sender-specific fields. */
+ uint64_t adh_trail_offset;
+
+ /* Next resource. */
+ TAILQ_ENTRY(adist_host) adh_next;
+};
+
+#define ADIST_BYTEORDER_UNDEFINED 0
+#define ADIST_BYTEORDER_LITTLE_ENDIAN 1
+#define ADIST_BYTEORDER_BIG_ENDIAN 2
+
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#define ADIST_BYTEORDER ADIST_BYTEORDER_LITTLE_ENDIAN
+#elif _BYTE_ORDER == _BIG_ENDIAN
+#define ADIST_BYTEORDER ADIST_BYTEORDER_BIG_ENDIAN
+#else
+#error Unknown byte order.
+#endif
+
+struct adpkt {
+ uint8_t adp_byteorder;
+#define ADIST_CMD_UNDEFINED 0
+#define ADIST_CMD_OPEN 1
+#define ADIST_CMD_APPEND 2
+#define ADIST_CMD_CLOSE 3
+#define ADIST_CMD_KEEPALIVE 4
+#define ADIST_CMD_ERROR 5
+ uint8_t adp_cmd;
+ uint64_t adp_seq;
+ uint32_t adp_datasize;
+ unsigned char adp_data[0];
+} __packed;
+
+struct adreq {
+ int adr_error;
+ TAILQ_ENTRY(adreq) adr_next;
+ struct adpkt adr_packet;
+};
+
+#define adr_byteorder adr_packet.adp_byteorder
+#define adr_cmd adr_packet.adp_cmd
+#define adr_seq adr_packet.adp_seq
+#define adr_datasize adr_packet.adp_datasize
+#define adr_data adr_packet.adp_data
+
+#define ADPKT_SIZE(adreq) (sizeof((adreq)->adr_packet) + (adreq)->adr_datasize)
+
+struct adrep {
+ uint8_t adrp_byteorder;
+ uint64_t adrp_seq;
+ uint16_t adrp_error;
+} __packed;
+
+#define ADIST_QUEUE_SIZE 16
+#define ADIST_BUF_SIZE 65536
+
+#define QUEUE_TAKE(adreq, list, timeout) do { \
+ mtx_lock(list##_lock); \
+ if ((timeout) == 0) { \
+ while (((adreq) = TAILQ_FIRST(list)) == NULL) \
+ cv_wait(list##_cond, list##_lock); \
+ } else { \
+ (adreq) = TAILQ_FIRST(list); \
+ if ((adreq) == NULL) { \
+ cv_timedwait(list##_cond, list##_lock, \
+ (timeout)); \
+ (adreq) = TAILQ_FIRST(list); \
+ } \
+ } \
+ if ((adreq) != NULL) \
+ TAILQ_REMOVE((list), (adreq), adr_next); \
+ mtx_unlock(list##_lock); \
+} while (0)
+#define QUEUE_INSERT(adreq, list) do { \
+ bool _wakeup; \
+ \
+ mtx_lock(list##_lock); \
+ _wakeup = TAILQ_EMPTY(list); \
+ TAILQ_INSERT_TAIL((list), (adreq), adr_next); \
+ mtx_unlock(list##_lock); \
+ if (_wakeup) \
+ cv_signal(list##_cond); \
+} while (0)
+#define QUEUE_WAIT(list) do { \
+ mtx_lock(list##_lock); \
+ while (TAILQ_EMPTY(list)) \
+ cv_wait(list##_cond, list##_lock); \
+ mtx_unlock(list##_lock); \
+} while (0)
+
+extern const char *cfgpath;
+extern bool sigexit_received;
+extern struct pidfh *pfh;
+
+void descriptors_cleanup(struct adist_host *adhost);
+void descriptors_assert(const struct adist_host *adhost, int pjdlogmode);
+
+void adist_sender(struct adist_config *config, struct adist_host *adhost);
+void adist_receiver(struct adist_config *config, struct adist_host *adhost);
+
+struct adist_config *yy_config_parse(const char *config, bool exitonerror);
+void yy_config_free(struct adist_config *config);
+
+void yyerror(const char *);
+int yylex(void);
+
+#endif /* !_AUDITDISTD_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/faccessat.h b/contrib/openbsm/bin/auditdistd/faccessat.h
new file mode 100644
index 0000000..568a6b7
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/faccessat.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _FACCESSAT_H_
+#define _FACCESSAT_H_
+
+#include <unistd.h>
+
+#define AT_EACCESS 0x01
+
+static int
+faccessat(int fd, const char *path, int mode, int flag)
+{
+ int cfd, error, ret;
+
+ if (flag == AT_EACCESS) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ cfd = open(".", O_RDONLY | O_DIRECTORY);
+ if (cfd == -1)
+ return (-1);
+
+ if (fchdir(fd) == -1) {
+ error = errno;
+ (void)close(cfd);
+ errno = error;
+ return (-1);
+ }
+
+ ret = access(path, mode);
+
+ error = errno;
+ (void)fchdir(cfd);
+ (void)close(cfd);
+ errno = error;
+ return (ret);
+}
+
+#endif /* !_FACCESSAT_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/fstatat.h b/contrib/openbsm/bin/auditdistd/fstatat.h
new file mode 100644
index 0000000..5327a7c
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/fstatat.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _FSTATAT_H_
+#define _FSTATAT_H_
+
+#include <sys/stat.h>
+
+#include <unistd.h>
+
+#define AT_SYMLINK_NOFOLLOW 0x01
+
+static int
+fstatat(int fd, const char *path, struct stat *buf, int flag)
+{
+ int cfd, error, ret;
+
+ cfd = open(".", O_RDONLY | O_DIRECTORY);
+ if (cfd == -1)
+ return (-1);
+
+ if (fchdir(fd) == -1) {
+ error = errno;
+ (void)close(cfd);
+ errno = error;
+ return (-1);
+ }
+
+ if (flag == AT_SYMLINK_NOFOLLOW)
+ ret = lstat(path, buf);
+ else
+ ret = stat(path, buf);
+
+ error = errno;
+ (void)fchdir(cfd);
+ (void)close(cfd);
+ errno = error;
+ return (ret);
+}
+
+#endif /* !_FSTATAT_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/openat.h b/contrib/openbsm/bin/auditdistd/openat.h
new file mode 100644
index 0000000..1d98014
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/openat.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _OPENAT_H_
+#define _OPENAT_H_
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+static int
+openat(int fd, const char *path, int flags, ...)
+{
+ int cfd, ffd, error;
+
+ cfd = open(".", O_RDONLY | O_DIRECTORY);
+ if (cfd == -1)
+ return (-1);
+
+ if (fchdir(fd) == -1) {
+ error = errno;
+ (void)close(cfd);
+ errno = error;
+ return (-1);
+ }
+
+ if ((flags & O_CREAT) != 0) {
+ va_list ap;
+ int mode;
+
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+
+ ffd = open(path, flags, mode);
+ } else {
+ ffd = open(path, flags);
+ }
+
+ error = errno;
+ (void)fchdir(cfd);
+ (void)close(cfd);
+ errno = error;
+ return (ffd);
+}
+
+#endif /* !_OPENAT_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/parse.y b/contrib/openbsm/bin/auditdistd/parse.y
new file mode 100644
index 0000000..1f80d50
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/parse.y
@@ -0,0 +1,854 @@
+%{
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config/config.h>
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#ifndef HAVE_STRLCPY
+#include <compat/strlcpy.h>
+#endif
+
+#include "auditdistd.h"
+#include "pjdlog.h"
+
+extern int depth;
+extern int lineno;
+
+extern FILE *yyin;
+extern char *yytext;
+
+static struct adist_config *lconfig;
+static struct adist_host *curhost;
+#define SECTION_GLOBAL 0
+#define SECTION_SENDER 1
+#define SECTION_RECEIVER 2
+static int cursection;
+
+/* Sender section. */
+static char depth1_source[ADIST_ADDRSIZE];
+static int depth1_checksum;
+static int depth1_compression;
+/* Sender and receiver sections. */
+static char depth1_directory[PATH_MAX];
+
+static bool adjust_directory(char *path);
+static bool family_supported(int family);
+
+extern void yyrestart(FILE *);
+%}
+
+%token CB
+%token CERTFILE
+%token DIRECTORY
+%token FINGERPRINT
+%token HOST
+%token KEYFILE
+%token LISTEN
+%token NAME
+%token OB
+%token PASSWORD
+%token PIDFILE
+%token RECEIVER REMOTE
+%token SENDER SOURCE
+%token TIMEOUT
+
+/*
+%type <num> checksum_type
+%type <num> compression_type
+*/
+
+%union
+{
+ int num;
+ char *str;
+}
+
+%token <num> NUM
+%token <str> STR
+
+%%
+
+statements:
+ |
+ statements statement
+ ;
+
+statement:
+ name_statement
+ |
+ pidfile_statement
+ |
+ timeout_statement
+ |
+ sender_statement
+ |
+ receiver_statement
+ ;
+
+name_statement: NAME STR
+ {
+ PJDLOG_RASSERT(depth == 0,
+ "The name variable can only be specificed in the global section.");
+
+ if (lconfig->adc_name[0] != '\0') {
+ pjdlog_error("The name variable is specified twice.");
+ free($2);
+ return (1);
+ }
+ if (strlcpy(lconfig->adc_name, $2,
+ sizeof(lconfig->adc_name)) >=
+ sizeof(lconfig->adc_name)) {
+ pjdlog_error("The name value is too long.");
+ free($2);
+ return (1);
+ }
+ free($2);
+ }
+ ;
+
+pidfile_statement: PIDFILE STR
+ {
+ PJDLOG_RASSERT(depth == 0,
+ "The pidfile variable can only be specificed in the global section.");
+
+ if (lconfig->adc_pidfile[0] != '\0') {
+ pjdlog_error("The pidfile variable is specified twice.");
+ free($2);
+ return (1);
+ }
+ if (strcmp($2, "none") != 0 && $2[0] != '/') {
+ pjdlog_error("The pidfile variable must be set to absolute pathname or \"none\".");
+ free($2);
+ return (1);
+ }
+ if (strlcpy(lconfig->adc_pidfile, $2,
+ sizeof(lconfig->adc_pidfile)) >=
+ sizeof(lconfig->adc_pidfile)) {
+ pjdlog_error("The pidfile value is too long.");
+ free($2);
+ return (1);
+ }
+ free($2);
+ }
+ ;
+
+timeout_statement: TIMEOUT NUM
+ {
+ PJDLOG_ASSERT(depth == 0);
+
+ lconfig->adc_timeout = $2;
+ }
+ ;
+
+sender_statement: SENDER sender_start sender_entries CB
+ {
+ PJDLOG_ASSERT(depth == 0);
+ PJDLOG_ASSERT(cursection == SECTION_SENDER);
+
+ /* Configure defaults. */
+ if (depth1_checksum == -1)
+ depth1_checksum = ADIST_CHECKSUM_NONE;
+ if (depth1_compression == -1)
+ depth1_compression = ADIST_COMPRESSION_NONE;
+ if (depth1_directory[0] == '\0') {
+ (void)strlcpy(depth1_directory, ADIST_DIRECTORY_SENDER,
+ sizeof(depth1_directory));
+ }
+ /* Empty depth1_source is ok. */
+ TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
+ if (curhost->adh_role != ADIST_ROLE_SENDER)
+ continue;
+ if (curhost->adh_checksum == -1)
+ curhost->adh_checksum = depth1_checksum;
+ if (curhost->adh_compression == -1)
+ curhost->adh_compression = depth1_compression;
+ if (curhost->adh_directory[0] == '\0') {
+ (void)strlcpy(curhost->adh_directory,
+ depth1_directory,
+ sizeof(curhost->adh_directory));
+ }
+ if (curhost->adh_localaddr[0] == '\0') {
+ (void)strlcpy(curhost->adh_localaddr,
+ depth1_source,
+ sizeof(curhost->adh_localaddr));
+ }
+ }
+ cursection = SECTION_GLOBAL;
+ }
+ ;
+
+sender_start: OB
+ {
+ PJDLOG_ASSERT(depth == 1);
+ PJDLOG_ASSERT(cursection == SECTION_GLOBAL);
+
+ cursection = SECTION_SENDER;
+ depth1_checksum = -1;
+ depth1_compression = -1;
+ depth1_source[0] = '\0';
+ depth1_directory[0] = '\0';
+
+#ifndef HAVE_AUDIT_SYSCALLS
+ pjdlog_error("Sender functionality is not available.");
+ return (1);
+#endif
+ }
+ ;
+
+sender_entries:
+ |
+ sender_entries sender_entry
+ ;
+
+sender_entry:
+ source_statement
+ |
+ directory_statement
+/*
+ |
+ checksum_statement
+ |
+ compression_statement
+*/
+ |
+ sender_host_statement
+ ;
+
+receiver_statement: RECEIVER receiver_start receiver_entries CB
+ {
+ PJDLOG_ASSERT(depth == 0);
+ PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
+
+ /*
+ * If not listen addresses were specified,
+ * configure default ones.
+ */
+ if (TAILQ_EMPTY(&lconfig->adc_listen)) {
+ struct adist_listen *lst;
+
+ if (family_supported(AF_INET)) {
+ lst = calloc(1, sizeof(*lst));
+ if (lst == NULL) {
+ pjdlog_error("Unable to allocate memory for listen address.");
+ return (1);
+ }
+ (void)strlcpy(lst->adl_addr,
+ ADIST_LISTEN_TLS_TCP4,
+ sizeof(lst->adl_addr));
+ TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
+ } else {
+ pjdlog_debug(1,
+ "No IPv4 support in the kernel, not listening on IPv4 address.");
+ }
+ if (family_supported(AF_INET6)) {
+ lst = calloc(1, sizeof(*lst));
+ if (lst == NULL) {
+ pjdlog_error("Unable to allocate memory for listen address.");
+ return (1);
+ }
+ (void)strlcpy(lst->adl_addr,
+ ADIST_LISTEN_TLS_TCP6,
+ sizeof(lst->adl_addr));
+ TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
+ } else {
+ pjdlog_debug(1,
+ "No IPv6 support in the kernel, not listening on IPv6 address.");
+ }
+ if (TAILQ_EMPTY(&lconfig->adc_listen)) {
+ pjdlog_error("No address to listen on.");
+ return (1);
+ }
+ }
+ /* Configure defaults. */
+ if (depth1_directory[0] == '\0') {
+ (void)strlcpy(depth1_directory,
+ ADIST_DIRECTORY_RECEIVER,
+ sizeof(depth1_directory));
+ }
+ TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
+ if (curhost->adh_role != ADIST_ROLE_RECEIVER)
+ continue;
+ if (curhost->adh_directory[0] == '\0') {
+ if (snprintf(curhost->adh_directory,
+ sizeof(curhost->adh_directory), "%s/%s",
+ depth1_directory, curhost->adh_name) >=
+ (ssize_t)sizeof(curhost->adh_directory)) {
+ pjdlog_error("Directory value is too long.");
+ return (1);
+ }
+ }
+ }
+ cursection = SECTION_GLOBAL;
+ }
+ ;
+
+receiver_start: OB
+ {
+ PJDLOG_ASSERT(depth == 1);
+ PJDLOG_ASSERT(cursection == SECTION_GLOBAL);
+
+ cursection = SECTION_RECEIVER;
+ depth1_directory[0] = '\0';
+ }
+ ;
+
+receiver_entries:
+ |
+ receiver_entries receiver_entry
+ ;
+
+receiver_entry:
+ listen_statement
+ |
+ directory_statement
+ |
+ certfile_statement
+ |
+ keyfile_statement
+ |
+ receiver_host_statement
+ ;
+
+/*
+checksum_statement: CHECKSUM checksum_type
+ {
+ PJDLOG_ASSERT(cursection == SECTION_SENDER);
+
+ switch (depth) {
+ case 1:
+ depth1_checksum = $2;
+ break;
+ case 2:
+ PJDLOG_ASSERT(curhost != NULL);
+ curhost->adh_checksum = $2;
+ break;
+ default:
+ PJDLOG_ABORT("checksum at wrong depth level");
+ }
+ }
+ ;
+
+checksum_type:
+ NONE { $$ = ADIST_CHECKSUM_NONE; }
+ |
+ CRC32 { $$ = ADIST_CHECKSUM_CRC32; }
+ |
+ SHA256 { $$ = ADIST_CHECKSUM_SHA256; }
+ ;
+
+compression_statement: COMPRESSION compression_type
+ {
+ PJDLOG_ASSERT(cursection == SECTION_SENDER);
+
+ switch (depth) {
+ case 1:
+ depth1_compression = $2;
+ break;
+ case 2:
+ PJDLOG_ASSERT(curhost != NULL);
+ curhost->adh_compression = $2;
+ break;
+ default:
+ PJDLOG_ABORT("compression at wrong depth level");
+ }
+ }
+ ;
+
+compression_type:
+ NONE { $$ = ADIST_COMPRESSION_NONE; }
+ |
+ LZF { $$ = ADIST_COMPRESSION_LZF; }
+ ;
+*/
+
+directory_statement: DIRECTORY STR
+ {
+ PJDLOG_ASSERT(cursection == SECTION_SENDER ||
+ cursection == SECTION_RECEIVER);
+
+ switch (depth) {
+ case 1:
+ if (strlcpy(depth1_directory, $2,
+ sizeof(depth1_directory)) >=
+ sizeof(depth1_directory)) {
+ pjdlog_error("Directory value is too long.");
+ free($2);
+ return (1);
+ }
+ if (!adjust_directory(depth1_directory))
+ return (1);
+ break;
+ case 2:
+ if (cursection == SECTION_SENDER || $2[0] == '/') {
+ if (strlcpy(curhost->adh_directory, $2,
+ sizeof(curhost->adh_directory)) >=
+ sizeof(curhost->adh_directory)) {
+ pjdlog_error("Directory value is too long.");
+ free($2);
+ return (1);
+ }
+ } else /* if (cursection == SECTION_RECEIVER) */ {
+ if (depth1_directory[0] == '\0') {
+ pjdlog_error("Directory path must be absolute.");
+ free($2);
+ return (1);
+ }
+ if (snprintf(curhost->adh_directory,
+ sizeof(curhost->adh_directory), "%s/%s",
+ depth1_directory, $2) >=
+ (ssize_t)sizeof(curhost->adh_directory)) {
+ pjdlog_error("Directory value is too long.");
+ free($2);
+ return (1);
+ }
+ }
+ break;
+ default:
+ PJDLOG_ABORT("directory at wrong depth level");
+ }
+ free($2);
+ }
+ ;
+
+source_statement: SOURCE STR
+ {
+ PJDLOG_RASSERT(cursection == SECTION_SENDER,
+ "The source variable must be in sender section.");
+
+ switch (depth) {
+ case 1:
+ if (strlcpy(depth1_source, $2,
+ sizeof(depth1_source)) >=
+ sizeof(depth1_source)) {
+ pjdlog_error("Source value is too long.");
+ free($2);
+ return (1);
+ }
+ break;
+ case 2:
+ if (strlcpy(curhost->adh_localaddr, $2,
+ sizeof(curhost->adh_localaddr)) >=
+ sizeof(curhost->adh_localaddr)) {
+ pjdlog_error("Source value is too long.");
+ free($2);
+ return (1);
+ }
+ break;
+ }
+ free($2);
+ }
+ ;
+
+fingerprint_statement: FINGERPRINT STR
+ {
+ PJDLOG_ASSERT(cursection == SECTION_SENDER);
+ PJDLOG_ASSERT(depth == 2);
+
+ if (strncasecmp($2, "SHA256=", 7) != 0) {
+ pjdlog_error("Invalid fingerprint value.");
+ free($2);
+ return (1);
+ }
+ if (strlcpy(curhost->adh_fingerprint, $2,
+ sizeof(curhost->adh_fingerprint)) >=
+ sizeof(curhost->adh_fingerprint)) {
+ pjdlog_error("Fingerprint value is too long.");
+ free($2);
+ return (1);
+ }
+ free($2);
+ }
+ ;
+
+password_statement: PASSWORD STR
+ {
+ PJDLOG_ASSERT(cursection == SECTION_SENDER ||
+ cursection == SECTION_RECEIVER);
+ PJDLOG_ASSERT(depth == 2);
+
+ if (strlcpy(curhost->adh_password, $2,
+ sizeof(curhost->adh_password)) >=
+ sizeof(curhost->adh_password)) {
+ pjdlog_error("Password value is too long.");
+ bzero($2, strlen($2));
+ free($2);
+ return (1);
+ }
+ bzero($2, strlen($2));
+ free($2);
+ }
+ ;
+
+certfile_statement: CERTFILE STR
+ {
+ PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
+ PJDLOG_ASSERT(depth == 1);
+
+ if (strlcpy(lconfig->adc_certfile, $2,
+ sizeof(lconfig->adc_certfile)) >=
+ sizeof(lconfig->adc_certfile)) {
+ pjdlog_error("Certfile value is too long.");
+ free($2);
+ return (1);
+ }
+ free($2);
+ }
+ ;
+
+keyfile_statement: KEYFILE STR
+ {
+ PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
+ PJDLOG_ASSERT(depth == 1);
+
+ if (strlcpy(lconfig->adc_keyfile, $2,
+ sizeof(lconfig->adc_keyfile)) >=
+ sizeof(lconfig->adc_keyfile)) {
+ pjdlog_error("Keyfile value is too long.");
+ free($2);
+ return (1);
+ }
+ free($2);
+ }
+ ;
+
+listen_statement: LISTEN STR
+ {
+ struct adist_listen *lst;
+
+ PJDLOG_ASSERT(depth == 1);
+ PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
+
+ lst = calloc(1, sizeof(*lst));
+ if (lst == NULL) {
+ pjdlog_error("Unable to allocate memory for listen address.");
+ free($2);
+ return (1);
+ }
+ if (strlcpy(lst->adl_addr, $2, sizeof(lst->adl_addr)) >=
+ sizeof(lst->adl_addr)) {
+ pjdlog_error("listen argument is too long.");
+ free($2);
+ free(lst);
+ return (1);
+ }
+ TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
+ free($2);
+ }
+ ;
+
+sender_host_statement: HOST host_start OB sender_host_entries CB
+ {
+ /* Put it onto host list. */
+ TAILQ_INSERT_TAIL(&lconfig->adc_hosts, curhost, adh_next);
+ curhost = NULL;
+ }
+ ;
+
+receiver_host_statement: HOST host_start OB receiver_host_entries CB
+ {
+ /* Put it onto host list. */
+ TAILQ_INSERT_TAIL(&lconfig->adc_hosts, curhost, adh_next);
+ curhost = NULL;
+ }
+ ;
+
+host_start: STR
+ {
+ /* Check if there is no duplicate entry. */
+ TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
+ if (strcmp(curhost->adh_name, $1) != 0)
+ continue;
+ if (curhost->adh_role == ADIST_ROLE_SENDER &&
+ cursection == SECTION_RECEIVER) {
+ continue;
+ }
+ if (curhost->adh_role == ADIST_ROLE_RECEIVER &&
+ cursection == SECTION_SENDER) {
+ continue;
+ }
+ pjdlog_error("%s host %s is configured more than once.",
+ curhost->adh_role == ADIST_ROLE_SENDER ?
+ "Sender" : "Receiver", curhost->adh_name);
+ free($1);
+ return (1);
+ }
+
+ curhost = calloc(1, sizeof(*curhost));
+ if (curhost == NULL) {
+ pjdlog_error("Unable to allocate memory for host configuration.");
+ free($1);
+ return (1);
+ }
+ if (strlcpy(curhost->adh_name, $1, sizeof(curhost->adh_name)) >=
+ sizeof(curhost->adh_name)) {
+ pjdlog_error("Host name is too long.");
+ free($1);
+ return (1);
+ }
+ free($1);
+ curhost->adh_role = cursection == SECTION_SENDER ?
+ ADIST_ROLE_SENDER : ADIST_ROLE_RECEIVER;
+ curhost->adh_version = ADIST_VERSION;
+ curhost->adh_localaddr[0] = '\0';
+ curhost->adh_remoteaddr[0] = '\0';
+ curhost->adh_remote = NULL;
+ curhost->adh_directory[0] = '\0';
+ curhost->adh_password[0] = '\0';
+ curhost->adh_fingerprint[0] = '\0';
+ curhost->adh_worker_pid = 0;
+ curhost->adh_conn = NULL;
+ }
+ ;
+
+sender_host_entries:
+ |
+ sender_host_entries sender_host_entry
+ ;
+
+sender_host_entry:
+ source_statement
+ |
+ remote_statement
+ |
+ directory_statement
+ |
+ fingerprint_statement
+ |
+ password_statement
+/*
+ |
+ checksum_statement
+ |
+ compression_statement
+*/
+ ;
+
+receiver_host_entries:
+ |
+ receiver_host_entries receiver_host_entry
+ ;
+
+receiver_host_entry:
+ remote_statement
+ |
+ directory_statement
+ |
+ password_statement
+ ;
+
+remote_statement: REMOTE STR
+ {
+ PJDLOG_ASSERT(depth == 2);
+ PJDLOG_ASSERT(cursection == SECTION_SENDER ||
+ cursection == SECTION_RECEIVER);
+
+ if (strlcpy(curhost->adh_remoteaddr, $2,
+ sizeof(curhost->adh_remoteaddr)) >=
+ sizeof(curhost->adh_remoteaddr)) {
+ pjdlog_error("Remote value is too long.");
+ free($2);
+ return (1);
+ }
+ free($2);
+ }
+ ;
+
+%%
+
+static bool
+family_supported(int family)
+{
+ int sock;
+
+ sock = socket(family, SOCK_STREAM, 0);
+ if (sock == -1 && errno == EPROTONOSUPPORT)
+ return (false);
+ if (sock >= 0)
+ (void)close(sock);
+ return (true);
+}
+
+static bool
+adjust_directory(char *path)
+{
+ size_t len;
+
+ len = strlen(path);
+ for (;;) {
+ if (len == 0) {
+ pjdlog_error("Directory path is empty.");
+ return (false);
+ }
+ if (path[len - 1] != '/')
+ break;
+ len--;
+ path[len] = '\0';
+ }
+ if (path[0] != '/') {
+ pjdlog_error("Directory path must be absolute.");
+ return (false);
+ }
+ return (true);
+}
+
+static int
+my_name(char *name, size_t size)
+{
+ char buf[MAXHOSTNAMELEN];
+ char *pos;
+
+ if (gethostname(buf, sizeof(buf)) < 0) {
+ pjdlog_errno(LOG_ERR, "gethostname() failed");
+ return (-1);
+ }
+
+ /* First component of the host name. */
+ pos = strchr(buf, '.');
+ if (pos == NULL)
+ (void)strlcpy(name, buf, size);
+ else
+ (void)strlcpy(name, buf, MIN((size_t)(pos - buf + 1), size));
+
+ if (name[0] == '\0') {
+ pjdlog_error("Empty host name.");
+ return (-1);
+ }
+
+ return (0);
+}
+
+void
+yyerror(const char *str)
+{
+
+ pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
+ lineno, yytext, str);
+}
+
+struct adist_config *
+yy_config_parse(const char *config, bool exitonerror)
+{
+ int ret;
+
+ curhost = NULL;
+ cursection = SECTION_GLOBAL;
+ depth = 0;
+ lineno = 0;
+
+ lconfig = calloc(1, sizeof(*lconfig));
+ if (lconfig == NULL) {
+ pjdlog_error("Unable to allocate memory for configuration.");
+ if (exitonerror)
+ exit(EX_TEMPFAIL);
+ return (NULL);
+ }
+ TAILQ_INIT(&lconfig->adc_hosts);
+ TAILQ_INIT(&lconfig->adc_listen);
+ lconfig->adc_name[0] = '\0';
+ lconfig->adc_timeout = -1;
+ lconfig->adc_pidfile[0] = '\0';
+ lconfig->adc_certfile[0] = '\0';
+ lconfig->adc_keyfile[0] = '\0';
+
+ yyin = fopen(config, "r");
+ if (yyin == NULL) {
+ pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
+ config);
+ yy_config_free(lconfig);
+ if (exitonerror)
+ exit(EX_OSFILE);
+ return (NULL);
+ }
+ yyrestart(yyin);
+ ret = yyparse();
+ fclose(yyin);
+ if (ret != 0) {
+ yy_config_free(lconfig);
+ if (exitonerror)
+ exit(EX_CONFIG);
+ return (NULL);
+ }
+
+ /*
+ * Let's see if everything is set up.
+ */
+ if (lconfig->adc_name[0] == '\0' && my_name(lconfig->adc_name,
+ sizeof(lconfig->adc_name)) == -1) {
+ yy_config_free(lconfig);
+ if (exitonerror)
+ exit(EX_CONFIG);
+ return (NULL);
+ }
+ if (lconfig->adc_timeout == -1)
+ lconfig->adc_timeout = ADIST_TIMEOUT;
+ if (lconfig->adc_pidfile[0] == '\0') {
+ (void)strlcpy(lconfig->adc_pidfile, ADIST_PIDFILE,
+ sizeof(lconfig->adc_pidfile));
+ }
+ if (lconfig->adc_certfile[0] == '\0') {
+ (void)strlcpy(lconfig->adc_certfile, ADIST_CERTFILE,
+ sizeof(lconfig->adc_certfile));
+ }
+ if (lconfig->adc_keyfile[0] == '\0') {
+ (void)strlcpy(lconfig->adc_keyfile, ADIST_KEYFILE,
+ sizeof(lconfig->adc_keyfile));
+ }
+
+ return (lconfig);
+}
+
+void
+yy_config_free(struct adist_config *config)
+{
+ struct adist_host *adhost;
+ struct adist_listen *lst;
+
+ while ((lst = TAILQ_FIRST(&config->adc_listen)) != NULL) {
+ TAILQ_REMOVE(&config->adc_listen, lst, adl_next);
+ free(lst);
+ }
+ while ((adhost = TAILQ_FIRST(&config->adc_hosts)) != NULL) {
+ TAILQ_REMOVE(&config->adc_hosts, adhost, adh_next);
+ bzero(adhost, sizeof(*adhost));
+ free(adhost);
+ }
+ free(config);
+}
diff --git a/contrib/openbsm/bin/auditdistd/pjdlog.c b/contrib/openbsm/bin/auditdistd/pjdlog.c
new file mode 100644
index 0000000..16f176e
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/pjdlog.c
@@ -0,0 +1,619 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <errno.h>
+#ifdef __FreeBSD__
+#include <libutil.h>
+#include <printf.h>
+#endif
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "pjdlog.h"
+
+#define PJDLOG_NEVER_INITIALIZED 0
+#define PJDLOG_NOT_INITIALIZED 1
+#define PJDLOG_INITIALIZED 2
+
+static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
+static int pjdlog_mode, pjdlog_debug_level;
+static char pjdlog_prefix[128];
+
+#ifdef __FreeBSD__
+static int
+pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
+ size_t n, int *argt)
+{
+
+ assert(n >= 1);
+ argt[0] = PA_INT | PA_FLAG_INTMAX;
+ return (1);
+}
+
+static int
+pjdlog_printf_render_humanized_number(struct __printf_io *io,
+ const struct printf_info *pi, const void * const *arg)
+{
+ char buf[5];
+ intmax_t num;
+ int ret;
+
+ num = *(const intmax_t *)arg[0];
+ humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
+ HN_NOSPACE | HN_DECIMAL);
+ ret = __printf_out(io, pi, buf, strlen(buf));
+ __printf_flush(io);
+ return (ret);
+}
+
+static int
+pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
+ size_t n, int *argt)
+{
+
+ assert(n >= 1);
+ argt[0] = PA_POINTER;
+ return (1);
+}
+
+static int
+pjdlog_printf_render_sockaddr(struct __printf_io *io,
+ const struct printf_info *pi, const void * const *arg)
+{
+ const struct sockaddr_storage *ss;
+ char buf[64];
+ int ret;
+
+ ss = *(const struct sockaddr_storage * const *)arg[0];
+ switch (ss->ss_family) {
+ case AF_INET:
+ {
+ char addr[INET_ADDRSTRLEN];
+ const struct sockaddr_in *sin;
+ unsigned int port;
+
+ sin = (const struct sockaddr_in *)ss;
+ port = ntohs(sin->sin_port);
+ if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
+ sizeof(addr)) == NULL) {
+ PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
+ strerror(errno));
+ }
+ snprintf(buf, sizeof(buf), "%s:%u", addr, port);
+ break;
+ }
+ case AF_INET6:
+ {
+ char addr[INET6_ADDRSTRLEN];
+ const struct sockaddr_in6 *sin;
+ unsigned int port;
+
+ sin = (const struct sockaddr_in6 *)ss;
+ port = ntohs(sin->sin6_port);
+ if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
+ sizeof(addr)) == NULL) {
+ PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
+ strerror(errno));
+ }
+ snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
+ break;
+ }
+ default:
+ snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
+ ss->ss_family);
+ break;
+ }
+ ret = __printf_out(io, pi, buf, strlen(buf));
+ __printf_flush(io);
+ return (ret);
+}
+#endif /* __FreeBSD__ */
+
+void
+pjdlog_init(int mode)
+{
+ int saved_errno;
+
+ assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
+ pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
+ assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
+
+ saved_errno = errno;
+
+ if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
+#ifdef __FreeBSD__
+ __use_xprintf = 1;
+ register_printf_render_std("T");
+ register_printf_render('N',
+ pjdlog_printf_render_humanized_number,
+ pjdlog_printf_arginfo_humanized_number);
+ register_printf_render('S',
+ pjdlog_printf_render_sockaddr,
+ pjdlog_printf_arginfo_sockaddr);
+#endif
+ }
+
+ if (mode == PJDLOG_MODE_SYSLOG)
+ openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
+ pjdlog_mode = mode;
+ pjdlog_debug_level = 0;
+ bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
+
+ pjdlog_initialized = PJDLOG_INITIALIZED;
+
+ errno = saved_errno;
+}
+
+void
+pjdlog_fini(void)
+{
+ int saved_errno;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ saved_errno = errno;
+
+ if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
+ closelog();
+
+ pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
+
+ errno = saved_errno;
+}
+
+/*
+ * Configure where the logs should go.
+ * By default they are send to stdout/stderr, but after going into background
+ * (eg. by calling daemon(3)) application is responsible for changing mode to
+ * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
+ */
+void
+pjdlog_mode_set(int mode)
+{
+ int saved_errno;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+ assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
+
+ if (pjdlog_mode == mode)
+ return;
+
+ saved_errno = errno;
+
+ if (mode == PJDLOG_MODE_SYSLOG)
+ openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
+ else /* if (mode == PJDLOG_MODE_STD) */
+ closelog();
+
+ pjdlog_mode = mode;
+
+ errno = saved_errno;
+}
+
+/*
+ * Return current mode.
+ */
+int
+pjdlog_mode_get(void)
+{
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ return (pjdlog_mode);
+}
+
+/*
+ * Set debug level. All the logs above the level specified here will be
+ * ignored.
+ */
+void
+pjdlog_debug_set(int level)
+{
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+ assert(level >= 0);
+
+ pjdlog_debug_level = level;
+}
+
+/*
+ * Return current debug level.
+ */
+int
+pjdlog_debug_get(void)
+{
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ return (pjdlog_debug_level);
+}
+
+/*
+ * Set prefix that will be used before each log.
+ * Setting prefix to NULL will remove it.
+ */
+void
+pjdlog_prefix_set(const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ va_start(ap, fmt);
+ pjdlogv_prefix_set(fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Set prefix that will be used before each log.
+ * Setting prefix to NULL will remove it.
+ */
+void
+pjdlogv_prefix_set(const char *fmt, va_list ap)
+{
+ int saved_errno;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+ assert(fmt != NULL);
+
+ saved_errno = errno;
+
+ vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
+
+ errno = saved_errno;
+}
+
+/*
+ * Convert log level into string.
+ */
+static const char *
+pjdlog_level_string(int loglevel)
+{
+
+ switch (loglevel) {
+ case LOG_EMERG:
+ return ("EMERG");
+ case LOG_ALERT:
+ return ("ALERT");
+ case LOG_CRIT:
+ return ("CRIT");
+ case LOG_ERR:
+ return ("ERROR");
+ case LOG_WARNING:
+ return ("WARNING");
+ case LOG_NOTICE:
+ return ("NOTICE");
+ case LOG_INFO:
+ return ("INFO");
+ case LOG_DEBUG:
+ return ("DEBUG");
+ }
+ assert(!"Invalid log level.");
+ abort(); /* XXX: gcc */
+}
+
+/*
+ * Common log routine.
+ */
+void
+pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ va_start(ap, fmt);
+ pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Common log routine, which can handle regular log level as well as debug
+ * level. We decide here where to send the logs (stdout/stderr or syslog).
+ */
+void
+pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
+ va_list ap)
+{
+ int saved_errno;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+ assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
+ loglevel == LOG_CRIT || loglevel == LOG_ERR ||
+ loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
+ loglevel == LOG_INFO || loglevel == LOG_DEBUG);
+ assert(loglevel != LOG_DEBUG || debuglevel > 0);
+ assert(error >= -1);
+
+ /* Ignore debug above configured level. */
+ if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
+ return;
+
+ saved_errno = errno;
+
+ switch (pjdlog_mode) {
+ case PJDLOG_MODE_STD:
+ {
+ FILE *out;
+
+ /*
+ * We send errors and warning to stderr and the rest to stdout.
+ */
+ switch (loglevel) {
+ case LOG_EMERG:
+ case LOG_ALERT:
+ case LOG_CRIT:
+ case LOG_ERR:
+ case LOG_WARNING:
+ out = stderr;
+ break;
+ case LOG_NOTICE:
+ case LOG_INFO:
+ case LOG_DEBUG:
+ out = stdout;
+ break;
+ default:
+ assert(!"Invalid loglevel.");
+ abort(); /* XXX: gcc */
+ }
+
+ fprintf(out, "(%d) ", getpid());
+ fprintf(out, "[%s]", pjdlog_level_string(loglevel));
+ /* Attach debuglevel if this is debug log. */
+ if (loglevel == LOG_DEBUG)
+ fprintf(out, "[%d]", debuglevel);
+ fprintf(out, " %s", pjdlog_prefix);
+ vfprintf(out, fmt, ap);
+ if (error != -1)
+ fprintf(out, ": %s.", strerror(error));
+ fprintf(out, "\n");
+ fflush(out);
+ break;
+ }
+ case PJDLOG_MODE_SYSLOG:
+ {
+ char log[1024];
+ int len;
+
+ len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
+ if ((size_t)len < sizeof(log))
+ len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
+ if (error != -1 && (size_t)len < sizeof(log)) {
+ (void)snprintf(log + len, sizeof(log) - len, ": %s.",
+ strerror(error));
+ }
+ syslog(loglevel, "%s", log);
+ break;
+ }
+ default:
+ assert(!"Invalid mode.");
+ }
+
+ errno = saved_errno;
+}
+
+/*
+ * Regular logs.
+ */
+void
+pjdlogv(int loglevel, const char *fmt, va_list ap)
+{
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
+ assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
+ loglevel == LOG_CRIT || loglevel == LOG_ERR ||
+ loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
+ loglevel == LOG_INFO);
+
+ pjdlogv_common(loglevel, 0, -1, fmt, ap);
+}
+
+/*
+ * Regular logs.
+ */
+void
+pjdlog(int loglevel, const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ va_start(ap, fmt);
+ pjdlogv(loglevel, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Debug logs.
+ */
+void
+pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
+{
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
+}
+
+/*
+ * Debug logs.
+ */
+void
+pjdlog_debug(int debuglevel, const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ va_start(ap, fmt);
+ pjdlogv_debug(debuglevel, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Error logs with errno logging.
+ */
+void
+pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
+{
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ pjdlogv_common(loglevel, 0, errno, fmt, ap);
+}
+
+/*
+ * Error logs with errno logging.
+ */
+void
+pjdlog_errno(int loglevel, const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ va_start(ap, fmt);
+ pjdlogv_errno(loglevel, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Log error, errno and exit.
+ */
+void
+pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
+{
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ pjdlogv_errno(LOG_ERR, fmt, ap);
+ exit(exitcode);
+ /* NOTREACHED */
+}
+
+/*
+ * Log error, errno and exit.
+ */
+void
+pjdlog_exit(int exitcode, const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ va_start(ap, fmt);
+ pjdlogv_exit(exitcode, fmt, ap);
+ /* NOTREACHED */
+ va_end(ap);
+}
+
+/*
+ * Log error and exit.
+ */
+void
+pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
+{
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ pjdlogv(LOG_ERR, fmt, ap);
+ exit(exitcode);
+ /* NOTREACHED */
+}
+
+/*
+ * Log error and exit.
+ */
+void
+pjdlog_exitx(int exitcode, const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ va_start(ap, fmt);
+ pjdlogv_exitx(exitcode, fmt, ap);
+ /* NOTREACHED */
+ va_end(ap);
+}
+
+/*
+ * Log failure message and exit.
+ */
+void
+pjdlog_abort(const char *func, const char *file, int line,
+ const char *failedexpr, const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(pjdlog_initialized == PJDLOG_INITIALIZED);
+
+ /*
+ * When there is no message we pass __func__ as 'fmt'.
+ * It would be cleaner to pass NULL or "", but gcc generates a warning
+ * for both of those.
+ */
+ if (fmt != func) {
+ va_start(ap, fmt);
+ pjdlogv_critical(fmt, ap);
+ va_end(ap);
+ }
+ if (failedexpr == NULL) {
+ if (func == NULL) {
+ pjdlog_critical("Aborted at file %s, line %d.", file,
+ line);
+ } else {
+ pjdlog_critical("Aborted at function %s, file %s, line %d.",
+ func, file, line);
+ }
+ } else {
+ if (func == NULL) {
+ pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
+ failedexpr, file, line);
+ } else {
+ pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
+ failedexpr, func, file, line);
+ }
+ }
+ abort();
+}
diff --git a/contrib/openbsm/bin/auditdistd/pjdlog.h b/contrib/openbsm/bin/auditdistd/pjdlog.h
new file mode 100644
index 0000000..d6f217f
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/pjdlog.h
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _PJDLOG_H_
+#define _PJDLOG_H_
+
+#include <sys/cdefs.h>
+
+#include <stdarg.h>
+#include <sysexits.h>
+#include <syslog.h>
+
+#include <compat/compat.h>
+
+#define PJDLOG_MODE_STD 0
+#define PJDLOG_MODE_SYSLOG 1
+
+void pjdlog_init(int mode);
+void pjdlog_fini(void);
+
+void pjdlog_mode_set(int mode);
+int pjdlog_mode_get(void);
+
+void pjdlog_debug_set(int level);
+int pjdlog_debug_get(void);
+
+void pjdlog_prefix_set(const char *fmt, ...) __printflike(1, 2);
+void pjdlogv_prefix_set(const char *fmt, va_list ap) __printflike(1, 0);
+
+void pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt,
+ ...) __printflike(4, 5);
+void pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
+ va_list ap) __printflike(4, 0);
+
+void pjdlog(int loglevel, const char *fmt, ...) __printflike(2, 3);
+void pjdlogv(int loglevel, const char *fmt, va_list ap) __printflike(2, 0);
+
+#define pjdlogv_emergency(fmt, ap) pjdlogv(LOG_EMERG, (fmt), (ap))
+#define pjdlog_emergency(...) pjdlog(LOG_EMERG, __VA_ARGS__)
+#define pjdlogv_alert(fmt, ap) pjdlogv(LOG_ALERT, (fmt), (ap))
+#define pjdlog_alert(...) pjdlog(LOG_ALERT, __VA_ARGS__)
+#define pjdlogv_critical(fmt, ap) pjdlogv(LOG_CRIT, (fmt), (ap))
+#define pjdlog_critical(...) pjdlog(LOG_CRIT, __VA_ARGS__)
+#define pjdlogv_error(fmt, ap) pjdlogv(LOG_ERR, (fmt), (ap))
+#define pjdlog_error(...) pjdlog(LOG_ERR, __VA_ARGS__)
+#define pjdlogv_warning(fmt, ap) pjdlogv(LOG_WARNING, (fmt), (ap))
+#define pjdlog_warning(...) pjdlog(LOG_WARNING, __VA_ARGS__)
+#define pjdlogv_notice(fmt, ap) pjdlogv(LOG_NOTICE, (fmt), (ap))
+#define pjdlog_notice(...) pjdlog(LOG_NOTICE, __VA_ARGS__)
+#define pjdlogv_info(fmt, ap) pjdlogv(LOG_INFO, (fmt), (ap))
+#define pjdlog_info(...) pjdlog(LOG_INFO, __VA_ARGS__)
+
+void pjdlog_debug(int debuglevel, const char *fmt, ...) __printflike(2, 3);
+void pjdlogv_debug(int debuglevel, const char *fmt, va_list ap) __printflike(2, 0);
+
+void pjdlog_errno(int loglevel, const char *fmt, ...) __printflike(2, 3);
+void pjdlogv_errno(int loglevel, const char *fmt, va_list ap) __printflike(2, 0);
+
+void pjdlog_exit(int exitcode, const char *fmt, ...) __printflike(2, 3) __dead2;
+void pjdlogv_exit(int exitcode, const char *fmt, va_list ap) __printflike(2, 0) __dead2;
+
+void pjdlog_exitx(int exitcode, const char *fmt, ...) __printflike(2, 3) __dead2;
+void pjdlogv_exitx(int exitcode, const char *fmt, va_list ap) __printflike(2, 0) __dead2;
+
+void pjdlog_abort(const char *func, const char *file, int line,
+ const char *failedexpr, const char *fmt, ...) __printflike(5, 6) __dead2;
+
+#define PJDLOG_VERIFY(expr) do { \
+ if (!(expr)) { \
+ pjdlog_abort(__func__, __FILE__, __LINE__, #expr, \
+ "%s", __func__); \
+ } \
+} while (0)
+#define PJDLOG_RVERIFY(expr, ...) do { \
+ if (!(expr)) { \
+ pjdlog_abort(__func__, __FILE__, __LINE__, #expr, \
+ __VA_ARGS__); \
+ } \
+} while (0)
+#define PJDLOG_ABORT(...) pjdlog_abort(__func__, __FILE__, \
+ __LINE__, NULL, __VA_ARGS__)
+#ifdef NDEBUG
+#define PJDLOG_ASSERT(expr) do { } while (0)
+#define PJDLOG_RASSERT(...) do { } while (0)
+#else
+#define PJDLOG_ASSERT(expr) PJDLOG_VERIFY(expr)
+#define PJDLOG_RASSERT(...) PJDLOG_RVERIFY(__VA_ARGS__)
+#endif
+
+#endif /* !_PJDLOG_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/proto.c b/contrib/openbsm/bin/auditdistd/proto.c
new file mode 100644
index 0000000..4e9bea0
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/proto.c
@@ -0,0 +1,527 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <strings.h>
+
+#include "pjdlog.h"
+#include "proto.h"
+#include "proto_impl.h"
+
+#define PROTO_CONN_MAGIC 0x907041c
+struct proto_conn {
+ int pc_magic;
+ struct proto *pc_proto;
+ void *pc_ctx;
+ int pc_side;
+#define PROTO_SIDE_CLIENT 0
+#define PROTO_SIDE_SERVER_LISTEN 1
+#define PROTO_SIDE_SERVER_WORK 2
+};
+
+static TAILQ_HEAD(, proto) protos = TAILQ_HEAD_INITIALIZER(protos);
+
+void
+proto_register(struct proto *proto, bool isdefault)
+{
+ static bool seen_default = false;
+
+ if (!isdefault)
+ TAILQ_INSERT_HEAD(&protos, proto, prt_next);
+ else {
+ PJDLOG_ASSERT(!seen_default);
+ seen_default = true;
+ TAILQ_INSERT_TAIL(&protos, proto, prt_next);
+ }
+}
+
+static struct proto_conn *
+proto_alloc(struct proto *proto, int side)
+{
+ struct proto_conn *conn;
+
+ PJDLOG_ASSERT(proto != NULL);
+ PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
+ side == PROTO_SIDE_SERVER_LISTEN ||
+ side == PROTO_SIDE_SERVER_WORK);
+
+ conn = malloc(sizeof(*conn));
+ if (conn != NULL) {
+ conn->pc_proto = proto;
+ conn->pc_side = side;
+ conn->pc_magic = PROTO_CONN_MAGIC;
+ }
+ return (conn);
+}
+
+static void
+proto_free(struct proto_conn *conn)
+{
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT ||
+ conn->pc_side == PROTO_SIDE_SERVER_LISTEN ||
+ conn->pc_side == PROTO_SIDE_SERVER_WORK);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+
+ bzero(conn, sizeof(*conn));
+ free(conn);
+}
+
+static int
+proto_common_setup(const char *srcaddr, const char *dstaddr, int timeout,
+ int side, struct proto_conn **connp)
+{
+ struct proto *proto;
+ struct proto_conn *conn;
+ void *ctx;
+ int ret;
+
+ PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
+ side == PROTO_SIDE_SERVER_LISTEN);
+
+ TAILQ_FOREACH(proto, &protos, prt_next) {
+ if (side == PROTO_SIDE_CLIENT) {
+ if (proto->prt_connect == NULL) {
+ ret = -1;
+ } else {
+ ret = proto->prt_connect(srcaddr, dstaddr,
+ timeout, &ctx);
+ }
+ } else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ {
+ if (proto->prt_server == NULL)
+ ret = -1;
+ else
+ ret = proto->prt_server(dstaddr, &ctx);
+ }
+ /*
+ * ret == 0 - success
+ * ret == -1 - dstaddr is not for this protocol
+ * ret > 0 - right protocol, but an error occured
+ */
+ if (ret >= 0)
+ break;
+ }
+ if (proto == NULL) {
+ /* Unrecognized address. */
+ errno = EINVAL;
+ return (-1);
+ }
+ if (ret > 0) {
+ /* An error occured. */
+ errno = ret;
+ return (-1);
+ }
+ conn = proto_alloc(proto, side);
+ if (conn == NULL) {
+ if (proto->prt_close != NULL)
+ proto->prt_close(ctx);
+ errno = ENOMEM;
+ return (-1);
+ }
+ conn->pc_ctx = ctx;
+ *connp = conn;
+
+ return (0);
+}
+
+int
+proto_connect(const char *srcaddr, const char *dstaddr, int timeout,
+ struct proto_conn **connp)
+{
+
+ PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0');
+ PJDLOG_ASSERT(dstaddr != NULL);
+ PJDLOG_ASSERT(timeout >= -1);
+
+ return (proto_common_setup(srcaddr, dstaddr, timeout,
+ PROTO_SIDE_CLIENT, connp));
+}
+
+int
+proto_connect_wait(struct proto_conn *conn, int timeout)
+{
+ int error;
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_connect_wait != NULL);
+ PJDLOG_ASSERT(timeout >= 0);
+
+ error = conn->pc_proto->prt_connect_wait(conn->pc_ctx, timeout);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+proto_server(const char *addr, struct proto_conn **connp)
+{
+
+ PJDLOG_ASSERT(addr != NULL);
+
+ return (proto_common_setup(NULL, addr, -1, PROTO_SIDE_SERVER_LISTEN,
+ connp));
+}
+
+int
+proto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
+{
+ struct proto_conn *newconn;
+ int error;
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_SERVER_LISTEN);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_accept != NULL);
+
+ newconn = proto_alloc(conn->pc_proto, PROTO_SIDE_SERVER_WORK);
+ if (newconn == NULL)
+ return (-1);
+
+ error = conn->pc_proto->prt_accept(conn->pc_ctx, &newconn->pc_ctx);
+ if (error != 0) {
+ proto_free(newconn);
+ errno = error;
+ return (-1);
+ }
+
+ *newconnp = newconn;
+
+ return (0);
+}
+
+int
+proto_send(const struct proto_conn *conn, const void *data, size_t size)
+{
+ int error;
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
+
+ error = conn->pc_proto->prt_send(conn->pc_ctx, data, size, -1);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+proto_recv(const struct proto_conn *conn, void *data, size_t size)
+{
+ int error;
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
+
+ error = conn->pc_proto->prt_recv(conn->pc_ctx, data, size, NULL);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+proto_connection_send(const struct proto_conn *conn, struct proto_conn *mconn)
+{
+ const char *protoname;
+ int error, fd;
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
+ PJDLOG_ASSERT(mconn != NULL);
+ PJDLOG_ASSERT(mconn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(mconn->pc_proto != NULL);
+ fd = proto_descriptor(mconn);
+ PJDLOG_ASSERT(fd >= 0);
+ protoname = mconn->pc_proto->prt_name;
+ PJDLOG_ASSERT(protoname != NULL);
+
+ error = conn->pc_proto->prt_send(conn->pc_ctx,
+ (const unsigned char *)protoname, strlen(protoname) + 1, fd);
+ proto_close(mconn);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+proto_wrap(const char *protoname, bool client, int fd,
+ struct proto_conn **newconnp)
+{
+ struct proto *proto;
+ struct proto_conn *newconn;
+ int error;
+
+ TAILQ_FOREACH(proto, &protos, prt_next) {
+ if (strcmp(proto->prt_name, protoname) == 0)
+ break;
+ }
+ if (proto == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ newconn = proto_alloc(proto,
+ client ? PROTO_SIDE_CLIENT : PROTO_SIDE_SERVER_WORK);
+ if (newconn == NULL)
+ return (-1);
+ PJDLOG_ASSERT(newconn->pc_proto->prt_wrap != NULL);
+ error = newconn->pc_proto->prt_wrap(fd, client, &newconn->pc_ctx);
+ if (error != 0) {
+ proto_free(newconn);
+ errno = error;
+ return (-1);
+ }
+
+ *newconnp = newconn;
+
+ return (0);
+}
+
+int
+proto_connection_recv(const struct proto_conn *conn, bool client,
+ struct proto_conn **newconnp)
+{
+ char protoname[128];
+ int error, fd;
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
+ PJDLOG_ASSERT(newconnp != NULL);
+
+ bzero(protoname, sizeof(protoname));
+
+ error = conn->pc_proto->prt_recv(conn->pc_ctx,
+ (unsigned char *)protoname, sizeof(protoname) - 1, &fd);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+
+ PJDLOG_ASSERT(fd >= 0);
+
+ return (proto_wrap(protoname, client, fd, newconnp));
+}
+
+int
+proto_descriptor(const struct proto_conn *conn)
+{
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_descriptor != NULL);
+
+ return (conn->pc_proto->prt_descriptor(conn->pc_ctx));
+}
+
+bool
+proto_address_match(const struct proto_conn *conn, const char *addr)
+{
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_address_match != NULL);
+
+ return (conn->pc_proto->prt_address_match(conn->pc_ctx, addr));
+}
+
+void
+proto_local_address(const struct proto_conn *conn, char *addr, size_t size)
+{
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_local_address != NULL);
+
+ conn->pc_proto->prt_local_address(conn->pc_ctx, addr, size);
+}
+
+void
+proto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
+{
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_remote_address != NULL);
+
+ conn->pc_proto->prt_remote_address(conn->pc_ctx, addr, size);
+}
+
+int
+proto_timeout(const struct proto_conn *conn, int timeout)
+{
+ struct timeval tv;
+ int fd;
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+
+ fd = proto_descriptor(conn);
+ if (fd < 0)
+ return (-1);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
+ return (-1);
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
+ return (-1);
+
+ return (0);
+}
+
+void
+proto_close(struct proto_conn *conn)
+{
+
+ PJDLOG_ASSERT(conn != NULL);
+ PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
+ PJDLOG_ASSERT(conn->pc_proto != NULL);
+ PJDLOG_ASSERT(conn->pc_proto->prt_close != NULL);
+
+ conn->pc_proto->prt_close(conn->pc_ctx);
+ proto_free(conn);
+}
+
+int
+proto_exec(int argc, char *argv[])
+{
+ struct proto *proto;
+ int error;
+
+ if (argc == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ TAILQ_FOREACH(proto, &protos, prt_next) {
+ if (strcmp(proto->prt_name, argv[0]) == 0)
+ break;
+ }
+ if (proto == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (proto->prt_exec == NULL) {
+ errno = EOPNOTSUPP;
+ return (-1);
+ }
+ error = proto->prt_exec(argc, argv);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+ /* NOTREACHED */
+ return (0);
+}
+
+struct proto_nvpair {
+ char *pnv_name;
+ char *pnv_value;
+ TAILQ_ENTRY(proto_nvpair) pnv_next;
+};
+
+static TAILQ_HEAD(, proto_nvpair) proto_nvpairs =
+ TAILQ_HEAD_INITIALIZER(proto_nvpairs);
+
+int
+proto_set(const char *name, const char *value)
+{
+ struct proto_nvpair *pnv;
+
+ TAILQ_FOREACH(pnv, &proto_nvpairs, pnv_next) {
+ if (strcmp(pnv->pnv_name, name) == 0)
+ break;
+ }
+ if (pnv != NULL) {
+ TAILQ_REMOVE(&proto_nvpairs, pnv, pnv_next);
+ free(pnv->pnv_value);
+ } else {
+ pnv = malloc(sizeof(*pnv));
+ if (pnv == NULL)
+ return (-1);
+ pnv->pnv_name = strdup(name);
+ if (pnv->pnv_name == NULL) {
+ free(pnv);
+ return (-1);
+ }
+ }
+ pnv->pnv_value = strdup(value);
+ if (pnv->pnv_value == NULL) {
+ free(pnv->pnv_name);
+ free(pnv);
+ return (-1);
+ }
+ TAILQ_INSERT_TAIL(&proto_nvpairs, pnv, pnv_next);
+ return (0);
+}
+
+const char *
+proto_get(const char *name)
+{
+ struct proto_nvpair *pnv;
+
+ TAILQ_FOREACH(pnv, &proto_nvpairs, pnv_next) {
+ if (strcmp(pnv->pnv_name, name) == 0)
+ break;
+ }
+ if (pnv != NULL)
+ return (pnv->pnv_value);
+ return (NULL);
+}
diff --git a/contrib/openbsm/bin/auditdistd/proto.h b/contrib/openbsm/bin/auditdistd/proto.h
new file mode 100644
index 0000000..f26c0ad
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/proto.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _PROTO_H_
+#define _PROTO_H_
+
+#include <stdbool.h> /* bool */
+#include <stdlib.h> /* size_t */
+
+struct proto_conn;
+
+int proto_connect(const char *srcaddr, const char *dstaddr, int timeout,
+ struct proto_conn **connp);
+int proto_connect_wait(struct proto_conn *conn, int timeout);
+int proto_server(const char *addr, struct proto_conn **connp);
+int proto_accept(struct proto_conn *conn, struct proto_conn **newconnp);
+int proto_send(const struct proto_conn *conn, const void *data, size_t size);
+int proto_recv(const struct proto_conn *conn, void *data, size_t size);
+int proto_connection_send(const struct proto_conn *conn,
+ struct proto_conn *mconn);
+int proto_connection_recv(const struct proto_conn *conn, bool client,
+ struct proto_conn **newconnp);
+int proto_descriptor(const struct proto_conn *conn);
+bool proto_address_match(const struct proto_conn *conn, const char *addr);
+void proto_local_address(const struct proto_conn *conn, char *addr,
+ size_t size);
+void proto_remote_address(const struct proto_conn *conn, char *addr,
+ size_t size);
+int proto_timeout(const struct proto_conn *conn, int timeout);
+void proto_close(struct proto_conn *conn);
+int proto_exec(int argc, char *argv[]);
+int proto_set(const char *name, const char *value);
+const char *proto_get(const char *name);
+
+#endif /* !_PROTO_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/proto_common.c b/contrib/openbsm/bin/auditdistd/proto_common.c
new file mode 100644
index 0000000..acd2294
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/proto_common.c
@@ -0,0 +1,231 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <compat/compat.h>
+
+#include "pjdlog.h"
+#include "proto_impl.h"
+
+/* Maximum size of packet we want to use when sending data. */
+#ifndef MAX_SEND_SIZE
+#define MAX_SEND_SIZE 32768
+#endif
+
+static bool
+blocking_socket(int sock)
+{
+ int flags;
+
+ flags = fcntl(sock, F_GETFL);
+ PJDLOG_ASSERT(flags >= 0);
+ return ((flags & O_NONBLOCK) == 0);
+}
+
+static int
+proto_descriptor_send(int sock, int fd)
+{
+ unsigned char ctrl[CMSG_SPACE(sizeof(fd))];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(fd >= 0);
+
+ bzero(&msg, sizeof(msg));
+ bzero(&ctrl, sizeof(ctrl));
+
+ msg.msg_iov = NULL;
+ msg.msg_iovlen = 0;
+ msg.msg_control = ctrl;
+ msg.msg_controllen = sizeof(ctrl);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
+
+ if (sendmsg(sock, &msg, 0) == -1)
+ return (errno);
+
+ return (0);
+}
+
+int
+proto_common_send(int sock, const unsigned char *data, size_t size, int fd)
+{
+ ssize_t done;
+ size_t sendsize;
+ int errcount = 0;
+
+ PJDLOG_ASSERT(sock >= 0);
+
+ if (data == NULL) {
+ /* The caller is just trying to decide about direction. */
+
+ PJDLOG_ASSERT(size == 0);
+
+ if (shutdown(sock, SHUT_RD) == -1)
+ return (errno);
+ return (0);
+ }
+
+ PJDLOG_ASSERT(data != NULL);
+ PJDLOG_ASSERT(size > 0);
+
+ do {
+ sendsize = size < MAX_SEND_SIZE ? size : MAX_SEND_SIZE;
+ done = send(sock, data, sendsize, MSG_NOSIGNAL);
+ if (done == 0) {
+ return (ENOTCONN);
+ } else if (done < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == ENOBUFS) {
+ /*
+ * If there are no buffers we retry.
+ * After each try we increase delay before the
+ * next one and we give up after fifteen times.
+ * This gives 11s of total wait time.
+ */
+ if (errcount == 15) {
+ pjdlog_warning("Getting ENOBUFS errors for 11s on send(), giving up.");
+ } else {
+ if (errcount == 0)
+ pjdlog_warning("Got ENOBUFS error on send(), retrying for a bit.");
+ errcount++;
+ usleep(100000 * errcount);
+ continue;
+ }
+ }
+ /*
+ * If this is blocking socket and we got EAGAIN, this
+ * means the request timed out. Translate errno to
+ * ETIMEDOUT, to give administrator a hint to
+ * eventually increase timeout.
+ */
+ if (errno == EAGAIN && blocking_socket(sock))
+ errno = ETIMEDOUT;
+ return (errno);
+ }
+ data += done;
+ size -= done;
+ } while (size > 0);
+ if (errcount > 0) {
+ pjdlog_info("Data sent successfully after %d ENOBUFS error%s.",
+ errcount, errcount == 1 ? "" : "s");
+ }
+
+ if (fd == -1)
+ return (0);
+ return (proto_descriptor_send(sock, fd));
+}
+
+static int
+proto_descriptor_recv(int sock, int *fdp)
+{
+ unsigned char ctrl[CMSG_SPACE(sizeof(*fdp))];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(fdp != NULL);
+
+ bzero(&msg, sizeof(msg));
+ bzero(&ctrl, sizeof(ctrl));
+
+ msg.msg_iov = NULL;
+ msg.msg_iovlen = 0;
+ msg.msg_control = ctrl;
+ msg.msg_controllen = sizeof(ctrl);
+
+ if (recvmsg(sock, &msg, 0) == -1)
+ return (errno);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg->cmsg_level != SOL_SOCKET ||
+ cmsg->cmsg_type != SCM_RIGHTS) {
+ return (EINVAL);
+ }
+ bcopy(CMSG_DATA(cmsg), fdp, sizeof(*fdp));
+
+ return (0);
+}
+
+int
+proto_common_recv(int sock, unsigned char *data, size_t size, int *fdp)
+{
+ ssize_t done;
+
+ PJDLOG_ASSERT(sock >= 0);
+
+ if (data == NULL) {
+ /* The caller is just trying to decide about direction. */
+
+ PJDLOG_ASSERT(size == 0);
+
+ if (shutdown(sock, SHUT_WR) == -1)
+ return (errno);
+ return (0);
+ }
+
+ PJDLOG_ASSERT(data != NULL);
+ PJDLOG_ASSERT(size > 0);
+
+ do {
+ done = recv(sock, data, size, MSG_WAITALL);
+ } while (done == -1 && errno == EINTR);
+ if (done == 0) {
+ return (ENOTCONN);
+ } else if (done < 0) {
+ /*
+ * If this is blocking socket and we got EAGAIN, this
+ * means the request timed out. Translate errno to
+ * ETIMEDOUT, to give administrator a hint to
+ * eventually increase timeout.
+ */
+ if (errno == EAGAIN && blocking_socket(sock))
+ errno = ETIMEDOUT;
+ return (errno);
+ }
+ if (fdp == NULL)
+ return (0);
+ return (proto_descriptor_recv(sock, fdp));
+}
diff --git a/contrib/openbsm/bin/auditdistd/proto_impl.h b/contrib/openbsm/bin/auditdistd/proto_impl.h
new file mode 100644
index 0000000..7915ee9
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/proto_impl.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _PROTO_IMPL_H_
+#define _PROTO_IMPL_H_
+
+#include <sys/queue.h>
+
+#include <stdbool.h> /* bool */
+#include <stdlib.h> /* size_t */
+
+#define __constructor __attribute__((constructor))
+
+struct proto_conn;
+
+typedef int prt_connect_t(const char *, const char *, int, void **);
+typedef int prt_connect_wait_t(void *, int);
+typedef int prt_server_t(const char *, void **);
+typedef int prt_accept_t(void *, void **);
+typedef int prt_wrap_t(int, bool, void **);
+typedef int prt_send_t(void *, const unsigned char *, size_t, int);
+typedef int prt_recv_t(void *, unsigned char *, size_t, int *);
+typedef int prt_descriptor_t(const void *);
+typedef bool prt_address_match_t(const void *, const char *);
+typedef void prt_local_address_t(const void *, char *, size_t);
+typedef void prt_remote_address_t(const void *, char *, size_t);
+typedef void prt_close_t(void *);
+typedef int prt_exec_t(int, char *[]);
+
+struct proto {
+ const char *prt_name;
+ prt_connect_t *prt_connect;
+ prt_connect_wait_t *prt_connect_wait;
+ prt_server_t *prt_server;
+ prt_accept_t *prt_accept;
+ prt_wrap_t *prt_wrap;
+ prt_send_t *prt_send;
+ prt_recv_t *prt_recv;
+ prt_descriptor_t *prt_descriptor;
+ prt_address_match_t *prt_address_match;
+ prt_local_address_t *prt_local_address;
+ prt_remote_address_t *prt_remote_address;
+ prt_close_t *prt_close;
+ prt_exec_t *prt_exec;
+ TAILQ_ENTRY(proto) prt_next;
+};
+
+void proto_register(struct proto *proto, bool isdefault);
+
+int proto_wrap(const char *protoname, bool client, int fd,
+ struct proto_conn **newconnp);
+
+int proto_common_send(int sock, const unsigned char *data, size_t size, int fd);
+int proto_common_recv(int sock, unsigned char *data, size_t size, int *fdp);
+
+#endif /* !_PROTO_IMPL_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/proto_socketpair.c b/contrib/openbsm/bin/auditdistd/proto_socketpair.c
new file mode 100644
index 0000000..fc65c76
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/proto_socketpair.c
@@ -0,0 +1,264 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pjdlog.h"
+#include "proto_impl.h"
+
+#define SP_CTX_MAGIC 0x50c3741
+struct sp_ctx {
+ int sp_magic;
+ int sp_fd[2];
+ int sp_side;
+#define SP_SIDE_UNDEF 0
+#define SP_SIDE_CLIENT 1
+#define SP_SIDE_SERVER 2
+};
+
+static void sp_close(void *ctx);
+
+static int
+sp_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp)
+{
+ struct sp_ctx *spctx;
+ int error;
+
+ PJDLOG_ASSERT(dstaddr != NULL);
+ PJDLOG_ASSERT(timeout >= -1);
+
+ if (strcmp(dstaddr, "socketpair://") != 0)
+ return (-1);
+
+ PJDLOG_ASSERT(srcaddr == NULL);
+
+ spctx = malloc(sizeof(*spctx));
+ if (spctx == NULL)
+ return (errno);
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) {
+ error = errno;
+ free(spctx);
+ return (error);
+ }
+
+ spctx->sp_side = SP_SIDE_UNDEF;
+ spctx->sp_magic = SP_CTX_MAGIC;
+ *ctxp = spctx;
+
+ return (0);
+}
+
+static int
+sp_wrap(int fd, bool client, void **ctxp)
+{
+ struct sp_ctx *spctx;
+
+ PJDLOG_ASSERT(fd >= 0);
+
+ spctx = malloc(sizeof(*spctx));
+ if (spctx == NULL)
+ return (errno);
+
+ if (client) {
+ spctx->sp_side = SP_SIDE_CLIENT;
+ spctx->sp_fd[0] = fd;
+ spctx->sp_fd[1] = -1;
+ } else {
+ spctx->sp_side = SP_SIDE_SERVER;
+ spctx->sp_fd[0] = -1;
+ spctx->sp_fd[1] = fd;
+ }
+ spctx->sp_magic = SP_CTX_MAGIC;
+ *ctxp = spctx;
+
+ return (0);
+}
+
+static int
+sp_send(void *ctx, const unsigned char *data, size_t size, int fd)
+{
+ struct sp_ctx *spctx = ctx;
+ int sock;
+
+ PJDLOG_ASSERT(spctx != NULL);
+ PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
+
+ switch (spctx->sp_side) {
+ case SP_SIDE_UNDEF:
+ /*
+ * If the first operation done by the caller is proto_send(),
+ * we assume this is the client.
+ */
+ /* FALLTHROUGH */
+ spctx->sp_side = SP_SIDE_CLIENT;
+ /* Close other end. */
+ close(spctx->sp_fd[1]);
+ spctx->sp_fd[1] = -1;
+ case SP_SIDE_CLIENT:
+ PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
+ sock = spctx->sp_fd[0];
+ break;
+ case SP_SIDE_SERVER:
+ PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
+ sock = spctx->sp_fd[1];
+ break;
+ default:
+ PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
+ }
+
+ /* Someone is just trying to decide about side. */
+ if (data == NULL)
+ return (0);
+
+ return (proto_common_send(sock, data, size, fd));
+}
+
+static int
+sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
+{
+ struct sp_ctx *spctx = ctx;
+ int sock;
+
+ PJDLOG_ASSERT(spctx != NULL);
+ PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
+
+ switch (spctx->sp_side) {
+ case SP_SIDE_UNDEF:
+ /*
+ * If the first operation done by the caller is proto_recv(),
+ * we assume this is the server.
+ */
+ /* FALLTHROUGH */
+ spctx->sp_side = SP_SIDE_SERVER;
+ /* Close other end. */
+ close(spctx->sp_fd[0]);
+ spctx->sp_fd[0] = -1;
+ case SP_SIDE_SERVER:
+ PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
+ sock = spctx->sp_fd[1];
+ break;
+ case SP_SIDE_CLIENT:
+ PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
+ sock = spctx->sp_fd[0];
+ break;
+ default:
+ PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
+ }
+
+ /* Someone is just trying to decide about side. */
+ if (data == NULL)
+ return (0);
+
+ return (proto_common_recv(sock, data, size, fdp));
+}
+
+static int
+sp_descriptor(const void *ctx)
+{
+ const struct sp_ctx *spctx = ctx;
+
+ PJDLOG_ASSERT(spctx != NULL);
+ PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
+ PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
+ spctx->sp_side == SP_SIDE_SERVER);
+
+ switch (spctx->sp_side) {
+ case SP_SIDE_CLIENT:
+ PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
+ return (spctx->sp_fd[0]);
+ case SP_SIDE_SERVER:
+ PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
+ return (spctx->sp_fd[1]);
+ }
+
+ PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
+}
+
+static void
+sp_close(void *ctx)
+{
+ struct sp_ctx *spctx = ctx;
+
+ PJDLOG_ASSERT(spctx != NULL);
+ PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
+
+ switch (spctx->sp_side) {
+ case SP_SIDE_UNDEF:
+ PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
+ close(spctx->sp_fd[0]);
+ spctx->sp_fd[0] = -1;
+ PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
+ close(spctx->sp_fd[1]);
+ spctx->sp_fd[1] = -1;
+ break;
+ case SP_SIDE_CLIENT:
+ PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
+ close(spctx->sp_fd[0]);
+ spctx->sp_fd[0] = -1;
+ PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
+ break;
+ case SP_SIDE_SERVER:
+ PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
+ close(spctx->sp_fd[1]);
+ spctx->sp_fd[1] = -1;
+ PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
+ break;
+ default:
+ PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
+ }
+
+ spctx->sp_magic = 0;
+ free(spctx);
+}
+
+static struct proto sp_proto = {
+ .prt_name = "socketpair",
+ .prt_connect = sp_connect,
+ .prt_wrap = sp_wrap,
+ .prt_send = sp_send,
+ .prt_recv = sp_recv,
+ .prt_descriptor = sp_descriptor,
+ .prt_close = sp_close
+};
+
+static __constructor void
+sp_ctor(void)
+{
+
+ proto_register(&sp_proto, false);
+}
diff --git a/contrib/openbsm/bin/auditdistd/proto_tcp.c b/contrib/openbsm/bin/auditdistd/proto_tcp.c
new file mode 100644
index 0000000..465221d
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/proto_tcp.c
@@ -0,0 +1,721 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config/config.h>
+
+#include <sys/param.h> /* MAXHOSTNAMELEN */
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HAVE_STRLCPY
+#include <compat/strlcpy.h>
+#endif
+
+#include "pjdlog.h"
+#include "proto_impl.h"
+#include "subr.h"
+
+#define TCP_CTX_MAGIC 0x7c41c
+struct tcp_ctx {
+ int tc_magic;
+ struct sockaddr_storage tc_sa;
+ int tc_fd;
+ int tc_side;
+#define TCP_SIDE_CLIENT 0
+#define TCP_SIDE_SERVER_LISTEN 1
+#define TCP_SIDE_SERVER_WORK 2
+ bool tc_wait_called;
+};
+
+static int tcp_connect_wait(void *ctx, int timeout);
+static void tcp_close(void *ctx);
+
+/*
+ * Function converts the given string to unsigned number.
+ */
+static int
+numfromstr(const char *str, intmax_t minnum, intmax_t maxnum, intmax_t *nump)
+{
+ intmax_t digit, num;
+
+ if (str[0] == '\0')
+ goto invalid; /* Empty string. */
+ num = 0;
+ for (; *str != '\0'; str++) {
+ if (*str < '0' || *str > '9')
+ goto invalid; /* Non-digit character. */
+ digit = *str - '0';
+ if (num > num * 10 + digit)
+ goto invalid; /* Overflow. */
+ num = num * 10 + digit;
+ if (num > maxnum)
+ goto invalid; /* Too big. */
+ }
+ if (num < minnum)
+ goto invalid; /* Too small. */
+ *nump = num;
+ return (0);
+invalid:
+ errno = EINVAL;
+ return (-1);
+}
+
+static int
+tcp_addr(const char *addr, int defport, struct sockaddr_storage *sap)
+{
+ char iporhost[MAXHOSTNAMELEN], portstr[6];
+ struct addrinfo hints;
+ struct addrinfo *res;
+ const char *pp;
+ intmax_t port;
+ size_t size;
+ int error;
+
+ if (addr == NULL)
+ return (-1);
+
+ bzero(&hints, sizeof(hints));
+ hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ if (strncasecmp(addr, "tcp4://", 7) == 0) {
+ addr += 7;
+ hints.ai_family = PF_INET;
+ } else if (strncasecmp(addr, "tcp6://", 7) == 0) {
+ addr += 7;
+ hints.ai_family = PF_INET6;
+ } else if (strncasecmp(addr, "tcp://", 6) == 0) {
+ addr += 6;
+ } else {
+ /*
+ * Because TCP is the default assume IP or host is given without
+ * prefix.
+ */
+ }
+
+ /*
+ * Extract optional port.
+ * There are three cases to consider.
+ * 1. hostname with port, eg. freefall.freebsd.org:8457
+ * 2. IPv4 address with port, eg. 192.168.0.101:8457
+ * 3. IPv6 address with port, eg. [fe80::1]:8457
+ * We discover IPv6 address by checking for two colons and if port is
+ * given, the address has to start with [.
+ */
+ pp = NULL;
+ if (strchr(addr, ':') != strrchr(addr, ':')) {
+ if (addr[0] == '[')
+ pp = strrchr(addr, ':');
+ } else {
+ pp = strrchr(addr, ':');
+ }
+ if (pp == NULL) {
+ /* Port not given, use the default. */
+ port = defport;
+ } else {
+ if (numfromstr(pp + 1, 1, 65535, &port) < 0)
+ return (errno);
+ }
+ (void)snprintf(portstr, sizeof(portstr), "%jd", (intmax_t)port);
+ /* Extract host name or IP address. */
+ if (pp == NULL) {
+ size = sizeof(iporhost);
+ if (strlcpy(iporhost, addr, size) >= size)
+ return (ENAMETOOLONG);
+ } else if (addr[0] == '[' && pp[-1] == ']') {
+ size = (size_t)(pp - addr - 2 + 1);
+ if (size > sizeof(iporhost))
+ return (ENAMETOOLONG);
+ (void)strlcpy(iporhost, addr + 1, size);
+ } else {
+ size = (size_t)(pp - addr + 1);
+ if (size > sizeof(iporhost))
+ return (ENAMETOOLONG);
+ (void)strlcpy(iporhost, addr, size);
+ }
+
+ error = getaddrinfo(iporhost, portstr, &hints, &res);
+ if (error != 0) {
+ pjdlog_debug(1, "getaddrinfo(%s, %s) failed: %s.", iporhost,
+ portstr, gai_strerror(error));
+ return (EINVAL);
+ }
+ if (res == NULL)
+ return (ENOENT);
+
+ memcpy(sap, res->ai_addr, res->ai_addrlen);
+
+ freeaddrinfo(res);
+
+ return (0);
+}
+
+static int
+tcp_setup_new(const char *addr, int side, struct tcp_ctx **tctxp)
+{
+ struct tcp_ctx *tctx;
+ int error, nodelay;
+
+ PJDLOG_ASSERT(addr != NULL);
+ PJDLOG_ASSERT(side == TCP_SIDE_CLIENT ||
+ side == TCP_SIDE_SERVER_LISTEN);
+ PJDLOG_ASSERT(tctxp != NULL);
+
+ tctx = malloc(sizeof(*tctx));
+ if (tctx == NULL)
+ return (errno);
+
+ /* Parse given address. */
+ error = tcp_addr(addr, atoi(proto_get("tcp:port")), &tctx->tc_sa);
+ if (error != 0) {
+ free(tctx);
+ return (error);
+ }
+
+ PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
+
+ tctx->tc_fd = socket(tctx->tc_sa.ss_family, SOCK_STREAM, 0);
+ if (tctx->tc_fd == -1) {
+ error = errno;
+ free(tctx);
+ return (error);
+ }
+
+ PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
+
+ /* Socket settings. */
+ nodelay = 1;
+ if (setsockopt(tctx->tc_fd, IPPROTO_TCP, TCP_NODELAY, &nodelay,
+ sizeof(nodelay)) == -1) {
+ pjdlog_errno(LOG_WARNING, "Unable to set TCP_NOELAY");
+ }
+
+ tctx->tc_wait_called = (side == TCP_SIDE_CLIENT ? false : true);
+ tctx->tc_side = side;
+ tctx->tc_magic = TCP_CTX_MAGIC;
+ *tctxp = tctx;
+
+ return (0);
+}
+
+static socklen_t
+sockaddr_len(const struct sockaddr_storage *ss)
+{
+
+#ifdef HAVE_SOCKADDR_STORAGE_SS_LEN
+ return (ss->ss_len);
+#else
+ switch (ss->ss_family) {
+ case AF_INET:
+ return (sizeof(struct sockaddr_in));
+ case AF_INET6:
+ return (sizeof(struct sockaddr_in6));
+ default:
+ PJDLOG_ABORT("Unexpected family %hhu.", ss->ss_family);
+ }
+#endif
+}
+
+static int
+tcp_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp)
+{
+ struct tcp_ctx *tctx;
+ struct sockaddr_storage sa;
+ int error, flags, ret;
+
+ PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0');
+ PJDLOG_ASSERT(dstaddr != NULL);
+ PJDLOG_ASSERT(timeout >= -1);
+
+ error = tcp_setup_new(dstaddr, TCP_SIDE_CLIENT, &tctx);
+ if (error != 0)
+ return (error);
+ if (srcaddr != NULL) {
+ error = tcp_addr(srcaddr, 0, &sa);
+ if (error != 0)
+ goto fail;
+ if (bind(tctx->tc_fd, (struct sockaddr *)&sa,
+ sockaddr_len(&sa)) == -1) {
+ error = errno;
+ goto fail;
+ }
+ }
+
+ flags = fcntl(tctx->tc_fd, F_GETFL);
+ if (flags == -1) {
+ error = errno;
+ pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed");
+ goto fail;
+ }
+ /*
+ * We make socket non-blocking so we can handle connection timeout
+ * manually.
+ */
+ flags |= O_NONBLOCK;
+ if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) {
+ error = errno;
+ pjdlog_common(LOG_DEBUG, 1, errno,
+ "fcntl(F_SETFL, O_NONBLOCK) failed");
+ goto fail;
+ }
+
+ ret = connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa,
+ sockaddr_len(&tctx->tc_sa));
+ if (ret == -1 && errno != EINPROGRESS) {
+ error = errno;
+ pjdlog_common(LOG_DEBUG, 1, errno, "connect() failed");
+ goto fail;
+ }
+
+ if (timeout >= 0) {
+ if (ret == -1) {
+ /* Connection still in progress. Wait for it. */
+ error = tcp_connect_wait(tctx, timeout);
+ if (error != 0)
+ goto fail;
+ } else {
+ /* Connection already complete. */
+ flags &= ~O_NONBLOCK;
+ if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) {
+ error = errno;
+ pjdlog_common(LOG_DEBUG, 1, errno,
+ "fcntl(F_SETFL, ~O_NONBLOCK) failed");
+ goto fail;
+ }
+ }
+ }
+
+ *ctxp = tctx;
+ return (0);
+fail:
+ tcp_close(tctx);
+ return (error);
+}
+
+static int
+tcp_connect_wait(void *ctx, int timeout)
+{
+ struct tcp_ctx *tctx = ctx;
+ struct timeval tv;
+ fd_set fdset;
+ socklen_t esize;
+ int error, flags, ret;
+
+ PJDLOG_ASSERT(tctx != NULL);
+ PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+ PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT);
+ PJDLOG_ASSERT(!tctx->tc_wait_called);
+ PJDLOG_ASSERT(tctx->tc_fd >= 0);
+ PJDLOG_ASSERT(timeout >= 0);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+again:
+ FD_ZERO(&fdset);
+ FD_SET(tctx->tc_fd, &fdset);
+ ret = select(tctx->tc_fd + 1, NULL, &fdset, NULL, &tv);
+ if (ret == 0) {
+ error = ETIMEDOUT;
+ goto done;
+ } else if (ret == -1) {
+ if (errno == EINTR)
+ goto again;
+ error = errno;
+ pjdlog_common(LOG_DEBUG, 1, errno, "select() failed");
+ goto done;
+ }
+ PJDLOG_ASSERT(ret > 0);
+ PJDLOG_ASSERT(FD_ISSET(tctx->tc_fd, &fdset));
+ esize = sizeof(error);
+ if (getsockopt(tctx->tc_fd, SOL_SOCKET, SO_ERROR, &error,
+ &esize) == -1) {
+ error = errno;
+ pjdlog_common(LOG_DEBUG, 1, errno,
+ "getsockopt(SO_ERROR) failed");
+ goto done;
+ }
+ if (error != 0) {
+ pjdlog_common(LOG_DEBUG, 1, error,
+ "getsockopt(SO_ERROR) returned error");
+ goto done;
+ }
+ error = 0;
+ tctx->tc_wait_called = true;
+done:
+ flags = fcntl(tctx->tc_fd, F_GETFL);
+ if (flags == -1) {
+ if (error == 0)
+ error = errno;
+ pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed");
+ return (error);
+ }
+ flags &= ~O_NONBLOCK;
+ if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) {
+ if (error == 0)
+ error = errno;
+ pjdlog_common(LOG_DEBUG, 1, errno,
+ "fcntl(F_SETFL, ~O_NONBLOCK) failed");
+ }
+ return (error);
+}
+
+static int
+tcp_server(const char *addr, void **ctxp)
+{
+ struct tcp_ctx *tctx;
+ int error, val;
+
+ error = tcp_setup_new(addr, TCP_SIDE_SERVER_LISTEN, &tctx);
+ if (error != 0)
+ return (error);
+
+ val = 1;
+ /* Ignore failure. */
+ (void)setsockopt(tctx->tc_fd, SOL_SOCKET, SO_REUSEADDR, &val,
+ sizeof(val));
+
+ PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
+
+ if (bind(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa,
+ sockaddr_len(&tctx->tc_sa)) == -1) {
+ error = errno;
+ tcp_close(tctx);
+ return (error);
+ }
+ if (listen(tctx->tc_fd, 8) == -1) {
+ error = errno;
+ tcp_close(tctx);
+ return (error);
+ }
+
+ *ctxp = tctx;
+
+ return (0);
+}
+
+static int
+tcp_accept(void *ctx, void **newctxp)
+{
+ struct tcp_ctx *tctx = ctx;
+ struct tcp_ctx *newtctx;
+ socklen_t fromlen;
+ int ret;
+
+ PJDLOG_ASSERT(tctx != NULL);
+ PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+ PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_SERVER_LISTEN);
+ PJDLOG_ASSERT(tctx->tc_fd >= 0);
+ PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
+
+ newtctx = malloc(sizeof(*newtctx));
+ if (newtctx == NULL)
+ return (errno);
+
+ fromlen = sockaddr_len(&tctx->tc_sa);
+ newtctx->tc_fd = accept(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa,
+ &fromlen);
+ if (newtctx->tc_fd < 0) {
+ ret = errno;
+ free(newtctx);
+ return (ret);
+ }
+
+ newtctx->tc_wait_called = true;
+ newtctx->tc_side = TCP_SIDE_SERVER_WORK;
+ newtctx->tc_magic = TCP_CTX_MAGIC;
+ *newctxp = newtctx;
+
+ return (0);
+}
+
+static int
+tcp_wrap(int fd, bool client, void **ctxp)
+{
+ struct tcp_ctx *tctx;
+
+ PJDLOG_ASSERT(fd >= 0);
+ PJDLOG_ASSERT(ctxp != NULL);
+
+ tctx = malloc(sizeof(*tctx));
+ if (tctx == NULL)
+ return (errno);
+
+ tctx->tc_fd = fd;
+ tctx->tc_sa.ss_family = AF_UNSPEC;
+ tctx->tc_wait_called = (client ? false : true);
+ tctx->tc_side = (client ? TCP_SIDE_CLIENT : TCP_SIDE_SERVER_WORK);
+ tctx->tc_magic = TCP_CTX_MAGIC;
+ *ctxp = tctx;
+
+ return (0);
+}
+
+static int
+tcp_send(void *ctx, const unsigned char *data, size_t size, int fd)
+{
+ struct tcp_ctx *tctx = ctx;
+
+ PJDLOG_ASSERT(tctx != NULL);
+ PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+ PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT ||
+ tctx->tc_side == TCP_SIDE_SERVER_WORK);
+ PJDLOG_ASSERT(tctx->tc_wait_called);
+ PJDLOG_ASSERT(tctx->tc_fd >= 0);
+ PJDLOG_ASSERT(fd == -1);
+
+ return (proto_common_send(tctx->tc_fd, data, size, -1));
+}
+
+static int
+tcp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
+{
+ struct tcp_ctx *tctx = ctx;
+
+ PJDLOG_ASSERT(tctx != NULL);
+ PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+ PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT ||
+ tctx->tc_side == TCP_SIDE_SERVER_WORK);
+ PJDLOG_ASSERT(tctx->tc_wait_called);
+ PJDLOG_ASSERT(tctx->tc_fd >= 0);
+ PJDLOG_ASSERT(fdp == NULL);
+
+ return (proto_common_recv(tctx->tc_fd, data, size, NULL));
+}
+
+static int
+tcp_descriptor(const void *ctx)
+{
+ const struct tcp_ctx *tctx = ctx;
+
+ PJDLOG_ASSERT(tctx != NULL);
+ PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+
+ return (tctx->tc_fd);
+}
+
+static bool
+tcp_address_match(const void *ctx, const char *addr)
+{
+ const struct tcp_ctx *tctx = ctx;
+ struct sockaddr_storage sa1, sa2;
+ socklen_t salen;
+
+ PJDLOG_ASSERT(tctx != NULL);
+ PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+
+ if (tcp_addr(addr, atoi(proto_get("tcp:port")), &sa1) != 0)
+ return (false);
+
+ salen = sizeof(sa2);
+ if (getpeername(tctx->tc_fd, (struct sockaddr *)&sa2, &salen) < 0)
+ return (false);
+
+ if (sa1.ss_family != sa2.ss_family)
+ return (false);
+
+#ifdef HAVE_SOCKADDR_STORAGE_SS_LEN
+ if (sa1.ss_len != sa2.ss_len)
+ return (false);
+#endif
+
+ switch (sa1.ss_family) {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin1, *sin2;
+
+ sin1 = (struct sockaddr_in *)&sa1;
+ sin2 = (struct sockaddr_in *)&sa2;
+
+ return (memcmp(&sin1->sin_addr, &sin2->sin_addr,
+ sizeof(sin1->sin_addr)) == 0);
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin1, *sin2;
+
+ sin1 = (struct sockaddr_in6 *)&sa1;
+ sin2 = (struct sockaddr_in6 *)&sa2;
+
+ return (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
+ sizeof(sin1->sin6_addr)) == 0);
+ }
+ default:
+ return (false);
+ }
+}
+
+#ifndef __FreeBSD__
+static void
+sockaddr_to_string(const void *sa, char *buf, size_t size)
+{
+ const struct sockaddr_storage *ss;
+
+ ss = (const struct sockaddr_storage * const *)sa;
+ switch (ss->ss_family) {
+ case AF_INET:
+ {
+ char addr[INET_ADDRSTRLEN];
+ const struct sockaddr_in *sin;
+ unsigned int port;
+
+ sin = (const struct sockaddr_in *)ss;
+ port = ntohs(sin->sin_port);
+ if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
+ sizeof(addr)) == NULL) {
+ PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
+ strerror(errno));
+ }
+ snprintf(buf, size, "%s:%u", addr, port);
+ break;
+ }
+ case AF_INET6:
+ {
+ char addr[INET6_ADDRSTRLEN];
+ const struct sockaddr_in6 *sin;
+ unsigned int port;
+
+ sin = (const struct sockaddr_in6 *)ss;
+ port = ntohs(sin->sin6_port);
+ if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
+ sizeof(addr)) == NULL) {
+ PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
+ strerror(errno));
+ }
+ snprintf(buf, size, "[%s]:%u", addr, port);
+ break;
+ }
+ default:
+ snprintf(buf, size, "[unsupported family %hhu]",
+ ss->ss_family);
+ break;
+ }
+}
+#endif /* !__FreeBSD__ */
+
+static void
+tcp_local_address(const void *ctx, char *addr, size_t size)
+{
+ const struct tcp_ctx *tctx = ctx;
+ struct sockaddr_storage sa;
+ socklen_t salen;
+
+ PJDLOG_ASSERT(tctx != NULL);
+ PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+
+ salen = sizeof(sa);
+ if (getsockname(tctx->tc_fd, (struct sockaddr *)&sa, &salen) < 0) {
+ PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
+ return;
+ }
+#ifdef __FreeBSD__
+ PJDLOG_VERIFY(snprintf(addr, size, "tcp://%S", &sa) < (ssize_t)size);
+#else
+ strlcpy(addr, "tcp://", size);
+ if (size > 6)
+ sockaddr_to_string(&sa, addr + 6, size - 6);
+#endif
+}
+
+static void
+tcp_remote_address(const void *ctx, char *addr, size_t size)
+{
+ const struct tcp_ctx *tctx = ctx;
+ struct sockaddr_storage sa;
+ socklen_t salen;
+
+ PJDLOG_ASSERT(tctx != NULL);
+ PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+
+ salen = sizeof(sa);
+ if (getpeername(tctx->tc_fd, (struct sockaddr *)&sa, &salen) < 0) {
+ PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
+ return;
+ }
+#ifdef __FreeBSD__
+ PJDLOG_VERIFY(snprintf(addr, size, "tcp://%S", &sa) < (ssize_t)size);
+#else
+ strlcpy(addr, "tcp://", size);
+ if (size > 6)
+ sockaddr_to_string(&sa, addr + 6, size - 6);
+#endif
+}
+
+static void
+tcp_close(void *ctx)
+{
+ struct tcp_ctx *tctx = ctx;
+
+ PJDLOG_ASSERT(tctx != NULL);
+ PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+
+ if (tctx->tc_fd >= 0)
+ close(tctx->tc_fd);
+ tctx->tc_magic = 0;
+ free(tctx);
+}
+
+static struct proto tcp_proto = {
+ .prt_name = "tcp",
+ .prt_connect = tcp_connect,
+ .prt_connect_wait = tcp_connect_wait,
+ .prt_server = tcp_server,
+ .prt_accept = tcp_accept,
+ .prt_wrap = tcp_wrap,
+ .prt_send = tcp_send,
+ .prt_recv = tcp_recv,
+ .prt_descriptor = tcp_descriptor,
+ .prt_address_match = tcp_address_match,
+ .prt_local_address = tcp_local_address,
+ .prt_remote_address = tcp_remote_address,
+ .prt_close = tcp_close
+};
+
+static __constructor void
+tcp_ctor(void)
+{
+
+ proto_register(&tcp_proto, true);
+}
diff --git a/contrib/openbsm/bin/auditdistd/proto_tls.c b/contrib/openbsm/bin/auditdistd/proto_tls.c
new file mode 100644
index 0000000..de89147
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/proto_tls.c
@@ -0,0 +1,1074 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config/config.h>
+
+#include <sys/param.h> /* MAXHOSTNAMELEN */
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
+#include <compat/compat.h>
+#ifndef HAVE_CLOSEFROM
+#include <compat/closefrom.h>
+#endif
+#ifndef HAVE_STRLCPY
+#include <compat/strlcpy.h>
+#endif
+
+#include "pjdlog.h"
+#include "proto_impl.h"
+#include "sandbox.h"
+#include "subr.h"
+
+#define TLS_CTX_MAGIC 0x715c7
+struct tls_ctx {
+ int tls_magic;
+ struct proto_conn *tls_sock;
+ struct proto_conn *tls_tcp;
+ char tls_laddr[256];
+ char tls_raddr[256];
+ int tls_side;
+#define TLS_SIDE_CLIENT 0
+#define TLS_SIDE_SERVER_LISTEN 1
+#define TLS_SIDE_SERVER_WORK 2
+ bool tls_wait_called;
+};
+
+#define TLS_DEFAULT_TIMEOUT 30
+
+static int tls_connect_wait(void *ctx, int timeout);
+static void tls_close(void *ctx);
+
+static void
+block(int fd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1)
+ pjdlog_exit(EX_TEMPFAIL, "fcntl(F_GETFL) failed");
+ flags &= ~O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "fcntl(F_SETFL) failed");
+}
+
+static void
+nonblock(int fd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1)
+ pjdlog_exit(EX_TEMPFAIL, "fcntl(F_GETFL) failed");
+ flags |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "fcntl(F_SETFL) failed");
+}
+
+static int
+wait_for_fd(int fd, int timeout)
+{
+ struct timeval tv;
+ fd_set fdset;
+ int error, ret;
+
+ error = 0;
+
+ for (;;) {
+ FD_ZERO(&fdset);
+ FD_SET(fd, &fdset);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ ret = select(fd + 1, NULL, &fdset, NULL,
+ timeout == -1 ? NULL : &tv);
+ if (ret == 0) {
+ error = ETIMEDOUT;
+ break;
+ } else if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ error = errno;
+ break;
+ }
+ PJDLOG_ASSERT(ret > 0);
+ PJDLOG_ASSERT(FD_ISSET(fd, &fdset));
+ break;
+ }
+
+ return (error);
+}
+
+static void
+ssl_log_errors(void)
+{
+ unsigned long error;
+
+ while ((error = ERR_get_error()) != 0)
+ pjdlog_error("SSL error: %s", ERR_error_string(error, NULL));
+}
+
+static int
+ssl_check_error(SSL *ssl, int ret)
+{
+ int error;
+
+ error = SSL_get_error(ssl, ret);
+
+ switch (error) {
+ case SSL_ERROR_NONE:
+ return (0);
+ case SSL_ERROR_WANT_READ:
+ pjdlog_debug(2, "SSL_ERROR_WANT_READ");
+ return (-1);
+ case SSL_ERROR_WANT_WRITE:
+ pjdlog_debug(2, "SSL_ERROR_WANT_WRITE");
+ return (-1);
+ case SSL_ERROR_ZERO_RETURN:
+ pjdlog_exitx(EX_OK, "Connection closed.");
+ case SSL_ERROR_SYSCALL:
+ ssl_log_errors();
+ pjdlog_exitx(EX_TEMPFAIL, "SSL I/O error.");
+ case SSL_ERROR_SSL:
+ ssl_log_errors();
+ pjdlog_exitx(EX_TEMPFAIL, "SSL protocol error.");
+ default:
+ ssl_log_errors();
+ pjdlog_exitx(EX_TEMPFAIL, "Unknown SSL error (%d).", error);
+ }
+}
+
+static void
+tcp_recv_ssl_send(int recvfd, SSL *sendssl)
+{
+ static unsigned char buf[65536];
+ ssize_t tcpdone;
+ int sendfd, ssldone;
+
+ sendfd = SSL_get_fd(sendssl);
+ PJDLOG_ASSERT(sendfd >= 0);
+ pjdlog_debug(2, "%s: start %d -> %d", __func__, recvfd, sendfd);
+ for (;;) {
+ tcpdone = recv(recvfd, buf, sizeof(buf), 0);
+ pjdlog_debug(2, "%s: recv() returned %zd", __func__, tcpdone);
+ if (tcpdone == 0) {
+ pjdlog_debug(1, "Connection terminated.");
+ exit(0);
+ } else if (tcpdone == -1) {
+ if (errno == EINTR)
+ continue;
+ else if (errno == EAGAIN)
+ break;
+ pjdlog_exit(EX_TEMPFAIL, "recv() failed");
+ }
+ for (;;) {
+ ssldone = SSL_write(sendssl, buf, (int)tcpdone);
+ pjdlog_debug(2, "%s: send() returned %d", __func__,
+ ssldone);
+ if (ssl_check_error(sendssl, ssldone) == -1) {
+ (void)wait_for_fd(sendfd, -1);
+ continue;
+ }
+ PJDLOG_ASSERT(ssldone == tcpdone);
+ break;
+ }
+ }
+ pjdlog_debug(2, "%s: done %d -> %d", __func__, recvfd, sendfd);
+}
+
+static void
+ssl_recv_tcp_send(SSL *recvssl, int sendfd)
+{
+ static unsigned char buf[65536];
+ unsigned char *ptr;
+ ssize_t tcpdone;
+ size_t todo;
+ int recvfd, ssldone;
+
+ recvfd = SSL_get_fd(recvssl);
+ PJDLOG_ASSERT(recvfd >= 0);
+ pjdlog_debug(2, "%s: start %d -> %d", __func__, recvfd, sendfd);
+ for (;;) {
+ ssldone = SSL_read(recvssl, buf, sizeof(buf));
+ pjdlog_debug(2, "%s: SSL_read() returned %d", __func__,
+ ssldone);
+ if (ssl_check_error(recvssl, ssldone) == -1)
+ break;
+ todo = (size_t)ssldone;
+ ptr = buf;
+ do {
+ tcpdone = send(sendfd, ptr, todo, MSG_NOSIGNAL);
+ pjdlog_debug(2, "%s: send() returned %zd", __func__,
+ tcpdone);
+ if (tcpdone == 0) {
+ pjdlog_debug(1, "Connection terminated.");
+ exit(0);
+ } else if (tcpdone == -1) {
+ if (errno == EINTR || errno == ENOBUFS)
+ continue;
+ if (errno == EAGAIN) {
+ (void)wait_for_fd(sendfd, -1);
+ continue;
+ }
+ pjdlog_exit(EX_TEMPFAIL, "send() failed");
+ }
+ todo -= tcpdone;
+ ptr += tcpdone;
+ } while (todo > 0);
+ }
+ pjdlog_debug(2, "%s: done %d -> %d", __func__, recvfd, sendfd);
+}
+
+static void
+tls_loop(int sockfd, SSL *tcpssl)
+{
+ fd_set fds;
+ int maxfd, tcpfd;
+
+ tcpfd = SSL_get_fd(tcpssl);
+ PJDLOG_ASSERT(tcpfd >= 0);
+
+ for (;;) {
+ FD_ZERO(&fds);
+ FD_SET(sockfd, &fds);
+ FD_SET(tcpfd, &fds);
+ maxfd = MAX(sockfd, tcpfd);
+
+ PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE);
+ if (select(maxfd + 1, &fds, NULL, NULL, NULL) == -1) {
+ if (errno == EINTR)
+ continue;
+ pjdlog_exit(EX_TEMPFAIL, "select() failed");
+ }
+ if (FD_ISSET(sockfd, &fds))
+ tcp_recv_ssl_send(sockfd, tcpssl);
+ if (FD_ISSET(tcpfd, &fds))
+ ssl_recv_tcp_send(tcpssl, sockfd);
+ }
+}
+
+static void
+tls_certificate_verify(SSL *ssl, const char *fingerprint)
+{
+ unsigned char md[EVP_MAX_MD_SIZE];
+ char mdstr[sizeof("SHA256=") - 1 + EVP_MAX_MD_SIZE * 3];
+ char *mdstrp;
+ unsigned int i, mdsize;
+ X509 *cert;
+
+ if (fingerprint[0] == '\0') {
+ pjdlog_debug(1, "No fingerprint verification requested.");
+ return;
+ }
+
+ cert = SSL_get_peer_certificate(ssl);
+ if (cert == NULL)
+ pjdlog_exitx(EX_TEMPFAIL, "No peer certificate received.");
+
+ if (X509_digest(cert, EVP_sha256(), md, &mdsize) != 1)
+ pjdlog_exitx(EX_TEMPFAIL, "X509_digest() failed.");
+ PJDLOG_ASSERT(mdsize <= EVP_MAX_MD_SIZE);
+
+ X509_free(cert);
+
+ (void)strlcpy(mdstr, "SHA256=", sizeof(mdstr));
+ mdstrp = mdstr + strlen(mdstr);
+ for (i = 0; i < mdsize; i++) {
+ PJDLOG_VERIFY(mdstrp + 3 <= mdstr + sizeof(mdstr));
+ (void)sprintf(mdstrp, "%02hhX:", md[i]);
+ mdstrp += 3;
+ }
+ /* Clear last colon. */
+ mdstrp[-1] = '\0';
+ if (strcasecmp(mdstr, fingerprint) != 0) {
+ pjdlog_exitx(EX_NOPERM,
+ "Finger print doesn't match. Received \"%s\", expected \"%s\"",
+ mdstr, fingerprint);
+ }
+}
+
+static void
+tls_exec_client(const char *user, int startfd, const char *srcaddr,
+ const char *dstaddr, const char *fingerprint, const char *defport,
+ int timeout, int debuglevel)
+{
+ struct proto_conn *tcp;
+ char *saddr, *daddr;
+ SSL_CTX *sslctx;
+ SSL *ssl;
+ long ret;
+ int sockfd, tcpfd;
+ uint8_t connected;
+
+ pjdlog_debug_set(debuglevel);
+ pjdlog_prefix_set("[TLS sandbox] (client) ");
+#ifdef HAVE_SETPROCTITLE
+ setproctitle("[TLS sandbox] (client) ");
+#endif
+ proto_set("tcp:port", defport);
+
+ sockfd = startfd;
+
+ /* Change tls:// to tcp://. */
+ if (srcaddr == NULL) {
+ saddr = NULL;
+ } else {
+ saddr = strdup(srcaddr);
+ if (saddr == NULL)
+ pjdlog_exitx(EX_TEMPFAIL, "Unable to allocate memory.");
+ bcopy("tcp://", saddr, 6);
+ }
+ daddr = strdup(dstaddr);
+ if (daddr == NULL)
+ pjdlog_exitx(EX_TEMPFAIL, "Unable to allocate memory.");
+ bcopy("tcp://", daddr, 6);
+
+ /* Establish TCP connection. */
+ if (proto_connect(saddr, daddr, timeout, &tcp) == -1)
+ exit(EX_TEMPFAIL);
+
+ SSL_load_error_strings();
+ SSL_library_init();
+
+ /*
+ * TODO: On FreeBSD we could move this below sandbox() once libc and
+ * libcrypto use sysctl kern.arandom to obtain random data
+ * instead of /dev/urandom and friends.
+ */
+ sslctx = SSL_CTX_new(TLSv1_client_method());
+ if (sslctx == NULL)
+ pjdlog_exitx(EX_TEMPFAIL, "SSL_CTX_new() failed.");
+
+ if (sandbox(user, true, "proto_tls client: %s", dstaddr) != 0)
+ pjdlog_exitx(EX_CONFIG, "Unable to sandbox TLS client.");
+ pjdlog_debug(1, "Privileges successfully dropped.");
+
+ SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+
+ /* Load CA certs. */
+ /* TODO */
+ //SSL_CTX_load_verify_locations(sslctx, cacerts_file, NULL);
+
+ ssl = SSL_new(sslctx);
+ if (ssl == NULL)
+ pjdlog_exitx(EX_TEMPFAIL, "SSL_new() failed.");
+
+ tcpfd = proto_descriptor(tcp);
+
+ block(tcpfd);
+
+ if (SSL_set_fd(ssl, tcpfd) != 1)
+ pjdlog_exitx(EX_TEMPFAIL, "SSL_set_fd() failed.");
+
+ ret = SSL_connect(ssl);
+ ssl_check_error(ssl, (int)ret);
+
+ nonblock(sockfd);
+ nonblock(tcpfd);
+
+ tls_certificate_verify(ssl, fingerprint);
+
+ /*
+ * The following byte is send to make proto_connect_wait() to work.
+ */
+ connected = 1;
+ for (;;) {
+ switch (send(sockfd, &connected, sizeof(connected), 0)) {
+ case -1:
+ if (errno == EINTR || errno == ENOBUFS)
+ continue;
+ if (errno == EAGAIN) {
+ (void)wait_for_fd(sockfd, -1);
+ continue;
+ }
+ pjdlog_exit(EX_TEMPFAIL, "send() failed");
+ case 0:
+ pjdlog_debug(1, "Connection terminated.");
+ exit(0);
+ case 1:
+ break;
+ }
+ break;
+ }
+
+ tls_loop(sockfd, ssl);
+}
+
+static void
+tls_call_exec_client(struct proto_conn *sock, const char *srcaddr,
+ const char *dstaddr, int timeout)
+{
+ char *timeoutstr, *startfdstr, *debugstr;
+ int startfd;
+
+ /* Declare that we are receiver. */
+ proto_recv(sock, NULL, 0);
+
+ if (pjdlog_mode_get() == PJDLOG_MODE_STD)
+ startfd = 3;
+ else /* if (pjdlog_mode_get() == PJDLOG_MODE_SYSLOG) */
+ startfd = 0;
+
+ if (proto_descriptor(sock) != startfd) {
+ /* Move socketpair descriptor to descriptor number startfd. */
+ if (dup2(proto_descriptor(sock), startfd) == -1)
+ pjdlog_exit(EX_OSERR, "dup2() failed");
+ proto_close(sock);
+ } else {
+ /*
+ * The FD_CLOEXEC is cleared by dup2(2), so when we not
+ * call it, we have to clear it by hand in case it is set.
+ */
+ if (fcntl(startfd, F_SETFD, 0) == -1)
+ pjdlog_exit(EX_OSERR, "fcntl() failed");
+ }
+
+ closefrom(startfd + 1);
+
+ if (asprintf(&startfdstr, "%d", startfd) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "asprintf() failed");
+ if (timeout == -1)
+ timeout = TLS_DEFAULT_TIMEOUT;
+ if (asprintf(&timeoutstr, "%d", timeout) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "asprintf() failed");
+ if (asprintf(&debugstr, "%d", pjdlog_debug_get()) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "asprintf() failed");
+
+ execl(proto_get("execpath"), proto_get("execpath"), "proto", "tls",
+ proto_get("user"), "client", startfdstr,
+ srcaddr == NULL ? "" : srcaddr, dstaddr,
+ proto_get("tls:fingerprint"), proto_get("tcp:port"), timeoutstr,
+ debugstr, NULL);
+ pjdlog_exit(EX_SOFTWARE, "execl() failed");
+}
+
+static int
+tls_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp)
+{
+ struct tls_ctx *tlsctx;
+ struct proto_conn *sock;
+ pid_t pid;
+ int error;
+
+ PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0');
+ PJDLOG_ASSERT(dstaddr != NULL);
+ PJDLOG_ASSERT(timeout >= -1);
+ PJDLOG_ASSERT(ctxp != NULL);
+
+ if (strncmp(dstaddr, "tls://", 6) != 0)
+ return (-1);
+ if (srcaddr != NULL && strncmp(srcaddr, "tls://", 6) != 0)
+ return (-1);
+
+ if (proto_connect(NULL, "socketpair://", -1, &sock) == -1)
+ return (errno);
+
+#if 0
+ /*
+ * We use rfork() with the following flags to disable SIGCHLD
+ * delivery upon the sandbox process exit.
+ */
+ pid = rfork(RFFDG | RFPROC | RFTSIGZMB | RFTSIGFLAGS(0));
+#else
+ /*
+ * We don't use rfork() to be able to log information about sandbox
+ * process exiting.
+ */
+ pid = fork();
+#endif
+ switch (pid) {
+ case -1:
+ /* Failure. */
+ error = errno;
+ proto_close(sock);
+ return (error);
+ case 0:
+ /* Child. */
+ pjdlog_prefix_set("[TLS sandbox] (client) ");
+#ifdef HAVE_SETPROCTITLE
+ setproctitle("[TLS sandbox] (client) ");
+#endif
+ tls_call_exec_client(sock, srcaddr, dstaddr, timeout);
+ /* NOTREACHED */
+ default:
+ /* Parent. */
+ tlsctx = calloc(1, sizeof(*tlsctx));
+ if (tlsctx == NULL) {
+ error = errno;
+ proto_close(sock);
+ (void)kill(pid, SIGKILL);
+ return (error);
+ }
+ proto_send(sock, NULL, 0);
+ tlsctx->tls_sock = sock;
+ tlsctx->tls_tcp = NULL;
+ tlsctx->tls_side = TLS_SIDE_CLIENT;
+ tlsctx->tls_wait_called = false;
+ tlsctx->tls_magic = TLS_CTX_MAGIC;
+ if (timeout >= 0) {
+ error = tls_connect_wait(tlsctx, timeout);
+ if (error != 0) {
+ (void)kill(pid, SIGKILL);
+ tls_close(tlsctx);
+ return (error);
+ }
+ }
+ *ctxp = tlsctx;
+ return (0);
+ }
+}
+
+static int
+tls_connect_wait(void *ctx, int timeout)
+{
+ struct tls_ctx *tlsctx = ctx;
+ int error, sockfd;
+ uint8_t connected;
+
+ PJDLOG_ASSERT(tlsctx != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC);
+ PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_CLIENT);
+ PJDLOG_ASSERT(tlsctx->tls_sock != NULL);
+ PJDLOG_ASSERT(!tlsctx->tls_wait_called);
+ PJDLOG_ASSERT(timeout >= 0);
+
+ sockfd = proto_descriptor(tlsctx->tls_sock);
+ error = wait_for_fd(sockfd, timeout);
+ if (error != 0)
+ return (error);
+
+ for (;;) {
+ switch (recv(sockfd, &connected, sizeof(connected),
+ MSG_WAITALL)) {
+ case -1:
+ if (errno == EINTR || errno == ENOBUFS)
+ continue;
+ error = errno;
+ break;
+ case 0:
+ pjdlog_debug(1, "Connection terminated.");
+ error = ENOTCONN;
+ break;
+ case 1:
+ tlsctx->tls_wait_called = true;
+ break;
+ }
+ break;
+ }
+
+ return (error);
+}
+
+static int
+tls_server(const char *lstaddr, void **ctxp)
+{
+ struct proto_conn *tcp;
+ struct tls_ctx *tlsctx;
+ char *laddr;
+ int error;
+
+ if (strncmp(lstaddr, "tls://", 6) != 0)
+ return (-1);
+
+ tlsctx = malloc(sizeof(*tlsctx));
+ if (tlsctx == NULL) {
+ pjdlog_warning("Unable to allocate memory.");
+ return (ENOMEM);
+ }
+
+ laddr = strdup(lstaddr);
+ if (laddr == NULL) {
+ free(tlsctx);
+ pjdlog_warning("Unable to allocate memory.");
+ return (ENOMEM);
+ }
+ bcopy("tcp://", laddr, 6);
+
+ if (proto_server(laddr, &tcp) == -1) {
+ error = errno;
+ free(tlsctx);
+ free(laddr);
+ return (error);
+ }
+ free(laddr);
+
+ tlsctx->tls_sock = NULL;
+ tlsctx->tls_tcp = tcp;
+ tlsctx->tls_side = TLS_SIDE_SERVER_LISTEN;
+ tlsctx->tls_wait_called = true;
+ tlsctx->tls_magic = TLS_CTX_MAGIC;
+ *ctxp = tlsctx;
+
+ return (0);
+}
+
+static void
+tls_exec_server(const char *user, int startfd, const char *privkey,
+ const char *cert, int debuglevel)
+{
+ SSL_CTX *sslctx;
+ SSL *ssl;
+ int sockfd, tcpfd, ret;
+
+ pjdlog_debug_set(debuglevel);
+ pjdlog_prefix_set("[TLS sandbox] (server) ");
+#ifdef HAVE_SETPROCTITLE
+ setproctitle("[TLS sandbox] (server) ");
+#endif
+
+ sockfd = startfd;
+ tcpfd = startfd + 1;
+
+ SSL_load_error_strings();
+ SSL_library_init();
+
+ sslctx = SSL_CTX_new(TLSv1_server_method());
+ if (sslctx == NULL)
+ pjdlog_exitx(EX_TEMPFAIL, "SSL_CTX_new() failed.");
+
+ SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+
+ ssl = SSL_new(sslctx);
+ if (ssl == NULL)
+ pjdlog_exitx(EX_TEMPFAIL, "SSL_new() failed.");
+
+ if (SSL_use_RSAPrivateKey_file(ssl, privkey, SSL_FILETYPE_PEM) != 1) {
+ ssl_log_errors();
+ pjdlog_exitx(EX_CONFIG,
+ "SSL_use_RSAPrivateKey_file(%s) failed.", privkey);
+ }
+
+ if (SSL_use_certificate_file(ssl, cert, SSL_FILETYPE_PEM) != 1) {
+ ssl_log_errors();
+ pjdlog_exitx(EX_CONFIG, "SSL_use_certificate_file(%s) failed.",
+ cert);
+ }
+
+ if (sandbox(user, true, "proto_tls server") != 0)
+ pjdlog_exitx(EX_CONFIG, "Unable to sandbox TLS server.");
+ pjdlog_debug(1, "Privileges successfully dropped.");
+
+ nonblock(sockfd);
+ nonblock(tcpfd);
+
+ if (SSL_set_fd(ssl, tcpfd) != 1)
+ pjdlog_exitx(EX_TEMPFAIL, "SSL_set_fd() failed.");
+
+ ret = SSL_accept(ssl);
+ ssl_check_error(ssl, ret);
+
+ tls_loop(sockfd, ssl);
+}
+
+static void
+tls_call_exec_server(struct proto_conn *sock, struct proto_conn *tcp)
+{
+ int startfd, sockfd, tcpfd, safefd;
+ char *startfdstr, *debugstr;
+
+ if (pjdlog_mode_get() == PJDLOG_MODE_STD)
+ startfd = 3;
+ else /* if (pjdlog_mode_get() == PJDLOG_MODE_SYSLOG) */
+ startfd = 0;
+
+ /* Declare that we are receiver. */
+ proto_send(sock, NULL, 0);
+
+ sockfd = proto_descriptor(sock);
+ tcpfd = proto_descriptor(tcp);
+
+ safefd = MAX(sockfd, tcpfd);
+ safefd = MAX(safefd, startfd);
+ safefd++;
+
+ /* Move sockfd and tcpfd to safe numbers first. */
+ if (dup2(sockfd, safefd) == -1)
+ pjdlog_exit(EX_OSERR, "dup2() failed");
+ proto_close(sock);
+ sockfd = safefd;
+ if (dup2(tcpfd, safefd + 1) == -1)
+ pjdlog_exit(EX_OSERR, "dup2() failed");
+ proto_close(tcp);
+ tcpfd = safefd + 1;
+
+ /* Move socketpair descriptor to descriptor number startfd. */
+ if (dup2(sockfd, startfd) == -1)
+ pjdlog_exit(EX_OSERR, "dup2() failed");
+ (void)close(sockfd);
+ /* Move tcp descriptor to descriptor number startfd + 1. */
+ if (dup2(tcpfd, startfd + 1) == -1)
+ pjdlog_exit(EX_OSERR, "dup2() failed");
+ (void)close(tcpfd);
+
+ closefrom(startfd + 2);
+
+ /*
+ * Even if FD_CLOEXEC was set on descriptors before dup2(), it should
+ * have been cleared on dup2(), but better be safe than sorry.
+ */
+ if (fcntl(startfd, F_SETFD, 0) == -1)
+ pjdlog_exit(EX_OSERR, "fcntl() failed");
+ if (fcntl(startfd + 1, F_SETFD, 0) == -1)
+ pjdlog_exit(EX_OSERR, "fcntl() failed");
+
+ if (asprintf(&startfdstr, "%d", startfd) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "asprintf() failed");
+ if (asprintf(&debugstr, "%d", pjdlog_debug_get()) == -1)
+ pjdlog_exit(EX_TEMPFAIL, "asprintf() failed");
+
+ execl(proto_get("execpath"), proto_get("execpath"), "proto", "tls",
+ proto_get("user"), "server", startfdstr, proto_get("tls:keyfile"),
+ proto_get("tls:certfile"), debugstr, NULL);
+ pjdlog_exit(EX_SOFTWARE, "execl() failed");
+}
+
+static int
+tls_accept(void *ctx, void **newctxp)
+{
+ struct tls_ctx *tlsctx = ctx;
+ struct tls_ctx *newtlsctx;
+ struct proto_conn *sock, *tcp;
+ pid_t pid;
+ int error;
+
+ PJDLOG_ASSERT(tlsctx != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC);
+ PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_SERVER_LISTEN);
+
+ if (proto_connect(NULL, "socketpair://", -1, &sock) == -1)
+ return (errno);
+
+ /* Accept TCP connection. */
+ if (proto_accept(tlsctx->tls_tcp, &tcp) == -1) {
+ error = errno;
+ proto_close(sock);
+ return (error);
+ }
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ /* Failure. */
+ error = errno;
+ proto_close(sock);
+ return (error);
+ case 0:
+ /* Child. */
+ pjdlog_prefix_set("[TLS sandbox] (server) ");
+#ifdef HAVE_SETPROCTITLE
+ setproctitle("[TLS sandbox] (server) ");
+#endif
+ /* Close listen socket. */
+ proto_close(tlsctx->tls_tcp);
+ tls_call_exec_server(sock, tcp);
+ /* NOTREACHED */
+ PJDLOG_ABORT("Unreachable.");
+ default:
+ /* Parent. */
+ newtlsctx = calloc(1, sizeof(*tlsctx));
+ if (newtlsctx == NULL) {
+ error = errno;
+ proto_close(sock);
+ proto_close(tcp);
+ (void)kill(pid, SIGKILL);
+ return (error);
+ }
+ proto_local_address(tcp, newtlsctx->tls_laddr,
+ sizeof(newtlsctx->tls_laddr));
+ PJDLOG_ASSERT(strncmp(newtlsctx->tls_laddr, "tcp://", 6) == 0);
+ bcopy("tls://", newtlsctx->tls_laddr, 6);
+ *strrchr(newtlsctx->tls_laddr, ':') = '\0';
+ proto_remote_address(tcp, newtlsctx->tls_raddr,
+ sizeof(newtlsctx->tls_raddr));
+ PJDLOG_ASSERT(strncmp(newtlsctx->tls_raddr, "tcp://", 6) == 0);
+ bcopy("tls://", newtlsctx->tls_raddr, 6);
+ *strrchr(newtlsctx->tls_raddr, ':') = '\0';
+ proto_close(tcp);
+ proto_recv(sock, NULL, 0);
+ newtlsctx->tls_sock = sock;
+ newtlsctx->tls_tcp = NULL;
+ newtlsctx->tls_wait_called = true;
+ newtlsctx->tls_side = TLS_SIDE_SERVER_WORK;
+ newtlsctx->tls_magic = TLS_CTX_MAGIC;
+ *newctxp = newtlsctx;
+ return (0);
+ }
+}
+
+static int
+tls_wrap(int fd, bool client, void **ctxp)
+{
+ struct tls_ctx *tlsctx;
+ struct proto_conn *sock;
+ int error;
+
+ tlsctx = calloc(1, sizeof(*tlsctx));
+ if (tlsctx == NULL)
+ return (errno);
+
+ if (proto_wrap("socketpair", client, fd, &sock) == -1) {
+ error = errno;
+ free(tlsctx);
+ return (error);
+ }
+
+ tlsctx->tls_sock = sock;
+ tlsctx->tls_tcp = NULL;
+ tlsctx->tls_wait_called = (client ? false : true);
+ tlsctx->tls_side = (client ? TLS_SIDE_CLIENT : TLS_SIDE_SERVER_WORK);
+ tlsctx->tls_magic = TLS_CTX_MAGIC;
+ *ctxp = tlsctx;
+
+ return (0);
+}
+
+static int
+tls_send(void *ctx, const unsigned char *data, size_t size, int fd)
+{
+ struct tls_ctx *tlsctx = ctx;
+
+ PJDLOG_ASSERT(tlsctx != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC);
+ PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_CLIENT ||
+ tlsctx->tls_side == TLS_SIDE_SERVER_WORK);
+ PJDLOG_ASSERT(tlsctx->tls_sock != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_wait_called);
+ PJDLOG_ASSERT(fd == -1);
+
+ if (proto_send(tlsctx->tls_sock, data, size) == -1)
+ return (errno);
+
+ return (0);
+}
+
+static int
+tls_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
+{
+ struct tls_ctx *tlsctx = ctx;
+
+ PJDLOG_ASSERT(tlsctx != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC);
+ PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_CLIENT ||
+ tlsctx->tls_side == TLS_SIDE_SERVER_WORK);
+ PJDLOG_ASSERT(tlsctx->tls_sock != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_wait_called);
+ PJDLOG_ASSERT(fdp == NULL);
+
+ if (proto_recv(tlsctx->tls_sock, data, size) == -1)
+ return (errno);
+
+ return (0);
+}
+
+static int
+tls_descriptor(const void *ctx)
+{
+ const struct tls_ctx *tlsctx = ctx;
+
+ PJDLOG_ASSERT(tlsctx != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC);
+
+ switch (tlsctx->tls_side) {
+ case TLS_SIDE_CLIENT:
+ case TLS_SIDE_SERVER_WORK:
+ PJDLOG_ASSERT(tlsctx->tls_sock != NULL);
+
+ return (proto_descriptor(tlsctx->tls_sock));
+ case TLS_SIDE_SERVER_LISTEN:
+ PJDLOG_ASSERT(tlsctx->tls_tcp != NULL);
+
+ return (proto_descriptor(tlsctx->tls_tcp));
+ default:
+ PJDLOG_ABORT("Invalid side (%d).", tlsctx->tls_side);
+ }
+}
+
+static bool
+tcp_address_match(const void *ctx, const char *addr)
+{
+ const struct tls_ctx *tlsctx = ctx;
+
+ PJDLOG_ASSERT(tlsctx != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC);
+
+ return (strcmp(tlsctx->tls_raddr, addr) == 0);
+}
+
+static void
+tls_local_address(const void *ctx, char *addr, size_t size)
+{
+ const struct tls_ctx *tlsctx = ctx;
+
+ PJDLOG_ASSERT(tlsctx != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC);
+ PJDLOG_ASSERT(tlsctx->tls_wait_called);
+
+ switch (tlsctx->tls_side) {
+ case TLS_SIDE_CLIENT:
+ PJDLOG_ASSERT(tlsctx->tls_sock != NULL);
+
+ PJDLOG_VERIFY(strlcpy(addr, "tls://N/A", size) < size);
+ break;
+ case TLS_SIDE_SERVER_WORK:
+ PJDLOG_ASSERT(tlsctx->tls_sock != NULL);
+
+ PJDLOG_VERIFY(strlcpy(addr, tlsctx->tls_laddr, size) < size);
+ break;
+ case TLS_SIDE_SERVER_LISTEN:
+ PJDLOG_ASSERT(tlsctx->tls_tcp != NULL);
+
+ proto_local_address(tlsctx->tls_tcp, addr, size);
+ PJDLOG_ASSERT(strncmp(addr, "tcp://", 6) == 0);
+ /* Replace tcp:// prefix with tls:// */
+ bcopy("tls://", addr, 6);
+ break;
+ default:
+ PJDLOG_ABORT("Invalid side (%d).", tlsctx->tls_side);
+ }
+}
+
+static void
+tls_remote_address(const void *ctx, char *addr, size_t size)
+{
+ const struct tls_ctx *tlsctx = ctx;
+
+ PJDLOG_ASSERT(tlsctx != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC);
+ PJDLOG_ASSERT(tlsctx->tls_wait_called);
+
+ switch (tlsctx->tls_side) {
+ case TLS_SIDE_CLIENT:
+ PJDLOG_ASSERT(tlsctx->tls_sock != NULL);
+
+ PJDLOG_VERIFY(strlcpy(addr, "tls://N/A", size) < size);
+ break;
+ case TLS_SIDE_SERVER_WORK:
+ PJDLOG_ASSERT(tlsctx->tls_sock != NULL);
+
+ PJDLOG_VERIFY(strlcpy(addr, tlsctx->tls_raddr, size) < size);
+ break;
+ case TLS_SIDE_SERVER_LISTEN:
+ PJDLOG_ASSERT(tlsctx->tls_tcp != NULL);
+
+ proto_remote_address(tlsctx->tls_tcp, addr, size);
+ PJDLOG_ASSERT(strncmp(addr, "tcp://", 6) == 0);
+ /* Replace tcp:// prefix with tls:// */
+ bcopy("tls://", addr, 6);
+ break;
+ default:
+ PJDLOG_ABORT("Invalid side (%d).", tlsctx->tls_side);
+ }
+}
+
+static void
+tls_close(void *ctx)
+{
+ struct tls_ctx *tlsctx = ctx;
+
+ PJDLOG_ASSERT(tlsctx != NULL);
+ PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC);
+
+ if (tlsctx->tls_sock != NULL) {
+ proto_close(tlsctx->tls_sock);
+ tlsctx->tls_sock = NULL;
+ }
+ if (tlsctx->tls_tcp != NULL) {
+ proto_close(tlsctx->tls_tcp);
+ tlsctx->tls_tcp = NULL;
+ }
+ tlsctx->tls_side = 0;
+ tlsctx->tls_magic = 0;
+ free(tlsctx);
+}
+
+static int
+tls_exec(int argc, char *argv[])
+{
+
+ PJDLOG_ASSERT(argc > 3);
+ PJDLOG_ASSERT(strcmp(argv[0], "tls") == 0);
+
+ pjdlog_init(atoi(argv[3]) == 0 ? PJDLOG_MODE_SYSLOG : PJDLOG_MODE_STD);
+
+ if (strcmp(argv[2], "client") == 0) {
+ if (argc != 10)
+ return (EINVAL);
+ tls_exec_client(argv[1], atoi(argv[3]),
+ argv[4][0] == '\0' ? NULL : argv[4], argv[5], argv[6],
+ argv[7], atoi(argv[8]), atoi(argv[9]));
+ } else if (strcmp(argv[2], "server") == 0) {
+ if (argc != 7)
+ return (EINVAL);
+ tls_exec_server(argv[1], atoi(argv[3]), argv[4], argv[5],
+ atoi(argv[6]));
+ }
+ return (EINVAL);
+}
+
+static struct proto tls_proto = {
+ .prt_name = "tls",
+ .prt_connect = tls_connect,
+ .prt_connect_wait = tls_connect_wait,
+ .prt_server = tls_server,
+ .prt_accept = tls_accept,
+ .prt_wrap = tls_wrap,
+ .prt_send = tls_send,
+ .prt_recv = tls_recv,
+ .prt_descriptor = tls_descriptor,
+ .prt_address_match = tcp_address_match,
+ .prt_local_address = tls_local_address,
+ .prt_remote_address = tls_remote_address,
+ .prt_close = tls_close,
+ .prt_exec = tls_exec
+};
+
+static __constructor void
+tls_ctor(void)
+{
+
+ proto_register(&tls_proto, false);
+}
diff --git a/contrib/openbsm/bin/auditdistd/proto_uds.c b/contrib/openbsm/bin/auditdistd/proto_uds.c
new file mode 100644
index 0000000..3168bbf
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/proto_uds.c
@@ -0,0 +1,360 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* UDS - UNIX Domain Socket */
+
+#include <config/config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HAVE_STRLCPY
+#include <compat/strlcpy.h>
+#endif
+
+#include "pjdlog.h"
+#include "proto_impl.h"
+
+#define UDS_CTX_MAGIC 0xd541c
+struct uds_ctx {
+ int uc_magic;
+ struct sockaddr_un uc_sun;
+ int uc_fd;
+ int uc_side;
+#define UDS_SIDE_CLIENT 0
+#define UDS_SIDE_SERVER_LISTEN 1
+#define UDS_SIDE_SERVER_WORK 2
+ pid_t uc_owner;
+};
+
+static void uds_close(void *ctx);
+
+static int
+uds_addr(const char *addr, struct sockaddr_un *sunp)
+{
+
+ if (addr == NULL)
+ return (-1);
+
+ if (strncasecmp(addr, "uds://", 6) == 0)
+ addr += 6;
+ else if (strncasecmp(addr, "unix://", 7) == 0)
+ addr += 7;
+ else if (addr[0] == '/' && /* If it starts from /... */
+ strstr(addr, "://") == NULL)/* ...and there is no prefix... */
+ ; /* ...we assume its us. */
+ else
+ return (-1);
+
+ sunp->sun_family = AF_UNIX;
+ if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >=
+ sizeof(sunp->sun_path)) {
+ return (ENAMETOOLONG);
+ }
+#ifdef HAVE_SOCKADDR_STORAGE_SS_LEN
+ sunp->sun_len = SUN_LEN(sunp);
+#endif
+
+ return (0);
+}
+
+static int
+uds_common_setup(const char *addr, int side, struct uds_ctx **uctxp)
+{
+ struct uds_ctx *uctx;
+ int error;
+
+ uctx = malloc(sizeof(*uctx));
+ if (uctx == NULL)
+ return (errno);
+
+ /* Parse given address. */
+ error = uds_addr(addr, &uctx->uc_sun);
+ if (error != 0) {
+ free(uctx);
+ return (error);
+ }
+
+ uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (uctx->uc_fd == -1) {
+ error = errno;
+ free(uctx);
+ return (error);
+ }
+
+ uctx->uc_side = side;
+ uctx->uc_owner = 0;
+ uctx->uc_magic = UDS_CTX_MAGIC;
+ *uctxp = uctx;
+
+ return (0);
+}
+
+static int
+uds_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp)
+{
+ struct uds_ctx *uctx;
+ int error;
+
+ PJDLOG_ASSERT(dstaddr != NULL);
+ PJDLOG_ASSERT(timeout >= -1);
+
+ error = uds_common_setup(dstaddr, UDS_SIDE_CLIENT, &uctx);
+ if (error != 0)
+ return (error);
+
+ PJDLOG_ASSERT(srcaddr == NULL);
+
+ if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
+ sizeof(uctx->uc_sun)) == -1) {
+ error = errno;
+ uds_close(uctx);
+ return (error);
+ }
+
+ *ctxp = uctx;
+
+ return (0);
+}
+
+static int
+uds_connect_wait(void *ctx, int timeout)
+{
+ struct uds_ctx *uctx = ctx;
+
+ PJDLOG_ASSERT(uctx != NULL);
+ PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
+ PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
+ PJDLOG_ASSERT(uctx->uc_fd >= 0);
+ PJDLOG_ASSERT(timeout >= 0);
+
+ return (0);
+}
+
+static int
+uds_server(const char *addr, void **ctxp)
+{
+ struct uds_ctx *uctx;
+ int error;
+
+ error = uds_common_setup(addr, UDS_SIDE_SERVER_LISTEN, &uctx);
+ if (error != 0)
+ return (error);
+
+ (void)unlink(uctx->uc_sun.sun_path);
+ if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
+ sizeof(uctx->uc_sun)) == -1) {
+ error = errno;
+ uds_close(uctx);
+ return (error);
+ }
+ uctx->uc_owner = getpid();
+ if (listen(uctx->uc_fd, 8) == -1) {
+ error = errno;
+ uds_close(uctx);
+ return (error);
+ }
+
+ *ctxp = uctx;
+
+ return (0);
+}
+
+static int
+uds_accept(void *ctx, void **newctxp)
+{
+ struct uds_ctx *uctx = ctx;
+ struct uds_ctx *newuctx;
+ socklen_t fromlen;
+ int error;
+
+ PJDLOG_ASSERT(uctx != NULL);
+ PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
+ PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
+ PJDLOG_ASSERT(uctx->uc_fd >= 0);
+
+ newuctx = malloc(sizeof(*newuctx));
+ if (newuctx == NULL)
+ return (errno);
+
+ fromlen = sizeof(newuctx->uc_sun);
+ newuctx->uc_fd = accept(uctx->uc_fd,
+ (struct sockaddr *)&newuctx->uc_sun, &fromlen);
+ if (newuctx->uc_fd < 0) {
+ error = errno;
+ free(newuctx);
+ return (error);
+ }
+
+ newuctx->uc_side = UDS_SIDE_SERVER_WORK;
+ newuctx->uc_magic = UDS_CTX_MAGIC;
+ *newctxp = newuctx;
+
+ return (0);
+}
+
+static int
+uds_send(void *ctx, const unsigned char *data, size_t size, int fd)
+{
+ struct uds_ctx *uctx = ctx;
+
+ PJDLOG_ASSERT(uctx != NULL);
+ PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
+ PJDLOG_ASSERT(uctx->uc_fd >= 0);
+
+ return (proto_common_send(uctx->uc_fd, data, size, fd));
+}
+
+static int
+uds_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
+{
+ struct uds_ctx *uctx = ctx;
+
+ PJDLOG_ASSERT(uctx != NULL);
+ PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
+ PJDLOG_ASSERT(uctx->uc_fd >= 0);
+
+ return (proto_common_recv(uctx->uc_fd, data, size, fdp));
+}
+
+static int
+uds_descriptor(const void *ctx)
+{
+ const struct uds_ctx *uctx = ctx;
+
+ PJDLOG_ASSERT(uctx != NULL);
+ PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
+
+ return (uctx->uc_fd);
+}
+
+static void
+uds_local_address(const void *ctx, char *addr, size_t size)
+{
+ const struct uds_ctx *uctx = ctx;
+ struct sockaddr_un sun;
+ socklen_t sunlen;
+
+ PJDLOG_ASSERT(uctx != NULL);
+ PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
+ PJDLOG_ASSERT(addr != NULL);
+
+ sunlen = sizeof(sun);
+ if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
+ PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
+ return;
+ }
+ PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
+ if (sun.sun_path[0] == '\0') {
+ PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
+ return;
+ }
+ PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size);
+}
+
+static void
+uds_remote_address(const void *ctx, char *addr, size_t size)
+{
+ const struct uds_ctx *uctx = ctx;
+ struct sockaddr_un sun;
+ socklen_t sunlen;
+
+ PJDLOG_ASSERT(uctx != NULL);
+ PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
+ PJDLOG_ASSERT(addr != NULL);
+
+ sunlen = sizeof(sun);
+ if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
+ PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
+ return;
+ }
+ PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
+ if (sun.sun_path[0] == '\0') {
+ PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
+ return;
+ }
+ snprintf(addr, size, "uds://%s", sun.sun_path);
+}
+
+static void
+uds_close(void *ctx)
+{
+ struct uds_ctx *uctx = ctx;
+
+ PJDLOG_ASSERT(uctx != NULL);
+ PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
+
+ if (uctx->uc_fd >= 0)
+ close(uctx->uc_fd);
+ /*
+ * Unlink the socket only if we are the owner and this is descriptor
+ * we listen on.
+ */
+ if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN &&
+ uctx->uc_owner == getpid()) {
+ PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0');
+ if (unlink(uctx->uc_sun.sun_path) == -1) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to unlink socket file %s",
+ uctx->uc_sun.sun_path);
+ }
+ }
+ uctx->uc_owner = 0;
+ uctx->uc_magic = 0;
+ free(uctx);
+}
+
+static struct proto uds_proto = {
+ .prt_name = "uds",
+ .prt_connect = uds_connect,
+ .prt_connect_wait = uds_connect_wait,
+ .prt_server = uds_server,
+ .prt_accept = uds_accept,
+ .prt_send = uds_send,
+ .prt_recv = uds_recv,
+ .prt_descriptor = uds_descriptor,
+ .prt_local_address = uds_local_address,
+ .prt_remote_address = uds_remote_address,
+ .prt_close = uds_close
+};
+
+static __constructor void
+uds_ctor(void)
+{
+
+ proto_register(&uds_proto, false);
+}
diff --git a/contrib/openbsm/bin/auditdistd/receiver.c b/contrib/openbsm/bin/auditdistd/receiver.c
new file mode 100644
index 0000000..9dc3b018
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/receiver.c
@@ -0,0 +1,712 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config/config.h>
+
+#include <sys/param.h>
+#if defined(HAVE_SYS_ENDIAN_H) && defined(HAVE_BSWAP)
+#include <sys/endian.h>
+#else /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include <machine/endian.h>
+#else /* !HAVE_MACHINE_ENDIAN_H */
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#else /* !HAVE_ENDIAN_H */
+#error "No supported endian.h"
+#endif /* !HAVE_ENDIAN_H */
+#endif /* !HAVE_MACHINE_ENDIAN_H */
+#include <compat/endian.h>
+#endif /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+#include <pthread.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#ifndef HAVE_STRLCPY
+#include <compat/strlcpy.h>
+#endif
+#ifndef HAVE_FSTATAT
+#include "fstatat.h"
+#endif
+#ifndef HAVE_OPENAT
+#include "openat.h"
+#endif
+#ifndef HAVE_RENAMEAT
+#include "renameat.h"
+#endif
+
+#include "auditdistd.h"
+#include "pjdlog.h"
+#include "proto.h"
+#include "sandbox.h"
+#include "subr.h"
+#include "synch.h"
+#include "trail.h"
+
+static struct adist_config *adcfg;
+static struct adist_host *adhost;
+
+static TAILQ_HEAD(, adreq) adist_free_list;
+static pthread_mutex_t adist_free_list_lock;
+static pthread_cond_t adist_free_list_cond;
+static TAILQ_HEAD(, adreq) adist_disk_list;
+static pthread_mutex_t adist_disk_list_lock;
+static pthread_cond_t adist_disk_list_cond;
+static TAILQ_HEAD(, adreq) adist_send_list;
+static pthread_mutex_t adist_send_list_lock;
+static pthread_cond_t adist_send_list_cond;
+
+static void
+adreq_clear(struct adreq *adreq)
+{
+
+ adreq->adr_error = -1;
+ adreq->adr_byteorder = ADIST_BYTEORDER_UNDEFINED;
+ adreq->adr_cmd = ADIST_CMD_UNDEFINED;
+ adreq->adr_seq = 0;
+ adreq->adr_datasize = 0;
+}
+
+static void
+init_environment(void)
+{
+ struct adreq *adreq;
+ unsigned int ii;
+
+ TAILQ_INIT(&adist_free_list);
+ mtx_init(&adist_free_list_lock);
+ cv_init(&adist_free_list_cond);
+ TAILQ_INIT(&adist_disk_list);
+ mtx_init(&adist_disk_list_lock);
+ cv_init(&adist_disk_list_cond);
+ TAILQ_INIT(&adist_send_list);
+ mtx_init(&adist_send_list_lock);
+ cv_init(&adist_send_list_cond);
+
+ for (ii = 0; ii < ADIST_QUEUE_SIZE; ii++) {
+ adreq = malloc(sizeof(*adreq) + ADIST_BUF_SIZE);
+ if (adreq == NULL) {
+ pjdlog_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for adreq object.",
+ sizeof(*adreq) + ADIST_BUF_SIZE);
+ }
+ adreq_clear(adreq);
+ TAILQ_INSERT_TAIL(&adist_free_list, adreq, adr_next);
+ }
+}
+
+static void
+adreq_decode_and_validate_header(struct adreq *adreq)
+{
+
+ /* Byte-swap only is the sender is using different byte order. */
+ if (adreq->adr_byteorder != ADIST_BYTEORDER) {
+ adreq->adr_byteorder = ADIST_BYTEORDER;
+ adreq->adr_seq = bswap64(adreq->adr_seq);
+ adreq->adr_datasize = bswap32(adreq->adr_datasize);
+ }
+
+ /* Validate packet header. */
+
+ if (adreq->adr_datasize > ADIST_BUF_SIZE) {
+ pjdlog_exitx(EX_PROTOCOL, "Invalid datasize received (%ju).",
+ (uintmax_t)adreq->adr_datasize);
+ }
+
+ switch (adreq->adr_cmd) {
+ case ADIST_CMD_OPEN:
+ case ADIST_CMD_APPEND:
+ case ADIST_CMD_CLOSE:
+ if (adreq->adr_datasize == 0) {
+ pjdlog_exitx(EX_PROTOCOL,
+ "Invalid datasize received (%ju).",
+ (uintmax_t)adreq->adr_datasize);
+ }
+ break;
+ case ADIST_CMD_KEEPALIVE:
+ case ADIST_CMD_ERROR:
+ if (adreq->adr_datasize > 0) {
+ pjdlog_exitx(EX_PROTOCOL,
+ "Invalid datasize received (%ju).",
+ (uintmax_t)adreq->adr_datasize);
+ }
+ break;
+ default:
+ pjdlog_exitx(EX_PROTOCOL, "Invalid command received (%hhu).",
+ adreq->adr_cmd);
+ }
+}
+
+static void
+adreq_validate_data(const struct adreq *adreq)
+{
+
+ /* Validate packet data. */
+
+ switch (adreq->adr_cmd) {
+ case ADIST_CMD_OPEN:
+ case ADIST_CMD_CLOSE:
+ /*
+ * File name must end up with '\0' and there must be no '\0'
+ * in the middle.
+ */
+ if (adreq->adr_data[adreq->adr_datasize - 1] != '\0' ||
+ strchr(adreq->adr_data, '\0') !=
+ (const char *)adreq->adr_data + adreq->adr_datasize - 1) {
+ pjdlog_exitx(EX_PROTOCOL,
+ "Invalid file name received.");
+ }
+ break;
+ }
+}
+
+/*
+ * Thread receives requests from the sender.
+ */
+static void *
+recv_thread(void *arg __unused)
+{
+ struct adreq *adreq;
+
+ for (;;) {
+ pjdlog_debug(3, "recv: Taking free request.");
+ QUEUE_TAKE(adreq, &adist_free_list, 0);
+ pjdlog_debug(3, "recv: (%p) Got request.", adreq);
+
+ if (proto_recv(adhost->adh_remote, &adreq->adr_packet,
+ sizeof(adreq->adr_packet)) == -1) {
+ pjdlog_exit(EX_TEMPFAIL,
+ "Unable to receive request header");
+ }
+ adreq_decode_and_validate_header(adreq);
+
+ switch (adreq->adr_cmd) {
+ case ADIST_CMD_KEEPALIVE:
+ adreq->adr_error = 0;
+ adreq_log(LOG_DEBUG, 2, -1, adreq,
+ "recv: (%p) Got request header: ", adreq);
+ pjdlog_debug(3,
+ "recv: (%p) Moving request to the send queue.",
+ adreq);
+ QUEUE_INSERT(adreq, &adist_send_list);
+ continue;
+ case ADIST_CMD_ERROR:
+ pjdlog_error("An error occured on the sender while reading \"%s/%s\".",
+ adhost->adh_directory, adhost->adh_trail_name);
+ adreq_log(LOG_DEBUG, 2, ADIST_ERROR_READ, adreq,
+ "recv: (%p) Got request header: ", adreq);
+ pjdlog_debug(3,
+ "recv: (%p) Moving request to the send queue.",
+ adreq);
+ QUEUE_INSERT(adreq, &adist_disk_list);
+ continue;
+ case ADIST_CMD_OPEN:
+ case ADIST_CMD_APPEND:
+ case ADIST_CMD_CLOSE:
+ if (proto_recv(adhost->adh_remote, adreq->adr_data,
+ adreq->adr_datasize) == -1) {
+ pjdlog_exit(EX_TEMPFAIL,
+ "Unable to receive request data");
+ }
+ adreq_validate_data(adreq);
+ adreq_log(LOG_DEBUG, 2, -1, adreq,
+ "recv: (%p) Got request header: ", adreq);
+ pjdlog_debug(3,
+ "recv: (%p) Moving request to the disk queue.",
+ adreq);
+ QUEUE_INSERT(adreq, &adist_disk_list);
+ break;
+ default:
+ PJDLOG_ABORT("Invalid condition.");
+ }
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * Function that opens trail file requested by the sender.
+ * If the file already exist, it has to be the most recent file and it can
+ * only be open for append.
+ * If the file doesn't already exist, it has to be "older" than all existing
+ * files.
+ */
+static int
+receiver_open(const char *filename)
+{
+ int fd;
+
+ /*
+ * Previous file should be closed by now. Sending OPEN request without
+ * sending CLOSE for the previous file is a sender bug.
+ */
+ if (adhost->adh_trail_fd != -1) {
+ pjdlog_error("Sender requested opening file \"%s\" without first closing \"%s\".",
+ filename, adhost->adh_trail_name);
+ return (ADIST_ERROR_WRONG_ORDER);
+ }
+
+ if (!trail_validate_name(filename, NULL)) {
+ pjdlog_error("Sender wants to open file \"%s\", which has invalid name.",
+ filename);
+ return (ADIST_ERROR_INVALID_NAME);
+ }
+
+ switch (trail_name_compare(filename, adhost->adh_trail_name)) {
+ case TRAIL_RENAMED:
+ if (!trail_is_not_terminated(adhost->adh_trail_name)) {
+ pjdlog_error("Terminated trail \"%s/%s\" was unterminated on the sender as \"%s/%s\"?",
+ adhost->adh_directory, adhost->adh_trail_name,
+ adhost->adh_directory, filename);
+ return (ADIST_ERROR_INVALID_NAME);
+ }
+ if (renameat(adhost->adh_trail_dirfd, adhost->adh_trail_name,
+ adhost->adh_trail_dirfd, filename) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to rename file \"%s/%s\" to \"%s/%s\"",
+ adhost->adh_directory, adhost->adh_trail_name,
+ adhost->adh_directory, filename);
+ PJDLOG_ASSERT(errno > 0);
+ return (ADIST_ERROR_RENAME);
+ }
+ pjdlog_debug(1, "Renamed file \"%s/%s\" to \"%s/%s\".",
+ adhost->adh_directory, adhost->adh_trail_name,
+ adhost->adh_directory, filename);
+ /* FALLTHROUGH */
+ case TRAIL_IDENTICAL:
+ /* Opening existing file. */
+ fd = openat(adhost->adh_trail_dirfd, filename,
+ O_WRONLY | O_APPEND | O_NOFOLLOW);
+ if (fd == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to open file \"%s/%s\" for append",
+ adhost->adh_directory, filename);
+ PJDLOG_ASSERT(errno > 0);
+ return (ADIST_ERROR_OPEN);
+ }
+ pjdlog_debug(1, "Opened file \"%s/%s\".",
+ adhost->adh_directory, filename);
+ break;
+ case TRAIL_NEWER:
+ /* Opening new file. */
+ fd = openat(adhost->adh_trail_dirfd, filename,
+ O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
+ if (fd == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to create file \"%s/%s\"",
+ adhost->adh_directory, filename);
+ PJDLOG_ASSERT(errno > 0);
+ return (ADIST_ERROR_CREATE);
+ }
+ pjdlog_debug(1, "Created file \"%s/%s\".",
+ adhost->adh_directory, filename);
+ break;
+ case TRAIL_OLDER:
+ /* Trying to open old file. */
+ pjdlog_error("Sender wants to open an old file \"%s\".", filename);
+ return (ADIST_ERROR_OPEN_OLD);
+ default:
+ PJDLOG_ABORT("Unknown return value from trail_name_compare().");
+ }
+ PJDLOG_VERIFY(strlcpy(adhost->adh_trail_name, filename,
+ sizeof(adhost->adh_trail_name)) < sizeof(adhost->adh_trail_name));
+ adhost->adh_trail_fd = fd;
+ return (0);
+}
+
+/*
+ * Function appends data to the trail file that is currently open.
+ */
+static int
+receiver_append(const unsigned char *data, size_t size)
+{
+ ssize_t done;
+ size_t osize;
+
+ /* We should have opened trail file. */
+ if (adhost->adh_trail_fd == -1) {
+ pjdlog_error("Sender requested append without first opening file.");
+ return (ADIST_ERROR_WRONG_ORDER);
+ }
+
+ osize = size;
+ while (size > 0) {
+ done = write(adhost->adh_trail_fd, data, size);
+ if (done == -1) {
+ if (errno == EINTR)
+ continue;
+ pjdlog_errno(LOG_ERR, "Write to \"%s/%s\" failed",
+ adhost->adh_directory, adhost->adh_trail_name);
+ PJDLOG_ASSERT(errno > 0);
+ return (ADIST_ERROR_WRITE);
+ }
+ pjdlog_debug(3, "Wrote %zd bytes into \"%s/%s\".", done,
+ adhost->adh_directory, adhost->adh_trail_name);
+ size -= done;
+ }
+ pjdlog_debug(2, "Appended %zu bytes to file \"%s/%s\".",
+ osize, adhost->adh_directory, adhost->adh_trail_name);
+ return (0);
+}
+
+static int
+receiver_close(const char *filename)
+{
+
+ /* We should have opened trail file. */
+ if (adhost->adh_trail_fd == -1) {
+ pjdlog_error("Sender requested closing file without first opening it.");
+ return (ADIST_ERROR_WRONG_ORDER);
+ }
+
+ /* Validate if we can do the rename. */
+ if (!trail_validate_name(adhost->adh_trail_name, filename)) {
+ pjdlog_error("Sender wants to close file \"%s\" using name \"%s\".",
+ adhost->adh_trail_name, filename);
+ return (ADIST_ERROR_INVALID_NAME);
+ }
+
+ PJDLOG_VERIFY(close(adhost->adh_trail_fd) == 0);
+ adhost->adh_trail_fd = -1;
+
+ pjdlog_debug(1, "Closed file \"%s/%s\".", adhost->adh_directory,
+ adhost->adh_trail_name);
+
+ if (strcmp(adhost->adh_trail_name, filename) == 0) {
+ /* File name didn't change, we are done here. */
+ return (0);
+ }
+
+ if (renameat(adhost->adh_trail_dirfd, adhost->adh_trail_name,
+ adhost->adh_trail_dirfd, filename) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to rename \"%s\" to \"%s\"",
+ adhost->adh_trail_name, filename);
+ PJDLOG_ASSERT(errno > 0);
+ return (ADIST_ERROR_RENAME);
+ }
+ pjdlog_debug(1, "Renamed file \"%s/%s\" to \"%s/%s\".",
+ adhost->adh_directory, adhost->adh_trail_name,
+ adhost->adh_directory, filename);
+ PJDLOG_VERIFY(strlcpy(adhost->adh_trail_name, filename,
+ sizeof(adhost->adh_trail_name)) < sizeof(adhost->adh_trail_name));
+
+ return (0);
+}
+
+static int
+receiver_error(void)
+{
+
+ /* We should have opened trail file. */
+ if (adhost->adh_trail_fd == -1) {
+ pjdlog_error("Sender send read error, but file is not open.");
+ return (ADIST_ERROR_WRONG_ORDER);
+ }
+
+ PJDLOG_VERIFY(close(adhost->adh_trail_fd) == 0);
+ adhost->adh_trail_fd = -1;
+
+ pjdlog_debug(1, "Closed file \"%s/%s\".", adhost->adh_directory,
+ adhost->adh_trail_name);
+
+ return (0);
+}
+
+static void *
+disk_thread(void *arg __unused)
+{
+ struct adreq *adreq;
+
+ for (;;) {
+ pjdlog_debug(3, "disk: Taking request.");
+ QUEUE_TAKE(adreq, &adist_disk_list, 0);
+ adreq_log(LOG_DEBUG, 3, -1, adreq, "disk: (%p) Got request: ",
+ adreq);
+ /* Handle the actual request. */
+ switch (adreq->adr_cmd) {
+ case ADIST_CMD_OPEN:
+ adreq->adr_error = receiver_open(adreq->adr_data);
+ break;
+ case ADIST_CMD_APPEND:
+ adreq->adr_error = receiver_append(adreq->adr_data,
+ adreq->adr_datasize);
+ break;
+ case ADIST_CMD_CLOSE:
+ adreq->adr_error = receiver_close(adreq->adr_data);
+ break;
+ case ADIST_CMD_ERROR:
+ adreq->adr_error = receiver_error();
+ break;
+ default:
+ PJDLOG_ABORT("Unexpected command (cmd=%hhu).",
+ adreq->adr_cmd);
+ }
+ if (adreq->adr_error != 0) {
+ adreq_log(LOG_ERR, 0, adreq->adr_error, adreq,
+ "Request failed: ");
+ }
+ pjdlog_debug(3, "disk: (%p) Moving request to the send queue.",
+ adreq);
+ QUEUE_INSERT(adreq, &adist_send_list);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * Thread sends requests back to primary node.
+ */
+static void *
+send_thread(void *arg __unused)
+{
+ struct adreq *adreq;
+ struct adrep adrep;
+
+ for (;;) {
+ pjdlog_debug(3, "send: Taking request.");
+ QUEUE_TAKE(adreq, &adist_send_list, 0);
+ adreq_log(LOG_DEBUG, 3, -1, adreq, "send: (%p) Got request: ",
+ adreq);
+ adrep.adrp_byteorder = ADIST_BYTEORDER;
+ adrep.adrp_seq = adreq->adr_seq;
+ adrep.adrp_error = adreq->adr_error;
+ if (proto_send(adhost->adh_remote, &adrep,
+ sizeof(adrep)) == -1) {
+ pjdlog_exit(EX_TEMPFAIL, "Unable to send reply");
+ }
+ pjdlog_debug(3, "send: (%p) Moving request to the free queue.",
+ adreq);
+ adreq_clear(adreq);
+ QUEUE_INSERT(adreq, &adist_free_list);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+static void
+receiver_directory_create(void)
+{
+ struct passwd *pw;
+
+ /*
+ * According to getpwnam(3) we have to clear errno before calling the
+ * function to be able to distinguish between an error and missing
+ * entry (with is not treated as error by getpwnam(3)).
+ */
+ errno = 0;
+ pw = getpwnam(ADIST_USER);
+ if (pw == NULL) {
+ if (errno != 0) {
+ pjdlog_exit(EX_NOUSER,
+ "Unable to find info about '%s' user", ADIST_USER);
+ } else {
+ pjdlog_exitx(EX_NOUSER, "User '%s' doesn't exist.",
+ ADIST_USER);
+ }
+ }
+
+ if (mkdir(adhost->adh_directory, 0700) == -1) {
+ pjdlog_exit(EX_OSFILE, "Unable to create directory \"%s\"",
+ adhost->adh_directory);
+ }
+ if (chown(adhost->adh_directory, pw->pw_uid, pw->pw_gid) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to change owner of the directory \"%s\"",
+ adhost->adh_directory);
+ (void)rmdir(adhost->adh_directory);
+ exit(EX_OSFILE);
+ }
+}
+
+static void
+receiver_directory_open(void)
+{
+
+#ifdef HAVE_FDOPENDIR
+ adhost->adh_trail_dirfd = open(adhost->adh_directory,
+ O_RDONLY | O_DIRECTORY);
+ if (adhost->adh_trail_dirfd == -1) {
+ if (errno == ENOENT) {
+ receiver_directory_create();
+ adhost->adh_trail_dirfd = open(adhost->adh_directory,
+ O_RDONLY | O_DIRECTORY);
+ }
+ if (adhost->adh_trail_dirfd == -1) {
+ pjdlog_exit(EX_CONFIG,
+ "Unable to open directory \"%s\"",
+ adhost->adh_directory);
+ }
+ }
+ adhost->adh_trail_dirfp = fdopendir(adhost->adh_trail_dirfd);
+ if (adhost->adh_trail_dirfp == NULL) {
+ pjdlog_exit(EX_CONFIG, "Unable to fdopen directory \"%s\"",
+ adhost->adh_directory);
+ }
+#else
+ struct stat sb;
+
+ if (stat(adhost->adh_directory, &sb) == -1) {
+ if (errno == ENOENT) {
+ receiver_directory_create();
+ } else {
+ pjdlog_exit(EX_CONFIG,
+ "Unable to stat directory \"%s\"",
+ adhost->adh_directory);
+ }
+ }
+ adhost->adh_trail_dirfp = opendir(adhost->adh_directory);
+ if (adhost->adh_trail_dirfp == NULL) {
+ pjdlog_exit(EX_CONFIG, "Unable to open directory \"%s\"",
+ adhost->adh_directory);
+ }
+ adhost->adh_trail_dirfd = dirfd(adhost->adh_trail_dirfp);
+#endif
+}
+
+static void
+receiver_connect(void)
+{
+ uint64_t trail_size;
+ struct stat sb;
+
+ PJDLOG_ASSERT(adhost->adh_trail_dirfp != NULL);
+
+ trail_last(adhost->adh_trail_dirfp, adhost->adh_trail_name,
+ sizeof(adhost->adh_trail_name));
+
+ if (adhost->adh_trail_name[0] == '\0') {
+ trail_size = 0;
+ } else {
+ if (fstatat(adhost->adh_trail_dirfd, adhost->adh_trail_name,
+ &sb, AT_SYMLINK_NOFOLLOW) == -1) {
+ pjdlog_exit(EX_CONFIG, "Unable to stat \"%s/%s\"",
+ adhost->adh_directory, adhost->adh_trail_name);
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ pjdlog_exitx(EX_CONFIG,
+ "File \"%s/%s\" is not a regular file.",
+ adhost->adh_directory, adhost->adh_trail_name);
+ }
+ trail_size = sb.st_size;
+ }
+ trail_size = htole64(trail_size);
+ if (proto_send(adhost->adh_remote, &trail_size,
+ sizeof(trail_size)) == -1) {
+ pjdlog_exit(EX_TEMPFAIL,
+ "Unable to send size of the most recent trail file");
+ }
+ if (proto_send(adhost->adh_remote, adhost->adh_trail_name,
+ sizeof(adhost->adh_trail_name)) == -1) {
+ pjdlog_exit(EX_TEMPFAIL,
+ "Unable to send name of the most recent trail file");
+ }
+}
+
+void
+adist_receiver(struct adist_config *config, struct adist_host *adh)
+{
+ sigset_t mask;
+ pthread_t td;
+ pid_t pid;
+ int error, mode, debuglevel;
+
+ pid = fork();
+ if (pid == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to fork");
+ proto_close(adh->adh_remote);
+ adh->adh_remote = NULL;
+ return;
+ }
+
+ if (pid > 0) {
+ /* This is parent. */
+ proto_close(adh->adh_remote);
+ adh->adh_remote = NULL;
+ adh->adh_worker_pid = pid;
+ return;
+ }
+
+ adcfg = config;
+ adhost = adh;
+ mode = pjdlog_mode_get();
+ debuglevel = pjdlog_debug_get();
+
+ descriptors_cleanup(adhost);
+
+// descriptors_assert(adhost, mode);
+
+ pjdlog_init(mode);
+ pjdlog_debug_set(debuglevel);
+ pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
+ role2str(adhost->adh_role));
+#ifdef HAVE_SETPROCTITLE
+ setproctitle("%s (%s)", adhost->adh_name, role2str(adhost->adh_role));
+#endif
+
+ PJDLOG_VERIFY(sigemptyset(&mask) == 0);
+ PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
+
+ /* Error in setting timeout is not critical, but why should it fail? */
+ if (proto_timeout(adhost->adh_remote, adcfg->adc_timeout) == -1)
+ pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");
+
+ init_environment();
+
+ adhost->adh_trail_fd = -1;
+ receiver_directory_open();
+
+ if (sandbox(ADIST_USER, true, "auditdistd: %s (%s)",
+ role2str(adhost->adh_role), adhost->adh_name) != 0) {
+ exit(EX_CONFIG);
+ }
+ pjdlog_info("Privileges successfully dropped.");
+
+ receiver_connect();
+
+ error = pthread_create(&td, NULL, recv_thread, adhost);
+ PJDLOG_ASSERT(error == 0);
+ error = pthread_create(&td, NULL, disk_thread, adhost);
+ PJDLOG_ASSERT(error == 0);
+ (void)send_thread(adhost);
+}
diff --git a/contrib/openbsm/bin/auditdistd/renameat.h b/contrib/openbsm/bin/auditdistd/renameat.h
new file mode 100644
index 0000000..0becb8a
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/renameat.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _RENAMEAT_H_
+#define _RENAMEAT_H_
+
+#include <stdio.h>
+#include <unistd.h>
+
+static int
+renameat(int fromfd, const char *from, int tofd, const char *to)
+{
+ int cfd, error, ret;
+
+ if (fromfd != tofd) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ cfd = open(".", O_RDONLY | O_DIRECTORY);
+ if (cfd == -1)
+ return (-1);
+
+ if (fchdir(fromfd) == -1) {
+ error = errno;
+ (void)close(cfd);
+ errno = error;
+ return (-1);
+ }
+
+ ret = rename(from, to);
+
+ error = errno;
+ (void)fchdir(cfd);
+ (void)close(cfd);
+ errno = error;
+ return (ret);
+}
+
+#endif /* !_RENAMEAT_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/sandbox.c b/contrib/openbsm/bin/auditdistd/sandbox.c
new file mode 100644
index 0000000..53cd6b3
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/sandbox.c
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config/config.h>
+
+#include <sys/param.h>
+#ifdef HAVE_JAIL
+#include <sys/jail.h>
+#endif
+#ifdef HAVE_CAP_ENTER
+#include <sys/capability.h>
+#endif
+
+#include <errno.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "pjdlog.h"
+#include "sandbox.h"
+
+static int
+groups_compare(const void *grp0, const void *grp1)
+{
+ gid_t gr0 = *(const gid_t *)grp0;
+ gid_t gr1 = *(const gid_t *)grp1;
+
+ return (gr0 <= gr1 ? (gr0 < gr1 ? -1 : 0) : 1);
+
+}
+
+int
+sandbox(const char *user, bool capsicum, const char *fmt, ...)
+{
+#ifdef HAVE_JAIL
+ struct jail jailst;
+ char *jailhost;
+ va_list ap;
+#endif
+ struct passwd *pw;
+ uid_t ruid, euid;
+ gid_t rgid, egid;
+#ifdef HAVE_GETRESUID
+ uid_t suid;
+#endif
+#ifdef HAVE_GETRESGID
+ gid_t sgid;
+#endif
+ gid_t *groups, *ggroups;
+ bool jailed;
+ int ngroups, ret;
+
+ PJDLOG_ASSERT(user != NULL);
+ PJDLOG_ASSERT(fmt != NULL);
+
+ ret = -1;
+ groups = NULL;
+ ggroups = NULL;
+
+ /*
+ * According to getpwnam(3) we have to clear errno before calling the
+ * function to be able to distinguish between an error and missing
+ * entry (with is not treated as error by getpwnam(3)).
+ */
+ errno = 0;
+ pw = getpwnam(user);
+ if (pw == NULL) {
+ if (errno != 0) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to find info about '%s' user", user);
+ goto out;
+ } else {
+ pjdlog_error("'%s' user doesn't exist.", user);
+ errno = ENOENT;
+ goto out;
+ }
+ }
+
+ ngroups = sysconf(_SC_NGROUPS_MAX);
+ if (ngroups == -1) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to obtain maximum number of groups");
+ ngroups = NGROUPS_MAX;
+ }
+ ngroups++; /* For base gid. */
+ groups = malloc(sizeof(groups[0]) * ngroups);
+ if (groups == NULL) {
+ pjdlog_error("Unable to allocate memory for %d groups.",
+ ngroups);
+ goto out;
+ }
+ if (getgrouplist(user, pw->pw_gid, groups, &ngroups) == -1) {
+ pjdlog_error("Unable to obtain groups of user %s.", user);
+ goto out;
+ }
+
+#ifdef HAVE_JAIL
+ va_start(ap, fmt);
+ (void)vasprintf(&jailhost, fmt, ap);
+ va_end(ap);
+ if (jailhost == NULL) {
+ pjdlog_error("Unable to allocate memory for jail host name.");
+ goto out;
+ }
+ bzero(&jailst, sizeof(jailst));
+ jailst.version = JAIL_API_VERSION;
+ jailst.path = pw->pw_dir;
+ jailst.hostname = jailhost;
+ if (jail(&jailst) >= 0) {
+ jailed = true;
+ } else {
+ jailed = false;
+ pjdlog_errno(LOG_WARNING,
+ "Unable to jail to directory %s", pw->pw_dir);
+ }
+ free(jailhost);
+#else /* !HAVE_JAIL */
+ jailed = false;
+#endif /* !HAVE_JAIL */
+
+ if (!jailed) {
+ if (chroot(pw->pw_dir) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to change root directory to %s",
+ pw->pw_dir);
+ goto out;
+ }
+ }
+ PJDLOG_VERIFY(chdir("/") == 0);
+
+ if (setgroups(ngroups, groups) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to set groups");
+ goto out;
+ }
+ if (setgid(pw->pw_gid) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to set gid to %u",
+ (unsigned int)pw->pw_gid);
+ goto out;
+ }
+ if (setuid(pw->pw_uid) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to set uid to %u",
+ (unsigned int)pw->pw_uid);
+ goto out;
+ }
+
+#ifdef HAVE_CAP_ENTER
+ if (capsicum) {
+ capsicum = (cap_enter() == 0);
+ if (!capsicum) {
+ pjdlog_common(LOG_DEBUG, 1, errno,
+ "Unable to sandbox using capsicum");
+ }
+ }
+#else /* !HAVE_CAP_ENTER */
+ capsicum = false;
+#endif /* !HAVE_CAP_ENTER */
+
+ /*
+ * Better be sure that everything succeeded.
+ */
+#ifdef HAVE_GETRESUID
+ PJDLOG_VERIFY(getresuid(&ruid, &euid, &suid) == 0);
+ PJDLOG_VERIFY(suid == pw->pw_uid);
+#else
+ ruid = getuid();
+ euid = geteuid();
+#endif
+ PJDLOG_VERIFY(ruid == pw->pw_uid);
+ PJDLOG_VERIFY(euid == pw->pw_uid);
+#ifdef HAVE_GETRESGID
+ PJDLOG_VERIFY(getresgid(&rgid, &egid, &sgid) == 0);
+ PJDLOG_VERIFY(sgid == pw->pw_gid);
+#else
+ rgid = getgid();
+ egid = getegid();
+#endif
+ PJDLOG_VERIFY(rgid == pw->pw_gid);
+ PJDLOG_VERIFY(egid == pw->pw_gid);
+ PJDLOG_VERIFY(getgroups(0, NULL) == ngroups);
+ ggroups = malloc(sizeof(ggroups[0]) * ngroups);
+ if (ggroups == NULL) {
+ pjdlog_error("Unable to allocate memory for %d groups.",
+ ngroups);
+ goto out;
+ }
+ PJDLOG_VERIFY(getgroups(ngroups, ggroups) == ngroups);
+ qsort(groups, (size_t)ngroups, sizeof(groups[0]), groups_compare);
+ qsort(ggroups, (size_t)ngroups, sizeof(ggroups[0]), groups_compare);
+ PJDLOG_VERIFY(bcmp(groups, ggroups, sizeof(groups[0]) * ngroups) == 0);
+
+ pjdlog_debug(1,
+ "Privileges successfully dropped using %s%s+setgid+setuid.",
+ capsicum ? "capsicum+" : "", jailed ? "jail" : "chroot");
+
+ ret = 0;
+out:
+ if (groups != NULL)
+ free(groups);
+ if (ggroups != NULL)
+ free(ggroups);
+ return (ret);
+}
diff --git a/contrib/openbsm/bin/auditdistd/sandbox.h b/contrib/openbsm/bin/auditdistd/sandbox.h
new file mode 100644
index 0000000..7bcde25
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/sandbox.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SANDBOX_H_
+#define _SANDBOX_H_
+
+#include <stdbool.h>
+
+int sandbox(const char *user, bool capsicum, const char *fmt, ...);
+
+#endif /* !_SANDBOX_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/sender.c b/contrib/openbsm/bin/auditdistd/sender.c
new file mode 100644
index 0000000..4349b0f
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/sender.c
@@ -0,0 +1,845 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config/config.h>
+
+#include <sys/param.h>
+#if defined(HAVE_SYS_ENDIAN_H) && defined(HAVE_BSWAP)
+#include <sys/endian.h>
+#else /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include <machine/endian.h>
+#else /* !HAVE_MACHINE_ENDIAN_H */
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#else /* !HAVE_ENDIAN_H */
+#error "No supported endian.h"
+#endif /* !HAVE_ENDIAN_H */
+#endif /* !HAVE_MACHINE_ENDIAN_H */
+#include <compat/endian.h>
+#endif /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+#include <signal.h>
+#include <string.h>
+#include <strings.h>
+
+#include <openssl/hmac.h>
+
+#ifndef HAVE_SIGTIMEDWAIT
+#include "sigtimedwait.h"
+#endif
+
+#include "auditdistd.h"
+#include "pjdlog.h"
+#include "proto.h"
+#include "sandbox.h"
+#include "subr.h"
+#include "synch.h"
+#include "trail.h"
+
+static struct adist_config *adcfg;
+static struct adist_host *adhost;
+
+static pthread_rwlock_t adist_remote_lock;
+static pthread_mutex_t adist_remote_mtx;
+static pthread_cond_t adist_remote_cond;
+static struct trail *adist_trail;
+
+static TAILQ_HEAD(, adreq) adist_free_list;
+static pthread_mutex_t adist_free_list_lock;
+static pthread_cond_t adist_free_list_cond;
+static TAILQ_HEAD(, adreq) adist_send_list;
+static pthread_mutex_t adist_send_list_lock;
+static pthread_cond_t adist_send_list_cond;
+static TAILQ_HEAD(, adreq) adist_recv_list;
+static pthread_mutex_t adist_recv_list_lock;
+static pthread_cond_t adist_recv_list_cond;
+
+static void
+init_environment(void)
+{
+ struct adreq *adreq;
+ unsigned int ii;
+
+ rw_init(&adist_remote_lock);
+ mtx_init(&adist_remote_mtx);
+ cv_init(&adist_remote_cond);
+ TAILQ_INIT(&adist_free_list);
+ mtx_init(&adist_free_list_lock);
+ cv_init(&adist_free_list_cond);
+ TAILQ_INIT(&adist_send_list);
+ mtx_init(&adist_send_list_lock);
+ cv_init(&adist_send_list_cond);
+ TAILQ_INIT(&adist_recv_list);
+ mtx_init(&adist_recv_list_lock);
+ cv_init(&adist_recv_list_cond);
+
+ for (ii = 0; ii < ADIST_QUEUE_SIZE; ii++) {
+ adreq = malloc(sizeof(*adreq) + ADIST_BUF_SIZE);
+ if (adreq == NULL) {
+ pjdlog_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for adreq object.",
+ sizeof(*adreq) + ADIST_BUF_SIZE);
+ }
+ adreq->adr_byteorder = ADIST_BYTEORDER;
+ adreq->adr_cmd = ADIST_CMD_UNDEFINED;
+ adreq->adr_seq = 0;
+ adreq->adr_datasize = 0;
+ TAILQ_INSERT_TAIL(&adist_free_list, adreq, adr_next);
+ }
+}
+
+static int
+sender_connect(void)
+{
+ unsigned char rnd[32], hash[32], resp[32];
+ struct proto_conn *conn;
+ char welcome[8];
+ int16_t val;
+
+ val = 1;
+ if (proto_send(adhost->adh_conn, &val, sizeof(val)) < 0) {
+ pjdlog_exit(EX_TEMPFAIL,
+ "Unable to send connection request to parent");
+ }
+ if (proto_recv(adhost->adh_conn, &val, sizeof(val)) < 0) {
+ pjdlog_exit(EX_TEMPFAIL,
+ "Unable to receive reply to connection request from parent");
+ }
+ if (val != 0) {
+ errno = val;
+ pjdlog_errno(LOG_WARNING, "Unable to connect to %s",
+ adhost->adh_remoteaddr);
+ return (-1);
+ }
+ if (proto_connection_recv(adhost->adh_conn, true, &conn) < 0) {
+ pjdlog_exit(EX_TEMPFAIL,
+ "Unable to receive connection from parent");
+ }
+ if (proto_connect_wait(conn, adcfg->adc_timeout) < 0) {
+ pjdlog_errno(LOG_WARNING, "Unable to connect to %s",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Connected to %s.", adhost->adh_remoteaddr);
+ /* Error in setting timeout is not critical, but why should it fail? */
+ if (proto_timeout(conn, adcfg->adc_timeout) < 0)
+ pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");
+ else
+ pjdlog_debug(1, "Timeout set to %d.", adcfg->adc_timeout);
+
+ /* Exchange welcome message, which includes version number. */
+ (void)snprintf(welcome, sizeof(welcome), "ADIST%02d", ADIST_VERSION);
+ if (proto_send(conn, welcome, sizeof(welcome)) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to send welcome message to %s",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Welcome message sent (%s).", welcome);
+ bzero(welcome, sizeof(welcome));
+ if (proto_recv(conn, welcome, sizeof(welcome)) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to receive welcome message from %s",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ if (strncmp(welcome, "ADIST", 5) != 0 || !isdigit(welcome[5]) ||
+ !isdigit(welcome[6]) || welcome[7] != '\0') {
+ pjdlog_warning("Invalid welcome message from %s.",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Welcome message received (%s).", welcome);
+ /*
+ * Receiver can only reply with version number lower or equal to
+ * the one we sent.
+ */
+ adhost->adh_version = atoi(welcome + 5);
+ if (adhost->adh_version > ADIST_VERSION) {
+ pjdlog_warning("Invalid version number from %s (%d received, up to %d supported).",
+ adhost->adh_remoteaddr, adhost->adh_version, ADIST_VERSION);
+ proto_close(conn);
+ return (-1);
+ }
+
+ pjdlog_debug(1, "Version %d negotiated with %s.", adhost->adh_version,
+ adhost->adh_remoteaddr);
+
+ if (proto_send(conn, adcfg->adc_name, sizeof(adcfg->adc_name)) == -1) {
+ pjdlog_errno(LOG_WARNING, "Unable to send name to %s",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Name (%s) sent.", adcfg->adc_name);
+
+ if (proto_recv(conn, rnd, sizeof(rnd)) == -1) {
+ pjdlog_errno(LOG_WARNING, "Unable to receive challenge from %s",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Challenge received.");
+
+ if (HMAC(EVP_sha256(), adhost->adh_password,
+ (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash,
+ NULL) == NULL) {
+ pjdlog_warning("Unable to generate response.");
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Response generated.");
+
+ if (proto_send(conn, hash, sizeof(hash)) == -1) {
+ pjdlog_errno(LOG_WARNING, "Unable to send response to %s",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Response sent.");
+
+ if (adist_random(rnd, sizeof(rnd)) == -1) {
+ pjdlog_warning("Unable to generate challenge.");
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Challenge generated.");
+
+ if (proto_send(conn, rnd, sizeof(rnd)) == -1) {
+ pjdlog_errno(LOG_WARNING, "Unable to send challenge to %s",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Challenge sent.");
+
+ if (proto_recv(conn, resp, sizeof(resp)) == -1) {
+ pjdlog_errno(LOG_WARNING, "Unable to receive response from %s",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Response received.");
+
+ if (HMAC(EVP_sha256(), adhost->adh_password,
+ (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash,
+ NULL) == NULL) {
+ pjdlog_warning("Unable to generate hash.");
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Hash generated.");
+
+ if (memcmp(resp, hash, sizeof(hash)) != 0) {
+ pjdlog_warning("Invalid response from %s (wrong password?).",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_info("Receiver authenticated.");
+
+ if (proto_recv(conn, &adhost->adh_trail_offset,
+ sizeof(adhost->adh_trail_offset)) == -1) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to receive size of the most recent trail file from %s",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ adhost->adh_trail_offset = le64toh(adhost->adh_trail_offset);
+ if (proto_recv(conn, &adhost->adh_trail_name,
+ sizeof(adhost->adh_trail_name)) == -1) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to receive name of the most recent trail file from %s",
+ adhost->adh_remoteaddr);
+ proto_close(conn);
+ return (-1);
+ }
+ pjdlog_debug(1, "Trail name (%s) and offset (%ju) received.",
+ adhost->adh_trail_name, (uintmax_t)adhost->adh_trail_offset);
+
+ rw_wlock(&adist_remote_lock);
+ mtx_lock(&adist_remote_mtx);
+ PJDLOG_ASSERT(adhost->adh_remote == NULL);
+ PJDLOG_ASSERT(conn != NULL);
+ adhost->adh_remote = conn;
+ mtx_unlock(&adist_remote_mtx);
+ rw_unlock(&adist_remote_lock);
+ cv_signal(&adist_remote_cond);
+
+ return (0);
+}
+
+static void
+sender_disconnect(void)
+{
+
+ rw_wlock(&adist_remote_lock);
+ /*
+ * Check for a race between dropping rlock and acquiring wlock -
+ * another thread can close connection in-between.
+ */
+ if (adhost->adh_remote == NULL) {
+ rw_unlock(&adist_remote_lock);
+ return;
+ }
+ pjdlog_debug(2, "Closing connection to %s.", adhost->adh_remoteaddr);
+ proto_close(adhost->adh_remote);
+ mtx_lock(&adist_remote_mtx);
+ adhost->adh_remote = NULL;
+ adhost->adh_reset = true;
+ adhost->adh_trail_name[0] = '\0';
+ adhost->adh_trail_offset = 0;
+ mtx_unlock(&adist_remote_mtx);
+ rw_unlock(&adist_remote_lock);
+
+ pjdlog_warning("Disconnected from %s.", adhost->adh_remoteaddr);
+
+ /* Move all in-flight requests back onto free list. */
+ mtx_lock(&adist_free_list_lock);
+ mtx_lock(&adist_send_list_lock);
+ TAILQ_CONCAT(&adist_free_list, &adist_send_list, adr_next);
+ mtx_unlock(&adist_send_list_lock);
+ mtx_lock(&adist_recv_list_lock);
+ TAILQ_CONCAT(&adist_free_list, &adist_recv_list, adr_next);
+ mtx_unlock(&adist_recv_list_lock);
+ mtx_unlock(&adist_free_list_lock);
+}
+
+static void
+adreq_fill(struct adreq *adreq, uint8_t cmd, const unsigned char *data,
+ size_t size)
+{
+ static uint64_t seq = 1;
+
+ PJDLOG_ASSERT(size <= ADIST_BUF_SIZE);
+
+ switch (cmd) {
+ case ADIST_CMD_OPEN:
+ case ADIST_CMD_CLOSE:
+ PJDLOG_ASSERT(data != NULL && size == 0);
+ size = strlen(data) + 1;
+ break;
+ case ADIST_CMD_APPEND:
+ PJDLOG_ASSERT(data != NULL && size > 0);
+ break;
+ case ADIST_CMD_KEEPALIVE:
+ case ADIST_CMD_ERROR:
+ PJDLOG_ASSERT(data == NULL && size == 0);
+ break;
+ default:
+ PJDLOG_ABORT("Invalid command (%hhu).", cmd);
+ }
+
+ adreq->adr_cmd = cmd;
+ adreq->adr_seq = seq++;
+ adreq->adr_datasize = size;
+ /* Don't copy if data is already in out buffer. */
+ if (data != NULL && data != adreq->adr_data)
+ bcopy(data, adreq->adr_data, size);
+}
+
+static bool
+read_thread_wait(void)
+{
+ bool newfile = false;
+
+ mtx_lock(&adist_remote_mtx);
+ if (adhost->adh_reset) {
+reset:
+ adhost->adh_reset = false;
+ if (trail_filefd(adist_trail) != -1)
+ trail_close(adist_trail);
+ trail_reset(adist_trail);
+ while (adhost->adh_remote == NULL)
+ cv_wait(&adist_remote_cond, &adist_remote_mtx);
+ trail_start(adist_trail, adhost->adh_trail_name,
+ adhost->adh_trail_offset);
+ newfile = true;
+ }
+ mtx_unlock(&adist_remote_mtx);
+ while (trail_filefd(adist_trail) == -1) {
+ newfile = true;
+ wait_for_dir();
+ /*
+ * We may have been disconnected and reconnected in the
+ * meantime, check if reset is set.
+ */
+ mtx_lock(&adist_remote_mtx);
+ if (adhost->adh_reset)
+ goto reset;
+ mtx_unlock(&adist_remote_mtx);
+ if (trail_filefd(adist_trail) == -1)
+ trail_next(adist_trail);
+ }
+ if (newfile) {
+ pjdlog_debug(1, "Trail file \"%s/%s\" opened.",
+ adhost->adh_directory,
+ trail_filename(adist_trail));
+ (void)wait_for_file_init(trail_filefd(adist_trail));
+ }
+ return (newfile);
+}
+
+static void *
+read_thread(void *arg __unused)
+{
+ struct adreq *adreq;
+ ssize_t done;
+ bool newfile;
+
+ pjdlog_debug(1, "%s started.", __func__);
+
+ for (;;) {
+ newfile = read_thread_wait();
+ QUEUE_TAKE(adreq, &adist_free_list, 0);
+ if (newfile) {
+ adreq_fill(adreq, ADIST_CMD_OPEN,
+ trail_filename(adist_trail), 0);
+ newfile = false;
+ goto move;
+ }
+
+ done = read(trail_filefd(adist_trail), adreq->adr_data,
+ ADIST_BUF_SIZE);
+ if (done == -1) {
+ off_t offset;
+ int error;
+
+ error = errno;
+ offset = lseek(trail_filefd(adist_trail), 0, SEEK_CUR);
+ errno = error;
+ pjdlog_errno(LOG_ERR,
+ "Error while reading \"%s/%s\" at offset %jd",
+ adhost->adh_directory, trail_filename(adist_trail),
+ offset);
+ trail_close(adist_trail);
+ adreq_fill(adreq, ADIST_CMD_ERROR, NULL, 0);
+ goto move;
+ } else if (done == 0) {
+ /* End of file. */
+ pjdlog_debug(3, "End of \"%s/%s\".",
+ adhost->adh_directory, trail_filename(adist_trail));
+ if (!trail_switch(adist_trail)) {
+ /* More audit records can arrive. */
+ mtx_lock(&adist_free_list_lock);
+ TAILQ_INSERT_TAIL(&adist_free_list, adreq,
+ adr_next);
+ mtx_unlock(&adist_free_list_lock);
+ wait_for_file();
+ continue;
+ }
+ adreq_fill(adreq, ADIST_CMD_CLOSE,
+ trail_filename(adist_trail), 0);
+ trail_close(adist_trail);
+ goto move;
+ }
+
+ adreq_fill(adreq, ADIST_CMD_APPEND, adreq->adr_data, done);
+move:
+ pjdlog_debug(3,
+ "read thread: Moving request %p to the send queue (%hhu).",
+ adreq, adreq->adr_cmd);
+ QUEUE_INSERT(adreq, &adist_send_list);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+static void
+keepalive_send(void)
+{
+ struct adreq *adreq;
+
+ rw_rlock(&adist_remote_lock);
+ if (adhost->adh_remote == NULL) {
+ rw_unlock(&adist_remote_lock);
+ return;
+ }
+ rw_unlock(&adist_remote_lock);
+
+ mtx_lock(&adist_free_list_lock);
+ adreq = TAILQ_FIRST(&adist_free_list);
+ if (adreq != NULL)
+ TAILQ_REMOVE(&adist_free_list, adreq, adr_next);
+ mtx_unlock(&adist_free_list_lock);
+ if (adreq == NULL)
+ return;
+
+ adreq_fill(adreq, ADIST_CMD_KEEPALIVE, NULL, 0);
+
+ QUEUE_INSERT(adreq, &adist_send_list);
+
+ pjdlog_debug(3, "keepalive_send: Request sent.");
+}
+
+/*
+ * Thread sends request to secondary node.
+ */
+static void *
+send_thread(void *arg __unused)
+{
+ time_t lastcheck, now;
+ struct adreq *adreq;
+
+ pjdlog_debug(1, "%s started.", __func__);
+
+ lastcheck = time(NULL);
+
+ for (;;) {
+ pjdlog_debug(3, "send thread: Taking request.");
+ for (;;) {
+ QUEUE_TAKE(adreq, &adist_send_list, ADIST_KEEPALIVE);
+ if (adreq != NULL)
+ break;
+ now = time(NULL);
+ if (lastcheck + ADIST_KEEPALIVE <= now) {
+ keepalive_send();
+ lastcheck = now;
+ }
+ }
+ PJDLOG_ASSERT(adreq != NULL);
+ pjdlog_debug(3, "send thread: (%p) Got request %hhu.", adreq,
+ adreq->adr_cmd);
+ /*
+ * Protect connection from disappearing.
+ */
+ rw_rlock(&adist_remote_lock);
+ /*
+ * Move the request to the recv queue first to avoid race
+ * where the recv thread receives the reply before we move
+ * the request to the recv queue.
+ */
+ QUEUE_INSERT(adreq, &adist_recv_list);
+ if (adhost->adh_remote == NULL ||
+ proto_send(adhost->adh_remote, &adreq->adr_packet,
+ ADPKT_SIZE(adreq)) == -1) {
+ rw_unlock(&adist_remote_lock);
+ pjdlog_debug(1,
+ "send thread: (%p) Unable to send request.", adreq);
+ if (adhost->adh_remote != NULL)
+ sender_disconnect();
+ continue;
+ } else {
+ pjdlog_debug(3, "Request %p sent successfully.", adreq);
+ adreq_log(LOG_DEBUG, 2, -1, adreq,
+ "send: (%p) Request sent: ", adreq);
+ rw_unlock(&adist_remote_lock);
+ }
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+static void
+adrep_decode_header(struct adrep *adrep)
+{
+
+ /* Byte-swap only is the receiver is using different byte order. */
+ if (adrep->adrp_byteorder != ADIST_BYTEORDER) {
+ adrep->adrp_byteorder = ADIST_BYTEORDER;
+ adrep->adrp_seq = bswap64(adrep->adrp_seq);
+ adrep->adrp_error = bswap16(adrep->adrp_error);
+ }
+}
+
+/*
+ * Thread receives answer from secondary node and passes it to ggate_send
+ * thread.
+ */
+static void *
+recv_thread(void *arg __unused)
+{
+ struct adrep adrep;
+ struct adreq *adreq;
+
+ pjdlog_debug(1, "%s started.", __func__);
+
+ for (;;) {
+ /* Wait until there is anything to receive. */
+ QUEUE_WAIT(&adist_recv_list);
+ pjdlog_debug(3, "recv thread: Got something.");
+ rw_rlock(&adist_remote_lock);
+ if (adhost->adh_remote == NULL) {
+ /*
+ * Connection is dead.
+ * XXX: We shouldn't be here.
+ */
+ rw_unlock(&adist_remote_lock);
+ continue;
+ }
+ if (proto_recv(adhost->adh_remote, &adrep,
+ sizeof(adrep)) == -1) {
+ rw_unlock(&adist_remote_lock);
+ pjdlog_errno(LOG_ERR, "Unable to receive reply");
+ sender_disconnect();
+ continue;
+ }
+ rw_unlock(&adist_remote_lock);
+ adrep_decode_header(&adrep);
+ /*
+ * Find the request that was just confirmed.
+ */
+ mtx_lock(&adist_recv_list_lock);
+ TAILQ_FOREACH(adreq, &adist_recv_list, adr_next) {
+ if (adreq->adr_seq == adrep.adrp_seq) {
+ TAILQ_REMOVE(&adist_recv_list, adreq,
+ adr_next);
+ break;
+ }
+ }
+ if (adreq == NULL) {
+ /*
+ * If we disconnected in the meantime, just continue.
+ * On disconnect sender_disconnect() clears the queue,
+ * we can use that.
+ */
+ if (TAILQ_EMPTY(&adist_recv_list)) {
+ mtx_unlock(&adist_recv_list_lock);
+ continue;
+ }
+ mtx_unlock(&adist_recv_list_lock);
+ pjdlog_error("Found no request matching received 'seq' field (%ju).",
+ (uintmax_t)adrep.adrp_seq);
+ sender_disconnect();
+ continue;
+ }
+ mtx_unlock(&adist_recv_list_lock);
+ adreq_log(LOG_DEBUG, 2, -1, adreq,
+ "recv thread: (%p) Request confirmed: ", adreq);
+ pjdlog_debug(3, "recv thread: (%p) Got request %hhu.", adreq,
+ adreq->adr_cmd);
+ if (adrep.adrp_error != 0) {
+ pjdlog_error("Receiver returned error (%s), disconnecting.",
+ adist_errstr((int)adrep.adrp_error));
+ sender_disconnect();
+ continue;
+ }
+ if (adreq->adr_cmd == ADIST_CMD_CLOSE)
+ trail_unlink(adist_trail, adreq->adr_data);
+ pjdlog_debug(3, "Request received successfully.");
+ QUEUE_INSERT(adreq, &adist_free_list);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+static void
+guard_check_connection(void)
+{
+
+ PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER);
+
+ rw_rlock(&adist_remote_lock);
+ if (adhost->adh_remote != NULL) {
+ rw_unlock(&adist_remote_lock);
+ pjdlog_debug(3, "remote_guard: Connection to %s is ok.",
+ adhost->adh_remoteaddr);
+ return;
+ }
+
+ /*
+ * Upgrade the lock. It doesn't have to be atomic as no other thread
+ * can change connection status from disconnected to connected.
+ */
+ rw_unlock(&adist_remote_lock);
+ pjdlog_debug(1, "remote_guard: Reconnecting to %s.",
+ adhost->adh_remoteaddr);
+ if (sender_connect() == 0) {
+ pjdlog_info("Successfully reconnected to %s.",
+ adhost->adh_remoteaddr);
+ } else {
+ pjdlog_debug(1, "remote_guard: Reconnect to %s failed.",
+ adhost->adh_remoteaddr);
+ }
+}
+
+/*
+ * Thread guards remote connections and reconnects when needed, handles
+ * signals, etc.
+ */
+static void *
+guard_thread(void *arg __unused)
+{
+ struct timespec timeout;
+ time_t lastcheck, now;
+ sigset_t mask;
+ int signo;
+
+ lastcheck = time(NULL);
+
+ PJDLOG_VERIFY(sigemptyset(&mask) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0);
+
+ timeout.tv_sec = ADIST_KEEPALIVE;
+ timeout.tv_nsec = 0;
+ signo = -1;
+
+ for (;;) {
+ switch (signo) {
+ case SIGINT:
+ case SIGTERM:
+ sigexit_received = true;
+ pjdlog_exitx(EX_OK,
+ "Termination signal received, exiting.");
+ break;
+ default:
+ break;
+ }
+
+ pjdlog_debug(3, "remote_guard: Checking connections.");
+ now = time(NULL);
+ if (lastcheck + ADIST_KEEPALIVE <= now) {
+ guard_check_connection();
+ lastcheck = now;
+ }
+ signo = sigtimedwait(&mask, NULL, &timeout);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+void
+adist_sender(struct adist_config *config, struct adist_host *adh)
+{
+ pthread_t td;
+ pid_t pid;
+ int error, mode, debuglevel;
+
+ /*
+ * Create communication channel for sending connection requests from
+ * child to parent.
+ */
+ if (proto_connect(NULL, "socketpair://", -1, &adh->adh_conn) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to create connection sockets between child and parent");
+ return;
+ }
+
+ pid = fork();
+ if (pid == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to fork");
+ proto_close(adh->adh_conn);
+ adh->adh_conn = NULL;
+ return;
+ }
+
+ if (pid > 0) {
+ /* This is parent. */
+ adh->adh_worker_pid = pid;
+ /* Declare that we are receiver. */
+ proto_recv(adh->adh_conn, NULL, 0);
+ return;
+ }
+
+ adcfg = config;
+ adhost = adh;
+
+ mode = pjdlog_mode_get();
+ debuglevel = pjdlog_debug_get();
+
+ /* Declare that we are sender. */
+ proto_send(adhost->adh_conn, NULL, 0);
+
+ descriptors_cleanup(adhost);
+
+#ifdef TODO
+ descriptors_assert(adhost, mode);
+#endif
+
+ pjdlog_init(mode);
+ pjdlog_debug_set(debuglevel);
+ pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
+ role2str(adhost->adh_role));
+#ifdef HAVE_SETPROCTITLE
+ setproctitle("[%s] (%s) ", adhost->adh_name,
+ role2str(adhost->adh_role));
+#endif
+
+ /*
+ * The sender process should be able to remove entries from its
+ * trail directory, but it should not be able to write to the
+ * trail files, only read from them.
+ */
+ adist_trail = trail_new(adhost->adh_directory, false);
+ if (adist_trail == NULL)
+ exit(EX_OSFILE);
+
+ if (sandbox(ADIST_USER, true, "auditdistd: %s (%s)",
+ role2str(adhost->adh_role), adhost->adh_name) != 0) {
+ exit(EX_CONFIG);
+ }
+ pjdlog_info("Privileges successfully dropped.");
+
+ /*
+ * We can ignore wait_for_dir_init() failures. It will fall back to
+ * using sleep(3).
+ */
+ (void)wait_for_dir_init(trail_dirfd(adist_trail));
+
+ init_environment();
+ if (sender_connect() == 0) {
+ pjdlog_info("Successfully connected to %s.",
+ adhost->adh_remoteaddr);
+ }
+ adhost->adh_reset = true;
+
+ /*
+ * Create the guard thread first, so we can handle signals from the
+ * very begining.
+ */
+ error = pthread_create(&td, NULL, guard_thread, NULL);
+ PJDLOG_ASSERT(error == 0);
+ error = pthread_create(&td, NULL, send_thread, NULL);
+ PJDLOG_ASSERT(error == 0);
+ error = pthread_create(&td, NULL, recv_thread, NULL);
+ PJDLOG_ASSERT(error == 0);
+ (void)read_thread(NULL);
+}
diff --git a/contrib/openbsm/bin/auditdistd/sigtimedwait.h b/contrib/openbsm/bin/auditdistd/sigtimedwait.h
new file mode 100644
index 0000000..06a4d13
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/sigtimedwait.h
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SIGTIMEDWAIT_H_
+#define _SIGTIMEDWAIT_H_
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pjdlog.h"
+
+static int
+sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec *timeout)
+{
+ struct itimerval it;
+ sigset_t mask;
+ int error, signo;
+
+ PJDLOG_ASSERT(info == NULL);
+
+ PJDLOG_VERIFY(sigemptyset(&mask) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGALRM) == 0);
+ PJDLOG_VERIFY(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
+
+ timerclear(&it.it_interval);
+ it.it_value.tv_sec = timeout->tv_sec;
+ it.it_value.tv_usec = timeout->tv_nsec / 1000;
+ if (it.it_value.tv_sec == 0 && it.it_value.tv_usec == 0)
+ it.it_value.tv_usec = 1;
+ PJDLOG_VERIFY(setitimer(ITIMER_REAL, &it, NULL) == 0);
+
+ bcopy(set, &mask, sizeof(mask));
+ PJDLOG_VERIFY(sigaddset(&mask, SIGALRM) == 0);
+
+ PJDLOG_VERIFY(sigwait(&mask, &signo) == 0);
+ error = errno;
+
+ timerclear(&it.it_interval);
+ timerclear(&it.it_value);
+ PJDLOG_VERIFY(setitimer(ITIMER_REAL, &it, NULL) == 0);
+
+ PJDLOG_VERIFY(sigemptyset(&mask) == 0);
+ PJDLOG_VERIFY(sigaddset(&mask, SIGALRM) == 0);
+ PJDLOG_VERIFY(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0);
+
+ if (signo == SIGALRM) {
+ errno = EAGAIN;
+ signo = -1;
+ } else {
+ errno = error;
+ }
+
+ return (signo);
+}
+
+#endif /* !_SIGTIMEDWAIT_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/strndup.h b/contrib/openbsm/bin/auditdistd/strndup.h
new file mode 100644
index 0000000..c36a950
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/strndup.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _STRNDUP_H_
+#define _STRNDUP_H_
+
+#include <stdlib.h>
+#include <string.h>
+
+static char *
+strndup(const char *str, size_t len)
+{
+ size_t outlen;
+ char *outstr;
+
+ outlen = strlen(str);
+ if (outlen > len)
+ outlen = len;
+ outstr = malloc(outlen + 1);
+ if (outstr != NULL) {
+ memcpy(outstr, str, outlen);
+ outstr[outlen] = '\0';
+ }
+ return (outstr);
+}
+
+#endif /* !_STRNDUP_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/subr.c b/contrib/openbsm/bin/auditdistd/subr.c
new file mode 100644
index 0000000..ecc626c
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/subr.c
@@ -0,0 +1,304 @@
+/*-
+ * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config/config.h>
+
+#ifdef HAVE_KQUEUE
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HAVE_ARC4RANDOM
+#include <openssl/rand.h>
+#endif
+
+#ifndef HAVE_STRLCAT
+#include <compat/strlcat.h>
+#endif
+
+#include "auditdistd.h"
+#include "pjdlog.h"
+#include "subr.h"
+
+int
+vsnprlcat(char *str, size_t size, const char *fmt, va_list ap)
+{
+ size_t len;
+
+ len = strlen(str);
+ return (vsnprintf(str + len, size - len, fmt, ap));
+}
+
+int
+snprlcat(char *str, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+ int result;
+
+ va_start(ap, fmt);
+ result = vsnprlcat(str, size, fmt, ap);
+ va_end(ap);
+ return (result);
+}
+
+const char *
+role2str(int role)
+{
+
+ switch (role) {
+ case ADIST_ROLE_SENDER:
+ return ("sender");
+ case ADIST_ROLE_RECEIVER:
+ return ("receiver");
+ }
+ return ("unknown");
+}
+
+const char *
+adist_errstr(int error)
+{
+
+ switch (error) {
+ case ADIST_ERROR_WRONG_ORDER:
+ return ("wrong operations order");
+ case ADIST_ERROR_INVALID_NAME:
+ return ("invalid trail file name");
+ case ADIST_ERROR_OPEN_OLD:
+ return ("attempt to open an old trail file");
+ case ADIST_ERROR_CREATE:
+ return ("creation of new trail file failed");
+ case ADIST_ERROR_OPEN:
+ return ("open of existing trail file failed");
+ case ADIST_ERROR_READ:
+ return ("read failed");
+ case ADIST_ERROR_WRITE:
+ return ("write failed");
+ case ADIST_ERROR_RENAME:
+ return ("rename of a trail file failed");
+ default:
+ return ("unknown error");
+ }
+}
+
+void
+adreq_log(int loglevel, int debuglevel, int error, struct adreq *adreq,
+ const char *fmt, ...)
+{
+ char msg[1024];
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void)vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ (void)snprlcat(msg, sizeof(msg), "(seq=%ju) ",
+ (uintmax_t)adreq->adr_seq);
+ switch (adreq->adr_cmd) {
+ case ADIST_CMD_OPEN:
+ (void)snprlcat(msg, sizeof(msg), "OPEN(%s)",
+ adreq->adr_data);
+ break;
+ case ADIST_CMD_APPEND:
+ (void)snprlcat(msg, sizeof(msg), "APPEND(%ju)",
+ (uintmax_t)adreq->adr_datasize);
+ break;
+ case ADIST_CMD_CLOSE:
+ (void)snprlcat(msg, sizeof(msg), "CLOSE(%s)",
+ adreq->adr_data);
+ break;
+ case ADIST_CMD_KEEPALIVE:
+ (void)snprlcat(msg, sizeof(msg), "KEEPALIVE");
+ break;
+ case ADIST_CMD_ERROR:
+ (void)snprlcat(msg, sizeof(msg), "ERROR");
+ break;
+ default:
+ (void)snprlcat(msg, sizeof(msg), "UNKNOWN(%hhu)",
+ adreq->adr_cmd);
+ break;
+ }
+ if (error != -1)
+ (void)snprlcat(msg, sizeof(msg), ": %s", adist_errstr(error));
+ (void)strlcat(msg, ".", sizeof(msg));
+ pjdlog_common(loglevel, debuglevel, -1, "%s", msg);
+}
+
+int
+adist_random(unsigned char *buf, size_t size)
+{
+#ifdef HAVE_ARC4RANDOM_BUF
+ arc4random_buf(buf, size);
+ return (0);
+#elif defined(HAVE_ARC4RANDOM)
+ uint32_t val;
+
+ PJDLOG_ASSERT(size > 0);
+ PJDLOG_ASSERT((size % sizeof(val)) == 0);
+
+ do {
+ val = arc4random();
+ bcopy(&val, buf, sizeof(val));
+ buf += sizeof(val);
+ size -= sizeof(val);
+ } while (size > 0);
+
+ return (0);
+#else
+ if (RAND_bytes(buf, (int)size) == 0)
+ return (-1);
+ return (0);
+#endif
+}
+
+static int wait_for_dir_kq = -1;
+static int wait_for_file_kq = -1;
+
+int
+wait_for_dir_init(int fd)
+{
+#ifdef HAVE_KQUEUE
+ struct kevent ev;
+ int error, kq;
+
+ PJDLOG_ASSERT(wait_for_dir_kq == -1);
+#endif
+
+ PJDLOG_ASSERT(fd != -1);
+
+#ifdef HAVE_KQUEUE
+ kq = kqueue();
+ if (kq == -1) {
+ pjdlog_errno(LOG_WARNING, "kqueue() failed");
+ return (-1);
+ }
+ EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
+ NOTE_WRITE, 0, 0);
+ if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) {
+ error = errno;
+ pjdlog_errno(LOG_WARNING, "kevent() failed");
+ (void)close(kq);
+ errno = error;
+ return (-1);
+ }
+ wait_for_dir_kq = kq;
+#endif
+
+ return (0);
+}
+
+int
+wait_for_file_init(int fd)
+{
+#ifdef HAVE_KQUEUE
+ struct kevent ev[2];
+ int error, kq;
+#endif
+
+ PJDLOG_ASSERT(fd != -1);
+
+#ifdef HAVE_KQUEUE
+ if (wait_for_file_kq != -1) {
+ close(wait_for_file_kq);
+ wait_for_file_kq = -1;
+ }
+
+ kq = kqueue();
+ if (kq == -1) {
+ pjdlog_errno(LOG_WARNING, "kqueue() failed");
+ return (-1);
+ }
+ EV_SET(&ev[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
+ NOTE_RENAME, 0, 0);
+ EV_SET(&ev[1], fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR,
+ 0, 0, 0);
+ if (kevent(kq, ev, 2, NULL, 0, NULL) == -1) {
+ error = errno;
+ pjdlog_errno(LOG_WARNING, "kevent() failed");
+ (void)close(kq);
+ errno = error;
+ return (-1);
+ }
+ wait_for_file_kq = kq;
+#endif
+
+ return (0);
+}
+
+/*
+ * Wait for new file to appear in directory.
+ */
+void
+wait_for_dir(void)
+{
+#ifdef HAVE_KQUEUE
+ struct kevent ev;
+#endif
+
+ if (wait_for_dir_kq == -1) {
+ sleep(1);
+ return;
+ }
+
+#ifdef HAVE_KQUEUE
+ PJDLOG_ASSERT(wait_for_dir_kq != -1);
+
+ if (kevent(wait_for_dir_kq, NULL, 0, &ev, 1, NULL) == -1) {
+ pjdlog_errno(LOG_WARNING, "kevent() failed");
+ sleep(1);
+ }
+#endif
+}
+
+/*
+ * Wait for file growth or rename.
+ */
+void
+wait_for_file(void)
+{
+#ifdef HAVE_KQUEUE
+ struct kevent ev[2];
+#endif
+
+ if (wait_for_file_kq == -1) {
+ sleep(1);
+ return;
+ }
+
+#ifdef HAVE_KQUEUE
+ PJDLOG_ASSERT(wait_for_file_kq != -1);
+
+ if (kevent(wait_for_file_kq, NULL, 0, ev, 2, NULL) == -1) {
+ pjdlog_errno(LOG_WARNING, "kevent() failed");
+ sleep(1);
+ }
+#endif
+}
diff --git a/contrib/openbsm/bin/auditdistd/subr.h b/contrib/openbsm/bin/auditdistd/subr.h
new file mode 100644
index 0000000..7e2ddeb
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/subr.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _AUDITDISTD_SUBR_H_
+#define _AUDITDISTD_SUBR_H_
+
+#include <sys/types.h>
+
+#include "auditdistd.h"
+
+#define KEEP_ERRNO(work) do { \
+ int _rerrno; \
+ \
+ _rerrno = errno; \
+ work; \
+ errno = _rerrno; \
+} while (0)
+
+int vsnprlcat(char *str, size_t size, const char *fmt, va_list ap);
+int snprlcat(char *str, size_t size, const char *fmt, ...);
+
+const char *role2str(int role);
+const char *adist_errstr(int error);
+
+void adreq_log(int loglevel, int debuglevel, int error, struct adreq *adreq,
+ const char *fmt, ...);
+
+int adist_random(unsigned char *buf, size_t size);
+
+int wait_for_dir_init(int fd);
+int wait_for_file_init(int fd);
+void wait_for_dir(void);
+void wait_for_file(void);
+
+#endif /* !_AUDITDISTD_SUBR_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/synch.h b/contrib/openbsm/bin/auditdistd/synch.h
new file mode 100644
index 0000000..6d83a9b
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/synch.h
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SYNCH_H_
+#define _SYNCH_H_
+
+#include <errno.h>
+#include <pthread.h>
+#ifdef HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif
+#include <stdbool.h>
+#include <time.h>
+
+#include "pjdlog.h"
+
+#ifndef PJDLOG_ASSERT
+#include <assert.h>
+#define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
+#endif
+
+static __inline void
+mtx_init(pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_mutex_init(lock, NULL);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline void
+mtx_destroy(pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_mutex_destroy(lock);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline void
+mtx_lock(pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_mutex_lock(lock);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline bool
+mtx_trylock(pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_mutex_trylock(lock);
+ PJDLOG_ASSERT(error == 0 || error == EBUSY);
+ return (error == 0);
+}
+static __inline void
+mtx_unlock(pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_mutex_unlock(lock);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline bool
+mtx_owned(pthread_mutex_t *lock)
+{
+
+ return (pthread_mutex_isowned_np(lock) != 0);
+}
+
+static __inline void
+rw_init(pthread_rwlock_t *lock)
+{
+ int error;
+
+ error = pthread_rwlock_init(lock, NULL);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline void
+rw_destroy(pthread_rwlock_t *lock)
+{
+ int error;
+
+ error = pthread_rwlock_destroy(lock);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline void
+rw_rlock(pthread_rwlock_t *lock)
+{
+ int error;
+
+ error = pthread_rwlock_rdlock(lock);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline void
+rw_wlock(pthread_rwlock_t *lock)
+{
+ int error;
+
+ error = pthread_rwlock_wrlock(lock);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline void
+rw_unlock(pthread_rwlock_t *lock)
+{
+ int error;
+
+ error = pthread_rwlock_unlock(lock);
+ PJDLOG_ASSERT(error == 0);
+}
+
+static __inline void
+cv_init(pthread_cond_t *cv)
+{
+ pthread_condattr_t attr;
+ int error;
+
+ error = pthread_condattr_init(&attr);
+ PJDLOG_ASSERT(error == 0);
+#ifdef HAVE_PTHREAD_CONDATTR_SETCLOCK
+ error = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ PJDLOG_ASSERT(error == 0);
+#endif
+ error = pthread_cond_init(cv, &attr);
+ PJDLOG_ASSERT(error == 0);
+ error = pthread_condattr_destroy(&attr);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline void
+cv_wait(pthread_cond_t *cv, pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_cond_wait(cv, lock);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline bool
+cv_timedwait(pthread_cond_t *cv, pthread_mutex_t *lock, int timeout)
+{
+ struct timespec ts;
+ int error;
+
+ if (timeout == 0) {
+ cv_wait(cv, lock);
+ return (false);
+ }
+
+#ifdef HAVE_PTHREAD_CONDATTR_SETCLOCK
+ error = clock_gettime(CLOCK_MONOTONIC, &ts);
+ PJDLOG_ASSERT(error == 0);
+ ts.tv_sec += timeout;
+ error = pthread_cond_timedwait(cv, lock, &ts);
+#elif HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
+ ts.tv_sec = timeout;
+ ts.tv_nsec = 0;
+ error = pthread_cond_timedwait_relative_np(cv, lock, &ts);
+#else
+#error Neither pthread_condattr_setclock nor pthread_cond_timedwait_relative_np is available.
+#endif
+ PJDLOG_ASSERT(error == 0 || error == ETIMEDOUT);
+ return (error == ETIMEDOUT);
+}
+static __inline void
+cv_signal(pthread_cond_t *cv)
+{
+ int error;
+
+ error = pthread_cond_signal(cv);
+ PJDLOG_ASSERT(error == 0);
+}
+static __inline void
+cv_broadcast(pthread_cond_t *cv)
+{
+ int error;
+
+ error = pthread_cond_broadcast(cv);
+ PJDLOG_ASSERT(error == 0);
+}
+#endif /* !_SYNCH_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/token.l b/contrib/openbsm/bin/auditdistd/token.l
new file mode 100644
index 0000000..e3c4624
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/token.l
@@ -0,0 +1,82 @@
+%{
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config/config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef HAVE_STRNDUP
+#include "strndup.h"
+#endif
+
+#include "auditdistd.h"
+
+#include "parse.h"
+
+#define SECTION_GLOBAL 0
+#define SECTION_SENDER 1
+#define SECTION_RECEIVER 2
+
+int cursection;
+int depth;
+int lineno;
+
+#define DP do { } while (0)
+#define YY_DECL int yylex(void)
+%}
+
+%option noinput
+%option nounput
+%option noyywrap
+
+%%
+certfile { DP; return CERTFILE; }
+directory { DP; return DIRECTORY; }
+fingerprint { DP; return FINGERPRINT; }
+host { DP; return HOST; }
+keyfile { DP; return KEYFILE; }
+listen { DP; return LISTEN; }
+name { DP; return NAME; }
+password { DP; return PASSWORD; }
+pidfile { DP; return PIDFILE; }
+receiver { DP; return RECEIVER; }
+remote { DP; return REMOTE; }
+sender { DP; return SENDER; }
+source { DP; return SOURCE; }
+timeout { DP; return TIMEOUT; }
+[0-9]+ { DP; yylval.num = atoi(yytext); return NUM; }
+\"[a-zA-Z0-9_/ !@#\$%\^\&\*\(\)\+\=\|\;\?\,\.\[\]\-\:]*\" { DP; yylval.str = strndup(yytext + 1, strlen(yytext) - 2); return STR; }
+\{ { DP; depth++; return OB; }
+\} { DP; depth--; return CB; }
+#.*$ /* ignore comments */;
+\n { lineno++; }
+[ \t]+ /* ignore whitespace */;
+%%
diff --git a/contrib/openbsm/bin/auditdistd/trail.c b/contrib/openbsm/bin/auditdistd/trail.c
new file mode 100644
index 0000000..b8a9881
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/trail.c
@@ -0,0 +1,609 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config/config.h>
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <compat/compat.h>
+#ifndef HAVE_STRLCPY
+#include <compat/strlcpy.h>
+#endif
+#ifndef HAVE_FACCESSAT
+#include "faccessat.h"
+#endif
+#ifndef HAVE_FSTATAT
+#include "fstatat.h"
+#endif
+#ifndef HAVE_OPENAT
+#include "openat.h"
+#endif
+#ifndef HAVE_UNLINKAT
+#include "unlinkat.h"
+#endif
+
+#include "pjdlog.h"
+#include "trail.h"
+
+#define TRAIL_MAGIC 0x79a11
+struct trail {
+ int tr_magic;
+ /* Path usually to /var/audit/dist/ directory. */
+ char tr_dirname[PATH_MAX];
+ /* Descriptor to td_dirname directory. */
+ DIR *tr_dirfp;
+ /* Path to audit trail file. */
+ char tr_filename[PATH_MAX];
+ /* Descriptor to audit trail file. */
+ int tr_filefd;
+};
+
+#define HALF_LEN 14
+
+bool
+trail_is_not_terminated(const char *filename)
+{
+
+ return (strcmp(filename + HALF_LEN, ".not_terminated") == 0);
+}
+
+bool
+trail_is_crash_recovery(const char *filename)
+{
+
+ return (strcmp(filename + HALF_LEN, ".crash_recovery") == 0);
+}
+
+struct trail *
+trail_new(const char *dirname, bool create)
+{
+ struct trail *trail;
+
+ trail = calloc(1, sizeof(*trail));
+
+ if (strlcpy(trail->tr_dirname, dirname, sizeof(trail->tr_dirname)) >=
+ sizeof(trail->tr_dirname)) {
+ free(trail);
+ pjdlog_error("Directory name too long (\"%s\").", dirname);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ trail->tr_dirfp = opendir(dirname);
+ if (trail->tr_dirfp == NULL) {
+ if (create && errno == ENOENT) {
+ if (mkdir(dirname, 0700) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to create directory \"%s\"",
+ dirname);
+ free(trail);
+ return (NULL);
+ }
+ /* TODO: Set directory ownership. */
+ } else {
+ pjdlog_errno(LOG_ERR,
+ "Unable to open directory \"%s\"",
+ dirname);
+ free(trail);
+ return (NULL);
+ }
+ trail->tr_dirfp = opendir(dirname);
+ if (trail->tr_dirfp == NULL) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to open directory \"%s\"",
+ dirname);
+ free(trail);
+ return (NULL);
+ }
+ }
+ trail->tr_filefd = -1;
+ trail->tr_magic = TRAIL_MAGIC;
+ return (trail);
+}
+
+void
+trail_free(struct trail *trail)
+{
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+
+ if (trail->tr_filefd != -1)
+ trail_close(trail);
+ closedir(trail->tr_dirfp);
+ bzero(trail, sizeof(*trail));
+ trail->tr_magic = 0;
+ trail->tr_filefd = -1;
+ free(trail);
+}
+
+static uint8_t
+trail_type(DIR *dirfp, const char *filename)
+{
+ struct stat sb;
+ int dfd;
+
+ PJDLOG_ASSERT(dirfp != NULL);
+
+ dfd = dirfd(dirfp);
+ PJDLOG_ASSERT(dfd >= 0);
+ if (fstatat(dfd, filename, &sb, AT_SYMLINK_NOFOLLOW) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to stat \"%s\"", filename);
+ return (DT_UNKNOWN);
+ }
+ return (IFTODT(sb.st_mode));
+}
+
+/*
+ * Find trail file by first part of the name in case it was renamed.
+ * First part of the trail file name never changes, but trail file
+ * can be renamed when hosts are disconnected from .not_terminated
+ * to .[0-9]{14} or to .crash_recovery.
+ */
+static bool
+trail_find(struct trail *trail)
+{
+ struct dirent *dp;
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+ PJDLOG_ASSERT(trail_is_not_terminated(trail->tr_filename));
+
+ rewinddir(trail->tr_dirfp);
+ while ((dp = readdir(trail->tr_dirfp)) != NULL) {
+ if (strncmp(dp->d_name, trail->tr_filename, HALF_LEN + 1) == 0)
+ break;
+ }
+ if (dp == NULL)
+ return (false);
+ PJDLOG_VERIFY(strlcpy(trail->tr_filename, dp->d_name,
+ sizeof(trail->tr_filename)) < sizeof(trail->tr_filename));
+ return (true);
+}
+
+/*
+ * Open the given trail file and move pointer at the given offset, as this is
+ * where receiver finished the last time.
+ * If the file doesn't exist or the given offset is equal to the file size,
+ * move to the next trail file.
+ */
+void
+trail_start(struct trail *trail, const char *filename, off_t offset)
+{
+ struct stat sb;
+ int dfd, fd;
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+
+ PJDLOG_VERIFY(strlcpy(trail->tr_filename, filename,
+ sizeof(trail->tr_filename)) < sizeof(trail->tr_filename));
+ trail->tr_filefd = -1;
+
+ if (trail->tr_filename[0] == '\0') {
+ PJDLOG_ASSERT(offset == 0);
+ trail_next(trail);
+ return;
+ }
+
+ dfd = dirfd(trail->tr_dirfp);
+ PJDLOG_ASSERT(dfd >= 0);
+again:
+ fd = openat(dfd, trail->tr_filename, O_RDONLY);
+ if (fd == -1) {
+ if (errno == ENOENT &&
+ trail_is_not_terminated(trail->tr_filename) &&
+ trail_find(trail)) {
+ /* File was renamed. Retry with new name. */
+ pjdlog_debug(1,
+ "Trail file was renamed since last connection to \"%s/%s\".",
+ trail->tr_dirname, trail->tr_filename);
+ goto again;
+ } else if (errno == ENOENT) {
+ /* File disappeared. */
+ pjdlog_debug(1, "File \"%s/%s\" doesn't exist.",
+ trail->tr_dirname, trail->tr_filename);
+ } else {
+ pjdlog_errno(LOG_ERR,
+ "Unable to open file \"%s/%s\", skipping",
+ trail->tr_dirname, trail->tr_filename);
+ }
+ trail_next(trail);
+ return;
+ }
+ if (fstat(fd, &sb) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to stat file \"%s/%s\", skipping",
+ trail->tr_dirname, trail->tr_filename);
+ close(fd);
+ trail_next(trail);
+ return;
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ pjdlog_warning("File \"%s/%s\" is not a regular file, skipping.",
+ trail->tr_dirname, trail->tr_filename);
+ close(fd);
+ trail_next(trail);
+ return;
+ }
+ /*
+ * We continue sending requested file if:
+ * 1. It is not fully sent yet, or
+ * 2. It is fully sent, but is not terminated, so new data can be
+ * appended still, or
+ * 3. It is fully sent but file name has changed.
+ *
+ * Note that we are fine if our .not_terminated or .crash_recovery file
+ * is smaller than the one on the receiver side, as it is possible that
+ * more data was send to the receiver than was safely stored on disk.
+ * We accept .not_terminated only because auditdistd can start before
+ * auditd manage to rename it to .crash_recovery.
+ */
+ if (offset < sb.st_size ||
+ (offset >= sb.st_size &&
+ trail_is_not_terminated(trail->tr_filename)) ||
+ (offset >= sb.st_size && trail_is_not_terminated(filename) &&
+ trail_is_crash_recovery(trail->tr_filename))) {
+ /* File was not fully send. Let's finish it. */
+ if (lseek(fd, offset, SEEK_SET) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to move to offset %jd within file \"%s/%s\", skipping",
+ (intmax_t)offset, trail->tr_dirname,
+ trail->tr_filename);
+ close(fd);
+ trail_next(trail);
+ return;
+ }
+ if (!trail_is_crash_recovery(trail->tr_filename)) {
+ pjdlog_debug(1,
+ "Restarting file \"%s/%s\" at offset %jd.",
+ trail->tr_dirname, trail->tr_filename,
+ (intmax_t)offset);
+ }
+ trail->tr_filefd = fd;
+ return;
+ }
+ close(fd);
+ if (offset > sb.st_size) {
+ pjdlog_warning("File \"%s/%s\" shrinked, removing it.",
+ trail->tr_dirname, trail->tr_filename);
+ } else {
+ pjdlog_debug(1, "File \"%s/%s\" is already sent, removing it.",
+ trail->tr_dirname, trail->tr_filename);
+ }
+ /* Entire file is already sent or it shirnked, we can remove it. */
+ if (unlinkat(dfd, trail->tr_filename, 0) == -1) {
+ pjdlog_errno(LOG_WARNING, "Unable to remove file \"%s/%s\"",
+ trail->tr_dirname, trail->tr_filename);
+ }
+ trail_next(trail);
+}
+
+/*
+ * Set next file in the trail->tr_dirname directory and open it for reading.
+ */
+void
+trail_next(struct trail *trail)
+{
+ char curfile[PATH_MAX];
+ struct dirent *dp;
+ int dfd;
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+ PJDLOG_ASSERT(trail->tr_filefd == -1);
+
+again:
+ curfile[0] = '\0';
+
+ rewinddir(trail->tr_dirfp);
+ while ((dp = readdir(trail->tr_dirfp)) != NULL) {
+ if (dp->d_name[0] < '0' || dp->d_name[0] > '9')
+ continue;
+ if (dp->d_type == DT_UNKNOWN)
+ dp->d_type = trail_type(trail->tr_dirfp, dp->d_name);
+ /* We are only interested in regular files, skip the rest. */
+ if (dp->d_type != DT_REG) {
+ pjdlog_debug(1,
+ "File \"%s/%s\" is not a regular file, skipping.",
+ trail->tr_dirname, dp->d_name);
+ continue;
+ }
+ /* Skip all files "greater" than curfile. */
+ if (curfile[0] != '\0' && strcmp(dp->d_name, curfile) > 0)
+ continue;
+ /* Skip all files "smaller" than the current trail_filename. */
+ if (trail->tr_filename[0] != '\0' &&
+ strcmp(dp->d_name, trail->tr_filename) <= 0) {
+ continue;
+ }
+ PJDLOG_VERIFY(strlcpy(curfile, dp->d_name, sizeof(curfile)) <
+ sizeof(curfile));
+ }
+ if (curfile[0] == '\0') {
+ /*
+ * There are no new trail files, so we return.
+ * We don't clear trail_filename string, to know where to
+ * start when new file appears.
+ */
+ PJDLOG_ASSERT(trail->tr_filefd == -1);
+ pjdlog_debug(1, "No new trail files.");
+ return;
+ }
+ PJDLOG_VERIFY(strlcpy(trail->tr_filename, curfile,
+ sizeof(trail->tr_filename)) < sizeof(trail->tr_filename));
+ dfd = dirfd(trail->tr_dirfp);
+ PJDLOG_ASSERT(dfd >= 0);
+ trail->tr_filefd = openat(dfd, trail->tr_filename, O_RDONLY);
+ if (trail->tr_filefd == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to open file \"%s/%s\", skipping",
+ trail->tr_dirname, trail->tr_filename);
+ goto again;
+ }
+ pjdlog_debug(1, "Found next trail file: \"%s/%s\".", trail->tr_dirname,
+ trail->tr_filename);
+}
+
+/*
+ * Close current trial file.
+ */
+void
+trail_close(struct trail *trail)
+{
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+ PJDLOG_ASSERT(trail->tr_filefd >= 0);
+ PJDLOG_ASSERT(trail->tr_filename[0] != '\0');
+
+ PJDLOG_VERIFY(close(trail->tr_filefd) == 0);
+ trail->tr_filefd = -1;
+}
+
+/*
+ * Reset trail state. Used when connection is disconnected and we will
+ * need to start over after reconnect. Trail needs to be already closed.
+ */
+void
+trail_reset(struct trail *trail)
+{
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+ PJDLOG_ASSERT(trail->tr_filefd == -1);
+
+ trail->tr_filename[0] = '\0';
+}
+
+/*
+ * Unlink current trial file.
+ */
+void
+trail_unlink(struct trail *trail, const char *filename)
+{
+ int dfd;
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+ PJDLOG_ASSERT(filename != NULL);
+ PJDLOG_ASSERT(filename[0] != '\0');
+
+ dfd = dirfd(trail->tr_dirfp);
+ PJDLOG_ASSERT(dfd >= 0);
+
+ if (unlinkat(dfd, filename, 0) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to remove \"%s/%s\"",
+ trail->tr_dirname, filename);
+ } else {
+ pjdlog_debug(1, "Trail file \"%s/%s\" removed.",
+ trail->tr_dirname, filename);
+ }
+}
+
+/*
+ * Return true if we should switch to next trail file.
+ * We don't switch if our file name ends with ".not_terminated" and it
+ * exists (ie. wasn't renamed).
+ */
+bool
+trail_switch(struct trail *trail)
+{
+ char filename[PATH_MAX];
+ int fd;
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+ PJDLOG_ASSERT(trail->tr_filefd >= 0);
+
+ if (!trail_is_not_terminated(trail->tr_filename))
+ return (true);
+ fd = dirfd(trail->tr_dirfp);
+ PJDLOG_ASSERT(fd >= 0);
+ if (faccessat(fd, trail->tr_filename, F_OK, 0) == 0)
+ return (false);
+ if (errno != ENOENT) {
+ pjdlog_errno(LOG_ERR, "Unable to access file \"%s/%s\"",
+ trail->tr_dirname, trail->tr_filename);
+ }
+ strlcpy(filename, trail->tr_filename, sizeof(filename));
+ if (!trail_find(trail)) {
+ pjdlog_error("Trail file \"%s/%s\" disappeared.",
+ trail->tr_dirname, trail->tr_filename);
+ return (true);
+ }
+ pjdlog_debug(1, "Trail file \"%s/%s\" was renamed to \"%s/%s\".",
+ trail->tr_dirname, filename, trail->tr_dirname,
+ trail->tr_filename);
+ return (true);
+}
+
+const char *
+trail_filename(const struct trail *trail)
+{
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+
+ return (trail->tr_filename);
+}
+
+int
+trail_filefd(const struct trail *trail)
+{
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+
+ return (trail->tr_filefd);
+}
+
+int
+trail_dirfd(const struct trail *trail)
+{
+
+ PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC);
+
+ return (dirfd(trail->tr_dirfp));
+}
+
+/*
+ * Find the last file in the directory opened under dirfp.
+ */
+void
+trail_last(DIR *dirfp, char *filename, size_t filenamesize)
+{
+ char curfile[PATH_MAX];
+ struct dirent *dp;
+
+ PJDLOG_ASSERT(dirfp != NULL);
+
+ curfile[0] = '\0';
+
+ rewinddir(dirfp);
+ while ((dp = readdir(dirfp)) != NULL) {
+ if (dp->d_name[0] < '0' || dp->d_name[0] > '9')
+ continue;
+ if (dp->d_type == DT_UNKNOWN)
+ dp->d_type = trail_type(dirfp, dp->d_name);
+ /* We are only interested in regular files, skip the rest. */
+ if (dp->d_type != DT_REG)
+ continue;
+ /* Skip all files "greater" than curfile. */
+ if (curfile[0] != '\0' && strcmp(dp->d_name, curfile) < 0)
+ continue;
+ PJDLOG_VERIFY(strlcpy(curfile, dp->d_name, sizeof(curfile)) <
+ sizeof(curfile));
+ }
+ if (curfile[0] == '\0') {
+ /*
+ * There are no trail files, so we return.
+ */
+ pjdlog_debug(1, "No trail files.");
+ bzero(filename, filenamesize);
+ return;
+ }
+ PJDLOG_VERIFY(strlcpy(filename, curfile, filenamesize) < filenamesize);
+ pjdlog_debug(1, "Found the most recent trail file: \"%s\".", filename);
+}
+
+/*
+ * Check if the given file name is a valid audit trail file name.
+ * Possible names:
+ * 20120106132657.20120106132805
+ * 20120106132657.not_terminated
+ * 20120106132657.crash_recovery
+ * If two names are given, check if the first name can be renamed
+ * to the second name. When renaming, first part of the name has
+ * to be identical and only the following renames are valid:
+ * 20120106132657.not_terminated -> 20120106132657.20120106132805
+ * 20120106132657.not_terminated -> 20120106132657.crash_recovery
+ */
+bool
+trail_validate_name(const char *srcname, const char *dstname)
+{
+ int i;
+
+ PJDLOG_ASSERT(srcname != NULL);
+
+ if (strlen(srcname) != 2 * HALF_LEN + 1)
+ return (false);
+ if (srcname[HALF_LEN] != '.')
+ return (false);
+ for (i = 0; i < HALF_LEN; i++) {
+ if (srcname[i] < '0' || srcname[i] > '9')
+ return (false);
+ }
+ for (i = HALF_LEN + 1; i < 2 * HALF_LEN - 1; i++) {
+ if (srcname[i] < '0' || srcname[i] > '9')
+ break;
+ }
+ if (i < 2 * HALF_LEN - 1 &&
+ strcmp(srcname + HALF_LEN + 1, "not_terminated") != 0 &&
+ strcmp(srcname + HALF_LEN + 1, "crash_recovery") != 0) {
+ return (false);
+ }
+
+ if (dstname == NULL)
+ return (true);
+
+ /* We tolarate if both names are identical. */
+ if (strcmp(srcname, dstname) == 0)
+ return (true);
+
+ /* We can only rename not_terminated files. */
+ if (strcmp(srcname + HALF_LEN + 1, "not_terminated") != 0)
+ return (false);
+ if (strlen(dstname) != 2 * HALF_LEN + 1)
+ return (false);
+ if (strncmp(srcname, dstname, HALF_LEN + 1) != 0)
+ return (false);
+ for (i = HALF_LEN + 1; i < 2 * HALF_LEN - 1; i++) {
+ if (dstname[i] < '0' || dstname[i] > '9')
+ break;
+ }
+ if (i < 2 * HALF_LEN - 1 &&
+ strcmp(dstname + HALF_LEN + 1, "crash_recovery") != 0) {
+ return (false);
+ }
+
+ return (true);
+}
+
+int
+trail_name_compare(const char *name0, const char *name1)
+{
+ int ret;
+
+ ret = strcmp(name0, name1);
+ if (ret == 0)
+ return (TRAIL_IDENTICAL);
+ if (strncmp(name0, name1, HALF_LEN + 1) == 0)
+ return (TRAIL_RENAMED);
+ return (ret < 0 ? TRAIL_OLDER : TRAIL_NEWER);
+}
diff --git a/contrib/openbsm/bin/auditdistd/trail.h b/contrib/openbsm/bin/auditdistd/trail.h
new file mode 100644
index 0000000..204ea2b
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/trail.h
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _AUDITDISTD_TRAIL_H_
+#define _AUDITDISTD_TRAIL_H_
+
+#include <stdbool.h>
+#include <unistd.h> /* off_t */
+
+#define TRAIL_IDENTICAL 0
+#define TRAIL_RENAMED 1
+#define TRAIL_OLDER 2
+#define TRAIL_NEWER 3
+
+struct trail;
+
+struct trail *trail_new(const char *dirname, bool create);
+void trail_free(struct trail *trail);
+bool trail_is_not_terminated(const char *filename);
+bool trail_is_crash_recovery(const char *filename);
+void trail_start(struct trail *trail, const char *filename, off_t offset);
+void trail_next(struct trail *trail);
+void trail_close(struct trail *trail);
+void trail_reset(struct trail *trail);
+void trail_unlink(struct trail *trail, const char *filename);
+bool trail_switch(struct trail *trail);
+const char *trail_filename(const struct trail *trail);
+int trail_filefd(const struct trail *trail);
+int trail_dirfd(const struct trail *trail);
+void trail_last(DIR *dirfp, char *filename, size_t filenamesize);
+bool trail_validate_name(const char *srcname, const char *dstname);
+int trail_name_compare(const char *name0, const char *name1);
+
+#endif /* !_AUDITDISTD_TRAIL_H_ */
diff --git a/contrib/openbsm/bin/auditdistd/unlinkat.h b/contrib/openbsm/bin/auditdistd/unlinkat.h
new file mode 100644
index 0000000..6364208
--- /dev/null
+++ b/contrib/openbsm/bin/auditdistd/unlinkat.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _UNLINKAT_H_
+#define _UNLINKAT_H_
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#define AT_REMOVEDIR 0x01
+
+static int
+unlinkat(int fd, const char *path, int flag)
+{
+ int cfd, error, ret;
+
+ cfd = open(".", O_RDONLY | O_DIRECTORY);
+ if (cfd == -1)
+ return (-1);
+
+ if (fchdir(fd) == -1) {
+ error = errno;
+ (void)close(cfd);
+ errno = error;
+ return (-1);
+ }
+
+ if (flag == AT_REMOVEDIR)
+ ret = rmdir(path);
+ else
+ ret = unlink(path);
+
+ error = errno;
+ (void)fchdir(cfd);
+ (void)close(cfd);
+ errno = error;
+ return (ret);
+}
+
+#endif /* !_UNLINKAT_H_ */
OpenPOWER on IntegriCloud