diff options
Diffstat (limited to 'runtime')
35 files changed, 666 insertions, 144 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 09cb6b41..c8e8ce2a 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -110,12 +110,12 @@ librsyslog_la_SOURCES = \ # runtime or will no longer be needed. -- rgerhards, 2008-06-13 if WITH_MODDIRS -librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) +librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) else -librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) +librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) endif #librsyslog_la_LDFLAGS = -module -avoid-version -librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS) +librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS) $(LIBEE_LIBS) # # regular expression support diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c index 646ab39b..97b35bb2 100644 --- a/runtime/cfsysline.c +++ b/runtime/cfsysline.c @@ -39,6 +39,7 @@ #include "cfsysline.h" #include "obj.h" +#include "conf.h" #include "errmsg.h" #include "srUtils.h" #include "unicode-helper.h" @@ -658,11 +659,13 @@ static int cslchKeyCompare(void *pKey1, void *pKey2) /* set data members for this object */ -rsRetVal cslchSetEntry(cslCmdHdlr_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData) +rsRetVal cslchSetEntry(cslCmdHdlr_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), + void *pData, ecslConfObjType eConfObjType) { assert(pThis != NULL); assert(eType != eCmdHdlrInvalid); + pThis->eConfObjType = eConfObjType; pThis->eType = eType; pThis->cslCmdHdlr = pHdlr; pThis->pData = pData; @@ -779,7 +782,8 @@ finalize_it: /* add a handler entry to a known command */ -static rsRetVal cslcAddHdlr(cslCmd_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie) +static rsRetVal cslcAddHdlr(cslCmd_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, + void *pOwnerCookie, ecslConfObjType eConfObjType) { DEFiRet; cslCmdHdlr_t *pCmdHdlr = NULL; @@ -787,7 +791,7 @@ static rsRetVal cslcAddHdlr(cslCmd_t *pThis, ecslCmdHdrlType eType, rsRetVal (*p assert(pThis != NULL); CHKiRet(cslchConstruct(&pCmdHdlr)); - CHKiRet(cslchSetEntry(pCmdHdlr, eType, pHdlr, pData)); + CHKiRet(cslchSetEntry(pCmdHdlr, eType, pHdlr, pData, eConfObjType)); CHKiRet(llAppend(&pThis->llCmdHdlrs, pOwnerCookie, pCmdHdlr)); finalize_it: @@ -807,7 +811,7 @@ finalize_it: * free pCmdName if he allocated it dynamically! -- rgerhards, 2007-08-09 */ rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, - void *pOwnerCookie) + void *pOwnerCookie, ecslConfObjType eConfObjType) { DEFiRet; cslCmd_t *pThis; @@ -817,7 +821,7 @@ rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlTy if(iRet == RS_RET_NOT_FOUND) { /* new command */ CHKiRet(cslcConstruct(&pThis, bChainingPermitted)); - CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie)) { + CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie, eConfObjType)) { cslcDestruct(pThis); FINALIZE; } @@ -837,7 +841,7 @@ rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlTy if(pThis->bChainingPermitted == 0 || bChainingPermitted == 0) { ABORT_FINALIZE(RS_RET_CHAIN_NOT_PERMITTED); } - CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie)) { + CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie, eConfObjType)) { cslcDestruct(pThis); FINALIZE; } @@ -912,6 +916,7 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p) uchar *pHdlrP; /* the handler's private p (else we could only call one handler) */ int bWasOnceOK; /* was the result of an handler at least once RS_RET_OK? */ uchar *pOKp = NULL; /* returned conf line pointer when it was OK */ + int bHadScopingErr = 0; /* set if a scoping error occured */ iRet = llFind(&llCmdList, (void *) pCmdName, (void*) &pCmd); @@ -925,17 +930,25 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p) llCookieCmdHdlr = NULL; bWasOnceOK = 0; while((iRetLL = llGetNextElt(&pCmd->llCmdHdlrs, &llCookieCmdHdlr, (void*)&pCmdHdlr)) == RS_RET_OK) { - /* for the time being, we ignore errors during handlers. The - * reason is that handlers are independent. An error in one - * handler does not necessarily mean that another one will - * fail, too. Later, we might add a config variable to control - * this behaviour (but I am not sure if that is rally - * necessary). -- rgerhards, 2007-07-31 - */ - pHdlrP = *p; - if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) { - bWasOnceOK = 1; - pOKp = pHdlrP; + /* check if handler is valid in current scope */ + if(pCmdHdlr->eConfObjType == eConfObjAlways || + (bConfStrictScoping == 0 && currConfObj == eConfObjGlobal) || + pCmdHdlr->eConfObjType == currConfObj) { + /* for the time being, we ignore errors during handlers. The + * reason is that handlers are independent. An error in one + * handler does not necessarily mean that another one will + * fail, too. Later, we might add a config variable to control + * this behaviour (but I am not sure if that is really + * necessary). -- rgerhards, 2007-07-31 + */ + pHdlrP = *p; + if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) { + bWasOnceOK = 1; + pOKp = pHdlrP; + } + } else { + errmsg.LogError(0, RS_RET_CONF_INVLD_SCOPE, "config command invalid for current scope"); + bHadScopingErr = 1; } } @@ -947,6 +960,10 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p) if(iRetLL != RS_RET_END_OF_LINKEDLIST) iRet = iRetLL; + if(bHadScopingErr) { + iRet = RS_RET_CONF_INVLD_SCOPE; + } + finalize_it: RETiRet; } diff --git a/runtime/cfsysline.h b/runtime/cfsysline.h index 07ab5fcd..a4502672 100644 --- a/runtime/cfsysline.h +++ b/runtime/cfsysline.h @@ -26,28 +26,12 @@ #include "linkedlist.h" -/* types of configuration handlers - */ -typedef enum cslCmdHdlrType { - eCmdHdlrInvalid = 0, /* invalid handler type - indicates a coding error */ - eCmdHdlrCustomHandler, /* custom handler, just call handler function */ - eCmdHdlrUID, - eCmdHdlrGID, - eCmdHdlrBinary, - eCmdHdlrFileCreateMode, - eCmdHdlrInt, - eCmdHdlrSize, - eCmdHdlrGetChar, - eCmdHdlrFacility, - eCmdHdlrSeverity, - eCmdHdlrGetWord -} ecslCmdHdrlType; - /* this is a single entry for a parse routine. It describes exactly * one entry point/handler. * The short name is cslch (Configfile SysLine CommandHandler) */ struct cslCmdHdlr_s { /* config file sysline parse entry */ + ecslConfObjType eConfObjType; /* which config object is this for? */ ecslCmdHdrlType eType; /* which type of handler is this? */ rsRetVal (*cslCmdHdlr)(); /* function pointer to use with handler (params depending on eType) */ void *pData; /* user-supplied data pointer */ @@ -66,7 +50,7 @@ struct cslCmd_s { /* config file sysline parse entry */ typedef struct cslCmd_s cslCmd_t; /* prototypes */ -rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie); +rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie, ecslConfObjType eConfObjType); rsRetVal unregCfSysLineHdlrs(void); rsRetVal unregCfSysLineHdlrs4Owner(void *pOwnerCookie); rsRetVal processCfSysLineCommand(uchar *pCmd, uchar **p); diff --git a/runtime/conf.c b/runtime/conf.c index 529142ed..1d28a884 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -52,7 +52,6 @@ #endif #include "rsyslog.h" -#include "../tools/syslogd.h" /* TODO: this must be removed! */ #include "dirty.h" #include "parse.h" #include "action.h" @@ -93,6 +92,10 @@ DEFobjCurrIf(net) DEFobjCurrIf(rule) DEFobjCurrIf(ruleset) +ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which config object is currently active? */ +int bConfStrictScoping = 0; /* force strict scoping during config processing? */ + + static int iNbrActions = 0; /* number of currently defined actions */ /* The following module-global variables are used for building @@ -871,6 +874,14 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) rsParsDestruct(pPars); return(iRet); } + if(f->f_filterData.prop.propID == PROP_CEE) { + /* in CEE case, we need to preserve the actual property name */ + if((f->f_filterData.prop.propName = + es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) { + cstrDestruct(&pCSPropName); + return(RS_RET_ERR); + } + } cstrDestruct(&pCSPropName); /* read operation */ @@ -899,10 +910,13 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) iOffset = 0; } +dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp)); if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) { f->f_filterData.prop.operation = FIOP_CONTAINS; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) { f->f_filterData.prop.operation = FIOP_ISEQUAL; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) { + f->f_filterData.prop.operation = FIOP_ISEMPTY; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) { f->f_filterData.prop.operation = FIOP_STARTSWITH; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) { @@ -915,12 +929,15 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) } rsCStrDestruct(&pCSCompOp); /* no longer needed */ - /* read compare value */ - iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); +dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); + if(f->f_filterData.prop.operation != FIOP_ISEMPTY) { + /* read compare value */ + iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } } /* skip to action part */ @@ -1062,7 +1079,6 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) * and, if so, we copy them over. rgerhards, 2005-10-18 */ if(pDfltProgNameCmp != NULL) { -RUNLOG_STR("dflt ProgNameCmp != NULL, setting opCSProgNameComp"); CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); } @@ -1102,6 +1118,11 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) iRet = pMod->mod.om.parseSelectorAct(p, &pModData, &pOMSR); dbgprintf("tried selector action for %s: %d\n", module.GetName(pMod), iRet); if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) { + /* advance our config parser state: we now only accept an $End as valid, + * no more action statments. + */ + if(currConfObj == eConfObjAction) + currConfObj = eConfObjActionWaitEnd; if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { /* now check if the module is compatible with select features */ if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) @@ -1251,6 +1272,136 @@ finalize_it: ENDobjQueryInterface(conf) +/* switch to a new action scope. This means that we switch the current + * mode to action, but it also means we need to clear all scope variables, + * so that we have a new environment. + * rgerhards, 2010-07-23 + */ +static inline rsRetVal +setActionScope(void) +{ + DEFiRet; + modInfo_t *pMod; + + currConfObj = eConfObjAction; + DBGPRINTF("entering action scope\n"); + CHKiRet(actionNewScope()); + + /* now tell each action to start the scope */ + pMod = NULL; + while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { + DBGPRINTF("beginning scope on module %s\n", pMod->pszName); + pMod->mod.om.newScope(); + } + +finalize_it: + RETiRet; +} + + +/* switch back from action scope. + * rgerhards, 2010-07-27 + */ +static inline rsRetVal +unsetActionScope(void) +{ + DEFiRet; + modInfo_t *pMod; + + currConfObj = eConfObjAction; + DBGPRINTF("exiting action scope\n"); + CHKiRet(actionRestoreScope()); + + /* now tell each action to restore the scope */ + pMod = NULL; + while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { + DBGPRINTF("exiting scope on module %s\n", pMod->pszName); + pMod->mod.om.restoreScope(); + } + +finalize_it: + RETiRet; +} + + +/* This method is called by our own handlers to begin a new config + * object ($Begin statement). This also implies a new scope. + * rgerhards, 2010-07-23 + */ +static rsRetVal +beginConfObj(void __attribute__((unused)) *pVal, uchar *pszName) +{ + DEFiRet; + + if(currConfObj != eConfObjGlobal) { + errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "not in global scope - can not nest $Begin"); + ABORT_FINALIZE(RS_RET_CONF_NOT_GLBL); + } + + if(!strcasecmp((char*)pszName, "action")) { + setActionScope(); + } else { + errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $Begin", pszName); + ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); + } + +finalize_it: + free(pszName); /* no longer needed */ + RETiRet; +} + + +/* This method is called to end a config scope and switch + * back to global scope. + * rgerhards, 2010-07-23 + */ +static rsRetVal +endConfObj(void __attribute__((unused)) *pVal, uchar *pszName) +{ + DEFiRet; + + if(currConfObj == eConfObjGlobal) { + errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "already in global scope - dangling $End"); + ABORT_FINALIZE(RS_RET_CONF_IN_GLBL); + } + + if(!strcasecmp((char*)pszName, "action")) { + if(currConfObj == eConfObjAction) { + errmsg.LogError(0, RS_RET_CONF_END_NO_ACT, "$End action but not action specified"); + /* this is a warning, we continue processing in that case (unscope) */ + } else if(currConfObj != eConfObjActionWaitEnd) { + errmsg.LogError(0, RS_RET_CONF_INVLD_END, "$End not for active config object - " + "nesting error?"); + ABORT_FINALIZE(RS_RET_CONF_INVLD_END); + } + currConfObj = eConfObjGlobal; + CHKiRet(unsetActionScope()); + } else { + errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $End", pszName); + ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); + } + +finalize_it: + free(pszName); /* no longer needed */ + RETiRet; +} + + +/* Reset config variables to default values. Note that + * when we are inside an scope, we simply reset this to global. + * However, $ResetConfigVariables is a global directive, and as such + * will not be honored inside a scope! + * rgerhards, 2010-07-23 + */ +static rsRetVal +resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + currConfObj = eConfObjGlobal; + bConfStrictScoping = 0; + return RS_RET_OK; +} + + /* exit our class * rgerhards, 2008-03-11 */ @@ -1291,6 +1442,11 @@ BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANG CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */ CHKiRet(objUse(rule, CORE_COMPONENT)); CHKiRet(objUse(ruleset, CORE_COMPONENT)); + + CHKiRet(regCfSysLineHdlr((uchar *)"begin", 0, eCmdHdlrGetWord, beginConfObj, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"end", 0, eCmdHdlrGetWord, endConfObj, NULL, NULL, eConfObjAlways)); + CHKiRet(regCfSysLineHdlr((uchar *)"strictscoping", 0, eCmdHdlrBinary, NULL, &bConfStrictScoping, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjAction)); ENDObjClassInit(conf) /* vi:set ai: diff --git a/runtime/conf.h b/runtime/conf.h index d85d1f82..bc09d502 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -28,6 +28,8 @@ * somewhat strange (at least its name). -- rgerhards, 2007-08-01 */ enum eDirective { DIR_TEMPLATE = 0, DIR_OUTCHANNEL = 1, DIR_ALLOWEDSENDER = 2}; +extern ecslConfObjType currConfObj; +extern int bConfStrictScoping; /* force strict scoping during config processing? */ /* interfaces */ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ @@ -38,8 +40,14 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ rsRetVal (*cfline)(uchar *line, rule_t **pfCurr); rsRetVal (*processConfFile)(uchar *pConfFile); rsRetVal (*GetNbrActActions)(int *); + /* version 4 -- 2010-07-23 rgerhards */ + /* "just" added global variables + * FYI: we reconsider repacking as a non-object, as only the core currently + * accesses this module. The current object structure complicates things without + * any real benefit. + */ ENDinterface(conf) -#define confCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */ +#define confCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */ /* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need * to support restart-type HUP -- rgerhards, 2009-07-15 */ diff --git a/runtime/ctok.c b/runtime/ctok.c index 99b0e095..19c9bd24 100644 --- a/runtime/ctok.c +++ b/runtime/ctok.c @@ -277,6 +277,9 @@ ctokGetVar(ctok_t *pThis, ctok_token_t *pToken) if(c == '$') { /* second dollar, we have a system variable */ pToken->tok = ctok_SYSVAR; CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */ + } else if(c == '!') { /* cee variable indicator */ + pToken->tok = ctok_CEEVAR; + CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */ } else { pToken->tok = ctok_MSGVAR; } diff --git a/runtime/ctok_token.h b/runtime/ctok_token.h index d36689fa..1413c699 100644 --- a/runtime/ctok_token.h +++ b/runtime/ctok_token.h @@ -54,6 +54,7 @@ typedef struct { ctok_FUNCTION = 17, ctok_THEN = 18, ctok_STRADD = 19, + ctok_CEEVAR = 20, ctok_CMP_EQ = 100, /* all compare operations must be in a row */ ctok_CMP_NEQ = 101, ctok_CMP_LT = 102, diff --git a/runtime/debug.c b/runtime/debug.c index 3f1c23bd..283dae3a 100644 --- a/runtime/debug.c +++ b/runtime/debug.c @@ -843,12 +843,15 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg) static int bWasNL = 0; char pszThrdName[64]; /* 64 is to be on the safe side, anything over 20 is bad... */ char pszWriteBuf[32*1024]; + size_t lenCopy; + size_t offsWriteBuf = 0; size_t lenWriteBuf; struct timespec t; # if _POSIX_TIMERS <= 0 struct timeval tv; # endif +#if 1 /* The bWasNL handler does not really work. It works if no thread * switching occurs during non-NL messages. Else, things are messed * up. Anyhow, it works well enough to provide useful help during @@ -859,8 +862,8 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg) */ if(ptLastThrdID != pthread_self()) { if(!bWasNL) { - if(stddbg != -1) write(stddbg, "\n", 1); - if(altdbg != -1) write(altdbg, "\n", 1); + pszWriteBuf[0] = '\n'; + offsWriteBuf = 1; bWasNL = 1; } ptLastThrdID = pthread_self(); @@ -881,25 +884,28 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg) t.tv_sec = tv.tv_sec; t.tv_nsec = tv.tv_usec * 1000; # endif - lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), + lenWriteBuf = snprintf(pszWriteBuf+offsWriteBuf, sizeof(pszWriteBuf) - offsWriteBuf, "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec); - if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf); - if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf); + offsWriteBuf += lenWriteBuf; } - lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "%s: ", pszThrdName); - // use for testing: lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "{%ld}%s: ", (long) syscall(SYS_gettid), pszThrdName); - if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf); - if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf); + lenWriteBuf = snprintf(pszWriteBuf + offsWriteBuf, sizeof(pszWriteBuf) - offsWriteBuf, "%s: ", pszThrdName); + offsWriteBuf += lenWriteBuf; /* print object name header if we have an object */ if(pszObjName != NULL) { - lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "%s: ", pszObjName); - if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf); - if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf); + lenWriteBuf = snprintf(pszWriteBuf + offsWriteBuf, sizeof(pszWriteBuf) - offsWriteBuf, "%s: ", pszObjName); + offsWriteBuf += lenWriteBuf; } } - if(stddbg != -1) write(stddbg, pszMsg, lenMsg); - if(altdbg != -1) write(altdbg, pszMsg, lenMsg); +#endif + if(lenMsg > sizeof(pszWriteBuf) - offsWriteBuf) + lenCopy = sizeof(pszWriteBuf) - offsWriteBuf; + else + lenCopy = lenMsg; + memcpy(pszWriteBuf + offsWriteBuf, pszMsg, lenCopy); + offsWriteBuf += lenCopy; + if(stddbg != -1) write(stddbg, pszWriteBuf, offsWriteBuf); + if(altdbg != -1) write(altdbg, pszWriteBuf, offsWriteBuf); bWasNL = (pszMsg[lenMsg - 1] == '\n') ? 1 : 0; } @@ -923,12 +929,12 @@ dbgprint(obj_t *pObj, char *pszMsg, size_t lenMsg) pszObjName = obj.GetName(pObj); } - pthread_mutex_lock(&mutdbgprint); - pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint); +// pthread_mutex_lock(&mutdbgprint); +// pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint); do_dbgprint(pszObjName, pszMsg, lenMsg); - pthread_cleanup_pop(1); +// pthread_cleanup_pop(1); } #pragma GCC diagnostic warning "-Wempty-body" diff --git a/runtime/expr.c b/runtime/expr.c index e449d1c7..01431474 100644 --- a/runtime/expr.c +++ b/runtime/expr.c @@ -151,6 +151,11 @@ terminal(expr_t *pThis, ctok_t *tok) CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHMSGVAR, pVar)); /* add to program */ break; + case ctok_CEEVAR: + dbgoprint((obj_t*) pThis, "SYSVAR\n"); + CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); + CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCEEVAR, pVar)); /* add to program */ + break; case ctok_SYSVAR: dbgoprint((obj_t*) pThis, "SYSVAR\n"); CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); diff --git a/runtime/glbl.c b/runtime/glbl.c index 68eb276c..0114b1ac 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -391,16 +391,16 @@ BEGINAbstractObjClassInit(glbl, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); /* register config handlers (TODO: we need to implement a way to unregister them) */ - CHKiRet(regCfSysLineHdlr((uchar *)"workdirectory", 0, eCmdHdlrGetWord, setWorkDir, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"dropmsgswithmaliciousdnsptrrecords", 0, eCmdHdlrBinary, NULL, &bDropMalPTRMsgs, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriver", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvr, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercafile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCAF, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriverkeyfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrKeyFile, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercertfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCertFile, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"localhostname", 0, eCmdHdlrGetWord, NULL, &LocalHostNameOverride, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"optimizeforuniprocessor", 0, eCmdHdlrBinary, NULL, &bOptimizeUniProc, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"preservefqdn", 0, eCmdHdlrBinary, NULL, &bPreserveFQDN, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"workdirectory", 0, eCmdHdlrGetWord, setWorkDir, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"dropmsgswithmaliciousdnsptrrecords", 0, eCmdHdlrBinary, NULL, &bDropMalPTRMsgs, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriver", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvr, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercafile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCAF, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriverkeyfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrKeyFile, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercertfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCertFile, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"localhostname", 0, eCmdHdlrGetWord, NULL, &LocalHostNameOverride, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"optimizeforuniprocessor", 0, eCmdHdlrBinary, NULL, &bOptimizeUniProc, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"preservefqdn", 0, eCmdHdlrBinary, NULL, &bPreserveFQDN, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjGlobal)); INIT_ATOMIC_HELPER_MUT(mutTerminateInputs); ENDObjClassInit(glbl) diff --git a/runtime/glbl.h b/runtime/glbl.h index 4b4bdf83..82bd1a7a 100644 --- a/runtime/glbl.h +++ b/runtime/glbl.h @@ -76,7 +76,7 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */ */ SIMP_PROP(FdSetSize, int) /* v7: was neeeded to mean v5+v6 - do NOT add anything else for that version! */ - /* next change is v8! */ + /* next is v8! */ #undef SIMP_PROP ENDinterface(glbl) #define glblCURR_IF_VERSION 7 /* increment whenever you change the interface structure! */ diff --git a/runtime/module-template.h b/runtime/module-template.h index c2585e67..2b0ed593 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -35,7 +35,7 @@ /* macro to define standard output-module static data members */ #define DEF_MOD_STATIC_DATA \ - static __attribute__((unused)) rsRetVal (*omsdRegCFSLineHdlr)(); + static __attribute__((unused)) rsRetVal (*omsdRegCFSLineHdlr)(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie, ecslConfObjType eConfObjType); #define DEF_OMOD_STATIC_DATA \ DEF_MOD_STATIC_DATA \ @@ -316,6 +316,50 @@ static rsRetVal tryResume(instanceData __attribute__((unused)) *pData)\ } +/* Config scoping system. + * save current config scope and start a new one. Note that we do NOT implement a + * stack. Exactly one scope can be saved. + * We assume standard naming conventions (local confgSettings_t holds all + * config settings and MUST have been defined before this macro is being used!). + * Note that initConfVars() must be defined locally as well. + */ +#define SCOPING_SUPPORT \ +static rsRetVal initConfVars(void);\ +static configSettings_t cs; /* our current config settings */ \ +static configSettings_t cs_save; /* our saved (scope!) config settings */ \ +static rsRetVal newScope(void) \ +{ \ + DEFiRet; \ + memcpy(&cs_save, &cs, sizeof(cs)); \ + iRet = initConfVars(); \ + RETiRet; \ +} \ +static rsRetVal restoreScope(void) \ +{ \ + DEFiRet; \ + memcpy(&cs, &cs_save, sizeof(cs)); \ + RETiRet; \ +} +/* initConfVars() + * This entry point is called to check if a module can resume operations. This + * happens when a module requested that it be suspended. In suspended state, + * the engine periodically tries to resume the module. If that succeeds, normal + * processing continues. If not, the module will not be called unless a + * tryResume() call succeeds. + * Returns RS_RET_OK, if resumption succeeded, RS_RET_SUSPENDED otherwise + * rgerhard, 2007-08-02 + */ +#define BEGINinitConfVars \ +static rsRetVal initConfVars(void)\ +{\ + DEFiRet; + +#define CODESTARTinitConfVars + +#define ENDinitConfVars \ + RETiRet;\ +} + /* queryEtryPt() */ @@ -370,6 +414,10 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ *pEtryPoint = freeInstance;\ } else if(!strcmp((char*) name, "parseSelectorAct")) {\ *pEtryPoint = parseSelectorAct;\ + } else if(!strcmp((char*) name, "newScope")) {\ + *pEtryPoint = newScope;\ + } else if(!strcmp((char*) name, "restoreScope")) {\ + *pEtryPoint = restoreScope;\ } else if(!strcmp((char*) name, "isCompatibleWithFeature")) {\ *pEtryPoint = isCompatibleWithFeature;\ } else if(!strcmp((char*) name, "tryResume")) {\ @@ -485,6 +533,10 @@ rsRetVal modInit##uniqName(int iIFVersRequested __attribute__((unused)), int *ip /* now get the obj interface so that we can access other objects */ \ CHKiRet(pObjGetObjInterface(&obj)); +/* do those initializations necessary for scoping */ +#define SCOPINGmodInit \ + initConfVars(); + #define ENDmodInit \ finalize_it:\ *pQueryEtryPt = queryEtryPt;\ diff --git a/runtime/modules.c b/runtime/modules.c index 4541bddf..8ede134b 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -355,8 +355,7 @@ static modInfo_t *GetNxt(modInfo_t *pThis) /* this function is like GetNxt(), but it returns pointers to - * modules of specific type only. As we currently deal just with output modules, - * it is a dummy, to be filled with real code later. + * modules of specific type only. * rgerhards, 2007-07-24 */ static modInfo_t *GetNxtType(modInfo_t *pThis, eModType_t rqtdType) @@ -470,6 +469,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"doAction", &pNew->mod.om.doAction)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parseSelectorAct", &pNew->mod.om.parseSelectorAct)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"tryResume", &pNew->tryResume)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"newScope", &pNew->mod.om.newScope)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"restoreScope", &pNew->mod.om.restoreScope)); /* try load optional interfaces */ localRet = (*pNew->modQueryEtryPt)((uchar*)"doHUP", &pNew->doHUP); if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) @@ -623,6 +624,8 @@ static void modPrintList(void) dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct); dbgprintf("\ttryResume: 0x%lx\n", (unsigned long) pMod->tryResume); dbgprintf("\tdoHUP: 0x%lx\n", (unsigned long) pMod->doHUP); + dbgprintf("\tnewScope: 0x%lx\n", (unsigned long) pMod->mod.om.newScope); + dbgprintf("\trestoreScope: 0x%lx\n", (unsigned long) pMod->mod.om.restoreScope); dbgprintf("\tBeginTransaction: 0x%lx\n", (unsigned long) ((pMod->mod.om.beginTransaction == dummyBeginTransaction) ? 0 : pMod->mod.om.beginTransaction)); diff --git a/runtime/modules.h b/runtime/modules.h index 4daaf1f9..c1c38a26 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -47,8 +47,10 @@ * version 5 changes the way parsing works for input modules. This is * an important change, parseAndSubmitMessage() goes away. Other * module types are not affected. -- rgerhards, 2008-10-09 + * version 6 introduces scoping support (starting with the output + * modules) -- rgerhards, 2010-07-27 */ -#define CURR_MOD_IF_VERSION 5 +#define CURR_MOD_IF_VERSION 6 typedef enum eModType_ { eMOD_IN = 0, /* input module */ @@ -131,6 +133,8 @@ struct modInfo_s { rsRetVal (*doAction)(uchar**, unsigned, void*); rsRetVal (*endTransaction)(void*); rsRetVal (*parseSelectorAct)(uchar**, void**,omodStringRequest_t**); + rsRetVal (*newScope)(void); + rsRetVal (*restoreScope)(void); } om; struct { /* data for library modules */ char dummy; diff --git a/runtime/msg.c b/runtime/msg.c index b0261faa..ec132489 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -37,6 +37,7 @@ #include <ctype.h> #include <sys/socket.h> #include <netdb.h> +#include <libee/libee.h> #if HAVE_MALLOC_H # include <malloc.h> #endif @@ -444,6 +445,10 @@ rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID) *pPropID = PROP_SYS_MINUTE; } else if(!strcmp((char*) pName, "$myhostname")) { *pPropID = PROP_SYS_MYHOSTNAME; + } else if(!strcmp((char*) pName, "$!all-json")) { + *pPropID = PROP_CEE_ALL_JSON; + } else if(!strncmp((char*) pName, "$!", 2)) { + *pPropID = PROP_CEE; } else { *pPropID = PROP_INVALID; iRet = RS_RET_VAR_NOT_FOUND; @@ -525,6 +530,10 @@ uchar *propIDToName(propid_t propID) return UCHAR_CONSTANT("$MINUTE"); case PROP_SYS_MYHOSTNAME: return UCHAR_CONSTANT("$MYHOSTNAME"); + case PROP_CEE: + return UCHAR_CONSTANT("*CEE-based property*"); + case PROP_CEE_ALL_JSON: + return UCHAR_CONSTANT("$!all-json"); default: return UCHAR_CONSTANT("*invalid property id*"); } @@ -708,6 +717,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis) pM->pRcvFromIP = NULL; pM->rcvFrom.pRcvFrom = NULL; pM->pRuleset = NULL; + pM->event = NULL; memset(&pM->tRcvdAt, 0, sizeof(pM->tRcvdAt)); memset(&pM->tTIMESTAMP, 0, sizeof(pM->tTIMESTAMP)); pM->TAG.pszTAG = NULL; @@ -843,6 +853,8 @@ CODESTARTobjDestruct(msg) rsCStrDestruct(&pThis->pCSPROCID); if(pThis->pCSMSGID != NULL) rsCStrDestruct(&pThis->pCSMSGID); + if(pThis->event != NULL) + ee_deleteEvent(pThis->event); # ifndef HAVE_ATOMIC_BUILTINS MsgUnlock(pThis); # endif @@ -1209,7 +1221,7 @@ char *getProtocolVersionString(msg_t *pM) } -static inline void +void getRawMsg(msg_t *pM, uchar **pBuf, int *piLen) { if(pM == NULL) { @@ -2230,6 +2242,41 @@ static uchar *getNOW(eNOWType eNow) #undef tmpBUFSIZE /* clean up */ +/* Get a CEE-Property from libee. This function probably should be + * placed somewhere else, but this smells like a big restructuring + * useful in any case. So for the time being, I'll simply leave the + * function here, as the context seems good enough. -- rgerhards, 2010-12-01 + */ +static inline void +getCEEPropVal(msg_t *pMsg, es_str_t *propName, uchar **pRes, int *buflen, unsigned short *pbMustBeFreed) +{ + struct ee_field *field; + es_str_t *str; + + if(*pbMustBeFreed) + free(*pRes); + *pRes = NULL; + + if(pMsg->event == NULL) goto finalize_it; + if((field = ee_getEventField(pMsg->event, propName)) == NULL) + goto finalize_it; + /* right now, we always extract data from the first field value. A reason for this + * is that as of now (2010-12-01) liblognorm never populates more than one ;) + */ + if((str = ee_getFieldValueAsStr(field, 0)) == NULL) goto finalize_it; + *pRes = (unsigned char*) es_str2cstr(str, "#000"); + es_deleteStr(str); + *buflen = (int) ustrlen(*pRes); + *pbMustBeFreed = 1; + +finalize_it: + if(*pRes == NULL) { + /* could not find any value, so set it to empty */ + *pRes = (unsigned char*)""; + *pbMustBeFreed = 0; + } +} + /* This function returns a string-representation of the * requested message property. This is a generic function used * to abstract properties so that these can be easier @@ -2272,7 +2319,7 @@ static uchar *getNOW(eNOWType eNow) *pPropLen = sizeof("**OUT OF MEMORY**") - 1; \ return(UCHAR_CONSTANT("**OUT OF MEMORY**"));} uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, - propid_t propID, size_t *pPropLen, + propid_t propid, es_str_t *propName, size_t *pPropLen, unsigned short *pbMustBeFreed) { uchar *pRes; /* result pointer */ @@ -2281,6 +2328,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, uchar *pBuf; int iLen; short iOffs; + es_str_t *str; /* for CEE handling, temp. string */ BEGINfunc assert(pMsg != NULL); @@ -2294,7 +2342,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, *pbMustBeFreed = 0; - switch(propID) { + switch(propid) { case PROP_MSG: pRes = getMSG(pMsg); bufLen = getMSGLen(pMsg); @@ -2427,11 +2475,20 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, case PROP_SYS_MYHOSTNAME: pRes = glbl.GetLocalHostName(); break; + case PROP_CEE_ALL_JSON: + ee_fmtEventToJSON(pMsg->event, &str); + pRes = (uchar*) es_str2cstr(str, "#000"); + es_deleteStr(str); + *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */ + break; + case PROP_CEE: + getCEEPropVal(pMsg, propName, &pRes, &bufLen, pbMustBeFreed); + break; default: /* there is no point in continuing, we may even otherwise render the * error message unreadable. rgerhards, 2007-07-10 */ - dbgprintf("invalid property id: '%d'\n", propID); + dbgprintf("invalid property id: '%d'\n", propid); *pbMustBeFreed = 0; *pPropLen = sizeof("**INVALID PROPERTY NAME**") - 1; return UCHAR_CONSTANT("**INVALID PROPERTY NAME**"); @@ -2439,6 +2496,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, /* If we did not receive a template pointer, we are already done... */ if(pTpe == NULL) { + *pPropLen = (bufLen == -1) ? ustrlen(pRes) : bufLen; return pRes; } @@ -3025,6 +3083,61 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, } +/* The function returns a cee variable suitable for use with RainerScript. Most importantly, this means + * that the value is returned in a var_t object. The var_t is constructed inside this function and + * MUST be freed by the caller. + * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once + * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend + * to rewrite the script engine as well! + * rgerhards, 2010-12-03 + */ +rsRetVal +msgGetCEEVar(msg_t *pMsg, cstr_t *propName, var_t **ppVar) +{ + DEFiRet; + var_t *pVar; + cstr_t *pstrProp; + es_str_t *str = NULL; + es_str_t *epropName = NULL; + struct ee_field *field; + + ISOBJ_TYPE_assert(pMsg, msg); + ASSERT(propName != NULL); + ASSERT(ppVar != NULL); + + /* make sure we have a var_t instance */ + CHKiRet(var.Construct(&pVar)); + CHKiRet(var.ConstructFinalize(pVar)); + + epropName = es_newStrFromBuf((char*)propName->pBuf, propName->iStrLen); + if((field = ee_getEventField(pMsg->event, epropName)) != NULL) { + /* right now, we always extract data from the first field value. A reason for this + * is that as of now (2010-12-01) liblognorm never populates more than one ;) + */ + str = ee_getFieldValueAsStr(field, 0); + } + + if(str == NULL) { + CHKiRet(cstrConstruct(&pstrProp)); + CHKiRet(cstrFinalize(pstrProp)); + } else { + CHKiRet(cstrConstructFromESStr(&pstrProp, str)); + } + + /* now create a string object out of it and hand that over to the var */ + CHKiRet(var.SetString(pVar, pstrProp)); + es_deleteStr(str); + + /* finally store var */ + *ppVar = pVar; + +finalize_it: + if(epropName != NULL) + es_deleteStr(epropName); + RETiRet; +} + + /* The returns a message variable suitable for use with RainerScript. Most importantly, this means * that the value is returned in a var_t object. The var_t is constructed inside this function and * MUST be freed by the caller. @@ -3052,7 +3165,7 @@ msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar) /* always call MsgGetProp() without a template specifier */ /* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */ propNameToID(pstrPropName, &propid); - pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, &propLen, &bMustBeFreed); + pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed); /* now create a string object out of it and hand that over to the var */ CHKiRet(rsCStrConstructFromszStr(&pstrProp, pszProp)); @@ -3067,6 +3180,8 @@ finalize_it: 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 diff --git a/runtime/msg.h b/runtime/msg.h index 26a07aca..01a1e059 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -29,10 +29,12 @@ #define MSG_H_INCLUDED 1 #include <pthread.h> +#include <libestr.h> #include "obj.h" #include "syslogd-types.h" #include "template.h" #include "atomic.h" +#include "libee/libee.h" /* rgerhards 2004-11-08: The following structure represents a @@ -106,6 +108,7 @@ struct msg { it obviously is solved in way or another...). */ struct syslogTime tRcvdAt;/* time the message entered this program */ struct syslogTime tTIMESTAMP;/* (parsed) value of the timestamp */ + struct ee_event *event; /**< libee event */ /* some fixed-size buffers to save malloc()/free() for frequently used fields (from the default templates) */ uchar szRawMsg[CONF_RAWMSG_BUFSIZE]; /* most messages are small, and these are stored here (without malloc/free!) */ uchar szHOSTNAME[CONF_HOSTNAME_BUFSIZE]; @@ -163,7 +166,8 @@ void MsgSetRawMsgWOSize(msg_t *pMsg, char* pszRawMsg); void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg, size_t lenMsg); rsRetVal MsgReplaceMSG(msg_t *pThis, uchar* pszMSG, int lenMSG); uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, - propid_t propID, size_t *pPropLen, unsigned short *pbMustBeFreed); + propid_t propid, es_str_t *propName, + size_t *pPropLen, unsigned short *pbMustBeFreed); char *textpri(char *pRes, size_t pResLen, int pri); rsRetVal msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar); rsRetVal MsgEnableThreadSafety(void); @@ -171,6 +175,8 @@ uchar *getRcvFrom(msg_t *pM); void getTAG(msg_t *pM, uchar **ppBuf, int *piLen); char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt); char *getPRI(msg_t *pMsg); +void getRawMsg(msg_t *pM, uchar **pBuf, int *piLen); +rsRetVal msgGetCEEVar(msg_t *pThis, cstr_t *propName, var_t **ppVar); /* TODO: remove these five (so far used in action.c) */ diff --git a/runtime/netstrm.c b/runtime/netstrm.c index 3658006f..a6f840a5 100644 --- a/runtime/netstrm.c +++ b/runtime/netstrm.c @@ -64,6 +64,7 @@ ENDobjConstruct(netstrm) /* destructor for the netstrm object */ BEGINobjDestruct(netstrm) /* be sure to specify the object type also in END and CODESTART macros! */ CODESTARTobjDestruct(netstrm) +//printf("destruct driver data %p\n", pThis->pDrvrData); if(pThis->pDrvrData != NULL) iRet = pThis->Drvr.Destruct(&pThis->pDrvrData); ENDobjDestruct(netstrm) @@ -169,6 +170,7 @@ Rcv(netstrm_t *pThis, uchar *pBuf, ssize_t *pLenBuf) { DEFiRet; ISOBJ_TYPE_assert(pThis, netstrm); +//printf("Rcv %p\n", pThis); iRet = pThis->Drvr.Rcv(pThis->pDrvrData, pBuf, pLenBuf); RETiRet; } diff --git a/runtime/netstrms.c b/runtime/netstrms.c index ea2dd9f3..0122064d 100644 --- a/runtime/netstrms.c +++ b/runtime/netstrms.c @@ -32,7 +32,6 @@ #include "rsyslog.h" #include "module-template.h" #include "obj.h" -//#include "errmsg.h" #include "nsd.h" #include "netstrm.h" #include "nssel.h" diff --git a/runtime/nsd.h b/runtime/nsd.h index e5b9320b..5a3f462e 100644 --- a/runtime/nsd.h +++ b/runtime/nsd.h @@ -29,6 +29,16 @@ #include <sys/socket.h> +/** + * The following structure is a set of descriptors that need to be processed. + * This set will be the result of the epoll call and be used + * in the actual request processing stage. -- rgerhards, 2011-01-24 + */ +struct nsd_epworkset_s { + int id; + void *pUsr; +}; + enum nsdsel_waitOp_e { NSDSEL_RD = 1, NSDSEL_WR = 2, @@ -92,7 +102,7 @@ BEGINinterface(nsdpoll) /* name must also be changed in ENDinterface macro! */ rsRetVal (*Construct)(nsdpoll_t **ppThis); rsRetVal (*Destruct)(nsdpoll_t **ppThis); rsRetVal (*Ctl)(nsdpoll_t *pNsdpoll, nsd_t *pNsd, int id, void *pUsr, int mode, int op); - rsRetVal (*Wait)(nsdpoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr); + rsRetVal (*Wait)(nsdpoll_t *pNsdpoll, int timeout, int *numReady, nsd_epworkset_t workset[]); ENDinterface(nsdpoll) #define nsdpollCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c index 152dc8de..d0fd0e0f 100644 --- a/runtime/nsd_gtls.c +++ b/runtime/nsd_gtls.c @@ -50,7 +50,6 @@ #include "nsd_gtls.h" /* things to move to some better place/functionality - TODO */ -#define DH_BITS 1024 #define CRLFILE "crl.pem" @@ -82,7 +81,6 @@ static pthread_mutex_t mutGtlsStrerror; /**< a mutex protecting the potentially /* ------------------------------ GnuTLS specifics ------------------------------ */ static gnutls_certificate_credentials xcred; -static gnutls_dh_params dh_params; #ifdef DEBUG #if 0 /* uncomment, if needed some time again -- DEV Debug only */ @@ -610,7 +608,6 @@ gtlsInitSession(nsd_gtls_t *pThis) /* request client certificate if any. */ gnutls_certificate_server_set_request( session, GNUTLS_CERT_REQUEST); - gnutls_dh_set_prime_bits(session, DH_BITS); pThis->sess = session; @@ -619,23 +616,6 @@ finalize_it: } -static rsRetVal -generate_dh_params(void) -{ - int gnuRet; - DEFiRet; - /* Generate Diffie Hellman parameters - for use with DHE - * kx algorithms. These should be discarded and regenerated - * once a day, once a week or once a month. Depending on the - * security requirements. - */ - CHKgnutls(gnutls_dh_params_init( &dh_params)); - CHKgnutls(gnutls_dh_params_generate2( dh_params, DH_BITS)); -finalize_it: - RETiRet; -} - - /* set up all global things that are needed for server operations * rgerhards, 2008-04-30 */ @@ -649,8 +629,6 @@ gtlsGlblInitLstn(void) * considered legacy. -- rgerhards, 2008-05-05 */ /*CHKgnutls(gnutls_certificate_set_x509_crl_file(xcred, CRLFILE, GNUTLS_X509_FMT_PEM));*/ - CHKiRet(generate_dh_params()); - gnutls_certificate_set_dh_params(xcred, dh_params); /* this is void */ bGlblSrvrInitDone = 1; /* we are all set now */ /* now we need to add our certificate */ @@ -1174,6 +1152,8 @@ CODESTARTobjDestruct(nsd_gtls) gnutls_x509_crt_deinit(pThis->ourCert); if(pThis->bOurKeyIsInit) gnutls_x509_privkey_deinit(pThis->ourKey); +#warning need more checks if the new gnutls_deinit() breaks things during normal operations +// gnutls_deinit(pThis->sess); /* see ln 600 pThis->bInSess as something to check? */ ENDobjDestruct(nsd_gtls) @@ -1419,6 +1399,10 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew) /* we got a handshake, now check authorization */ CHKiRet(gtlsChkPeerAuth(pNew)); } else { + uchar *pGnuErr = gtlsStrerror(gnuRet); + errmsg.LogError(0, RS_RET_TLS_HANDSHAKE_ERR, + "gnutls returned error on handshake: %s\n", pGnuErr); + free(pGnuErr); ABORT_FINALIZE(RS_RET_TLS_HANDSHAKE_ERR); } diff --git a/runtime/nsdpoll_ptcp.c b/runtime/nsdpoll_ptcp.c index ef9c37a3..78203292 100644 --- a/runtime/nsdpoll_ptcp.c +++ b/runtime/nsdpoll_ptcp.c @@ -71,13 +71,16 @@ addEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, int mode, nsd_ptcp_t *pSock, pNew->pUsr = pUsr; pNew->pSock = pSock; pNew->event.events = 0; /* TODO: at some time we should be able to use EPOLLET */ + //pNew->event.events = EPOLLET; if(mode & NSDPOLL_IN) pNew->event.events |= EPOLLIN; if(mode & NSDPOLL_OUT) pNew->event.events |= EPOLLOUT; pNew->event.data.u64 = (uint64) pNew; + pthread_mutex_lock(&pThis->mutEvtLst); pNew->pNext = pThis->pRoot; pThis->pRoot = pNew; + pthread_mutex_unlock(&pThis->mutEvtLst); *pEvtLst = pNew; finalize_it: @@ -94,6 +97,7 @@ unlinkEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, nsdpoll_epollevt_lst_t ** nsdpoll_epollevt_lst_t *pPrev = NULL; DEFiRet; + pthread_mutex_lock(&pThis->mutEvtLst); pEvtLst = pThis->pRoot; while(pEvtLst != NULL && !(pEvtLst->id == id && pEvtLst->pUsr == pUsr)) { pPrev = pEvtLst; @@ -111,6 +115,7 @@ unlinkEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, nsdpoll_epollevt_lst_t ** pPrev->pNext = pEvtLst->pNext; finalize_it: + pthread_mutex_unlock(&pThis->mutEvtLst); RETiRet; } @@ -147,6 +152,7 @@ BEGINobjConstruct(nsdpoll_ptcp) /* be sure to specify the object type also in EN DBGPRINTF("epoll_create1() could not create fd\n"); ABORT_FINALIZE(RS_RET_IO_ERROR); } + pthread_mutex_init(&pThis->mutEvtLst, NULL); finalize_it: ENDobjConstruct(nsdpoll_ptcp) @@ -154,6 +160,9 @@ ENDobjConstruct(nsdpoll_ptcp) /* destructor for the nsdpoll_ptcp object */ BEGINobjDestruct(nsdpoll_ptcp) /* be sure to specify the object type also in END and CODESTART macros! */ CODESTARTobjDestruct(nsdpoll_ptcp) + //printf("ndspoll_ptcp destruct, event list root is %p\n", pThis->pRoot); +#warning cleanup event list is missing! (at least I think so) + pthread_mutex_destroy(&pThis->mutEvtLst); ENDobjDestruct(nsdpoll_ptcp) @@ -202,23 +211,25 @@ finalize_it: /* Wait for io to become ready. After the successful call, idRdy contains the * id set by the caller for that i/o event, ppUsr is a pointer to a location * where the user pointer shall be stored. - * TODO: this is a trivial implementation that only polls one event at a time. We - * may later extend it to poll for multiple events, what would cause less - * overhead. + * numEntries contains the maximum number of entries on entry and the actual + * number of entries actually read on exit. * rgerhards, 2009-11-18 */ static rsRetVal -Wait(nsdpoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr) { +Wait(nsdpoll_t *pNsdpoll, int timeout, int *numEntries, nsd_epworkset_t workset[]) { nsdpoll_ptcp_t *pThis = (nsdpoll_ptcp_t*) pNsdpoll; nsdpoll_epollevt_lst_t *pOurEvt; - struct epoll_event event; + struct epoll_event event[128]; int nfds; + int i; DEFiRet; - assert(idRdy != NULL); - assert(ppUsr != NULL); + assert(workset != NULL); - nfds = epoll_wait(pThis->efd, &event, 1, timeout); + if(*numEntries > 128) + *numEntries = 128; + DBGPRINTF("doing epoll_wait for max %d events\n", *numEntries); + nfds = epoll_wait(pThis->efd, event, *numEntries, timeout); if(nfds == -1) { if(errno == EINTR) { ABORT_FINALIZE(RS_RET_EINTR); @@ -230,10 +241,15 @@ Wait(nsdpoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr) { ABORT_FINALIZE(RS_RET_TIMEOUT); } - /* we got a valid event, so tell the caller... */ - pOurEvt = (nsdpoll_epollevt_lst_t*) event.data.u64; - *idRdy = pOurEvt->id; - *ppUsr = pOurEvt->pUsr; + /* we got valid events, so tell the caller... */ +dbgprintf("epoll returned %d entries\n", nfds); + for(i = 0 ; i < nfds ; ++i) { + pOurEvt = (nsdpoll_epollevt_lst_t*) event[i].data.u64; + workset[i].id = pOurEvt->id; + workset[i].pUsr = pOurEvt->pUsr; +dbgprintf("epoll push ppusr[%d]: %p\n", i, pOurEvt->pUsr); + } + *numEntries = nfds; finalize_it: RETiRet; diff --git a/runtime/nsdpoll_ptcp.h b/runtime/nsdpoll_ptcp.h index cea2823d..dfefad1b 100644 --- a/runtime/nsdpoll_ptcp.h +++ b/runtime/nsdpoll_ptcp.h @@ -49,6 +49,7 @@ struct nsdpoll_ptcp_s { BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ int efd; /* file descriptor used by epoll */ nsdpoll_epollevt_lst_t *pRoot; /* Root of the epoll event list */ + pthread_mutex_t mutEvtLst; }; /* interface is defined in nsd.h, we just implement it! */ diff --git a/runtime/nspoll.c b/runtime/nspoll.c index 64927280..a936b255 100644 --- a/runtime/nspoll.c +++ b/runtime/nspoll.c @@ -129,11 +129,11 @@ finalize_it: /* Carries out the actual wait (all done in lower layers) */ static rsRetVal -Wait(nspoll_t *pThis, int timeout, int *idRdy, void **ppUsr) { +Wait(nspoll_t *pThis, int timeout, int *numEntries, nsd_epworkset_t workset[]) { DEFiRet; ISOBJ_TYPE_assert(pThis, nspoll); - assert(idRdy != NULL); - iRet = pThis->Drvr.Wait(pThis->pDrvrData, timeout, idRdy, ppUsr); + assert(workset != NULL); + iRet = pThis->Drvr.Wait(pThis->pDrvrData, timeout, numEntries, workset); RETiRet; } diff --git a/runtime/nspoll.h b/runtime/nspoll.h index a77759c0..037f6c38 100644 --- a/runtime/nspoll.h +++ b/runtime/nspoll.h @@ -50,11 +50,12 @@ BEGINinterface(nspoll) /* name must also be changed in ENDinterface macro! */ rsRetVal (*Construct)(nspoll_t **ppThis); rsRetVal (*ConstructFinalize)(nspoll_t *pThis); rsRetVal (*Destruct)(nspoll_t **ppThis); - rsRetVal (*Wait)(nspoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr); + rsRetVal (*Wait)(nspoll_t *pNsdpoll, int timeout, int *numEntries, nsd_epworkset_t workset[]); rsRetVal (*Ctl)(nspoll_t *pNsdpoll, netstrm_t *pStrm, int id, void *pUsr, int mode, int op); rsRetVal (*IsEPollSupported)(void); /* static method */ ENDinterface(nspoll) -#define nspollCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ +#define nspollCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ +/* interface change in v2 is that wait supports multiple return objects */ /* prototypes */ PROTOTYPEObj(nspoll); diff --git a/runtime/parser.c b/runtime/parser.c index d3644976..8776a25e 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -695,12 +695,12 @@ BEGINObjClassInit(parser, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(ruleset, CORE_COMPONENT)); - CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, NULL, &bDropTrailingLF, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"escape8bitcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscape8BitChars, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactertab", 0, eCmdHdlrBinary, NULL, &bEscapeTab, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, NULL, &bDropTrailingLF, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"escape8bitcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscape8BitChars, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactertab", 0, eCmdHdlrBinary, NULL, &bEscapeTab, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjGlobal)); InitParserList(&pParsLstRoot); InitParserList(&pDfltParsLst); diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 78e61bcb..9d3d0289 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -137,6 +137,8 @@ typedef uintTiny propid_t; #define PROP_SYS_QHOUR 156 #define PROP_SYS_MINUTE 157 #define PROP_SYS_MYHOSTNAME 158 +#define PROP_CEE 200 +#define PROP_CEE_ALL_JSON 201 /* The error codes below are orginally "borrowed" from @@ -331,6 +333,11 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_TIMEOUT = -2164, /**< timeout occured during operation */ RS_RET_RCV_ERR = -2165, /**< error occured during socket rcv operation */ RS_RET_NO_SOCK_CONFIGURED = -2166, /**< no socket (name) was configured where one is required */ + RS_RET_CONF_NOT_GLBL = -2167, /**< $Begin not in global scope */ + RS_RET_CONF_IN_GLBL = -2168, /**< $End when in global scope */ + RS_RET_CONF_INVLD_END = -2169, /**< $End for wrong conf object (probably nesting error) */ + RS_RET_CONF_INVLD_SCOPE = -2170,/**< config statement not valid in current scope (e.g. global stmt in action block) */ + RS_RET_CONF_END_NO_ACT = -2171, /**< end of action block, but no actual action specified */ RS_RET_NO_LSTN_DEFINED = -2172, /**< no listener defined (e.g. inside an input module) */ RS_RET_EPOLL_CR_FAILED = -2173, /**< epoll_create() failed */ RS_RET_EPOLL_CTL_FAILED = -2174, /**< epoll_ctl() failed */ @@ -342,6 +349,11 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_FILE_NOT_SPECIFIED = -2180, /**< file name not configured where this was required */ RS_RET_ERR_WRKDIR = -2181, /**< problems with the rsyslog working directory */ + RS_RET_INVLD_CONF_OBJ= -2200, /**< invalid config object (e.g. $Begin conf statement) */ + RS_RET_ERR_LIBEE_INIT = -2201, /**< cannot obtain libee ctx */ + RS_RET_ERR_LIBLOGNORM_INIT = -2202,/**< cannot obtain liblognorm ctx */ + RS_RET_ERR_LIBLOGNORM_SAMPDB_LOAD = -2203,/**< liblognorm sampledb load failed */ + /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ @@ -466,6 +478,13 @@ rsRetVal rsrtExit(void); int rsrtIsInit(void); rsRetVal rsrtSetErrLogger(rsRetVal (*errLogger)(int, uchar*)); +/* this define below is (later) intended to be used to implement empty + * structs. TODO: check if compilers supports this and, if not, define + * a dummy variable. This requires review of where in code empty structs + * are already defined. -- rgerhards, 2010-07-26 + */ +#define EMPTY_STRUCT + #endif /* multi-include protection */ /* vim:set ai: */ diff --git a/runtime/rule.c b/runtime/rule.c index 42773768..fc1ee17c 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -70,6 +70,12 @@ getFIOPName(unsigned iFIOP) case FIOP_REGEX: pRet = "regex"; break; + case FIOP_EREREGEX: + pRet = "ereregex"; + break; + case FIOP_ISEMPTY: + pRet = "isempty"; + break; default: pRet = "NOP"; break; @@ -190,7 +196,8 @@ dbgprintf("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFac bRet = (pResult->val.num) ? 1 : 0; } else { assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */ - pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, &propLen, &pbMustBeFreed); + pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, + pRule->f_filterData.prop.propName, &propLen, &pbMustBeFreed); /* Now do the compares (short list currently ;)) */ switch(pRule->f_filterData.prop.operation ) { @@ -198,6 +205,10 @@ dbgprintf("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFac if(rsCStrLocateInSzStr(pRule->f_filterData.prop.pCSCompValue, (uchar*) pszPropVal) != -1) bRet = 1; break; + case FIOP_ISEMPTY: + if(propLen == 0) + bRet = 1; /* process message! */ + break; case FIOP_ISEQUAL: if(rsCStrSzStrCmp(pRule->f_filterData.prop.pCSCompValue, pszPropVal, ustrlen(pszPropVal)) == 0) @@ -230,14 +241,28 @@ dbgprintf("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFac bRet = (bRet == 1) ? 0 : 1; if(Debug) { - dbgprintf("Filter: check for property '%s' (value '%s') ", - propIDToName(pRule->f_filterData.prop.propID), pszPropVal); + char *cstr; + if(pRule->f_filterData.prop.propID == PROP_CEE) { + cstr = es_str2cstr(pRule->f_filterData.prop.propName, NULL); + dbgprintf("Filter: check for CEE property '%s' (value '%s') ", + cstr, pszPropVal); + free(cstr); + } else { + 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", - getFIOPName(pRule->f_filterData.prop.operation), - rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue), - bRet ? "TRUE" : "FALSE"); + if(pRule->f_filterData.prop.operation == FIOP_ISEMPTY) { + dbgprintf("%s : %s\n", + getFIOPName(pRule->f_filterData.prop.operation), + bRet ? "TRUE" : "FALSE"); + } else { + dbgprintf("%s '%s': %s\n", + getFIOPName(pRule->f_filterData.prop.operation), + rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue), + bRet ? "TRUE" : "FALSE"); + } } /* cleanup */ @@ -324,6 +349,8 @@ CODESTARTobjDestruct(rule) rsCStrDestruct(&pThis->f_filterData.prop.pCSCompValue); if(pThis->f_filterData.prop.regex_cache != NULL) rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache); + if(pThis->f_filterData.prop.propName != NULL) + es_deleteStr(pThis->f_filterData.prop.propName); } else if(pThis->f_filter_type == FILTER_EXPR) { if(pThis->f_filterData.f_expr != NULL) expr.Destruct(&pThis->f_filterData.f_expr); @@ -368,6 +395,7 @@ DEFFUNC_llExecFunc(dbgPrintInitInfoAction) /* debugprint for the rule object */ BEGINobjDebugPrint(rule) /* be sure to specify the object type also in END and CODESTART macros! */ int i; + char *cstr; CODESTARTobjDebugPrint(rule) dbgoprint((obj_t*) pThis, "rsyslog rule:\n"); if(pThis->pCSProgNameComp != NULL) @@ -388,12 +416,19 @@ CODESTARTobjDebugPrint(rule) } else { dbgprintf("PROPERTY-BASED Filter:\n"); dbgprintf("\tProperty.: '%s'\n", propIDToName(pThis->f_filterData.prop.propID)); + if(pThis->f_filterData.prop.propName != NULL) { + cstr = es_str2cstr(pThis->f_filterData.prop.propName, NULL); + dbgprintf("\tCEE-Prop.: '%s'\n", cstr); + free(cstr); + } dbgprintf("\tOperation: "); if(pThis->f_filterData.prop.isNegated) dbgprintf("NOT "); dbgprintf("'%s'\n", getFIOPName(pThis->f_filterData.prop.operation)); - dbgprintf("\tValue....: '%s'\n", - rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSCompValue)); + if(pThis->f_filterData.prop.pCSCompValue != NULL) { + dbgprintf("\tValue....: '%s'\n", + rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSCompValue)); + } dbgprintf("\tAction...: "); } diff --git a/runtime/rule.h b/runtime/rule.h index 309a2ed8..3b34e11a 100644 --- a/runtime/rule.h +++ b/runtime/rule.h @@ -25,6 +25,7 @@ #ifndef INCLUDED_RULE_H #define INCLUDED_RULE_H +#include "libestr.h" #include "linkedlist.h" #include "regexp.h" #include "expr.h" @@ -49,6 +50,7 @@ struct rule_s { cstr_t *pCSCompValue; /* value to "compare" against */ sbool isNegated; propid_t propID; /* ID of the requested property */ + es_str_t *propName; /* name of property for CEE-based filters */ } prop; expr_t *f_expr; /* expression object */ } f_filterData; diff --git a/runtime/ruleset.c b/runtime/ruleset.c index c9c64a38..f48c2c2d 100644 --- a/runtime/ruleset.c +++ b/runtime/ruleset.c @@ -628,8 +628,8 @@ BEGINObjClassInit(ruleset, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(llInit(&llRulesets, rulesetDestructForLinkedList, keyDestruct, strcasecmp)); /* config file handlers */ - CHKiRet(regCfSysLineHdlr((uchar *)"rulesetparser", 0, eCmdHdlrGetWord, rulesetAddParser, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"rulesetcreatemainqueue", 0, eCmdHdlrBinary, rulesetCreateQueue, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"rulesetparser", 0, eCmdHdlrGetWord, rulesetAddParser, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"rulesetcreatemainqueue", 0, eCmdHdlrBinary, rulesetCreateQueue, NULL, NULL, eConfObjGlobal)); ENDObjClassInit(ruleset) /* vi:set ai: diff --git a/runtime/stringbuf.c b/runtime/stringbuf.c index 2b6815a4..d8c5923b 100644 --- a/runtime/stringbuf.c +++ b/runtime/stringbuf.c @@ -35,6 +35,7 @@ #include <string.h> #include <ctype.h> #include <sys/types.h> +#include <libestr.h> #include "rsyslog.h" #include "stringbuf.h" #include "srUtils.h" @@ -104,6 +105,34 @@ finalize_it: RETiRet; } + +/* construct from es_str_t string + * rgerhards 2010-12-03 + */ +rsRetVal cstrConstructFromESStr(cstr_t **ppThis, es_str_t *str) +{ + DEFiRet; + cstr_t *pThis; + + assert(ppThis != NULL); + + CHKiRet(rsCStrConstruct(&pThis)); + + pThis->iBufSize = pThis->iStrLen = es_strlen(str); + if((pThis->pBuf = (uchar*) MALLOC(sizeof(uchar) * pThis->iStrLen)) == NULL) { + RSFREEOBJ(pThis); + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); + } + + /* we do NOT need to copy the \0! */ + memcpy(pThis->pBuf, es_getBufAddr(str), pThis->iStrLen); + + *ppThis = pThis; + +finalize_it: + RETiRet; +} + /* construct from CStr object. only the counted string is * copied, not the szString. * rgerhards 2005-10-18 diff --git a/runtime/stringbuf.h b/runtime/stringbuf.h index c5130238..df234012 100644 --- a/runtime/stringbuf.h +++ b/runtime/stringbuf.h @@ -36,6 +36,7 @@ #define _STRINGBUF_H_INCLUDED__ 1 #include <assert.h> +#include <libestr.h> /** * The dynamic string buffer object. @@ -57,6 +58,7 @@ typedef struct cstr_s */ rsRetVal cstrConstruct(cstr_t **ppThis); #define rsCStrConstruct(x) cstrConstruct((x)) +rsRetVal cstrConstructFromESStr(cstr_t **ppThis, es_str_t *str); rsRetVal rsCStrConstructFromszStr(cstr_t **ppThis, uchar *sz); rsRetVal rsCStrConstructFromCStr(cstr_t **ppThis, cstr_t *pFrom); diff --git a/runtime/typedefs.h b/runtime/typedefs.h index d3da7699..b6cfbd57 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -79,6 +79,7 @@ typedef struct parserList_s parserList_t; typedef struct strgen_s strgen_t; typedef struct strgenList_s strgenList_t; typedef struct statsobj_s statsobj_t; +typedef struct nsd_epworkset_s nsd_epworkset_t; typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */ typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerously few */ @@ -127,9 +128,41 @@ typedef enum { FIOP_ISEQUAL = 2, /* is (exactly) equal? */ FIOP_STARTSWITH = 3, /* starts with a string? */ FIOP_REGEX = 4, /* matches a (BRE) regular expression? */ - FIOP_EREREGEX = 5 /* matches a ERE regular expression? */ + FIOP_EREREGEX = 5, /* matches a ERE regular expression? */ + FIOP_ISEMPTY = 6 /* string empty <=> strlen(s) == 0 ?*/ } fiop_t; +/* types of configuration handlers + */ +typedef enum cslCmdHdlrType { + eCmdHdlrInvalid = 0, /* invalid handler type - indicates a coding error */ + eCmdHdlrCustomHandler, /* custom handler, just call handler function */ + eCmdHdlrUID, + eCmdHdlrGID, + eCmdHdlrBinary, + eCmdHdlrFileCreateMode, + eCmdHdlrInt, + eCmdHdlrSize, + eCmdHdlrGetChar, + eCmdHdlrFacility, + eCmdHdlrSeverity, + eCmdHdlrGetWord +} ecslCmdHdrlType; + + +/* the next type describes $Begin .. $End block object types + */ +typedef enum cslConfObjType { + eConfObjGlobal = 0, /* global directives */ + eConfObjAction, /* action-specific directives */ + /* now come states that indicate that we wait for a block-end. These are + * states that permit us to do some safety checks and they hopefully ease + * migration to a "real" parser/grammar. + */ + eConfObjActionWaitEnd, + eConfObjAlways /* always valid, very special case (guess $End only!) */ +} ecslConfObjType; + /* multi-submit support. * This is done via a simple data structure, which holds the number of elements diff --git a/runtime/var.h b/runtime/var.h index 6d890ec9..ae971bb5 100644 --- a/runtime/var.h +++ b/runtime/var.h @@ -40,6 +40,7 @@ typedef struct var_s { varType_t varType; union { number_t num; + es_str_t *str; cstr_t *pStr; syslogTime_t vSyslogTime; diff --git a/runtime/vm.c b/runtime/vm.c index 0ed174d1..c5521c31 100644 --- a/runtime/vm.c +++ b/runtime/vm.c @@ -448,6 +448,7 @@ BEGINop(PUSHMSGVAR) /* remember to set the instruction also in the ENDop macro! var_t *pVal; /* the value to push */ cstr_t *pstrVal; CODESTARTop(PUSHMSGVAR) +dbgprintf("XXX: pushMSGVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr)); if(pThis->pMsg == NULL) { /* TODO: flag an error message! As a work-around, we permit * execution to continue here with an empty string @@ -468,6 +469,31 @@ finalize_it: ENDop(PUSHMSGVAR) +BEGINop(PUSHCEEVAR) /* remember to set the instruction also in the ENDop macro! */ + var_t *pVal; /* the value to push */ + cstr_t *pstrVal; +CODESTARTop(PUSHCEEVAR) +dbgprintf("XXX: pushCEEVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr)); + if(pThis->pMsg == NULL) { + /* TODO: flag an error message! As a work-around, we permit + * execution to continue here with an empty string + */ + CHKiRet(var.Construct(&pVal)); + CHKiRet(var.ConstructFinalize(pVal)); + CHKiRet(rsCStrConstructFromszStr(&pstrVal, (uchar*)"")); + CHKiRet(var.SetString(pVal, pstrVal)); + } else { + /* we have a message, so pull value from there */ + CHKiRet(msgGetCEEVar(pThis->pMsg, pOp->operand.pVar->val.pStr, &pVal)); + } + + /* if we reach this point, we have a valid pVal and can push it */ + vmstk.Push(pThis->pStk, pVal); +dbgprintf("XXX: pushCEEVAR, result '%s'\n", rsCStrGetSzStr(pVal->val.pStr)); +finalize_it: +ENDop(PUSHCEEVAR) + + BEGINop(PUSHSYSVAR) /* remember to set the instruction also in the ENDop macro! */ var_t *pVal; /* the value to push */ CODESTARTop(PUSHSYSVAR) @@ -685,6 +711,7 @@ execProg(vm_t *pThis, vmprg_t *pProg) doOP(NOT); doOP(PUSHCONSTANT); doOP(PUSHMSGVAR); + doOP(PUSHCEEVAR); doOP(PUSHSYSVAR); doOP(STRADD); doOP(PLUS); diff --git a/runtime/vmop.h b/runtime/vmop.h index 67048c26..c085a940 100644 --- a/runtime/vmop.h +++ b/runtime/vmop.h @@ -59,6 +59,7 @@ typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc( opcode_PUSHSYSVAR = 1001, /* requires var operand */ opcode_PUSHMSGVAR = 1002, /* requires var operand */ opcode_PUSHCONSTANT = 1003, /* requires var operand */ + opcode_PUSHCEEVAR = 1004, /* requires var operand */ opcode_UNARY_MINUS = 1010, opcode_FUNC_CALL = 1012, opcode_END_PROG = 2000 |