summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2009-10-02 10:27:55 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2009-10-02 10:27:55 +0200
commitf7f7d951fcbaa0f30b43c651dae36bcf31c91e78 (patch)
tree6b3cdb26c631d28f743ee44894d0ff19669b009b
parent8d8d1f01e1cd6ae372088a3ebddc27983e9a0185 (diff)
parent4c8546fd6fb56d5439edb5a098c8f82bc8fc36aa (diff)
downloadrsyslog-f7f7d951fcbaa0f30b43c651dae36bcf31c91e78.tar.gz
rsyslog-f7f7d951fcbaa0f30b43c651dae36bcf31c91e78.tar.xz
rsyslog-f7f7d951fcbaa0f30b43c651dae36bcf31c91e78.zip
Merge branch 'v4-beta' into beta
Conflicts: ChangeLog configure.ac doc/manual.html runtime/rsyslog.h tcpsrv.c
-rw-r--r--ChangeLog27
-rw-r--r--doc/imtcp.html4
-rw-r--r--doc/rsconf1_dircreatemode.html10
-rw-r--r--plugins/imtcp/imtcp.c5
-rw-r--r--plugins/imudp/imudp.c3
-rw-r--r--plugins/omstdout/omstdout.c2
-rw-r--r--runtime/datetime.c119
-rw-r--r--runtime/datetime.h4
-rw-r--r--runtime/parser.c13
-rw-r--r--runtime/rsyslog.h8
-rw-r--r--tcpsrv.c19
-rw-r--r--tcpsrv.h5
-rw-r--r--tools/syslogd.c100
13 files changed, 238 insertions, 81 deletions
diff --git a/ChangeLog b/ChangeLog
index 1aaeede1..3e7557d2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,15 @@
---------------------------------------------------------------------------
Version 5.1.6 [v5-beta] (rgerhards), 2009-09-??
+- feature imports from v4.5.6
- bugfixes imported from 4.5.4:
* bugfix: potential segfault in stream writer on destruction
* bugfix: potential race in object loader (obj.c) during use/release
* bugfixes: potential problems in out file zip writer
+- included some important fixes from 4.4.2:
+ * bugfix: invalid handling of zero-sized messages
+ * bugfix: zero-sized UDP messages are no longer processed
+ * bugfix: random data could be appended to message
+ * bugfix: reverse lookup reduction logic in imudp do DNS queries too often
---------------------------------------------------------------------------
Version 5.1.5 [v5-beta] (rgerhards), 2009-09-11
- added new config option $ActionWriteAllMarkMessages
@@ -116,6 +122,17 @@ increase.
- increased ompgsql performance by adapting to new transactional
output module interface
---------------------------------------------------------------------------
+Version 4.5.6 [v4-beta] (rgerhards), 2009-09-??
+- included some important fixes from v4-stable:
+ * bugfix: invalid handling of zero-sized messages
+ * bugfix: zero-sized UDP messages are no longer processed
+ * bugfix: random data could be appended to message
+ * bugfix: reverse lookup reduction logic in imudp do DNS queries too often
+---------------------------------------------------------------------------
+Version 4.5.5 [v4-beta] (rgerhards), 2009-09-??
+- added $InputTCPServerNotifyOnConnectionClose config directive
+ see doc for details
+---------------------------------------------------------------------------
Version 4.5.4 [v4-beta] (rgerhards), 2009-09-29
- bugfix: potential segfault in stream writer on destruction
Most severely affected omfile. The problem was that some buffers were
@@ -245,6 +262,15 @@ Version 4.5.0 [DEVEL] (rgerhards), 2009-07-02
an abort
---------------------------------------------------------------------------
Version 4.4.2 [v4-stable] (rgerhards), 2009-09-??
+- bugfix: invalid handling of zero-sized messages, could lead to mis-
+ addressing and potential memory corruption/segfault
+- bugfix: zero-sized UDP messages are no longer processed
+ until now, they were forwarded to processing, but this makes no sense
+ Also, it looks like the system seems to provide a zero return code
+ on a UDP recvfrom() from time to time for some internal reasons. These
+ "receives" are now silently ignored.
+- bugfix: random data could be appended to message, possibly causing
+ segfaults
- bugfix: reverse lookup reduction logic in imudp do DNS queries too often
A comparison was done between the current and the former source address.
However, this was done on the full sockaddr_storage structure and not
@@ -1637,6 +1663,7 @@ Version 2.0.8 V2-STABLE (rgerhards), 2008-??-??
connection broke, but not if there was a problem with statement
execution. The most probable case for such a case would be invalid
sql inside the template, and this is now much easier to diagnose.
+- doc bugfix: default for $DirCreateMode incorrectly stated
---------------------------------------------------------------------------
Version 2.0.7 V2-STABLE (rgerhards), 2008-04-14
- bugfix: the default for $DirCreateMode was 0644, and as such wrong.
diff --git a/doc/imtcp.html b/doc/imtcp.html
index 5217634e..0ccdecc7 100644
--- a/doc/imtcp.html
+++ b/doc/imtcp.html
@@ -41,6 +41,10 @@ very limited interest in fixing this issue. This directive <b>can not</b> fix th
That would require much more code changes, which I was unable to do so far. Full details
can be found at the <a href="http://www.rsyslog.com/Article321.phtml">Cisco tcp syslog anomaly</a>
page.
+<li>$InputTCPServerNotifyOnConnectionClose [on/<b>off</b>] (available since 4.5.5)<br>
+instructs imtcp to emit a message if the remote peer closes a connection.<br>
+<b>Important:</b> This directive is global to all listeners and must be given right
+after loading imtcp, otherwise it may have no effect.</li>
<li>$InputTCPServerRun &lt;port&gt;<br>
Starts a TCP server on selected port</li>
<li>$InputTCPMaxListeners &lt;number&gt;<br>
diff --git a/doc/rsconf1_dircreatemode.html b/doc/rsconf1_dircreatemode.html
index 9a9c61eb..b22b6c59 100644
--- a/doc/rsconf1_dircreatemode.html
+++ b/doc/rsconf1_dircreatemode.html
@@ -7,9 +7,13 @@
<h2>$DirCreateMode</h2>
<p><b>Type:</b> global configuration directive</p>
-<p><b>Default:</b> 0644</p>
+<p><b>Default:</b> 0700</p>
<p><b>Description:</b></p>
<p>This is the same as $FileCreateMode, but for directories automatically generated.</p>
+<p>Please visit the
+<a target="_blank" href="http://lists.adiscon.net/pipermail/rsyslog/2009-April/001986.html">rsyslog mailing list
+archive</a>
+to understand why the default is so restrictive.</p>
<p><b>Sample:</b></p>
<p><code><b></b></code></p>
@@ -17,8 +21,8 @@
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; 2007 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+Copyright &copy; 2007-2009 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 2 or higher.</font></p>
+version 3 or higher.</font></p>
</body>
</html>
diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c
index 0bd064e6..c56593f2 100644
--- a/plugins/imtcp/imtcp.c
+++ b/plugins/imtcp/imtcp.c
@@ -84,6 +84,7 @@ static permittedPeers_t *pPermPeersRoot = NULL;
static int iTCPSessMax = 200; /* max number of sessions */
static int iTCPLstnMax = 20; /* max number of sessions */
static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */
+static int bEmitMsgOnClose = 0; /* emit an informational message on close by remote peer */
static int iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; /* addtl frame delimiter, e.g. for netscreen, default none */
static uchar *pszStrmDrvrAuthMode = NULL; /* authentication mode to use */
static uchar *pszInputName = NULL; /* value for inputname property, NULL is OK and handled by core engine */
@@ -197,6 +198,7 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa
CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose));
CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, iStrmDrvrMode));
CHKiRet(tcpsrv.SetAddtlFrameDelim(pOurTcpsrv, iAddtlFrameDelim));
+ CHKiRet(tcpsrv.SetNotificationOnRemoteClose(pOurTcpsrv, bEmitMsgOnClose));
/* now set optional params, but only if they were actually configured */
if(pszStrmDrvrAuthMode != NULL) {
CHKiRet(tcpsrv.SetDrvrAuthMode(pOurTcpsrv, pszStrmDrvrAuthMode));
@@ -284,6 +286,7 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus
iTCPSessMax = 200;
iTCPLstnMax = 20;
iStrmDrvrMode = 0;
+ bEmitMsgOnClose = 0;
iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
free(pszInputName);
pszInputName = NULL;
@@ -321,6 +324,8 @@ CODEmodInit_QueryRegCFSLineHdlr
NULL, &iTCPSessMax, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpmaxlisteners"), 0, eCmdHdlrInt,
NULL, &iTCPLstnMax, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpservernotifyonconnectionclose"), 0,
+ eCmdHdlrBinary, NULL, &bEmitMsgOnClose, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdrivermode"), 0,
eCmdHdlrInt, NULL, &iStrmDrvrMode, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdriverauthmode"), 0,
diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c
index 0a8920f5..b9db1875 100644
--- a/plugins/imudp/imudp.c
+++ b/plugins/imudp/imudp.c
@@ -208,6 +208,9 @@ processSocket(int fd, struct sockaddr_storage *frominetPrev, int *pbIsPermitted,
ABORT_FINALIZE(RS_RET_ERR);
}
+ if(lenRcvBuf == 0)
+ continue; /* this looks a bit strange, but practice shows it happens... */
+
/* if we reach this point, we had a good receive and can process the packet received */
/* check if we have a different sender than before, if so, we need to query some new values */
if(net.CmpHost(&frominet, frominetPrev, socklen) != 0) {
diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c
index 584ae458..b3ec6287 100644
--- a/plugins/omstdout/omstdout.c
+++ b/plugins/omstdout/omstdout.c
@@ -124,7 +124,7 @@ CODESTARTdoAction
toWrite = (char*) ppString[0];
}
len = strlen(toWrite);
- write(1, toWrite, strlen(toWrite)); /* 1 is stdout! */
+ write(1, toWrite, len); /* 1 is stdout! */
if(pData->bEnsureLFEnding && toWrite[len-1] != '\n') {
write(1, "\n", 1); /* write missing LF */
}
diff --git a/runtime/datetime.c b/runtime/datetime.c
index dfa56b4f..6160bd7c 100644
--- a/runtime/datetime.c
+++ b/runtime/datetime.c
@@ -143,6 +143,7 @@ static void getCurrTime(struct syslogTime *t, time_t *ttSeconds)
* DO NOT PUT ANY OTHER CODE IN THIS BEGIN ... END BLOCK!!!!
*/
+
/**
* Parse a 32 bit integer number from a string.
*
@@ -150,17 +151,21 @@ static void getCurrTime(struct syslogTime *t, time_t *ttSeconds)
* must be positioned at the first digit. Will be updated
* so that on return it points to the first character AFTER
* the integer parsed.
+ * \param pLenStr pointer to string length, decremented on exit by
+ * characters processed
+ * Note that if an empty string (len < 1) is passed in,
+ * the method always returns zero.
* \retval The number parsed.
*/
-
-static int srSLMGParseInt32(uchar** ppsz)
+static int srSLMGParseInt32(uchar** ppsz, int *pLenStr)
{
register int i;
i = 0;
- while(isdigit((int) **ppsz)) {
+ while(*pLenStr > 0 && isdigit((int) **ppsz)) {
i = i * 10 + **ppsz - '0';
++(*ppsz);
+ --(*pLenStr);
}
return i;
@@ -172,9 +177,13 @@ static int srSLMGParseInt32(uchar** ppsz)
* updates the parse pointer position. The pTime parameter
* is guranteed to be updated only if a new valid timestamp
* could be obtained (restriction added 2008-09-16 by rgerhards).
+ * This method now also checks the maximum string length it is passed.
+ * If a *valid* timestamp is found, the string length is decremented
+ * by the number of characters processed. If it is not a valid timestamp,
+ * the length is kept unmodified. -- rgerhards, 2009-09-23
*/
static rsRetVal
-ParseTIMESTAMP3339(struct syslogTime *pTime, uchar** ppszTS)
+ParseTIMESTAMP3339(struct syslogTime *pTime, uchar** ppszTS, int *pLenStr)
{
uchar *pszTS = *ppszTS;
/* variables to temporarily hold time information while we parse */
@@ -189,6 +198,7 @@ ParseTIMESTAMP3339(struct syslogTime *pTime, uchar** ppszTS)
char OffsetMode; /* UTC offset + or - */
char OffsetHour; /* UTC offset in hours */
int OffsetMinute; /* UTC offset in minutes */
+ int lenStr;
/* end variables to temporarily hold time information while we parse */
DEFiRet;
@@ -196,48 +206,55 @@ ParseTIMESTAMP3339(struct syslogTime *pTime, uchar** ppszTS)
assert(ppszTS != NULL);
assert(pszTS != NULL);
- year = srSLMGParseInt32(&pszTS);
+ lenStr = *pLenStr;
+ year = srSLMGParseInt32(&pszTS, &lenStr);
/* We take the liberty to accept slightly malformed timestamps e.g. in
* the format of 2003-9-1T1:0:0. This doesn't hurt on receiving. Of course,
* with the current state of affairs, we would never run into this code
* here because at postion 11, there is no "T" in such cases ;)
*/
- if(*pszTS++ != '-')
+ if(lenStr == 0 || *pszTS++ != '-')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- month = srSLMGParseInt32(&pszTS);
+ --lenStr;
+ month = srSLMGParseInt32(&pszTS, &lenStr);
if(month < 1 || month > 12)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- if(*pszTS++ != '-')
+ if(lenStr == 0 || *pszTS++ != '-')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- day = srSLMGParseInt32(&pszTS);
+ --lenStr;
+ day = srSLMGParseInt32(&pszTS, &lenStr);
if(day < 1 || day > 31)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- if(*pszTS++ != 'T')
+ if(lenStr == 0 || *pszTS++ != 'T')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ --lenStr;
- hour = srSLMGParseInt32(&pszTS);
+ hour = srSLMGParseInt32(&pszTS, &lenStr);
if(hour < 0 || hour > 23)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- if(*pszTS++ != ':')
+ if(lenStr == 0 || *pszTS++ != ':')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- minute = srSLMGParseInt32(&pszTS);
+ --lenStr;
+ minute = srSLMGParseInt32(&pszTS, &lenStr);
if(minute < 0 || minute > 59)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- if(*pszTS++ != ':')
+ if(lenStr == 0 || *pszTS++ != ':')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- second = srSLMGParseInt32(&pszTS);
+ --lenStr;
+ second = srSLMGParseInt32(&pszTS, &lenStr);
if(second < 0 || second > 60)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
/* Now let's see if we have secfrac */
- if(*pszTS == '.') {
+ if(lenStr > 0 && *pszTS == '.') {
+ --lenStr;
uchar *pszStart = ++pszTS;
- secfrac = srSLMGParseInt32(&pszTS);
+ secfrac = srSLMGParseInt32(&pszTS, &lenStr);
secfracPrecision = (int) (pszTS - pszStart);
} else {
secfracPrecision = 0;
@@ -245,23 +262,27 @@ ParseTIMESTAMP3339(struct syslogTime *pTime, uchar** ppszTS)
}
/* check the timezone */
- if(*pszTS == 'Z')
- {
+ if(lenStr == 0)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+
+ if(*pszTS == 'Z') {
+ --lenStr;
pszTS++; /* eat Z */
OffsetMode = 'Z';
OffsetHour = 0;
OffsetMinute = 0;
} else if((*pszTS == '+') || (*pszTS == '-')) {
OffsetMode = *pszTS;
+ --lenStr;
pszTS++;
- OffsetHour = srSLMGParseInt32(&pszTS);
+ OffsetHour = srSLMGParseInt32(&pszTS, &lenStr);
if(OffsetHour < 0 || OffsetHour > 23)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- if(*pszTS++ != ':')
+ if(lenStr == 0 || *pszTS++ != ':')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- OffsetMinute = srSLMGParseInt32(&pszTS);
+ OffsetMinute = srSLMGParseInt32(&pszTS, &lenStr);
if(OffsetMinute < 0 || OffsetMinute > 59)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else {
@@ -270,10 +291,12 @@ ParseTIMESTAMP3339(struct syslogTime *pTime, uchar** ppszTS)
}
/* OK, we actually have a 3339 timestamp, so let's indicated this */
- if(*pszTS == ' ')
+ if(lenStr > 0 && *pszTS == ' ') {
+ --lenStr;
++pszTS;
- else
+ } else {
ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ }
/* we had success, so update parse pointer and caller-provided timestamp */
*ppszTS = pszTS;
@@ -289,6 +312,7 @@ ParseTIMESTAMP3339(struct syslogTime *pTime, uchar** ppszTS)
pTime->OffsetMode = OffsetMode;
pTime->OffsetHour = OffsetHour;
pTime->OffsetMinute = OffsetMinute;
+ *pLenStr = lenStr;
finalize_it:
RETiRet;
@@ -307,9 +331,13 @@ finalize_it:
* permits us to use a pre-aquired timestamp and thus avoids to do
* a (costly) time() call. Thanks to David Lang for insisting on
* time() call reduction ;).
+ * This method now also checks the maximum string length it is passed.
+ * If a *valid* timestamp is found, the string length is decremented
+ * by the number of characters processed. If it is not a valid timestamp,
+ * the length is kept unmodified. -- rgerhards, 2009-09-23
*/
static rsRetVal
-ParseTIMESTAMP3164(struct syslogTime *pTime, uchar** ppszTS)
+ParseTIMESTAMP3164(struct syslogTime *pTime, uchar** ppszTS, int *pLenStr)
{
/* variables to temporarily hold time information while we parse */
int month;
@@ -319,6 +347,7 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, uchar** ppszTS)
int minute;
int second;
/* end variables to temporarily hold time information while we parse */
+ int lenStr;
uchar *pszTS;
DEFiRet;
@@ -326,6 +355,8 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, uchar** ppszTS)
pszTS = *ppszTS;
assert(pszTS != NULL);
assert(pTime != NULL);
+ assert(pLenStr != NULL);
+ lenStr = *pLenStr;
/* If we look at the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec),
* we may see the following character sequences occur:
@@ -348,6 +379,9 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, uchar** ppszTS)
* june, when it first manifested. This also lead to invalid parsing of the rest
* of the message, as the time stamp was not detected to be correct. - rgerhards
*/
+ if(lenStr < 3)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+
switch(*pszTS++)
{
case 'j':
@@ -470,26 +504,31 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, uchar** ppszTS)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
}
+ lenStr -= 3;
+
/* done month */
- if(*pszTS++ != ' ')
+ if(lenStr == 0 || *pszTS++ != ' ')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
/* we accept a slightly malformed timestamp when receiving. This is
* we accept one-digit days
*/
- if(*pszTS == ' ')
+ if(*pszTS == ' ') {
+ --lenStr;
++pszTS;
+ }
- day = srSLMGParseInt32(&pszTS);
+ day = srSLMGParseInt32(&pszTS, &lenStr);
if(day < 1 || day > 31)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- if(*pszTS++ != ' ')
+ if(lenStr == 0 || *pszTS++ != ' ')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ --lenStr;
/* time part */
- hour = srSLMGParseInt32(&pszTS);
+ hour = srSLMGParseInt32(&pszTS, &lenStr);
if(hour > 1970 && hour < 2100) {
/* if so, we assume this actually is a year. This is a format found
* e.g. in Cisco devices.
@@ -499,23 +538,26 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, uchar** ppszTS)
year = hour;
/* re-query the hour, this time it must be valid */
- if(*pszTS++ != ' ')
+ if(lenStr == 0 || *pszTS++ != ' ')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- hour = srSLMGParseInt32(&pszTS);
+ --lenStr;
+ hour = srSLMGParseInt32(&pszTS, &lenStr);
}
if(hour < 0 || hour > 23)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- if(*pszTS++ != ':')
+ if(lenStr == 0 || *pszTS++ != ':')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- minute = srSLMGParseInt32(&pszTS);
+ --lenStr;
+ minute = srSLMGParseInt32(&pszTS, &lenStr);
if(minute < 0 || minute > 59)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- if(*pszTS++ != ':')
+ if(lenStr == 0 || *pszTS++ != ':')
ABORT_FINALIZE(RS_RET_INVLD_TIME);
- second = srSLMGParseInt32(&pszTS);
+ --lenStr;
+ second = srSLMGParseInt32(&pszTS, &lenStr);
if(second < 0 || second > 60)
ABORT_FINALIZE(RS_RET_INVLD_TIME);
@@ -523,8 +565,10 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, uchar** ppszTS)
* invalid format, it occurs frequently enough (e.g. with Cisco devices)
* to permit it as a valid case. -- rgerhards, 2008-09-12
*/
- if(*pszTS++ == ':')
+ if(lenStr == 0 || *pszTS++ == ':') {
++pszTS; /* just skip past it */
+ --lenStr;
+ }
/* we had success, so update parse pointer and caller-provided timestamp
* fields we do not have are not updated in the caller's timestamp. This
@@ -541,6 +585,7 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, uchar** ppszTS)
pTime->second = second;
pTime->secfracPrecision = 0;
pTime->secfrac = 0;
+ *pLenStr = lenStr;
finalize_it:
RETiRet;
diff --git a/runtime/datetime.h b/runtime/datetime.h
index 58f368e7..8140eb71 100644
--- a/runtime/datetime.h
+++ b/runtime/datetime.h
@@ -34,8 +34,8 @@ typedef struct datetime_s {
/* interfaces */
BEGINinterface(datetime) /* name must also be changed in ENDinterface macro! */
void (*getCurrTime)(struct syslogTime *t, time_t *ttSeconds);
- rsRetVal (*ParseTIMESTAMP3339)(struct syslogTime *pTime, uchar** ppszTS);
- rsRetVal (*ParseTIMESTAMP3164)(struct syslogTime *pTime, uchar** pszTS);
+ rsRetVal (*ParseTIMESTAMP3339)(struct syslogTime *pTime, uchar** ppszTS, int*);
+ rsRetVal (*ParseTIMESTAMP3164)(struct syslogTime *pTime, uchar** pszTS, int*);
int (*formatTimestampToMySQL)(struct syslogTime *ts, char* pDst);
int (*formatTimestampToPgSQL)(struct syslogTime *ts, char *pDst);
int (*formatTimestamp3339)(struct syslogTime *ts, char* pBuf);
diff --git a/runtime/parser.c b/runtime/parser.c
index db11ac5b..466066e7 100644
--- a/runtime/parser.c
+++ b/runtime/parser.c
@@ -167,6 +167,7 @@ sanitizeMessage(msg_t *pMsg)
uchar szSanBuf[32*1024]; /* buffer used for sanitizing a string */
assert(pMsg != NULL);
+ assert(pMsg->iLenRawMsg > 0);
# ifdef USE_NETZIP
CHKiRet(uncompressMessage(pMsg));
@@ -254,6 +255,7 @@ finalize_it:
RETiRet;
}
+
/* Parse a received message. The object's rawmsg property is taken and
* parsed according to the relevant standards. This can later be
* extended to support configured parsers.
@@ -264,6 +266,11 @@ rsRetVal parseMsg(msg_t *pMsg)
DEFiRet;
uchar *msg;
int pri;
+ int lenMsg;
+ int iPriText;
+
+ if(pMsg->iLenRawMsg == 0)
+ ABORT_FINALIZE(RS_RET_EMPTY_MSG);
CHKiRet(sanitizeMessage(pMsg));
@@ -271,15 +278,17 @@ rsRetVal parseMsg(msg_t *pMsg)
DBGPRINTF("msg parser: flags %x, from '%s', msg '%s'\n", pMsg->msgFlags, getRcvFrom(pMsg), pMsg->pszRawMsg);
/* pull PRI */
- pri = DEFUPRI;
+ lenMsg = pMsg->iLenRawMsg;
msg = pMsg->pszRawMsg;
+ pri = DEFUPRI;
+ iPriText = 0;
if(*msg == '<') {
/* while we process the PRI, we also fill the PRI textual representation
* inside the msg object. This may not be ideal from an OOP point of view,
* but it offers us performance...
*/
pri = 0;
- while(isdigit((int) *++msg)) {
+ while(--lenMsg > 0 && isdigit((int) *++msg)) {
pri = 10 * pri + (*msg - '0');
}
if(*msg == '>')
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 71cb9cf2..59e8458b 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -381,9 +381,11 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_FILENAME_INVALID = -2140, /**< filename invalid, not found, no access, ... */
RS_RET_ZLIB_ERR = -2141, /**< error during zlib call */
RS_RET_VAR_NOT_FOUND = -2142, /**< variable not found */
- RS_RET_NO_SRCNAME_TPL = -2143, /**< sourcename template was not specified where one was needed (omudpspoof spoof addr) */
- RS_RET_HOST_NOT_SPECIFIED = -2144, /**< (target) host was not specified where it was needed */
- RS_RET_ERR_LIBNET_INIT = -2145, /**< error initializing libnet */
+ RS_RET_EMPTY_MSG = -2143, /**< provided (raw) MSG is empty */
+ RS_RET_PEER_CLOSED_CONN = -2144, /**< remote peer closed connection (information, no error) */
+ RS_RET_NO_SRCNAME_TPL = -2150, /**< sourcename template was not specified where one was needed (omudpspoof spoof addr) */
+ RS_RET_HOST_NOT_SPECIFIED = -2151, /**< (target) host was not specified where it was needed */
+ RS_RET_ERR_LIBNET_INIT = -2152, /**< error initializing libnet */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/tcpsrv.c b/tcpsrv.c
index 3f445063..49d8a099 100644
--- a/tcpsrv.c
+++ b/tcpsrv.c
@@ -482,6 +482,14 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t **ppSess)
iRet = pThis->pRcvData(*ppSess, buf, sizeof(buf), &iRcvd);
switch(iRet) {
case RS_RET_CLOSED:
+ if(pThis->bEmitMsgOnClose) {
+ uchar *pszPeer;
+ int lenPeer;
+ errno = 0;
+ prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer);
+ errmsg.LogError(0, RS_RET_PEER_CLOSED_CONN, "Netstream session %p closed by remote peer %s.\n",
+ (*ppSess)->pStrm, pszPeer);
+ }
pThis->pOnRegularClose(*ppSess);
tcps_sess.Destruct(ppSess);
break;
@@ -794,6 +802,16 @@ SetRuleset(tcpsrv_t *pThis, ruleset_t *pRuleset)
}
+/* Set connection close notification */
+static rsRetVal
+SetNotificationOnRemoteClose(tcpsrv_t *pThis, int bNewVal)
+{
+ DEFiRet;
+ pThis->bEmitMsgOnClose = bNewVal;
+ RETiRet;
+}
+
+
/* here follows a number of methods that shuffle authentication settings down
* to the drivers. Drivers not supporting these settings may return an error
* state.
@@ -910,6 +928,7 @@ CODESTARTobjQueryInterface(tcpsrv)
pIf->SetCBOnErrClose = SetCBOnErrClose;
pIf->SetOnMsgReceive = SetOnMsgReceive;
pIf->SetRuleset = SetRuleset;
+ pIf->SetNotificationOnRemoteClose = SetNotificationOnRemoteClose;
finalize_it:
ENDobjQueryInterface(tcpsrv)
diff --git a/tcpsrv.h b/tcpsrv.h
index 64065aab..b8d82163 100644
--- a/tcpsrv.h
+++ b/tcpsrv.h
@@ -54,12 +54,14 @@ struct tcpsrv_s {
uchar *pszInputName; /**< value to be used as input name */
ruleset_t *pRuleset; /**< ruleset to bind to */
permittedPeers_t *pPermPeers;/**< driver's permitted peers */
+ bool bEmitMsgOnClose; /**< emit an informational message when the remote peer closes connection */
int iLstnCurr; /**< max nbr of listeners currently supported */
netstrm_t **ppLstn; /**< our netstream listners */
tcpLstnPortList_t **ppLstnPort; /**< pointer to relevant listen port description */
int iLstnMax; /**< max number of listners supported */
int iSessMax; /**< max number of sessions supported */
tcpLstnPortList_t *pLstnPorts; /**< head pointer for listen ports */
+
int addtlFrameDelim; /**< additional frame delimiter for plain TCP syslog framing (e.g. to handle NetScreen) */
tcps_sess_t **pSessions;/**< array of all of our sessions */
void *pUsr; /**< a user-settable pointer (provides extensibility for "derived classes")*/
@@ -114,8 +116,9 @@ BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SetRuleset)(tcpsrv_t *pThis, ruleset_t*); /* 2009-06-12 */
/* added v7 */
rsRetVal (*SetLstnMax)(tcpsrv_t *pThis, int iMaxLstn); /* 2009-08-17 */
+ rsRetVal (*SetNotificationOnRemoteClose)(tcpsrv_t *pThis, int bNewVal); /* 2009-10-01 */
ENDinterface(tcpsrv)
-#define tcpsrvCURR_IF_VERSION 7 /* increment whenever you change the interface structure! */
+#define tcpsrvCURR_IF_VERSION 8 /* increment whenever you change the interface structure! */
/* change for v4:
* - SetAddtlFrameDelim() added -- rgerhards, 2008-12-10
* - SetInputName() added -- rgerhards, 2008-12-10
diff --git a/tools/syslogd.c b/tools/syslogd.c
index ff671138..73b76df1 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -954,10 +954,12 @@ msgConsumer(void __attribute__((unused)) *notNeeded, batch_t *pBatch)
* to after the terminating SP. The caller must ensure that the
* provided buffer is large enough to hold the to be extracted value.
* Returns 0 if everything is fine or 1 if either the field is not
- * SP-terminated or any other error occurs.
- * rger, 2005-11-24
+ * SP-terminated or any other error occurs. -- rger, 2005-11-24
+ * The function now receives the size of the string and makes sure
+ * that it does not process more than that. The *pLenStr counter is
+ * updated on exit. -- rgerhards, 2009-09-23
*/
-static int parseRFCField(uchar **pp2parse, uchar *pResult)
+static int parseRFCField(uchar **pp2parse, uchar *pResult, int *pLenStr)
{
uchar *p2parse;
int iRet = 0;
@@ -969,14 +971,17 @@ static int parseRFCField(uchar **pp2parse, uchar *pResult)
p2parse = *pp2parse;
/* this is the actual parsing loop */
- while(*p2parse && *p2parse != ' ') {
+ while(*pLenStr > 0 && *p2parse != ' ') {
*pResult++ = *p2parse++;
+ --(*pLenStr);
}
- if(*p2parse == ' ')
+ if(*pLenStr > 0 && *p2parse == ' ') {
++p2parse; /* eat SP, but only if not at end of string */
- else
+ --(*pLenStr);
+ } else {
iRet = 1; /* there MUST be an SP! */
+ }
*pResult = '\0';
/* set the new parse pointer */
@@ -992,20 +997,24 @@ static int parseRFCField(uchar **pp2parse, uchar *pResult)
* to after the terminating SP. The caller must ensure that the
* provided buffer is large enough to hold the to be extracted value.
* Returns 0 if everything is fine or 1 if either the field is not
- * SP-terminated or any other error occurs.
- * rger, 2005-11-24
+ * SP-terminated or any other error occurs. -- rger, 2005-11-24
+ * The function now receives the size of the string and makes sure
+ * that it does not process more than that. The *pLenStr counter is
+ * updated on exit. -- rgerhards, 2009-09-23
*/
-static int parseRFCStructuredData(uchar **pp2parse, uchar *pResult)
+static int parseRFCStructuredData(uchar **pp2parse, uchar *pResult, int *pLenStr)
{
uchar *p2parse;
int bCont = 1;
int iRet = 0;
+ int lenStr;
assert(pp2parse != NULL);
assert(*pp2parse != NULL);
assert(pResult != NULL);
p2parse = *pp2parse;
+ lenStr = *pLenStr;
/* this is the actual parsing loop
* Remeber: structured data starts with [ and includes any characters
@@ -1013,40 +1022,55 @@ static int parseRFCStructuredData(uchar **pp2parse, uchar *pResult)
* structured data. There may also be \] inside the structured data, which
* do NOT terminate an element.
*/
- if(*p2parse != '[')
+ if(lenStr == 0 || *p2parse != '[')
return 1; /* this is NOT structured data! */
if(*p2parse == '-') { /* empty structured data? */
*pResult++ = '-';
++p2parse;
+ --lenStr;
} else {
while(bCont) {
- if(*p2parse == '\0') {
- iRet = 1; /* this is not valid! */
- bCont = 0;
+ if(lenStr < 2) {
+ /* we now need to check if we have only structured data */
+ if(lenStr > 0 && *p2parse == ']') {
+ *pResult++ = *p2parse;
+ p2parse++;
+ lenStr--;
+ bCont = 0;
+ } else {
+ iRet = 1; /* this is not valid! */
+ bCont = 0;
+ }
} else if(*p2parse == '\\' && *(p2parse+1) == ']') {
/* this is escaped, need to copy both */
*pResult++ = *p2parse++;
*pResult++ = *p2parse++;
+ lenStr -= 2;
} else if(*p2parse == ']' && *(p2parse+1) == ' ') {
/* found end, just need to copy the ] and eat the SP */
*pResult++ = *p2parse;
p2parse += 2;
+ lenStr -= 2;
bCont = 0;
} else {
*pResult++ = *p2parse++;
+ --lenStr;
}
}
}
- if(*p2parse == ' ')
+ if(lenStr > 0 && *p2parse == ' ') {
++p2parse; /* eat SP, but only if not at end of string */
- else
+ --lenStr;
+ } else {
iRet = 1; /* there MUST be an SP! */
+ }
*pResult = '\0';
/* set the new parse pointer */
*pp2parse = p2parse;
+ *pLenStr = lenStr;
return 0;
}
@@ -1071,23 +1095,26 @@ int parseRFCSyslogMsg(msg_t *pMsg, int flags)
{
uchar *p2parse;
uchar *pBuf;
+ int lenMsg;
int bContParse = 1;
BEGINfunc
assert(pMsg != NULL);
assert(pMsg->pszRawMsg != NULL);
p2parse = pMsg->pszRawMsg + pMsg->offAfterPRI; /* point to start of text, after PRI */
+ lenMsg = pMsg->iLenRawMsg - pMsg->offAfterPRI;
- /* do a sanity check on the version and eat it */
+ /* do a sanity check on the version and eat it (the caller checked this already) */
assert(p2parse[0] == '1' && p2parse[1] == ' ');
p2parse += 2;
+ lenMsg -= 2;
/* Now get us some memory we can use as a work buffer while parsing.
* We simply allocated a buffer sufficiently large to hold all of the
* message, so we can not run into any troubles. I think this is
* more wise then to use individual buffers.
*/
- if((pBuf = malloc(sizeof(uchar) * ustrlen(p2parse) + 1)) == NULL)
+ if((pBuf = malloc(sizeof(uchar) * (lenMsg + 1))) == NULL)
return 1;
/* IMPORTANT NOTE:
@@ -1098,7 +1125,7 @@ int parseRFCSyslogMsg(msg_t *pMsg, int flags)
*/
/* TIMESTAMP */
- if(datetime.ParseTIMESTAMP3339(&(pMsg->tTIMESTAMP), &p2parse) == RS_RET_OK) {
+ if(datetime.ParseTIMESTAMP3339(&(pMsg->tTIMESTAMP), &p2parse, &lenMsg) == RS_RET_OK) {
if(flags & IGNDATE) {
/* we need to ignore the msg data, so simply copy over reception date */
memcpy(&pMsg->tTIMESTAMP, &pMsg->tRcvdAt, sizeof(struct syslogTime));
@@ -1110,31 +1137,31 @@ int parseRFCSyslogMsg(msg_t *pMsg, int flags)
/* HOSTNAME */
if(bContParse) {
- parseRFCField(&p2parse, pBuf);
+ parseRFCField(&p2parse, pBuf, &lenMsg);
MsgSetHOSTNAME(pMsg, pBuf, ustrlen(pBuf));
}
/* APP-NAME */
if(bContParse) {
- parseRFCField(&p2parse, pBuf);
+ parseRFCField(&p2parse, pBuf, &lenMsg);
MsgSetAPPNAME(pMsg, (char*)pBuf);
}
/* PROCID */
if(bContParse) {
- parseRFCField(&p2parse, pBuf);
+ parseRFCField(&p2parse, pBuf, &lenMsg);
MsgSetPROCID(pMsg, (char*)pBuf);
}
/* MSGID */
if(bContParse) {
- parseRFCField(&p2parse, pBuf);
+ parseRFCField(&p2parse, pBuf, &lenMsg);
MsgSetMSGID(pMsg, (char*)pBuf);
}
/* STRUCTURED-DATA */
if(bContParse) {
- parseRFCStructuredData(&p2parse, pBuf);
+ parseRFCStructuredData(&p2parse, pBuf, &lenMsg);
MsgSetStructuredData(pMsg, (char*)pBuf);
}
@@ -1163,6 +1190,7 @@ int parseRFCSyslogMsg(msg_t *pMsg, int flags)
int parseLegacySyslogMsg(msg_t *pMsg, int flags)
{
uchar *p2parse;
+ int lenMsg;
int bTAGCharDetected;
int i; /* general index for parsing */
uchar bufParseTAG[CONF_TAG_MAXSIZE];
@@ -1171,27 +1199,32 @@ int parseLegacySyslogMsg(msg_t *pMsg, int flags)
assert(pMsg != NULL);
assert(pMsg->pszRawMsg != NULL);
+ lenMsg = pMsg->iLenRawMsg - (pMsg->offAfterPRI + 1);
+RUNLOG_VAR("%d", pMsg->offAfterPRI);
+RUNLOG_VAR("%d", lenMsg);
p2parse = pMsg->pszRawMsg + pMsg->offAfterPRI; /* point to start of text, after PRI */
/* Check to see if msg contains a timestamp. We start by assuming
- * that the message timestamp is the time of reciption (which we
+ * that the message timestamp is the time of reception (which we
* generated ourselfs and then try to actually find one inside the
* message. There we go from high-to low precison and are done
* when we find a matching one. -- rgerhards, 2008-09-16
*/
- if(datetime.ParseTIMESTAMP3339(&(pMsg->tTIMESTAMP), &p2parse) == RS_RET_OK) {
+ if(datetime.ParseTIMESTAMP3339(&(pMsg->tTIMESTAMP), &p2parse, &lenMsg) == RS_RET_OK) {
/* we are done - parse pointer is moved by ParseTIMESTAMP3339 */;
- } else if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), &p2parse) == RS_RET_OK) {
+ } else if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), &p2parse, &lenMsg) == RS_RET_OK) {
/* we are done - parse pointer is moved by ParseTIMESTAMP3164 */;
- } else if(*p2parse == ' ') { /* try to see if it is slighly malformed - HP procurve seems to do that sometimes */
+ } else if(*p2parse == ' ' && lenMsg > 1) { /* try to see if it is slighly malformed - HP procurve seems to do that sometimes */
++p2parse; /* move over space */
- if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), &p2parse) == RS_RET_OK) {
+ --lenMsg;
+ if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), &p2parse, &lenMsg) == RS_RET_OK) {
/* indeed, we got it! */
/* we are done - parse pointer is moved by ParseTIMESTAMP3164 */;
} else {/* parse pointer needs to be restored, as we moved it off-by-one
* for this try.
*/
--p2parse;
+ ++lenMsg;
}
}
@@ -1222,12 +1255,13 @@ int parseLegacySyslogMsg(msg_t *pMsg, int flags)
* that is not a valid hostname.
*/
bTAGCharDetected = 0;
- if(flags & PARSE_HOSTNAME) {
+ if(lenMsg > 0 && flags & PARSE_HOSTNAME) {
i = 0;
- while((isalnum(p2parse[i]) || p2parse[i] == '.' || p2parse[i] == '.'
+ while(lenMsg > 0 && (isalnum(p2parse[i]) || p2parse[i] == '.' || p2parse[i] == '.'
|| p2parse[i] == '_' || p2parse[i] == '-') && i < CONF_TAG_MAXSIZE) {
bufParseHOSTNAME[i] = p2parse[i];
++i;
+ --lenMsg;
}
if(i > 0 && p2parse[i] == ' ' && isalnum(p2parse[i-1])) {
@@ -1252,11 +1286,13 @@ int parseLegacySyslogMsg(msg_t *pMsg, int flags)
* outputs so that only 32 characters max are used by default.
*/
i = 0;
- while(*p2parse && *p2parse != ':' && *p2parse != ' ' && i < CONF_TAG_MAXSIZE) {
+ while(lenMsg > 0 && *p2parse != ':' && *p2parse != ' ' && i < CONF_TAG_MAXSIZE) {
bufParseTAG[i++] = *p2parse++;
+ --lenMsg;
}
- if(*p2parse == ':') {
+ if(lenMsg > 0 && *p2parse == ':') {
++p2parse;
+ --lenMsg;
bufParseTAG[i++] = ':';
}