summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog59
-rw-r--r--Makefile.am10
-rw-r--r--action.c15
-rw-r--r--action.h4
-rw-r--r--build/rhel/rsyslog/rsyslog.spec15
-rw-r--r--configure.ac69
-rw-r--r--dirty.h2
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/debug.html1
-rw-r--r--doc/imfile.html4
-rw-r--r--doc/imjournal.html45
-rw-r--r--doc/imrelp.html28
-rw-r--r--doc/manual.html2
-rw-r--r--doc/mmcount.html58
-rw-r--r--doc/omfile.html12
-rw-r--r--doc/omrelp.html14
-rw-r--r--doc/rsyslog_conf_global.html190
-rw-r--r--doc/rsyslog_conf_modules.html2
-rw-r--r--grammar/.gitignore1
-rw-r--r--plugins/imgssapi/imgssapi.c21
-rwxr-xr-x[-rw-r--r--]plugins/imjournal/imjournal.c153
-rw-r--r--plugins/imrelp/imrelp.c86
-rw-r--r--plugins/imuxsock/imuxsock.c4
-rw-r--r--plugins/imzmq3/README59
-rw-r--r--plugins/imzmq3/imzmq3.c781
-rw-r--r--plugins/mmaudit/Makefile.am4
-rw-r--r--plugins/mmaudit/mmaudit.c3
-rw-r--r--plugins/mmcount/Makefile.am8
-rw-r--r--plugins/mmcount/mmcount.c342
-rw-r--r--plugins/mmfields/Makefile.am8
-rw-r--r--plugins/mmfields/mmfields.c265
-rw-r--r--plugins/mmjsonparse/Makefile.am4
-rw-r--r--plugins/mmjsonparse/mmjsonparse.c1
-rw-r--r--plugins/omjournal/omjournal.c2
-rw-r--r--plugins/omrelp/omrelp.c115
-rw-r--r--plugins/omzmq3/README14
-rw-r--r--plugins/omzmq3/omzmq3.c202
-rw-r--r--runtime/Makefile.am6
-rw-r--r--runtime/conf.c18
-rw-r--r--runtime/cryprov.h17
-rw-r--r--runtime/debug.c17
-rw-r--r--runtime/glbl.c20
-rw-r--r--runtime/glbl.h2
-rw-r--r--runtime/libgcry.c350
-rw-r--r--runtime/libgcry.h24
-rw-r--r--runtime/libgcry_common.c2
-rw-r--r--runtime/librsgt.c2
-rw-r--r--runtime/librsgt_read.c4
-rw-r--r--runtime/lmcry_gcry.c86
-rw-r--r--runtime/msg.h2
-rw-r--r--runtime/queue.c133
-rw-r--r--runtime/queue.h11
-rw-r--r--runtime/ratelimit.c4
-rw-r--r--runtime/rsyslog.h4
-rw-r--r--runtime/ruleset.c6
-rw-r--r--runtime/stream.c73
-rw-r--r--runtime/stringbuf.c13
-rw-r--r--runtime/stringbuf.h2
-rw-r--r--template.c1
-rw-r--r--tools/Makefile.am4
-rw-r--r--tools/omfile.c3
-rw-r--r--tools/rsyslogd.84
-rw-r--r--tools/syslogd.c17
63 files changed, 2680 insertions, 749 deletions
diff --git a/ChangeLog b/ChangeLog
index b927d130..bfcb3f3e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,63 @@
---------------------------------------------------------------------------
+Version 7.5.0 [devel] 2013-06-11
+- imrelp: implement "ruleset" module parameter
+- imrelp/omrelp: add TLS & compression (zip) support
+- omrelp: add "rebindInterval" parameter
+- add -S command line option to specify IP address to use for RELP client
+ connections
+ Thanks to Axel Rau for the patch.
+---------------------------------------------------------------------------
+Version 7.4.1 [v7.4-stable] 2013-06-??
+- bugfix: potential loop in rate limiting
+ if the message that tells about rate-limiting gets rate-limited itself,
+ it will potentially create and endless loop
+- bugfix: potential segfault in imjournal if journal DB is corrupted
+- bugfix imzmq3: potential segfault on startup
+ if no problem happend at startup, everything went fine
+ Thanks to Hongfei Cheng and Brian Knox for the patch
+---------------------------------------------------------------------------
+Version 7.4.0 [v7.4-stable] 2013-06-06
+This starts a new stable branch based on 7.3.15 plus the following changes:
+- add --enable-cached-man-pages ./configure option
+ permits to build rsyslog on a system where rst2man is not installed. In
+ that case, cached versions of the man pages are used (they were built
+ during "make dist", so they should be current for the version in
+ question.
+- doc bugfix: ReadMode wrong in imfile doc, two values were swapped
+ Thanks to jokajak@gmail.com for mentioning this
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=450
+- imjournal: no longer do periodic wakeup
+- bugfix: potential hang *in debug mode* on rsyslogd termination
+ This ONLY affected rsyslogd if it were running with debug output
+ enabled.
+- bugfix: $template statement with multiple spaces lead to invalid tpl name
+ If multiple spaces were used in front of the template name, all but one
+ of them became actually part of the template name. So
+ $template a,"..." would be name " a", and as such "a" was not
+ available, e.g. in
+ *.* /var/log/file;a
+ This is a legacy config problem. As it was unreported for many years,
+ no backport of the fix to old versions will happen.
+ This is a long-standing bug that was only recently reported by forum
+ user mc-sim.
+ Reference: http://kb.monitorware.com/post23448.html
+- 0mq fixes; credits to Hongfei Cheng and Brian Knox
+---------------------------------------------------------------------------
+Version 7.3.15 [beta] 2013-05-15
+- bugfix: problem in build system (especially when cross-compiling)
+ Thanks to Tomas Heinrich and winfried_mb2@xmsnet.nl for the patch.
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=445
+- bugfix: imjournal had problem with systemd journal API change
+- imjournal: now obtain and include PID
+- bugfix: .logsig files had tlv16 indicator bit at wrong offset
+- bugfix: omrelp legacy config parameters set a timeout of zero
+ which lead the legacy config to be unusable.
+- bugfix: segfault on startup if a disk queue was configure without file
+ name
+ Now this triggers an error message and the queue is changed to
+ linkedList type.
+- bugfix: invalid addressing in string class (recent regression)
+---------------------------------------------------------------------------
Version 7.3.14 [beta] 2013-05-06
- bugfix: some man pages were not properly installed
either rscryutil or rsgtutil man was installed, but not both
diff --git a/Makefile.am b/Makefile.am
index ed3b54b8..f604c1cd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -241,6 +241,14 @@ if ENABLE_MMANON
SUBDIRS += plugins/mmanon
endif
+if ENABLE_MMCOUNT
+SUBDIRS += plugins/mmcount
+endif
+
+if ENABLE_MMFIELDS
+SUBDIRS += plugins/mmfields
+endif
+
if ENABLE_ORACLE
SUBDIRS += plugins/omoracle
endif
@@ -289,5 +297,5 @@ DISTCHECK_CONFIGURE_FLAGS= --enable-gssapi_krb5 \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
# temporarily disable these checks for make distcheck 2012-09-06 rgerhards
# --enable-extended-tests \
-# --enable-pgsql \
+# --enable-pgsql
ACLOCAL_AMFLAGS = -I m4
diff --git a/action.c b/action.c
index 259fb666..85766941 100644
--- a/action.c
+++ b/action.c
@@ -357,7 +357,7 @@ finalize_it:
/* action construction finalizer
*/
rsRetVal
-actionConstructFinalize(action_t *pThis, struct cnfparamvals *queueParams)
+actionConstructFinalize(action_t *pThis, struct nvlst *lst)
{
DEFiRet;
uchar pszAName[64]; /* friendly name of our action */
@@ -432,7 +432,7 @@ actionConstructFinalize(action_t *pThis, struct cnfparamvals *queueParams)
obj.SetName((obj_t*) pThis->pQueue, pszAName);
qqueueSetpAction(pThis->pQueue, pThis);
- if(queueParams == NULL) { /* use legacy params? */
+ if(lst == NULL) { /* use legacy params? */
/* ... set some properties ... */
# define setQPROP(func, directive, data) \
CHKiRet_Hdlr(func(pThis->pQueue, data)) { \
@@ -466,7 +466,7 @@ actionConstructFinalize(action_t *pThis, struct cnfparamvals *queueParams)
} else {
/* we have v6-style config params */
qqueueSetDefaultsActionQueue(pThis->pQueue);
- qqueueApplyCnfParam(pThis->pQueue, queueParams);
+ qqueueApplyCnfParam(pThis->pQueue, lst);
}
# undef setQPROP
@@ -1788,7 +1788,7 @@ actionApplyCnfParam(action_t *pAction, struct cnfparamvals *pvals)
rsRetVal
addAction(action_t **ppAction, modInfo_t *pMod, void *pModData,
omodStringRequest_t *pOMSR, struct cnfparamvals *actParams,
- struct cnfparamvals *queueParams, int bSuspended)
+ struct nvlst *lst, int bSuspended)
{
DEFiRet;
int i;
@@ -1881,7 +1881,7 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData,
if(bSuspended)
actionSuspend(pAction);
- CHKiRet(actionConstructFinalize(pAction, queueParams));
+ CHKiRet(actionConstructFinalize(pAction, lst));
/* TODO: if we exit here, we have a memory leak... */
@@ -1940,7 +1940,6 @@ rsRetVal
actionNewInst(struct nvlst *lst, action_t **ppAction)
{
struct cnfparamvals *paramvals;
- struct cnfparamvals *queueParams;
modInfo_t *pMod;
uchar *cnfModName = NULL;
omodStringRequest_t *pOMSR;
@@ -1971,9 +1970,7 @@ actionNewInst(struct nvlst *lst, action_t **ppAction)
FINALIZE; /* iRet is already set to error state */
}
- qqueueDoCnfParams(lst, &queueParams);
-
- if((iRet = addAction(&pAction, pMod, pModData, pOMSR, paramvals, queueParams,
+ if((iRet = addAction(&pAction, pMod, pModData, pOMSR, paramvals, lst,
(iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) {
/* check if the module is compatible with select features
* (currently no such features exist) */
diff --git a/action.h b/action.h
index dfafe301..54cdb54c 100644
--- a/action.h
+++ b/action.h
@@ -91,7 +91,7 @@ struct action_s {
/* function prototypes
*/
rsRetVal actionConstruct(action_t **ppThis);
-rsRetVal actionConstructFinalize(action_t *pThis, struct cnfparamvals *queueParams);
+rsRetVal actionConstructFinalize(action_t *pThis, struct nvlst *lst);
rsRetVal actionDestruct(action_t *pThis);
rsRetVal actionDbgPrint(action_t *pThis);
rsRetVal actionSetGlobalResumeInterval(int iNewVal);
@@ -99,7 +99,7 @@ rsRetVal actionDoAction(action_t *pAction);
rsRetVal actionWriteToAction(action_t *pAction, msg_t *pMsg);
rsRetVal actionCallHUPHdlr(action_t *pAction);
rsRetVal actionClassInit(void);
-rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR, struct cnfparamvals *actParams, struct cnfparamvals *queueParams, int bSuspended);
+rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR, struct cnfparamvals *actParams, struct nvlst *lst, int bSuspended);
rsRetVal activateActions(void);
rsRetVal actionNewInst(struct nvlst *lst, action_t **ppAction);
rsRetVal actionProcessCnf(struct cnfobj *o);
diff --git a/build/rhel/rsyslog/rsyslog.spec b/build/rhel/rsyslog/rsyslog.spec
index 4aa91df3..7bb367d4 100644
--- a/build/rhel/rsyslog/rsyslog.spec
+++ b/build/rhel/rsyslog/rsyslog.spec
@@ -47,6 +47,11 @@ Summary: ElasticSearch output module for rsyslog
Group: System Environment/Daemons
Requires: %name = %version-%release
+%package mmcount
+Summary: Message counting support for rsyslog
+Group: System Environment/Daemons
+Requires: %name = %version-%release
+
%package mmjsonparse
Summary: JSON enhanced logging support
Group: System Environment/Daemons
@@ -154,6 +159,11 @@ relay chains.
This module provides the capability for rsyslog to feed logs directly into
Elasticsearch.
+%description mmcount
+This module provides the capability to count log messages by severity
+or json property of given app-name. The count value is added into the
+log message in json property named 'mmcount'
+
%description mmjsonparse
This module provides the capability to recognize and parse JSON enhanced
syslog messages.
@@ -226,6 +236,7 @@ export PKG_CONFIG=/usr/bin/pkg-config
%configure --disable-static \
--disable-testbench \
--enable-elasticsearch \
+ --enable-mmcount \
--enable-mmjsonparse \
--enable-mmnormalize \
--enable-imzmq3 \
@@ -339,6 +350,10 @@ fi
%defattr(-,root,root)
%{_libdir}/rsyslog/omelasticsearch.so
+%files mmcount
+%defattr(-,root,root)
+%{_libdir}/rsyslog/mmcount.so
+
%files mmjsonparse
%defattr(-,root,root)
%{_libdir}/rsyslog/mmjsonparse.so
diff --git a/configure.ac b/configure.ac
index e18a0a72..53900b61 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
-AC_INIT([rsyslog],[7.3.14],[rsyslog@lists.adiscon.com])
+AC_INIT([rsyslog],[7.5.0],[rsyslog@lists.adiscon.com])
AM_INIT_AUTOMAKE
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -28,13 +28,11 @@ fi
AC_DISABLE_STATIC
AC_PROG_LIBTOOL
AC_CANONICAL_HOST
-AC_PATH_PROG([RST2MAN], [rst2man])
PKG_PROG_PKG_CONFIG
# modules we require
PKG_CHECK_MODULES(LIBESTR, libestr >= 0.1.5)
-PKG_CHECK_MODULES(LIBEE, libee >= 0.4.0)
PKG_CHECK_MODULES([JSON_C], [json])
case "${host}" in
@@ -919,6 +917,7 @@ AC_ARG_ENABLE(mmnormalize,
[enable_mmnormalize=no]
)
if test "x$enable_mmnormalize" = "xyes"; then
+ PKG_CHECK_MODULES(LIBEE, libee >= 0.4.0)
PKG_CHECK_MODULES(LIBLOGNORM, lognorm >= 0.3.1)
fi
AM_CONDITIONAL(ENABLE_MMNORMALIZE, test x$enable_mmnormalize = xyes)
@@ -934,9 +933,6 @@ AC_ARG_ENABLE(mmjsonparse,
esac],
[enable_mmjsonparse=no]
)
-if test "x$enable_mmjsonparse" = "xyes"; then
- PKG_CHECK_MODULES(LIBLOGNORM, lognorm >= 0.3.1)
-fi
AM_CONDITIONAL(ENABLE_MMJSONPARSE, test x$enable_mmjsonparse = xyes)
@@ -950,9 +946,6 @@ AC_ARG_ENABLE(mmaudit,
esac],
[enable_mmaudit=no]
)
-if test "x$enable_mmaudit" = "xyes"; then
- PKG_CHECK_MODULES(LIBLOGNORM, lognorm >= 0.3.1)
-fi
AM_CONDITIONAL(ENABLE_MMAUDIT, test x$enable_mmaudit = xyes)
@@ -969,6 +962,32 @@ AC_ARG_ENABLE(mmanon,
AM_CONDITIONAL(ENABLE_MMANON, test x$enable_mmanon = xyes)
+# mmcount
+AC_ARG_ENABLE(mmcount,
+ [AS_HELP_STRING([--enable-mmcount],[Enable message counting @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_xmpp="yes" ;;
+ no) enable_xmpp="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-mmcount) ;;
+ esac],
+ [enable_mmcount=no]
+)
+AM_CONDITIONAL(ENABLE_MMCOUNT, test x$enable_mmcount = xyes)
+
+
+# mmfields
+AC_ARG_ENABLE(mmfields,
+ [AS_HELP_STRING([--enable-mmfields],[Enable building mmfields support @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_mmfields="yes" ;;
+ no) enable_mmfields="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-mmfields) ;;
+ esac],
+ [enable_mmfields=no]
+)
+AM_CONDITIONAL(ENABLE_MMFIELDS, test x$enable_mmfields = xyes)
+
+
# RELP support
AC_ARG_ENABLE(relp,
[AS_HELP_STRING([--enable-relp],[Enable RELP support @<:@default=no@:>@])],
@@ -980,7 +999,7 @@ AC_ARG_ENABLE(relp,
[enable_relp=no]
)
if test "x$enable_relp" = "xyes"; then
- PKG_CHECK_MODULES(RELP, relp >= 1.0.3)
+ PKG_CHECK_MODULES(RELP, relp >= 1.1.1)
fi
AM_CONDITIONAL(ENABLE_RELP, test x$enable_relp = xyes)
@@ -1000,6 +1019,31 @@ if test "x$enable_guardtime" = "xyes"; then
fi
AM_CONDITIONAL(ENABLE_GUARDTIME, test x$enable_guardtime = xyes)
+
+# Support using cached man file copies, to avoid the need for rst2man
+# in the build environment
+AC_ARG_ENABLE(cached_man_pages,
+ [AS_HELP_STRING([--enable-cached-man-pages],[Enable using cached versions of man files (avoid rst2man) @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_cached_man_pages="yes" ;;
+ no) enable_cached_man_pages="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-cached-man-pages) ;;
+ esac],
+ [enable_cached_man_pages=no]
+)
+if test "x$enable_cached_man_pages" = "xno"; then
+# obtain path for rst2man
+ if test "x$enable_libgcrypt" = "xyes" || \
+ "x$enable_guardtime" = "xyes"; then
+ AC_PATH_PROG([RST2MAN], [rst2man])
+ if test "x${RST2MAN}" == "x"; then
+ AC_MSG_FAILURE([rst2man not found in PATH])
+ fi
+ fi
+fi
+
+
+
# RFC 3195 support
AC_ARG_ENABLE(rfc3195,
[AS_HELP_STRING([--enable-rfc3195],[Enable RFC3195 support @<:@default=no@:>@])],
@@ -1460,6 +1504,8 @@ AC_CONFIG_FILES([Makefile \
plugins/mmjsonparse/Makefile \
plugins/mmaudit/Makefile \
plugins/mmanon/Makefile \
+ plugins/mmcount/Makefile \
+ plugins/mmfields/Makefile \
plugins/omelasticsearch/Makefile \
plugins/sm_cust_bindcdr/Makefile \
plugins/mmsnmptrapd/Makefile \
@@ -1477,11 +1523,14 @@ echo " Zlib compression support enabled: $enable_zlib"
echo " rsyslog runtime will be built: $enable_rsyslogrt"
echo " rsyslogd will be built: $enable_rsyslogd"
echo " GUI components will be built: $enable_gui"
+echo " cached man files will be used: $enable_cached_man_pages"
echo " Unlimited select() support enabled: $enable_unlimited_select"
echo " uuid support enabled: $enable_uuid"
echo " Log file signing support: $enable_guardtime"
echo " Log file encryption support: $enable_libgcrypt"
echo " anonymization support enabled: $enable_mmanon"
+echo " message counting support enabled: $enable_mmcount"
+echo " mmfields enabled: $enable_mmfields"
echo
echo "---{ input plugins }---"
echo " Klog functionality enabled: $enable_klog ($os_type)"
diff --git a/dirty.h b/dirty.h
index 4db2e3ce..e0a6e26e 100644
--- a/dirty.h
+++ b/dirty.h
@@ -35,7 +35,7 @@ rsRetVal multiSubmitFlush(multi_submit_t *pMultiSub);
rsRetVal logmsgInternal(int iErr, int pri, uchar *msg, int flags);
rsRetVal __attribute__((deprecated)) parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlTypeu, prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime, ruleset_t *pRuleset);
rsRetVal diagGetMainMsgQSize(int *piSize); /* for imdiag */
-rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName, struct cnfparamvals *queueParams);
+rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName, struct nvlst *lst);
extern int MarkInterval;
extern qqueue_t *pMsgQueue; /* the main message queue */
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 46afd900..e1757644 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -35,6 +35,7 @@ html_files = \
omfwd.html \
omfile.html \
omjournal.html \
+ imjournal.html \
mmanon.html \
omusrmsg.html \
omstdout.html \
diff --git a/doc/debug.html b/doc/debug.html
index 996bf5c8..557ca6d3 100644
--- a/doc/debug.html
+++ b/doc/debug.html
@@ -56,6 +56,7 @@ only available under Linux. This usually does NOT work when privileges have
been dropped (that's not a bug, but the way it is).
<li><b>help</b> - display a very short list of commands - hopefully a life saver if you can't access the documentation...</li>
</ul>
+<p>Individual options are separated by spaces.</p>
</ul>
<h3>Why Environment Variables?</h3>
<p>You may ask why we use environment variables for debug-system parameters and not
diff --git a/doc/imfile.html b/doc/imfile.html
index f37f7055..274d6e60 100644
--- a/doc/imfile.html
+++ b/doc/imfile.html
@@ -104,8 +104,8 @@ file is very time consuming.
<li><b>ReadMode</b> [mode]</b><br>
This mode should defined when having multiline messages. The value can range from 0-2 and determines the multiline detection method.
<br>0 (default) - line based (Each line is a new message)
-<br>1 - indented (New log messages start at the beginning of a line. If a line starts with a space it is part of the log message before it)
-<br>2 - paragraph (There is a blank line between log messages)
+<br>1 - paragraph (There is a blank line between log messages)
+<br>2 - indented (New log messages start at the beginning of a line. If a line starts with a space it is part of the log message before it)
<li><b>MaxLinesAtOnce</b> [number]</b>
<br>
This is useful if multiple files need to be monitored. If set to 0, each file
diff --git a/doc/imjournal.html b/doc/imjournal.html
new file mode 100644
index 00000000..e3f64502
--- /dev/null
+++ b/doc/imjournal.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head>
+<meta http-equiv="Content-Language" content="en"><title>Text File Input Monitor</title></head>
+<body>
+<a href="rsyslog_conf_modules.html">back</a>
+
+<h1>Systemd Journal Input Module</h1>
+<p><b>Module Name:&nbsp;&nbsp;&nbsp; imjournal</b></p>
+<p><b>Author: </b>Milan Bartos
+&lt;mbartos@redhat.com&gt;</p>
+<p><b>Description</b>:</p>
+<p>Provides the ability to import structured log messages from systemd journal
+to syslog.</p>
+
+<p><b>Configuration Directives</b>:</p>
+<p><b>Module Directives</b></p>
+<ul>
+<li><span style="font-weight: bold;">PersistStateInterval
+messages</span><br>
+This is a global setting. It specifies how often should the journal state be persisted.
+This option is useful for rsyslog to start reding from the last journal message it read.
+
+<li><span style="font-weight: bold;">StateFile
+/path/to/file</span><br>
+This is a global setting. It specifies where the state file for persisting
+journal state is located.
+</ul>
+<b>Caveats/Known Bugs:</b>
+<p>
+</p>
+<p><b>Sample:</b></p>
+<p>
+The following example shows pulling structured imjournal messages and saving them into /var/log/ceelog
+</p>
+<textarea rows="15" cols="60">
+module(load="imjournal" PersistStateInterval="100" StateFile="/path/to/file") #load imjournal module
+module(load="mmjsonparse") #load mmjsonparse module for structured logs
+
+$template CEETemplate,"%TIMESTAMP% %HOSTNAME% %syslogtag% @cee: %$!all-json%\n" #template for messages
+
+*.* :mmjsonparse:
+*.* /var/log/ceelog;CEETemplate
+</textarea>
+</body>
+</html>
diff --git a/doc/imrelp.html b/doc/imrelp.html
index 9f3e4875..11894668 100644
--- a/doc/imrelp.html
+++ b/doc/imrelp.html
@@ -28,12 +28,27 @@ nits outlined above, is a much more reliable solution than plain tcp
syslog and so it is highly suggested to use RELP instead of plain tcp.
Clients send messages to the RELP server via omrelp.</p>
-<p><b>Configuration Directives</b>:</p>
+<p><b>Module Parameters</b>:</p>
+<ul>
+ <li><b>Ruleset</b> &lt;name&gt;</br>
+ Binds the specified ruleset to <b>all</b> RELP listeners.
+</ul>
+<p><b>Input Parameters</b>:</p>
<ul>
-<li><b>Ruleset</b> &lt;name&gt;</br>
-Binds the specified ruleset to all RELP listeners.
<li><b>Port</b> &lt;port&gt;<br>
Starts a RELP server on selected port</li>
+<li><b>tls</b> (not mandatory, values "on","off", default "off")<br>
+If set to "on", the RELP connection will be encrypted by TLS,
+so that the data is protected against observers. Please note
+that both the client and the server must have set TLS to
+either "on" or "off". Other combinations lead to unpredictable
+results.
+</li>
+<li><b>tls.compression</b> (not mandatory, values "on","off", default "off")<br>
+The controls if the TLS stream should be compressed (zipped). While this
+increases CPU use, the network bandwidth should be reduced. Note that
+typical text-based log records usually compress rather well.
+</li>
</ul>
<b>Caveats/Known Bugs:</b>
<ul>
@@ -47,7 +62,7 @@ not specific ones. This is due to a currently existing limitation in librelp.
<p><b>Sample:</b></p>
<p>This sets up a RELP server on port 20514.<br>
</p>
-<textarea rows="15" cols="60">module(load="imrelp") # needs to be done just once
+<textarea rows="5" cols="60">module(load="imrelp") # needs to be done just once
input(type="imrelp" port="20514")
</textarea>
@@ -60,7 +75,6 @@ equivalent to: Port</li>
</ul>
<b>Caveats/Known Bugs:</b>
<ul>
-<li>see description</li>
<li>To obtain the remote system's IP address, you need to have at least
librelp 1.0.0 installed. Versions below it return the hostname instead
of the IP address.</li>
@@ -70,14 +84,14 @@ not specific ones. This is due to a currently existing limitation in librelp.
<p><b>Sample:</b></p>
<p>This sets up a RELP server on port 20514.<br>
</p>
-<textarea rows="15" cols="60">$ModLoad imrelp # needs to be done just once
+<textarea rows="5" cols="60">$ModLoad imrelp # needs to be done just once
$InputRELPServerRun 20514
</textarea>
<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
<p><font size="2">This documentation is part of the
<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
-Copyright &copy; 2008-2011 by <a href="http://www.gerhards.net/rainer">Rainer
+Copyright &copy; 2008-2013 by <a href="http://www.gerhards.net/rainer">Rainer
Gerhards</a> and
<a href="http://www.adiscon.com/">Adiscon</a>.
Released under the GNU GPL version 3 or higher.</font></p>
diff --git a/doc/manual.html b/doc/manual.html
index 5a74c8c4..8cb519a5 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -19,7 +19,7 @@ professional services</a> available directly from the source!</p>
<p><b>Please visit the <a href="http://www.rsyslog.com/sponsors">rsyslog sponsor's page</a>
to honor the project sponsors or become one yourself!</b> We are very grateful for any help towards the
project goals.</p>
-<p><b>This documentation is for version 7.3.14 (beta branch) of rsyslog.</b>
+<p><b>This documentation is for version 7.5.0 (devel branch) of rsyslog.</b>
Visit the <i><a href="http://www.rsyslog.com/status">rsyslog status page</a></i></b>
to obtain current version information and project status.
</p><p><b>If you like rsyslog, you might
diff --git a/doc/mmcount.html b/doc/mmcount.html
new file mode 100644
index 00000000..1d06340d
--- /dev/null
+++ b/doc/mmcount.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head>
+<meta http-equiv="Content-Language" content="en">
+<title>mmcount</title></head>
+
+<body>
+<a href="rsyslog_conf_modules.html">back</a>
+
+<h1>mmcount</h1>
+<p><b>Module Name:&nbsp;&nbsp;&nbsp; mmcount</b></p>
+<p><b>Author: </b>Bala.FA &lt;barumuga@redhat.com&gt;</p>
+<p><b>Status: </b>Non project-supported module - contact author
+or rsyslog mailing list for questions
+<p><b>Available since</b>: 7.5.0</p>
+<p><b>Description</b>:</p>
+<p>
+<pre>
+ mmcount: message modification plugin which counts messages
+
+ This module provides the capability to count log messages by severity
+ or json property of given app-name. The count value is added into the
+ log message as json property named 'mmcount'
+
+ Example usage of the module in the configuration file
+
+ module(load="mmcount")
+
+ # count each severity of appname gluster
+ action(type="mmcount" appname="gluster")
+
+ # count each value of gf_code of appname gluster
+ action(type="mmcount" appname="glusterd" key="!gf_code")
+
+ # count value 9999 of gf_code of appname gluster
+ action(type="mmcount" appname="glusterfsd" key="!gf_code" value="9999")
+
+ # send email for every 50th mmcount
+ if $app-name == 'glusterfsd' and $!mmcount <> 0 and $!mmcount % 50 == 0 then {
+ $ActionMailSMTPServer smtp.example.com
+ $ActionMailFrom rsyslog@example.com
+ $ActionMailTo glusteradmin@example.com
+ $template mailSubject,"50th message of gf_code=9999 on %hostname%"
+ $template mailBody,"RSYSLOG Alert\r\nmsg='%msg%'"
+ $ActionMailSubject mailSubject
+ $ActionExecOnlyOnceEveryInterval 30
+ :ommail:;RSYSLOG_SyslogProtocol23Format
+ }
+</pre>
+
+<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>] [<a href="manual.html">manual
+index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
+<p><font size="2">This documentation is part of the
+<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
+Copyright &copy; 2008-2013 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+<a href="http://www.adiscon.com/">Adiscon</a>. Released under the GNU GPL
+version 3 or higher.</font></p>
+
+</body></html>
diff --git a/doc/omfile.html b/doc/omfile.html
index 3966ab13..a5c3bb3b 100644
--- a/doc/omfile.html
+++ b/doc/omfile.html
@@ -57,10 +57,10 @@
Set the group for directories newly created. Please note that this setting does not affect the group of directories already existing. The parameter is a group name, for which the groupid is obtained by rsyslogd on during startup processing. Interim changes to the user mapping are not detected.<br></li><br>
<li><strong>FileOwner </strong><br>
- Set the file owner for dynaFiles newly created. Please note that this setting does not affect the owner of files already existing. The parameter is a user name, for which the userid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.<br></li><br>
+ Set the file owner for files newly created. Please note that this setting does not affect the owner of files already existing. The parameter is a user name, for which the userid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.<br></li><br>
<li><strong>FileGroup </strong><br>
- Set the group for dynaFiles newly created. Please note that this setting does not affect the group of files already existing. The parameter is a group name, for which the groupid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.<br></li><br>
+ Set the group for files newly created. Please note that this setting does not affect the group of files already existing. The parameter is a group name, for which the groupid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.<br></li><br>
<li><strong>DirCreateMode </strong>[defaul 0700]<br>
This is the same as $FileCreateMode, but for directories automatically generated.<br></li><br>
@@ -69,7 +69,7 @@
The FileCreateMode directive allows to specify the creation mode with which rsyslogd creates new files. If not specified, the value 0644 is used (which retains backward-compatibility with earlier releases). The value given must always be a 4-digit octal number, with the initial digit being zero. <br>Please note that the actual permission depend on rsyslogd's process umask. If in doubt, use "$umask 0000" right at the beginning of the configuration file to remove any restrictions. <br>FileCreateMode may be specified multiple times. If so, it specifies the creation mode for all selector lines that follow until the next $FileCreateMode directive. Order of lines is vitally important.<br></li><br>
<li><strong>FailOnCHOwnFailure </strong>on/off [default on]<br>
- This option modifies behaviour of dynaFile creation. If different owners or groups are specified for new files or directories and rsyslogd fails to set these new owners or groups, it will log an error and NOT write to the file in question if that option is set to "on". If it is set to "off", the error will be ignored and processing continues. Keep in mind, that the files in this case may be (in)accessible by people who should not have permission. The default is "on".<br></li><br>
+ This option modifies behaviour of file creation. If different owners or groups are specified for new files or directories and rsyslogd fails to set these new owners or groups, it will log an error and NOT write to the file in question if that option is set to "on". If it is set to "off", the error will be ignored and processing continues. Keep in mind, that the files in this case may be (in)accessible by people who should not have permission. The default is "on".<br></li><br>
<li><strong>CreateDirs </strong>on/off [default on]<br>
create directories on an as-needed basis<br></li><br>
@@ -136,10 +136,10 @@ File="/var/log/messages")
Set the group for directories newly created. Please note that this setting does not affect the group of directories already existing. The parameter is a group name, for which the groupid is obtained by rsyslogd on during startup processing. Interim changes to the user mapping are not detected.<br></li><br>
<li><strong>$FileOwner </strong><br>
- Set the file owner for dynaFiles newly created. Please note that this setting does not affect the owner of files already existing. The parameter is a user name, for which the userid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.<br></li><br>
+ Set the file owner for files newly created. Please note that this setting does not affect the owner of files already existing. The parameter is a user name, for which the userid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.<br></li><br>
<li><strong>$FileGroup </strong><br>
- Set the group for dynaFiles newly created. Please note that this setting does not affect the group of files already existing. The parameter is a group name, for which the groupid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.<br></li><br>
+ Set the group for files newly created. Please note that this setting does not affect the group of files already existing. The parameter is a group name, for which the groupid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.<br></li><br>
<li><strong>$DirCreateMode </strong>[defaul 0700]<br>
This is the same as $FileCreateMode, but for directories automatically generated.<br></li><br>
@@ -148,7 +148,7 @@ File="/var/log/messages")
The FileCreateMode directive allows to specify the creation mode with which rsyslogd creates new files. If not specified, the value 0644 is used (which retains backward-compatibility with earlier releases). The value given must always be a 4-digit octal number, with the initial digit being zero. <br>Please note that the actual permission depend on rsyslogd's process umask. If in doubt, use "$umask 0000" right at the beginning of the configuration file to remove any restrictions. <br>FileCreateMode may be specified multiple times. If so, it specifies the creation mode for all selector lines that follow until the next $FileCreateMode directive. Order of lines is vitally important.<br></li><br>
<li><strong>$FailOnCHOwnFailure </strong>on/off [default on]<br>
- This option modifies behaviour of dynaFile creation. If different owners or groups are specified for new files or directories and rsyslogd fails to set these new owners or groups, it will log an error and NOT write to the file in question if that option is set to "on". If it is set to "off", the error will be ignored and processing continues. Keep in mind, that the files in this case may be (in)accessible by people who should not have permission. The default is "on".<br></li><br>
+ This option modifies behaviour of file creation. If different owners or groups are specified for new files or directories and rsyslogd fails to set these new owners or groups, it will log an error and NOT write to the file in question if that option is set to "on". If it is set to "off", the error will be ignored and processing continues. Keep in mind, that the files in this case may be (in)accessible by people who should not have permission. The default is "on".<br></li><br>
<li><strong>$F$OMFileForceCHOwn </strong><br>
force ownership change for all files<br></li><br>
diff --git a/doc/omrelp.html b/doc/omrelp.html
index 8858f884..39f253bd 100644
--- a/doc/omrelp.html
+++ b/doc/omrelp.html
@@ -24,16 +24,24 @@ implementation).</p>
rsyslog 7.3.10. For older versions, legacy configuration directives
must be used.
<ul>
- <li><b>target </b>(mandatory)<br>
+ <li><b>target</b> (mandatory)<br>
The target server to connect to.
</li>
- <li><b>template </b>(not mandatory, default "RSYSLOG_ForwardFormat")<br>
+ <li><b>template</b> (not mandatory, default "RSYSLOG_ForwardFormat")<br>
Defines the template to be used for the output.
</li>
- <li><b>timeout </b>(not mandatory, default 90)<br>
+ <li><b>timeout</b> (not mandatory, default 90)<br>
Timeout for relp sessions. If set too low, valid sessions
may be considered dead and tried to recover.
</li>
+ <li><b>tls</b> (not mandatory, values "on","off", default "off")<br>
+ If set to "on", the RELP connection will be encrypted by TLS, so that the data is protected against observers. Please note that both the client and the server must have set TLS to either "on" or "off". Other combinations lead to unpredictable results.
+ </li>
+ <li><b>tls.compression</b> (not mandatory, values "on","off", default "off")<br>
+ The controls if the TLS stream should be compressed (zipped). While this
+ increases CPU use, the network bandwidth should be reduced. Note that
+ typical text-based log records usually compress rather well.
+ </li>
</ul>
<p><b>Sample:</b></p>
<p>The following sample sends all messages to the central server
diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html
index 651808f6..e48ed6d3 100644
--- a/doc/rsyslog_conf_global.html
+++ b/doc/rsyslog_conf_global.html
@@ -17,12 +17,12 @@ appear as implementation progresses.
many parameter settings modify queue parameters. If in doubt, use the
default, it is usually well-chosen and applicable in most cases.</p>
<ul>
-<li><a href="rsconf1_abortonuncleanconfig.html">$AbortOnUncleanConfig</a> - abort startup if there is
+<li><a href="rsconf1_abortonuncleanconfig.html"><b>$AbortOnUncleanConfig</b></a> - abort startup if there is
any issue with the config file</li>
<li><a href="rsconf1_actionexeconlywhenpreviousissuspended.html">$ActionExecOnlyWhenPreviousIsSuspended</a></li>
-<li>$ActionName &lt;a_single_word&gt; - used primarily for documentation, e.g. when
+<li><b>$ActionName</b> &lt;a_single_word&gt; - used primarily for documentation, e.g. when
generating a configuration graph. Available sice 4.3.1.
-<li>$ActionExecOnlyOnceEveryInterval &lt;seconds&gt; -
+<li><b>$ActionExecOnlyOnceEveryInterval</b> &lt;seconds&gt; -
execute action only if the last execute is at last
&lt;seconds&gt; seconds in the past (more info in <a href="ommail.html">ommail</a>,
but may be used with any action)</li>
@@ -46,60 +46,60 @@ The question is if this is desired behavior? Or should the rule only be
triggered if the messages occur within an e.g. 20 minute window? If the
later is the case, you need a
<br>
-$ActionExecOnlyEveryNthTimeTimeout 1200
+<b>$ActionExecOnlyEveryNthTimeTimeout 1200</b>
<br>
This directive will timeout previous messages seen if they are older
than 20 minutes. In the example above, the count would now be always 1
and consequently no rule would ever be triggered.
-<li><a href="omfile.html">$ActionFileDefaultTemplate</a> [templateName] - sets a new default template for file actions</li>
-<li><a href="omfile.html">$ActionFileEnableSync</a> [on/<span style="font-weight: bold;">off</span>] - enables file
+<li><a href="omfile.html"><b>$ActionFileDefaultTemplate</b></a> [templateName] - sets a new default template for file actions</li>
+<li><a href="omfile.html"><b>$ActionFileEnableSync</b></a> [on/<span style="font-weight: bold;">off</span>] - enables file
syncing capability of omfile</li>
-<li><a href="omfwd.html">$ActionForwardDefaultTemplate</a> [templateName] - sets a new
+<li><a href="omfwd.html"><b>$ActionForwardDefaultTemplate</b></a> [templateName] - sets a new
default template for UDP and plain TCP forwarding action</li>
-<li>$ActionGSSForwardDefaultTemplate [templateName] - sets a
+<li><b>$ActionGSSForwardDefaultTemplate</b> [templateName] - sets a
new default template for GSS-API forwarding action</li>
-<li>$ActionQueueCheckpointInterval &lt;number&gt;</li>
-<li>$ActionQueueDequeueBatchSize &lt;number&gt; [default 16]</li>
-<li>$ActionQueueDequeueSlowdown &lt;number&gt; [number
+<li><b>$ActionQueueCheckpointInterval</b> &lt;number&gt;</li>
+<li><b>$ActionQueueDequeueBatchSize</b> &lt;number&gt; [default 16]</li>
+<li><b>$ActionQueueDequeueSlowdown</b> &lt;number&gt; [number
is timeout in <i> micro</i>seconds (1000000us is 1sec!),
default 0 (no delay). Simple rate-limiting!]</li>
-<li>$ActionQueueDiscardMark &lt;number&gt; [default
+<li><b>$ActionQueueDiscardMark</b> &lt;number&gt; [default
9750]</li>
-<li>$ActionQueueDiscardSeverity &lt;number&gt;
+<li><b>$ActionQueueDiscardSeverity</b> &lt;number&gt;
[*numerical* severity! default 8 (nothing discarded)]</li>
-<li>$ActionQueueFileName &lt;name&gt;</li>
-<li>$ActionQueueHighWaterMark &lt;number&gt; [default
+<li><b>$ActionQueueFileName</b> &lt;name&gt;</li>
+<li><b>$ActionQueueHighWaterMark</b> &lt;number&gt; [default
8000]</li>
-<li>$ActionQueueImmediateShutdown [on/<b>off</b>]</li>
-<li>$ActionQueueSize &lt;number&gt;</li>
-<li>$ActionQueueLowWaterMark &lt;number&gt; [default
+<li><b>$ActionQueueImmediateShutdown</b> [on/<b>off</b>]</li>
+<li><b>$ActionQueueSize</b> &lt;number&gt;</li>
+<li><b>$ActionQueueLowWaterMark</b> &lt;number&gt; [default
2000]</li>
-<li>$ActionQueueMaxFileSize &lt;size_nbr&gt;, default 1m</li>
-<li>$ActionQueueTimeoutActionCompletion &lt;number&gt;
+<li><b>$ActionQueueMaxFileSize</b> &lt;size_nbr&gt;, default 1m</li>
+<li><b>$ActionQueueTimeoutActionCompletion</b> &lt;number&gt;
[number is timeout in ms (1000ms is 1sec!), default 1000, 0 means
immediate!]</li>
-<li>$ActionQueueTimeoutEnqueue &lt;number&gt; [number
+<li><b>$ActionQueueTimeoutEnqueue</b> &lt;number&gt; [number
is timeout in ms (1000ms is 1sec!), default 2000, 0 means indefinite]</li>
-<li>$ActionQueueTimeoutShutdown &lt;number&gt; [number
+<li><b>$ActionQueueTimeoutShutdown</b> &lt;number&gt; [number
is timeout in ms (1000ms is 1sec!), default 0 (indefinite)]</li>
-<li>$ActionQueueWorkerTimeoutThreadShutdown
+<li><b>$ActionQueueWorkerTimeoutThreadShutdown</b>
&lt;number&gt; [number is timeout in ms (1000ms is 1sec!),
default 60000 (1 minute)]</li>
-<li>$ActionQueueType [FixedArray/LinkedList/<b>Direct</b>/Disk]</li>
-<li>$ActionQueueSaveOnShutdown&nbsp; [on/<b>off</b>]
+<li><b>$ActionQueueType</b> [FixedArray/LinkedList/<b>Direct</b>/Disk]</li>
+<li><b>$ActionQueueSaveOnShutdown&nbsp;</b> [on/<b>off</b>]
</li>
-<li>$ActionQueueWorkerThreads &lt;number&gt;, num worker threads, default 1, recommended 1</li>
-<li>$ActionQueueWorkerThreadMinumumMessages &lt;number&gt;, default 100</li>
-<li><a href="rsconf1_actionresumeinterval.html">$ActionResumeInterval</a></li>
-<li>$ActionResumeRetryCount &lt;number&gt; [default 0, -1 means eternal]</li>
-<li><a href="omfwd.html">$ActionSendResendLastMsgOnReconnect</a> &lt;[on/<b>off</b>]&gt; specifies if the last message is to be resend when a connecition breaks and has been reconnected. May increase reliability, but comes at the risk of message duplication.
-<li><a href="omfwd.html">$ActionSendStreamDriver</a> &lt;driver basename&gt; just like $DefaultNetstreamDriver, but for the specific action</li>
-<li><a href="omfwd.html">$ActionSendStreamDriverMode</a> &lt;mode&gt;, default 0, mode to use with the stream driver (driver-specific)</li>
-<li><a href="omfwd.html">$ActionSendStreamDriverAuthMode</a> &lt;mode&gt;,&nbsp; authentication mode to use with the stream driver. Note that this directive requires TLS
+<li><b>$ActionQueueWorkerThreads</b> &lt;number&gt;, num worker threads, default 1, recommended 1</li>
+<li><b>$ActionQueueWorkerThreadMinumumMessages</b> &lt;number&gt;, default 100</li>
+<li><a href="rsconf1_actionresumeinterval.html"><b>$ActionResumeInterval</b></a></li>
+<li><b>$ActionResumeRetryCount</b> &lt;number&gt; [default 0, -1 means eternal]</li>
+<li><a href="omfwd.html"><b>$ActionSendResendLastMsgOnReconnect</b></a> &lt;[on/<b>off</b>]&gt; specifies if the last message is to be resend when a connecition breaks and has been reconnected. May increase reliability, but comes at the risk of message duplication.
+<li><a href="omfwd.html"><b>$ActionSendStreamDriver</b></a> &lt;driver basename&gt; just like $DefaultNetstreamDriver, but for the specific action</li>
+<li><a href="omfwd.html"><b>$ActionSendStreamDriverMode</b></a> &lt;mode&gt;, default 0, mode to use with the stream driver (driver-specific)</li>
+<li><a href="omfwd.html"><b>$ActionSendStreamDriverAuthMode</b></a> &lt;mode&gt;,&nbsp; authentication mode to use with the stream driver. Note that this directive requires TLS
netstream drivers. For all others, it will be ignored.
(driver-specific)</li>
-<li><a href="omfwd.html">$ActionSendStreamDriverPermittedPeer</a> &lt;ID&gt;,&nbsp; accepted fingerprint (SHA1) or name of remote peer. Note that this directive requires TLS
+<li><a href="omfwd.html"><b>$ActionSendStreamDriverPermittedPeer</b></a> &lt;ID&gt;,&nbsp; accepted fingerprint (SHA1) or name of remote peer. Note that this directive requires TLS
netstream drivers. For all others, it will be ignored.
(driver-specific) -<span style="font-weight: bold;"> directive may go away</span>!</li>
<li><a href="omfwd.html"><b>$ActionSendTCPRebindInterval</b> nbr</a>- [available since 4.5.1] - instructs the TCP send
@@ -120,40 +120,40 @@ heartbeat. Note that this option auto-resets to &quot;off&quot;, so if you inten
actions, it must be specified in front off <b>all</b> selector lines that should provide this
functionality.
</li>
-<li><a href="rsconf1_allowedsender.html">$AllowedSender</a></li>
-<li><a href="rsconf1_controlcharacterescapeprefix.html">$ControlCharacterEscapePrefix</a></li>
-<li><a href="rsconf1_debugprintcfsyslinehandlerlist.html">$DebugPrintCFSyslineHandlerList</a></li>
+<li><a href="rsconf1_allowedsender.html"><b>$AllowedSender</b></a></li>
+<li><a href="rsconf1_controlcharacterescapeprefix.html"><b>$ControlCharacterEscapePrefix</b></a></li>
+<li><a href="rsconf1_debugprintcfsyslinehandlerlist.html"><b>$DebugPrintCFSyslineHandlerList</b></a></li>
-<li><a href="rsconf1_debugprintmodulelist.html">$DebugPrintModuleList</a></li>
-<li><a href="rsconf1_debugprinttemplatelist.html">$DebugPrintTemplateList</a></li>
-<li>$DefaultNetstreamDriver &lt;drivername&gt;, the default <a href="netstream.html">network stream driver</a> to use. Defaults to&nbsp;ptcp.$DefaultNetstreamDriverCAFile &lt;/path/to/cafile.pem&gt;</li>
-<li>$DefaultNetstreamDriverCertFile &lt;/path/to/certfile.pem&gt;</li>
-<li>$DefaultNetstreamDriverKeyFile &lt;/path/to/keyfile.pem&gt;</li>
+<li><a href="rsconf1_debugprintmodulelist.html"><b>$DebugPrintModuleList</b></a></li>
+<li><a href="rsconf1_debugprinttemplatelist.html"><b>$DebugPrintTemplateList</b></a></li>
+<li><b>$DefaultNetstreamDriver</b> &lt;drivername&gt;, the default <a href="netstream.html">network stream driver</a> to use. Defaults to&nbsp;ptcp.$DefaultNetstreamDriverCAFile &lt;/path/to/cafile.pem&gt;</li>
+<li><b>$DefaultNetstreamDriverCertFile</b> &lt;/path/to/certfile.pem&gt;</li>
+<li><b>$DefaultNetstreamDriverKeyFile</b> &lt;/path/to/keyfile.pem&gt;</li>
<li><b>$DefaultRuleset</b> <i>name</i> - changes the default ruleset for unbound inputs to
the provided <i>name</i> (the default default ruleset is named
&quot;RSYSLOG_DefaultRuleset&quot;). It is advised to also read
our paper on <a href="multi_ruleset.html">using multiple rule sets in rsyslog</a>.</li>
<li><a href="omfile.html"><b>$CreateDirs</b></a> [<b>on</b>/off] - create directories on an as-needed basis</li>
-<li><a href="omfile.html">$DirCreateMode</a></li>
-<li><a href="omfile.html">$DirGroup</a></li>
-<li><a href="omfile.html">$DirOwner</a></li>
-<li><a href="rsconf1_dropmsgswithmaliciousdnsptrrecords.html">$DropMsgsWithMaliciousDnsPTRRecords</a></li>
-<li><a href="rsconf1_droptrailinglfonreception.html">$DropTrailingLFOnReception</a></li>
-<li><a href="omfile.html">$DynaFileCacheSize</a></li>
-<li><a href="rsconf1_escape8bitcharsonreceive.html">$Escape8BitCharactersOnReceive</a></li>
-<li><a href="rsconf1_escapecontrolcharactersonreceive.html">$EscapeControlCharactersOnReceive</a></li>
+<li><a href="omfile.html"><b>$DirCreateMode</b></a></li>
+<li><a href="omfile.html"><b>$DirGroup</b></a></li>
+<li><a href="omfile.html"><b>$DirOwner</b></a></li>
+<li><a href="rsconf1_dropmsgswithmaliciousdnsptrrecords.html"><b>$DropMsgsWithMaliciousDnsPTRRecords</b></a></li>
+<li><a href="rsconf1_droptrailinglfonreception.html"><b>$DropTrailingLFOnReception</b></a></li>
+<li><a href="omfile.html"><b>$DynaFileCacheSize</b></a></li>
+<li><a href="rsconf1_escape8bitcharsonreceive.html"><b>$Escape8BitCharactersOnReceive</b></a></li>
+<li><a href="rsconf1_escapecontrolcharactersonreceive.html"><b>$EscapeControlCharactersOnReceive</b></a></li>
<li><b>$EscapeControlCharactersOnReceive</b> [<b>on</b>|off] - escape USASCII HT character</li>
-<li>$SpaceLFOnReceive [on/<b>off</b>] - instructs rsyslogd to replace LF with spaces during message reception (sysklogd compatibility aid)</li>
-<li>$ErrorMessagesToStderr [<b>on</b>|off] - direct rsyslogd error message to stderr (in addition to other targets)</li>
-<li><a href="omfile.html">$FailOnChownFailure</a></li>
-<li><a href="omfile.html">$FileCreateMode</a></li>
-<li><a href="omfile.html">$FileGroup</a></li>
-<li><a href="omfile.html">$FileOwner</a></li>
-<li><a href="rsconf1_generateconfiggraph.html">$GenerateConfigGraph</a></li>
-<li><a href="rsconf1_gssforwardservicename.html">$GssForwardServiceName</a></li>
-<li><a href="rsconf1_gsslistenservicename.html">$GssListenServiceName</a></li>
-<li><a href="rsconf1_gssmode.html">$GssMode</a></li>
-<li><a href="rsconf1_includeconfig.html">$IncludeConfig</a></li><li>MainMsgQueueCheckpointInterval &lt;number&gt;</li>
+<li><b>$SpaceLFOnReceive</b> [on/<b>off</b>] - instructs rsyslogd to replace LF with spaces during message reception (sysklogd compatibility aid)</li>
+<li><b>$ErrorMessagesToStderr</b> [<b>on</b>|off] - direct rsyslogd error message to stderr (in addition to other targets)</li>
+<li><a href="omfile.html"><b>$FailOnChownFailure</b></a></li>
+<li><a href="omfile.html"><b>$FileCreateMode</b></a></li>
+<li><a href="omfile.html"><b>$FileGroup</b></a></li>
+<li><a href="omfile.html"><b>$FileOwner</b></a></li>
+<li><a href="rsconf1_generateconfiggraph.html"><b>$GenerateConfigGraph</b></a></li>
+<li><a href="rsconf1_gssforwardservicename.html"><b>$GssForwardServiceName</b></a></li>
+<li><a href="rsconf1_gsslistenservicename.html"><b>$GssListenServiceName</b></a></li>
+<li><a href="rsconf1_gssmode.html"><b>$GssMode</b></a></li>
+<li><a href="rsconf1_includeconfig.html"><b>$IncludeConfig</b></a></li><li>MainMsgQueueCheckpointInterval &lt;number&gt;</li>
<li><b>$LocalHostName</b> [name] - this directive permits to overwrite the system
hostname with the one specified in the directive. If the directive is given
multiple times, all but the last one will be ignored. Please note that startup
@@ -166,39 +166,39 @@ This information might be needed by some log analyzers. If set to off, no such
status messages are logged, what may be useful for other scenarios.
[available since 4.7.0 and 5.3.0]
<li><b>$MainMsgQueueDequeueBatchSize</b> &lt;number&gt; [default 32]</li>
-<li>$MainMsgQueueDequeueSlowdown &lt;number&gt; [number
+<li><b>$MainMsgQueueDequeueSlowdown</b> &lt;number&gt; [number
is timeout in <i> micro</i>seconds (1000000us is 1sec!),
default 0 (no delay). Simple rate-limiting!]</li>
-<li>$MainMsgQueueDiscardMark &lt;number&gt; [default 9750]</li>
-<li>$MainMsgQueueDiscardSeverity &lt;severity&gt;
+<li><b>$MainMsgQueueDiscardMark</b> &lt;number&gt; [default 9750]</li>
+<li><b>$MainMsgQueueDiscardSeverity</b> &lt;severity&gt;
[either a textual or numerical severity! default 4 (warning)]</li>
-<li>$MainMsgQueueFileName &lt;name&gt;</li>
-<li>$MainMsgQueueHighWaterMark &lt;number&gt; [default
+<li><b>$MainMsgQueueFileName</b> &lt;name&gt;</li>
+<li><b>$MainMsgQueueHighWaterMark</b> &lt;number&gt; [default
8000]</li>
-<li>$MainMsgQueueImmediateShutdown [on/<b>off</b>]</li>
-<li><a href="rsconf1_mainmsgqueuesize.html">$MainMsgQueueSize</a></li>
-<li>$MainMsgQueueLowWaterMark &lt;number&gt; [default
+<li><b>$MainMsgQueueImmediateShutdown</b> [on/<b>off</b>]</li>
+<li><a href="rsconf1_mainmsgqueuesize.html"><b>$MainMsgQueueSize</b></a></li>
+<li><b>$MainMsgQueueLowWaterMark</b> &lt;number&gt; [default
2000]</li>
-<li>$MainMsgQueueMaxFileSize &lt;size_nbr&gt;, default
+<li><b>$MainMsgQueueMaxFileSize</b> &lt;size_nbr&gt;, default
1m</li>
-<li>$MainMsgQueueTimeoutActionCompletion
+<li><b>$MainMsgQueueTimeoutActionCompletion</b>
&lt;number&gt; [number is timeout in ms (1000ms is 1sec!),
default
1000, 0 means immediate!]</li>
-<li>$MainMsgQueueTimeoutEnqueue &lt;number&gt; [number
+<li><b>$MainMsgQueueTimeoutEnqueue</b> &lt;number&gt; [number
is timeout in ms (1000ms is 1sec!), default 2000, 0 means indefinite]</li>
-<li>$MainMsgQueueTimeoutShutdown &lt;number&gt; [number
+<li><b>$MainMsgQueueTimeoutShutdown</b> &lt;number&gt; [number
is timeout in ms (1000ms is 1sec!), default 0 (indefinite)]</li>
-<li>$MainMsgQueueWorkerTimeoutThreadShutdown
+<li><b>$MainMsgQueueWorkerTimeoutThreadShutdown</b>
&lt;number&gt; [number is timeout in ms (1000ms is 1sec!),
default 60000 (1 minute)]</li>
-<li>$MainMsgQueueType [<b>FixedArray</b>/LinkedList/Direct/Disk]</li>
-<li>$MainMsgQueueSaveOnShutdown&nbsp; [on/<b>off</b>]
+<li><b>$MainMsgQueueType</b> [<b>FixedArray</b>/LinkedList/Direct/Disk]</li>
+<li><b>$MainMsgQueueSaveOnShutdown&nbsp;</b> [on/<b>off</b>]
</li>
-<li>$MainMsgQueueWorkerThreads &lt;number&gt;, num
+<li><b>$MainMsgQueueWorkerThreads</b> &lt;number&gt;, num
worker threads, default 1, recommended 1</li>
-<li>$MainMsgQueueWorkerThreadMinumumMessages &lt;number&gt;, default 100</li>
-<li><a href="rsconf1_markmessageperiod.html">$MarkMessagePeriod</a> (immark)</li>
+<li><b>$MainMsgQueueWorkerThreadMinumumMessages</b> &lt;number&gt;, default 100</li>
+<li><a href="rsconf1_markmessageperiod.html"><b>$MarkMessagePeriod</b></a> (immark)</li>
<li><b><i>$MaxMessageSize</i></b> &lt;size_nbr&gt;, default 2k - allows to specify maximum supported message size
(both for sending and receiving). The default
should be sufficient for almost all cases. Do not set this below 1k, as it would cause
@@ -221,9 +221,9 @@ instead of UDP (plain TCP syslog, RELP). This resolves the UDP stack size restri
<br>Note that 2k, the current default, is the smallest size that must be
supported in order to be compliant to the upcoming new syslog RFC series.
</li>
-<li><a href="rsconf1_maxopenfiles.html">$MaxOpenFiles</a></li>
-<li><a href="rsconf1_moddir.html">$ModDir</a></li>
-<li><a href="rsconf1_modload.html">$ModLoad</a></li>
+<li><a href="rsconf1_maxopenfiles.html"><b>$MaxOpenFiles</b></a></li>
+<li><a href="rsconf1_moddir.html"><b>$ModDir</b></a></li>
+<li><a href="rsconf1_modload.html"><b>$ModLoad</b></a></li>
<li><a href="omfile.html"><b>$OMFileAsyncWriting</b></a> [on/<b>off</b>], if turned on, the files will be written
in asynchronous mode via a separate thread. In that case, double buffers will be used so
that one buffer can be filled while the other buffer is being written. Note that in order
@@ -246,15 +246,15 @@ error recovery thus can handle write errors without data loss. Note that this op
severely reduces the effect of zip compression and should be switched to off
for that use case. Note that the default -on- is primarily an aid to preserve
the traditional syslogd behaviour.</li>
-<li><a href="omfile.html">$omfileForceChown</a> - force ownership change for all files</li>
+<li><a href="omfile.html"><b>$omfileForceChown</b></a> - force ownership change for all files</li>
<li><b>$RepeatedMsgContainsOriginalMsg</b> [on/<b>off</b>] - "last message repeated n times" messages, if generated,
have a different format that contains the message that is being repeated.
Note that only the first "n" characters are included, with n to be at least 80 characters, most
probably more (this may change from version to version, thus no specific limit is given). The bottom
line is that n is large enough to get a good idea which message was repeated but it is not necessarily
large enough for the whole message. (Introduced with 4.1.5). Once set, it affects all following actions.</li>
-<li><a href="rsconf1_repeatedmsgreduction.html">$RepeatedMsgReduction</a></li>
-<li><a href="rsconf1_resetconfigvariables.html">$ResetConfigVariables</a></li>
+<li><a href="rsconf1_repeatedmsgreduction.html"><b>$RepeatedMsgReduction</b></a></li>
+<li><a href="rsconf1_resetconfigvariables.html"><b>$ResetConfigVariables</b></a></li>
<li><b>$Ruleset</b> <i>name</i> - starts a new ruleset or switches back to one already defined.
All following actions belong to that new rule set.
the <i>name</i> does not yet exist, it is created. To switch back to rsyslog's
@@ -268,17 +268,17 @@ a specific (list of) message parsers to be used with the ruleset.
<li><b>$OptimizeForUniprocessor</b> [on/<b>off</b>] - turns on optimizatons which lead to better
performance on uniprocessors. If you run on multicore-machiens, turning this off lessens CPU load. The
default may change as uniprocessor systems become less common. [available since 4.1.0]</li>
-<li>$PreserveFQDN [on/<b>off</b>) - if set to off (legacy default to remain compatible
+<li><b>$PreserveFQDN</b> [on/<b>off</b>) - if set to off (legacy default to remain compatible
to sysklogd), the domain part from a name that is within the same domain as the receiving
system is stripped. If set to on, full names are always used.</li>
-<li>$WorkDirectory &lt;name&gt; (directory for spool and other work files.
+<li><b>$WorkDirectory</b> &lt;name&gt; (directory for spool and other work files.
Do <b>not</b> use trailing slashes)</li>
-<li>$UDPServerAddress &lt;IP&gt; (imudp) -- local IP
+<li><b>$UDPServerAddress</b> &lt;IP&gt; (imudp) -- local IP
address (or name) the UDP listens should bind to</li>
-<li>$UDPServerRun &lt;port&gt; (imudp) -- former
+<li><b>$UDPServerRun</b> &lt;port&gt; (imudp) -- former
-r&lt;port&gt; option, default 514, start UDP server on this
port, "*" means all addresses</li>
-<li>$UDPServerTimeRequery &lt;nbr-of-times&gt; (imudp) -- this is a performance
+<li><b>$UDPServerTimeRequery</b> &lt;nbr-of-times&gt; (imudp) -- this is a performance
optimization. Getting the system time is very costly. With this setting, imudp can
be instructed to obtain the precise time only once every n-times. This logic is
only activated if messages come in at a very fast rate, so doing less frequent
@@ -286,10 +286,10 @@ time calls should usually be acceptable. The default value is two, because we ha
seen that even without optimization the kernel often returns twice the identical time.
You can set this value as high as you like, but do so at your own risk. The higher
the value, the less precise the timestamp.
-<li><a href="droppriv.html">$PrivDropToGroup</a></li>
-<li><a href="droppriv.html">$PrivDropToGroupID</a></li>
-<li><a href="droppriv.html">$PrivDropToUser</a></li>
-<li><a href="droppriv.html">$PrivDropToUserID</a></li>
+<li><a href="droppriv.html"><b>$PrivDropToGroup</b></a></li>
+<li><a href="droppriv.html"><b>$PrivDropToGroupID</b></a></li>
+<li><a href="droppriv.html"><b>$PrivDropToUser</b></a></li>
+<li><a href="droppriv.html"><b>$PrivDropToUserID</b></a></li>
<li><b>$Sleep</b> &lt;seconds&gt; - puts the rsyslog main thread to sleep for the specified
number of seconds immediately when the directive is encountered. You should have a
good reason for using this directive!</li>
@@ -306,7 +306,7 @@ rsyslog.conf</b>. Otherwise, if error messages are triggered before this directi
is processed, rsyslog will fix the local host IP to "127.0.0.1", what than can
not be reset.
</li>
-<li><a href="rsconf1_umask.html">$UMASK</a></li>
+<li><a href="rsconf1_umask.html"><b>$UMASK</b></a></li>
</ul>
<p><b>Where &lt;size_nbr&gt; or integers are specified above,</b>
modifiers can be used after the number part. For example, 1k means
diff --git a/doc/rsyslog_conf_modules.html b/doc/rsyslog_conf_modules.html
index 2668bf2d..c8c1c5d7 100644
--- a/doc/rsyslog_conf_modules.html
+++ b/doc/rsyslog_conf_modules.html
@@ -45,6 +45,7 @@ to message generators.
<li><a href="imsolaris.html">imsolaris</a> - input for the Sun Solaris system log source</li>
<li><a href="im3195.html">im3195</a> - accepts syslog messages via RFC 3195</li>
<li><a href="impstats.html">impstats</a> - provides periodic statistics of rsyslog internal counters</li>
+<li><a href="imjournal.html">imjournal</a> - Linux journal inuput module</li>
</ul>
<a name"om"></a><h2>Output Modules</h2>
@@ -110,6 +111,7 @@ probably an excellent starting base for writing a new module. Currently, the fol
modules exist inside the source tree:
<ul>
<li><a href="mmanon.html">mmanon</a> - used to anonymize log messages.
+<li><a href="mmcount.html">mmcount</a> - message modification plugin which counts messages
<li><a href="mmnormalize.html">mmnormalize</a> - used to normalize log messages.
Note that this actually is a <b>generic</b> module.
<li><a href="mmjsonparse.html">mmjsonparse</a> - used to interpret CEE/lumberjack
diff --git a/grammar/.gitignore b/grammar/.gitignore
new file mode 100644
index 00000000..8bd546bd
--- /dev/null
+++ b/grammar/.gitignore
@@ -0,0 +1 @@
+lexer.c
diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c
index 4e3a70ab..15d994cc 100644
--- a/plugins/imgssapi/imgssapi.c
+++ b/plugins/imgssapi/imgssapi.c
@@ -72,6 +72,7 @@ MODULE_CNFNAME("imgssapi")
/* some forward definitions - they may go away when we no longer include imtcp.c */
static rsRetVal addGSSListener(void __attribute__((unused)) *pVal, uchar *pNewVal);
+static rsRetVal actGSSListener(uchar *port);
static int TCPSessGSSInit(void);
static void TCPSessGSSClose(tcps_sess_t* pSess);
static rsRetVal TCPSessGSSRecv(tcps_sess_t *pSess, void *buf, size_t buf_len, ssize_t *);
@@ -90,6 +91,7 @@ DEFobjCurrIf(glbl)
static tcpsrv_t *pOurTcpsrv = NULL; /* our TCP server(listener) TODO: change for multiple instances */
static gss_cred_id_t gss_server_creds = GSS_C_NO_CREDENTIAL;
+static uchar *srvPort;
/* our usr structure for the tcpsrv object */
typedef struct gsssrv_s {
@@ -317,6 +319,16 @@ static rsRetVal
addGSSListener(void __attribute__((unused)) *pVal, uchar *pNewVal)
{
DEFiRet;
+
+ srvPort = pNewVal;
+
+ RETiRet;
+}
+
+static rsRetVal
+actGSSListener(uchar *port)
+{
+ DEFiRet;
gsssrv_t *pGSrv;
if(pOurTcpsrv == NULL) {
@@ -340,7 +352,7 @@ addGSSListener(void __attribute__((unused)) *pVal, uchar *pNewVal)
CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose));
CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose));
CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, UCHAR_CONSTANT("imgssapi")));
- tcpsrv.configureTCPListen(pOurTcpsrv, pNewVal, 1);
+ tcpsrv.configureTCPListen(pOurTcpsrv, port, 1);
CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv));
}
@@ -676,6 +688,11 @@ ENDfreeCnf
*/
BEGINrunInput
CODESTARTrunInput
+ /* This will fail if the priviledges are dropped. Should be
+ * moved to the '*activateCnfPrePrivDrop' section eventually.
+ */
+ actGSSListener(srvPort);
+
iRet = tcpsrv.Run(pOurTcpsrv);
ENDrunInput
@@ -683,7 +700,7 @@ ENDrunInput
/* initialize and return if will run or not */
BEGINwillRun
CODESTARTwillRun
- if(pOurTcpsrv == NULL)
+ if(srvPort == NULL)
ABORT_FINALIZE(RS_RET_NO_RUN);
net.PrintAllowedSenders(2); /* TCP */
diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c
index 2af1958e..cce45b9c 100644..100755
--- a/plugins/imjournal/imjournal.c
+++ b/plugins/imjournal/imjournal.c
@@ -30,7 +30,9 @@
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
+#include <sys/poll.h>
#include <sys/socket.h>
+#include <errno.h>
#include "dirty.h"
#include "cfsysline.h"
@@ -43,6 +45,7 @@
#include "glbl.h"
#include "prop.h"
#include "errmsg.h"
+#include "srUtils.h"
#include "unicode-helper.h"
#include <systemd/sd-journal.h>
@@ -136,16 +139,20 @@ readjournal() {
uint64_t timestamp;
struct json_object *json = NULL;
+ int r;
/* Information from messages */
char *message;
+ char *sys_pid;
char *sys_iden;
char *sys_iden_help;
const void *get;
+ const void *pidget;
char *parse;
char *get2;
size_t length;
+ size_t pidlength;
const void *equal_sign;
struct json_object *jval;
@@ -158,13 +165,6 @@ readjournal() {
int priority = 0;
int facility = 0;
- /* Get next journal message, if there is none, wait a second */
- if (sd_journal_next(j) == 0) {
- sleep(1);
- iRet = RS_RET_OK;
- goto ret;
- }
-
/* Get message text */
if (sd_journal_get_data(j, "MESSAGE", &get, &length) < 0) {
logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar *)"log message from journal doesn't have MESSAGE", 0);
@@ -203,7 +203,7 @@ readjournal() {
goto free_message;
}
- /* Get message identifier and add ':' */
+ /* Get message identifier, client pid and add ':' */
if (sd_journal_get_data(j, "SYSLOG_IDENTIFIER", &get, &length) >= 0) {
sys_iden = strndup(get+18, length-18);
} else {
@@ -214,19 +214,44 @@ readjournal() {
goto free_message;
}
- asprintf(&sys_iden_help, "%s:", sys_iden);
- if (sys_iden_help == NULL) {
+ if (sd_journal_get_data(j, "SYSLOG_PID", &pidget, &pidlength) >= 0) {
+ sys_pid = strndup(pidget+11, pidlength-11);
+ if (sys_pid == NULL) {
+ iRet = RS_RET_OUT_OF_MEMORY;
+ free (sys_iden);
+ goto free_message;
+ }
+ } else {
+ sys_pid = NULL;
+ }
+
+ if (sys_pid) {
+ r = asprintf(&sys_iden_help, "%s[%s]:", sys_iden, sys_pid);
+ } else {
+ r = asprintf(&sys_iden_help, "%s:", sys_iden);
+ }
+
+ free (sys_iden);
+ free (sys_pid);
+
+ if (-1 == r) {
iRet = RS_RET_OUT_OF_MEMORY;
goto finalize_it;
}
- free (sys_iden);
json = json_object_new_object();
SD_JOURNAL_FOREACH_DATA(j, get, l) {
/* locate equal sign, this is always present */
equal_sign = memchr(get, '=', l);
- assert (equal_sign != NULL);
+
+ /* ... but we know better than to trust the specs */
+ if (equal_sign == NULL) {
+ errmsg.LogError(0, RS_RET_ERR,"SD_JOURNAL_FOREACH_DATA()"
+ " returned a malformed field (has no '='): '%s'",
+ get);
+ continue; /* skip the entry */
+ }
/* get length of journal data prefix */
prefixlen = ((char *)equal_sign - (char *)get);
@@ -337,7 +362,9 @@ persistJournalState () {
char *cursor;
int ret = 0;
- if ((ret = sd_journal_get_cursor(j, &cursor)) > 0) {
+ /* On success, sd_journal_get_cursor() returns 1 in systemd
+ 197 or older and 0 in systemd 198 or newer */
+ if ((ret = sd_journal_get_cursor(j, &cursor)) >= 0) {
if ((sf = fopen(cs.stateFile, "wb")) != NULL) {
if (fprintf(sf, "%s", cursor) < 0) {
iRet = RS_RET_IO_ERROR;
@@ -345,29 +372,92 @@ persistJournalState () {
fclose(sf);
free(cursor);
} else {
+ char errStr[256];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ errmsg.LogError(0, RS_RET_FOPEN_FAILURE, "fopen() failed: "
+ "'%s', path: '%s'\n", errStr, cs.stateFile);
iRet = RS_RET_FOPEN_FAILURE;
}
} else {
+ char errStr[256];
+ rs_strerror_r(-(ret), errStr, sizeof(errStr));
+ errmsg.LogError(0, RS_RET_ERR, "sd_journal_get_cursor() failed: '%s'\n", errStr);
iRet = RS_RET_ERR;
}
RETiRet;
}
+/* Polls the journal for new messages. Similar to sd_journal_wait()
+ * except for the special handling of EINTR.
+ */
+static rsRetVal
+pollJournal()
+{
+ DEFiRet;
+ struct pollfd pollfd;
+ int r;
+
+ pollfd.fd = sd_journal_get_fd(j);
+ pollfd.events = sd_journal_get_events(j);
+ r = poll(&pollfd, 1, -1);
+ if (r == -1) {
+ if (errno == EINTR) {
+ /* EINTR is also received during termination
+ * so return now to check the term state.
+ */
+ ABORT_FINALIZE(RS_RET_OK);
+ } else {
+ char errStr[256];
+
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ errmsg.LogError(0, RS_RET_ERR,
+ "poll() failed: '%s'", errStr);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ }
+
+ assert(r == 1);
+
+ r = sd_journal_process(j);
+ if (r < 0) {
+ char errStr[256];
+
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ errmsg.LogError(0, RS_RET_ERR,
+ "sd_journal_process() failed: '%s'", errStr);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
BEGINrunInput
CODESTARTrunInput
/* this is an endless loop - it is terminated when the thread is
* signalled to do so. This, however, is handled by the framework,
* right into the sleep below.
*/
- int count = 0;
+ if (cs.stateFile[0] != '/') {
+ char *new_stateFile;
- char readCursor[128 + 1];
- FILE *r_sf;
+ if (-1 == asprintf(&new_stateFile, "%s/%s", (char *)glbl.GetWorkDir(), cs.stateFile)) {
+ errmsg.LogError(0, RS_RET_OUT_OF_MEMORY, "imjournal: asprintf failed\n");
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ }
+ free (cs.stateFile);
+ cs.stateFile = new_stateFile;
+ }
/* if state file exists, set cursor to appropriate position */
if (access(cs.stateFile, F_OK|R_OK) != -1) {
+ FILE *r_sf;
+
if ((r_sf = fopen(cs.stateFile, "rb")) != NULL) {
+ char readCursor[128 + 1];
+
if (fscanf(r_sf, "%128s\n", readCursor) != EOF) {
if (sd_journal_seek_cursor(j, readCursor) != 0) {
errmsg.LogError(0, RS_RET_ERR, "imjournal: "
@@ -390,14 +480,32 @@ CODESTARTrunInput
}
while (glbl.GetGlobalInputTermState() == 0) {
+ int count = 0, r;
+
+ r = sd_journal_next(j);
+ if (r < 0) {
+ char errStr[256];
+
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ errmsg.LogError(0, RS_RET_ERR,
+ "sd_journal_next() failed: '%s'", errStr);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+ if (r == 0) {
+ /* No new messages, wait for activity. */
+ CHKiRet(pollJournal());
+ continue;
+ }
+
CHKiRet(readjournal());
+ /* TODO: This could use some finer metric. */
count++;
if (count == cs.iPersistStateInterval) {
count = 0;
persistJournalState();
}
}
- persistJournalState();
finalize_it:
ENDrunInput
@@ -444,6 +552,7 @@ ENDwillRun
/* close journal */
BEGINafterRun
CODESTARTafterRun
+ persistJournalState();
sd_journal_close(j);
ENDafterRun
@@ -500,16 +609,22 @@ finalize_it:
ENDsetModCnf
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURENonCancelInputTermination)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_IMOD_QUERIES
CODEqueryEtryPt_STD_CONF2_QUERIES
CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
ENDqueryEtryPt
-
-
BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c
index 5e0ae552..7fa98617 100644
--- a/plugins/imrelp/imrelp.c
+++ b/plugins/imrelp/imrelp.c
@@ -4,7 +4,7 @@
*
* File begun on 2008-03-13 by RGerhards
*
- * Copyright 2008-2012 Adiscon GmbH.
+ * Copyright 2008-2013 Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -74,6 +74,8 @@ static struct configSettings_s {
struct instanceConf_s {
uchar *pszBindPort; /* port to bind to */
+ sbool bEnableTLS;
+ sbool bEnableTLSZip;
struct instanceConf_s *next;
};
@@ -88,9 +90,21 @@ struct modConfData_s {
static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */
+/* module-global parameters */
+static struct cnfparamdescr modpdescr[] = {
+ { "ruleset", eCmdHdlrGetWord, 0 },
+};
+static struct cnfparamblk modpblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(modpdescr)/sizeof(struct cnfparamdescr),
+ modpdescr
+ };
+
/* input instance parameters */
static struct cnfparamdescr inppdescr[] = {
- { "port", eCmdHdlrString, CNFPARAM_REQUIRED }
+ { "port", eCmdHdlrString, CNFPARAM_REQUIRED },
+ { "tls", eCmdHdlrBinary, 0 },
+ { "tls.compression", eCmdHdlrBinary, 0 }
};
static struct cnfparamblk inppblk =
{ CNFPARAMBLK_VERSION,
@@ -155,6 +169,8 @@ createInstance(instanceConf_t **pinst)
inst->next = NULL;
inst->pszBindPort = NULL;
+ inst->bEnableTLS = 0;
+ inst->bEnableTLSZip = 0;
/* node created, let's add to config */
if(loadModConf->tail == NULL) {
@@ -179,7 +195,7 @@ std_checkRuleset_genErrMsg(modConfData_t *modConf, __attribute__((unused)) insta
}
-/* This function is called when a new listener instace shall be added to
+/* This function is called when a new listener instance shall be added to
* the current config object via the legacy config system. It just shuffles
* all parameters to the listener in-memory instance.
* rgerhards, 2011-05-04
@@ -204,6 +220,7 @@ finalize_it:
static rsRetVal
addListner(modConfData_t __attribute__((unused)) *modConf, instanceConf_t *inst)
{
+ relpSrv_t *pSrv;
DEFiRet;
if(pRelpEngine == NULL) {
CHKiRet(relpEngineConstruct(&pRelpEngine));
@@ -216,7 +233,15 @@ addListner(modConfData_t __attribute__((unused)) *modConf, instanceConf_t *inst)
}
}
- CHKiRet(relpEngineAddListner(pRelpEngine, inst->pszBindPort));
+ CHKiRet(relpEngineListnerConstruct(pRelpEngine, &pSrv));
+ CHKiRet(relpSrvSetLstnPort(pSrv, inst->pszBindPort));
+ if(inst->bEnableTLS) {
+ relpSrvEnableTLS(pSrv);
+ if(inst->bEnableTLSZip) {
+ relpSrvEnableTLSZip(pSrv);
+ }
+ }
+ CHKiRet(relpEngineListnerConstructFinalize(pRelpEngine, pSrv));
finalize_it:
RETiRet;
@@ -249,6 +274,10 @@ CODESTARTnewInpInst
continue;
if(!strcmp(inppblk.descr[i].name, "port")) {
inst->pszBindPort = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "tls")) {
+ inst->bEnableTLS = (unsigned) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "tls.compression")) {
+ inst->bEnableTLSZip = (unsigned) pvals[i].val.d.n;
} else {
dbgprintf("imrelp: program error, non-handled "
"param '%s'\n", inppblk.descr[i].name);
@@ -264,19 +293,58 @@ BEGINbeginCnfLoad
CODESTARTbeginCnfLoad
loadModConf = pModConf;
pModConf->pConf = pConf;
+ pModConf->pszBindRuleset = NULL;
+ pModConf->pBindRuleset = NULL;
/* init legacy config variables */
cs.pszBindRuleset = NULL;
ENDbeginCnfLoad
+BEGINsetModCnf
+ struct cnfparamvals *pvals = NULL;
+ int i;
+CODESTARTsetModCnf
+ pvals = nvlstGetParams(lst, &modpblk, NULL);
+ if(pvals == NULL) {
+ errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module "
+ "config parameters [module(...)]");
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ if(Debug) {
+ dbgprintf("module (global) param blk for imrelp:\n");
+ cnfparamsPrint(&modpblk, pvals);
+ }
+
+ for(i = 0 ; i < modpblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(modpblk.descr[i].name, "ruleset")) {
+ loadModConf->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else {
+ dbgprintf("imrelp: program error, non-handled "
+ "param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
+ }
+ }
+finalize_it:
+ if(pvals != NULL)
+ cnfparamvalsDestruct(pvals, &modpblk);
+ENDsetModCnf
+
BEGINendCnfLoad
CODESTARTendCnfLoad
- if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) {
- loadModConf->pszBindRuleset = NULL;
+ if(loadModConf->pszBindRuleset == NULL) {
+ if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) {
+ loadModConf->pszBindRuleset = NULL;
+ } else {
+ CHKmalloc(loadModConf->pszBindRuleset = ustrdup(cs.pszBindRuleset));
+ }
} else {
- CHKmalloc(loadModConf->pszBindRuleset = ustrdup(cs.pszBindRuleset));
+ if((cs.pszBindRuleset != NULL) && (cs.pszBindRuleset[0] != '\0')) {
+ errmsg.LogError(0, RS_RET_DUP_PARAM, "imrelp: warning: ruleset "
+ "set via legacy directive ignored");
+ }
}
- loadModConf->pBindRuleset = NULL;
finalize_it:
free(cs.pszBindRuleset);
loadModConf = NULL; /* done loading */
@@ -293,6 +361,7 @@ CODESTARTcheckCnf
if(pModConf->pszBindRuleset == NULL) {
pModConf->pBindRuleset = NULL;
} else {
+ DBGPRINTF("imrelp: using ruleset '%s'\n", pModConf->pszBindRuleset);
localRet = ruleset.GetRuleset(pModConf->pConf, &pRuleset, pModConf->pszBindRuleset);
if(localRet == RS_RET_NOT_FOUND) {
std_checkRuleset_genErrMsg(pModConf, NULL);
@@ -420,6 +489,7 @@ CODEqueryEtryPt_STD_IMOD_QUERIES
CODEqueryEtryPt_STD_CONF2_QUERIES
CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES
CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES
+CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES
CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
ENDqueryEtryPt
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index c503852c..dad09ab4 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -1284,6 +1284,8 @@ BEGINactivateCnfPrePrivDrop
instanceConf_t *inst;
CODESTARTactivateCnfPrePrivDrop
runModConf = pModConf;
+ if(runModConf->bOmitLocalLogging && nfd == 1)
+ ABORT_FINALIZE(RS_RET_OK);
for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
addListner(inst);
}
@@ -1325,6 +1327,8 @@ BEGINrunInput
#endif
CODESTARTrunInput
+ if(runModConf->bOmitLocalLogging && nfd == 1)
+ ABORT_FINALIZE(RS_RET_OK);
/* this is an endless loop - it is terminated when the thread is
* signalled to do so. This, however, is handled by the framework,
* right into the sleep below.
diff --git a/plugins/imzmq3/README b/plugins/imzmq3/README
index 88653b83..9a108a01 100644
--- a/plugins/imzmq3/README
+++ b/plugins/imzmq3/README
@@ -1,24 +1,59 @@
ZeroMQ 3.x Input Plugin
Building this plugin:
-Requires libzmq and libczmq. First, install libzmq from the HEAD on github:
-http://github.com/zeromq/libzmq. You can clone the repository, build, then
-install it. The directions for doing so are there in the readme. Then, do
-the same for libczmq: http://github.com/zeromq/czmq. At some point, the 3.1
-version of libzmq will be released, and a supporting version of libczmq.
-At that time, you could simply download and install the tarballs instead of
-using git to clone the repositories. Those tarballs (when available) can
-be found at http://download.zeromq.org. As of this writing (5/31/2012), the
-most recent version of czmq (1.1.0) and libzmq (3.1.0-beta) will not compile
-properly.
+Requires libzmq and libczmq. First, download the tarballs of both libzmq
+and its supporting libczmq from http://download.zeromq.org. As of this
+writing (04/23/2013), the most recent versions of libzmq and czmq are
+3.2.2 and 1.3.2 respectively. Configure, build, and then install both libs.
Imzmq3 allows you to push data into rsyslog from a zeromq socket. The example
below binds a SUB socket to port 7172, and then any messages with the topic
"foo" will be pushed into rsyslog.
+Please note:
+This plugin only supports the newer (v7) config format. Legacy config support
+was removed.
+
Example Rsyslog.conf snippet:
-------------------------------------------------------------------------------
-
-$InputZmq3ServerRun action=BIND,type=SUB,description=tcp://*:7172,subscribe=foo
+module(load="imzmq3" ioThreads="1")
+input(type="imzmq3" action="CONNECT" socktype="SUB" description="tcp://*:7172" subscribe="foo,bar")
-------------------------------------------------------------------------------
+Note you can specify multiple subscriptions with a comma-delimited list, with
+no spaces between values.
+
+The only global parameter for this plugin is ioThreads, which is optional and
+probably best left to the zmq default unless you know exactly what you are
+doing.
+
+The instance-level parameters are:
+
+Required
+description
+subscribe (required if the sockType is SUB)
+
+Optional
+sockType (defaults to SUB)
+action (defaults to BIND
+sndHWM
+rcvHWM
+identity
+sndBuf
+rcvBuf
+linger
+backlog
+sndTimeout
+rcvTimeout
+maxMsgSize
+rate
+recoveryIVL
+multicastHops
+reconnectIVL
+reconnectIVLMax
+ipv4Only
+affinity
+
+These all correspond to zmq optional settings. Except where noted, the defaults
+are the zmq defaults if not set. See http://api.zeromq.org/3-2:zmq-setsockopt
+for info on these.
diff --git a/plugins/imzmq3/imzmq3.c b/plugins/imzmq3/imzmq3.c
index 52c12a53..08b1dbe4 100644
--- a/plugins/imzmq3/imzmq3.c
+++ b/plugins/imzmq3/imzmq3.c
@@ -19,20 +19,21 @@
* License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*
- * Author: David Kelly
- * <davidk@talksum.com>
+ * Authors:
+ * David Kelly <davidk@talksum.com>
+ * Hongfei Cheng <hongfeic@talksum.com>
*/
+
+#include "config.h"
+#include "rsyslog.h"
+
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-
-#include "rsyslog.h"
-
#include "cfsysline.h"
-#include "config.h"
#include "dirty.h"
#include "errmsg.h"
#include "glbl.h"
@@ -49,6 +50,7 @@
MODULE_TYPE_INPUT
MODULE_TYPE_NOKEEP
+MODULE_CNFNAME("imzmq3");
/* convienent symbols to denote a socket we want to bind
* vs one we want to just connect to
@@ -83,47 +85,67 @@ typedef struct _poller_data {
thrdInfo_t* thread;
} poller_data;
-typedef struct _socket_info {
- int type;
- int action;
- char* description;
- int sndHWM; /* if you want more than 2^32 messages, */
- int rcvHWM; /* then pass in 0 (the default). */
- char* identity;
- char** subscriptions;
- ruleset_t* ruleset;
- int sndBuf;
- int rcvBuf;
- int linger;
- int backlog;
- int sndTimeout;
- int rcvTimeout;
- int maxMsgSize;
- int rate;
- int recoveryIVL;
- int multicastHops;
- int reconnectIVL;
- int reconnectIVLMax;
- int ipv4Only;
- int affinity;
-
-} socket_info;
+/* a linked-list of subscription topics */
+typedef struct sublist_t {
+ char* subscribe;
+ struct sublist_t* next;
+} sublist;
+
+struct instanceConf_s {
+ int type;
+ int action;
+ char* description;
+ int sndHWM; /* if you want more than 2^32 messages, */
+ int rcvHWM; /* then pass in 0 (the default). */
+ char* identity;
+ sublist* subscriptions;
+ int sndBuf;
+ int rcvBuf;
+ int linger;
+ int backlog;
+ int sndTimeout;
+ int rcvTimeout;
+ int maxMsgSize;
+ int rate;
+ int recoveryIVL;
+ int multicastHops;
+ int reconnectIVL;
+ int reconnectIVLMax;
+ int ipv4Only;
+ int affinity;
+ uchar* pszBindRuleset;
+ ruleset_t* pBindRuleset;
+ struct instanceConf_s* next;
+
+};
+
+struct modConfData_s {
+ rsconf_t* pConf;
+ instanceConf_t* root;
+ instanceConf_t* tail;
+ int io_threads;
+};
+struct lstn_s {
+ struct lstn_s* next;
+ void* sock;
+ ruleset_t* pRuleset;
+};
/* ----------------------------------------------------------------------------
* Static definitions/initializations.
*/
-static socket_info* s_socketInfo = NULL;
-static size_t s_nitems = 0;
-static prop_t * s_namep = NULL;
+static modConfData_t* runModConf = NULL;
+static struct lstn_s* lcnfRoot = NULL;
+static struct lstn_s* lcnfLast = NULL;
+static prop_t* s_namep = NULL;
static zloop_t* s_zloop = NULL;
-static int s_io_threads = 1;
static zctx_t* s_context = NULL;
-static ruleset_t* s_ruleset = NULL;
static socket_type socketTypes[] = {
- {"SUB", ZMQ_SUB },
- {"PULL", ZMQ_PULL },
- {"XSUB", ZMQ_XSUB }
+ {"SUB", ZMQ_SUB },
+ {"PULL", ZMQ_PULL },
+ {"ROUTER", ZMQ_ROUTER },
+ {"XSUB", ZMQ_XSUB }
};
static socket_action socketActions[] = {
@@ -131,6 +153,48 @@ static socket_action socketActions[] = {
{"CONNECT", ACTION_CONNECT},
};
+static struct cnfparamdescr modpdescr[] = {
+ { "ioThreads", eCmdHdlrInt, 0 },
+};
+
+static struct cnfparamblk modpblk = {
+ CNFPARAMBLK_VERSION,
+ sizeof(modpdescr)/sizeof(struct cnfparamdescr),
+ modpdescr
+};
+
+static struct cnfparamdescr inppdescr[] = {
+ { "description", eCmdHdlrGetWord, 0 },
+ { "sockType", eCmdHdlrGetWord, 0 },
+ { "subscribe", eCmdHdlrGetWord, 0 },
+ { "ruleset", eCmdHdlrGetWord, 0 },
+ { "action", eCmdHdlrGetWord, 0 },
+ { "sndHWM", eCmdHdlrInt, 0 },
+ { "rcvHWM", eCmdHdlrInt, 0 },
+ { "identity", eCmdHdlrGetWord, 0 },
+ { "sndBuf", eCmdHdlrInt, 0 },
+ { "rcvBuf", eCmdHdlrInt, 0 },
+ { "linger", eCmdHdlrInt, 0 },
+ { "backlog", eCmdHdlrInt, 0 },
+ { "sndTimeout", eCmdHdlrInt, 0 },
+ { "rcvTimeout", eCmdHdlrInt, 0 },
+ { "maxMsgSize", eCmdHdlrInt, 0 },
+ { "rate", eCmdHdlrInt, 0 },
+ { "recoveryIVL", eCmdHdlrInt, 0 },
+ { "multicastHops", eCmdHdlrInt, 0 },
+ { "reconnectIVL", eCmdHdlrInt, 0 },
+ { "reconnectIVLMax", eCmdHdlrInt, 0 },
+ { "ipv4Only", eCmdHdlrInt, 0 },
+ { "affinity", eCmdHdlrInt, 0 }
+};
+
+static struct cnfparamblk inppblk = {
+ CNFPARAMBLK_VERSION,
+ sizeof(inppdescr)/sizeof(struct cnfparamdescr),
+ inppdescr
+};
+
+#include "im-helper.h" /* must be included AFTER the type definitions! */
/* ----------------------------------------------------------------------------
* Helper functions
@@ -179,15 +243,16 @@ static int getSocketAction(char* name) {
}
-static void setDefaults(socket_info* info) {
- info->type = ZMQ_SUB;
- info->action = ACTION_BIND;
+static void setDefaults(instanceConf_t* info) {
+ info->type = -1;
+ info->action = -1;
info->description = NULL;
- info->sndHWM = 0;
- info->rcvHWM = 0;
+ info->sndHWM = -1;
+ info->rcvHWM = -1;
info->identity = NULL;
info->subscriptions = NULL;
- info->ruleset = NULL;
+ info->pszBindRuleset = NULL;
+ info->pBindRuleset = NULL;
info->sndBuf = -1;
info->rcvBuf = -1;
info->linger = -1;
@@ -202,93 +267,49 @@ static void setDefaults(socket_info* info) {
info->reconnectIVLMax = -1;
info->ipv4Only = -1;
info->affinity = -1;
-
+ info->next = NULL;
};
-
-/* The config string should look like:
- * "action=AAA,type=TTT,description=DDD,sndHWM=SSS,rcvHWM=RRR,subscribe='xxx',subscribe='yyy'"
- *
+/* given a comma separated list of subscriptions, create a char* array of them
+ * to set later
*/
-static rsRetVal parseConfig(char* config, socket_info* info) {
- int nsubs = 0;
-
- char* binding;
- char* ptr1;
- for (binding = strtok_r(config, ",", &ptr1);
- binding != NULL;
- binding = strtok_r(NULL, ",", &ptr1)) {
-
- /* Each binding looks like foo=bar */
- char * sep = strchr(binding, '=');
- if (sep == NULL)
- {
- errmsg.LogError(0, NO_ERRCODE,
- "Invalid argument format %s, ignoring ...",
- binding);
- continue;
- }
+static rsRetVal parseSubscriptions(char* subscribes, sublist** subList){
+ char* tok = strtok(subscribes, ",");
+ sublist* currentSub;
+ sublist* head;
+ DEFiRet;
- /* Replace '=' with '\0'. */
- *sep = '\0';
-
- char * val = sep + 1;
-
- if (strcmp(binding, "action") == 0) {
- info->action = getSocketAction(val);
- } else if (strcmp(binding, "type") == 0) {
- info->type = getSocketType(val);
- } else if (strcmp(binding, "description") == 0) {
- info->description = strdup(val);
- } else if (strcmp(binding, "sndHWM") == 0) {
- info->sndHWM = atoi(val);
- } else if (strcmp(binding, "rcvHWM") == 0) {
- info->sndHWM = atoi(val);
- } else if (strcmp(binding, "subscribe") == 0) {
- /* Add the subscription value to the list.*/
- char * substr = NULL;
- substr = strdup(val);
- info->subscriptions = realloc(info->subscriptions, sizeof(char *) * nsubs + 1);
- info->subscriptions[nsubs] = substr;
- ++nsubs;
- } else if (strcmp(binding, "sndBuf") == 0) {
- info->sndBuf = atoi(val);
- } else if (strcmp(binding, "rcvBuf") == 0) {
- info->rcvBuf = atoi(val);
- } else if (strcmp(binding, "linger") == 0) {
- info->linger = atoi(val);
- } else if (strcmp(binding, "backlog") == 0) {
- info->backlog = atoi(val);
- } else if (strcmp(binding, "sndTimeout") == 0) {
- info->sndTimeout = atoi(val);
- } else if (strcmp(binding, "rcvTimeout") == 0) {
- info->rcvTimeout = atoi(val);
- } else if (strcmp(binding, "maxMsgSize") == 0) {
- info->maxMsgSize = atoi(val);
- } else if (strcmp(binding, "rate") == 0) {
- info->rate = atoi(val);
- } else if (strcmp(binding, "recoveryIVL") == 0) {
- info->recoveryIVL = atoi(val);
- } else if (strcmp(binding, "multicastHops") == 0) {
- info->multicastHops = atoi(val);
- } else if (strcmp(binding, "reconnectIVL") == 0) {
- info->reconnectIVL = atoi(val);
- } else if (strcmp(binding, "reconnectIVLMax") == 0) {
- info->reconnectIVLMax = atoi(val);
- } else if (strcmp(binding, "ipv4Only") == 0) {
- info->ipv4Only = atoi(val);
- } else if (strcmp(binding, "affinity") == 0) {
- info->affinity = atoi(val);
- } else {
- errmsg.LogError(0, NO_ERRCODE, "Unknown argument %s", binding);
- return RS_RET_INVALID_PARAMS;
+ /* create empty list */
+ CHKmalloc(*subList = (sublist*)MALLOC(sizeof(sublist)));
+ head = *subList;
+ head->next = NULL;
+ head->subscribe=NULL;
+ currentSub=head;
+
+ if(tok) {
+ head->subscribe=strdup(tok);
+ for(tok=strtok(NULL, ","); tok!=NULL;tok=strtok(NULL, ",")) {
+ CHKmalloc(currentSub->next = (sublist*)MALLOC(sizeof(sublist)));
+ currentSub=currentSub->next;
+ currentSub->subscribe=strdup(tok);
+ currentSub->next=NULL;
}
+ } else {
+ /* make empty subscription ie subscribe="" */
+ head->subscribe=strdup("");
}
-
- return RS_RET_OK;
+ /* TODO: temporary logging */
+ currentSub = head;
+ DBGPRINTF("imzmq3: Subscriptions:");
+ for(currentSub = head; currentSub != NULL; currentSub=currentSub->next) {
+ DBGPRINTF("'%s'", currentSub->subscribe);
+ }
+ DBGPRINTF("\n");
+finalize_it:
+ RETiRet;
}
-static rsRetVal validateConfig(socket_info* info) {
+static rsRetVal validateConfig(instanceConf_t* info) {
if (info->type == -1) {
errmsg.LogError(0, RS_RET_INVALID_PARAMS,
@@ -307,7 +328,7 @@ static rsRetVal validateConfig(socket_info* info) {
}
if(info->type == ZMQ_SUB && info->subscriptions == NULL) {
errmsg.LogError(0, RS_RET_INVALID_PARAMS,
- "SUB sockets need at least one subscription");
+ "SUB sockets need a subscription");
return RS_RET_INVALID_PARAMS;
}
if(info->type != ZMQ_SUB && info->subscriptions != NULL) {
@@ -320,39 +341,40 @@ static rsRetVal validateConfig(socket_info* info) {
static rsRetVal createContext() {
if (s_context == NULL) {
- errmsg.LogError(0, NO_ERRCODE, "creating zctx.");
+ DBGPRINTF("imzmq3: creating zctx...");
+ zsys_handler_set(NULL);
s_context = zctx_new();
if (s_context == NULL) {
errmsg.LogError(0, RS_RET_INVALID_PARAMS,
"zctx_new failed: %s",
- strerror(errno));
+ zmq_strerror(errno));
/* DK: really should do better than invalid params...*/
return RS_RET_INVALID_PARAMS;
}
-
- if (s_io_threads > 1) {
- errmsg.LogError(0, NO_ERRCODE, "setting io worker threads to %d", s_io_threads);
- zctx_set_iothreads(s_context, s_io_threads);
+ DBGPRINTF("success!\n");
+ if (runModConf->io_threads > 1) {
+ DBGPRINTF("setting io worker threads to %d\n", runModConf->io_threads);
+ zctx_set_iothreads(s_context, runModConf->io_threads);
}
}
return RS_RET_OK;
}
-static rsRetVal createSocket(socket_info* info, void** sock) {
- size_t ii;
+static rsRetVal createSocket(instanceConf_t* info, void** sock) {
int rv;
+ sublist* sub;
*sock = zsocket_new(s_context, info->type);
if (!sock) {
- errmsg.LogError(0,
+ errmsg.LogError(0,
RS_RET_INVALID_PARAMS,
"zsocket_new failed: %s, for type %d",
- strerror(errno),info->type);
- /* DK: invalid params seems right here */
+ zmq_strerror(errno),info->type);
+ /* DK: invalid params seems right here */
return RS_RET_INVALID_PARAMS;
}
-
+ DBGPRINTF("imzmq3: socket of type %d created successfully\n", info->type)
/* Set options *before* the connect/bind. */
if (info->identity) zsocket_set_identity(*sock, info->identity);
if (info->sndBuf > -1) zsocket_set_sndbuf(*sock, info->sndBuf);
@@ -369,38 +391,36 @@ static rsRetVal createSocket(socket_info* info, void** sock) {
if (info->reconnectIVLMax > -1) zsocket_set_reconnect_ivl_max(*sock, info->reconnectIVLMax);
if (info->ipv4Only > -1) zsocket_set_ipv4only(*sock, info->ipv4Only);
if (info->affinity > -1) zsocket_set_affinity(*sock, info->affinity);
-
- /* since HWM have defaults, we always set them. No return codes to check, either.*/
- zsocket_set_sndhwm(*sock, info->sndHWM);
- zsocket_set_rcvhwm(*sock, info->rcvHWM);
-
+ if (info->sndHWM > -1 ) zsocket_set_sndhwm(*sock, info->sndHWM);
+ if (info->rcvHWM > -1 ) zsocket_set_rcvhwm(*sock, info->rcvHWM);
/* Set subscriptions.*/
if (info->type == ZMQ_SUB) {
- for (ii = 0; ii < sizeof(info->subscriptions)/sizeof(char*); ++ii)
- zsocket_set_subscribe(*sock, info->subscriptions[ii]);
+ for(sub = info->subscriptions; sub!=NULL; sub=sub->next) {
+ zsocket_set_subscribe(*sock, sub->subscribe);
+ }
}
-
-
/* Do the bind/connect... */
if (info->action==ACTION_CONNECT) {
rv = zsocket_connect(*sock, info->description);
- if (rv < 0) {
+ if (rv == -1) {
errmsg.LogError(0,
RS_RET_INVALID_PARAMS,
"zmq_connect using %s failed: %s",
- info->description, strerror(errno));
+ info->description, zmq_strerror(errno));
return RS_RET_INVALID_PARAMS;
}
+ DBGPRINTF("imzmq3: connect for %s successful\n",info->description);
} else {
rv = zsocket_bind(*sock, info->description);
- if (rv <= 0) {
+ if (rv == -1) {
errmsg.LogError(0,
RS_RET_INVALID_PARAMS,
"zmq_bind using %s failed: %s",
- info->description, strerror(errno));
+ info->description, zmq_strerror(errno));
return RS_RET_INVALID_PARAMS;
}
+ DBGPRINTF("imzmq3: bind for %s successful\n",info->description);
}
return RS_RET_OK;
}
@@ -409,89 +429,138 @@ static rsRetVal createSocket(socket_info* info, void** sock) {
* Module endpoints
*/
-/* accept a new ruleset to bind. Checks if it exists and complains, if not. Note
- * that this makes the assumption that after the bind ruleset is called in the config,
- * another call will be made to add an endpoint.
-*/
-static rsRetVal
-set_ruleset(void __attribute__((unused)) *pVal, uchar *pszName) {
- ruleset_t* ruleset_ptr;
- rsRetVal localRet;
- DEFiRet;
-
- localRet = ruleset.GetRuleset(ourConf, &ruleset_ptr, pszName);
- if(localRet == RS_RET_NOT_FOUND) {
- errmsg.LogError(0, NO_ERRCODE, "error: "
- "ruleset '%s' not found - ignored", pszName);
- }
- CHKiRet(localRet);
- s_ruleset = ruleset_ptr;
- DBGPRINTF("imzmq3 current bind ruleset '%s'\n", pszName);
-
-finalize_it:
- free(pszName); /* no longer needed */
- RETiRet;
-}
/* add an actual endpoint
*/
-static rsRetVal add_endpoint(void __attribute__((unused)) * oldp, uchar * valp) {
+static rsRetVal createInstance(instanceConf_t** pinst) {
DEFiRet;
+ instanceConf_t* inst;
+ CHKmalloc(inst = MALLOC(sizeof(instanceConf_t)));
- /* increment number of items and store old num items, as it will be handy.*/
- size_t idx = s_nitems++;
-
- /* allocate a new socket_info array to accomidate this new endpoint*/
- socket_info* tmpSocketInfo;
- CHKmalloc(tmpSocketInfo = (socket_info*)MALLOC(sizeof(socket_info) * s_nitems));
+ /* set defaults into new instance config struct */
+ setDefaults(inst);
- /* copy existing socket_info across into new array, if any, and free old storage*/
- if(idx) {
- memcpy(tmpSocketInfo, s_socketInfo, sizeof(socket_info) * idx);
- free(s_socketInfo);
+ /* add this to the config */
+ if (runModConf->root == NULL || runModConf->tail == NULL) {
+ runModConf->tail = runModConf->root = inst;
+ } else {
+ runModConf->tail->next = inst;
+ runModConf->tail = inst;
}
+ *pinst = inst;
+finalize_it:
+ RETiRet;
+}
- /* set the static to hold the new array */
- s_socketInfo = tmpSocketInfo;
-
- /* point to the new one */
- socket_info* sockInfo = &s_socketInfo[idx];
-
- /* set defaults for the new socket info */
- setDefaults(sockInfo);
-
- /* Make a writeable copy of the string so we can use strtok
- in the parseConfig call */
- char * copy = NULL;
- CHKmalloc(copy = strdup((char *) valp));
+static rsRetVal createListener(struct cnfparamvals* pvals) {
+ instanceConf_t* inst;
+ int i;
+ DEFiRet;
- /* parse the config string */
- CHKiRet(parseConfig(copy, sockInfo));
+ CHKiRet(createInstance(&inst));
+ for(i = 0 ; i < inppblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(inppblk.descr[i].name, "ruleset")) {
+ inst->pszBindRuleset = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "description")) {
+ inst->description = es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "sockType")){
+ inst->type = getSocketType(es_str2cstr(pvals[i].val.d.estr, NULL));
+ } else if(!strcmp(inppblk.descr[i].name, "action")){
+ inst->action = getSocketAction(es_str2cstr(pvals[i].val.d.estr, NULL));
+ } else if(!strcmp(inppblk.descr[i].name, "sndHWM")) {
+ inst->sndHWM = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "rcvHWM")) {
+ inst->rcvHWM = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "subscribe")) {
+ CHKiRet(parseSubscriptions(es_str2cstr(pvals[i].val.d.estr, NULL),
+ &inst->subscriptions));
+ } else if(!strcmp(inppblk.descr[i].name, "identity")){
+ inst->identity = es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "sndBuf")) {
+ inst->sndBuf = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "rcvBuf")) {
+ inst->rcvBuf = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "linger")) {
+ inst->linger = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "backlog")) {
+ inst->backlog = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "sndTimeout")) {
+ inst->sndTimeout = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "rcvTimeout")) {
+ inst->rcvTimeout = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "maxMsgSize")) {
+ inst->maxMsgSize = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "rate")) {
+ inst->rate = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "recoveryIVL")) {
+ inst->recoveryIVL = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "multicastHops")) {
+ inst->multicastHops = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "reconnectIVL")) {
+ inst->reconnectIVL = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "reconnectIVLMax")) {
+ inst->reconnectIVLMax = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "ipv4Only")) {
+ inst->ipv4Only = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "affinity")) {
+ inst->affinity = (int) pvals[i].val.d.n;
+ } else {
+ errmsg.LogError(0, NO_ERRCODE, "imzmq3: program error, non-handled "
+ "param '%s'\n", inppblk.descr[i].name);
+ }
- /* validate it */
- CHKiRet(validateConfig(sockInfo));
+ }
+finalize_it:
+ RETiRet;
+}
+
+static rsRetVal addListener(instanceConf_t* inst){
+ /* create the socket */
+ void* sock;
+ struct lstn_s* newcnfinfo;
+ DEFiRet;
- /* bind to the current ruleset (if any)*/
- sockInfo->ruleset = s_ruleset;
+ CHKiRet(createSocket(inst, &sock));
+
+ /* now create new lstn_s struct */
+ CHKmalloc(newcnfinfo=(struct lstn_s*)MALLOC(sizeof(struct lstn_s)));
+ newcnfinfo->next = NULL;
+ newcnfinfo->sock = sock;
+ newcnfinfo->pRuleset = inst->pBindRuleset;
+ /* add this struct to the global */
+ if(lcnfRoot == NULL) {
+ lcnfRoot = newcnfinfo;
+ }
+ if(lcnfLast == NULL) {
+ lcnfLast = newcnfinfo;
+ } else {
+ lcnfLast->next = newcnfinfo;
+ lcnfLast = newcnfinfo;
+ }
+
finalize_it:
- free(valp); /* in any case, this is no longer needed */
- RETiRet;
+ RETiRet;
}
-
static int handlePoll(zloop_t __attribute__((unused)) * loop, zmq_pollitem_t *poller, void* pd) {
- msg_t* logmsg;
+ msg_t* pMsg;
poller_data* pollerData = (poller_data*)pd;
char* buf = zstr_recv(poller->socket);
- if (msgConstruct(&logmsg) == RS_RET_OK) {
- MsgSetRawMsg(logmsg, buf, strlen(buf));
- MsgSetInputName(logmsg, s_namep);
- MsgSetFlowControlType(logmsg, eFLOWCTL_NO_DELAY);
- MsgSetRuleset(logmsg, pollerData->ruleset);
- logmsg->msgFlags = NEEDS_PARSING;
- submitMsg(logmsg);
+ if (msgConstruct(&pMsg) == RS_RET_OK) {
+ MsgSetRawMsg(pMsg, buf, strlen(buf));
+ MsgSetInputName(pMsg, s_namep);
+ MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()));
+ MsgSetRcvFrom(pMsg, glbl.GetLocalHostNameProp());
+ MsgSetRcvFromIP(pMsg, glbl.GetLocalHostIP());
+ MsgSetMSGoffs(pMsg, 0);
+ MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY);
+ MsgSetRuleset(pMsg, pollerData->ruleset);
+ pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME;
+ submitMsg2(pMsg);
}
/* gotta free the string returned from zstr_recv() */
@@ -510,51 +579,65 @@ static int handlePoll(zloop_t __attribute__((unused)) * loop, zmq_pollitem_t *po
/* called when runInput is called by rsyslog
*/
static rsRetVal rcv_loop(thrdInfo_t* pThrd){
+ size_t n_items = 0;
size_t i;
int rv;
- zmq_pollitem_t* items;
- poller_data* pollerData;
-
+ zmq_pollitem_t* items = NULL;
+ poller_data* pollerData = NULL;
+ struct lstn_s* current;
+ instanceConf_t* inst;
DEFiRet;
-
- /* create the context*/
- CHKiRet(createContext());
+ /* now add listeners. This actually creates the sockets, etc... */
+ for (inst = runModConf->root; inst != NULL; inst=inst->next) {
+ addListener(inst);
+ }
+ if (lcnfRoot == NULL) {
+ errmsg.LogError(0, NO_ERRCODE, "imzmq3: no listeners were "
+ "started, input not activated.\n");
+ ABORT_FINALIZE(RS_RET_NO_RUN);
+ }
+
+ /* count the # of items first */
+ for(current=lcnfRoot;current!=NULL;current=current->next)
+ n_items++;
+
+ /* make arrays of pollitems, pollerdata so they are easy to delete later */
+
/* create the poll items*/
- CHKmalloc(items = (zmq_pollitem_t*)MALLOC(sizeof(zmq_pollitem_t)*s_nitems));
+ CHKmalloc(items = (zmq_pollitem_t*)MALLOC(sizeof(zmq_pollitem_t)*n_items));
/* create poller data (stuff to pass into the zmq closure called when we get a message)*/
- CHKmalloc(pollerData = (poller_data*)MALLOC(sizeof(poller_data)*s_nitems));
+ CHKmalloc(pollerData = (poller_data*)MALLOC(sizeof(poller_data)*n_items));
/* loop through and initialize the poll items and poller_data arrays...*/
- for(i=0; i<s_nitems;++i) {
+ for(i=0, current = lcnfRoot; current != NULL; current = current->next, i++) {
/* create the socket, update items.*/
- createSocket(&s_socketInfo[i], &items[i].socket);
+ items[i].socket=current->sock;
items[i].events = ZMQ_POLLIN;
/* now update the poller_data for this item */
pollerData[i].thread = pThrd;
- pollerData[i].ruleset = s_socketInfo[i].ruleset;
+ pollerData[i].ruleset = current->pRuleset;
}
-
+
s_zloop = zloop_new();
- for(i=0; i<s_nitems; ++i) {
+ for(i=0; i<n_items; ++i) {
rv = zloop_poller(s_zloop, &items[i], handlePoll, &pollerData[i]);
if (rv) {
- errmsg.LogError(0, NO_ERRCODE, "imzmq3: zloop_poller failed for item %zu", i);
+ errmsg.LogError(0, NO_ERRCODE, "imzmq3: zloop_poller failed for item %zu: %s", i, zmq_strerror(errno));
}
}
+ DBGPRINTF("imzmq3: zloop_poller starting...");
zloop_start(s_zloop);
zloop_destroy(&s_zloop);
- finalize_it:
- for(i=0; i< s_nitems; ++i) {
- zsocket_destroy(s_context, items[i].socket);
- }
-
+ DBGPRINTF("imzmq3: zloop_poller stopped.");
+finalize_it:
zctx_destroy(&s_context);
free(items);
+ free(pollerData);
RETiRet;
}
@@ -564,7 +647,8 @@ static rsRetVal rcv_loop(thrdInfo_t* pThrd){
BEGINrunInput
CODESTARTrunInput
- iRet = rcv_loop(pThrd);
+ CHKiRet(rcv_loop(pThrd));
+finalize_it:
RETiRet;
ENDrunInput
@@ -572,17 +656,13 @@ ENDrunInput
/* initialize and return if will run or not */
BEGINwillRun
CODESTARTwillRun
- /* we need to create the inputName property (only once during our
+ /* we need to create the inputName property (only once during our
lifetime) */
- CHKiRet(prop.Construct(&s_namep));
- CHKiRet(prop.SetString(s_namep,
+ CHKiRet(prop.Construct(&s_namep));
+ CHKiRet(prop.SetString(s_namep,
UCHAR_CONSTANT("imzmq3"),
sizeof("imzmq3") - 1));
- CHKiRet(prop.ConstructFinalize(s_namep));
-
-/* If there are no endpoints this is pointless ...*/
- if (s_nitems == 0)
- ABORT_FINALIZE(RS_RET_NO_RUN);
+ CHKiRet(prop.ConstructFinalize(s_namep));
finalize_it:
ENDwillRun
@@ -590,70 +670,207 @@ ENDwillRun
BEGINafterRun
CODESTARTafterRun
- /* do cleanup here */
- if(s_namep != NULL)
- prop.Destruct(&s_namep);
+ /* do cleanup here */
+ if (s_namep != NULL)
+ prop.Destruct(&s_namep);
ENDafterRun
BEGINmodExit
CODESTARTmodExit
- /* release what we no longer need */
- objRelease(errmsg, CORE_COMPONENT);
- objRelease(glbl, CORE_COMPONENT);
- objRelease(prop, CORE_COMPONENT);
+ /* release what we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
objRelease(ruleset, CORE_COMPONENT);
ENDmodExit
BEGINisCompatibleWithFeature
CODESTARTisCompatibleWithFeature
- if(eFeat == sFEATURENonCancelInputTermination)
- iRet = RS_RET_OK;
+ if (eFeat == sFEATURENonCancelInputTermination)
+ iRet = RS_RET_OK;
ENDisCompatibleWithFeature
+BEGINbeginCnfLoad
+CODESTARTbeginCnfLoad
+ /* After endCnfLoad() (BEGINendCnfLoad...ENDendCnfLoad) is called,
+ * the pModConf pointer must not be used to change the in-memory
+ * config object. It's safe to use the same pointer for accessing
+ * the config object until freeCnf() (BEGINfreeCnf...ENDfreeCnf). */
+ runModConf = pModConf;
+ runModConf->pConf = pConf;
+ /* init module config */
+ runModConf->io_threads = 0; /* 0 means don't set it */
+ENDbeginCnfLoad
+
+
+BEGINsetModCnf
+ struct cnfparamvals* pvals = NULL;
+ int i;
+CODESTARTsetModCnf
+ pvals = nvlstGetParams(lst, &modpblk, NULL);
+ if (NULL == pvals) {
+ errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "imzmq3: error processing module "
+ " config parameters ['module(...)']");
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ for (i=0; i < modpblk.nParams; ++i) {
+ if (!pvals[i].bUsed)
+ continue;
+ if (!strcmp(modpblk.descr[i].name, "ioThreads")) {
+ runModConf->io_threads = (int)pvals[i].val.d.n;
+ } else {
+ errmsg.LogError(0, RS_RET_INVALID_PARAMS,
+ "imzmq3: config error, unknown "
+ "param %s in setModCnf\n",
+ modpblk.descr[i].name);
+ }
+ }
+
+finalize_it:
+ if (pvals != NULL)
+ cnfparamvalsDestruct(pvals, &modpblk);
+ENDsetModCnf
+
+
+BEGINendCnfLoad
+CODESTARTendCnfLoad
+ /* Last chance to make changes to the in-memory config object for this
+ * input module. After this call, the config object must no longer be
+ * changed. */
+ if (pModConf != runModConf) {
+ errmsg.LogError(0, NO_ERRCODE, "imzmq3: pointer of in-memory config object has "
+ "changed - pModConf=%p, runModConf=%p", pModConf, runModConf);
+ }
+ assert(pModConf == runModConf);
+ENDendCnfLoad
+
+
+/* function to generate error message if framework does not find requested ruleset */
+static inline void
+std_checkRuleset_genErrMsg(__attribute__((unused)) modConfData_t *modConf, instanceConf_t *inst)
+{
+ errmsg.LogError(0, NO_ERRCODE, "imzmq3: ruleset '%s' for socket %s not found - "
+ "using default ruleset instead", inst->pszBindRuleset,
+ inst->description);
+}
+
+
+BEGINcheckCnf
+instanceConf_t* inst;
+CODESTARTcheckCnf
+ for(inst = pModConf->root; inst!=NULL; inst=inst->next) {
+ std_checkRuleset(pModConf, inst);
+ /* now, validate the instanceConf */
+ CHKiRet(validateConfig(inst));
+ }
+finalize_it:
+ RETiRet;
+ENDcheckCnf
+
+
+BEGINactivateCnfPrePrivDrop
+CODESTARTactivateCnfPrePrivDrop
+ if (pModConf != runModConf) {
+ errmsg.LogError(0, NO_ERRCODE, "imzmq3: pointer of in-memory config object has "
+ "changed - pModConf=%p, runModConf=%p", pModConf, runModConf);
+ }
+ assert(pModConf == runModConf);
+
+ /* first create the context */
+ createContext();
+
+ /* could setup context here, and set the global worker threads
+ and so on... */
+ENDactivateCnfPrePrivDrop
+
+
+BEGINactivateCnf
+CODESTARTactivateCnf
+ if (pModConf != runModConf) {
+ errmsg.LogError(0, NO_ERRCODE, "imzmq3: pointer of in-memory config object has "
+ "changed - pModConf=%p, runModConf=%p", pModConf, runModConf);
+ }
+ assert(pModConf == runModConf);
+ENDactivateCnf
+
+
+BEGINfreeCnf
+ struct lstn_s *lstn, *lstn_r;
+ instanceConf_t *inst, *inst_r;
+ sublist *sub, *sub_r;
+CODESTARTfreeCnf
+ DBGPRINTF("imzmq3: BEGINfreeCnf ...\n");
+ if (pModConf != runModConf) {
+ errmsg.LogError(0, NO_ERRCODE, "imzmq3: pointer of in-memory config object has "
+ "changed - pModConf=%p, runModConf=%p", pModConf, runModConf);
+ }
+ for (lstn = lcnfRoot; lstn != NULL; ) {
+ lstn_r = lstn;
+ lstn = lstn_r->next;
+ free(lstn_r);
+ }
+ for (inst = pModConf->root ; inst != NULL ; ) {
+ for (sub = inst->subscriptions; sub != NULL; ) {
+ free(sub->subscribe);
+ sub_r = sub;
+ sub = sub_r->next;
+ free(sub_r);
+ }
+ free(inst->pszBindRuleset);
+ inst_r = inst;
+ inst = inst->next;
+ free(inst_r);
+ }
+ENDfreeCnf
+
+
+BEGINnewInpInst
+ struct cnfparamvals* pvals;
+CODESTARTnewInpInst
+
+ DBGPRINTF("newInpInst (imzmq3)\n");
+ pvals = nvlstGetParams(lst, &inppblk, NULL);
+ if(NULL==pvals) {
+ errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS,
+ "imzmq3: required parameters are missing\n");
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+ DBGPRINTF("imzmq3: input param blk:\n");
+ cnfparamsPrint(&inppblk, pvals);
+
+ /* now, parse the config params and so on... */
+ CHKiRet(createListener(pvals));
+
+finalize_it:
+CODE_STD_FINALIZERnewInpInst
+ cnfparamvalsDestruct(pvals, &inppblk);
+ENDnewInpInst
+
+
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_IMOD_QUERIES
+CODEqueryEtryPt_STD_CONF2_QUERIES
+CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES
+CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES
+CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES
CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
ENDqueryEtryPt
-static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp,
- void __attribute__((unused)) *pVal) {
- return RS_RET_OK;
-}
-static rsRetVal setGlobalWorkerThreads(uchar __attribute__((unused)) *pp, int val) {
- errmsg.LogError(0, NO_ERRCODE, "setGlobalWorkerThreads called with %d",val);
- s_io_threads = val;
- return RS_RET_OK;
-}
BEGINmodInit()
CODESTARTmodInit
/* we only support the current interface specification */
- *ipIFVersProvided = CURR_MOD_IF_VERSION;
+ *ipIFVersProvided = CURR_MOD_IF_VERSION;
CODEmodInit_QueryRegCFSLineHdlr
- CHKiRet(objUse(errmsg, CORE_COMPONENT));
- CHKiRet(objUse(glbl, CORE_COMPONENT));
- CHKiRet(objUse(prop, CORE_COMPONENT));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
CHKiRet(objUse(ruleset, CORE_COMPONENT));
-
- /* register config file handlers */
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputzmq3serverbindruleset",
- 0, eCmdHdlrGetWord,
- set_ruleset, NULL,
- STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputzmq3serverrun",
- 0, eCmdHdlrGetWord,
- add_endpoint, NULL,
- STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables",
- 1, eCmdHdlrCustomHandler,
- resetConfigVariables, NULL,
- STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputzmq3globalWorkerThreads",
- 1, eCmdHdlrInt,
- setGlobalWorkerThreads, NULL,
- STD_LOADABLE_MODULE_ID));
ENDmodInit
+
+
diff --git a/plugins/mmaudit/Makefile.am b/plugins/mmaudit/Makefile.am
index c64d0822..77b2e85f 100644
--- a/plugins/mmaudit/Makefile.am
+++ b/plugins/mmaudit/Makefile.am
@@ -1,8 +1,8 @@
pkglib_LTLIBRARIES = mmaudit.la
mmaudit_la_SOURCES = mmaudit.c
-mmaudit_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(LIBLOGNORM_CFLAGS) $(LIBEE_CFLAGS)
-mmaudit_la_LDFLAGS = -module -avoid-version $(LIBLOGNORM_LIBS) $(LIBEE_LIBS)
+mmaudit_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+mmaudit_la_LDFLAGS = -module -avoid-version
mmaudit_la_LIBADD =
EXTRA_DIST =
diff --git a/plugins/mmaudit/mmaudit.c b/plugins/mmaudit/mmaudit.c
index 018e1771..6b6b804c 100644
--- a/plugins/mmaudit/mmaudit.c
+++ b/plugins/mmaudit/mmaudit.c
@@ -43,8 +43,7 @@
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
-#include <libestr.h>
-#include <libee/libee.h>
+#include <json/json.h>
#include "conf.h"
#include "syslogd-types.h"
#include "template.h"
diff --git a/plugins/mmcount/Makefile.am b/plugins/mmcount/Makefile.am
new file mode 100644
index 00000000..9c8c99db
--- /dev/null
+++ b/plugins/mmcount/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = mmcount.la
+
+mmcount_la_SOURCES = mmcount.c
+mmcount_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+mmcount_la_LDFLAGS = -module -avoid-version
+mmcount_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/mmcount/mmcount.c b/plugins/mmcount/mmcount.c
new file mode 100644
index 00000000..56a4de55
--- /dev/null
+++ b/plugins/mmcount/mmcount.c
@@ -0,0 +1,342 @@
+/* mmcount.c
+ * count messages by priority or json property of given app-name.
+ *
+ * Copyright 2013 Red Hat Inc.
+ *
+ * This file is part of rsyslog.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * -or-
+ * see COPYING.ASL20 in the source distribution
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <json/json.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "template.h"
+#include "module-template.h"
+#include "errmsg.h"
+#include "hashtable.h"
+
+#define JSON_COUNT_NAME "!mmcount"
+#define SEVERITY_COUNT 8
+
+MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
+MODULE_CNFNAME("mmcount")
+
+
+DEFobjCurrIf(errmsg);
+DEF_OMOD_STATIC_DATA
+
+/* config variables */
+
+typedef struct _instanceData {
+ char *pszAppName;
+ int severity[SEVERITY_COUNT];
+ char *pszKey;
+ char *pszValue;
+ int valueCounter;
+ struct hashtable *ht;
+} instanceData;
+
+struct modConfData_s {
+ rsconf_t *pConf; /* our overall config object */
+};
+static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
+static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */
+
+
+/* tables for interfacing with the v6 config system */
+/* action (instance) parameters */
+static struct cnfparamdescr actpdescr[] = {
+ { "appname", eCmdHdlrGetWord, 0 },
+ { "key", eCmdHdlrGetWord, 0 },
+ { "value", eCmdHdlrGetWord, 0 },
+};
+static struct cnfparamblk actpblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(actpdescr)/sizeof(struct cnfparamdescr),
+ actpdescr
+ };
+
+BEGINbeginCnfLoad
+CODESTARTbeginCnfLoad
+ loadModConf = pModConf;
+ pModConf->pConf = pConf;
+ENDbeginCnfLoad
+
+BEGINendCnfLoad
+CODESTARTendCnfLoad
+ENDendCnfLoad
+
+BEGINcheckCnf
+CODESTARTcheckCnf
+ENDcheckCnf
+
+BEGINactivateCnf
+CODESTARTactivateCnf
+ runModConf = pModConf;
+ENDactivateCnf
+
+BEGINfreeCnf
+CODESTARTfreeCnf
+ENDfreeCnf
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ENDfreeInstance
+
+
+static inline void
+setInstParamDefaults(instanceData *pData)
+{
+ int i;
+
+ pData->pszAppName = NULL;
+ for (i = 0; i < SEVERITY_COUNT; i++)
+ pData->severity[i] = 0;
+ pData->pszKey = NULL;
+ pData->pszValue = NULL;
+ pData->valueCounter = 0;
+ pData->ht = NULL;
+}
+
+static unsigned int
+hash_from_key_fn(void *k)
+{
+ return *(unsigned int *)k;
+}
+
+static int
+key_equals_fn(void *k1, void *k2)
+{
+ return (*(unsigned int *)k1 == *(unsigned int *)k2);
+}
+
+BEGINnewActInst
+ struct cnfparamvals *pvals;
+ int i;
+CODESTARTnewActInst
+ DBGPRINTF("newActInst (mmcount)\n");
+ if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) {
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ CODE_STD_STRING_REQUESTnewActInst(1)
+ CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG));
+ CHKiRet(createInstance(&pData));
+ setInstParamDefaults(pData);
+
+ for(i = 0 ; i < actpblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(actpblk.descr[i].name, "appname")) {
+ pData->pszAppName = es_str2cstr(pvals[i].val.d.estr, NULL);
+ continue;
+ }
+ if(!strcmp(actpblk.descr[i].name, "key")) {
+ pData->pszKey = es_str2cstr(pvals[i].val.d.estr, NULL);
+ continue;
+ }
+ if(!strcmp(actpblk.descr[i].name, "value")) {
+ pData->pszValue = es_str2cstr(pvals[i].val.d.estr, NULL);
+ continue;
+ }
+ dbgprintf("mmcount: program error, non-handled "
+ "param '%s'\n", actpblk.descr[i].name);
+ }
+
+ if(pData->pszAppName == NULL) {
+ dbgprintf("mmcount: action requires a appname");
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ if(pData->pszKey != NULL && pData->pszValue == NULL) {
+ if(NULL == (pData->ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, NULL))) {
+ DBGPRINTF("mmcount: error creating hash table!\n");
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ }
+CODE_STD_FINALIZERnewActInst
+ cnfparamvalsDestruct(pvals, &actpblk);
+ENDnewActInst
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ENDdbgPrintInstInfo
+
+
+BEGINtryResume
+CODESTARTtryResume
+ENDtryResume
+
+static int *
+getCounter(struct hashtable *ht, char *str) {
+ unsigned int key;
+ int *pCounter;
+ unsigned int *pKey;
+
+ /* we dont store str as key, instead we store hash of the str
+ as key to reduce memory usage */
+ key = hash_from_string(str);
+ pCounter = hashtable_search(ht, &key);
+ if(pCounter) {
+ return pCounter;
+ }
+
+ /* counter is not found for the str, so add new entry and
+ return the counter */
+ if(NULL == (pKey = (unsigned int*)malloc(sizeof(unsigned int)))) {
+ DBGPRINTF("mmcount: memory allocation for key failed\n");
+ return NULL;
+ }
+ *pKey = key;
+
+ if(NULL == (pCounter = (int*)malloc(sizeof(int)))) {
+ DBGPRINTF("mmcount: memory allocation for value failed\n");
+ free(pKey);
+ return NULL;
+ }
+ *pCounter = 0;
+
+ if(!hashtable_insert(ht, pKey, pCounter)) {
+ DBGPRINTF("mmcount: inserting element into hashtable failed\n");
+ free(pKey);
+ free(pCounter);
+ return NULL;
+ }
+ return pCounter;
+}
+
+BEGINdoAction
+ msg_t *pMsg;
+ char *appname;
+ struct json_object *json = NULL;
+ es_str_t *estr = NULL;
+ struct json_object *keyjson = NULL;
+ char *pszValue;
+ int *pCounter;
+CODESTARTdoAction
+ pMsg = (msg_t*) ppString[0];
+ appname = getAPPNAME(pMsg, LOCK_MUTEX);
+
+ if(0 != strcmp(appname, pData->pszAppName)) {
+ /* we are not working for this appname. nothing to do */
+ ABORT_FINALIZE(RS_RET_OK);
+ }
+
+ if(!pData->pszKey) {
+ /* no key given for count, so we count severity */
+ if(pMsg->iSeverity <= SEVERITY_COUNT) {
+ pData->severity[pMsg->iSeverity]++;
+ json = json_object_new_int(pData->severity[pMsg->iSeverity]);
+ }
+ ABORT_FINALIZE(RS_RET_OK);
+ }
+
+ /* key is given, so get the property json */
+ estr = es_newStrFromBuf(pData->pszKey, strlen(pData->pszKey));
+ if(msgGetCEEPropJSON(pMsg, estr, &keyjson) != RS_RET_OK) {
+ /* key not found in the message. nothing to do */
+ ABORT_FINALIZE(RS_RET_OK);
+ }
+
+ /* key found, so get the value */
+ pszValue = (char*)json_object_get_string(keyjson);
+
+ if(pData->pszValue) {
+ /* value also given for count */
+ if(!strcmp(pszValue, pData->pszValue)) {
+ /* count for (value and key and appname) matched */
+ pData->valueCounter++;
+ json = json_object_new_int(pData->valueCounter);
+ }
+ ABORT_FINALIZE(RS_RET_OK);
+ }
+
+ /* value is not given, so we count for each value of given key */
+ pCounter = getCounter(pData->ht, pszValue);
+ if(pCounter) {
+ (*pCounter)++;
+ json = json_object_new_int(*pCounter);
+ }
+finalize_it:
+ if(estr) {
+ es_deleteStr(estr);
+ }
+
+ if(json) {
+ msgAddJSON(pMsg, (uchar *)JSON_COUNT_NAME, json);
+ }
+ENDdoAction
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ if(strncmp((char*) p, ":mmcount:", sizeof(":mmcount:") - 1)) {
+ errmsg.LogError(0, RS_RET_LEGA_ACT_NOT_SUPPORTED,
+ "mmcount supports only v6+ config format, use: "
+ "action(type=\"mmcount\" ...)");
+ }
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+BEGINmodExit
+CODESTARTmodExit
+ objRelease(errmsg, CORE_COMPONENT);
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES
+CODEqueryEtryPt_STD_CONF2_QUERIES
+ENDqueryEtryPt
+
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ DBGPRINTF("mmcount: module compiled with rsyslog version %s.\n", VERSION);
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ENDmodInit
diff --git a/plugins/mmfields/Makefile.am b/plugins/mmfields/Makefile.am
new file mode 100644
index 00000000..08170d52
--- /dev/null
+++ b/plugins/mmfields/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = mmfields.la
+
+mmfields_la_SOURCES = mmfields.c
+mmfields_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+mmfields_la_LDFLAGS = -module -avoid-version
+mmfields_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/mmfields/mmfields.c b/plugins/mmfields/mmfields.c
new file mode 100644
index 00000000..99c78916
--- /dev/null
+++ b/plugins/mmfields/mmfields.c
@@ -0,0 +1,265 @@
+/* mmfields.c
+ * Parse all fields of the message into structured data inside the
+ * JSON tree.
+ *
+ * Copyright 2013 Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * -or-
+ * see COPYING.ASL20 in the source distribution
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "template.h"
+#include "module-template.h"
+#include "errmsg.h"
+
+MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
+MODULE_CNFNAME("mmfields")
+
+
+DEFobjCurrIf(errmsg);
+DEF_OMOD_STATIC_DATA
+
+/* config variables */
+
+/* define operation modes we have */
+#define SIMPLE_MODE 0 /* just overwrite */
+#define REWRITE_MODE 1 /* rewrite IP address, canoninized */
+typedef struct _instanceData {
+ char separator;
+} instanceData;
+
+struct modConfData_s {
+ rsconf_t *pConf; /* our overall config object */
+};
+static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
+static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */
+
+
+/* tables for interfacing with the v6 config system */
+/* action (instance) parameters */
+static struct cnfparamdescr actpdescr[] = {
+ { "separator", eCmdHdlrGetChar, 0 }
+};
+static struct cnfparamblk actpblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(actpdescr)/sizeof(struct cnfparamdescr),
+ actpdescr
+ };
+
+BEGINbeginCnfLoad
+CODESTARTbeginCnfLoad
+ loadModConf = pModConf;
+ pModConf->pConf = pConf;
+ENDbeginCnfLoad
+
+BEGINendCnfLoad
+CODESTARTendCnfLoad
+ENDendCnfLoad
+
+BEGINcheckCnf
+CODESTARTcheckCnf
+ENDcheckCnf
+
+BEGINactivateCnf
+CODESTARTactivateCnf
+ runModConf = pModConf;
+ENDactivateCnf
+
+BEGINfreeCnf
+CODESTARTfreeCnf
+ENDfreeCnf
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ENDfreeInstance
+
+
+static inline void
+setInstParamDefaults(instanceData *pData)
+{
+ pData->separator = ',';
+}
+
+BEGINnewActInst
+ struct cnfparamvals *pvals;
+ int i;
+CODESTARTnewActInst
+ DBGPRINTF("newActInst (mmfields)\n");
+ if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) {
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ CODE_STD_STRING_REQUESTnewActInst(1)
+ CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG));
+ CHKiRet(createInstance(&pData));
+ setInstParamDefaults(pData);
+
+ for(i = 0 ; i < actpblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(actpblk.descr[i].name, "separator")) {
+ pData->separator = es_getBufAddr(pvals[i].val.d.estr)[0];
+ } else {
+ dbgprintf("mmfields: program error, non-handled "
+ "param '%s'\n", actpblk.descr[i].name);
+ }
+ }
+
+CODE_STD_FINALIZERnewActInst
+ cnfparamvalsDestruct(pvals, &actpblk);
+ENDnewActInst
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ENDdbgPrintInstInfo
+
+
+BEGINtryResume
+CODESTARTtryResume
+ENDtryResume
+
+
+static inline rsRetVal
+extractField(instanceData *pData, uchar *msgtext, int lenMsg, int *curridx, uchar *fieldbuf)
+{
+ int i, j;
+ DEFiRet;
+ i = *curridx;
+ j = 0;
+ while(i < lenMsg && msgtext[i] != pData->separator) {
+ fieldbuf[j++] = msgtext[i++];
+ }
+ fieldbuf[j] = '\0';
+ if(i < lenMsg)
+ ++i;
+ *curridx = i;
+
+ RETiRet;
+}
+
+
+static inline rsRetVal
+parse_fields(instanceData *pData, msg_t *pMsg, uchar *msgtext, int lenMsg)
+{
+ uchar fieldbuf[32*1024];
+ uchar fieldname[512];
+ struct json_object *json;
+ struct json_object *jval;
+ int field;
+ uchar *buf;
+ int currIdx = 0;
+ DEFiRet;
+
+ if(lenMsg < (int) sizeof(fieldbuf)) {
+ buf = fieldbuf;
+ } else {
+ CHKmalloc(buf = malloc(lenMsg+1));
+ }
+
+ json = json_object_new_object();
+ if(json == NULL) {
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ field = 1;
+ while(currIdx < lenMsg) {
+ CHKiRet(extractField(pData, msgtext, lenMsg, &currIdx, buf));
+ DBGPRINTF("mmfields: field %d: '%s'\n", field, buf);
+ snprintf(fieldname, sizeof(fieldname), "f%d", (char*)field);
+ fieldname[sizeof(fieldname)-1] = '\0';
+ jval = json_object_new_string((char*)fieldbuf);
+ json_object_object_add(json, (char*)fieldname, jval);
+ field++;
+ }
+ msgAddJSON(pMsg, (uchar*)"!", json);
+finalize_it:
+ RETiRet;
+}
+
+
+BEGINdoAction
+ msg_t *pMsg;
+ uchar *msg;
+ int lenMsg;
+CODESTARTdoAction
+ pMsg = (msg_t*) ppString[0];
+ lenMsg = getMSGLen(pMsg);
+ msg = getMSG(pMsg);
+ CHKiRet(parse_fields(pData, pMsg, msg, lenMsg));
+finalize_it:
+ENDdoAction
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ if(strncmp((char*) p, ":mmfields:", sizeof(":mmfields:") - 1)) {
+ errmsg.LogError(0, RS_RET_LEGA_ACT_NOT_SUPPORTED,
+ "mmfields supports only v6+ config format, use: "
+ "action(type=\"mmfields\" ...)");
+ }
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+BEGINmodExit
+CODESTARTmodExit
+ objRelease(errmsg, CORE_COMPONENT);
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES
+CODEqueryEtryPt_STD_CONF2_QUERIES
+ENDqueryEtryPt
+
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ DBGPRINTF("mmfields: module compiled with rsyslog version %s.\n", VERSION);
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ENDmodInit
diff --git a/plugins/mmjsonparse/Makefile.am b/plugins/mmjsonparse/Makefile.am
index 5175fe81..ef39163e 100644
--- a/plugins/mmjsonparse/Makefile.am
+++ b/plugins/mmjsonparse/Makefile.am
@@ -1,8 +1,8 @@
pkglib_LTLIBRARIES = mmjsonparse.la
mmjsonparse_la_SOURCES = mmjsonparse.c
-mmjsonparse_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(LIBLOGNORM_CFLAGS) $(LIBEE_CFLAGS)
-mmjsonparse_la_LDFLAGS = -module -avoid-version $(LIBLOGNORM_LIBS) $(LIBEE_LIBS)
+mmjsonparse_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+mmjsonparse_la_LDFLAGS = -module -avoid-version
mmjsonparse_la_LIBADD =
EXTRA_DIST =
diff --git a/plugins/mmjsonparse/mmjsonparse.c b/plugins/mmjsonparse/mmjsonparse.c
index c47aceb6..35f69aab 100644
--- a/plugins/mmjsonparse/mmjsonparse.c
+++ b/plugins/mmjsonparse/mmjsonparse.c
@@ -35,7 +35,6 @@
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
-#include <libestr.h>
#include <json/json.h>
#include "conf.h"
#include "syslogd-types.h"
diff --git a/plugins/omjournal/omjournal.c b/plugins/omjournal/omjournal.c
index c340287f..160c369d 100644
--- a/plugins/omjournal/omjournal.c
+++ b/plugins/omjournal/omjournal.c
@@ -107,6 +107,7 @@ CODESTARTnewActInst
* the lst ptr. However, we will most probably need params in the
* future.
*/
+ (void) lst; /* prevent compiler warning */
DBGPRINTF("newActInst (mmjournal)\n");
CODE_STD_STRING_REQUESTnewActInst(1)
CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG));
@@ -145,6 +146,7 @@ CODESTARTdoAction
"SYSLOG_IDENTIFIER=%s", tag,
NULL);
/* FIXME: think about what to do with errors ;) */
+ (void) r; /* prevent compiler warning */
ENDdoAction
diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c
index c9e32444..50f6f905 100644
--- a/plugins/omrelp/omrelp.c
+++ b/plugins/omrelp/omrelp.c
@@ -55,16 +55,22 @@ DEF_OMOD_STATIC_DATA
DEFobjCurrIf(errmsg)
DEFobjCurrIf(glbl)
+#define DFLT_ENABLE_TLS 0
+#define DFLT_ENABLE_TLSZIP 0
+
static relpEngine_t *pRelpEngine; /* our relp engine */
typedef struct _instanceData {
uchar *target;
- int compressionLevel; /* 0 - no compression, else level for zlib */
uchar *port;
int bInitialConnect; /* is this the initial connection request of our module? (0-no, 1-yes) */
int bIsConnected; /* currently connected to server? 0 - no, 1 - yes */
unsigned timeout;
+ unsigned rebindInterval;
+ unsigned nSent;
relpClt_t *pRelpClt; /* relp client for this instance */
+ sbool bEnableTLS;
+ sbool bEnableTLSZip;
uchar *tplName;
} instanceData;
@@ -78,7 +84,10 @@ static configSettings_t __attribute__((unused)) cs;
/* action (instance) parameters */
static struct cnfparamdescr actpdescr[] = {
{ "target", eCmdHdlrGetWord, 1 },
+ { "tls", eCmdHdlrBinary, 0 },
+ { "tls.compression", eCmdHdlrBinary, 0 },
{ "port", eCmdHdlrGetWord, 0 },
+ { "rebindinterval", eCmdHdlrInt, 0 },
{ "timeout", eCmdHdlrInt, 0 },
{ "template", eCmdHdlrGetWord, 1 }
};
@@ -113,6 +122,20 @@ doCreateRelpClient(instanceData *pData)
ABORT_FINALIZE(RS_RET_RELP_ERR);
if(relpCltSetTimeout(pData->pRelpClt, pData->timeout) != RELP_RET_OK)
ABORT_FINALIZE(RS_RET_RELP_ERR);
+ if(pData->bEnableTLS) {
+ if(relpCltEnableTLS(pData->pRelpClt) != RELP_RET_OK)
+ ABORT_FINALIZE(RS_RET_RELP_ERR);
+ if(pData->bEnableTLSZip) {
+ if(relpCltEnableTLSZip(pData->pRelpClt) != RELP_RET_OK)
+ ABORT_FINALIZE(RS_RET_RELP_ERR);
+ }
+ }
+ if(glbl.GetSourceIPofLocalClient() == NULL) { /* ar Do we have a client IP set? */
+ if(relpCltSetClientIP(pData->pRelpClt, glbl.GetSourceIPofLocalClient()) != RELP_RET_OK)
+ ABORT_FINALIZE(RS_RET_RELP_ERR);
+ }
+ pData->bInitialConnect = 1;
+ pData->nSent = 0;
finalize_it:
RETiRet;
}
@@ -120,7 +143,10 @@ finalize_it:
BEGINcreateInstance
CODESTARTcreateInstance
- pData->bInitialConnect = 1;
+ pData->timeout = 90;
+ pData->rebindInterval = 0;
+ pData->bEnableTLS = DFLT_ENABLE_TLS;
+ pData->bEnableTLSZip = DFLT_ENABLE_TLSZIP;
ENDcreateInstance
BEGINfreeInstance
@@ -139,6 +165,9 @@ setInstParamDefaults(instanceData *pData)
pData->port = NULL;
pData->tplName = NULL;
pData->timeout = 90;
+ pData->rebindInterval = 0;
+ pData->bEnableTLS = DFLT_ENABLE_TLS;
+ pData->bEnableTLSZip = DFLT_ENABLE_TLSZIP;
}
@@ -164,6 +193,12 @@ CODESTARTnewActInst
pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(actpblk.descr[i].name, "timeout")) {
pData->timeout = (unsigned) pvals[i].val.d.n;
+ } else if(!strcmp(actpblk.descr[i].name, "rebindinterval")) {
+ pData->rebindInterval = (unsigned) pvals[i].val.d.n;
+ } else if(!strcmp(actpblk.descr[i].name, "tls")) {
+ pData->bEnableTLS = (unsigned) pvals[i].val.d.n;
+ } else if(!strcmp(actpblk.descr[i].name, "tls.compression")) {
+ pData->bEnableTLSZip = (unsigned) pvals[i].val.d.n;
} else {
dbgprintf("omrelp: program error, non-handled "
"param '%s'\n", actpblk.descr[i].name);
@@ -232,6 +267,17 @@ CODESTARTtryResume
iRet = doConnect(pData);
ENDtryResume
+static inline rsRetVal
+doRebind(instanceData *pData)
+{
+ DEFiRet;
+ DBGPRINTF("omrelp: destructing relp client due to rebindInterval\n");
+ CHKiRet(relpEngineCltDestruct(pRelpEngine, &pData->pRelpClt));
+ pData->bIsConnected = 0;
+ CHKiRet(doCreateRelpClient(pData));
+finalize_it:
+ RETiRet;
+}
BEGINdoAction
uchar *pMsg; /* temporary buffering */
@@ -247,7 +293,7 @@ CODESTARTdoAction
pMsg = ppString[0];
lenMsg = strlen((char*) pMsg); /* TODO: don't we get this? */
- /* TODO: think about handling oversize messages! */
+ /* we need to truncate oversize msgs - no way around that... */
if((int) lenMsg > glbl.GetMaxLine())
lenMsg = glbl.GetMaxLine();
@@ -256,9 +302,13 @@ CODESTARTdoAction
if(ret != RELP_RET_OK) {
/* error! */
dbgprintf("error forwarding via relp, suspending\n");
- iRet = RS_RET_SUSPENDED;
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
}
+ if(pData->rebindInterval != 0 &&
+ (++pData->nSent >= pData->rebindInterval)) {
+ doRebind(pData);
+ }
finalize_it:
ENDdoAction
@@ -279,62 +329,6 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
if((iRet = createInstance(&pData)) != RS_RET_OK)
FINALIZE;
- /* we are now after the protocol indicator. Now check if we should
- * use compression. We begin to use a new option format for this:
- * @(option,option)host:port
- * The first option defined is "z[0..9]" where the digit indicates
- * the compression level. If it is not given, 9 (best compression) is
- * assumed. An example action statement might be:
- * :omrelp:(z5,o)127.0.0.1:1400
- * Which means send via TCP with medium (5) compresion (z) to the local
- * host on port 1400. The '0' option means that octet-couting (as in
- * IETF I-D syslog-transport-tls) is to be used for framing (this option
- * applies to TCP-based syslog only and is ignored when specified with UDP).
- * That is not yet implemented.
- * rgerhards, 2006-12-07
- * TODO: think of all this in spite of RELP -- rgerhards, 2008-03-13
- */
- if(*p == '(') {
- /* at this position, it *must* be an option indicator */
- do {
- ++p; /* eat '(' or ',' (depending on when called) */
- /* check options */
- if(*p == 'z') { /* compression */
-# ifdef USE_NETZIP
- ++p; /* eat */
- if(isdigit((int) *p)) {
- int iLevel;
- iLevel = *p - '0';
- ++p; /* eat */
- pData->compressionLevel = iLevel;
- } else {
- errmsg.LogError(0, NO_ERRCODE, "Invalid compression level '%c' specified in "
- "forwardig action - NOT turning on compression.",
- *p);
- }
-# else
- errmsg.LogError(0, NO_ERRCODE, "Compression requested, but rsyslogd is not compiled "
- "with compression support - request ignored.");
-# endif /* #ifdef USE_NETZIP */
- } else { /* invalid option! Just skip it... */
- errmsg.LogError(0, NO_ERRCODE, "Invalid option %c in forwarding action - ignoring.", *p);
- ++p; /* eat invalid option */
- }
- /* the option processing is done. We now do a generic skip
- * to either the next option or the end of the option
- * block.
- */
- while(*p && *p != ')' && *p != ',')
- ++p; /* just skip it */
- } while(*p && *p == ','); /* Attention: do.. while() */
- if(*p == ')')
- ++p; /* eat terminator, on to next */
- else
- /* we probably have end of string - leave it for the rest
- * of the code to handle it (but warn the user)
- */
- errmsg.LogError(0, NO_ERRCODE, "Option block not terminated in forwarding action.");
- }
/* extract the host first (we do a trick - we replace the ';' or ':' with a '\0')
* now skip to port and then template name. rgerhards 2005-07-06
*/
@@ -384,7 +378,6 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
++p;
}
- /* TODO: make this if go away! */
if(*p == ';') {
*p = '\0'; /* trick to obtain hostname (later)! */
CHKmalloc(pData->target = ustrdup(q));
diff --git a/plugins/omzmq3/README b/plugins/omzmq3/README
index ccc96c74..c2a33555 100644
--- a/plugins/omzmq3/README
+++ b/plugins/omzmq3/README
@@ -1,16 +1,10 @@
ZeroMQ 3.x Output Plugin
Building this plugin:
-Requires libzmq and libczmq. First, install libzmq from the HEAD on github:
-http://github.com/zeromq/libzmq. You can clone the repository, build, then
-install it. The directions for doing so are there in the readme. Then, do
-the same for libczmq: http://github.com/zeromq/czmq. At some point, the 3.1
-version of libzmq will be released, and a supporting version of libczmq.
-At that time, you could simply download and install the tarballs instead of
-using git to clone the repositories. Those tarballs (when available) can
-be found at http://download.zeromq.org. As of this writing (5/31/2012), the
-most recent version of czmq (1.1.0) and libzmq (3.1.0-beta) will not compile
-properly.
+Requires libzmq and libczmq. First, download the tarballs of both libzmq
+and its supporting libczmq from http://download.zeromq.org. As of this
+writing (04/23/2013), the most recent versions of libzmq and czmq are
+3.2.2 and 1.3.2 respectively. Configure, build, and then install both libs.
Omzmq3 allows you to push data out of rsyslog from a zeromq socket. The example
below binds a PUB socket to port 7171, and any message fitting the criteria will
diff --git a/plugins/omzmq3/omzmq3.c b/plugins/omzmq3/omzmq3.c
index ee6756b9..c8552f11 100644
--- a/plugins/omzmq3/omzmq3.c
+++ b/plugins/omzmq3/omzmq3.c
@@ -110,9 +110,10 @@ static zctx_t* s_context = NULL;
static int s_workerThreads = -1;
static struct socket_type types[] = {
- {"PUB", ZMQ_PUB },
- {"PUSH", ZMQ_PUSH },
- {"XPUB", ZMQ_XPUB }
+ {"PUB", ZMQ_PUB },
+ {"PUSH", ZMQ_PUSH },
+ {"DEALER", ZMQ_DEALER },
+ {"XPUB", ZMQ_XPUB }
};
static struct socket_action actions[] = {
@@ -201,17 +202,18 @@ static rsRetVal initZMQ(instanceData* pData) {
/* create the context if necessary. */
if (NULL == s_context) {
+ zsys_handler_set(NULL);
s_context = zctx_new();
if (s_workerThreads > 0) zctx_set_iothreads(s_context, s_workerThreads);
}
pData->socket = zsocket_new(s_context, pData->type);
-
- /* ALWAYS set the HWM as the zmq3 default is 1000 and we default
- to 0 (infinity) */
- zsocket_set_rcvhwm(pData->socket, pData->rcvHWM);
- zsocket_set_sndhwm(pData->socket, pData->sndHWM);
-
+ if (NULL == pData->socket) {
+ errmsg.LogError(0, RS_RET_NO_ERRCODE,
+ "omzmq3: zsocket_new failed for %s: %s",
+ pData->description, zmq_strerror(errno));
+ ABORT_FINALIZE(RS_RET_NO_ERRCODE);
+ }
/* use czmq defaults for these, unless set to non-default values */
if(pData->identity) zsocket_set_identity(pData->socket, (char*)pData->identity);
if(pData->sndBuf > -1) zsocket_set_sndbuf(pData->socket, pData->sndBuf);
@@ -228,17 +230,26 @@ static rsRetVal initZMQ(instanceData* pData) {
if(pData->reconnectIVLMax > -1) zsocket_set_reconnect_ivl_max(pData->socket, pData->reconnectIVLMax);
if(pData->ipv4Only > -1) zsocket_set_ipv4only(pData->socket, pData->ipv4Only);
if(pData->affinity != 1) zsocket_set_affinity(pData->socket, pData->affinity);
-
+ if(pData->rcvHWM > -1) zsocket_set_rcvhwm(pData->socket, pData->rcvHWM);
+ if(pData->sndHWM > -1) zsocket_set_sndhwm(pData->socket, pData->sndHWM);
+
/* bind or connect to it */
if (pData->action == ACTION_BIND) {
/* bind asserts, so no need to test return val here
which isn't the greatest api -- oh well */
- zsocket_bind(pData->socket, (char*)pData->description);
+ if(-1 == zsocket_bind(pData->socket, (char*)pData->description)) {
+ errmsg.LogError(0, RS_RET_NO_ERRCODE, "omzmq3: bind failed for %s: %s",
+ pData->description, zmq_strerror(errno));
+ ABORT_FINALIZE(RS_RET_NO_ERRCODE);
+ }
+ DBGPRINTF("omzmq3: bind to %s successful\n",pData->description);
} else {
- if(zsocket_connect(pData->socket, (char*)pData->description) == -1) {
- errmsg.LogError(0, RS_RET_SUSPENDED, "omzmq3: connect failed!");
- ABORT_FINALIZE(RS_RET_SUSPENDED);
+ if(-1 == zsocket_connect(pData->socket, (char*)pData->description)) {
+ errmsg.LogError(0, RS_RET_NO_ERRCODE, "omzmq3: connect failed for %s: %s",
+ pData->description, zmq_strerror(errno));
+ ABORT_FINALIZE(RS_RET_NO_ERRCODE);
}
+ DBGPRINTF("omzmq3: connect to %s successful", pData->description);
}
finalize_it:
RETiRet;
@@ -256,7 +267,7 @@ rsRetVal writeZMQ(uchar* msg, instanceData* pData) {
/* whine if things went wrong */
if (result == -1) {
- errmsg.LogError(0, NO_ERRCODE, "omzmq3: send of %s failed with return %d", msg, result);
+ errmsg.LogError(0, NO_ERRCODE, "omzmq3: send of %s failed: %s", msg, zmq_strerror(errno));
ABORT_FINALIZE(RS_RET_ERR);
}
finalize_it:
@@ -265,13 +276,13 @@ rsRetVal writeZMQ(uchar* msg, instanceData* pData) {
static inline void
setInstParamDefaults(instanceData* pData) {
- pData->description = (uchar*)"tcp://*:7171";
+ pData->description = NULL;
pData->socket = NULL;
pData->tplName = NULL;
pData->type = ZMQ_PUB;
pData->action = ACTION_BIND;
- pData->sndHWM = 0; /*unlimited*/
- pData->rcvHWM = 0; /*unlimited*/
+ pData->sndHWM = -1;
+ pData->rcvHWM = -1;
pData->identity = NULL;
pData->sndBuf = -1;
pData->rcvBuf = -1;
@@ -314,6 +325,7 @@ CODESTARTfreeInstance
closeZMQ(pData);
free(pData->description);
free(pData->tplName);
+ free(pData->identity);
ENDfreeInstance
BEGINtryResume
@@ -329,88 +341,90 @@ ENDdoAction
BEGINnewActInst
- struct cnfparamvals *pvals;
- int i;
+ struct cnfparamvals *pvals;
+ int i;
CODESTARTnewActInst
-if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) {
- ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
- }
+ if ((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) {
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
CHKiRet(createInstance(&pData));
setInstParamDefaults(pData);
CODE_STD_STRING_REQUESTnewActInst(1)
-for(i = 0 ; i < actpblk.nParams ; ++i) {
- if(!pvals[i].bUsed)
- continue;
- if(!strcmp(actpblk.descr[i].name, "description")) {
- pData->description = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
- } else if(!strcmp(actpblk.descr[i].name, "template")) {
- pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
- } else if(!strcmp(actpblk.descr[i].name, "sockType")){
- pData->type = getSocketType(es_str2cstr(pvals[i].val.d.estr, NULL));
- } else if(!strcmp(actpblk.descr[i].name, "action")){
- pData->action = getSocketAction(es_str2cstr(pvals[i].val.d.estr, NULL));
- } else if(!strcmp(actpblk.descr[i].name, "sndHWM")) {
- pData->sndHWM = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "rcvHWM")) {
- pData->rcvHWM = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "identity")){
- pData->identity = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
- } else if(!strcmp(actpblk.descr[i].name, "sndBuf")) {
- pData->sndBuf = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "rcvBuf")) {
- pData->rcvBuf = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "linger")) {
- pData->linger = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "backlog")) {
- pData->backlog = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "sndTimeout")) {
- pData->sndTimeout = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "rcvTimeout")) {
- pData->rcvTimeout = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "maxMsgSize")) {
- pData->maxMsgSize = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "rate")) {
- pData->rate = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "recoveryIVL")) {
- pData->recoveryIVL = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "multicastHops")) {
- pData->multicastHops = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "reconnectIVL")) {
- pData->reconnectIVL = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "reconnectIVLMax")) {
- pData->reconnectIVLMax = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "ipv4Only")) {
- pData->ipv4Only = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "affinity")) {
- pData->affinity = (int) pvals[i].val.d.n;
- } else if(!strcmp(actpblk.descr[i].name, "globalWorkerThreads")) {
- s_workerThreads = (int) pvals[i].val.d.n;
- } else {
- errmsg.LogError(0, NO_ERRCODE, "omzmq3: program error, non-handled "
- "param '%s'\n", actpblk.descr[i].name);
+ for (i = 0; i < actpblk.nParams; ++i) {
+ if (!pvals[i].bUsed)
+ continue;
+ if (!strcmp(actpblk.descr[i].name, "description")) {
+ pData->description = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if (!strcmp(actpblk.descr[i].name, "template")) {
+ pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if (!strcmp(actpblk.descr[i].name, "sockType")){
+ pData->type = getSocketType(es_str2cstr(pvals[i].val.d.estr, NULL));
+ } else if (!strcmp(actpblk.descr[i].name, "action")){
+ pData->action = getSocketAction(es_str2cstr(pvals[i].val.d.estr, NULL));
+ } else if (!strcmp(actpblk.descr[i].name, "sndHWM")) {
+ pData->sndHWM = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "rcvHWM")) {
+ pData->rcvHWM = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "identity")){
+ pData->identity = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if (!strcmp(actpblk.descr[i].name, "sndBuf")) {
+ pData->sndBuf = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "rcvBuf")) {
+ pData->rcvBuf = (int) pvals[i].val.d.n;
+ } else if(!strcmp(actpblk.descr[i].name, "linger")) {
+ pData->linger = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "backlog")) {
+ pData->backlog = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "sndTimeout")) {
+ pData->sndTimeout = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "rcvTimeout")) {
+ pData->rcvTimeout = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "maxMsgSize")) {
+ pData->maxMsgSize = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "rate")) {
+ pData->rate = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "recoveryIVL")) {
+ pData->recoveryIVL = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "multicastHops")) {
+ pData->multicastHops = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "reconnectIVL")) {
+ pData->reconnectIVL = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "reconnectIVLMax")) {
+ pData->reconnectIVLMax = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "ipv4Only")) {
+ pData->ipv4Only = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "affinity")) {
+ pData->affinity = (int) pvals[i].val.d.n;
+ } else if (!strcmp(actpblk.descr[i].name, "globalWorkerThreads")) {
+ s_workerThreads = (int) pvals[i].val.d.n;
+ } else {
+ errmsg.LogError(0, NO_ERRCODE, "omzmq3: program error, non-handled "
+ "param '%s'\n", actpblk.descr[i].name);
+ }
}
- }
-
-if(pData->tplName == NULL) {
- CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG));
- } else {
- CHKiRet(OMSRsetEntry(*ppOMSR, 0, (uchar*)pData->tplName, OMSR_NO_RQD_TPL_OPTS));
- }
-
-if(pData->type == -1) {
- errmsg.LogError(0, RS_RET_CONFIG_ERROR, "omzmq3: unknown socket type.");
- ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
- }
-if(pData->action == -1) {
- errmsg.LogError(0, RS_RET_CONFIG_ERROR, "omzmq3: unknown socket action");
- ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
- }
+ if (pData->tplName == NULL) {
+ CHKiRet(OMSRsetEntry(*ppOMSR, 0, (uchar*)strdup("RSYSLOG_ForwardFormat"), OMSR_NO_RQD_TPL_OPTS));
+ } else {
+ CHKiRet(OMSRsetEntry(*ppOMSR, 0, (uchar*)pData->tplName, OMSR_NO_RQD_TPL_OPTS));
+ }
+ if (NULL == pData->description) {
+ errmsg.LogError(0, RS_RET_CONFIG_ERROR, "omzmq3: you didn't enter a description");
+ ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
+ }
+ if (pData->type == -1) {
+ errmsg.LogError(0, RS_RET_CONFIG_ERROR, "omzmq3: unknown socket type.");
+ ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
+ }
+ if (pData->action == -1) {
+ errmsg.LogError(0, RS_RET_CONFIG_ERROR, "omzmq3: unknown socket action");
+ ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
+ }
CODE_STD_FINALIZERnewActInst
- cnfparamvalsDestruct(pvals, &actpblk);
+ cnfparamvalsDestruct(pvals, &actpblk);
ENDnewActInst
BEGINparseSelectorAct
@@ -433,10 +447,10 @@ ENDinitConfVars
BEGINmodExit
CODESTARTmodExit
-if(NULL != s_context) {
- zctx_destroy(&s_context);
- s_context=NULL;
- }
+ if (NULL != s_context) {
+ zctx_destroy(&s_context);
+ s_context=NULL;
+ }
ENDmodExit
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index fe4afb09..dea06fe0 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -97,12 +97,12 @@ librsyslog_la_SOURCES = \
#
if WITH_MODDIRS
-librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) $(LIBGCRYPT_CFLAGS) -I\$(top_srcdir)/tools
+librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) -I\$(top_srcdir)/tools
else
-librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) $(LIBGCRYPT_CFLAGS) -I\$(top_srcdir)/tools -I\$(top_srcdir)/grammar
+librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) -I\$(top_srcdir)/tools -I\$(top_srcdir)/grammar
endif
#librsyslog_la_LDFLAGS = -module -avoid-version
-librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS) $(LIBGCRYPT_LIBS) $(LIBEE_LIBS)
+librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS)
#
# regular expression support
diff --git a/runtime/conf.c b/runtime/conf.c
index c97391c6..c3c7e447 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -129,6 +129,23 @@ finalize_it:
}
+/* remove leading spaces from name; this "fixes" some anomalies in
+ * getSubString(), but I was not brave enough to fix the former as
+ * it has many other callers... -- rgerhards, 2013-05-27
+ */
+static inline void
+ltrim(char *src)
+{
+ char *dst = src;
+ while(isspace(*src))
+ ++src; /*SKIP*/;
+ if(dst != src) {
+ while(*src != '\0')
+ *dst++ = *src++;
+ *dst = '\0';
+ }
+}
+
/* parse and interpret a $-config line that starts with
* a name (this is common code). It is parsed to the name
* and then the proper sub-function is called to handle
@@ -155,6 +172,7 @@ doNameLine(uchar **pp, void* pVal)
errmsg.LogError(0, RS_RET_NOT_FOUND, "Invalid config line: could not extract name - line ignored");
ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
+ ltrim(szName);
if(*p == ',')
++p; /* comma was eaten */
diff --git a/runtime/cryprov.h b/runtime/cryprov.h
index 8496b745..5690904d 100644
--- a/runtime/cryprov.h
+++ b/runtime/cryprov.h
@@ -26,14 +26,25 @@
#include <gcrypt.h>
+/* we unfortunately need to have two different param names depending on the
+ * context in which parameters are set. Other than (re/over)engineering the core
+ * interface, we just define some values to keep track of that.
+ */
+#define CRYPROV_PARAMTYPE_REGULAR 0
+#define CRYPROV_PARAMTYPE_DISK 1
+
/* interface */
BEGINinterface(cryprov) /* name must also be changed in ENDinterface macro! */
rsRetVal (*Construct)(void *ppThis);
- rsRetVal (*SetCnfParam)(void *ppThis, struct nvlst *lst);
+ rsRetVal (*SetCnfParam)(void *ppThis, struct nvlst *lst, int paramType);
rsRetVal (*Destruct)(void *ppThis);
- rsRetVal (*OnFileOpen)(void *pThis, uchar *fn, void *pFileInstData);
+ rsRetVal (*OnFileOpen)(void *pThis, uchar *fn, void *pFileInstData, char openMode);
rsRetVal (*Encrypt)(void *pFileInstData, uchar *buf, size_t *lenBuf);
+ rsRetVal (*Decrypt)(void *pFileInstData, uchar *buf, size_t *lenBuf);
rsRetVal (*OnFileClose)(void *pFileInstData, off64_t offsLogfile);
+ rsRetVal (*DeleteStateFiles)(uchar *logfn);
+ rsRetVal (*GetBytesLeftInBlock)(void *pFileInstData, ssize_t *left);
+ void (*SetDeleteOnClose)(void *pFileInstData, int val);
ENDinterface(cryprov)
-#define cryprovCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+#define cryprovCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */
#endif /* #ifndef INCLUDED_CRYPROV_H */
diff --git a/runtime/debug.c b/runtime/debug.c
index 876f61d0..68474989 100644
--- a/runtime/debug.c
+++ b/runtime/debug.c
@@ -1430,6 +1430,7 @@ dbgSetDebugFile(uchar *fn)
rsRetVal dbgClassInit(void)
{
+ pthread_mutexattr_t mutAttr;
rsRetVal iRet; /* do not use DEFiRet, as this makes calls into the debug system! */
struct sigaction sigAct;
@@ -1437,14 +1438,16 @@ rsRetVal dbgClassInit(void)
(void) pthread_key_create(&keyCallStack, dbgCallStackDestruct); /* MUST be the first action done! */
- /* we initialize all Mutexes with code, as some platforms seem to have
- * bugs in the static initializer macros. So better be on the safe side...
- * rgerhards, 2008-03-06
+ /* the mutexes must be recursive, because it may be called from within
+ * signal handlers, which can lead to a hang if the signal interrupted dbgprintf
+ * (yes, we have really seen that situation in practice!). -- rgerhards, 2013-05-17
*/
- pthread_mutex_init(&mutFuncDBList, NULL);
- pthread_mutex_init(&mutMutLog, NULL);
- pthread_mutex_init(&mutCallStack, NULL);
- pthread_mutex_init(&mutdbgprint, NULL);
+ pthread_mutexattr_init(&mutAttr);
+ pthread_mutexattr_settype(&mutAttr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mutFuncDBList, &mutAttr);
+ pthread_mutex_init(&mutMutLog, &mutAttr);
+ pthread_mutex_init(&mutCallStack, &mutAttr);
+ pthread_mutex_init(&mutdbgprint, &mutAttr);
/* while we try not to use any of the real rsyslog code (to avoid infinite loops), we
* need to have the ability to query object names. Thus, we need to obtain a pointer to
diff --git a/runtime/glbl.c b/runtime/glbl.c
index b3fe3a1d..ccb978ba 100644
--- a/runtime/glbl.c
+++ b/runtime/glbl.c
@@ -89,6 +89,7 @@ static DEF_ATOMIC_HELPER_MUT(mutTerminateInputs);
#ifdef USE_UNLIMITED_SELECT
static int iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); /* size of select() bitmask in bytes */
#endif
+static uchar *SourceIPofLocalClient = NULL; /* [ar] Source IP for local client to be used on multihomed host */
/* tables for interfacing with the v6 config system */
@@ -478,6 +479,23 @@ GetDfltNetstrmDrvrCertFile(void)
}
+/* [ar] Source IP for local client to be used on multihomed host */
+static rsRetVal
+SetSourceIPofLocalClient(uchar *newname)
+{
+ if(SourceIPofLocalClient != NULL) {
+ free(SourceIPofLocalClient); }
+ SourceIPofLocalClient = newname;
+ return RS_RET_OK;
+}
+
+static uchar*
+GetSourceIPofLocalClient(void)
+{
+ return(SourceIPofLocalClient);
+}
+
+
/* queryInterface function
* rgerhards, 2008-02-21
*/
@@ -498,6 +516,8 @@ CODESTARTobjQueryInterface(glbl)
pIf->GetLocalHostIP = GetLocalHostIP;
pIf->SetGlobalInputTermination = SetGlobalInputTermination;
pIf->GetGlobalInputTermState = GetGlobalInputTermState;
+ pIf->GetSourceIPofLocalClient = GetSourceIPofLocalClient; /* [ar] */
+ pIf->SetSourceIPofLocalClient = SetSourceIPofLocalClient; /* [ar] */
#define SIMP_PROP(name) \
pIf->Get##name = Get##name; \
pIf->Set##name = Set##name;
diff --git a/runtime/glbl.h b/runtime/glbl.h
index e95e48f7..2c7f3b31 100644
--- a/runtime/glbl.h
+++ b/runtime/glbl.h
@@ -81,6 +81,8 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
/* next change is v9! */
/* v8 - 2012-03-21 */
prop_t* (*GetLocalHostIP)(void);
+ uchar* (*GetSourceIPofLocalClient)(void); /* [ar] */
+ rsRetVal (*SetSourceIPofLocalClient)(uchar*); /* [ar] */
#undef SIMP_PROP
ENDinterface(glbl)
#define glblCURR_IF_VERSION 7 /* increment whenever you change the interface structure! */
diff --git a/runtime/libgcry.c b/runtime/libgcry.c
index 51c10af4..4772cf47 100644
--- a/runtime/libgcry.c
+++ b/runtime/libgcry.c
@@ -49,8 +49,12 @@
#include <errno.h>
#include "rsyslog.h"
+#include "srUtils.h"
#include "libgcry.h"
+#define READBUF_SIZE 4096 /* size of the read buffer */
+
+static rsRetVal rsgcryBlkBegin(gcryfile gf);
static rsRetVal
eiWriteRec(gcryfile gf, char *recHdr, size_t lenRecHdr, char *buf, size_t lenBuf)
@@ -90,19 +94,66 @@ finalize_it:
RETiRet;
}
+static rsRetVal
+eiRead(gcryfile gf)
+{
+ ssize_t nRead;
+ DEFiRet;
+
+ if(gf->readBuf == NULL) {
+ CHKmalloc(gf->readBuf = malloc(READBUF_SIZE));
+ }
+
+ nRead = read(gf->fd, gf->readBuf, READBUF_SIZE);
+ if(nRead <= 0) { /* TODO: provide specific EOF case? */
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ gf->readBufMaxIdx = (int16_t) nRead;
+ gf->readBufIdx = 0;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* returns EOF on any kind of error */
+static int
+eiReadChar(gcryfile gf)
+{
+ int c;
+
+ if(gf->readBufIdx >= gf->readBufMaxIdx) {
+ if(eiRead(gf) != RS_RET_OK) {
+ c = EOF;
+ goto finalize_it;
+ }
+ }
+ c = gf->readBuf[gf->readBufIdx++];
+finalize_it:
+ return c;
+}
+
static rsRetVal
eiCheckFiletype(gcryfile gf)
{
char hdrBuf[128];
size_t toRead, didRead;
+ sbool bNeedClose = 0;
DEFiRet;
- CHKiRet(eiOpenRead(gf));
+ if(gf->fd == -1) {
+ bNeedClose = 1;
+ CHKiRet(eiOpenRead(gf));
+ }
+
if(Debug) memset(hdrBuf, 0, sizeof(hdrBuf)); /* for dbgprintf below! */
toRead = sizeof("FILETYPE:")-1 + sizeof(RSGCRY_FILETYPE_NAME)-1 + 1;
didRead = read(gf->fd, hdrBuf, toRead);
- close(gf->fd);
+ if(bNeedClose) {
+ close(gf->fd);
+ gf->fd = -1;
+ }
DBGPRINTF("eiCheckFiletype read %d bytes: '%s'\n", didRead, hdrBuf);
if( didRead != toRead
|| strncmp(hdrBuf, "FILETYPE:" RSGCRY_FILETYPE_NAME "\n", toRead))
@@ -111,6 +162,98 @@ finalize_it:
RETiRet;
}
+/* rectype/value must be EIF_MAX_*_LEN+1 long!
+ * returns 0 on success or something else on error/EOF
+ */
+static rsRetVal
+eiGetRecord(gcryfile gf, char *rectype, char *value)
+{
+ unsigned short i, j;
+ int c;
+ DEFiRet;
+
+ c = eiReadChar(gf);
+ if(c == EOF) { ABORT_FINALIZE(RS_RET_NO_DATA); }
+ for(i = 0 ; i < EIF_MAX_RECTYPE_LEN ; ++i) {
+ if(c == ':' || c == EOF)
+ break;
+ rectype[i] = c;
+ c = eiReadChar(gf);
+ }
+ if(c != ':') { ABORT_FINALIZE(RS_RET_ERR); }
+ rectype[i] = '\0';
+ j = 0;
+ for(++i ; i < EIF_MAX_VALUE_LEN ; ++i, ++j) {
+ c = eiReadChar(gf);
+ if(c == '\n' || c == EOF)
+ break;
+ value[j] = c;
+ }
+ if(c != '\n') { ABORT_FINALIZE(RS_RET_ERR); }
+ value[j] = '\0';
+finalize_it:
+ RETiRet;
+}
+
+static rsRetVal
+eiGetIV(gcryfile gf, uchar *iv, size_t leniv)
+{
+ char rectype[EIF_MAX_RECTYPE_LEN+1];
+ char value[EIF_MAX_VALUE_LEN+1];
+ size_t valueLen;
+ unsigned short i, j;
+ unsigned char nibble;
+ DEFiRet;
+
+ CHKiRet(eiGetRecord(gf, rectype, value));
+ if(strcmp(rectype, "IV")) {
+ DBGPRINTF("no IV record found when expected, record type "
+ "seen is '%s'\n", rectype);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ valueLen = strlen(value);
+ if(valueLen/2 != leniv) {
+ DBGPRINTF("length of IV is %d, expected %d\n",
+ valueLen/2, leniv);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+ for(i = j = 0 ; i < valueLen ; ++i) {
+ if(value[i] >= '0' && value[i] <= '9')
+ nibble = value[i] - '0';
+ else if(value[i] >= 'a' && value[i] <= 'f')
+ nibble = value[i] - 'a' + 10;
+ else {
+ DBGPRINTF("invalid IV '%s'\n", value);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ if(i % 2 == 0)
+ iv[j] = nibble << 4;
+ else
+ iv[j++] |= nibble;
+ }
+finalize_it:
+ RETiRet;
+}
+
+static rsRetVal
+eiGetEND(gcryfile gf, off64_t *offs)
+{
+ char rectype[EIF_MAX_RECTYPE_LEN+1];
+ char value[EIF_MAX_VALUE_LEN+1];
+ DEFiRet;
+
+ CHKiRet(eiGetRecord(gf, rectype, value));
+ if(strcmp(rectype, "END")) {
+ DBGPRINTF("no END record found when expected, record type "
+ "seen is '%s'\n", rectype);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ *offs = atoll(value);
+finalize_it:
+ RETiRet;
+}
+
static rsRetVal
eiOpenAppend(gcryfile gf)
{
@@ -177,13 +320,55 @@ eiClose(gcryfile gf, off64_t offsLogfile)
size_t len;
if(gf->fd == -1)
return;
- /* 2^64 is 20 digits, so the snprintf buffer is large enough */
- len = snprintf(offs, sizeof(offs), "%lld", offsLogfile);
- eiWriteRec(gf, "END:", 4, offs, len);
+ if(gf->openMode == 'w') {
+ /* 2^64 is 20 digits, so the snprintf buffer is large enough */
+ len = snprintf(offs, sizeof(offs), "%lld", offsLogfile);
+ eiWriteRec(gf, "END:", 4, offs, len);
+ }
+ gcry_cipher_close(gf->chd);
+ free(gf->readBuf);
close(gf->fd);
+ gf->fd = -1;
DBGPRINTF("encryption info file %s: closed\n", gf->eiName);
}
+/* this returns the number of bytes left inside the block or -1, if the block
+ * size is unbounded. The function automatically handles end-of-block and begins
+ * to read the next block in this case.
+ */
+rsRetVal
+gcryfileGetBytesLeftInBlock(gcryfile gf, ssize_t *left)
+{
+ DEFiRet;
+ if(gf->bytesToBlkEnd == 0) {
+ DBGPRINTF("libgcry: end of current crypto block\n");
+ gcry_cipher_close(gf->chd);
+ CHKiRet(rsgcryBlkBegin(gf));
+ }
+ *left = gf->bytesToBlkEnd;
+finalize_it:
+ // TODO: remove once this code is sufficiently well-proven
+ DBGPRINTF("gcryfileGetBytesLeftInBlock returns %lld, iRet %d\n", (long long) *left, iRet);
+ RETiRet;
+}
+
+/* this is a special functon for use by the rsyslog disk queue subsystem. It
+ * needs to have the capability to delete state when a queue file is rolled
+ * over. This simply generates the file name and deletes it. It must take care
+ * of "all" state files, which currently happens to be a single one.
+ */
+rsRetVal
+gcryfileDeleteState(uchar *logfn)
+{
+ char fn[MAXFNAME+1];
+ DEFiRet;
+ snprintf(fn, sizeof(fn), "%s%s", logfn, ENCINFO_SUFFIX);
+ fn[MAXFNAME] = '\0'; /* be on save side */
+ DBGPRINTF("crypto provider deletes state file '%s' on request\n", fn);
+ unlink(fn);
+ RETiRet;
+}
+
static rsRetVal
gcryfileConstruct(gcryctx ctx, gcryfile *pgf, uchar *logfn)
{
@@ -193,6 +378,7 @@ gcryfileConstruct(gcryctx ctx, gcryfile *pgf, uchar *logfn)
CHKmalloc(gf = calloc(1, sizeof(struct gcryfile_s)));
gf->ctx = ctx;
+ gf->fd = -1;
snprintf(fn, sizeof(fn), "%s%s", logfn, ENCINFO_SUFFIX);
fn[MAXFNAME] = '\0'; /* be on save side */
gf->eiName = (uchar*) strdup(fn);
@@ -219,7 +405,12 @@ gcryfileDestruct(gcryfile gf, off64_t offsLogfile)
if(gf == NULL)
goto done;
+ DBGPRINTF("libgcry: close file %s\n", gf->eiName);
eiClose(gf, offsLogfile);
+ if(gf->bDeleteOnClose) {
+ DBGPRINTF("unlink file '%s' due to bDeleteOnClose set\n", gf->eiName);
+ unlink((char*)gf->eiName);
+ }
free(gf->eiName);
free(gf);
done: return r;
@@ -246,13 +437,13 @@ addPadding(gcryfile pF, uchar *buf, size_t *plen)
}
static inline void
-removePadding(char *buf, size_t *plen)
+removePadding(uchar *buf, size_t *plen)
{
unsigned len = (unsigned) *plen;
unsigned iSrc, iDst;
- char *frstNUL;
+ uchar *frstNUL;
- frstNUL = strchr(buf, 0x00);
+ frstNUL = (uchar*)strchr((char*)buf, 0x00);
if(frstNUL == NULL)
goto done;
iDst = iSrc = frstNUL - buf;
@@ -343,53 +534,123 @@ seedIV(gcryfile gf, uchar **iv)
}
}
-rsRetVal
-rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname)
+static inline rsRetVal
+readIV(gcryfile gf, uchar **iv)
{
- gcry_error_t gcryError;
- gcryfile gf = NULL;
- uchar *iv = NULL;
+ rsRetVal localRet;
DEFiRet;
- CHKiRet(gcryfileConstruct(ctx, &gf, fname));
+ if(gf->fd == -1) {
+ while(gf->fd == -1) {
+ localRet = eiOpenRead(gf);
+ if(localRet == RS_RET_EI_NO_EXISTS) {
+ /* wait until it is created */
+ srSleep(0, 10000);
+ } else {
+ CHKiRet(localRet);
+ }
+ }
+ CHKiRet(eiCheckFiletype(gf));
+ }
+ *iv = malloc(gf->blkLength); /* do NOT zero-out! */
+ CHKiRet(eiGetIV(gf, *iv, (size_t) gf->blkLength));
+finalize_it:
+ RETiRet;
+}
+
+/* this tries to read the END record. HOWEVER, no such record may be
+ * present, which is the case if we handle a currently-written to queue
+ * file. On the other hand, the queue file may contain multiple blocks. So
+ * what we do is try to see if there is a block end or not - and set the
+ * status accordingly. Note that once we found no end-of-block, we will never
+ * retry. This is because that case can never happen under current queue
+ * implementations. -- gerhards, 2013-05-16
+ */
+static inline rsRetVal
+readBlkEnd(gcryfile gf)
+{
+ off64_t blkEnd;
+ DEFiRet;
+
+ iRet = eiGetEND(gf, &blkEnd);
+ if(iRet == RS_RET_OK) {
+ gf->bytesToBlkEnd = (ssize_t) blkEnd;
+ } else if(iRet == RS_RET_NO_DATA) {
+ gf->bytesToBlkEnd = -1;
+ } else {
+ FINALIZE;
+ }
+
+finalize_it:
+ RETiRet;
+}
- gf->blkLength = gcry_cipher_get_algo_blklen(ctx->algo);
- gcryError = gcry_cipher_open(&gf->chd, ctx->algo, ctx->mode, 0);
+/* Read the block begin metadata and set our state variables accordingly. Can also
+ * be used to init the first block in write case.
+ */
+static rsRetVal
+rsgcryBlkBegin(gcryfile gf)
+{
+ gcry_error_t gcryError;
+ uchar *iv = NULL;
+ DEFiRet;
+
+ gcryError = gcry_cipher_open(&gf->chd, gf->ctx->algo, gf->ctx->mode, 0);
if (gcryError) {
- dbgprintf("gcry_cipher_open failed: %s/%s\n",
- gcry_strsource(gcryError),
- gcry_strerror(gcryError));
+ DBGPRINTF("gcry_cipher_open failed: %s/%s\n",
+ gcry_strsource(gcryError), gcry_strerror(gcryError));
ABORT_FINALIZE(RS_RET_ERR);
}
gcryError = gcry_cipher_setkey(gf->chd, gf->ctx->key, gf->ctx->keyLen);
if (gcryError) {
- dbgprintf("gcry_cipher_setkey failed: %s/%s\n",
- gcry_strsource(gcryError),
- gcry_strerror(gcryError));
+ DBGPRINTF("gcry_cipher_setkey failed: %s/%s\n",
+ gcry_strsource(gcryError), gcry_strerror(gcryError));
ABORT_FINALIZE(RS_RET_ERR);
}
- seedIV(gf, &iv);
+ if(gf->openMode == 'r') {
+ readIV(gf, &iv);
+ readBlkEnd(gf);
+ } else {
+ seedIV(gf, &iv);
+ }
+
gcryError = gcry_cipher_setiv(gf->chd, iv, gf->blkLength);
if (gcryError) {
- dbgprintf("gcry_cipher_setiv failed: %s/%s\n",
- gcry_strsource(gcryError),
- gcry_strerror(gcryError));
+ DBGPRINTF("gcry_cipher_setiv failed: %s/%s\n",
+ gcry_strsource(gcryError), gcry_strerror(gcryError));
ABORT_FINALIZE(RS_RET_ERR);
}
- CHKiRet(eiOpenAppend(gf));
- CHKiRet(eiWriteIV(gf, iv));
- *pgf = gf;
+
+ if(gf->openMode == 'w') {
+ CHKiRet(eiOpenAppend(gf));
+ CHKiRet(eiWriteIV(gf, iv));
+ }
finalize_it:
free(iv);
+ RETiRet;
+}
+
+rsRetVal
+rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname, char openMode)
+{
+ gcryfile gf = NULL;
+ DEFiRet;
+
+ CHKiRet(gcryfileConstruct(ctx, &gf, fname));
+ gf->openMode = openMode;
+ gf->blkLength = gcry_cipher_get_algo_blklen(ctx->algo);
+ CHKiRet(rsgcryBlkBegin(gf));
+ *pgf = gf;
+finalize_it:
if(iRet != RS_RET_OK && gf != NULL)
gcryfileDestruct(gf, -1);
RETiRet;
}
-int
+rsRetVal
rsgcryEncrypt(gcryfile pF, uchar *buf, size_t *len)
{
int gcryError;
@@ -410,6 +671,35 @@ finalize_it:
RETiRet;
}
+/* TODO: handle multiple blocks
+ * test-read END record; if present, store offset, else unbounded (current active block)
+ * when decrypting, check if bound is reached. If yes, split into two blocks, get new IV for
+ * second one.
+ */
+rsRetVal
+rsgcryDecrypt(gcryfile pF, uchar *buf, size_t *len)
+{
+ gcry_error_t gcryError;
+ DEFiRet;
+
+ if(pF->bytesToBlkEnd != -1)
+ pF->bytesToBlkEnd -= *len;
+ gcryError = gcry_cipher_decrypt(pF->chd, buf, *len, NULL, 0);
+ if(gcryError) {
+ DBGPRINTF("gcry_cipher_decrypt failed: %s/%s\n",
+ gcry_strsource(gcryError),
+ gcry_strerror(gcryError));
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ removePadding(buf, len);
+ // TODO: remove dbgprintf once things are sufficently stable -- rgerhards, 2013-05-16
+ dbgprintf("libgcry: decrypted, bytesToBlkEnd %lld, buffer is now '%50.50s'\n", (long long) pF->bytesToBlkEnd, buf);
+
+finalize_it:
+ RETiRet;
+}
+
+
/* module-init dummy for potential later use */
int
diff --git a/runtime/libgcry.h b/runtime/libgcry.h
index b77b0f9e..2f700554 100644
--- a/runtime/libgcry.h
+++ b/runtime/libgcry.h
@@ -38,7 +38,15 @@ struct gcryfile_s {
size_t blkLength; /* size of low-level crypto block */
uchar *eiName; /* name of .encinfo file */
int fd; /* descriptor of .encinfo file (-1 if not open) */
+ char openMode; /* 'r': read, 'w': write */
gcryctx ctx;
+ uchar *readBuf;
+ int16_t readBufIdx;
+ int16_t readBufMaxIdx;
+ int8_t bDeleteOnClose; /* for queue support, similar to stream subsys */
+ ssize_t bytesToBlkEnd; /* number of bytes remaining in current crypto block
+ -1 means -> no end (still being writen to, queue files),
+ 0 means -> end of block, new one must be started. */
};
int gcryGetKeyFromFile(char *fn, char **key, unsigned *keylen);
@@ -50,8 +58,12 @@ rsRetVal rsgcrySetAlgo(gcryctx ctx, uchar *modename);
gcryctx gcryCtxNew(void);
void rsgcryCtxDel(gcryctx ctx);
int gcryfileDestruct(gcryfile gf, off64_t offsLogfile);
-rsRetVal rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname);
-int rsgcryEncrypt(gcryfile pF, uchar *buf, size_t *len);
+rsRetVal rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, uchar *fname, char openMode);
+rsRetVal rsgcryEncrypt(gcryfile pF, uchar *buf, size_t *len);
+rsRetVal rsgcryDecrypt(gcryfile pF, uchar *buf, size_t *len);
+int gcryGetKeyFromProg(char *cmd, char **key, unsigned *keylen);
+rsRetVal gcryfileDeleteState(uchar *fn);
+rsRetVal gcryfileGetBytesLeftInBlock(gcryfile gf, ssize_t *left);
/* error states */
#define RSGCRYE_EI_OPEN 1 /* error opening .encinfo file */
@@ -62,6 +74,14 @@ int rsgcryEncrypt(gcryfile pF, uchar *buf, size_t *len);
#define RSGCRY_FILETYPE_NAME "rsyslog-enrcyption-info"
#define ENCINFO_SUFFIX ".encinfo"
+/* Note: gf may validly be NULL, e.g. if file has not yet been opened! */
+static inline void
+gcryfileSetDeleteOnClose(gcryfile gf, int val)
+{
+ if(gf != NULL)
+ gf->bDeleteOnClose = val;
+}
+
static inline int
rsgcryAlgoname2Algo(char *algoname) {
if(!strcmp((char*)algoname, "3DES")) return GCRY_CIPHER_3DES;
diff --git a/runtime/libgcry_common.c b/runtime/libgcry_common.c
index 63b5e5d5..07a524dc 100644
--- a/runtime/libgcry_common.c
+++ b/runtime/libgcry_common.c
@@ -98,7 +98,7 @@ fprintf(stderr, "pre execve: %s\n", cmd);
*/
/* we should never reach this point, but if we do, we terminate */
-done: return;
+ return;
}
diff --git a/runtime/librsgt.c b/runtime/librsgt.c
index ae0b0df6..85fc7742 100644
--- a/runtime/librsgt.c
+++ b/runtime/librsgt.c
@@ -296,7 +296,7 @@ tlv16Write(gtfile gf, int flags, int tlvtype, uint16_t len)
{
uint16_t typ;
int r;
- typ = ((flags|1) << 13)|tlvtype;
+ typ = ((flags|1) << 15)|tlvtype;
r = tlvbufAddOctet(gf, typ >> 8);
if(r != 0) goto done;
r = tlvbufAddOctet(gf, typ & 0xff);
diff --git a/runtime/librsgt_read.c b/runtime/librsgt_read.c
index 25c0db4d..a6e33160 100644
--- a/runtime/librsgt_read.c
+++ b/runtime/librsgt_read.c
@@ -249,7 +249,7 @@ rsgt_tlvRecRead(FILE *fp, tlvrecord_t *rec)
NEXTC;
rec->hdr[0] = c;
rec->tlvtype = c & 0x1f;
- if(c & 0x20) { /* tlv16? */
+ if(c & 0x80) { /* tlv16? */
rec->lenHdr = 4;
NEXTC;
rec->hdr[1] = c;
@@ -290,7 +290,7 @@ rsgt_tlvDecodeSUBREC(tlvrecord_t *rec, uint16_t *stridx, tlvrecord_t *newrec)
c = rec->data[(*stridx)++];
newrec->hdr[0] = c;
newrec->tlvtype = c & 0x1f;
- if(c & 0x20) { /* tlv16? */
+ if(c & 0x80) { /* tlv16? */
newrec->lenHdr = 4;
if(rec->tlvlen == *stridx) {r=RSGTE_LEN; goto done;}
c = rec->data[(*stridx)++];
diff --git a/runtime/lmcry_gcry.c b/runtime/lmcry_gcry.c
index 0a9b94bc..9a0c0072 100644
--- a/runtime/lmcry_gcry.c
+++ b/runtime/lmcry_gcry.c
@@ -43,17 +43,30 @@ DEFobjCurrIf(errmsg)
DEFobjCurrIf(glbl)
/* tables for interfacing with the v6 config system */
-static struct cnfparamdescr cnfpdescr[] = {
+static struct cnfparamdescr cnfpdescrRegular[] = {
{ "cry.key", eCmdHdlrGetWord, 0 },
{ "cry.keyfile", eCmdHdlrGetWord, 0 },
{ "cry.keyprogram", eCmdHdlrGetWord, 0 },
{ "cry.mode", eCmdHdlrGetWord, 0 }, /* CBC, ECB, etc */
{ "cry.algo", eCmdHdlrGetWord, 0 }
};
-static struct cnfparamblk pblk =
+static struct cnfparamblk pblkRegular =
{ CNFPARAMBLK_VERSION,
- sizeof(cnfpdescr)/sizeof(struct cnfparamdescr),
- cnfpdescr
+ sizeof(cnfpdescrRegular)/sizeof(struct cnfparamdescr),
+ cnfpdescrRegular
+ };
+
+static struct cnfparamdescr cnfpdescrQueue[] = {
+ { "queue.cry.key", eCmdHdlrGetWord, 0 },
+ { "queue.cry.keyfile", eCmdHdlrGetWord, 0 },
+ { "queue.cry.keyprogram", eCmdHdlrGetWord, 0 },
+ { "queue.cry.mode", eCmdHdlrGetWord, 0 }, /* CBC, ECB, etc */
+ { "queue.cry.algo", eCmdHdlrGetWord, 0 }
+};
+static struct cnfparamblk pblkQueue =
+ { CNFPARAMBLK_VERSION,
+ sizeof(cnfpdescrQueue)/sizeof(struct cnfparamdescr),
+ cnfpdescrQueue
};
@@ -85,7 +98,7 @@ ENDobjDestruct(lmcry_gcry)
* Defaults are expected to have been set during construction.
*/
static rsRetVal
-SetCnfParam(void *pT, struct nvlst *lst)
+SetCnfParam(void *pT, struct nvlst *lst, int paramType)
{
lmcry_gcry_t *pThis = (lmcry_gcry_t*) pT;
int i, r;
@@ -97,34 +110,41 @@ SetCnfParam(void *pT, struct nvlst *lst)
uchar *mode = NULL;
int nKeys; /* number of keys (actually methods) specified */
struct cnfparamvals *pvals;
+ struct cnfparamblk *pblk;
DEFiRet;
+ pblk = (paramType == CRYPROV_PARAMTYPE_REGULAR ) ? &pblkRegular : &pblkQueue;
nKeys = 0;
- pvals = nvlstGetParams(lst, &pblk, NULL);
+ pvals = nvlstGetParams(lst, pblk, NULL);
if(Debug) {
dbgprintf("param blk in lmcry_gcry:\n");
- cnfparamsPrint(&pblk, pvals);
+ cnfparamsPrint(pblk, pvals);
}
- for(i = 0 ; i < pblk.nParams ; ++i) {
+ for(i = 0 ; i < pblk->nParams ; ++i) {
if(!pvals[i].bUsed)
continue;
- if(!strcmp(pblk.descr[i].name, "cry.key")) {
+ if(!strcmp(pblk->descr[i].name, "cry.key") ||
+ !strcmp(pblk->descr[i].name, "queue.cry.key")) {
key = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
++nKeys;
- } else if(!strcmp(pblk.descr[i].name, "cry.keyfile")) {
+ } else if(!strcmp(pblk->descr[i].name, "cry.keyfile") ||
+ !strcmp(pblk->descr[i].name, "queue.cry.keyfile")) {
keyfile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
++nKeys;
- } else if(!strcmp(pblk.descr[i].name, "cry.keyprogram")) {
+ } else if(!strcmp(pblk->descr[i].name, "cry.keyprogram") ||
+ !strcmp(pblk->descr[i].name, "queue.cry.keyprogram")) {
keyprogram = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
++nKeys;
- } else if(!strcmp(pblk.descr[i].name, "cry.mode")) {
+ } else if(!strcmp(pblk->descr[i].name, "cry.mode") ||
+ !strcmp(pblk->descr[i].name, "queue.cry.mode")) {
mode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
- } else if(!strcmp(pblk.descr[i].name, "cry.algo")) {
+ } else if(!strcmp(pblk->descr[i].name, "cry.algo") ||
+ !strcmp(pblk->descr[i].name, "queue.cry.algo")) {
algo = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else {
DBGPRINTF("lmcry_gcry: program error, non-handled "
- "param '%s'\n", pblk.descr[i].name);
+ "param '%s'\n", pblk->descr[i].name);
}
}
if(algo != NULL) {
@@ -177,7 +197,7 @@ SetCnfParam(void *pT, struct nvlst *lst)
ABORT_FINALIZE(RS_RET_INVALID_PARAMS);
}
- cnfparamvalsDestruct(pvals, &pblk);
+ cnfparamvalsDestruct(pvals, pblk);
if(key != NULL) {
memset(key, 0, strlen((char*)key));
free(key);
@@ -189,15 +209,33 @@ finalize_it:
RETiRet;
}
+static void
+SetDeleteOnClose(void *pF, int val)
+{
+ gcryfileSetDeleteOnClose(pF, val);
+}
+
+static rsRetVal
+GetBytesLeftInBlock(void *pF, ssize_t *left)
+{
+ return gcryfileGetBytesLeftInBlock((gcryfile) pF, left);
+}
static rsRetVal
-OnFileOpen(void *pT, uchar *fn, void *pGF)
+DeleteStateFiles(uchar *logfn)
+{
+ return gcryfileDeleteState(logfn);
+}
+
+static rsRetVal
+OnFileOpen(void *pT, uchar *fn, void *pGF, char openMode)
{
lmcry_gcry_t *pThis = (lmcry_gcry_t*) pT;
gcryfile *pgf = (gcryfile*) pGF;
DEFiRet;
+ DBGPRINTF("lmcry_gcry: open file '%s', mode '%c'\n", fn, openMode);
- CHKiRet(rsgcryInitCrypt(pThis->ctx, pgf, fn));
+ CHKiRet(rsgcryInitCrypt(pThis->ctx, pgf, fn, openMode));
finalize_it:
/* TODO: enable this error message (need to cleanup loop first ;))
errmsg.LogError(0, iRet, "Encryption Provider"
@@ -207,6 +245,16 @@ finalize_it:
}
static rsRetVal
+Decrypt(void *pF, uchar *rec, size_t *lenRec)
+{
+ DEFiRet;
+ iRet = rsgcryDecrypt(pF, rec, lenRec);
+
+ RETiRet;
+}
+
+
+static rsRetVal
Encrypt(void *pF, uchar *rec, size_t *lenRec)
{
DEFiRet;
@@ -231,10 +279,14 @@ CODESTARTobjQueryInterface(lmcry_gcry)
}
pIf->Construct = (rsRetVal(*)(void*)) lmcry_gcryConstruct;
pIf->SetCnfParam = SetCnfParam;
+ pIf->SetDeleteOnClose = SetDeleteOnClose;
pIf->Destruct = (rsRetVal(*)(void*)) lmcry_gcryDestruct;
pIf->OnFileOpen = OnFileOpen;
pIf->Encrypt = Encrypt;
+ pIf->Decrypt = Decrypt;
pIf->OnFileClose = OnFileClose;
+ pIf->DeleteStateFiles = DeleteStateFiles;
+ pIf->GetBytesLeftInBlock = GetBytesLeftInBlock;
finalize_it:
ENDobjQueryInterface(lmcry_gcry)
diff --git a/runtime/msg.h b/runtime/msg.h
index edf5ed98..6faf066a 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -35,8 +35,6 @@
#include "syslogd-types.h"
#include "template.h"
#include "atomic.h"
-#include "libee/libee.h"
-
/* rgerhards 2004-11-08: The following structure represents a
* syslog message.
diff --git a/runtime/queue.c b/runtime/queue.c
index 600b5688..699e2a66 100644
--- a/runtime/queue.c
+++ b/runtime/queue.c
@@ -12,7 +12,7 @@
* function names - this makes it really hard to read and does not provide much
* benefit, at least I (now) think so...
*
- * Copyright 2008-2011 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2008-2013 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -118,6 +118,7 @@ static struct cnfparamdescr cnfpdescr[] = {
{ "queue.dequeueslowdown", eCmdHdlrInt, 0 },
{ "queue.dequeuetimebegin", eCmdHdlrInt, 0 },
{ "queue.dequeuetimeend", eCmdHdlrInt, 0 },
+ { "queue.cry.provider", eCmdHdlrGetWord, 0 }
};
static struct cnfparamblk pblk =
{ CNFPARAMBLK_VERSION,
@@ -776,11 +777,19 @@ qqueueTryLoadPersistedInfo(qqueue_t *pThis)
(rsRetVal(*)(obj_t*,void*))qqueueLoadPersStrmInfoFixup, pThis));
CHKiRet(obj.Deserialize(&pThis->tVars.disk.pReadDel, (uchar*) "strm", psQIF,
(rsRetVal(*)(obj_t*,void*))qqueueLoadPersStrmInfoFixup, pThis));
-
/* create a duplicate for the read "pointer". */
CHKiRet(strm.Dup(pThis->tVars.disk.pReadDel, &pThis->tVars.disk.pReadDeq));
CHKiRet(strm.SetbDeleteOnClose(pThis->tVars.disk.pReadDeq, 0)); /* deq must NOT delete the files! */
CHKiRet(strm.ConstructFinalize(pThis->tVars.disk.pReadDeq));
+ /* if we use a crypto provider, we need to amend the objects with it's info */
+ if(pThis->useCryprov) {
+ CHKiRet(strm.Setcryprov(pThis->tVars.disk.pWrite, &pThis->cryprov));
+ CHKiRet(strm.SetcryprovData(pThis->tVars.disk.pWrite, pThis->cryprovData));
+ CHKiRet(strm.Setcryprov(pThis->tVars.disk.pReadDeq, &pThis->cryprov));
+ CHKiRet(strm.SetcryprovData(pThis->tVars.disk.pReadDeq, pThis->cryprovData));
+ CHKiRet(strm.Setcryprov(pThis->tVars.disk.pReadDel, &pThis->cryprov));
+ CHKiRet(strm.SetcryprovData(pThis->tVars.disk.pReadDel, pThis->cryprovData));
+ }
CHKiRet(strm.SeekCurrOffs(pThis->tVars.disk.pWrite));
CHKiRet(strm.SeekCurrOffs(pThis->tVars.disk.pReadDel));
@@ -834,6 +843,10 @@ static rsRetVal qConstructDisk(qqueue_t *pThis)
CHKiRet(strm.SetiMaxFiles(pThis->tVars.disk.pWrite, 10000000));
CHKiRet(strm.SettOperationsMode(pThis->tVars.disk.pWrite, STREAMMODE_WRITE));
CHKiRet(strm.SetsType(pThis->tVars.disk.pWrite, STREAMTYPE_FILE_CIRCULAR));
+ if(pThis->useCryprov) {
+ CHKiRet(strm.Setcryprov(pThis->tVars.disk.pWrite, &pThis->cryprov));
+ CHKiRet(strm.SetcryprovData(pThis->tVars.disk.pWrite, pThis->cryprovData));
+ }
CHKiRet(strm.ConstructFinalize(pThis->tVars.disk.pWrite));
CHKiRet(strm.Construct(&pThis->tVars.disk.pReadDeq));
@@ -842,6 +855,10 @@ static rsRetVal qConstructDisk(qqueue_t *pThis)
CHKiRet(strm.SetiMaxFiles(pThis->tVars.disk.pReadDeq, 10000000));
CHKiRet(strm.SettOperationsMode(pThis->tVars.disk.pReadDeq, STREAMMODE_READ));
CHKiRet(strm.SetsType(pThis->tVars.disk.pReadDeq, STREAMTYPE_FILE_CIRCULAR));
+ if(pThis->useCryprov) {
+ CHKiRet(strm.Setcryprov(pThis->tVars.disk.pReadDeq, &pThis->cryprov));
+ CHKiRet(strm.SetcryprovData(pThis->tVars.disk.pReadDeq, pThis->cryprovData));
+ }
CHKiRet(strm.ConstructFinalize(pThis->tVars.disk.pReadDeq));
CHKiRet(strm.Construct(&pThis->tVars.disk.pReadDel));
@@ -851,6 +868,10 @@ static rsRetVal qConstructDisk(qqueue_t *pThis)
CHKiRet(strm.SetiMaxFiles(pThis->tVars.disk.pReadDel, 10000000));
CHKiRet(strm.SettOperationsMode(pThis->tVars.disk.pReadDel, STREAMMODE_READ));
CHKiRet(strm.SetsType(pThis->tVars.disk.pReadDel, STREAMTYPE_FILE_CIRCULAR));
+ if(pThis->useCryprov) {
+ CHKiRet(strm.Setcryprov(pThis->tVars.disk.pReadDel, &pThis->cryprov));
+ CHKiRet(strm.SetcryprovData(pThis->tVars.disk.pReadDel, pThis->cryprovData));
+ }
CHKiRet(strm.ConstructFinalize(pThis->tVars.disk.pReadDel));
CHKiRet(strm.SetFName(pThis->tVars.disk.pWrite, pThis->pszFilePrefix, pThis->lenFilePrefix));
@@ -1320,6 +1341,7 @@ rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThread
pThis->iMaxFileSize = 1024 * 1024; /* default is 1 MiB */
pThis->iQueueSize = 0;
pThis->nLogDeq = 0;
+ pThis->useCryprov = 0;
pThis->iMaxQueueSize = iMaxQueueSize;
pThis->pConsumer = pConsumer;
pThis->iNumWorkerThreads = iWorkerThreads;
@@ -2389,6 +2411,13 @@ CODESTARTobjDestruct(qqueue)
free(pThis->pszFilePrefix);
free(pThis->pszSpoolDir);
+ if(pThis->useCryprov) {
+ pThis->cryprov.Destruct(&pThis->cryprovData);
+ obj.ReleaseObj(__FILE__, pThis->cryprovNameFull+2, pThis->cryprovNameFull,
+ (void*) &pThis->cryprov);
+ free(pThis->cryprovName);
+ free(pThis->cryprovNameFull);
+ }
/* some queues do not provide stats and thus have no statsobj! */
if(pThis->statsobj != NULL)
@@ -2672,27 +2701,67 @@ finalize_it:
}
-/* take v6 config list and extract the queue params out of it. Hand the
- * param values back to the caller. Caller is responsible for destructing
- * them when no longer needed. Caller can use this param block to configure
- * all parameters for a newly created queue with one call to qqueueSetParams().
- * rgerhards, 2011-07-22
+/* are any queue params set at all? 1 - yes, 0 - no
+ * We need to evaluate the param block for this function, which is somewhat
+ * inefficient. HOWEVER, this is only done during config load, so we really
+ * don't care... -- rgerhards, 2013-05-10
*/
-rsRetVal
-qqueueDoCnfParams(struct nvlst *lst, struct cnfparamvals **ppvals)
+int
+queueCnfParamsSet(struct nvlst *lst)
{
- *ppvals = nvlstGetParams(lst, &pblk, NULL);
- return RS_RET_OK;
+ int r;
+ struct cnfparamvals *pvals;
+
+ pvals = nvlstGetParams(lst, &pblk, NULL);
+ r = cnfparamvalsIsSet(&pblk, pvals);
+ cnfparamvalsDestruct(pvals, &pblk);
+ return r;
}
-/* are any queue params set at all? 1 - yes, 0 - no */
-int
-queueCnfParamsSet(struct cnfparamvals *pvals)
+static inline rsRetVal
+initCryprov(qqueue_t *pThis, struct nvlst *lst)
{
- return cnfparamvalsIsSet(&pblk, pvals);
-}
+ uchar szDrvrName[1024];
+ DEFiRet;
+
+ if(snprintf((char*)szDrvrName, sizeof(szDrvrName), "lmcry_%s", pThis->cryprovName)
+ == sizeof(szDrvrName)) {
+ errmsg.LogError(0, RS_RET_ERR, "queue: crypto provider "
+ "name is too long: '%s' - encryption disabled",
+ pThis->cryprovName);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ pThis->cryprovNameFull = ustrdup(szDrvrName);
+ pThis->cryprov.ifVersion = cryprovCURR_IF_VERSION;
+ /* The pDrvrName+2 below is a hack to obtain the object name. It
+ * safes us to have yet another variable with the name without "lm" in
+ * front of it. If we change the module load interface, we may re-think
+ * about this hack, but for the time being it is efficient and clean enough.
+ */
+ if(obj.UseObj(__FILE__, szDrvrName, szDrvrName, (void*) &pThis->cryprov)
+ != RS_RET_OK) {
+ errmsg.LogError(0, RS_RET_LOAD_ERROR, "queue: could not load "
+ "crypto provider '%s' - encryption disabled",
+ szDrvrName);
+ ABORT_FINALIZE(RS_RET_CRYPROV_ERR);
+ }
+
+ if(pThis->cryprov.Construct(&pThis->cryprovData) != RS_RET_OK) {
+ errmsg.LogError(0, RS_RET_CRYPROV_ERR, "queue: error constructing "
+ "crypto provider %s dataset - encryption disabled",
+ szDrvrName);
+ ABORT_FINALIZE(RS_RET_CRYPROV_ERR);
+ }
+ CHKiRet(pThis->cryprov.SetCnfParam(pThis->cryprovData, lst, CRYPROV_PARAMTYPE_DISK));
+
+ dbgprintf("loaded crypto provider %s, data instance at %p\n",
+ szDrvrName, pThis->cryprovData);
+ pThis->useCryprov = 1;
+finalize_it:
+ RETiRet;
+}
/* apply all params from param block to queue. Must be called before
* finalizing. This supports the v6 config system. Defaults were already
@@ -2700,15 +2769,24 @@ queueCnfParamsSet(struct cnfparamvals *pvals)
* function.
*/
rsRetVal
-qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals)
+qqueueApplyCnfParam(qqueue_t *pThis, struct nvlst *lst)
{
int i;
+ struct cnfparamvals *pvals;
+
+ pvals = nvlstGetParams(lst, &pblk, NULL);
+ if(Debug) {
+ dbgprintf("queue param blk:\n");
+ cnfparamsPrint(&pblk, pvals);
+ }
for(i = 0 ; i < pblk.nParams ; ++i) {
if(!pvals[i].bUsed)
continue;
if(!strcmp(pblk.descr[i].name, "queue.filename")) {
pThis->pszFilePrefix = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
pThis->lenFilePrefix = es_strlen(pvals[i].val.d.estr);
+ } else if(!strcmp(pblk.descr[i].name, "queue.cry.provider")) {
+ pThis->cryprovName = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(pblk.descr[i].name, "queue.size")) {
pThis->iMaxQueueSize = pvals[i].val.d.n;
} else if(!strcmp(pblk.descr[i].name, "queue.dequeuebatchsize")) {
@@ -2760,6 +2838,27 @@ qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals)
"param '%s'\n", pblk.descr[i].name);
}
}
+ if(pThis->qType == QUEUETYPE_DISK) {
+ if(pThis->pszFilePrefix == NULL) {
+ errmsg.LogError(0, RS_RET_QUEUE_DISK_NO_FN, "error on queue '%s', disk mode selected, but "
+ "no queue file name given; queue type changed to 'linkedList'",
+ obj.GetName((obj_t*) pThis));
+ pThis->qType = QUEUETYPE_LINKEDLIST;
+ }
+ }
+
+ if(pThis->pszFilePrefix == NULL && pThis->cryprovName != NULL) {
+ errmsg.LogError(0, RS_RET_QUEUE_CRY_DISK_ONLY, "error on queue '%s', crypto provider can "
+ "only be set for disk or disk assisted queue - ignored",
+ obj.GetName((obj_t*) pThis));
+ free(pThis->cryprovName);
+ pThis->cryprovName = NULL;
+ }
+
+ if(pThis->cryprovName != NULL) {
+ initCryprov(pThis, lst);
+ }
+
cnfparamvalsDestruct(pvals, &pblk);
return RS_RET_OK;
}
diff --git a/runtime/queue.h b/runtime/queue.h
index 886fac8d..844523ad 100644
--- a/runtime/queue.h
+++ b/runtime/queue.h
@@ -30,6 +30,7 @@
#include "batch.h"
#include "stream.h"
#include "statsobj.h"
+#include "cryprov.h"
/* support for the toDelete list */
typedef struct toDeleteLst_s toDeleteLst_t;
@@ -168,6 +169,11 @@ struct queue_s {
strm_t *pReadDel; /* current file for deleting */
} disk;
} tVars;
+ sbool useCryprov; /* quicker than checkig ptr (1 vs 8 bytes!) */
+ uchar *cryprovName; /* crypto provider to use */
+ cryprov_if_t cryprov; /* ptr to crypto provider interface */
+ void *cryprovData; /* opaque data ptr for provider use */
+ uchar *cryprovNameFull;/* full internal crypto provider name */
DEF_ATOMIC_HELPER_MUT(mutQueueSize);
DEF_ATOMIC_HELPER_MUT(mutLogDeq);
/* for statistics subsystem */
@@ -197,9 +203,8 @@ rsRetVal qqueueSetFilePrefix(qqueue_t *pThis, uchar *pszPrefix, size_t iLenPrefi
rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThreads,
int iMaxQueueSize, rsRetVal (*pConsumer)(void*,batch_t*, int*));
rsRetVal qqueueEnqObjDirectBatch(qqueue_t *pThis, batch_t *pBatch);
-rsRetVal qqueueDoCnfParams(struct nvlst *lst, struct cnfparamvals **ppvals);
-int queueCnfParamsSet(struct cnfparamvals *pvals);
-rsRetVal qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals);
+int queueCnfParamsSet(struct nvlst *lst);
+rsRetVal qqueueApplyCnfParam(qqueue_t *pThis, struct nvlst *lst);
void qqueueSetDefaultsRulesetQueue(qqueue_t *pThis);
void qqueueSetDefaultsActionQueue(qqueue_t *pThis);
void qqueueDbgPrint(qqueue_t *pThis);
diff --git a/runtime/ratelimit.c b/runtime/ratelimit.c
index d83da2dd..ec248550 100644
--- a/runtime/ratelimit.c
+++ b/runtime/ratelimit.c
@@ -167,13 +167,13 @@ withinRatelimit(ratelimit_t *ratelimit, time_t tt)
ratelimit->done++;
ret = 1;
} else {
- if(ratelimit->missed == 0) {
+ ratelimit->missed++;
+ if(ratelimit->missed == 1) {
snprintf((char*)msgbuf, sizeof(msgbuf),
"%s: begin to drop messages due to rate-limiting",
ratelimit->name);
logmsgInternal(RS_RET_RATE_LIMITED, LOG_SYSLOG|LOG_INFO, msgbuf, 0);
}
- ratelimit->missed++;
ret = 0;
}
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index a901d2ef..179d93e6 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -412,6 +412,10 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_EI_INVLD_FILE = -2325,/**< header indicates the file is no .encinfo file */
RS_RET_CRY_INVLD_ALGO = -2326,/**< user specified invalid (unkonwn) crypto algorithm */
RS_RET_CRY_INVLD_MODE = -2327,/**< user specified invalid (unkonwn) crypto mode */
+ RS_RET_QUEUE_DISK_NO_FN = -2328,/**< disk queue configured, but filename not set */
+ /* up to 2350 reserved for 7.4 */
+ RS_RET_QUEUE_CRY_DISK_ONLY = -2351,/**< crypto provider only supported for disk-associated queues */
+ RS_RET_NO_DATA = -2352,/**< file has no data; more a state than a real error */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/runtime/ruleset.c b/runtime/ruleset.c
index e3348938..aacbdf57 100644
--- a/runtime/ruleset.c
+++ b/runtime/ruleset.c
@@ -928,7 +928,6 @@ rsRetVal
rulesetProcessCnf(struct cnfobj *o)
{
struct cnfparamvals *pvals;
- struct cnfparamvals *queueParams;
rsRetVal localRet;
uchar *rsName = NULL;
uchar *parserName;
@@ -974,11 +973,10 @@ rulesetProcessCnf(struct cnfobj *o)
}
/* pick up ruleset queue parameters */
- qqueueDoCnfParams(o->nvlst, &queueParams);
- if(queueCnfParamsSet(queueParams)) {
+ if(queueCnfParamsSet(o->nvlst)) {
rsname = (pRuleset->pszName == NULL) ? (uchar*) "[ruleset]" : pRuleset->pszName;
DBGPRINTF("adding a ruleset-specific \"main\" queue for ruleset '%s'\n", rsname);
- CHKiRet(createMainQueue(&pRuleset->pQueue, rsname, queueParams));
+ CHKiRet(createMainQueue(&pRuleset->pQueue, rsname, o->nvlst));
}
finalize_it:
diff --git a/runtime/stream.c b/runtime/stream.c
index b781324a..53039056 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -257,7 +257,9 @@ doPhysOpen(strm_t *pThis)
if(pThis->cryprov != NULL) {
CHKiRet(pThis->cryprov->OnFileOpen(pThis->cryprovData,
- pThis->pszCurrFName, &pThis->cryprovFileData));
+ pThis->pszCurrFName, &pThis->cryprovFileData,
+ (pThis->tOperationsMode == STREAMMODE_READ) ? 'r' : 'w'));
+ pThis->cryprov->SetDeleteOnClose(pThis->cryprovFileData, pThis->bDeleteOnClose);
}
finalize_it:
RETiRet;
@@ -405,6 +407,12 @@ static rsRetVal strmCloseFile(strm_t *pThis)
}
}
+ /* if we have a signature provider, we must make sure that the crypto
+ * state files are opened and proper close processing happens. */
+ if(pThis->cryprov != NULL && pThis->fd == -1) {
+ strmOpenFile(pThis);
+ }
+
/* the file may already be closed (or never have opened), so guard
* against this. -- rgerhards, 2010-03-19
*/
@@ -551,11 +559,14 @@ finalize_it:
* rgerhards, 2008-02-13
*/
static rsRetVal
-strmReadBuf(strm_t *pThis)
+strmReadBuf(strm_t *pThis, int *padBytes)
{
DEFiRet;
int bRun;
long iLenRead;
+ size_t actualDataLen;
+ size_t toRead;
+ ssize_t bytesLeft;
ISOBJ_TYPE_assert(pThis, strm);
/* We need to try read at least twice because we may run into EOF and need to switch files. */
@@ -566,13 +577,35 @@ strmReadBuf(strm_t *pThis)
* rgerhards, 2008-02-13
*/
CHKiRet(strmOpenFile(pThis));
- iLenRead = read(pThis->fd, pThis->pIOBuf, pThis->sIOBufSize);
+ if(pThis->cryprov == NULL) {
+ toRead = pThis->sIOBufSize;
+ } else {
+ CHKiRet(pThis->cryprov->GetBytesLeftInBlock(pThis->cryprovFileData, &bytesLeft));
+ if(bytesLeft == -1 || bytesLeft > (ssize_t) pThis->sIOBufSize) {
+ toRead = pThis->sIOBufSize;
+ } else {
+ toRead = (size_t) bytesLeft;
+ }
+ }
+ iLenRead = read(pThis->fd, pThis->pIOBuf, toRead);
DBGOPRINT((obj_t*) pThis, "file %d read %ld bytes\n", pThis->fd, iLenRead);
+ /* end crypto */
if(iLenRead == 0) {
CHKiRet(strmHandleEOF(pThis));
} else if(iLenRead < 0)
ABORT_FINALIZE(RS_RET_IO_ERROR);
else { /* good read */
+ /* here we place our crypto interface */
+ if(pThis->cryprov != NULL) {
+ actualDataLen = iLenRead;
+ pThis->cryprov->Decrypt(pThis->cryprovFileData, pThis->pIOBuf, &actualDataLen);
+ *padBytes = iLenRead - actualDataLen;
+ iLenRead = actualDataLen;
+ DBGOPRINT((obj_t*) pThis, "encrypted file %d pad bytes %d, actual "
+ "data %ld\n", pThis->fd, *padBytes, iLenRead);
+ } else {
+ *padBytes = 0;
+ }
pThis->iBufPtrMax = iLenRead;
bRun = 0; /* exit loop */
}
@@ -594,6 +627,7 @@ finalize_it:
*/
static rsRetVal strmReadChar(strm_t *pThis, uchar *pC)
{
+ int padBytes = 0; /* in crypto mode, we may have some padding (non-data) bytes */
DEFiRet;
ASSERT(pThis != NULL);
@@ -609,8 +643,9 @@ static rsRetVal strmReadChar(strm_t *pThis, uchar *pC)
/* do we need to obtain a new buffer? */
if(pThis->iBufPtr >= pThis->iBufPtrMax) {
- CHKiRet(strmReadBuf(pThis));
+ CHKiRet(strmReadBuf(pThis, &padBytes));
}
+ pThis->iCurrOffs += padBytes;
/* if we reach this point, we have data available in the buffer */
@@ -1455,6 +1490,8 @@ strmMultiFileSeek(strm_t *pThis, int FNum, off64_t offs, off64_t *bytesDel)
"deleting '%s' (%lld bytes)\n", pThis->iCurrFNum, FNum,
pThis->pszCurrFName, (long long) *bytesDel);
unlink((char*)pThis->pszCurrFName);
+ if(pThis->cryprov != NULL)
+ pThis->cryprov->DeleteStateFiles(pThis->pszCurrFName);
free(pThis->pszCurrFName);
pThis->pszCurrFName = NULL;
pThis->iCurrFNum = FNum;
@@ -1468,17 +1505,31 @@ finalize_it:
}
-
/* seek to current offset. This is primarily a helper to readjust the OS file
* pointer after a strm object has been deserialized.
*/
static rsRetVal strmSeekCurrOffs(strm_t *pThis)
{
+ off64_t targetOffs;
+ uchar c;
DEFiRet;
ISOBJ_TYPE_assert(pThis, strm);
- iRet = strmSeek(pThis, pThis->iCurrOffs);
+ if(pThis->cryprov == NULL || pThis->tOperationsMode != STREAMMODE_READ) {
+ iRet = strmSeek(pThis, pThis->iCurrOffs);
+ FINALIZE;
+ }
+
+ /* As the cryprov may use CBC or similiar things, we need to read skip data */
+ targetOffs = pThis->iCurrOffs;
+ pThis->iCurrOffs = 0;
+ DBGOPRINT((obj_t*) pThis, "encrypted, doing skip read of %lld bytes\n",
+ (long long) targetOffs);
+ while(targetOffs != pThis->iCurrOffs) {
+ CHKiRet(strmReadChar(pThis, &c));
+ }
+finalize_it:
RETiRet;
}
@@ -1605,7 +1656,6 @@ finalize_it:
/* property set methods */
/* simple ones first */
-DEFpropSetMeth(strm, bDeleteOnClose, int)
DEFpropSetMeth(strm, iMaxFileSize, int)
DEFpropSetMeth(strm, iFileNumDigits, int)
DEFpropSetMeth(strm, tOperationsMode, int)
@@ -1621,6 +1671,15 @@ DEFpropSetMeth(strm, pszSizeLimitCmd, uchar*)
DEFpropSetMeth(strm, cryprov, cryprov_if_t*)
DEFpropSetMeth(strm, cryprovData, void*)
+static rsRetVal strmSetbDeleteOnClose(strm_t *pThis, int val)
+{
+ pThis->bDeleteOnClose = val;
+ if(pThis->cryprov != NULL) {
+ pThis->cryprov->SetDeleteOnClose(pThis->cryprovFileData, pThis->bDeleteOnClose);
+ }
+ return RS_RET_OK;
+}
+
static rsRetVal strmSetiMaxFiles(strm_t *pThis, int iNewVal)
{
pThis->iMaxFiles = iNewVal;
diff --git a/runtime/stringbuf.c b/runtime/stringbuf.c
index 75d2eac4..cb4f0457 100644
--- a/runtime/stringbuf.c
+++ b/runtime/stringbuf.c
@@ -112,13 +112,12 @@ static rsRetVal rsCStrConstructFromszStrv(cstr_t **ppThis, uchar *fmt, va_list a
DEFiRet;
cstr_t *pThis;
va_list ap2;
- uchar *sz;
int len;
assert(ppThis != NULL);
va_copy(ap2, ap);
- len = vsnprintf(NULL, 0, fmt, ap2);
+ len = vsnprintf(NULL, 0, (char*)fmt, ap2);
va_end(ap2);
if(len < 0)
@@ -133,7 +132,7 @@ static rsRetVal rsCStrConstructFromszStrv(cstr_t **ppThis, uchar *fmt, va_list a
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
}
- vsnprintf(pThis->pBuf, len, fmt, ap);
+ vsnprintf((char*)pThis->pBuf, len, (char*)fmt, ap);
*ppThis = pThis;
finalize_it:
RETiRet;
@@ -142,13 +141,13 @@ finalize_it:
/* construct from a printf-style formated string
*/
-rsRetVal rsCStrConstructFromszStrf(cstr_t **ppThis, uchar *fmt, ...)
+rsRetVal rsCStrConstructFromszStrf(cstr_t **ppThis, char *fmt, ...)
{
DEFiRet;
va_list ap;
va_start(ap, fmt);
- iRet = rsCStrConstructFromszStrv(ppThis, fmt, ap);
+ iRet = rsCStrConstructFromszStrv(ppThis, (uchar*)fmt, ap);
va_end(ap);
RETiRet;
@@ -313,7 +312,7 @@ rsRetVal rsCStrAppendStrf(cstr_t *pThis, uchar *fmt, ...)
{
DEFiRet;
va_list ap;
- cstr_t *pStr;
+ cstr_t *pStr = NULL;
va_start(ap, fmt);
iRet = rsCStrConstructFromszStrv(&pStr, fmt, ap);
@@ -322,7 +321,7 @@ rsRetVal rsCStrAppendStrf(cstr_t *pThis, uchar *fmt, ...)
CHKiRet(iRet);
iRet = cstrAppendCStr(pThis, pStr);
- rsCStrDestruct(pStr);
+ rsCStrDestruct(&pStr);
finalize_it:
RETiRet;
}
diff --git a/runtime/stringbuf.h b/runtime/stringbuf.h
index b301f4b9..d0502a5b 100644
--- a/runtime/stringbuf.h
+++ b/runtime/stringbuf.h
@@ -58,7 +58,7 @@ rsRetVal cstrConstruct(cstr_t **ppThis);
rsRetVal cstrConstructFromESStr(cstr_t **ppThis, es_str_t *str);
rsRetVal rsCStrConstructFromszStr(cstr_t **ppThis, uchar *sz);
rsRetVal rsCStrConstructFromCStr(cstr_t **ppThis, cstr_t *pFrom);
-rsRetVal rsCStrConstructFromszStrf(cstr_t **ppThis, uchar *fmt, ...);
+rsRetVal rsCStrConstructFromszStrf(cstr_t **ppThis, char *fmt, ...) __attribute__((format(printf,2, 3)));
/**
* Destruct the string buffer object.
diff --git a/template.c b/template.c
index c48bf4bd..b6752551 100644
--- a/template.c
+++ b/template.c
@@ -1184,6 +1184,7 @@ struct template *tplAddLine(rsconf_t *conf, char* pName, uchar** ppRestOfConfLin
if((pTpl = tplConstruct(conf)) == NULL)
return NULL;
+ DBGPRINTF("tplAddLine processing template '%s'\n", pName);
pTpl->iLenName = strlen(pName);
pTpl->pszName = (char*) MALLOC(sizeof(char) * (pTpl->iLenName + 1));
if(pTpl->pszName == NULL) {
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 9a1497cd..6832494e 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -42,12 +42,14 @@ rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
# note: it looks like librsyslog.la must be explicitely given on LDDADD,
# otherwise dependencies are not properly calculated (resulting in a
# potentially incomplete build, a problem we had several times...)
-rsyslogd_LDADD = ../grammar/libgrammar.la ../runtime/librsyslog.la $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) $(LIBUUID_LIBS) $(LIBGCRYPT_LIBS)
+rsyslogd_LDADD = ../grammar/libgrammar.la ../runtime/librsyslog.la $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBUUID_LIBS)
rsyslogd_LDFLAGS = -export-dynamic
EXTRA_DIST = $(man_MANS) \
rsgtutil.rst \
+ rsgtutil.1 \
rscryutil.rst \
+ rscryutil.1 \
recover_qi.pl
if ENABLE_DIAGTOOLS
diff --git a/tools/omfile.c b/tools/omfile.c
index ba9f7f70..2ebb7df9 100644
--- a/tools/omfile.c
+++ b/tools/omfile.c
@@ -155,7 +155,6 @@ typedef struct _instanceData {
uchar *cryprovName; /* crypto provider */
uchar *cryprovNameFull;/* full internal crypto provider name */
void *cryprovData; /* opaque data ptr for provider use */
- void *cryprovFileData;/* opaque data ptr for file instance */
cryprov_if_t cryprov; /* ptr to crypto provider interface */
sbool useCryprov; /* quicker than checkig ptr (1 vs 8 bytes!) */
int iCurrElt; /* currently active cache element (-1 = none) */
@@ -1089,7 +1088,7 @@ initCryprov(instanceData *pData, struct nvlst *lst)
szDrvrName);
ABORT_FINALIZE(RS_RET_CRYPROV_ERR);
}
- CHKiRet(pData->cryprov.SetCnfParam(pData->cryprovData, lst));
+ CHKiRet(pData->cryprov.SetCnfParam(pData->cryprovData, lst, CRYPROV_PARAMTYPE_REGULAR));
dbgprintf("loaded crypto provider %s, data instance at %p\n",
szDrvrName, pData->cryprovData);
diff --git a/tools/rsyslogd.8 b/tools/rsyslogd.8
index 620006f2..ac732b88 100644
--- a/tools/rsyslogd.8
+++ b/tools/rsyslogd.8
@@ -191,6 +191,10 @@ is specified and the host logging resolves to satu.infodrom.north.de
no domain would be cut, you will have to specify two domains like:
.BR "\-s north.de:infodrom.north.de" .
.TP
+.BI "\-S ip_address" "local client source IP"
+rsyslogd uses ip_address as local client address while connecting
+to remote logserver. Currently used by omrelp only and only with tcp.
+.TP
.BI "\-u " "userlevel"
This is a "catch all" option for some very seldomly-used user settings.
The "userlevel" variable selects multiple things. Add the specific values
diff --git a/tools/syslogd.c b/tools/syslogd.c
index 1b38bf92..2bc80e44 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -51,7 +51,6 @@
#include <stddef.h>
#include <ctype.h>
#include <limits.h>
-#define GNU_SOURCE
#include <string.h>
#include <stdarg.h>
#include <time.h>
@@ -1057,7 +1056,7 @@ finalize_it:
* the time being (remember that we want to restructure config processing at large!).
* rgerhards, 2009-10-27
*/
-rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName, struct cnfparamvals *queueParams)
+rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName, struct nvlst *lst)
{
struct queuefilenames_s *qfn;
uchar *qfname = NULL;
@@ -1073,7 +1072,7 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName, struct cnfpara
/* name our main queue object (it's not fatal if it fails...) */
obj.SetName((obj_t*) (*ppQueue), pszQueueName);
- if(queueParams == NULL) { /* use legacy parameters? */
+ if(lst == NULL) { /* use legacy parameters? */
/* ... set some properties ... */
# define setQPROP(func, directive, data) \
CHKiRet_Hdlr(func(*ppQueue, data)) { \
@@ -1130,7 +1129,7 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName, struct cnfpara
# undef setQPROPstr
} else { /* use new style config! */
qqueueSetDefaultsRulesetQueue(*ppQueue);
- qqueueApplyCnfParam(*ppQueue, queueParams);
+ qqueueApplyCnfParam(*ppQueue, lst);
}
/* ... and finally start the queue! */
@@ -1773,7 +1772,7 @@ int realMain(int argc, char **argv)
* of other options, we do this during the inital option processing.
* rgerhards, 2008-04-04
*/
- while((ch = getopt(argc, argv, "46a:Ac:dDef:g:hi:l:m:M:nN:op:qQr::s:t:T:u:vwx")) != EOF) {
+ while((ch = getopt(argc, argv, "46a:Ac:dDef:g:hi:l:m:M:nN:op:qQr::s:S:t:T:u:vwx")) != EOF) {
switch((char)ch) {
case '4':
case '6':
@@ -1791,6 +1790,7 @@ int realMain(int argc, char **argv)
case 'q': /* add hostname if DNS resolving has failed */
case 'Q': /* dont resolve hostnames in ACL to IPs */
case 's':
+ case 'S': /* Source IP for local client to be used on multihomed host */
case 'T': /* chroot on startup (primarily for testing) */
case 'u': /* misc user settings */
case 'w': /* disable disallowed host warnings */
@@ -1882,6 +1882,13 @@ int realMain(int argc, char **argv)
case 'a':
fprintf(stderr, "rsyslogd: error -a is no longer supported, use module imuxsock instead");
break;
+ case 'S': /* Source IP for local client to be used on multihomed host */
+ if(glbl.GetSourceIPofLocalClient() != NULL) {
+ fprintf (stderr, "rsyslogd: Only one -S argument allowed, the first one is taken.\n");
+ } else {
+ glbl.SetSourceIPofLocalClient((uchar*)arg);
+ }
+ break;
case 'f': /* configuration file */
ConfFile = (uchar*) arg;
break;