diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2009-07-01 14:34:56 +0200 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2009-07-01 14:34:56 +0200 |
commit | 6322343eca1084b509386a94c1bcf2ca819f1220 (patch) | |
tree | cd873a34a4df087c3411de951c40a26f64f7d0ec | |
parent | e6aeb1b995d6629ff04fd0f6068be2e9ffe9ca42 (diff) | |
parent | 7bfa03bdc0b73647ffdbe4b73e5c1649af665fbf (diff) | |
download | rsyslog-6322343eca1084b509386a94c1bcf2ca819f1220.tar.gz rsyslog-6322343eca1084b509386a94c1bcf2ca819f1220.tar.xz rsyslog-6322343eca1084b509386a94c1bcf2ca819f1220.zip |
Merge branch 'master' into v5-devel
35 files changed, 1003 insertions, 282 deletions
@@ -44,6 +44,8 @@ increase. output module interface --------------------------------------------------------------------------- Version 4.5.0 [DEVEL] (rgerhards), 2009-??-?? +- activation order of inputs changed, they are now activated only after + privileges are dropped. Thanks to Michael Terry for the patch. - greatly improved performance - greatly reduced memory requirements of msg object to around half of the previous demand. This means that more messages can @@ -73,6 +75,16 @@ Version 4.5.0 [DEVEL] (rgerhards), 2009-??-?? - set a more sensible timeout for shutdow, now 1.5 seconds to complete processing (this also removes those cases where the shutdown message was not written because the termination happened before it) +- internal bugfix: object pointer was only reset to NULL when an object + was actually destructed. This most likely had no effect to existing code, + but it may also have caused trouble in remote cases. Similarly, the fix + may also cause trouble... +--------------------------------------------------------------------------- +Version 4.3.3 [beta] (rgerhards), 2009-0?-?? +- internal bugfix: object pointer was only reset to NULL when an object + was actually destructed. This most likely had no effect to existing code, + but it may also have caused trouble in remote cases. Similarly, the fix + may also cause trouble... --------------------------------------------------------------------------- Version 4.3.2 [beta] (rgerhards), 2009-06-24 - removed long-obsoleted property UxTradMsg @@ -129,6 +141,12 @@ Version 4.3.0 [DEVEL] (rgerhards), 2009-04-17 execution. The most probable case for such a case would be invalid sql inside the template, and this is now much easier to diagnose. --------------------------------------------------------------------------- +Version 4.2.1 [v4-stable] (rgerhards), 2009-0?-?? +- bugfix: stderr/stdout were not closed to be able to emit error messages, + but this caused ssh sessions to hang. Now we close them after the + initial initialization. See forum thread: + http://kb.monitorware.com/controlling-terminal-issues-t9875.html +--------------------------------------------------------------------------- Version 4.2.0 [v4-stable] (rgerhards), 2009-06-23 - bugfix: light and full delay watermarks had invalid values, badly affecting performance for delayable inputs @@ -30,7 +30,7 @@ rsRetVal multiSubmitMsg(multi_submit_t *pMultiSub); rsRetVal submitMsg(msg_t *pMsg); rsRetVal logmsgInternal(int iErr, int pri, uchar *msg, int flags); -rsRetVal parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlTypeu, uchar *pszInputName, struct syslogTime *stTime, time_t ttGenTime); +rsRetVal parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlTypeu, prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime); int parseRFCSyslogMsg(msg_t *pMsg, int flags); int parseLegacySyslogMsg(msg_t *pMsg, int flags); rsRetVal diagGetMainMsgQSize(int *piSize); /* for imdiag */ diff --git a/doc/omoracle.html b/doc/omoracle.html index 40f6360f..cfcf277f 100644 --- a/doc/omoracle.html +++ b/doc/omoracle.html @@ -67,6 +67,128 @@ it is suggested to post questions to the need to define the properties on the template in the correct order you want them passed to the statement! </pre> +<p>Some additional documentation contributed by Ronny Egner: +<pre> +REQUIREMENTS: +-------------- + +- Oracle Instantclient 10g (NOT 11g) Base + Devel + (if you´re on 64-bit linux you should choose the 64-bit libs!) +- JDK 1.6 (not neccessary for oracle plugin but "make" didd not finsished successfully without it) + +- "oracle-instantclient-config" script + (seems to shipped with instantclient 10g Release 1 but i was unable to find it for 10g Release 2 so here it is) + + +====================== /usr/local/bin/oracle-instantclient-config ===================== +#!/bin/sh +# +# Oracle InstantClient SDK config file +# Jean-Christophe Duberga - Bordeaux 2 University +# + +# just adapt it to your environment +incdirs="-I/usr/include/oracle/10.2.0.4/client64" +libdirs="-L/usr/lib/oracle/10.2.0.4/client64/lib" + +usage="\ +Usage: oracle-instantclient-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--cflags] [--libs] [--static-libs]" + +if test $# -eq 0; then + echo "${usage}" 1>&2 + exit 1 +fi + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + if test $exec_prefix_set = no ; then + exec_prefix=$optarg + fi + ;; + --prefix) + echo $prefix + ;; + --exec-prefix=*) + exec_prefix=$optarg + exec_prefix_set=yes + ;; + --exec-prefix) + echo ${exec_prefix} + ;; + --version) + echo ${version} + ;; + --cflags) + echo ${incdirs} + ;; + --libs) + echo $libdirs -lclntsh -lnnz10 -locci -lociei -locijdbc10 + ;; + --static-libs) + echo "No static libs" 1>&2 + exit 1 + ;; + *) + echo "${usage}" 1>&2 + exit 1 + ;; + esac + shift +done + +=============== END ============== + + + + +COMPILING RSYSLOGD +------------------- + + +./configure --enable-oracle + + + + +RUNNING +------- + +- make sure rsyslogd is able to locate the oracle libs (either via LD_LIBRARY_PATH or /etc/ld.so.conf) +- set TNS_ADMIN to point to your tnsnames.ora +- create a tnsnames.ora and test you are able to connect to the database + +- create user in oracle as shown in the following example: + create user syslog identified by syslog default tablespace users quota unlimited on users; + grant create session to syslog; + create role syslog_role; + grant syslog_role to syslog; + grant create table to syslog_role; + grant create sequence to syslog_role; + +- create tables as needed + +- configure rsyslog as shown in the following example + $ModLoad omoracle + + $OmoracleDBUser syslog + $OmoracleDBPassword syslog + $OmoracleDB syslog + $OmoracleBatchSize 1 + $OmoracleBatchItemSize 4096 + + $OmoracleStatementTemplate OmoracleStatement + $template OmoracleStatement,"insert into foo(hostname,message) values (:host,:message)" + $template TestStmt,"%hostname%%msg%" + *.* :omoracle:;TestStmt + (you guess it: username = password = database = "syslog".... see $rsyslogd_source/plugins/omoracle/omoracle.c for me info) +</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 diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c index 6edcb8b3..7cacc44a 100644 --- a/plugins/imdiag/imdiag.c +++ b/plugins/imdiag/imdiag.c @@ -66,10 +66,14 @@ DEFobjCurrIf(net) DEFobjCurrIf(netstrm) DEFobjCurrIf(errmsg) DEFobjCurrIf(datetime) +DEFobjCurrIf(prop) /* Module static data */ static tcpsrv_t *pOurTcpsrv = NULL; /* our TCP server(listener) TODO: change for multiple instances */ static permittedPeers_t *pPermPeersRoot = NULL; +static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this input */ +static prop_t *pRcvDummy = NULL; +static prop_t *pRcvIPDummy = NULL; /* config settings */ @@ -206,12 +210,12 @@ doInjectMsg(int iNum) /* we now create our own message object and submit it to the queue */ CHKiRet(msgConstructWithTime(&pMsg, &stTime, ttGenTime)); MsgSetRawMsg(pMsg, (char*) szMsg, ustrlen(szMsg)); - MsgSetInputName(pMsg, UCHAR_CONSTANT("imdiag"), sizeof("imdiag")-1); + MsgSetInputName(pMsg, pInputName); MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY); pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME; pMsg->bParseHOSTNAME = 1; - MsgSetRcvFrom(pMsg, UCHAR_CONSTANT("127.0.0.1")); /* TODO: way may use the real sender here... */ - CHKiRet(MsgSetRcvFromIP(pMsg, UCHAR_CONSTANT("127.0.0.1"))); + MsgSetRcvFrom(pMsg, pRcvDummy); + CHKiRet(MsgSetRcvFromIP(pMsg, pRcvIPDummy)); CHKiRet(submitMsg(pMsg)); finalize_it: @@ -380,13 +384,31 @@ CODESTARTwillRun /* first apply some config settings */ if(pOurTcpsrv == NULL) ABORT_FINALIZE(RS_RET_NO_RUN); + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imdiag"), sizeof("imdiag") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); + + CHKiRet(prop.Construct(&pRcvDummy)); + CHKiRet(prop.SetString(pRcvDummy, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1)); + CHKiRet(prop.ConstructFinalize(pRcvDummy)); + + CHKiRet(prop.Construct(&pRcvIPDummy)); + CHKiRet(prop.SetString(pRcvIPDummy, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1)); + CHKiRet(prop.ConstructFinalize(pRcvIPDummy)); + finalize_it: ENDwillRun BEGINafterRun CODESTARTafterRun - /* do cleanup here */ + if(pInputName != NULL) + prop.Destruct(&pInputName); + if(pRcvDummy != NULL) + prop.Destruct(&pRcvDummy); + if(pRcvIPDummy != NULL) + prop.Destruct(&pRcvIPDummy); ENDafterRun @@ -406,6 +428,7 @@ CODESTARTmodExit objRelease(tcpsrv, LM_TCPSRV_FILENAME); objRelease(errmsg, CORE_COMPONENT); objRelease(datetime, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); ENDmodExit @@ -443,6 +466,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(tcpsrv, LM_TCPSRV_FILENAME)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(datetime, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("imdiagserverrun"), 0, eCmdHdlrGetWord, diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 631d02ff..7c588f90 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -46,6 +46,7 @@ #include "glbl.h" #include "datetime.h" #include "unicode-helper.h" +#include "prop.h" MODULE_TYPE_INPUT /* must be present for input modules, do not remove */ @@ -57,6 +58,7 @@ DEFobjCurrIf(errmsg) DEFobjCurrIf(glbl) DEFobjCurrIf(datetime) DEFobjCurrIf(strm) +DEFobjCurrIf(prop) typedef struct fileInfo_s { uchar *pszFileName; @@ -81,6 +83,7 @@ static int iFilPtr = 0; /* number of files to be monitored; pointer to next fre #define MAX_INPUT_FILES 100 static fileInfo_t files[MAX_INPUT_FILES]; +static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this input */ /* enqueue the read file line as a message. The provided string is * not freed - thuis must be done by the caller. @@ -97,7 +100,7 @@ static rsRetVal enqLine(fileInfo_t *pInfo, cstr_t *cstrLine) CHKiRet(msgConstruct(&pMsg)); MsgSetFlowControlType(pMsg, eFLOWCTL_FULL_DELAY); - MsgSetInputName(pMsg, UCHAR_CONSTANT("imfile"), sizeof("imfile")-1); + MsgSetInputName(pMsg, pInputName); MsgSetRawMsg(pMsg, (char*)rsCStrGetSzStr(cstrLine), cstrLen(cstrLine)); MsgSetMSGoffs(pMsg, 0); /* we do not have a header... */ MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())); @@ -336,6 +339,11 @@ CODESTARTwillRun ABORT_FINALIZE(RS_RET_NO_RUN); } + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imfile"), sizeof("imfile") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); + finalize_it: ENDwillRun @@ -391,6 +399,9 @@ CODESTARTafterRun strm.Destruct(&(files[i].pStrm)); } } + + if(pInputName != NULL) + prop.Destruct(&pInputName); ENDafterRun @@ -405,6 +416,7 @@ CODESTARTmodExit objRelease(datetime, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); ENDmodExit @@ -515,6 +527,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(strm, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilename", 0, eCmdHdlrGetWord, NULL, &pszFileName, STD_LOADABLE_MODULE_ID)); diff --git a/plugins/imklog/bsd.c b/plugins/imklog/bsd.c index 090c4e9b..6d7b6c98 100644 --- a/plugins/imklog/bsd.c +++ b/plugins/imklog/bsd.c @@ -83,6 +83,11 @@ static int fklog = -1; /* /dev/klog */ # define _PATH_KLOG "/dev/klog" #endif +static uchar *GetPath(void) +{ + return pszPath ? pszPath : _PATH_KLOG; +} + /* open the kernel log - will be called inside the willRun() imklog * entry point. -- rgerhards, 2008-04-09 */ @@ -91,9 +96,9 @@ klogWillRun(void) { DEFiRet; - fklog = open(_PATH_KLOG, O_RDONLY, 0); + fklog = open(GetPath(), O_RDONLY, 0); if (fklog < 0) { - dbgprintf("can't open %s (%d)\n", _PATH_KLOG, errno); + dbgprintf("can't open %s (%d)\n", GetPath(), errno); iRet = RS_RET_ERR; // TODO: better error code } diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index f63d60ac..2a832bee 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -18,7 +18,7 @@ * Please note that this file replaces the klogd daemon that was * also present in pre-v3 versions of rsyslog. * - * Copyright (C) 2008 by Rainer Gerhards and Adiscon GmbH + * Copyright (C) 2008, 2009 by Rainer Gerhards and Adiscon GmbH * * This file is part of rsyslog. * @@ -44,6 +44,7 @@ #include <string.h> #include <stdarg.h> #include <ctype.h> +#include <stdlib.h> #include "dirty.h" #include "cfsysline.h" @@ -53,6 +54,7 @@ #include "datetime.h" #include "imklog.h" #include "glbl.h" +#include "prop.h" #include "unicode-helper.h" MODULE_TYPE_INPUT @@ -61,6 +63,7 @@ MODULE_TYPE_INPUT DEF_IMOD_STATIC_DATA DEFobjCurrIf(datetime) DEFobjCurrIf(glbl) +DEFobjCurrIf(prop) /* configuration settings */ int dbgPrintSymbols = 0; /* this one is extern so the helpers can access it! */ @@ -69,6 +72,7 @@ int use_syscall = 0; int symbol_lookup = 0; /* on recent kernels > 2.6, the kernel does this */ int bPermitNonKernel = 0; /* permit logging of messages not having LOG_KERN facility */ int iFacilIntMsg; /* the facility to use for internal messages (set by driver) */ +uchar *pszPath = NULL; /* TODO: configuration for the following directives must be implemented. It * was not done yet because we either do not yet have a config handler for * that type or I thought it was acceptable to push it to a later stage when @@ -79,6 +83,9 @@ char *symfile = NULL; int console_log_level = -1; +static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this module */ +static prop_t *pLocalHostIP = NULL; /* a pseudo-constant propterty for 127.0.0.1 */ + /* enqueue the the kernel message into the message queue. * The provided msg string is not freed - thus must be done * by the caller. @@ -95,11 +102,11 @@ enqMsg(uchar *msg, uchar* pszTag, int iFacility, int iSeverity) CHKiRet(msgConstruct(&pMsg)); MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY); - MsgSetInputName(pMsg, UCHAR_CONSTANT("imklog"), sizeof("imklog")-1); + MsgSetInputName(pMsg, pInputName); MsgSetRawMsgWOSize(pMsg, (char*)msg); MsgSetMSGoffs(pMsg, 0); /* we do not have a header... */ - MsgSetRcvFrom(pMsg, glbl.GetLocalHostName()); - MsgSetRcvFromIP(pMsg, (uchar*)"127.0.0.1"); + MsgSetRcvFrom(pMsg, glbl.GetLocalHostNameProp()); + MsgSetRcvFromIP(pMsg, pLocalHostIP); MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())); MsgSetTAG(pMsg, pszTag, ustrlen(pszTag)); pMsg->iFacility = LOG_FAC(iFacility); @@ -228,13 +235,23 @@ ENDrunInput BEGINwillRun CODESTARTwillRun + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.CreateStringProp(&pInputName, UCHAR_CONSTANT("imklog"), sizeof("imklog") - 1)); + CHKiRet(prop.CreateStringProp(&pLocalHostIP, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1)); + iRet = klogWillRun(); +finalize_it: ENDwillRun BEGINafterRun CODESTARTafterRun iRet = klogAfterRun(); + + if(pInputName != NULL) + prop.Destruct(&pInputName); + if(pLocalHostIP != NULL) + prop.Destruct(&pLocalHostIP); ENDafterRun @@ -243,6 +260,9 @@ CODESTARTmodExit /* release objects we used */ objRelease(glbl, CORE_COMPONENT); objRelease(datetime, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); + if(pszPath != NULL) + free(pszPath); ENDmodExit @@ -259,6 +279,10 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a symfile = NULL; symbol_lookup = 0; bPermitNonKernel = 0; + if(pszPath != NULL) { + free(pszPath); + pszPath = NULL; + } iFacilIntMsg = klogFacilIntMsg(); return RS_RET_OK; } @@ -269,10 +293,12 @@ CODESTARTmodInit CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); iFacilIntMsg = klogFacilIntMsg(); CHKiRet(omsdRegCFSLineHdlr((uchar *)"debugprintkernelsymbols", 0, eCmdHdlrBinary, NULL, &dbgPrintSymbols, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpath", 0, eCmdHdlrGetWord, NULL, &pszPath, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbollookup", 0, eCmdHdlrBinary, NULL, &symbol_lookup, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbolstwice", 0, eCmdHdlrBinary, NULL, &symbols_twice, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogusesyscallinterface", 0, eCmdHdlrBinary, NULL, &use_syscall, STD_LOADABLE_MODULE_ID)); diff --git a/plugins/imklog/imklog.h b/plugins/imklog/imklog.h index 37bd58b0..c183026d 100644 --- a/plugins/imklog/imklog.h +++ b/plugins/imklog/imklog.h @@ -52,6 +52,7 @@ extern int symbol_lookup; extern char *symfile; extern int console_log_level; extern int dbgPrintSymbols; +extern uchar *pszPath; /* the functions below may be called by the drivers */ rsRetVal imklogLogIntMsg(int priority, char *fmt, ...) __attribute__((format(printf,2, 3))); diff --git a/plugins/imklog/linux.c b/plugins/imklog/linux.c index 0dd4320d..977395ea 100644 --- a/plugins/imklog/linux.c +++ b/plugins/imklog/linux.c @@ -37,6 +37,7 @@ #include "msg.h" #include "module-template.h" #include "imklog.h" +#include "unicode-helper.h" /* Includes. */ @@ -84,6 +85,11 @@ static enum LOGSRC {none, proc, kernel} logsrc; extern int ksyslog(int type, char *buf, int len); +static uchar *GetPath(void) +{ + return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG); +} + static void CloseLogSrc(void) { /* Turn on logging of messages to console, but only if we had the -c @@ -135,7 +141,7 @@ static enum LOGSRC GetKernelLogSrc(void) * file system is available to get kernel messages from. */ if ( use_syscall || - ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) ) + ((stat((char*)GetPath(), &sb) < 0) && (errno == ENOENT)) ) { /* Initialize kernel logging. */ ksyslog(1, NULL, 0); @@ -144,14 +150,14 @@ static enum LOGSRC GetKernelLogSrc(void) return(kernel); } - if ( (kmsg = open(_PATH_KLOG, O_RDONLY|O_CLOEXEC)) < 0 ) + if ( (kmsg = open((char*)GetPath(), O_RDONLY|O_CLOEXEC)) < 0 ) { imklogLogIntMsg(LOG_ERR, "imklog: Cannot open proc file system, %d.\n", errno); ksyslog(7, NULL, 0); /* TODO: check this, implement more */ return(none); } - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, _PATH_KLOG); + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath()); return(proc); } diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c index 2255e643..b9e7b2f8 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 Rainer Gerhards and Adiscon GmbH. + * Copyright 2008, 2009 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -43,15 +43,19 @@ #include "module-template.h" #include "net.h" #include "msg.h" +#include "unicode-helper.h" +#include "prop.h" MODULE_TYPE_INPUT /* static data */ DEF_IMOD_STATIC_DATA DEFobjCurrIf(net) +DEFobjCurrIf(prop) /* Module static data */ static relpEngine_t *pRelpEngine; /* our relp engine */ +static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this module */ /* config settings */ @@ -85,7 +89,7 @@ onSyslogRcv(uchar *pHostname, uchar __attribute__((unused)) *pIP, uchar *pMsg, s { DEFiRet; parseAndSubmitMessage(pHostname, (uchar*) "[unset]", pMsg, lenMsg, PARSE_HOSTNAME, - eFLOWCTL_LIGHT_DELAY, (uchar*)"imrelp", NULL, 0); + eFLOWCTL_LIGHT_DELAY, pInputName, NULL, 0); RETiRet; } @@ -130,6 +134,11 @@ CODESTARTwillRun //net.PrintAllowedSenders(2); /* TCP */ if(pRelpEngine == NULL) ABORT_FINALIZE(RS_RET_NO_RUN); + + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imrelp"), sizeof("imrelp") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); finalize_it: ENDwillRun @@ -143,6 +152,9 @@ CODESTARTafterRun net.pAllowedSenders_TCP = NULL; } #endif + + if(pInputName != NULL) + prop.Destruct(&pInputName); ENDafterRun @@ -152,6 +164,7 @@ CODESTARTmodExit iRet = relpEngineDestruct(&pRelpEngine); /* release objects we used */ + objRelease(prop, CORE_COMPONENT); objRelease(net, LM_NET_FILENAME); ENDmodExit @@ -177,6 +190,7 @@ CODESTARTmodInit CODEmodInit_QueryRegCFSLineHdlr pRelpEngine = NULL; /* request objects we use */ + CHKiRet(objUse(prop, CORE_COMPONENT)); CHKiRet(objUse(net, LM_NET_FILENAME)); /* register config file handlers */ diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 2340aac4..718c3090 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -43,6 +43,7 @@ #include "msg.h" #include "parser.h" #include "datetime.h" +#include "prop.h" #include "unicode-helper.h" MODULE_TYPE_INPUT @@ -55,6 +56,7 @@ DEFobjCurrIf(errmsg) DEFobjCurrIf(glbl) DEFobjCurrIf(net) DEFobjCurrIf(datetime) +DEFobjCurrIf(prop) static int iMaxLine; /* maximum UDP message size supported */ static time_t ttLastDiscard = 0; /* timestamp when a message from a non-permitted sender was last discarded @@ -68,6 +70,7 @@ static uchar *pRcvBuf = NULL; /* receive buffer (for a single packet). We use a * it so that we can check available memory in willRun() and request * termination if we can not get it. -- rgerhards, 2007-12-27 */ +static prop_t *pInputName = NULL; /* our inputName currently is always "imudp", and this will hold it */ // TODO: static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */ #define TIME_REQUERY_DFLT 2 static int iTimeRequery = TIME_REQUERY_DFLT;/* how often is time to be queried inside tight recv loop? 0=always */ @@ -188,6 +191,8 @@ processSocket(int fd, struct sockaddr_storage *frominetPrev, int *pbIsPermitted, ssize_t lenRcvBuf; struct sockaddr_storage frominet; msg_t *pMsg; + prop_t *propFromHost = NULL; + prop_t *propFromHostIP = NULL; char errStr[1024]; iNbrTimeUsed = 0; @@ -242,18 +247,22 @@ processSocket(int fd, struct sockaddr_storage *frominetPrev, int *pbIsPermitted, /* we now create our own message object and submit it to the queue */ CHKiRet(msgConstructWithTime(&pMsg, &stTime, ttGenTime)); MsgSetRawMsg(pMsg, (char*)pRcvBuf, lenRcvBuf); - MsgSetInputName(pMsg, UCHAR_CONSTANT("imudp"), sizeof("imudp")-1); + MsgSetInputName(pMsg, pInputName); MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY); pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME; pMsg->bParseHOSTNAME = 1; - MsgSetRcvFrom(pMsg, fromHost); - CHKiRet(MsgSetRcvFromIP(pMsg, fromHostIP)); + MsgSetRcvFromStr(pMsg, fromHost, ustrlen(fromHost), &propFromHost); + CHKiRet(MsgSetRcvFromIPStr(pMsg, fromHostIP, ustrlen(fromHostIP), &propFromHostIP)); CHKiRet(submitMsg(pMsg)); } } - finalize_it: + if(propFromHost != NULL) + prop.Destruct(&propFromHost); + if(propFromHostIP != NULL) + prop.Destruct(&propFromHostIP); + RETiRet; } @@ -338,6 +347,11 @@ ENDrunInput /* initialize and return if will run or not */ BEGINwillRun CODESTARTwillRun + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imudp"), sizeof("imudp") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); + net.PrintAllowedSenders(1); /* UDP */ /* if we could not set up any listners, there is no point in running... */ @@ -365,6 +379,8 @@ CODESTARTafterRun free(pRcvBuf); pRcvBuf = NULL; } + if(pInputName != NULL) + prop.Destruct(&pInputName); ENDafterRun @@ -374,6 +390,7 @@ CODESTARTmodExit objRelease(errmsg, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); objRelease(datetime, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); objRelease(net, LM_NET_FILENAME); ENDmodExit @@ -405,6 +422,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(datetime, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); CHKiRet(objUse(net, LM_NET_FILENAME)); /* register config file handlers */ diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 9a1e424c..6d60efaf 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -37,12 +37,14 @@ #include <sys/un.h> #include "dirty.h" #include "cfsysline.h" +#include "unicode-helper.h" #include "module-template.h" #include "srUtils.h" #include "errmsg.h" #include "net.h" #include "glbl.h" #include "msg.h" +#include "prop.h" MODULE_TYPE_INPUT @@ -66,7 +68,9 @@ MODULE_TYPE_INPUT DEF_IMOD_STATIC_DATA DEFobjCurrIf(errmsg) DEFobjCurrIf(glbl) +DEFobjCurrIf(prop) +static prop_t *pInputName = NULL; /* our inputName currently is always "imudp", and this will hold it */ static int startIndexUxLocalSockets; /* process funix from that index on (used to * suppress local logging. rgerhards 2005-08-01 * read-only after startup @@ -223,7 +227,7 @@ static rsRetVal readSocket(int fd, int iSock) parseAndSubmitMessage(funixHName[iSock] == NULL ? glbl.GetLocalHostName() : funixHName[iSock], (uchar*)"127.0.0.1", pRcv, iRcvd, funixParseHost[iSock] ? (funixFlags[iSock] | PARSE_HOSTNAME) : funixFlags[iSock], - funixFlowCtl[iSock], (uchar*)"imuxsock", NULL, 0); + funixFlowCtl[iSock], pInputName, NULL, 0); } else if (iRcvd < 0 && errno != EINTR) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); @@ -306,7 +310,12 @@ CODESTARTwillRun dbgprintf("Opened UNIX socket '%s' (fd %d).\n", funixn[i], funix[i]); } - RETiRet; + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imudp"), sizeof("imudp") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); + +finalize_it: ENDwillRun @@ -329,6 +338,9 @@ CODESTARTafterRun discardFunixn(); nfunix = 1; + + if(pInputName != NULL) + prop.Destruct(&pInputName); ENDafterRun @@ -336,6 +348,7 @@ BEGINmodExit CODESTARTmodExit objRelease(glbl, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); ENDmodExit @@ -372,6 +385,7 @@ CODESTARTmodInit CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); dbgprintf("imuxsock version %s initializing\n", PACKAGE_VERSION); diff --git a/runtime/datetime.c b/runtime/datetime.c index 5b9f5b6d..46488433 100644 --- a/runtime/datetime.c +++ b/runtime/datetime.c @@ -558,7 +558,6 @@ int formatTimestampToMySQL(struct syslogTime *ts, char* pBuf) */ assert(ts != NULL); assert(pBuf != NULL); - assert(iLenDst >= 15); pBuf[0] = (ts->year / 1000) % 10 + '0'; pBuf[1] = (ts->year / 100) % 10 + '0'; @@ -584,7 +583,6 @@ int formatTimestampToPgSQL(struct syslogTime *ts, char *pBuf) /* see note in formatTimestampToMySQL, applies here as well */ assert(ts != NULL); assert(pBuf != NULL); - assert(iLenDst >= 20); pBuf[0] = (ts->year / 1000) % 10 + '0'; pBuf[1] = (ts->year / 100) % 10 + '0'; @@ -667,7 +665,6 @@ int formatTimestamp3339(struct syslogTime *ts, char* pBuf) BEGINfunc assert(ts != NULL); assert(pBuf != NULL); - assert(iLenBuf >= 33); /* start with fixed parts */ /* year yyyy */ @@ -742,8 +739,6 @@ int formatTimestamp3164(struct syslogTime *ts, char* pBuf) assert(ts != NULL); assert(pBuf != NULL); - assert(iLenBuf >= 16); - pBuf[0] = monthNames[(ts->month - 1)% 12][0]; pBuf[1] = monthNames[(ts->month - 1) % 12][1]; pBuf[2] = monthNames[(ts->month - 1) % 12][2]; diff --git a/runtime/datetime.h b/runtime/datetime.h index 79a86d05..58f368e7 100644 --- a/runtime/datetime.h +++ b/runtime/datetime.h @@ -23,8 +23,6 @@ #ifndef INCLUDED_DATETIME_H #define INCLUDED_DATETIME_H -#include "datetime.h" - /* TODO: define error codes */ #define NO_ERRCODE -1 diff --git a/runtime/glbl.c b/runtime/glbl.c index 28f14320..32b85622 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -35,8 +35,10 @@ #include "rsyslog.h" #include "obj.h" +#include "unicode-helper.h" #include "cfsysline.h" #include "glbl.h" +#include "prop.h" /* some defaults */ #ifndef DFLT_NETSTRM_DRVR @@ -45,6 +47,7 @@ /* static data */ DEFobjStaticHelpers +DEFobjCurrIf(prop) /* static data * For this object, these variables are obviously what makes the "meat" of the @@ -59,6 +62,7 @@ static int iDefPFFamily = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) static int bDropMalPTRMsgs = 0;/* Drop messages which have malicious PTR records during DNS lookup */ static int option_DisallowWarning = 1; /* complain if message from disallowed sender is received */ static int bDisableDNS = 0; /* don't look up IP addresses of remote messages */ +static prop_t *propLocalHostName = NULL;/* our hostname as FQDN - read-only after startup */ static uchar *LocalHostName = NULL;/* our hostname - read-only after startup */ static uchar *LocalFQDNName = NULL;/* our hostname as FQDN - read-only after startup */ static uchar *LocalDomain; /* our local domain name - read-only after startup */ @@ -132,6 +136,44 @@ GetLocalHostName(void) } +/* generate the local hostname property. This must be done after the hostname info + * has been set as well as PreserveFQDN. + * rgerhards, 2009-06-30 + */ +static rsRetVal +GenerateLocalHostNameProperty(void) +{ + DEFiRet; + uchar *pszName; + + if(propLocalHostName != NULL) + prop.Destruct(&propLocalHostName); + + CHKiRet(prop.Construct(&propLocalHostName)); + if(LocalHostName == NULL) + pszName = (uchar*) "[localhost]"; + else { + if(GetPreserveFQDN() == 1) + pszName = LocalFQDNName; + else + pszName = LocalHostName; + } + CHKiRet(prop.SetString(propLocalHostName, pszName, ustrlen(pszName))); + CHKiRet(prop.ConstructFinalize(propLocalHostName)); + +finalize_it: + RETiRet; +} + +/* return our local hostname as a string property + */ +static prop_t* +GetLocalHostNameProp(void) +{ + return(propLocalHostName); +} + + /* return the current localhost name as FQDN (requires FQDN to be set) * TODO: we should set the FQDN ourselfs in here! */ @@ -197,6 +239,8 @@ CODESTARTobjQueryInterface(glbl) * of course, also affects the "if" above). */ pIf->GetWorkDir = GetWorkDir; + pIf->GenerateLocalHostNameProperty = GenerateLocalHostNameProperty; + pIf->GetLocalHostNameProp = GetLocalHostNameProp; #define SIMP_PROP(name) \ pIf->Get##name = Get##name; \ pIf->Set##name = Set##name; @@ -262,6 +306,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a */ BEGINAbstractObjClassInit(glbl, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ + CHKiRet(objUse(prop, CORE_COMPONENT)); /* register config handlers (TODO: we need to implement a way to unregister them) */ CHKiRet(regCfSysLineHdlr((uchar *)"workdirectory", 0, eCmdHdlrGetWord, NULL, &pszWorkDir, NULL)); @@ -295,6 +340,7 @@ BEGINObjClassExit(glbl, OBJ_IS_CORE_MODULE) /* class, version */ free(LocalHostName); if(LocalFQDNName != NULL) free(LocalFQDNName); + objRelease(prop, CORE_COMPONENT); ENDObjClassExit(glbl) /* vi:set ai: diff --git a/runtime/glbl.h b/runtime/glbl.h index 5bdf4f57..dcfb6d5f 100644 --- a/runtime/glbl.h +++ b/runtime/glbl.h @@ -32,6 +32,8 @@ #ifndef GLBL_H_INCLUDED #define GLBL_H_INCLUDED +#include "prop.h" + #define glblGetIOBufSize() 4096 /* size of the IO buffer, e.g. for strm class */ /* interfaces */ @@ -57,9 +59,12 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */ SIMP_PROP(DfltNetstrmDrvrCAF, uchar*) SIMP_PROP(DfltNetstrmDrvrKeyFile, uchar*) SIMP_PROP(DfltNetstrmDrvrCertFile, uchar*) + /* added v3, 2009-06-30 */ + rsRetVal (*GenerateLocalHostNameProperty)(void); + prop_t* (*GetLocalHostNameProp)(void); #undef SIMP_PROP ENDinterface(glbl) -#define glblCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ +#define glblCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */ /* version 2 had PreserveFQDN added - rgerhards, 2008-12-08 */ /* the remaining prototypes */ diff --git a/runtime/modules.c b/runtime/modules.c index 9830aa45..0ec6b1ce 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -435,6 +435,7 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"runInput", &pNew->mod.im.runInput)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"willRun", &pNew->mod.im.willRun)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"afterRun", &pNew->mod.im.afterRun)); + pNew->mod.im.bCanRun = 0; break; case eMOD_OUT: CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeInstance", &pNew->freeInstance)); diff --git a/runtime/modules.h b/runtime/modules.h index e33bbbe1..71e3199c 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -106,6 +106,7 @@ typedef struct modInfo_s { rsRetVal (*runInput)(thrdInfo_t*); /* function to gather input and submit to queue */ rsRetVal (*willRun)(void); /* function to gather input and submit to queue */ rsRetVal (*afterRun)(thrdInfo_t*); /* function to gather input and submit to queue */ + int bCanRun; /* cached value of whether willRun() succeeded */ } im; struct {/* data for output modules */ /* below: perform the configured action diff --git a/runtime/msg.c b/runtime/msg.c index c4ba18df..6c272d1f 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -48,6 +48,7 @@ #include "atomic.h" #include "unicode-helper.h" #include "ruleset.h" +#include "prop.h" /* static data */ DEFobjStaticHelpers @@ -55,6 +56,7 @@ DEFobjCurrIf(var) DEFobjCurrIf(datetime) DEFobjCurrIf(glbl) DEFobjCurrIf(regexp) +DEFobjCurrIf(prop) static struct { uchar *pszName; @@ -273,12 +275,215 @@ static char *syslog_number_names[24] = { "0", "1", "2", "3", "4", "5", "6", "7", /* some forward declarations */ static int getAPPNAMELen(msg_t *pM, bool bLockMutex); + static inline int getProtocolVersion(msg_t *pM) { return(pM->iProtocolVersion); } +static inline void +getInputName(msg_t *pM, uchar **ppsz, int *plen) +{ + BEGINfunc + if(pM == NULL) { + *ppsz = UCHAR_CONSTANT(""); + *plen = 0; + } else { + prop.GetString(pM->pInputName, ppsz, plen); + } + ENDfunc +} + + +static inline uchar* +getRcvFromIP(msg_t *pM) +{ + uchar *psz; + int len; + BEGINfunc + if(pM == NULL) { + psz = UCHAR_CONSTANT(""); + } else { + if(pM->pRcvFromIP == NULL) + psz = UCHAR_CONSTANT(""); + else + prop.GetString(pM->pRcvFromIP, &psz, &len); + } + ENDfunc + return psz; +} + + + +/* map a property name (string) to a property ID */ +rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID) +{ + uchar *pName; + DEFiRet; + + assert(pCSPropName != NULL); + assert(pPropID != NULL); + pName = rsCStrGetSzStrNoNULL(pCSPropName); + + /* sometimes there are aliases to the original MonitoWare + * property names. These come after || in the ifs below. */ + if(!strcmp((char*) pName, "msg")) { + *pPropID = PROP_MSG; + } else if(!strcmp((char*) pName, "timestamp") + || !strcmp((char*) pName, "timereported")) { + *pPropID = PROP_TIMESTAMP; + } else if(!strcmp((char*) pName, "hostname") || !strcmp((char*) pName, "source")) { + *pPropID = PROP_HOSTNAME; + } else if(!strcmp((char*) pName, "syslogtag")) { + *pPropID = PROP_SYSLOGTAG; + } else if(!strcmp((char*) pName, "rawmsg")) { + *pPropID = PROP_RAWMSG; + /* enable this, if someone actually uses UxTradMsg, delete after some time has + * passed and nobody complained -- rgerhards, 2009-06-16 + } else if(!strcmp((char*) pName, "uxtradmsg")) { + pRes = getUxTradMsg(pMsg); + */ + } else if(!strcmp((char*) pName, "inputname")) { + *pPropID = PROP_INPUTNAME; + } else if(!strcmp((char*) pName, "fromhost")) { + *pPropID = PROP_FROMHOST; + } else if(!strcmp((char*) pName, "fromhost-ip")) { + *pPropID = PROP_FROMHOST_IP; + } else if(!strcmp((char*) pName, "pri")) { + *pPropID = PROP_PRI; + } else if(!strcmp((char*) pName, "pri-text")) { + *pPropID = PROP_PRI_TEXT; + } else if(!strcmp((char*) pName, "iut")) { + *pPropID = PROP_IUT; + } else if(!strcmp((char*) pName, "syslogfacility")) { + *pPropID = PROP_SYSLOGFACILITY; + } else if(!strcmp((char*) pName, "syslogfacility-text")) { + *pPropID = PROP_SYSLOGFACILITY_TEXT; + } else if(!strcmp((char*) pName, "syslogseverity") || !strcmp((char*) pName, "syslogpriority")) { + *pPropID = PROP_SYSLOGSEVERITY; + } else if(!strcmp((char*) pName, "syslogseverity-text") || !strcmp((char*) pName, "syslogpriority-text")) { + *pPropID = PROP_SYSLOGSEVERITY_TEXT; + } else if(!strcmp((char*) pName, "timegenerated")) { + *pPropID = PROP_TIMEGENERATED; + } else if(!strcmp((char*) pName, "programname")) { + *pPropID = PROP_PROGRAMNAME; + } else if(!strcmp((char*) pName, "protocol-version")) { + *pPropID = PROP_PROTOCOL_VERSION; + } else if(!strcmp((char*) pName, "structured-data")) { + *pPropID = PROP_STRUCTURED_DATA; + } else if(!strcmp((char*) pName, "app-name")) { + *pPropID = PROP_APP_NAME; + } else if(!strcmp((char*) pName, "procid")) { + *pPropID = PROP_PROCID; + } else if(!strcmp((char*) pName, "msgid")) { + *pPropID = PROP_MSGID; + /* here start system properties (those, that do not relate to the message itself */ + } else if(!strcmp((char*) pName, "$now")) { + *pPropID = PROP_SYS_NOW; + } else if(!strcmp((char*) pName, "$year")) { + *pPropID = PROP_SYS_YEAR; + } else if(!strcmp((char*) pName, "$month")) { + *pPropID = PROP_SYS_MONTH; + } else if(!strcmp((char*) pName, "$day")) { + *pPropID = PROP_SYS_DAY; + } else if(!strcmp((char*) pName, "$hour")) { + *pPropID = PROP_SYS_HOUR; + } else if(!strcmp((char*) pName, "$hhour")) { + *pPropID = PROP_SYS_HHOUR; + } else if(!strcmp((char*) pName, "$qhour")) { + *pPropID = PROP_SYS_QHOUR; + } else if(!strcmp((char*) pName, "$minute")) { + *pPropID = PROP_SYS_MINUTE; + } else if(!strcmp((char*) pName, "$myhostname")) { + *pPropID = PROP_SYS_MYHOSTNAME; + } else { + *pPropID = PROP_INVALID; + iRet = RS_RET_VAR_NOT_FOUND; + } + + RETiRet; +} + + +/* map a property ID to a name string (useful for displaying) */ +uchar *propIDToName(propid_t propID) +{ + switch(propID) { + case PROP_MSG: + return UCHAR_CONSTANT("msg"); + case PROP_TIMESTAMP: + return UCHAR_CONSTANT("timestamp"); + case PROP_HOSTNAME: + return UCHAR_CONSTANT("hostname"); + case PROP_SYSLOGTAG: + return UCHAR_CONSTANT("syslogtag"); + case PROP_RAWMSG: + return UCHAR_CONSTANT("rawmsg"); + /* enable this, if someone actually uses UxTradMsg, delete after some time has + * passed and nobody complained -- rgerhards, 2009-06-16 + case PROP_UXTRADMSG: + pRes = getUxTradMsg(pMsg); + break; + */ + case PROP_INPUTNAME: + return UCHAR_CONSTANT("inputname"); + case PROP_FROMHOST: + return UCHAR_CONSTANT("fromhost"); + case PROP_FROMHOST_IP: + return UCHAR_CONSTANT("fromhost-ip"); + case PROP_PRI: + return UCHAR_CONSTANT("pri"); + case PROP_PRI_TEXT: + return UCHAR_CONSTANT("pri-text"); + case PROP_IUT: + return UCHAR_CONSTANT("iut"); + case PROP_SYSLOGFACILITY: + return UCHAR_CONSTANT("syslogfacility"); + case PROP_SYSLOGFACILITY_TEXT: + return UCHAR_CONSTANT("syslogfacility-text"); + case PROP_SYSLOGSEVERITY: + return UCHAR_CONSTANT("syslogseverity"); + case PROP_SYSLOGSEVERITY_TEXT: + return UCHAR_CONSTANT("syslogseverity-text"); + case PROP_TIMEGENERATED: + return UCHAR_CONSTANT("timegenerated"); + case PROP_PROGRAMNAME: + return UCHAR_CONSTANT("programname"); + case PROP_PROTOCOL_VERSION: + return UCHAR_CONSTANT("protocol-version"); + case PROP_STRUCTURED_DATA: + return UCHAR_CONSTANT("structured-data"); + case PROP_APP_NAME: + return UCHAR_CONSTANT("app-name"); + case PROP_PROCID: + return UCHAR_CONSTANT("procid"); + case PROP_MSGID: + return UCHAR_CONSTANT("msgid"); + case PROP_SYS_NOW: + return UCHAR_CONSTANT("$NOW"); + case PROP_SYS_YEAR: + return UCHAR_CONSTANT("$YEAR"); + case PROP_SYS_MONTH: + return UCHAR_CONSTANT("$MONTH"); + case PROP_SYS_DAY: + return UCHAR_CONSTANT("$DAY"); + case PROP_SYS_HOUR: + return UCHAR_CONSTANT("$HOUR"); + case PROP_SYS_HHOUR: + return UCHAR_CONSTANT("$HHOUR"); + case PROP_SYS_QHOUR: + return UCHAR_CONSTANT("$QHOUR"); + case PROP_SYS_MINUTE: + return UCHAR_CONSTANT("$MINUTE"); + case PROP_SYS_MYHOSTNAME: + return UCHAR_CONSTANT("$MYHOSTNAME"); + default: + return UCHAR_CONSTANT("*invalid property id*"); + } +} + + /* The following functions will support advanced output module * multithreading, once this is implemented. Currently, we * include them as hooks only. The idea is that we need to guard @@ -431,20 +636,14 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis) pM->iFacility = -1; pM->offAfterPRI = 0; pM->offMSG = -1; - pM->iLenInputName = 0; pM->iProtocolVersion = 0; pM->msgFlags = 0; pM->iLenRawMsg = 0; pM->iLenMSG = 0; pM->iLenTAG = 0; pM->iLenHOSTNAME = 0; - pM->iLenRcvFrom = 0; - pM->iLenRcvFromIP = 0; pM->pszRawMsg = NULL; pM->pszHOSTNAME = NULL; - pM->pszRcvFrom = NULL; - pM->pszRcvFromIP = NULL; - pM->pszInputName = NULL; pM->pszRcvdAt3164 = NULL; pM->pszRcvdAt3339 = NULL; pM->pszRcvdAt_MySQL = NULL; @@ -458,6 +657,9 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis) pM->pCSAPPNAME = NULL; pM->pCSPROCID = NULL; pM->pCSMSGID = NULL; + pM->pInputName = NULL; + pM->pRcvFromIP = NULL; + pM->pRcvFrom = NULL; pM->pRuleset = NULL; memset(&pM->tRcvdAt, 0, sizeof(pM->tRcvdAt)); memset(&pM->tTIMESTAMP, 0, sizeof(pM->tTIMESTAMP)); @@ -556,9 +758,12 @@ CODESTARTobjDestruct(msg) free(pThis->pszRawMsg); freeTAG(pThis); freeHOSTNAME(pThis); - free(pThis->pszInputName); - free(pThis->pszRcvFrom); - free(pThis->pszRcvFromIP); + if(pThis->pInputName != NULL) + prop.Destruct(&pThis->pInputName); + if(pThis->pRcvFrom != NULL) + prop.Destruct(&pThis->pRcvFrom); + if(pThis->pRcvFromIP != NULL) + prop.Destruct(&pThis->pRcvFromIP); free(pThis->pszRcvdAt3164); free(pThis->pszRcvdAt3339); free(pThis->pszRcvdAt_MySQL); @@ -659,6 +864,12 @@ msg_t* MsgDup(msg_t* pOld) pNew->iProtocolVersion = pOld->iProtocolVersion; pNew->ttGenTime = pOld->ttGenTime; pNew->offMSG = pOld->offMSG; + pNew->pRcvFrom = pOld->pRcvFrom; + prop.AddRef(pNew->pRcvFrom); + pNew->pRcvFromIP = pOld->pRcvFromIP; + prop.AddRef(pNew->pRcvFromIP); + pNew->pInputName = pOld->pInputName; + prop.AddRef(pNew->pInputName); /* enable this, if someone actually uses UxTradMsg, delete after some time has * passed and nobody complained -- rgerhards, 2009-06-16 pNew->offAfterPRI = pOld->offAfterPRI; @@ -686,7 +897,6 @@ msg_t* MsgDup(msg_t* pOld) } else { tmpCOPYSZ(HOSTNAME); } - tmpCOPYSZ(RcvFrom); tmpCOPYCSTR(ProgName); tmpCOPYCSTR(StrucData); @@ -719,11 +929,16 @@ msg_t* MsgDup(msg_t* pOld) */ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm) { + uchar *psz; + int len; DEFiRet; assert(pThis != NULL); assert(pStrm != NULL); + /* "pump" some property values into strings */ + + /* then serialize elements */ CHKiRet(obj.BeginSerialize(pStrm, (obj_t*) pThis)); objSerializeSCALAR(pStrm, iProtocolVersion, SHORT); objSerializeSCALAR(pStrm, iSeverity, SHORT); @@ -743,9 +958,12 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm) objSerializePTR(pStrm, pszRawMsg, PSZ); objSerializePTR(pStrm, pszHOSTNAME, PSZ); - objSerializePTR(pStrm, pszInputName, PSZ); - objSerializePTR(pStrm, pszRcvFrom, PSZ); - objSerializePTR(pStrm, pszRcvFromIP, PSZ); + getInputName(pThis, &psz, &len); + objSerializeSCALAR_VAR(pStrm, "pszInputName", PSZ, psz); + psz = getRcvFrom(pThis); + objSerializeSCALAR_VAR(pStrm, "pszRcvFrom", PSZ, psz); + psz = getRcvFromIP(pThis); + objSerializeSCALAR_VAR(pStrm, "pszRcvFromIP", PSZ, psz); objSerializePTR(pStrm, pCSStrucData, CSTR); objSerializePTR(pStrm, pCSAPPNAME, CSTR); @@ -1409,7 +1627,10 @@ int getHOSTNAMELen(msg_t *pM) return 0; else if(pM->pszHOSTNAME == NULL) - return pM->iLenRcvFrom; + if(pM->pRcvFrom == NULL) + return 0; + else + return prop.GetStringLen(pM->pRcvFrom); else return pM->iLenHOSTNAME; } @@ -1420,48 +1641,39 @@ char *getHOSTNAME(msg_t *pM) if(pM == NULL) return ""; else - if(pM->pszHOSTNAME == NULL) - return (char*) pM->pszRcvFrom; - else + if(pM->pszHOSTNAME == NULL) { + if(pM->pRcvFrom == NULL) { + return ""; + } else { + uchar *psz; + int len; + prop.GetString(pM->pRcvFrom, &psz, &len); + return (char*) psz; + } + } else { return (char*) pM->pszHOSTNAME; -} - - -static uchar *getInputName(msg_t *pM) -{ - if(pM == NULL) - return (uchar*) ""; - else - if(pM->pszInputName == NULL) - return (uchar*) ""; - else - return pM->pszInputName; + } } uchar *getRcvFrom(msg_t *pM) { - if(pM == NULL) - return UCHAR_CONSTANT(""); - else - if(pM->pszRcvFrom == NULL) - return UCHAR_CONSTANT(""); + uchar *psz; + int len; + BEGINfunc + if(pM == NULL) { + psz = UCHAR_CONSTANT(""); + } else { + if(pM->pRcvFrom == NULL) + psz = UCHAR_CONSTANT(""); else - return pM->pszRcvFrom; + prop.GetString(pM->pRcvFrom, &psz, &len); + } + ENDfunc + return psz; } -uchar *getRcvFromIP(msg_t *pM) -{ - if(pM == NULL) - return (uchar*) ""; - else - if(pM->pszRcvFromIP == NULL) - return (uchar*) ""; - else - return pM->pszRcvFromIP; -} - /* rgerhards 2004-11-24: set STRUCTURED DATA in msg object */ rsRetVal MsgSetStructuredData(msg_t *pMsg, char* pszStrucData) @@ -1595,46 +1807,91 @@ static int getAPPNAMELen(msg_t *pM, bool bLockMutex) return (pM->pCSAPPNAME == NULL) ? 0 : rsCStrLen(pM->pCSAPPNAME); } -/* rgerhards 2008-09-10: set pszInputName in msg object +/* rgerhards 2008-09-10: set pszInputName in msg object. This calls AddRef() + * on the property, because this must be done in all current cases and there + * is no case expected where this may not be necessary. * rgerhards, 2009-06-16 */ -void MsgSetInputName(msg_t *pMsg, uchar* pszInputName, size_t lenInputName) +void MsgSetInputName(msg_t *pThis, prop_t *inputName) { - assert(pMsg != NULL); - free(pMsg->pszInputName); - pMsg->iLenInputName = lenInputName; - if((pMsg->pszInputName = malloc(pMsg->iLenInputName + 1)) != NULL) { - memcpy(pMsg->pszInputName, pszInputName, pMsg->iLenInputName + 1); - } + assert(pThis != NULL); + + prop.AddRef(inputName); + if(pThis->pInputName != NULL) + prop.Destruct(&pThis->pInputName); + pThis->pInputName = inputName; } -/* rgerhards 2004-11-16: set pszRcvFrom in msg object + +/* rgerhards 2008-09-10: set RcvFrom name in msg object. This calls AddRef() + * on the property, because this must be done in all current cases and there + * is no case expected where this may not be necessary. + * rgerhards, 2009-06-30 */ -void MsgSetRcvFrom(msg_t *pMsg, uchar* pszRcvFrom) +void MsgSetRcvFrom(msg_t *pThis, prop_t *new) { - assert(pMsg != NULL); - free(pMsg->pszRcvFrom); + assert(pThis != NULL); - pMsg->iLenRcvFrom = ustrlen(pszRcvFrom); - if((pMsg->pszRcvFrom = malloc(pMsg->iLenRcvFrom + 1)) != NULL) { - memcpy(pMsg->pszRcvFrom, pszRcvFrom, pMsg->iLenRcvFrom + 1); - } + prop.AddRef(new); + if(pThis->pRcvFrom != NULL) + prop.Destruct(&pThis->pRcvFrom); + pThis->pRcvFrom = new; } -/* rgerhards 2005-05-16: set pszRcvFromIP in msg object */ -rsRetVal -MsgSetRcvFromIP(msg_t *pMsg, uchar* pszRcvFromIP) +/* This is used to set the property via a string. This function should not be + * called if there is a reliable way for a caller to make sure that the + * same name can be used across multiple messages. However, if it can not + * ensure that, calling this function is the second best thing, because it + * will re-use the previously created property if it contained the same + * name (but it works only for the immediate previous). + * rgerhards, 2009-06-31 + */ +void MsgSetRcvFromStr(msg_t *pThis, uchar *psz, int len, prop_t **ppProp) +{ + assert(pThis != NULL); + assert(ppProp != NULL); + + prop.CreateOrReuseStringProp(ppProp, psz, len); + MsgSetRcvFrom(pThis, *ppProp); +} + + +/* set RcvFromIP name in msg object. This calls AddRef() + * on the property, because this must be done in all current cases and there + * is no case expected where this may not be necessary. + * rgerhards, 2009-06-30 + */ +rsRetVal MsgSetRcvFromIP(msg_t *pThis, prop_t *new) +{ + assert(pThis != NULL); + + BEGINfunc + prop.AddRef(new); + if(pThis->pRcvFromIP != NULL) + prop.Destruct(&pThis->pRcvFromIP); + pThis->pRcvFromIP = new; + ENDfunc + return RS_RET_OK; +} + + +/* This is used to set the property via a string. This function should not be + * called if there is a reliable way for a caller to make sure that the + * same name can be used across multiple messages. However, if it can not + * ensure that, calling this function is the second best thing, because it + * will re-use the previously created property if it contained the same + * name (but it works only for the immediate previous). + * rgerhards, 2009-06-31 + */ +rsRetVal MsgSetRcvFromIPStr(msg_t *pThis, uchar *psz, int len, prop_t **ppProp) { DEFiRet; - assert(pMsg != NULL); - if(pMsg->pszRcvFromIP != NULL) { - free(pMsg->pszRcvFromIP); - pMsg->iLenRcvFromIP = 0; - } + assert(pThis != NULL); + + CHKiRet(prop.CreateOrReuseStringProp(ppProp, psz, len)); + MsgSetRcvFrom(pThis, *ppProp); - CHKmalloc(pMsg->pszRcvFromIP = (uchar*)strdup((char*)pszRcvFromIP)); - pMsg->iLenRcvFromIP = strlen((char*)pszRcvFromIP); finalize_it: RETiRet; } @@ -1910,7 +2167,7 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, break; */ case PROP_INPUTNAME: - pRes = (char*) getInputName(pMsg); + getInputName(pMsg, ((uchar**) &pRes), &bufLen); break; case PROP_FROMHOST: pRes = (char*) getRcvFrom(pMsg); @@ -2638,97 +2895,6 @@ finalize_it: RETiRet; } - -/* map a property name (string) to a property ID */ -rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID) -{ - uchar *pName; - DEFiRet; - - assert(pCSPropName != NULL); - assert(pPropID != NULL); - pName = rsCStrGetSzStrNoNULL(pCSPropName); - - /* sometimes there are aliases to the original MonitoWare - * property names. These come after || in the ifs below. */ - if(!strcmp((char*) pName, "msg")) { - *pPropID = PROP_MSG; - } else if(!strcmp((char*) pName, "timestamp") - || !strcmp((char*) pName, "timereported")) { - *pPropID = PROP_TIMESTAMP; - } else if(!strcmp((char*) pName, "hostname") || !strcmp((char*) pName, "source")) { - *pPropID = PROP_HOSTNAME; - } else if(!strcmp((char*) pName, "syslogtag")) { - *pPropID = PROP_SYSLOGTAG; - } else if(!strcmp((char*) pName, "rawmsg")) { - *pPropID = PROP_RAWMSG; - /* enable this, if someone actually uses UxTradMsg, delete after some time has - * passed and nobody complained -- rgerhards, 2009-06-16 - } else if(!strcmp((char*) pName, "uxtradmsg")) { - pRes = getUxTradMsg(pMsg); - */ - } else if(!strcmp((char*) pName, "inputname")) { - *pPropID = PROP_INPUTNAME; - } else if(!strcmp((char*) pName, "fromhost")) { - *pPropID = PROP_FROMHOST; - } else if(!strcmp((char*) pName, "fromhost-ip")) { - *pPropID = PROP_FROMHOST_IP; - } else if(!strcmp((char*) pName, "pri")) { - *pPropID = PROP_PRI; - } else if(!strcmp((char*) pName, "pri-text")) { - *pPropID = PROP_PRI_TEXT; - } else if(!strcmp((char*) pName, "iut")) { - *pPropID = PROP_IUT; - } else if(!strcmp((char*) pName, "syslogfacility")) { - *pPropID = PROP_SYSLOGFACILITY; - } else if(!strcmp((char*) pName, "syslogfacility-text")) { - *pPropID = PROP_SYSLOGFACILITY_TEXT; - } else if(!strcmp((char*) pName, "syslogseverity") || !strcmp((char*) pName, "syslogpriority")) { - *pPropID = PROP_SYSLOGSEVERITY; - } else if(!strcmp((char*) pName, "syslogseverity-text") || !strcmp((char*) pName, "syslogpriority-text")) { - *pPropID = PROP_SYSLOGSEVERITY_TEXT; - } else if(!strcmp((char*) pName, "timegenerated")) { - *pPropID = PROP_TIMEGENERATED; - } else if(!strcmp((char*) pName, "programname")) { - *pPropID = PROP_PROGRAMNAME; - } else if(!strcmp((char*) pName, "protocol-version")) { - *pPropID = PROP_PROTOCOL_VERSION; - } else if(!strcmp((char*) pName, "structured-data")) { - *pPropID = PROP_STRUCTURED_DATA; - } else if(!strcmp((char*) pName, "app-name")) { - *pPropID = PROP_APP_NAME; - } else if(!strcmp((char*) pName, "procid")) { - *pPropID = PROP_PROCID; - } else if(!strcmp((char*) pName, "msgid")) { - *pPropID = PROP_MSGID; - /* here start system properties (those, that do not relate to the message itself */ - } else if(!strcmp((char*) pName, "$now")) { - *pPropID = PROP_SYS_NOW; - } else if(!strcmp((char*) pName, "$year")) { - *pPropID = PROP_SYS_YEAR; - } else if(!strcmp((char*) pName, "$month")) { - *pPropID = PROP_SYS_MONTH; - } else if(!strcmp((char*) pName, "$day")) { - *pPropID = PROP_SYS_DAY; - } else if(!strcmp((char*) pName, "$hour")) { - *pPropID = PROP_SYS_HOUR; - } else if(!strcmp((char*) pName, "$hhour")) { - *pPropID = PROP_SYS_HHOUR; - } else if(!strcmp((char*) pName, "$qhour")) { - *pPropID = PROP_SYS_QHOUR; - } else if(!strcmp((char*) pName, "$minute")) { - *pPropID = PROP_SYS_MINUTE; - } else if(!strcmp((char*) pName, "$myhostname")) { - *pPropID = PROP_SYS_MYHOSTNAME; - } else { - *pPropID = PROP_INVALID; - iRet = RS_RET_VAR_NOT_FOUND; - } - - RETiRet; -} - - /* This function can be used as a generic way to set properties. * We have to handle a lot of legacy, so our return value is not always * 100% correct (called functions do not always provide one, should @@ -2738,6 +2904,9 @@ rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID) #define isProp(name) !rsCStrSzStrCmp(pProp->pcsName, (uchar*) name, sizeof(name) - 1) rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp) { + prop_t *myProp; + prop_t *propRcvFrom = NULL; + prop_t *propRcvFromIP = NULL; DEFiRet; ISOBJ_TYPE_assert(pThis, msg); @@ -2765,11 +2934,18 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp) } else if(isProp("pszTAG")) { MsgSetTAG(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr), cstrLen(pProp->val.pStr)); } else if(isProp("pszInputName")) { - MsgSetInputName(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr), rsCStrLen(pProp->val.pStr)); + /* we need to create a property */ + CHKiRet(prop.Construct(&myProp)); + CHKiRet(prop.SetString(myProp, rsCStrGetSzStrNoNULL(pProp->val.pStr), rsCStrLen(pProp->val.pStr))); + CHKiRet(prop.ConstructFinalize(myProp)); + MsgSetInputName(pThis, myProp); + prop.Destruct(&myProp); } else if(isProp("pszRcvFromIP")) { - MsgSetRcvFromIP(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr)); + MsgSetRcvFromIPStr(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr), rsCStrLen(pProp->val.pStr), &propRcvFromIP); + prop.Destruct(&propRcvFromIP); } else if(isProp("pszRcvFrom")) { - MsgSetRcvFrom(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr)); + MsgSetRcvFromStr(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr), rsCStrLen(pProp->val.pStr), &propRcvFrom); + prop.Destruct(&propRcvFrom); } else if(isProp("pszHOSTNAME")) { MsgSetHOSTNAME(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr), rsCStrLen(pProp->val.pStr)); } else if(isProp("pCSStrucData")) { @@ -2790,6 +2966,7 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp) dbgprintf("no longer supported property pszMSG silently ignored\n"); } +finalize_it: RETiRet; } #undef isProp @@ -2833,6 +3010,7 @@ BEGINObjClassInit(msg, 1, OBJ_IS_CORE_MODULE) CHKiRet(objUse(var, CORE_COMPONENT)); CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_SERIALIZE, MsgSerialize); diff --git a/runtime/msg.h b/runtime/msg.h index e6b25e6c..c20fb005 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -72,21 +72,15 @@ struct msg { short iFacility; /* Facility code 0 .. 23*/ short offAfterPRI; /* offset, at which raw message WITHOUT PRI part starts in pszRawMsg */ short offMSG; /* offset at which the MSG part starts in pszRawMsg */ - short iLenInputName; /* Length of pszInputName */ short iProtocolVersion;/* protocol version of message received 0 - legacy, 1 syslog-protocol) */ int msgFlags; /* flags associated with this message */ int iLenRawMsg; /* length of raw message */ int iLenMSG; /* Length of the MSG part */ int iLenTAG; /* Length of the TAG part */ int iLenHOSTNAME; /* Length of HOSTNAME */ - int iLenRcvFrom; /* Length of pszRcvFrom */ - int iLenRcvFromIP; /* Length of pszRcvFromIP */ uchar *pszRawMsg; /* message as it was received on the wire. This is important in case we * need to preserve cryptographic verifiers. */ uchar *pszHOSTNAME; /* HOSTNAME from syslog message */ - uchar *pszRcvFrom; /* System message was received from */ - uchar *pszRcvFromIP; /* IP of system message was received from */ - uchar *pszInputName; /* name of the input module that submitted this message */ char *pszRcvdAt3164; /* time as RFC3164 formatted string (always 15 charcters) */ char *pszRcvdAt3339; /* time as RFC3164 formatted string (32 charcters at most) */ char *pszRcvdAt_MySQL; /* rcvdAt as MySQL formatted string (always 14 charcters) */ @@ -100,6 +94,9 @@ struct msg { cstr_t *pCSAPPNAME; /* APP-NAME */ cstr_t *pCSPROCID; /* PROCID */ cstr_t *pCSMSGID; /* MSGID */ + prop_t *pInputName; /* input name property */ + prop_t *pRcvFrom; /* name of system message was received from */ + prop_t *pRcvFromIP; /* IP of system message was received from */ ruleset_t *pRuleset; /* ruleset to be used for processing this message */ time_t ttGenTime; /* time msg object was generated, same as tRcvdAt, but a Unix timestamp. While this field looks redundant, it is required because a Unix timestamp @@ -144,7 +141,7 @@ rsRetVal msgDestruct(msg_t **ppM); msg_t* MsgDup(msg_t* pOld); msg_t *MsgAddRef(msg_t *pM); void setProtocolVersion(msg_t *pM, int iNewVersion); -void MsgSetInputName(msg_t *pMsg, uchar*, size_t); +void MsgSetInputName(msg_t *pMsg, prop_t*); rsRetVal MsgSetAPPNAME(msg_t *pMsg, char* pszAPPNAME); rsRetVal MsgSetPROCID(msg_t *pMsg, char* pszPROCID); rsRetVal MsgSetMSGID(msg_t *pMsg, char* pszMSGID); @@ -152,8 +149,10 @@ void MsgSetTAG(msg_t *pMsg, uchar* pszBuf, size_t lenBuf); void MsgSetRuleset(msg_t *pMsg, ruleset_t*); rsRetVal MsgSetFlowControlType(msg_t *pMsg, flowControl_t eFlowCtl); rsRetVal MsgSetStructuredData(msg_t *pMsg, char* pszStrucData); -void MsgSetRcvFrom(msg_t *pMsg, uchar* pszRcvFrom); -rsRetVal MsgSetRcvFromIP(msg_t *pMsg, uchar* pszRcvFromIP); +void MsgSetRcvFrom(msg_t *pMsg, prop_t*); +void MsgSetRcvFromStr(msg_t *pMsg, uchar* pszRcvFrom, int, prop_t **); +rsRetVal MsgSetRcvFromIP(msg_t *pMsg, prop_t*); +rsRetVal MsgSetRcvFromIPStr(msg_t *pThis, uchar *psz, int len, prop_t **ppProp); void MsgSetHOSTNAME(msg_t *pMsg, uchar* pszHOSTNAME, int lenHOSTNAME); rsRetVal MsgSetAfterPRIOffs(msg_t *pMsg, short offs); void MsgSetMSGoffs(msg_t *pMsg, short offs); @@ -165,6 +164,8 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, char *textpri(char *pRes, size_t pResLen, int pri); rsRetVal msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar); rsRetVal MsgEnableThreadSafety(void); +uchar *getRcvFrom(msg_t *pM); + /* TODO: remove these five (so far used in action.c) */ char *getMSG(msg_t *pM); @@ -179,6 +180,7 @@ char *getProgramName(msg_t *pM, bool bLockMutex); int getProgramNameLen(msg_t *pM, bool bLockMutex); uchar *getRcvFrom(msg_t *pM); rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID); +uchar *propIDToName(propid_t propID); /* The MsgPrepareEnqueue() function is a macro for performance reasons. diff --git a/runtime/obj-types.h b/runtime/obj-types.h index 6c1381ac..e1b54d4f 100644 --- a/runtime/obj-types.h +++ b/runtime/obj-types.h @@ -293,6 +293,15 @@ rsRetVal objName##ClassExit(void) \ ISOBJ_TYPE_assert(pThis, OBJ); \ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &iCancelStateSave); +/* note: there was a long-time bug in the macro below that lead to *ppThis = NULL + * only when the object was actually destructed. I discovered this issue during + * introduction of the pRcvFrom property in msg_t, but it potentially had other + * effects, too. I am not sure if some experienced instability resulted from this + * bug OR if its fix will cause harm to so-far "correctly" running code. The later + * may very well be. Thus I will change it only for the current branch and also + * the beta, but not in all old builds. Let's see how things evolve. + * rgerhards, 2009-06-30 + */ #define ENDobjDestruct(OBJ) \ goto finalize_it; /* prevent compiler warning ;) */ \ /* no more code here! */ \ @@ -300,8 +309,8 @@ rsRetVal objName##ClassExit(void) \ if(pThis != NULL) { \ obj.DestructObjSelf((obj_t*) pThis); \ free(pThis); \ - *ppThis = NULL; \ } \ + *ppThis = NULL; \ pthread_setcancelstate(iCancelStateSave, NULL); \ RETiRet; \ } diff --git a/runtime/parser.c b/runtime/parser.c index d4ca7673..a5183105 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -261,7 +261,7 @@ rsRetVal parseMsg(msg_t *pMsg) CHKiRet(sanitizeMessage(pMsg)); /* we needed to sanitize first, because we otherwise do not have a C-string we can print... */ - DBGPRINTF("msg parser: flags %x, from '%s', msg '%s'\n", pMsg->msgFlags, pMsg->pszRcvFrom, pMsg->pszRawMsg); + DBGPRINTF("msg parser: flags %x, from '%s', msg '%s'\n", pMsg->msgFlags, getRcvFrom(pMsg), pMsg->pszRawMsg); /* pull PRI */ pri = DEFUPRI; diff --git a/runtime/prop.c b/runtime/prop.c index 02be315f..804f3491 100644 --- a/runtime/prop.c +++ b/runtime/prop.c @@ -36,9 +36,13 @@ #include "config.h" #include <stdlib.h> #include <assert.h> +#include <string.h> #include "rsyslog.h" #include "obj.h" +#include "obj-types.h" +#include "unicode-helper.h" +#include "atomic.h" #include "prop.h" /* static data */ @@ -48,9 +52,69 @@ DEFobjStaticHelpers /* Standard-Constructor */ BEGINobjConstruct(prop) /* be sure to specify the object type also in END macro! */ + pThis->iRefCount = 1; ENDobjConstruct(prop) +/* destructor for the prop object */ +BEGINobjDestruct(prop) /* be sure to specify the object type also in END and CODESTART macros! */ + int currRefCount; +CODESTARTobjDestruct(prop) + currRefCount = ATOMIC_DEC_AND_FETCH(pThis->iRefCount); + if(currRefCount == 0) { + /* (only) in this case we need to actually destruct the object */ + if(pThis->len >= CONF_PROP_BUFSIZE) + free(pThis->szVal.psz); + } else { + pThis = NULL; /* tell framework NOT to destructing the object! */ + } +ENDobjDestruct(prop) + +/* set string, we make our own private copy! This MUST only be called BEFORE + * ConstructFinalize()! + */ +static rsRetVal SetString(prop_t *pThis, uchar *psz, int len) +{ + DEFiRet; + ISOBJ_TYPE_assert(pThis, prop); + if(pThis->len >= CONF_PROP_BUFSIZE) + free(pThis->szVal.psz); + pThis->len = len; + if(len < CONF_PROP_BUFSIZE) { + memcpy(pThis->szVal.sz, psz, len + 1); + } else { + CHKmalloc(pThis->szVal.psz = malloc(len + 1)); + memcpy(pThis->szVal.psz, psz, len + 1); + } + +finalize_it: + RETiRet; +} + + +/* get string length */ +static int GetStringLen(prop_t *pThis) +{ + return pThis->len; +} + + +/* get string */ +static rsRetVal GetString(prop_t *pThis, uchar **ppsz, int *plen) +{ + BEGINfunc + ISOBJ_TYPE_assert(pThis, prop); + if(pThis->len < CONF_PROP_BUFSIZE) { + *ppsz = pThis->szVal.sz; + } else { + *ppsz = pThis->szVal.psz; + } + *plen = pThis->len; + ENDfunc + return RS_RET_OK; +} + + /* ConstructionFinalizer * rgerhards, 2008-01-09 */ @@ -63,10 +127,63 @@ propConstructFinalize(prop_t __attribute__((unused)) *pThis) } -/* destructor for the prop object */ -BEGINobjDestruct(prop) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(prop) -ENDobjDestruct(prop) +/* add a new reference. It is VERY IMPORTANT to call this function whenever + * the property is handed over to some entitiy that later call Destruct() on it. + */ +static rsRetVal AddRef(prop_t *pThis) +{ + ATOMIC_INC(pThis->iRefCount); + return RS_RET_OK; +} + + +/* this is a "do it all in one shot" function that creates a new property, + * assigns the provided string to it and finalizes the property. Among the + * convenience, it is alos (very, very) slightly faster. + * rgerhards, 2009-07-01 + */ +static rsRetVal CreateStringProp(prop_t **ppThis, uchar* psz, int len) +{ + DEFiRet; + propConstruct(ppThis); + SetString(*ppThis, psz, len); + propConstructFinalize(*ppThis); + RETiRet; +} + +/* another one-stop function, quite useful: it takes a property pointer and + * a string. If the string is already contained in the property, nothing happens. + * If the string is different (or the pointer NULL), the current property + * is destructed and a new one created. This can be used to get a specific + * name in those cases where there is a good chance that the property + * immediatly previously processed already contained the value we need - in + * which case we save us all the creation overhead by just reusing the already + * existing property). + * rgerhards, 2009-07-01 + */ +rsRetVal CreateOrReuseStringProp(prop_t **ppThis, uchar *psz, int len) +{ + uchar *pszPrev; + int lenPrev; + DEFiRet; + assert(ppThis != NULL); + + if(*ppThis == NULL) { + /* we need to create a property */ + CHKiRet(CreateStringProp(ppThis, psz, len)); + } else { + /* already exists, check if we can re-use it */ + GetString(*ppThis, &pszPrev, &lenPrev); + if(len != lenPrev && ustrcmp(psz, pszPrev)) { + /* different, need to discard old & create new one */ + propDestruct(ppThis); + CHKiRet(CreateStringProp(ppThis, psz, len)); + } /* else we can re-use the existing one! */ + } + +finalize_it: + RETiRet; +} /* debugprint for the prop object */ @@ -94,6 +211,12 @@ CODESTARTobjQueryInterface(prop) pIf->ConstructFinalize = propConstructFinalize; pIf->Destruct = propDestruct; pIf->DebugPrint = propDebugPrint; + pIf->SetString = SetString; + pIf->GetString = GetString; + pIf->GetStringLen = GetStringLen; + pIf->AddRef = AddRef; + pIf->CreateStringProp = CreateStringProp; + pIf->CreateOrReuseStringProp = CreateOrReuseStringProp; finalize_it: ENDobjQueryInterface(prop) diff --git a/runtime/prop.h b/runtime/prop.h index 7fc466b5..e3519664 100644 --- a/runtime/prop.h +++ b/runtime/prop.h @@ -28,14 +28,26 @@ /* the prop object */ struct prop_s { BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ + int iRefCount; /* reference counter */ + union { + uchar *psz; /* stored string */ + uchar sz[CONF_PROP_BUFSIZE]; + } szVal; + int len; /* we use int intentionally, otherwise we may get some troubles... */ }; /* interfaces */ BEGINinterface(prop) /* name must also be changed in ENDinterface macro! */ INTERFACEObjDebugPrint(prop); rsRetVal (*Construct)(prop_t **ppThis); - rsRetVal (*ConstructFinalize)(prop_t __attribute__((unused)) *pThis); + rsRetVal (*ConstructFinalize)(prop_t *pThis); rsRetVal (*Destruct)(prop_t **ppThis); + rsRetVal (*SetString)(prop_t *pThis, uchar* psz, int len); + rsRetVal (*GetString)(prop_t *pThis, uchar** ppsz, int *plen); + int (*GetStringLen)(prop_t *pThis); + rsRetVal (*AddRef)(prop_t *pThis); + rsRetVal (*CreateStringProp)(prop_t **ppThis, uchar* psz, int len); + rsRetVal (*CreateOrReuseStringProp)(prop_t **ppThis, uchar *psz, int len); ENDinterface(prop) #define propCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 6f732f0e..443d0f41 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -77,6 +77,7 @@ #include "conf.h" #include "glbl.h" #include "errmsg.h" +#include "prop.h" #include "rule.h" #include "ruleset.h" @@ -146,6 +147,8 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) * class immediately after it is initialized. And, of course, we load those classes * first that we use ourselfs... -- rgerhards, 2008-03-07 */ + if(ppErrObj != NULL) *ppErrObj = "prop"; + CHKiRet(propClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "glbl"; CHKiRet(glblClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "datetime"; diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 76f320e6..c51b1272 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -39,6 +39,7 @@ #define CONF_RAWMSG_BUFSIZE 101 #define CONF_TAG_BUFSIZE 32 #define CONF_HOSTNAME_BUFSIZE 32 +#define CONF_PROP_BUFSIZE 16 /* should be close to sizeof(ptr) or lighly above it */ /* ############################################################# * diff --git a/runtime/rule.c b/runtime/rule.c index ce19146b..3a257a90 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -219,8 +219,8 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, int *bProcessMsg) bRet = (bRet == 1) ? 0 : 1; if(Debug) { - dbgprintf("Filter: check for property '%d' (value '%s') ", - pRule->f_filterData.prop.propID, pszPropVal); + dbgprintf("Filter: check for property '%s' (value '%s') ", + propIDToName(pRule->f_filterData.prop.propID), pszPropVal); if(pRule->f_filterData.prop.isNegated) dbgprintf("NOT "); dbgprintf("%s '%s': %s\n", @@ -373,8 +373,7 @@ CODESTARTobjDebugPrint(rule) dbgprintf("EXPRESSION-BASED Filter: can currently not be displayed"); } else { dbgprintf("PROPERTY-BASED Filter:\n"); - dbgprintf("\tProperty.: '%d'\n", pThis->f_filterData.prop.propID); -// TODO: XXXX ADD idtostring()! + dbgprintf("\tProperty.: '%s'\n", propIDToName(pThis->f_filterData.prop.propID)); dbgprintf("\tOperation: "); if(pThis->f_filterData.prop.isNegated) dbgprintf("NOT "); diff --git a/runtime/stringbuf.c b/runtime/stringbuf.c index 88f5a3a2..93995b38 100644 --- a/runtime/stringbuf.c +++ b/runtime/stringbuf.c @@ -1,4 +1,3 @@ -#include <stdio.h> /* This is the byte-counted string class for rsyslog. It is a replacement * for classical \0 terminated string functions. We introduce it in * the hope it will make the program more secure, obtain some performance diff --git a/runtime/stringbuf.h b/runtime/stringbuf.h index 400c74eb..c5130238 100644 --- a/runtime/stringbuf.h +++ b/runtime/stringbuf.h @@ -35,6 +35,7 @@ #ifndef _STRINGBUF_H_INCLUDED__ #define _STRINGBUF_H_INCLUDED__ 1 +#include <assert.h> /** * The dynamic string buffer object. @@ -48,7 +49,6 @@ typedef struct cstr_s uchar *pszBuf; /**< pointer to the sz version of the string (after it has been created )*/ size_t iBufSize; /**< current maximum size of the string buffer */ size_t iStrLen; /**< length of the string in characters. */ - bool bIsForeignBuf; /**< is pBuf a buffer provided by someone else? */ } cstr_t; diff --git a/tcps_sess.c b/tcps_sess.c index e0bec949..8d307380 100644 --- a/tcps_sess.c +++ b/tcps_sess.c @@ -36,6 +36,7 @@ #include "rsyslog.h" #include "dirty.h" +#include "unicode-helper.h" #include "module-template.h" #include "net.h" #include "tcpsrv.h" @@ -45,6 +46,7 @@ #include "netstrm.h" #include "msg.h" #include "datetime.h" +#include "prop.h" /* static data */ @@ -52,6 +54,7 @@ DEFobjStaticHelpers DEFobjCurrIf(glbl) DEFobjCurrIf(errmsg) DEFobjCurrIf(netstrm) +DEFobjCurrIf(prop) DEFobjCurrIf(datetime) static int iMaxLine; /* maximum size of a single message */ @@ -100,8 +103,10 @@ CODESTARTobjDestruct(tcps_sess) pThis->pSrv->pOnSessDestruct(&pThis->pUsr); } /* now destruct our own properties */ - free(pThis->fromHost); - free(pThis->fromHostIP); + if(pThis->fromHost != NULL) + CHKiRet(prop.Destruct(&pThis->fromHost)); + if(pThis->fromHostIP != NULL) + CHKiRet(prop.Destruct(&pThis->fromHostIP)); free(pThis->pMsg); ENDobjDestruct(tcps_sess) @@ -124,9 +129,13 @@ SetHost(tcps_sess_t *pThis, uchar *pszHost) ISOBJ_TYPE_assert(pThis, tcps_sess); - free(pThis->fromHost); - pThis->fromHost = pszHost; + if(pThis->fromHost == NULL) + CHKiRet(prop.Construct(&pThis->fromHost)); + CHKiRet(prop.SetString(pThis->fromHost, pszHost, ustrlen(pszHost))); + +finalize_it: + free(pszHost); /* we must free according to our (old) calling conventions */ RETiRet; } @@ -141,9 +150,13 @@ SetHostIP(tcps_sess_t *pThis, uchar *pszHostIP) ISOBJ_TYPE_assert(pThis, tcps_sess); - free(pThis->fromHostIP); - pThis->fromHostIP = pszHostIP; + if(pThis->fromHostIP == NULL) + CHKiRet(prop.Construct(&pThis->fromHostIP)); + CHKiRet(prop.SetString(pThis->fromHostIP, pszHostIP, ustrlen(pszHostIP))); + +finalize_it: + free(pszHostIP); RETiRet; } @@ -234,15 +247,14 @@ defaultDoSubmitMessage(tcps_sess_t *pThis, struct syslogTime *stTime, time_t ttG /* we now create our own message object and submit it to the queue */ CHKiRet(msgConstructWithTime(&pMsg, stTime, ttGenTime)); -dbgprintf("defaultDoSubmit, iMsg %d\n", pThis->iMsg); MsgSetRawMsg(pMsg, (char*)pThis->pMsg, pThis->iMsg); - MsgSetInputName(pMsg, pThis->pLstnInfo->pszInputName, pThis->pLstnInfo->lenInputName); + MsgSetInputName(pMsg, pThis->pLstnInfo->pInputName); MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY); pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME; pMsg->bParseHOSTNAME = 1; MsgSetRcvFrom(pMsg, pThis->fromHost); - MsgSetRuleset(pMsg, pThis->pLstnInfo->pRuleset); CHKiRet(MsgSetRcvFromIP(pMsg, pThis->fromHostIP)); + MsgSetRuleset(pMsg, pThis->pLstnInfo->pRuleset); if(pMultiSub == NULL) { CHKiRet(submitMsg(pMsg)); @@ -324,10 +336,11 @@ Close(tcps_sess_t *pThis) ISOBJ_TYPE_assert(pThis, tcps_sess); netstrm.Destruct(&pThis->pStrm); - free(pThis->fromHost); - pThis->fromHost = NULL; /* not really needed, but... */ - free(pThis->fromHostIP); - pThis->fromHostIP = NULL; /* not really needed, but... */ + if(pThis->fromHost != NULL) { + prop.Destruct(&pThis->fromHost); + } + if(pThis->fromHostIP != NULL) + prop.Destruct(&pThis->fromHostIP); RETiRet; } @@ -520,6 +533,7 @@ CODESTARTObjClassExit(tcps_sess) objRelease(errmsg, CORE_COMPONENT); objRelease(netstrm, LM_NETSTRMS_FILENAME); objRelease(datetime, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); ENDObjClassExit(tcps_sess) @@ -532,6 +546,7 @@ BEGINObjClassInit(tcps_sess, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE c CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(netstrm, LM_NETSTRMS_FILENAME)); CHKiRet(objUse(datetime, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); iMaxLine = glbl.GetMaxLine(); /* get maximum size we currently support */ diff --git a/tcps_sess.h b/tcps_sess.h index 5e59aaab..ec3a6af4 100644 --- a/tcps_sess.h +++ b/tcps_sess.h @@ -24,6 +24,7 @@ #define INCLUDED_TCPS_SESS_H #include "obj.h" +#include "prop.h" /* a forward-definition, we are somewhat cyclic */ struct tcpsrv_s; @@ -44,8 +45,8 @@ struct tcps_sess_s { int iOctetsRemain; /* Number of Octets remaining in message */ TCPFRAMINGMODE eFraming; uchar *pMsg; /* message (fragment) received */ - uchar *fromHost; - uchar *fromHostIP; + prop_t *fromHost; /* host name we received messages from */ + prop_t *fromHostIP; void *pUsr; /* a user-pointer */ rsRetVal (*DoSubmitMessage)(tcps_sess_t*, uchar*, int); /* submit message callback */ }; @@ -89,6 +89,7 @@ DEFobjCurrIf(net) DEFobjCurrIf(netstrms) DEFobjCurrIf(netstrm) DEFobjCurrIf(nssel) +DEFobjCurrIf(prop) /* add new listener port to listener port list @@ -107,8 +108,11 @@ addNewLstnPort(tcpsrv_t *pThis, uchar *pszPort) pEntry->pszPort = pszPort; pEntry->pSrv = pThis; pEntry->pRuleset = pThis->pRuleset; - CHKmalloc(pEntry->pszInputName = ustrdup(pThis->pszInputName)); - pEntry->lenInputName = ustrlen(pEntry->pszInputName); + + /* we need to create a property */ + CHKiRet(prop.Construct(&pEntry->pInputName)); + CHKiRet(prop.SetString(pEntry->pInputName, pThis->pszInputName, ustrlen(pThis->pszInputName))); + CHKiRet(prop.ConstructFinalize(pEntry->pInputName)); /* and add to list */ pEntry->pNext = pThis->pLstnPorts; @@ -250,7 +254,7 @@ static void deinit_tcp_listener(tcpsrv_t *pThis) pEntry = pThis->pLstnPorts; while(pEntry != NULL) { free(pEntry->pszPort); - free(pEntry->pszInputName); + prop.Destruct(&pEntry->pInputName); pDel = pEntry; pEntry = pEntry->pNext; free(pDel); @@ -477,6 +481,7 @@ Run(tcpsrv_t *pThis) * this thread. Thus, we also need to instantiate a cancel cleanup handler * to prevent us from leaking anything. -- rgerharsd, 20080-04-24 */ +RUNLOG_STR("XXXX: tcp server runs\n"); pthread_cleanup_push(RunCancelCleanup, (void*) &pSel); while(1) { CHKiRet(nssel.Construct(&pSel)); @@ -497,6 +502,7 @@ Run(tcpsrv_t *pThis) iTCPSess = TCPSessGetNxtSess(pThis, iTCPSess); } +RUNLOG_STR("XXXX: tcp server select\n"); /* wait for io to become ready */ CHKiRet(nssel.Wait(pSel, &nfds)); @@ -508,6 +514,7 @@ Run(tcpsrv_t *pThis) --nfds; /* indicate we have processed one */ } } +RUNLOG_STR("XXXX: tcp server post select\n"); /* now check the sessions */ iTCPSess = TCPSessGetNxtSess(pThis, -1); @@ -883,6 +890,7 @@ CODESTARTObjClassExit(tcpsrv) /* release objects we no longer need */ objRelease(tcps_sess, DONT_LOAD_LIB); objRelease(conf, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); objRelease(ruleset, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); @@ -908,6 +916,7 @@ BEGINObjClassInit(tcpsrv, 1, OBJ_IS_LOADABLE_MODULE) /* class, version - CHANGE CHKiRet(objUse(conf, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(ruleset, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, tcpsrvDebugPrint); @@ -23,6 +23,7 @@ #define INCLUDED_TCPSRV_H #include "obj.h" +#include "prop.h" #include "tcps_sess.h" /* support for framing anomalies */ @@ -36,8 +37,7 @@ typedef enum ETCPsyslogFramingAnomaly { /* list of tcp listen ports */ struct tcpLstnPortList_s { uchar *pszPort; /**< the ports the listener shall listen on */ - uchar *pszInputName; /**< value to be used as input name */ - size_t lenInputName; /**< length of inputName */ + prop_t *pInputName; tcpsrv_t *pSrv; /**< pointer to higher-level server instance */ ruleset_t *pRuleset; /**< associated ruleset */ tcpLstnPortList_t *pNext; /**< next port or NULL */ diff --git a/tests/nettester.c b/tests/nettester.c index b8816b7c..dbfb4db3 100644 --- a/tests/nettester.c +++ b/tests/nettester.c @@ -107,6 +107,7 @@ tcpSend(char *buf, int lenBuf) { static int sock = INVALID_SOCKET; struct sockaddr_in addr; + int retries; if(sock == INVALID_SOCKET) { /* first time, need to connect to target */ @@ -122,10 +123,20 @@ tcpSend(char *buf, int lenBuf) fprintf(stderr, "inet_aton() failed\n"); return(1); } - if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) != 0) { - fprintf(stderr, "connect() failed\n"); - return(1); - } + retries = 0; + while(1) { /* loop broken inside */ + if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0) { + break; + } else { + if(retries++ == 30) { + ++iFailed; + fprintf(stderr, "connect() failed\n"); + return(1); + } else { + usleep(100); + } + } + } } /* send test data */ diff --git a/tools/syslogd.c b/tools/syslogd.c index 72687495..e3824d9e 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -143,6 +143,7 @@ #include "rule.h" #include "net.h" #include "vm.h" +#include "prop.h" /* definitions for objects we access */ DEFobjCurrIf(obj) @@ -154,25 +155,13 @@ DEFobjCurrIf(module) DEFobjCurrIf(errmsg) DEFobjCurrIf(rule) DEFobjCurrIf(ruleset) +DEFobjCurrIf(prop) DEFobjCurrIf(net) /* TODO: make go away! */ /* forward definitions */ static rsRetVal GlobalClassExit(void); -/* We define our own set of syslog defintions so that we - * do not need to rely on (possibly different) implementations. - * 2007-07-19 rgerhards - */ -/* missing definitions for solaris - * 2006-02-16 Rger - */ -#ifdef __sun -# define LOG_AUTHPRIV LOG_AUTH -#endif -#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */ -#define LOG_FTP (11<<3) /* ftp daemon */ - #ifndef UTMP_FILE #ifdef UTMP_FILENAME @@ -220,14 +209,12 @@ static rsRetVal GlobalClassExit(void); # endif #endif -#ifndef _PATH_DEV -# define _PATH_DEV "/dev/" -#endif - #ifndef _PATH_TTY # define _PATH_TTY "/dev/tty" #endif +static prop_t *pInternalInputName = NULL; /* there is only one global inputName for all internally-generated messages */ +static prop_t *pLocalHostIP = NULL; /* there is only one global IP for all internally-generated messages */ static uchar *ConfFile = (uchar*) _PATH_LOGCONF; /* read-only after startup */ static char *PidFile = _PATH_LOGPID; /* read-only after startup */ @@ -571,12 +558,14 @@ void untty(void) * interface change: bParseHostname removed, now in flags */ static inline rsRetVal printline(uchar *hname, uchar *hnameIP, uchar *msg, int flags, flowControl_t flowCtlType, - uchar *pszInputName, struct syslogTime *stTime, time_t ttGenTime) + prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime) { DEFiRet; register uchar *p; int pri; msg_t *pMsg; + prop_t *propFromHost = NULL; + prop_t *propFromHostIP = NULL; /* Now it is time to create the message object (rgerhards) */ if(stTime == NULL) { @@ -584,8 +573,8 @@ static inline rsRetVal printline(uchar *hname, uchar *hnameIP, uchar *msg, int f } else { CHKiRet(msgConstructWithTime(&pMsg, stTime, ttGenTime)); } - if(pszInputName != NULL) - MsgSetInputName(pMsg, pszInputName, ustrlen(pszInputName)); + if(pInputName != NULL) + MsgSetInputName(pMsg, pInputName); MsgSetFlowControlType(pMsg, flowCtlType); MsgSetRawMsgWOSize(pMsg, (char*)msg); @@ -615,9 +604,9 @@ static inline rsRetVal printline(uchar *hname, uchar *hnameIP, uchar *msg, int f */ if((pMsg->msgFlags & PARSE_HOSTNAME) == 0) MsgSetHOSTNAME(pMsg, hname, ustrlen(hname)); - MsgSetRcvFrom(pMsg, hname); + MsgSetRcvFromStr(pMsg, hname, ustrlen(hname), &propFromHost); + CHKiRet(MsgSetRcvFromIPStr(pMsg, hnameIP, ustrlen(hname), &propFromHostIP)); MsgSetAfterPRIOffs(pMsg, p - msg); - CHKiRet(MsgSetRcvFromIP(pMsg, hnameIP)); logmsg(pMsg, flags); @@ -680,7 +669,7 @@ finalize_it: */ rsRetVal parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlType, - uchar *pszInputName, struct syslogTime *stTime, time_t ttGenTime) + prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime) { DEFiRet; register int iMsg; @@ -791,7 +780,7 @@ parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int fla */ if(iMsg == iMaxLine) { *(pMsg + iMsg) = '\0'; /* space *is* reserved for this! */ - printline(hname, hnameIP, tmpline, flags, flowCtlType, pszInputName, stTime, ttGenTime); + printline(hname, hnameIP, tmpline, flags, flowCtlType, pInputName, stTime, ttGenTime); } else { /* This case in theory never can happen. If it happens, we have * a logic error. I am checking for it, because if I would not, @@ -843,7 +832,7 @@ parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int fla *(pMsg + iMsg) = '\0'; /* space *is* reserved for this! */ /* typically, we should end up here! */ - printline(hname, hnameIP, tmpline, flags, flowCtlType, pszInputName, stTime, ttGenTime); + printline(hname, hnameIP, tmpline, flags, flowCtlType, pInputName, stTime, ttGenTime); finalize_it: if(tmpline != NULL) @@ -886,11 +875,11 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags) DEFiRet; CHKiRet(msgConstruct(&pMsg)); - MsgSetInputName(pMsg, UCHAR_CONSTANT("rsyslogd"), sizeof("rsyslogd")-1); + MsgSetInputName(pMsg, pInternalInputName); MsgSetRawMsgWOSize(pMsg, (char*)msg); MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())); - MsgSetRcvFrom(pMsg, glbl.GetLocalHostName()); - MsgSetRcvFromIP(pMsg, UCHAR_CONSTANT("127.0.0.1")); + MsgSetRcvFrom(pMsg, glbl.GetLocalHostNameProp()); + MsgSetRcvFromIP(pMsg, pLocalHostIP); /* check if we have an error code associated and, if so, * adjust the tag. -- rgerhards, 2008-06-27 */ @@ -1955,6 +1944,12 @@ die(int sig) legacyOptsFree(); + /* destruct our global properties */ + if(pInternalInputName != NULL) + prop.Destruct(&pInternalInputName); + if(pLocalHostIP != NULL) + prop.Destruct(&pLocalHostIP); + /* terminate the remaining classes */ GlobalClassExit(); @@ -2325,6 +2320,30 @@ static void dbgPrintInitInfo(void) } +/* Actually run the input modules. This happens after privileges are dropped, + * if that is requested. + */ +static rsRetVal +runInputModules(void) +{ + modInfo_t *pMod; + + BEGINfunc + /* loop through all modules and activate them (brr...) */ + pMod = module.GetNxtType(NULL, eMOD_IN); + while(pMod != NULL) { + if(pMod->mod.im.bCanRun) { + /* activate here */ + thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun); + } + pMod = module.GetNxtType(pMod, eMOD_IN); + } + + ENDfunc + return RS_RET_OK; /* intentional: we do not care about module errors */ +} + + /* Start the input modules. This function will probably undergo big changes * while we implement the input module interface. For now, it does the most * important thing to get at least my poor initial input modules up and @@ -2340,10 +2359,9 @@ startInputModules(void) /* loop through all modules and activate them (brr...) */ pMod = module.GetNxtType(NULL, eMOD_IN); while(pMod != NULL) { - if((iRet = pMod->mod.im.willRun()) == RS_RET_OK) { - /* activate here */ - thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun); - } else { + iRet = pMod->mod.im.willRun(); + pMod->mod.im.bCanRun = (iRet == RS_RET_OK); + if(!pMod->mod.im.bCanRun) { DBGPRINTF("module %lx will not run, iRet %d\n", (unsigned long) pMod, iRet); } pMod = module.GetNxtType(pMod, eMOD_IN); @@ -2360,7 +2378,7 @@ startInputModules(void) * else happens. -- rgerhards, 2008-07-28 */ static rsRetVal -init(void) +init() { rsRetVal localRet; int iNbrActions; @@ -2562,9 +2580,12 @@ init(void) DBGPRINTF("Main processing queue is initialized and running\n"); /* the output part and the queue is now ready to run. So it is a good time - * to start the inputs. Please note that the net code above should be + * to initialize the inputs. Please note that the net code above should be * shuffled to down here once we have everything in input modules. * rgerhards, 2007-12-14 + * NOTE: as of 2009-06-29, the input modules are initialized, but not yet run. + * Keep in mind. though, that the outputs already run if the queue was + * persisted to disk. -- rgerhards */ startInputModules(); @@ -2738,6 +2759,7 @@ doHUP(void) if(glbl.GetHUPisRestart()) { DBGPRINTF("Received SIGHUP, configured to be restart, reloading rsyslogd.\n"); init(); /* main queue is stopped as part of init() */ + runInputModules(); } else { DBGPRINTF("Received SIGHUP, configured to be a non-restart type of HUP - notifying actions.\n"); ruleset.IterateAllActions(doHUPActions, NULL); @@ -3001,6 +3023,7 @@ static rsRetVal mainThread() if(Debug && debugging_on) { DBGPRINTF("Debugging enabled, SIGUSR1 to turn off debugging.\n"); } + /* Send a signal to the parent so it can terminate. */ if(myPid != ppid) @@ -3008,7 +3031,7 @@ static rsRetVal mainThread() /* If instructed to do so, we now drop privileges. Note that this is not 100% secure, - * because inputs and outputs are already running at this time. However, we can implement + * because outputs are already running at this time. However, we can implement * dropping of privileges rather quickly and it will work in many cases. While it is not * the ultimate solution, the current one is still much better than not being able to * drop privileges at all. Doing it correctly, requires a change in architecture, which @@ -3024,15 +3047,28 @@ static rsRetVal mainThread() glbl.SetHUPisRestart(0); /* we can not do restart-type HUPs with dropped privs */ } + /* finally let the inputs run... */ + runInputModules(); /* END OF INTIALIZATION * ... but keep in mind that we might do a restart and thus init() might - * be called again. If that happens, we must shut down the worker thread, - * do the init() and then restart things. - * rgerhards, 2005-10-24 + * be called again. -- rgerhards, 2005-10-24 */ DBGPRINTF("initialization completed, transitioning to regular run mode\n"); + /* close stderr and stdout if they are kept open during a fork. Note that this + * may introduce subtle security issues: if we are in a jail, one may break out of + * it via these descriptors. But if I close them earlier, error messages will (once + * again) not be emitted to the user that starts the daemon. As root jail support + * is still in its infancy (and not really done), we currently accept this issue. + * rgerhards, 2009-06-29 + */ + if(!(Debug || NoFork)) { + close(1); + close(2); + bErrMsgToStderr = 0; + } + mainloop(); finalize_it: @@ -3072,6 +3108,8 @@ InitGlobalClasses(void) CHKiRet(objUse(ruleset, CORE_COMPONENT)); pErrObj = "conf"; CHKiRet(objUse(conf, CORE_COMPONENT)); + pErrObj = "prop"; + CHKiRet(objUse(prop, CORE_COMPONENT)); /* intialize some dummy classes that are not part of the runtime */ pErrObj = "action"; @@ -3112,6 +3150,7 @@ GlobalClassExit(void) /* first, release everything we used ourself */ objRelease(net, LM_NET_FILENAME);/* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */ + objRelease(prop, CORE_COMPONENT); objRelease(conf, CORE_COMPONENT); objRelease(ruleset, CORE_COMPONENT); objRelease(rule, CORE_COMPONENT); @@ -3418,6 +3457,15 @@ int realMain(int argc, char **argv) /* doing some core initializations */ + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInternalInputName)); + CHKiRet(prop.SetString(pInternalInputName, UCHAR_CONSTANT("rsyslogd"), sizeof("rsyslgod") - 1)); + CHKiRet(prop.ConstructFinalize(pInternalInputName)); + + CHKiRet(prop.Construct(&pLocalHostIP)); + CHKiRet(prop.SetString(pLocalHostIP, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1)); + CHKiRet(prop.ConstructFinalize(pLocalHostIP)); + /* get our host and domain names - we need to do this early as we may emit * error log messages, which need the correct hostname. -- rgerhards, 2008-04-04 */ @@ -3466,6 +3514,7 @@ int realMain(int argc, char **argv) */ glbl.SetLocalHostName(LocalHostName); glbl.SetLocalDomain(LocalDomain); + glbl.GenerateLocalHostNameProperty(); /* must be redone after conf processing, FQDN setting may have changed */ /* initialize the objects */ if((iRet = modInitIminternal()) != RS_RET_OK) { @@ -3662,6 +3711,9 @@ int realMain(int argc, char **argv) if(!iConfigVerify) CHKiRet(doGlblProcessInit()); + /* re-generate local host name property, as the config may have changed our FQDN settings */ + glbl.GenerateLocalHostNameProperty(); + CHKiRet(mainThread()); /* do any de-init's that need to be done AFTER this comment */ |