diff --git a/configure.in b/configure.in index d5f0769..1605bff 100644 --- a/configure.in +++ b/configure.in @@ -49,10 +49,8 @@ fi if test "x$prefix" = "xNONE"; then prefix=$ac_default_prefix - pidfiledir="/var/run" -else - pidfiledir="${prefix}/var/run" fi +pidfiledir="${localstatedir}" AM_CONFIG_HEADER(config.h) @@ -70,7 +68,7 @@ AC_ARG_WITH(pidfile-dir, AC_ARG_WITH(timezone-dir, [ --with-timezone-dir=path Use path as the directory to get the timezone files], - timezone_dir=$with_timezone_dir) + timezonedir=$with_timezone_dir) AC_ARG_WITH(ld-library-path, [ --with-ld-library-path=path Set LD_LIBRARY_PATH during runtime to the value given], @@ -92,10 +90,13 @@ AC_ARG_ENABLE(ssl, [ --enable-ssl Enable SSL support.],,enable_ssl="auto") AC_ARG_ENABLE(dynamic-linking, - [ --enable-dynamic-linking Link glib and eventlog dynamically instead of statically.]) + [ --enable-dynamic-linking Link glib and eventlog dynamically instead of statically.],,enable_dynamic_linking="auto") AC_ARG_ENABLE(static-linking, - [ --enable-static-linking Link everything statically.]) + [ --enable-static-linking Link everything statically.],,enable_static_linking="auto") + +AC_ARG_ENABLE(mixed-linking, + [ --enable-mixed-linking Link 3rd party libraries statically, system libraries dynamically],,enable_mixed_linking="auto") AC_ARG_ENABLE(ipv6, [ --enable-ipv6 Enable support for IPv6.],,enable_ipv6="auto") @@ -319,9 +320,6 @@ dnl *************************************************************************** dnl OpenSSL headers/libraries dnl *************************************************************************** -OPENSSL_LIBS="" -OPENSSL_CPPFLAGS="" - # openssl is needed for: # * TLS support @@ -360,7 +358,13 @@ dnl libdbi headers/libraries dnl *************************************************************************** AC_CHECK_LIB(dl, dlsym, DL_LIBS="-ldl") -PKG_CHECK_MODULES(LIBDBI, dbi >= $LIBDBI_MIN_VERSION,, LIBDBI_LIBS="") +PKG_CHECK_MODULES(LIBDBI, dbi >= $LIBDBI_MIN_VERSION,, libdbi_pkgconfig_not_found="1") + +if test "$libdbi_pkgconfig_not_found" -eq 1; then + dnl if libdbi has no .pc file, try it without one + AC_CHECK_LIB(dbi, dbi_initialize, LIBDBI_LIBS="-ldbi"; LIBDBI_CFLAGS="-I/usr/include") +fi + dnl *************************************************************************** dnl Some more checks based on the detected settings above @@ -606,8 +610,42 @@ int main() fi fi -if test "x$enable_dynamic_linking" = "xyes" -a "x$enable_static_linking" = "xyes"; then - AC_MSG_ERROR([You cannot specify dynamic and static linking at the same time.]) +if test "$enable_dynamic_linking" = "auto" -a "$enable_static_linking" = "auto" -a "$enable_mixed_linking" = "auto"; then + enable_dynamic_linking="yes" + enable_static_linking="no" + enable_mixed_linking="no" +fi + +linkopts=0 +if test "x$enable_dynamic_linking" = "xyes"; then + linkopts=`expr $linkopts + 1` +fi +if test "x$enable_static_linking" = "xyes"; then + linkopts=`expr $linkopts + 1` +fi +if test "x$enable_mixed_linking" = "xyes"; then + linkopts=`expr $linkopts + 1` +fi + +if test "$linkopts" -gt 1; then + AC_MSG_ERROR([You cannot specify multiple linking options at the same time (--enable-dynamic-linking, --enable-static-linking, --enable-mixed-linking).]) +fi + +if test "x$enable_dynamic_linking" = "xyes"; then + enable_dynamic_linking="yes" + enable_static_linking="no" + enable_mixed_linking="no" + linking_mode="dynamic" +elif test "x$enable_static_linking" = "xyes"; then + enable_dynamic_linking="no" + enable_static_linking="yes" + enable_mixed_linking="no" + linking_mode="static" +elif test "x$enable_mixed_linking" = "xyes"; then + enable_dynamic_linking="no" + enable_static_linking="no" + enable_mixed_linking="yes" + linking_mode="mixed" fi if test "x$enable_dynamic_linking" != "xyes" -a "x$blb_cv_static_glib" = "xno"; then @@ -615,7 +653,7 @@ if test "x$enable_dynamic_linking" != "xyes" -a "x$blb_cv_static_glib" = "xno"; fi if test "x$enable_dynamic_linking" != "xyes" -a "x$blb_cv_static_openssl" = "xno"; then - AC_MSG_ERROR([static OpenSSL libraries not found (libssl.a and libcrypto.a), either link OpenSSL statically using the --enable-dynamic-linking, or install a static OpenSSL]) + AC_MSG_ERROR([static OpenSSL libraries not found (libssl.a, libcrypto.a and their external dependencies like libz.a), either link OpenSSL statically using the --enable-dynamic-linking, or install a static OpenSSL]) fi @@ -672,8 +710,8 @@ AC_DEFINE_UNQUOTED(PATH_PREFIX, "`patheval $prefix`", [prefix directory]) AC_DEFINE_UNQUOTED(PATH_SYSCONFDIR, "`patheval $sysconfdir`", [sysconfdir]) AC_DEFINE_UNQUOTED(PATH_LOCALSTATEDIR, "`patheval $localstatedir`", [local state directory]) AC_DEFINE_UNQUOTED(PATH_PIDFILEDIR, "`patheval $pidfiledir`", [local state directory]) -if test -n "$timezone_dir"; then - AC_DEFINE_UNQUOTED(PATH_TIMEZONEDIR, "`patheval $timezone_dir`", [timezone base directory]) +if test -n "$timezonedir"; then + AC_DEFINE_UNQUOTED(PATH_TIMEZONEDIR, "`patheval $timezonedir`", [timezone base directory]) fi if test -n "$env_ld_library_path"; then AC_DEFINE_UNQUOTED(ENV_LD_LIBRARY_PATH, "$env_ld_library_path", [set LD_LIBRARY_PATH to this value]) @@ -695,6 +733,8 @@ AC_DEFINE_UNQUOTED(ENABLE_ENV_WRAPPER, `enable_value $enable_env_wrapper`, [Enab AM_CONDITIONAL(ENABLE_ENV_WRAPPER, [test "$enable_env_wrapper" = "yes"]) +AC_SUBST(timezonedir) +AC_SUBST(pidfiledir) AC_SUBST(DEPS_CPPFLAGS) AC_SUBST(DEPS_LIBS) AC_SUBST(BASE_LIBS) @@ -729,6 +769,7 @@ echo " compiler : $CC" echo " compiler options : $CFLAGS $CPPFLAGS" echo " linker flags : $LDFLAGS $LIBS" echo " prefix : $prefix" +echo " linking mode : $linking_mode" echo " Features:" echo " Sun STREAMS support : ${enable_sun_streams:=no}" echo " Sun Door support : ${enable_sun_door:=no}" diff --git a/contrib/balabit-initscripts/init-functions b/contrib/balabit-initscripts/init-functions index e1898a8..c3b18ef 100644 --- a/contrib/balabit-initscripts/init-functions +++ b/contrib/balabit-initscripts/init-functions @@ -6,12 +6,35 @@ NORMAL= FANCYTTY= PSOPTS= -case `uname -s` in +ECHO=echo + +OS=`uname -s` + +disable_xpg_echo() { + # \X chars only passed to echo under bash, if xpg_echo enabled or echo -e + # used on Linux. + if [ -n "$BASH_VERSION" ];then + shopt -s xpg_echo + fi +} + +case $OS in # default ps -e cuts the process' name at 8 characters, so we have to list it # in a long form - SunOS) PSOPTS=" -o pid -o tty -o time -o comm" ;; + SunOS) + PSOPTS=" -o pid -o tty -o time -o comm" + disable_xpg_echo + ;; + Linux) + if [ -z "$BASH_VERSION" ]; then + # beware of dash's builtin echo ... + ECHO="/bin/echo -e" + fi + ;; + *) disable_xpg_echo ;; esac + _checkpid() { _pid=$1 _proc=$2 @@ -30,7 +53,7 @@ _pid_from_pidfile() { pid= if [ -f "$pidfile" ];then - pid=`head -1 $pidfile` + pid=`head -1 $pidfile 2> /dev/null` if [ $? -ne 0 ]; then # on slow machines (or ones under high load) the pidfile could be # erased between -f and `head` ... @@ -195,17 +218,17 @@ log_use_fancy_output() { log_success_msg() { - echo "$@" + $ECHO "$@" } log_failure_msg() { log_use_fancy_output - echo "${RED}$@${NORMAL}" + $ECHO "${RED}$@${NORMAL}" } log_warning_msg() { log_use_fancy_output - echo "${YELLOW}$@${NORMAL}" + $ECHO "${YELLOW}$@${NORMAL}" } # NON-LSB Functions @@ -215,7 +238,7 @@ log_begin_msg() { return 1 fi - echo "$@\c " + $ECHO "$@\c " } log_daemon_msg() { @@ -224,11 +247,11 @@ log_daemon_msg() { fi if [ -z "$2" ]; then - echo "$1:\c " + $ECHO "$1:\c " return fi - echo "$1: $2\c " + $ECHO "$1: $2\c " } log_progress_msg() { @@ -237,9 +260,9 @@ log_progress_msg() { fi if [ $1 -eq 0 ]; then - echo "." + $ECHO "." else - echo " failed" + $ECHO " failed" fi } @@ -250,23 +273,23 @@ log_end_msg() { log_fancy_output if [ $1 -eq 0 ];then - echo "." + $ECHO "." else - echo "${RED}failed!${NORMAL}" + $ECHO "${RED}failed!${NORMAL}" fi return $1 } log_action_msg() { - echo "$@." + $ECHO "$@." } log_action_begin_msg() { - echo "$@...\c " + $ECHO "$@...\c " } log_action_cont_msg() { - echo "$@...\c " + $ECHO "$@...\c " } log_action_end_msg() { @@ -278,15 +301,12 @@ log_action_end_msg() { log_fancy_output if [ $1 -eq 0 ]; then - echo "done${end}" + $ECHO "done${end}" else - echo "${RED}failed${end}${NORMAL}" + $ECHO "${RED}failed${end}${NORMAL}" fi } -# \X chars only passed to echo under bash, if xpg_echo enabled.... -if [ -n "$BASH_VERSION" ];then - shopt -s xpg_echo -fi # vim: ft=sh ts=2 expandtab + diff --git a/contrib/balabit-initscripts/init.d b/contrib/balabit-initscripts/init.d index ff2e249..589da86 100644 --- a/contrib/balabit-initscripts/init.d +++ b/contrib/balabit-initscripts/init.d @@ -25,6 +25,7 @@ SYSLOGNG_PREFIX=/opt/syslog-ng SYSLOGNG="$SYSLOGNG_PREFIX/sbin/syslog-ng" CONFFILE=$SYSLOGNG_PREFIX/etc/syslog-ng.conf PIDFILE=$SYSLOGNG_PREFIX/var/run/syslog-ng.pid +SYSLOGPIDFILE="/var/run/syslog.pid" INIT_FUNCTIONS=/lib/lsb/init-functions SLNG_INIT_FUNCTIONS=$SYSLOGNG_PREFIX/lib/init-functions @@ -64,6 +65,17 @@ if [ -f /etc/lsb-release ]; then . /etc/lsb-release fi +if [ -f "/etc/redhat-release" ];then + # redhat uses a different syslogd pidfile... + SYSLOGPIDFILE="/var/run/syslogd.pid" +fi + +if [ "$OS" = "SunOS" ] || [ "$OS" = "Solaris" ];then + if [ "`uname -r`" = "5.8" ];then + SYSLOGPIDFILE="/etc/syslog.pid" + fi +fi + if [ -f /lib/lsb/init-functions ];then # long list of exclusions... if [ -f "/etc/redhat-release" ] || [ -f "/etc/SuSE-release" ];then @@ -117,7 +129,7 @@ check_syntax() { slng_waitforpid() { _pid=$1 - _process=$2 + _process=$2 _cnt=$MAXWAIT # no pid, return... @@ -147,6 +159,11 @@ returnmessage() { syslogng_start() { echo_n "Starting syslog-ng: " + PID=`pidofproc -p ${PIDFILE} ${SYSLOGNG} | head -1` + if [ -n "$PID" ] && [ $PID -gt 0 ] ;then + log_success_msg "already running: $PID" + return $retval + fi start_daemon -p ${PIDFILE} ${SYSLOGNG} ${SYSLOGNG_OPTIONS} retval=$? returnmessage $retval @@ -154,6 +171,13 @@ syslogng_start() { if [ "$OS" = "Linux" ] && [ -d $SUBSYSDIR ];then touch $SUBSYSDIR/syslog-ng fi + # remove symlinks + if [ -h $SYSLOGPIDFILE ];then + rm -f $SYSLOGPIDFILE + fi + if [ ! -f $SYSLOGPIDFILE ];then + ln -s $PIDFILE $SYSLOGPIDFILE + fi fi return $retval } @@ -180,6 +204,9 @@ syslogng_stop() { fi if [ $retval -eq 0 ];then rm -f $SUBSYSDIR/syslog-ng ${PIDFILE} + if [ -h $SYSLOGPIDFILE ];then + rm -f $SYSLOGPIDFILE + fi fi return $retval } @@ -270,6 +297,14 @@ case "$1" in force-reload) syslogng_restart ;; + reload-or-restart) + PID=`pidofproc -p ${PIDFILE} ${SYSLOGNG} | head -1` + if [ -n "$PID" ] && [ $PID -gt 0 ] ;then + syslogng_reload + else + syslogng_start + fi + ;; status) syslogng_status ;; @@ -284,4 +319,4 @@ esac exit $retval -# vim: ts=2 ft=sh +# vim: ts=2 ft=sh noexpandtab diff --git a/contrib/balabit-initscripts/init.d.freebsd b/contrib/balabit-initscripts/init.d.freebsd index 997b4db..de04473 100644 --- a/contrib/balabit-initscripts/init.d.freebsd +++ b/contrib/balabit-initscripts/init.d.freebsd @@ -33,9 +33,13 @@ command="$SYSLOGNG_PREFIX/sbin/syslog-ng" required_files="$SYSLOGNG_PREFIX/etc/syslog-ng.conf" start_precmd="syslog_ng_start_precmd" +start_postcmd="syslog_ng_start_postcmd" +stop_postcmd="syslog_ng_stop_postcmd" reload_precmd="syslog_ng_reload_precmd" extra_commands="reload" +# get original syslog pidfile from initscript. +_syslogd_pidfile=`sed -n -e 's/^pidfile="\([^"]*\)"/\1/p' /etc/rc.d/syslogd 2> /dev/null` syslog_ng_start_precmd() { if [ ! -L /dev/log ]; then ln -s /var/run/log /dev/log @@ -50,6 +54,26 @@ syslog_ng_reload_precmd() { fi } +syslog_ng_start_postcmd() { + if [ -n "$_syslogd_pidfile" ]; then + # remove symlinks + if [ -h $_syslogd_pidfile ]; then + rm -f $_syslogd_pidfile + fi + if [ ! -f $_syslogd_pidfile ]; then + ln -s "$pidfile" "$_syslogd_pidfile" + fi + fi +} + +syslog_ng_stop_postcmd() { + if [ -n "$_syslogd_pidfile" ]; then + if [ -h $_syslogd_pidfile ]; then + rm -f "$_syslogd_pidfile" + fi + fi +} + load_rc_config "$name" case $1 in diff --git a/contrib/cygwin-packaging/cygwin-postinstall b/contrib/cygwin-packaging/cygwin-postinstall index 4b7bf7d..e812ead 100755 --- a/contrib/cygwin-packaging/cygwin-postinstall +++ b/contrib/cygwin-packaging/cygwin-postinstall @@ -21,11 +21,11 @@ then exit 3 fi mkdir -p "${DESTDIR}/usr/bin" -mkdir -p "${DESTDIR}/usr/share/doc/syslog-ng" +#mkdir -p "${DESTDIR}/usr/share/doc/syslog-ng" mkdir -p "${DESTDIR}/usr/share/doc/Cygwin" cp contrib/cygwin-packaging/syslog-ng-config "${DESTDIR}/usr/bin" -cp -rp doc/examples/syslog-ng.conf.s* doc/reference/syslog-ng.[tx]* "${DESTDIR}/usr/share/doc/syslog-ng" -tar xzfC doc/reference/syslog-ng.html.tar.gz "${DESTDIR}/usr/share/doc/syslog-ng" +#cp -rp doc/examples/syslog-ng.conf.s* doc/reference/syslog-ng.[tx]* "${DESTDIR}/usr/share/doc/syslog-ng" +#tar xzfC doc/reference/syslog-ng.html.tar.gz "${DESTDIR}/usr/share/doc/syslog-ng" cat > "${DESTDIR}/usr/share/doc/Cygwin/syslog-ng.README" <<'EOF' If you want to use syslog-ng, just run the /usr/bin/syslog-ng-config script. This script will create a default configuration file @@ -42,15 +42,15 @@ The syslog-ng package has been built using the following command sequence from the top level source dir: ./configure \ - --disable-ipv6 \ - --disable-tcp-wrapper \ --prefix=/usr \ --sysconfdir=/etc \ --libexecdir='$(prefix)/sbin' \ --localstatedir=/var \ --datadir='$(prefix)/share' \ --mandir='$(prefix)/share/man' \ - --infodir='$(prefix)/share/info' + --infodir='$(prefix)/share/info' \ + --enable-dynamic-linking \ + --with-pidfile-dir=/var make make install-strip contrib/cygwin-packaging/cygwin-postinstall diff --git a/contrib/cygwin-packaging/syslog-ng-config b/contrib/cygwin-packaging/syslog-ng-config index 790f0cc..7ae5fec 100755 --- a/contrib/cygwin-packaging/syslog-ng-config +++ b/contrib/cygwin-packaging/syslog-ng-config @@ -205,13 +205,13 @@ if [ ! -f "${SYSCONFDIR}/syslog-ng.conf" ] then echo "Creating default ${SYSCONFDIR}/syslog-ng.conf file" cat > ${SYSCONFDIR}/syslog-ng.conf << EOF +@version 3.0 options { keep_hostname(yes); - chain_hostnames(no); owner("system"); group("root"); perm(0664); - sync(0); + flush_lines(0); }; source applications { @@ -220,7 +220,7 @@ source applications { }; source kernel { - file("/dev/kmsg", log_prefix("kernel: ")); + file("/dev/kmsg", program_override("kernel: ")); }; destination messages { @@ -240,42 +240,35 @@ EOF fi setfacl -m u:system:rw- "${SYSCONFDIR}/syslog-ng.conf" -# Check if running on NT -_sys="`uname`" -_nt=`expr "${_sys}" : "CYGWIN_NT"` -# On NT ask if syslog-ng should be installed as service -if [ ${_nt} -gt 0 ] +# Check if syslogd is installed and remove on user request. +if cygrunsrv -Q syslogd > /dev/null 2>&1 then - # Check if syslogd is installed and remove on user request. - if cygrunsrv -Q syslogd > /dev/null 2>&1 + echo "Warning: The syslogd service is already installed. You can not" + echo "run both, syslogd and syslog-ng in parallel." + echo + if request "Do you want to deinstall the syslogd service in favor of syslog-ng?" then - echo "Warning: The syslogd service is already installed. You can not" - echo "run both, syslogd and syslog-ng in parallel." - echo - if request "Do you want to deinstall the syslogd service in favor of syslog-ng?" - then - cygrunsrv -E syslogd - cygrunsrv -R syslogd - fi + cygrunsrv -E syslogd + cygrunsrv -R syslogd fi - # Install syslog-ng service if it is not already installed - if ! cygrunsrv -Q syslog-ng > /dev/null 2>&1 +fi +# Install syslog-ng service if it is not already installed +if ! cygrunsrv -Q syslog-ng > /dev/null 2>&1 +then + echo + echo + echo "Warning: The following function requires administrator privileges!" + echo + echo "Do you want to install syslog-ng as service?" + if request "(Say \"no\" if it's already installed as service)" then - echo - echo - echo "Warning: The following function requires administrator privileges!" - echo - echo "Do you want to install syslog-ng as service?" - if request "(Say \"no\" if it's already installed as service)" + if cygrunsrv -I syslog-ng -d "CYGWIN syslog-ng" -p /usr/sbin/syslog-ng -a "-F --fd-limit 256" then - if cygrunsrv -I syslog-ng -d "CYGWIN syslog-ng" -p /usr/sbin/syslog-ng -a -F - then - echo - echo "The service has been installed under LocalSystem account." - echo "To start the service, call \`net start syslog-ng' or \`cygrunsrv -S syslog-ng'." - echo - echo "Check ${SYSCONFDIR}/syslog-ng.conf first, if it suits your needs." - fi + echo + echo "The service has been installed under LocalSystem account." + echo "To start the service, call \`net start syslog-ng' or \`cygrunsrv -S syslog-ng'." + echo + echo "Check ${SYSCONFDIR}/syslog-ng.conf first, if it suits your needs." fi fi fi diff --git a/contrib/solaris-packaging/syslog-ng.method b/contrib/solaris-packaging/syslog-ng.method index f0fee58..d819a3c 100755 --- a/contrib/solaris-packaging/syslog-ng.method +++ b/contrib/solaris-packaging/syslog-ng.method @@ -13,6 +13,7 @@ SYSLOGNG_PREFIX=/opt/syslog-ng SYSLOGNG="$SYSLOGNG_PREFIX/sbin/syslog-ng" CONFFILE=$SYSLOGNG_PREFIX/etc/syslog-ng.conf PIDFILE=$SYSLOGNG_PREFIX/var/run/syslog-ng.pid +SYSLOGPIDFILE=/var/run/syslog.pid OPTIONS= MAXWAIT=30 @@ -56,7 +57,7 @@ slng_stop() { _process=`basename $SYSLOGNG` slng_waitforpid "$_process" $syspid - _ret=$? + _ret=$? if [ $_ret -eq 0 ]; then kill -KILL $syspid $_ret=$? @@ -68,6 +69,9 @@ slng_stop() { [ $? -ne 0 ] && exit $SMF_EXIT_ERR_FATAL fi rm -f $PIDFILE + if [ -h $SYSLOGPIDFILE ];then + rm -f $SYSLOGPIDFILE + fi return $SMF_EXIT_OK fi return $SMF_EXIT_ERR_FATAL @@ -93,6 +97,13 @@ slng_start () { fi check_syntax $SYSLOGNG $OPTIONS + # remove symlinks + if [ -h $SYSLOGPIDFILE ];then + rm -f $SYSLOGPIDFILE + fi + if [ ! -f $SYSLOGPIDFILE ];then + ln -s $PIDFILE $SYSLOGPIDFILE + fi return $SMF_EXIT_OK fi return $SMF_EXIT_ERR_FATAL diff --git a/debian/control b/debian/control index c0689a5..0dcc8b3 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: syslog-ng Section: admin Priority: extra Maintainer: SZALAY Attila -Build-depends: debhelper (>=3.0.0), libevtlog-dev, libnet1-dev, libglib2.0-dev (>= 2.4), pkg-config, libdbi-dev +Build-depends: debhelper (>=3.0.0), libevtlog-dev, libnet1-dev, libglib2.0-dev (>= 2.4), pkg-config, libdbi0-dev, libssl-dev Standards-Version: 3.6.1 Package: syslog-ng diff --git a/src/affile.c b/src/affile.c index 6d48915..5721a1a 100644 --- a/src/affile.c +++ b/src/affile.c @@ -40,11 +40,12 @@ static gboolean affile_open_file(gchar *name, gint flags, - uid_t uid, gid_t gid, mode_t mode, - uid_t dir_uid, gid_t dir_gid, mode_t dir_mode, - gboolean create_dirs, gboolean privileged, gint *fd) + uid_t uid, gid_t gid, mode_t mode, + uid_t dir_uid, gid_t dir_gid, mode_t dir_mode, + gboolean create_dirs, gboolean privileged, gboolean is_pipe, gint *fd) { cap_t saved_caps; + struct stat st; if (strstr(name, "../") || strstr(name, "/..")) { @@ -63,20 +64,43 @@ affile_open_file(gchar *name, gint flags, g_process_cap_modify(CAP_DAC_READ_SEARCH, TRUE); g_process_cap_modify(CAP_SYS_ADMIN, TRUE); } + if (stat(name, &st) >= 0) + { + if (is_pipe && !S_ISFIFO(st.st_mode)) + { + msg_error("Error opening pipe, underlying file is not a FIFO, it should be used by file()", + evt_tag_str("filename", name), + NULL); + goto exit; + } + else if (!is_pipe && S_ISFIFO(st.st_mode)) + { + msg_error("Error opening file, underlying file is a FIFO, it should be used by pipe()", + evt_tag_str("filename", name), + NULL); + goto exit; + } + } *fd = open(name, flags, mode); + if (is_pipe && *fd < 0 && errno == ENOENT) + { + if (mkfifo(name, 0666) >= 0) + *fd = open(name, flags, 0666); + } if (*fd != -1) { g_fd_set_cloexec(*fd, TRUE); g_process_cap_modify(CAP_DAC_OVERRIDE, TRUE); - if (uid != -1) + if (uid != (uid_t) -1) fchown(*fd, uid, -1); - if (gid != -1) + if (gid != (gid_t) -1) fchown(*fd, -1, gid); - if (mode != -1) + if (mode != (mode_t) -1) fchmod(*fd, mode); } + exit: if (privileged) { g_process_cap_restore(saved_caps); @@ -99,7 +123,7 @@ affile_sd_open_file(AFFileSourceDriver *self, gchar *name, gint *fd) else flags = O_RDONLY | O_NOCTTY | O_NONBLOCK | O_LARGEFILE; - if (affile_open_file(name, flags, -1, -1, -1, 0, 0, 0, 0, !!(self->flags & AFFILE_PRIVILEGED), fd)) + if (affile_open_file(name, flags, -1, -1, -1, 0, 0, 0, 0, !!(self->flags & AFFILE_PRIVILEGED), !!(self->flags & AFFILE_PIPE), fd)) return TRUE; return FALSE; } @@ -196,9 +220,15 @@ affile_sd_notify(LogPipe *s, LogPipe *sender, gint notify_code, gpointer user_da transport = log_transport_plain_new(fd, 0); transport->timeout = 10; - self->reader = log_reader_new(log_proto_plain_new_server(transport, self->reader_options.padding, self->reader_options.msg_size, LPPF_NOMREAD | ((self->reader_options.follow_freq > 0) ? LPPF_IGNORE_EOF : 0)), - LR_LOCAL); - + self->reader = log_reader_new( + log_proto_plain_new_server(transport, self->reader_options.padding, + self->reader_options.msg_size, + ((self->reader_options.follow_freq > 0) + ? LPPF_IGNORE_EOF + : LPPF_NOMREAD) + ), + LR_LOCAL); + log_reader_set_options(self->reader, s, &self->reader_options, 1, SCS_FILE, self->super.id, self->filename->str); log_reader_set_follow_filename(self->reader, self->filename->str); @@ -290,10 +320,16 @@ affile_sd_init(LogPipe *s) transport->timeout = 10; /* FIXME: we shouldn't use reader_options to store log protocol parameters */ - self->reader = log_reader_new(log_proto_plain_new_server(transport, self->reader_options.padding, self->reader_options.msg_size, LPPF_NOMREAD | ((self->reader_options.follow_freq > 0) ? LPPF_IGNORE_EOF : 0)), - LR_LOCAL); + self->reader = log_reader_new( + log_proto_plain_new_server(transport, self->reader_options.padding, + self->reader_options.msg_size, + ((self->reader_options.follow_freq > 0) + ? LPPF_IGNORE_EOF + : LPPF_NOMREAD) + ), + LR_LOCAL); log_reader_set_options(self->reader, s, &self->reader_options, 1, SCS_FILE, self->super.id, self->filename->str); - + log_reader_set_follow_filename(self->reader, self->filename->str); /* NOTE: if the file could not be opened, we ignore the last @@ -458,7 +494,7 @@ affile_dw_init(LogPipe *s) if (affile_open_file(self->filename->str, flags, self->owner->file_uid, self->owner->file_gid, self->owner->file_perm, self->owner->dir_uid, self->owner->dir_gid, self->owner->dir_perm, - !!(self->owner->flags & AFFILE_CREATE_DIRS), FALSE, &fd)) + !!(self->owner->flags & AFFILE_CREATE_DIRS), FALSE, !!(self->owner->flags & AFFILE_PIPE), &fd)) { guint write_flags; diff --git a/src/afsocket.c b/src/afsocket.c index ad8e198..af788f6 100644 --- a/src/afsocket.c +++ b/src/afsocket.c @@ -90,12 +90,12 @@ afsocket_open_socket(GSockAddr *bind_addr, int stream_or_dgram, int *fd) else sock = socket(bind_addr->sa.sa_family, SOCK_DGRAM, 0); - g_fd_set_nonblock(sock, TRUE); - g_fd_set_cloexec(sock, TRUE); if (sock != -1) { cap_t saved_caps; + g_fd_set_nonblock(sock, TRUE); + g_fd_set_cloexec(sock, TRUE); saved_caps = g_process_cap_save(); g_process_cap_modify(CAP_NET_BIND_SERVICE, TRUE); g_process_cap_modify(CAP_DAC_OVERRIDE, TRUE); @@ -208,7 +208,9 @@ afsocket_sc_init(LogPipe *s) if ((self->owner->flags & AFSOCKET_SYSLOG_PROTOCOL) == 0) { /* plain protocol */ - proto = log_proto_plain_new_server(transport, self->owner->reader_options.padding, self->owner->reader_options.msg_size, (self->owner->flags & AFSOCKET_DGRAM) ? LPPF_PKTTERM : 0); + proto = log_proto_plain_new_server(transport, self->owner->reader_options.padding, + self->owner->reader_options.msg_size, + (self->owner->flags & AFSOCKET_DGRAM) ? (LPPF_PKTTERM + LPPF_IGNORE_EOF) : 0); } else { diff --git a/src/afsql.c b/src/afsql.c index 96c5b22..dcbc02e 100644 --- a/src/afsql.c +++ b/src/afsql.c @@ -940,6 +940,7 @@ afsql_dd_new() self->frac_digits = -1; self->validated_tables = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + g_static_mutex_init(&self->queue_lock); init_sequence_number(&self->seq_num); return &self->super; diff --git a/src/apphook.c b/src/apphook.c index ab9cb02..6115b27 100644 --- a/src/apphook.c +++ b/src/apphook.c @@ -54,10 +54,10 @@ run_application_hook(gint type) if (e->type == type) { + l_next = l->next; application_hooks = g_list_remove_link(application_hooks, l); e->func(type, e->user_data); g_free(e); - l_next = l->next; g_list_free_1(l); } else diff --git a/src/cfg-grammar.y b/src/cfg-grammar.y index 9902d84..056783d 100644 --- a/src/cfg-grammar.y +++ b/src/cfg-grammar.y @@ -52,6 +52,7 @@ LogParser *last_parser; FilterRE *last_re_filter; LogRewrite *last_rewrite; gint last_addr_family = AF_INET; +gchar *last_include_file; #if ENABLE_SSL TLSContext *last_tls_context; @@ -92,17 +93,20 @@ cfg_check_template(LogTemplate *template) return TRUE; } + %} %union { + gint token; gint64 num; + double fnum; char *cptr; void *ptr; FilterExprNode *node; } /* statements */ -%token KW_SOURCE KW_FILTER KW_PARSER KW_DESTINATION KW_LOG KW_OPTIONS +%token KW_SOURCE KW_FILTER KW_PARSER KW_DESTINATION KW_LOG KW_OPTIONS KW_INCLUDE /* source & destination items */ %token KW_INTERNAL KW_FILE KW_PIPE KW_UNIX_STREAM KW_UNIX_DGRAM @@ -154,7 +158,7 @@ cfg_check_template(LogTemplate *template) /* socket related options */ %token KW_KEEP_ALIVE KW_MAX_CONNECTIONS -%token KW_LOCALIP KW_IP KW_LOCALPORT KW_PORT KW_DESTPORT KW_FRAMED +%token KW_LOCALIP KW_IP KW_LOCALPORT KW_PORT KW_DESTPORT %token KW_IP_TTL KW_SO_BROADCAST KW_IP_TOS KW_SO_SNDBUF KW_SO_RCVBUF KW_SO_KEEPALIVE KW_SPOOF_SOURCE /* misc options */ @@ -182,6 +186,7 @@ cfg_check_template(LogTemplate *template) %token DOTDOT %token IDENTIFIER %token NUMBER +%token FLOAT %token STRING %left KW_OR @@ -276,6 +281,32 @@ cfg_check_template(LogTemplate *template) %type string_list %type string_list_build +%type reserved_words_as_strings + +%type KW_PARSER +%type KW_REWRITE +%type KW_INCLUDE +%type KW_SYSLOG +%type KW_COLUMNS +%type KW_DELIMITERS +%type KW_QUOTES +%type KW_QUOTE_PAIRS +%type KW_NULL +%type KW_CSV_PARSER +%type KW_DB_PARSER +%type KW_ENCODING +%type KW_SET +%type KW_SUBST +%type KW_VALUE +%type KW_PROGRAM_OVERRIDE +%type KW_HOST_OVERRIDE +%type KW_TRANSPORT +%type KW_TRUSTED_KEYS +%type KW_TRUSTED_DN +%type KW_MESSAGE +%type KW_TYPE +%type KW_SQL + %% start @@ -283,7 +314,21 @@ start ; stmts - : stmt ';' stmts + : stmt ';' + { + if (last_include_file && !cfg_lex_process_include(last_include_file)) + { + free(last_include_file); + last_include_file = NULL; + YYERROR; + } + if (last_include_file) + { + free(last_include_file); + last_include_file = NULL; + } + } + stmts | ; @@ -296,6 +341,7 @@ stmt | KW_REWRITE rewrite_stmt { cfg_add_rewrite(configuration, $2); } | KW_TEMPLATE template_stmt { cfg_add_template(configuration, $2); } | KW_OPTIONS options_stmt { } + | KW_INCLUDE include_stmt { } ; source_stmt @@ -319,6 +365,9 @@ dest_stmt log_stmt : '{' log_items log_forks log_flags '}' { LogPipeItem *pi = log_pipe_item_append_tail($2, $3); $$ = log_connection_new(pi, $4); } ; + +include_stmt + : string { last_include_file = $1; } log_items : log_item ';' log_items { log_pipe_item_append($1, $3); $$ = $1; } @@ -442,7 +491,7 @@ source_affile_option affile_sd_set_pri_level(last_driver, level); free($3); } - | KW_FACILITY '(' string ')' + | KW_FACILITY '(' string ')' { int facility = -1; @@ -708,7 +757,8 @@ source_reader_option | KW_LOG_MSG_SIZE '(' NUMBER ')' { last_reader_options->msg_size = $3; } | KW_LOG_FETCH_LIMIT '(' NUMBER ')' { last_reader_options->fetch_limit = $3; } | KW_PAD_SIZE '(' NUMBER ')' { last_reader_options->padding = $3; } - | KW_FOLLOW_FREQ '(' NUMBER ')' { last_reader_options->follow_freq = $3; } + | KW_FOLLOW_FREQ '(' FLOAT ')' { last_reader_options->follow_freq = (long) ($3 * 1000); } + | KW_FOLLOW_FREQ '(' NUMBER ')' { last_reader_options->follow_freq = ($3 * 1000); } | KW_KEEP_TIMESTAMP '(' yesno ')' { last_reader_options->super.keep_timestamp = $3; } | KW_ENCODING '(' string ')' { last_reader_options->text_encoding = g_strdup($3); free($3); } ; @@ -777,7 +827,7 @@ dest_afpipe dest_afpipe_params : string { - last_driver = affile_dd_new($1, AFFILE_NO_EXPAND | AFFILE_PIPE); + last_driver = affile_dd_new($1, AFFILE_PIPE); free($1); last_writer_options = &((AFFileDestDriver *) last_driver)->writer_options; last_writer_options->flush_lines = 0; @@ -895,7 +945,7 @@ dest_afinet_tcp_option : dest_afinet_option | KW_TLS { -#if ENABLE_TLS +#if ENABLE_SSL last_tls_context = tls_context_new(TM_CLIENT); #endif } @@ -1282,7 +1332,7 @@ filter_fac_list ; filter_fac - : string + : string { int n = syslog_name_lookup_facility_by_name($1); if (n == -1) @@ -1461,6 +1511,34 @@ dnsmode string : IDENTIFIER | STRING + | reserved_words_as_strings { $$ = cfg_lex_get_keyword_string($1); } + ; + +reserved_words_as_strings + /* these keywords were introduced in syslog-ng 3.0 */ + : KW_PARSER + | KW_REWRITE + | KW_INCLUDE + | KW_SYSLOG + | KW_COLUMNS + | KW_DELIMITERS + | KW_QUOTES + | KW_QUOTE_PAIRS + | KW_NULL + | KW_CSV_PARSER + | KW_DB_PARSER + | KW_ENCODING + | KW_SET + | KW_SUBST + | KW_VALUE + | KW_PROGRAM_OVERRIDE + | KW_HOST_OVERRIDE + | KW_TRANSPORT + | KW_TRUSTED_KEYS + | KW_TRUSTED_DN + | KW_MESSAGE + | KW_TYPE + | KW_SQL ; string_or_number @@ -1483,14 +1561,8 @@ extern int linenum; void yyerror(char *msg) { - fprintf(stderr, "%s in %s at line %d.\n", msg, configuration->filename, linenum); + fprintf(stderr, "%s in %s at line %d.\n\n" + "syslog-ng documentation: http://www.balabit.com/support/documentation/?product=syslog-ng\n" + "mailing list: https://lists.balabit.hu/mailman/listinfo/syslog-ng\n", msg, cfg_lex_get_current_file(), cfg_lex_get_current_lineno()); } -void -yyparser_reset(void) -{ - last_driver = NULL; - last_reader_options = NULL; - last_writer_options = NULL; - last_template = NULL; -} diff --git a/src/cfg-lex.l b/src/cfg-lex.l index c9db716..b3c893c 100644 --- a/src/cfg-lex.l +++ b/src/cfg-lex.l @@ -31,6 +31,7 @@ #include #include +#include struct keyword { @@ -52,6 +53,7 @@ static struct keyword keywords[] = { { "destination", KW_DESTINATION }, { "log", KW_LOG }, { "options", KW_OPTIONS }, + { "include", KW_INCLUDE }, /* source or destination items */ { "file", KW_FILE }, @@ -162,7 +164,6 @@ static struct keyword keywords[] = { { "localport", KW_LOCALPORT }, { "port", KW_PORT }, { "destport", KW_DESTPORT }, - { "framed", KW_FRAMED }, { "ip_ttl", KW_IP_TTL }, { "ip_tos", KW_IP_TOS }, { "so_broadcast", KW_SO_BROADCAST }, @@ -229,7 +230,20 @@ static struct keyword keywords[] = { #define MAX_REGEXP_LEN 1024 -int linenum = 1; +typedef struct _CfgIncludeLevel +{ + GSList *files; + gchar *current_file; + gint linenum; + struct yy_buffer_state *yybuf; +} CfgIncludeLevel; + +#define MAX_INCLUDE_DEPTH 16 + +static CfgIncludeLevel include_stack[MAX_INCLUDE_DEPTH]; +static gint include_depth = 0; + + int lex_filter_params = 0; char buf[MAX_REGEXP_LEN]; char *str; @@ -237,6 +251,7 @@ char *str; static int check_reserved_words(char *token); static void append_string(int length, char *str); static void append_char(char c); +static gboolean cfg_start_next_include(gboolean first_on_this_level); %} @@ -254,9 +269,10 @@ word [^ \#'"\(\)\{\}\\;\n\t,|\.] %% \#.*$ ; -\r?\n { linenum++; } +\r?\n { include_stack[include_depth].linenum++; } {white}+ ; \.\. { return DOTDOT; } +(-|\+)?{digit}+\.{digit}+ { yylval.fnum = strtod(yytext, NULL); return FLOAT; } 0x{digit}+ { yylval.num = strtoll(yytext, NULL, 16); return NUMBER; } 0{digit}+ { yylval.num = strtoll(yytext, NULL, 8); return NUMBER; } (-|\+)?{digit}+ { yylval.num = strtoll(yytext, NULL, 10); return NUMBER; } @@ -298,16 +314,13 @@ word [^ \#'"\(\)\{\}\\;\n\t,|\.] return STRING; } + +<> { if (!cfg_start_next_include(FALSE)) yyterminate(); } + %% -int -lex_init(FILE *file, gint init_line_num) -{ - yyrestart(file); - linenum = init_line_num; - return 0; -} -int + +static int check_reserved_words(char *token) { int i, j; @@ -339,6 +352,7 @@ check_reserved_words(char *token) break; } keywords[i].kw_status = KWS_NORMAL; + yylval.token = keywords[i].kw_token; return keywords[i].kw_token; } } @@ -364,3 +378,251 @@ append_char(char c) str++; *str = 0; } + +const gchar * +cfg_lex_get_current_file(void) +{ + CfgIncludeLevel *level = &include_stack[include_depth]; + + return level->current_file; +} + +gint +cfg_lex_get_current_lineno(void) +{ + CfgIncludeLevel *level = &include_stack[include_depth]; + + return level->linenum; +} + +char * +cfg_lex_get_keyword_string(int kw) +{ + int i; + for (i = 0; i < (sizeof(keywords) / sizeof(struct keyword)); i++) + { + if (keywords[i].kw_token == kw) + { + msg_warning("WARNING: Your configuration uses a newly introduced reserved word as identifier, please use a different name", + evt_tag_str("keyword", keywords[i].kw_name), + evt_tag_str("filename", cfg_lex_get_current_file()), + evt_tag_int("line", cfg_lex_get_current_lineno()), + NULL); + return strdup(keywords[i].kw_name); + } + } + g_assert_not_reached(); +} + + + +static gboolean +cfg_start_next_include(gboolean first_on_this_level) +{ + FILE *include_file; + CfgIncludeLevel *level = &include_stack[include_depth]; + gchar *filename; + struct yy_buffer_state *yybuf; + + g_assert(level->yybuf == NULL); + + if (include_depth == 0) + { + return FALSE; + } + + if (!first_on_this_level) + { + msg_debug("Finishing include file", + evt_tag_str("filename", level->current_file), + evt_tag_int("depth", include_depth), + NULL); + } + + if (!level->files) + { + yybuf = YY_CURRENT_BUFFER; + g_free(level->current_file); + fclose(yybuf->yy_input_file); + level->current_file = NULL; + include_depth--; + yy_switch_to_buffer(include_stack[include_depth].yybuf); + include_stack[include_depth].yybuf = NULL; + if (!first_on_this_level) + yy_delete_buffer(yybuf); + + return TRUE; + } + + filename = (gchar *) level->files->data; + level->files = g_slist_delete_link(level->files, level->files); + + include_file = fopen(filename, "r"); + if (!include_file) + { + msg_error("Error opening include file", + evt_tag_str("filename", filename), + evt_tag_int("depth", include_depth), + NULL); + g_free(filename); + return FALSE; + } + msg_debug("Starting to read include file", + evt_tag_str("filename", filename), + evt_tag_int("depth", include_depth), + NULL); + yybuf = YY_CURRENT_BUFFER; + if (level->current_file) + { + g_free(level->current_file); + if (yybuf) + fclose(yybuf->yy_input_file); + } + level->current_file = filename; + level->linenum = 1; + + yy_switch_to_buffer(yy_create_buffer(include_file, YY_BUF_SIZE)); + if (!first_on_this_level) + yy_delete_buffer(yybuf); + return TRUE; +} + +gboolean +cfg_lex_process_include(const gchar *filename) +{ + struct stat st; + gchar buf[1024]; + CfgIncludeLevel *level; + + if (include_depth >= MAX_INCLUDE_DEPTH - 1) + { + msg_error("Include file depth is too deep, increase MAX_INCLUDE_DEPTH and recompile", + evt_tag_str("filename", filename), + evt_tag_int("depth", include_depth), + NULL); + return FALSE; + } + + if (filename[0] != '/') + { + g_snprintf(buf, sizeof(buf), "%s/%s", PATH_SYSCONFDIR, filename); + filename = buf; + } + + if (stat(filename, &st) < 0) + { + msg_error("Include file/directory not found", + evt_tag_str("filename", filename), + evt_tag_errno("error", errno), + NULL); + return FALSE; + } + include_stack[include_depth].yybuf = YY_CURRENT_BUFFER; + include_depth++; + level = &include_stack[include_depth]; + if (S_ISDIR(st.st_mode)) + { + GDir *dir; + GError *error = NULL; + const gchar *entry; + + dir = g_dir_open(filename, 0, &error); + if (!dir) + { + msg_error("Error opening directory for reading", + evt_tag_str("filename", filename), + evt_tag_str("error", error->message), + NULL); + goto drop_level; + } + while ((entry = g_dir_read_name(dir))) + { + const gchar *p; + + for (p = entry; *p; p++) + { + if (!((*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z') || + (*p >= '0' && *p <= '9') || + (*p == '_') || (*p == '-') || (*p == '.'))) + { + msg_debug("Skipping include file, does not match pattern [\\-_a-zA-Z0-9]+", + evt_tag_str("filename", entry), + NULL); + p = NULL; + break; + } + } + if (p) + { + gchar *full_filename = g_build_filename(filename, entry, NULL); + if (stat(full_filename, &st) < 0 || S_ISDIR(st.st_mode)) + { + msg_debug("Skipping include file as it is a directory", + evt_tag_str("filename", entry), + NULL); + g_free(full_filename); + continue; + } + level->files = g_slist_insert_sorted(level->files, full_filename, (GCompareFunc) strcmp); + msg_debug("Adding include file", + evt_tag_str("filename", entry), + NULL); + } + } + g_dir_close(dir); + if (!level->files) + { + /* no include files in the specified directory */ + msg_debug("No files in this include directory", + evt_tag_str("dir", filename), + NULL); + include_depth--; + include_stack[include_depth].yybuf = NULL; + return TRUE; + } + } + else + { + g_assert(level->files == NULL); + level->files = g_slist_prepend(level->files, g_strdup(filename)); + } + return cfg_start_next_include(TRUE); + drop_level: + g_slist_foreach(level->files, (GFunc) g_free, NULL); + g_slist_free(level->files); + level->files = NULL; + return FALSE; +} + +int +cfg_lex_init(FILE *file, gint init_line_num) +{ + CfgIncludeLevel *level; + + yyrestart(file); + level = &include_stack[0]; + level->current_file = g_strdup(configuration->filename); + level->linenum = init_line_num; + return 0; +} + +void +cfg_lex_deinit(void) +{ + gint i; + + for (i = 0; i < include_depth; i++) + { + CfgIncludeLevel *level = &include_stack[i]; + + if (level->current_file) + g_free(level->current_file); + + g_slist_foreach(level->files, (GFunc) g_free, NULL); + g_slist_free(level->files); + level->files = NULL; + if (level->yybuf) + yy_delete_buffer(level->yybuf); + } +} diff --git a/src/cfg.c b/src/cfg.c index 23d93b6..45e5119 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -34,6 +34,8 @@ #include "logparser.h" #include "serialize.h" +#include +#include #include #include @@ -203,15 +205,6 @@ cfg_deinit(GlobalConfig *cfg) return log_center_deinit(cfg->center); } -/* extern declarations in the generated parser & lexer */ -extern FILE *yyin; -extern int yyparse(); -extern void lex_init(FILE *, gint lineno); -extern int yydebug; -extern int linenum; - -extern void yyparser_reset(void); - gboolean cfg_read_pragmas(GlobalConfig *self, FILE *cfg, gint *lineno) { @@ -358,8 +351,9 @@ cfg_new(gchar *fname) self->chain_hostnames = TRUE; } - lex_init(cfg, lineno); + cfg_lex_init(cfg, lineno); res = yyparse(); + cfg_lex_deinit(); fclose(cfg); if (!res) { @@ -481,7 +475,15 @@ cfg_reload_config(gchar *fname, GlobalConfig *cfg) { msg_error("Error initializing new configuration, reverting to old config", NULL); cfg_persist_config_move(new_cfg, cfg); - cfg_init(cfg); + if (!cfg_init(cfg)) + { + /* hmm. hmmm, error reinitializing old configuration, we're hosed. + * Best is to kill ourselves in the hope that the supervisor + * restarts us. + */ + kill(getpid(), SIGQUIT); + g_assert_not_reached(); + } return cfg; } } diff --git a/src/cfg.h b/src/cfg.h index d7b4edc..91f3060 100644 --- a/src/cfg.h +++ b/src/cfg.h @@ -28,6 +28,7 @@ #include #include +#include struct _LogSourceGroup; struct _LogDestGroup; @@ -148,6 +149,19 @@ void cfg_persist_set_version(GlobalConfig *cfg, const gint version); void persist_config_free(PersistentConfig *persist); +/* defined in the lexer */ +void yyerror(char *msg); +int yylex(); +int cfg_lex_init(FILE *file, gint init_line_num); +void cfg_lex_deinit(void); +gboolean cfg_lex_process_include(const gchar *filename); +const gchar *cfg_lex_get_current_file(void); +gint cfg_lex_get_current_lineno(void); +char *cfg_lex_get_keyword_string(int kw); + +/* defined in the parser */ +int yyparse(void); + static inline gboolean cfg_check_current_config_version(gint req) { diff --git a/src/dnscache.c b/src/dnscache.c index ef8cc8f..bd23648 100644 --- a/src/dnscache.c +++ b/src/dnscache.c @@ -66,6 +66,7 @@ static gint dns_cache_expire_failed = 60; static gint dns_cache_persistent_count = 0; static gchar *dns_cache_hosts = NULL; static time_t dns_cache_hosts_mtime = -1; +static time_t dns_cache_hosts_checktime = 0; static gboolean dns_cache_key_equal(DNSCacheKey *e1, DNSCacheKey *e2) @@ -156,6 +157,12 @@ static void dns_cache_check_hosts(void) { struct stat st; + time_t t = time(NULL); + + if (G_LIKELY(dns_cache_hosts_checktime == t)) + return; + + dns_cache_hosts_checktime = t; if (!dns_cache_hosts || stat(dns_cache_hosts, &st) < 0) { @@ -299,6 +306,7 @@ dns_cache_set_params(gint cache_size, gint expire, gint expire_failed, const gch dns_cache_expire_failed = expire_failed; dns_cache_hosts = g_strdup(hosts); dns_cache_hosts_mtime = -1; + dns_cache_hosts_checktime = 0; } void diff --git a/src/filter.c b/src/filter.c index 0d1fe57..3a14fdd 100644 --- a/src/filter.c +++ b/src/filter.c @@ -375,6 +375,11 @@ filter_netmask_eval(FilterExprNode *s, LogMessage *msg) { addr.s_addr = htonl(INADDR_LOOPBACK); } + else + { + /* no address information, return FALSE */ + return s->comp; + } return ((addr.s_addr & self->netmask.s_addr) == (self->address.s_addr)) ^ s->comp; } diff --git a/src/gprocess.c b/src/gprocess.c index 5a4a76f..004f57c 100644 --- a/src/gprocess.c +++ b/src/gprocess.c @@ -87,7 +87,9 @@ static struct GProcessMode mode; const gchar *name; const gchar *user; + uid_t uid; const gchar *group; + gid_t gid; const gchar *chroot_dir; const gchar *pidfile; const gchar *pidfile_dir; @@ -109,9 +111,15 @@ static struct .argv = NULL, .argv_start = NULL, .argv_env_len = 0, +#ifdef __CYGWIN__ + .fd_limit_min = 256, +#else .fd_limit_min = 4096, +#endif .check_period = -1, .check_fn = NULL, + .uid = -1, + .gid = -1 }; #if ENABLE_LINUX_CAPS @@ -255,6 +263,8 @@ g_process_set_user(const gchar *user) { if (!process_opts.user) process_opts.user = user; + + } /** @@ -268,6 +278,7 @@ g_process_set_group(const gchar *group) { if (!process_opts.group) process_opts.group = group; + } /** @@ -666,35 +677,20 @@ g_process_change_root(void) static gboolean g_process_change_user(void) { - uid_t uid = -1; - gid_t gid = -1; - #if ENABLE_LINUX_CAPS if (process_opts.caps) prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); #endif - if (process_opts.user && !resolve_user(process_opts.user, &uid)) - { - g_process_message("Error resolving user; user='%s'", process_opts.user); - return FALSE; - } - - if (process_opts.group && !resolve_group(process_opts.group, &gid)) - { - g_process_message("Error resolving group; group='%s'", process_opts.group); - return FALSE; - } - - if ((gint) gid != -1) + if ((gint) process_opts.gid != -1) { - if (setgid(gid) < 0) + if (setgid(process_opts.gid) < 0) { - g_process_message("Error in setgid(); group='%s', error='%s'", process_opts.group, g_strerror(errno)); + g_process_message("Error in setgid(); group='%s', gid='%d', error='%s'", process_opts.group, (gint) process_opts.gid, g_strerror(errno)); if (getuid() == 0) return FALSE; } - if (process_opts.user && initgroups(process_opts.user, gid) < 0) + if (process_opts.user && initgroups(process_opts.user, process_opts.gid) < 0) { g_process_message("Error in initgroups(); user='%s', error='%s'", process_opts.user, g_strerror(errno)); if (getuid() == 0) @@ -702,11 +698,11 @@ g_process_change_user(void) } } - if ((gint) uid != -1) + if ((gint) process_opts.uid != -1) { - if (setuid(uid) < 0) + if (setuid(process_opts.uid) < 0) { - g_process_message("Error in setuid(); user='%s', error='%s'", process_opts.user, g_strerror(errno)); + g_process_message("Error in setuid(); user='%s', uid='%d', error='%s'", process_opts.user, (gint) process_opts.uid, g_strerror(errno)); if (getuid() == 0) return FALSE; } @@ -763,6 +759,21 @@ g_process_change_caps(void) #endif +static void +g_process_resolve_names(void) +{ + if (process_opts.user && !resolve_user(process_opts.user, &process_opts.uid)) + { + g_process_message("Error resolving user; user='%s'", process_opts.user); + process_opts.uid = (uid_t) -1; + } + if (process_opts.group && !resolve_group(process_opts.group, &process_opts.gid)) + { + g_process_message("Error resolving group; group='%s'", process_opts.group); + process_opts.gid = (gid_t) -1; + } +} + /** * g_process_change_dir: * @@ -1116,6 +1127,7 @@ g_process_start(void) g_process_detach_tty(); g_process_change_limits(); + g_process_resolve_names(); if (process_opts.mode == G_PM_BACKGROUND) { diff --git a/src/logmsg.c b/src/logmsg.c index 9bad35f..d7f7558 100644 --- a/src/logmsg.c +++ b/src/logmsg.c @@ -264,6 +264,10 @@ log_msg_get_value(LogMessage *self, const gchar *value_name, gssize *length) return value; } +/** + * NOTE: the new_value is taken as a reference, e.g. it'll be assigned to + * the LogMessage and freed later on. + **/ void log_msg_set_value(LogMessage *self, const gchar *value_name, gchar *new_value, gssize length) { @@ -1065,7 +1069,7 @@ log_msg_parse_version(LogMessage *self, const guchar **data, gint *length) } static void -log_msg_parse_legacy_program_name(LogMessage *self, const guchar **data, gint *length) +log_msg_parse_legacy_program_name(LogMessage *self, const guchar **data, gint *length, guint flags) { /* the data pointer will not change */ const guchar *src, *prog_start; @@ -1110,6 +1114,11 @@ log_msg_parse_legacy_program_name(LogMessage *self, const guchar **data, gint *l src++; left--; } + if (flags & LP_STORE_LEGACY_MSGHDR) + { + log_msg_set_value(self, "LEGACY_MSGHDR", g_strndup((gchar *) *data, *length - left), *length - left); + self->flags |= LF_LEGACY_MSGHDR; + } *data = src; *length = left; } @@ -1573,7 +1582,7 @@ log_msg_parse_legacy(LogMessage *self, const guchar *data, gint length, guint fl log_msg_parse_skip_chars(self, &src, &left, " ", -1); /* Try to extract a program name */ - log_msg_parse_legacy_program_name(self, &src, &left); + log_msg_parse_legacy_program_name(self, &src, &left, flags); } /* If we did manage to find a hostname, store it. */ @@ -1598,7 +1607,7 @@ log_msg_parse_legacy(LogMessage *self, const guchar *data, gint length, guint fl else { /* Capture the program name */ - log_msg_parse_legacy_program_name(self, &src, &left); + log_msg_parse_legacy_program_name(self, &src, &left, flags); } self->timestamps[LM_TS_STAMP] = self->timestamps[LM_TS_RECVD]; } @@ -1607,7 +1616,7 @@ log_msg_parse_legacy(LogMessage *self, const guchar *data, gint length, guint fl self->message_len = left; if ((flags & LP_VALIDATE_UTF8) && g_utf8_validate((gchar *) src, left, NULL)) self->flags |= LF_UTF8; - + return TRUE; } diff --git a/src/logmsg.h b/src/logmsg.h index 17d4b5c..6e0a9be 100644 --- a/src/logmsg.h +++ b/src/logmsg.h @@ -47,6 +47,7 @@ #define LP_ASSUME_UTF8 0x0080 #define LP_VALIDATE_UTF8 0x0100 #define LP_NO_MULTI_LINE 0x0200 +#define LP_STORE_LEGACY_MSGHDR 0x0400 typedef struct _LogPathOptions LogPathOptions; @@ -97,6 +98,13 @@ enum LF_OWN_MATCHES = 0x4000, LF_OWN_ALL = 0x7FF0, LF_CHAINED_HOSTNAME = 0x8000, + + /* originally parsed from RFC 3164 format and the legacy message header + * was saved in $LEGACY_MSGHDR. This flag is a hack to avoid a hash lookup + * in the fast path and indicates that the parser has saved the legacy + * message header intact in a value named LEGACY_MSGHDR. + */ + LF_LEGACY_MSGHDR = 0x00010000, }; typedef struct _LogMessageSDParam LogMessageSDParam; @@ -129,12 +137,25 @@ typedef struct _LogMessageMatch guint16 ofs; guint16 len; #else + +#if GLIB_SIZEOF_VOID_P == 4 + guint16 ofs; + guint8 __pad; + guint8 flags; + guint16 len; + guint8 builtin_value; + guint8 type; +#elif GLIB_SIZEOF_VOID_P == 8 guint16 ofs; guint16 len; guint8 builtin_value; guint8 type; guint8 __pad; guint8 flags; +#else +#error "Unknown pointer size" +#endif + #endif }; }; @@ -156,9 +177,10 @@ struct _LogMessage */ struct { - guint16 flags; - guint16 pri; + guint32 flags; guint32 message_len; + guint16 pri; + /* 6 bytes hole */ LogStamp timestamps[LM_TS_MAX]; gchar * const host; diff --git a/src/logproto.c b/src/logproto.c index b2c30ee..9d7187b 100644 --- a/src/logproto.c +++ b/src/logproto.c @@ -8,11 +8,22 @@ gboolean log_proto_set_encoding(LogProto *self, const gchar *encoding) { - self->convert = g_iconv_open("utf-8", encoding); if (self->convert != (GIConv) -1) { - return FALSE; + g_iconv_close(self->convert); + self->convert = (GIConv) -1; + } + if (self->encoding) + { + g_free(self->encoding); + self->encoding = NULL; } + + self->convert = g_iconv_open("utf-8", encoding); + if (self->convert == (GIConv) -1) + return FALSE; + + self->encoding = g_strdup(encoding); return TRUE; } @@ -23,6 +34,8 @@ log_proto_free(LogProto *s) s->free_fn(s); if (s->convert != (GIConv) -1) g_iconv_close(s->convert); + if (s->encoding) + g_free(s->encoding); log_transport_free(s->transport); g_free(s); } @@ -159,6 +172,8 @@ struct _LogProtoPlainServer gsize buffer_size, buffer_end, buffer_pos; gsize padding_size, max_msg_size; GSockAddr *prev_saddr; + gchar raw_buffer_leftover[8]; + gint raw_buffer_leftover_size; LogProtoStatus status; }; @@ -487,7 +502,8 @@ log_proto_plain_server_fetch(LogProto *s, const guchar **msg, gsize *msg_len, GS /* if conversion is needed, we first read into an on-stack * buffer, and then convert it into our internal buffer */ - raw_buffer = g_alloca(self->max_msg_size); + raw_buffer = g_alloca(self->max_msg_size + self->raw_buffer_leftover_size); + memcpy(raw_buffer, self->raw_buffer_leftover, self->raw_buffer_leftover_size); if (!self->padding_size) { avail = self->max_msg_size; @@ -499,7 +515,7 @@ log_proto_plain_server_fetch(LogProto *s, const guchar **msg, gsize *msg_len, GS } } - rc = log_transport_read(self->super.transport, raw_buffer, avail, sa); + rc = log_transport_read(self->super.transport, raw_buffer + self->raw_buffer_leftover_size, avail, sa); if (sa && *sa) self->prev_saddr = *sa; if (rc < 0) @@ -534,6 +550,13 @@ log_proto_plain_server_fetch(LogProto *s, const guchar **msg, gsize *msg_len, GS msg_verbose("EOF occurred while reading", evt_tag_int(EVT_TAG_FD, self->super.transport->fd), NULL); + if (self->raw_buffer_leftover_size > 0) + { + msg_error("EOF read on a channel with leftovers from previous character conversion, dropping input", + NULL); + self->status = LPS_EOF; + return self->status; + } self->status = LPS_EOF; if (log_proto_plain_server_fetch_from_buf(self, msg, msg_len, TRUE)) { @@ -562,6 +585,9 @@ log_proto_plain_server_fetch(LogProto *s, const guchar **msg, gsize *msg_len, GS } else { + rc += self->raw_buffer_leftover_size; + self->raw_buffer_leftover_size = 0; + /* some data was read */ if (self->super.convert != (GIConv) -1) { @@ -581,22 +607,62 @@ log_proto_plain_server_fetch(LogProto *s, const guchar **msg, gsize *msg_len, GS switch (errno) { case EINVAL: - /* Incomplete text, do not report an error */ + /* Incomplete text, do not report an error, rather try to read again */ + self->buffer_end = self->buffer_size - avail_out; + + if (avail_in > 0) + { + if (avail_in > sizeof(self->raw_buffer_leftover)) + { + msg_error("Invalid byte sequence, the remaining raw buffer is larger than the supported leftover size", + evt_tag_str("encoding", self->super.encoding), + evt_tag_int("avail_in", avail_in), + evt_tag_int("leftover_size", sizeof(self->raw_buffer_leftover)), + NULL); + self->status = LPS_ERROR; + return self->status; + } + memcpy(self->raw_buffer_leftover, raw_buffer, avail_in); + self->raw_buffer_leftover_size = avail_in; + msg_debug("Leftover characters remained after conversion, delaying message until another chunk arrives", + evt_tag_str("encoding", self->super.encoding), + evt_tag_int("avail_in", avail_in), + NULL); + return LPS_SUCCESS; + } break; case E2BIG: self->buffer_end = self->buffer_size - avail_out; /* extend the buffer */ - self->buffer_size *= 2; - self->buffer = g_realloc(self->buffer, self->buffer_size); - /* recalculate the out pointer, and add what we have now */ - ret = -1; + if (self->buffer_size < self->max_msg_size * 6) + { + self->buffer_size *= 2; + self->buffer = g_realloc(self->buffer, self->buffer_size); + + /* recalculate the out pointer, and add what we have now */ + ret = -1; + } + else + { + msg_error("Incoming byte stream requires a too large conversion buffer, probably invalid character sequence", + evt_tag_str("encoding", self->super.encoding), + evt_tag_printf("buffer", "%.*s", self->buffer_end, self->buffer), + NULL); + self->status = LPS_ERROR; + return self->status; + } break; case EILSEQ: default: - msg_error("Invalid byte sequence or other error while converting input", - NULL); + msg_notice("Invalid byte sequence or other error while converting input, skipping character", + evt_tag_str("encoding", self->super.encoding), + evt_tag_printf("char", "0x%02x", *(guchar *) raw_buffer), + NULL); + self->buffer_end = self->buffer_size - avail_out; + raw_buffer++; + avail_in--; break; } } diff --git a/src/logproto.h b/src/logproto.h index 8a03d75..f94e5df 100644 --- a/src/logproto.h +++ b/src/logproto.h @@ -18,6 +18,7 @@ struct _LogProto { LogTransport *transport; GIConv convert; + gchar *encoding; guint flags; gboolean (*read_state)(LogProto *s, SerializeArchive *archive); gboolean (*write_state)(LogProto *s, SerializeArchive *archive); diff --git a/src/logreader.c b/src/logreader.c index f9567ff..ca800d0 100644 --- a/src/logreader.c +++ b/src/logreader.c @@ -103,7 +103,7 @@ log_reader_fd_prepare(GSource *source, if (self->reader->flags & LR_FOLLOW) { - *timeout = self->reader->options->follow_freq * 1000; + *timeout = self->reader->options->follow_freq; return FALSE; } @@ -167,7 +167,7 @@ log_reader_fd_check(GSource *source) if (self->reader->follow_filename && stat(self->reader->follow_filename, &followed_st) != -1) { - if (fd < 0 || st.st_ino != followed_st.st_ino) + if (fd < 0 || (st.st_ino != followed_st.st_ino && followed_st.st_size > 0)) { msg_trace("log_reader_fd_check file moved eof", evt_tag_int("pos", pos), @@ -278,6 +278,8 @@ log_reader_fetch_log(LogReader *self, LogProto *proto) parse_flags |= LP_VALIDATE_UTF8; if (self->options->options & LRO_NO_MULTI_LINE) parse_flags |= LP_NO_MULTI_LINE; + if (self->options->options & LRO_STORE_LEGACY_MSGHDR) + parse_flags |= LP_STORE_LEGACY_MSGHDR; if (self->waiting_for_preemption) may_read = FALSE; @@ -321,7 +323,7 @@ log_reader_fetch_log(LogReader *self, LogProto *proto) /* no more messages for now */ break; } - if (msg_len > 0) + if (msg_len > 0 || (self->options->options & LRO_EMPTY_LINES)) { msg_count++; @@ -772,6 +774,10 @@ log_reader_options_lookup_flag(const gchar *flag) return LRO_VALIDATE_UTF8; if (strcmp(flag, "no-multi-line") == 0 || strcmp(flag, "no_multi_line") == 0) return LRO_NO_MULTI_LINE; + if (strcmp(flag, "store-legacy-msghdr") == 0 || strcmp(flag, "store_legacy_msghdr") == 0) + return LRO_STORE_LEGACY_MSGHDR; + if (strcmp(flag, "empty-lines") == 0 || strcmp(flag, "empty_lines") == 0) + return LRO_EMPTY_LINES; msg_error("Unknown parse flag", evt_tag_str("flag", flag), NULL); return 0; } diff --git a/src/logreader.h b/src/logreader.h index 8e5bc7c..11ff0da 100644 --- a/src/logreader.h +++ b/src/logreader.h @@ -43,6 +43,8 @@ #define LRO_SYSLOG_PROTOCOL 0x0004 #define LRO_VALIDATE_UTF8 0x0008 #define LRO_NO_MULTI_LINE 0x0010 +#define LRO_STORE_LEGACY_MSGHDR 0x0020 +#define LRO_EMPTY_LINES 0x0040 typedef struct _LogReaderWatch LogReaderWatch; @@ -77,7 +79,7 @@ typedef struct _LogReader GSockAddr *peer_addr; gchar *follow_filename; ino_t inode; - off_t size; + gint64 size; } LogReader; @@ -86,7 +88,7 @@ void log_reader_set_follow_filename(LogPipe *self, const gchar *follow_filename) void log_reader_set_peer_addr(LogPipe *s, GSockAddr *peer_addr); void log_reader_set_immediate_check(LogPipe *s); -void log_reader_update_pos(LogReader *self, off_t ofs); +void log_reader_update_pos(LogReader *self, gint64 ofs); void log_reader_save_state(LogReader *self, SerializeArchive *archive); void log_reader_restore_state(LogReader *self, SerializeArchive *archive); diff --git a/src/logwriter.c b/src/logwriter.c index bb01148..4d586e5 100644 --- a/src/logwriter.c +++ b/src/logwriter.c @@ -236,7 +236,7 @@ log_writer_fd_dispatch(GSource *source, log_writer_broken(self->writer, NC_CLOSE); return FALSE; } - else if (self->pollfd.revents & (G_IO_ERR)) + else if (self->pollfd.revents & (G_IO_ERR) && num_elements == 0) { msg_error("POLLERR occurred while idle", evt_tag_int("fd", log_proto_get_fd(self->proto)), @@ -595,9 +595,20 @@ log_writer_format_log(LogWriter *self, LogMessage *lm, GString *result) g_string_append_len(result, lm->host, lm->host_len); g_string_append_c(result, ' '); - g_string_append_len(result, lm->program, lm->program_len); - if (lm->program_len > 0) + if ((lm->flags & LF_LEGACY_MSGHDR)) { + gssize length; + const gchar *msghdr; + + msghdr = log_msg_get_value(lm, "LEGACY_MSGHDR", &length); + if (msghdr) + { + g_string_append_len(result, msghdr, length); + } + } + else if (lm->program_len > 0) + { + g_string_append_len(result, lm->program, lm->program_len); if (lm->pid_len > 0) { g_string_append_c(result, '['); diff --git a/src/main.c b/src/main.c index ba97f0c..f78dcc1 100644 --- a/src/main.c +++ b/src/main.c @@ -366,8 +366,6 @@ main(int argc, char *argv[]) g_process_set_name("syslog-ng"); -#if ENABLE_LINUX_CAPS - /* in this case we switch users early while retaining a limited set of * credentials in order to initialize/reinitialize the configuration. */ @@ -381,27 +379,11 @@ main(int argc, char *argv[]) } else { - g_process_startup_ok(); + if (syntax_only) + g_process_startup_failed(0, TRUE); + else + g_process_startup_ok(); } -#else - - /* if Linux capabilities are not compiled in, the initial setup is - * performed as the root user, and then the switch to a limited user - * account is made. This is compatible how syslog-ng behaved before - * capability support. - */ - - rc = initial_init(&cfg); - if (rc) - { - return rc; - } - g_process_start(); - g_process_startup_ok(); -#endif - - if (syntax_only) - return 0; /* we are running as a non-root user from this point */ @@ -424,6 +406,7 @@ main(int argc, char *argv[]) app_shutdown(); tls_deinit(); z_mem_trace_dump(); + g_process_finish(); return rc; } diff --git a/src/memtrace.c b/src/memtrace.c index ef4729a..eb33f4f 100644 --- a/src/memtrace.c +++ b/src/memtrace.c @@ -121,7 +121,7 @@ z_mem_trace_init(gchar *tracefile) for (i = 0; i < MEMTRACE_HASH_SIZE; i++) { mem_trace_hash[i].list = -1; - memset(&mem_trace_hash[i].lock, 0, sizeof(GStaticMutex)); + g_static_mutex_init(&mem_trace_hash[i].lock); } old_malloc = dlsym(RTLD_NEXT, "malloc"); old_free = dlsym(RTLD_NEXT, "free"); diff --git a/src/misc.c b/src/misc.c index 96fcdd2..364ead6 100644 --- a/src/misc.c +++ b/src/misc.c @@ -274,7 +274,7 @@ resolve_user(const char *user, uid_t *uid) struct passwd *pw; *uid = 0; - if (*user) + if (!(*user)) return FALSE; pw = getpwnam(user); @@ -299,7 +299,7 @@ resolve_group(const char *group, gid_t *gid) struct group *gr; *gid = 0; - if (!*group) + if (!(*group)) return FALSE; gr = getgrnam(group); diff --git a/src/sgroup.c b/src/sgroup.c index add7ac9..27e863f 100644 --- a/src/sgroup.c +++ b/src/sgroup.c @@ -25,8 +25,10 @@ #include "misc.h" #include "messages.h" #include "stats.h" +#include "afinter.h" #include +#include static gboolean log_source_group_init(LogPipe *s) diff --git a/src/templates.c b/src/templates.c index aee1f34..67b8217 100644 --- a/src/templates.c +++ b/src/templates.c @@ -339,17 +339,33 @@ log_macro_expand(GString *result, gint id, guint32 flags, gint ts_format, TimeZo } break; case M_MSGHDR: - /* message, complete with program name and pid */ - result_append(result, msg->program, msg->program_len, !!(flags & LT_ESCAPE)); - if (msg->program_len > 0) + if ((msg->flags & LF_LEGACY_MSGHDR)) { - if (msg->pid_len > 0) + gssize length; + const gchar *msghdr; + + /* fast path for now, as most messages come from legacy devices */ + + msghdr = log_msg_get_value(msg, "LEGACY_MSGHDR", &length); + if (msghdr) { - result_append(result, "[", 1, !!(flags & LT_ESCAPE)); - result_append(result, msg->pid, msg->pid_len, !!(flags & LT_ESCAPE)); - result_append(result, "]", 1, !!(flags & LT_ESCAPE)); + result_append(result, msghdr, length, !!(flags & LT_ESCAPE)); + } + } + else + { + /* message, complete with program name and pid */ + result_append(result, msg->program, msg->program_len, !!(flags & LT_ESCAPE)); + if (msg->program_len > 0) + { + if (msg->pid_len > 0) + { + result_append(result, "[", 1, !!(flags & LT_ESCAPE)); + result_append(result, msg->pid, msg->pid_len, !!(flags & LT_ESCAPE)); + result_append(result, "]", 1, !!(flags & LT_ESCAPE)); + } + result_append(result, ": ", 2, !!(flags & LT_ESCAPE)); } - result_append(result, ": ", 2, !!(flags & LT_ESCAPE)); } break; case M_MESSAGE: @@ -433,6 +449,9 @@ log_macro_expand(GString *result, gint id, guint32 flags, gint ts_format, TimeZo * local timezone */ zone_ofs = (zone_info != NULL ? time_zone_info_get_offset(zone_info, stamp->time.tv_sec) : stamp->zone_offset); + if (zone_ofs == -1) + zone_ofs = stamp->zone_offset; + t = stamp->time.tv_sec + zone_ofs; tm = gmtime_r(&t, &tm_storage); @@ -506,9 +525,6 @@ log_macro_expand(GString *result, gint id, guint32 flags, gint ts_format, TimeZo } break; } - - - g_assert_not_reached(); break; } @@ -634,6 +650,9 @@ log_template_compile(LogTemplate *self, GError **error) g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + if (self->compiled_template) + return TRUE; + p = self->template; while (*p) @@ -754,7 +773,7 @@ log_template_append_format(LogTemplate *self, LogMessage *lm, guint flags, gint flags |= self->flags; - if (self->compiled_template == NULL && !log_template_compile(self, NULL)) + if (!log_template_compile(self, NULL)) return; for (p = self->compiled_template; p; p = g_list_next(p)) diff --git a/src/tlscontext.c b/src/tlscontext.c index b22b546..c06ec88 100644 --- a/src/tlscontext.c +++ b/src/tlscontext.c @@ -102,28 +102,41 @@ tls_session_verify_dn(X509_STORE_CTX *ctx) } int -tls_session_verify(int ok, X509_STORE_CTX *ctx) +tls_session_verify(TLSSession *self, int ok, X509_STORE_CTX *ctx) { + /* untrusted means that we have to accept the certificate even if it is untrusted */ + if (self->ctx->verify_mode & TVM_UNTRUSTED) + return 1; + + /* accept certificate if its fingerprint matches, again regardless whether x509 certificate validation was successful */ if (tls_session_verify_fingerprint(ctx)) - return 1; /* success */ + { + msg_debug("Certificate accepted because its fingerprint is listed", NULL); + return 1; + } + + if (ok && ctx->error_depth != 0 && (ctx->current_cert->ex_flags & EXFLAG_CA) == 0) + { + msg_debug("Invalid certificate found in chain, basicConstraints.ca is unset in non-leaf certificate", NULL); + ctx->error = X509_V_ERR_INVALID_CA; + return 0; + } + /* reject certificate if it is valid, but its DN is not trusted */ if (ok && ctx->error_depth == 0 && !tls_session_verify_dn(ctx)) { + msg_debug("Certificate valid, but DN constraints were not met, rejecting", NULL); ctx->error = X509_V_ERR_CERT_UNTRUSTED; - return 0; /* fail */ + return 0; } - - return ok; -} - -int -tls_session_ignore_errors(int ok, X509_STORE_CTX *ctx) -{ /* if the crl_dir is set in the configuration file but the directory is empty ignore this error */ - if (ok == 0 && ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL) - return 1; - else - return ok; + if (!ok && ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL) + { + msg_notice("CRL directory is set but no CRLs found", NULL); + return 1; + } + + return ok; } int @@ -132,10 +145,8 @@ tls_session_verify_callback(int ok, X509_STORE_CTX *ctx) SSL *ssl = X509_STORE_CTX_get_app_data(ctx); TLSSession *self = SSL_get_app_data(ssl); - ok = tls_session_verify(ok, ctx); + ok = tls_session_verify(self, ok, ctx); - ok = tls_session_ignore_errors(ok, ctx); - tls_log_certificate_validation_progress(ok, ctx); if (self->verify_func) @@ -165,9 +176,6 @@ tls_session_set_verify(TLSSession *self, TLSSessionVerifyFunc verify_func, gpoin self->verify_func = verify_func; self->verify_data = verify_data; self->verify_data_destroy = verify_destroy; - - SSL_set_app_data(self->ssl, self); - SSL_set_verify(self->ssl, SSL_get_verify_mode(self->ssl), tls_session_verify_callback); } static TLSSession * @@ -212,11 +220,13 @@ TLSSession * tls_context_setup_session(TLSContext *self) { SSL *ssl; + TLSSession *session; gint ssl_error; if (!self->ssl_ctx) { gint verify_mode = 0; + gint verify_flags = X509_V_FLAG_POLICY_CHECK; if (self->mode == TM_CLIENT) self->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); @@ -240,7 +250,9 @@ tls_context_setup_session(TLSContext *self) goto error; if (self->crl_dir) - X509_VERIFY_PARAM_set_flags(self->ssl_ctx->param, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + verify_flags |= X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL; + + X509_VERIFY_PARAM_set_flags(self->ssl_ctx->param, verify_flags); switch (self->verify_mode) { @@ -254,7 +266,7 @@ tls_context_setup_session(TLSContext *self) verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; break; case TVM_REQUIRED | TVM_UNTRUSTED: - verify_mode = SSL_VERIFY_NONE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; break; case TVM_REQUIRED | TVM_TRUSTED: verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; @@ -263,7 +275,7 @@ tls_context_setup_session(TLSContext *self) g_assert_not_reached(); } - SSL_CTX_set_verify(self->ssl_ctx, verify_mode, NULL); + SSL_CTX_set_verify(self->ssl_ctx, verify_mode, tls_session_verify_callback); SSL_CTX_set_options(self->ssl_ctx, SSL_OP_NO_SSLv2); } @@ -273,7 +285,10 @@ tls_context_setup_session(TLSContext *self) SSL_set_connect_state(ssl); else SSL_set_accept_state(ssl); - return tls_session_new(ssl, self); + + session = tls_session_new(ssl, self); + SSL_set_app_data(ssl, session); + return session; error: ssl_error = ERR_get_error(); diff --git a/src/tlscontext.h b/src/tlscontext.h index ada8e18..568682d 100644 --- a/src/tlscontext.h +++ b/src/tlscontext.h @@ -7,7 +7,7 @@ #include "syslog-ng.h" -#ifdef ENABLE_SSL +#if ENABLE_SSL #include @@ -69,6 +69,9 @@ gboolean tls_verify_certificate_name(X509 *cert, const gchar *hostname); #else +typedef struct _TLSContext TLSContext; +typedef struct _TLSSession TLSSession; + #define tls_context_new(m) #endif diff --git a/src/tlstransport.c b/src/tlstransport.c index 608a427..2f07625 100644 --- a/src/tlstransport.c +++ b/src/tlstransport.c @@ -1,5 +1,7 @@ #include "tlstransport.h" +#if ENABLE_SSL + #include "messages.h" #include @@ -149,4 +151,4 @@ log_transport_tls_free_method(LogTransport *s) log_transport_free_method(s); } - +#endif diff --git a/tests/functional/func_test.py b/tests/functional/func_test.py index d7af8ff..ffd0fae 100755 --- a/tests/functional/func_test.py +++ b/tests/functional/func_test.py @@ -2,6 +2,7 @@ import os, sys, signal, traceback, time, errno from socket import * +import struct padding = 'x' * 250 session_counter = 0 @@ -39,12 +40,24 @@ class SocketSender(MessageSender): self.sock = socket(self.family, SOCK_STREAM) self.sock.connect(self.sock_name) + self.sock.setsockopt(SOL_SOCKET, SO_SNDTIMEO, struct.pack('ll', 3, 0)) + if self.dgram: + self.sock.send('') def sendMessage(self, msg): line = '%s%s' % (msg, self.terminate_seq) if self.send_by_bytes: for c in line: - self.sock.send(c) + try: + self.sock.send(c) + except error, e: + if e[0] == errno.ENOBUFS: + print 'got ENOBUFS, sleeping...' + time.sleep(0.5) + repeat = True + else: + print "hmm... got an error to the 'send' call, maybe syslog-ng is not accepting messages?" + raise else: repeat = True while repeat: @@ -59,6 +72,9 @@ class SocketSender(MessageSender): print 'got ENOBUFS, sleeping...' time.sleep(0.5) repeat = True + else: + print "hmm... got an error to the 'send' call, maybe syslog-ng is not accepting messages?" + raise def __str__(self): if self.family == AF_UNIX: diff --git a/tests/unit/test_logqueue.c b/tests/unit/test_logqueue.c index 6e9dd00..b27f08e 100644 --- a/tests/unit/test_logqueue.c +++ b/tests/unit/test_logqueue.c @@ -115,6 +115,91 @@ testcase_zero_diskbuf_alternating_send_acks() log_queue_free(q); } +#if 0 + +/* no synchronization between the feed/consume threads, therefore it does + * not succeed reliably. commented out for now, will fix at the next + * logqueue related threaded issue */ + +GStaticMutex threaded_lock = G_STATIC_MUTEX_INIT; + +gpointer +threaded_feed(gpointer st) +{ + LogQueue *q = (LogQueue *) st; + char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: árvíztűrőtükörfúrógép"; + gint i; + LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; + LogMessage *msg; + + for (i = 0; i < 100000; i++) + { + msg = log_msg_new(msg_str, strlen(msg_str), g_sockaddr_inet_new("10.10.10.10", 1010), 0, NULL, -1); + log_msg_add_ack(msg, &path_options); + msg->ack_func = test_ack; + + g_static_mutex_lock(&threaded_lock); + if (!log_queue_push_tail(q, msg, &path_options)) + { + fprintf(stderr, "Queue unable to consume enough messages: %d\n", fed_messages); + return GUINT_TO_POINTER(1); + } + g_static_mutex_unlock(&threaded_lock); + } + return NULL; +} + +gpointer +threaded_consume(gpointer st) +{ + LogQueue *q = (LogQueue *) st; + LogMessage *msg; + LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; + gboolean success; + gint i; + + for (i = 0; i < 100000; i++) + { + g_static_mutex_lock(&threaded_lock); + msg = NULL; + success = log_queue_pop_head(q, &msg, &path_options, FALSE); + g_static_mutex_unlock(&threaded_lock); + + g_assert(!success || (success && msg != NULL)); + if (!success) + { + fprintf(stderr, "Queue didn't return enough messages: i=%d\n", i); + return GUINT_TO_POINTER(1); + } + + log_msg_ack(msg, &path_options); + log_msg_unref(msg); + } + + return NULL; +} + +void +testcase_with_threads() +{ + LogQueue *q; + GThread *thread_feed, *thread_consume; + gint i; + + for (i = 0; i < 100; i++) + { + q = log_queue_new(100000, 0, 64); + thread_feed = g_thread_create(threaded_feed, q, TRUE, NULL); + + thread_consume = g_thread_create(threaded_consume, q, TRUE, NULL); + g_thread_join(thread_feed); + g_thread_join(thread_consume); + + log_queue_free(q); + } +} +#endif + int main() { diff --git a/tests/unit/test_template.c b/tests/unit/test_template.c index 675b9d6..c499d8d 100644 --- a/tests/unit/test_template.c +++ b/tests/unit/test_template.c @@ -18,9 +18,13 @@ testcase(LogMessage *msg, gchar *template, gchar *expected) { LogTemplate *templ; GString *res = g_string_sized_new(128); + static TimeZoneInfo *tzinfo = NULL; + + if (!tzinfo) + tzinfo = time_zone_info_new(NULL); templ = log_template_new("dummy", template); - log_template_format(templ, msg, LT_ESCAPE, TS_FMT_BSD, NULL, 3, 0, res); + log_template_format(templ, msg, LT_ESCAPE, TS_FMT_BSD, tzinfo, 3, 0, res); if (strcmp(res->str, expected) != 0) { @@ -39,7 +43,7 @@ int main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED) { LogMessage *msg; - char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: árvíztűrőtükörfúrógép"; + char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép"; GlobalConfig dummy; if (argc > 1) @@ -172,6 +176,14 @@ main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED) testcase(msg, "$PID", ""); log_msg_unref(msg); + msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép"; + + msg = log_msg_new(msg_str, strlen(msg_str), g_sockaddr_inet_new("10.10.10.10", 1010), LP_STORE_LEGACY_MSGHDR, NULL, -1); + + testcase(msg, "$LEGACY_MSGHDR", "syslog-ng[23323]:"); + testcase(msg, "$MSGHDR", "syslog-ng[23323]:"); + log_msg_unref(msg); + msg_str = "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog 3535 ID47 [exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] BOMAn application event log entry..."; msg = log_msg_new(msg_str, strlen(msg_str), g_sockaddr_inet_new("10.10.10.10", 1010), LP_SYSLOG_PROTOCOL, NULL, -1); diff --git a/tgz2build/rules b/tgz2build/rules index 57eb338..7f2c776 100644 --- a/tgz2build/rules +++ b/tgz2build/rules @@ -3,7 +3,7 @@ STAMPDIR=tgz2build/stamps DOCDIR=$(PREFIX)/doc -CONFIGURE_OPTS := --prefix $(ZBS_PREFIX) --enable-ssl --enable-dynamic-linking --enable-sql --enable-spoof-source --disable-tcp-wrapper --disable-pcre --with-ld-library-path=$(ZBS_PREFIX)/lib +CONFIGURE_OPTS := --prefix $(ZBS_PREFIX) --enable-ssl --enable-dynamic-linking --enable-sql --enable-spoof-source --disable-tcp-wrapper --disable-pcre --with-ld-library-path=$(ZBS_PREFIX)/lib --with-pidfile-dir=$(ZBS_PREFIX)/var/run INSTALL:=./install-sh RPATH=-Wl,-R/opt/syslog-ng/lib