diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile.am | 10 | ||||
-rw-r--r-- | tools/omdiscard.c | 11 | ||||
-rw-r--r-- | tools/omfile.c | 244 | ||||
-rw-r--r-- | tools/omfwd.c | 333 | ||||
-rw-r--r-- | tools/ompipe.c | 109 | ||||
-rw-r--r-- | tools/omshell.c | 19 | ||||
-rw-r--r-- | tools/omusrmsg.c | 172 | ||||
-rw-r--r-- | tools/syslogd.c | 1122 | ||||
-rw-r--r-- | tools/syslogd.h | 1 |
9 files changed, 775 insertions, 1246 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am index fef88af1..4e457426 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -34,9 +34,13 @@ rsyslogd_SOURCES = \ pidfile.c \ pidfile.h \ \ - ../dirty.h -rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) -rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) + ../dirty.h \ + ../runtime/librsyslog.la +rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(CNF_LIBS) +# note: it looks like librsyslog.la must be explicitely given on LDDADD, +# otherwise dependencies are not properly calculated (resulting in a +# potentially incomplete build, a problem we had several times...) +rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) $(CNF_LIBS) ../grammar/libgrammar.la ../runtime/librsyslog.la rsyslogd_LDFLAGS = -export-dynamic if ENABLE_DIAGTOOLS diff --git a/tools/omdiscard.c b/tools/omdiscard.c index 5b64d3ff..182c4b63 100644 --- a/tools/omdiscard.c +++ b/tools/omdiscard.c @@ -47,16 +47,6 @@ typedef struct _instanceData { EMPTY_STRUCT } instanceData; -typedef struct configSettings_s { - EMPTY_STRUCT -} configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ - -BEGINinitConfVars /* (re)set config variables to default values */ -CODESTARTinitConfVars -ENDinitConfVars - /* we do not need a createInstance()! BEGINcreateInstance CODESTARTcreateInstance @@ -124,7 +114,6 @@ ENDqueryEtryPt BEGINmodInit(Discard) CODESTARTmodInit -SCOPINGmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr ENDmodInit diff --git a/tools/omfile.c b/tools/omfile.c index e13efa74..c7f1b896 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -71,6 +71,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omfile") /* forward definitions */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); @@ -125,18 +126,16 @@ typedef struct s_dynaFileCacheEntry dynaFileCacheEntry; #define USE_ASYNCWRITER_DFLT 0 /* default buffer use async writer */ #define FLUSHONTX_DFLT 1 /* default for flush on TX end */ -#define DFLT_bForceChown 0 typedef struct _instanceData { - uchar f_fname[MAXFNAME];/* file or template name (display only) */ + uchar *f_fname; /* file or template name (display only) */ + uchar *tplName; /* name of assigned template */ strm_t *pStrm; /* our output stream */ - strmType_t strmType; /* stream type, used for named pipes */ char bDynamicName; /* 0 - static name, 1 - dynamic name (with properties) */ int fCreateMode; /* file creation mode for open() */ int fDirCreateMode; /* creation mode for mkdir() */ int bCreateDirs; /* auto-create directories? */ int bSyncFile; /* should the file by sync()'ed? 1- yes, 0- no */ - sbool bForceChown; /* force chown() on existing files? */ uid_t fileUID; /* IDs for creation */ uid_t dirUID; gid_t fileGID; @@ -165,7 +164,6 @@ typedef struct configSettings_s { int fCreateMode; /* mode to use when creating files */ int fDirCreateMode; /* mode to use when creating files */ int bFailOnChown; /* fail if chown fails? */ - int bForceChown; /* Force chown() on existing files? */ uid_t fileUID; /* UID to be used for newly created files */ uid_t fileGID; /* GID to be used for newly created files */ uid_t dirUID; /* UID to be used for newly created directories */ @@ -179,9 +177,38 @@ typedef struct configSettings_s { int bUseAsyncWriter; /* should we enable asynchronous writing? */ EMPTY_STRUCT } configSettings_t; +static configSettings_t cs; uchar *pszFileDfltTplName; /* name of the default template to use */ -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "dynafilecachesize", eCmdHdlrInt, 0 }, /* legacy: dynafilecachesize */ + { "ziplevel", eCmdHdlrInt, 0 }, /* legacy: omfileziplevel */ + { "flushinterval", eCmdHdlrInt, 0 }, /* legacy: omfileflushinterval */ + { "asyncwriting", eCmdHdlrBinary, 0 }, /* legacy: omfileasyncwriting */ + { "flushontxend", eCmdHdlrBinary, 0 }, /* legacy: omfileflushontxend */ + { "iobuffersize", eCmdHdlrSize, 0 }, /* legacy: omfileiobuffersize */ + { "dirowner", eCmdHdlrUID, 0 }, /* legacy: dirowner */ + { "dirgroup", eCmdHdlrGID, 0 }, /* legacy: dirgroup */ + { "fileowner", eCmdHdlrUID, 0 }, /* legacy: fileowner */ + { "filegroup", eCmdHdlrGID, 0 }, /* legacy: filegroup */ + { "dircreatemode", eCmdHdlrFileCreateMode, 0 }, /* legacy: dircreatemode */ + { "filecreatemode", eCmdHdlrFileCreateMode, 0 }, /* legacy: filecreatemode */ + { "failonchownfailure", eCmdHdlrBinary, 0 }, /* legacy: failonchownfailure */ + { "createdirs", eCmdHdlrBinary, 0 }, /* legacy: createdirs */ + { "sync", eCmdHdlrBinary, 0 }, /* legacy: actionfileenablesync */ + { "file", eCmdHdlrString, 0 }, /* either "file" or ... */ + { "dynafile", eCmdHdlrString, 0 }, /* "dynafile" MUST be present */ + { "template", eCmdHdlrGetWord, 0 }, + //{ "", eCmdHdlrGetWord, 0 }, /* legacy: */ +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -212,7 +239,6 @@ CODESTARTdbgPrintInstInfo dbgprintf("\tfile cache size=%d\n", pData->iDynaFileCacheSize); dbgprintf("\tcreate directories: %s\n", pData->bCreateDirs ? "yes" : "no"); dbgprintf("\tfile owner %d, group %d\n", (int) pData->fileUID, (int) pData->fileGID); - dbgprintf("\tforce chown() for all files: %s\n", pData->bForceChown ? "yes" : "no"); dbgprintf("\tdirectory owner %d, group %d\n", (int) pData->dirUID, (int) pData->dirGID); dbgprintf("\tdir create mode 0%3.3o, file create mode 0%3.3o\n", pData->fDirCreateMode, pData->fCreateMode); @@ -300,7 +326,7 @@ static rsRetVal cflineParseOutchannel(instanceData *pData, uchar* p, omodStringR } /* OK, we finally got a correct template. So let's use it... */ - ustrncpy(pData->f_fname, pOch->pszFileTemplate, MAXFNAME); + pData->f_fname = ustrdup(pOch->pszFileTemplate); pData->iSizeLimit = pOch->uSizeLimit; /* WARNING: It is dangerous "just" to pass the pointer. As we * never rebuild the output channel description, this is acceptable here. @@ -401,22 +427,7 @@ prepareFile(instanceData *pData, uchar *newFileName) DEFiRet; pData->pStrm = NULL; - if(access((char*)newFileName, F_OK) == 0) { - if(pData->bForceChown) { - /* Try to fix wrong ownership set by someone else. Note that this code - * will no longer work once we have made the $PrivDrop code fully secure. - * This change is based on an idea of Michael Terry, provided as part of - * the effort to make rsyslogd the Ubuntu default syslogd. - * rgerhards, 2009-09-11 - */ - if(chown((char*)newFileName, pData->fileUID, pData->fileGID) != 0) { - if(pData->bFailOnChown) { - int eSave = errno; - errno = eSave; - } - } - } - } else { + if(access((char*)newFileName, F_OK) != 0) { /* file does not exist, create it (and eventually parent directories */ if(pData->bCreateDirs) { /* We first need to create parent dirs if they are missing. @@ -436,7 +447,7 @@ prepareFile(instanceData *pData, uchar *newFileName) pData->fCreateMode); if(fd != -1) { /* check and set uid/gid */ - if(pData->bForceChown || pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) { + if(pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) { /* we need to set owner/group */ if(fchown(fd, pData->fileUID, pData->fileGID) != 0) { if(pData->bFailOnChown) { @@ -473,7 +484,7 @@ prepareFile(instanceData *pData, uchar *newFileName) CHKiRet(strm.SettOperationsMode(pData->pStrm, STREAMMODE_WRITE_APPEND)); CHKiRet(strm.SettOpenMode(pData->pStrm, cs.fCreateMode)); CHKiRet(strm.SetbSync(pData->pStrm, pData->bSyncFile)); - CHKiRet(strm.SetsType(pData->pStrm, pData->strmType)); + CHKiRet(strm.SetsType(pData->pStrm, STREAMTYPE_FILE_SINGLE)); CHKiRet(strm.SetiSizeLimit(pData->pStrm, pData->iSizeLimit)); /* set the flush interval only if we actually use it - otherwise it will activate * async processing, which is a real performance waste if we do not do buffered @@ -666,17 +677,15 @@ writeFile(uchar **ppString, unsigned iMsgOpts, instanceData *pData) } else { /* "regular", non-dynafile */ if(pData->pStrm == NULL) { CHKiRet(prepareFile(pData, pData->f_fname)); + if(pData->pStrm == NULL) { + errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could no open output file '%s'", pData->f_fname); + } } } CHKiRet(doWrite(pData, ppString[0], strlen(CHAR_CONVERT(ppString[0])))); finalize_it: - if(iRet != RS_RET_OK) { - /* in v5, we shall return different states for message-caused failure (but only there!) */ - if(pData->strmType == STREAMTYPE_NAMED_PIPE) - iRet = RS_RET_DISABLE_ACTION; /* this is the traditional semantic -- rgerhards, 2010-01-15 */ - } RETiRet; } @@ -689,6 +698,7 @@ ENDcreateInstance BEGINfreeInstance CODESTARTfreeInstance + free(pData->f_fname); if(pData->bDynamicName) { dynaFileFreeCache(pData); } else if(pData->pStrm != NULL) @@ -729,7 +739,128 @@ finalize_it: ENDdoAction +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->f_fname = NULL; + pData->tplName = NULL; + pData->fileUID = -1; + pData->fileGID = -1; + pData->dirUID = -1; + pData->dirGID = -1; + pData->bFailOnChown = 1; + pData->iDynaFileCacheSize = 10; + pData->fCreateMode = 0644; + pData->fDirCreateMode = 0700; + pData->bCreateDirs = 1; + pData->bSyncFile = 0; + pData->iZipLevel = 0; + pData->bFlushOnTXEnd = FLUSHONTX_DFLT; + pData->iIOBufSize = IOBUF_DFLT_SIZE; + pData->iFlushInterval = FLUSH_INTRVL_DFLT; + pData->bUseAsyncWriter = USE_ASYNCWRITER_DFLT; +} + +BEGINnewActInst + struct cnfparamvals *pvals; + int i; +CODESTARTnewActInst + DBGPRINTF("newActInst (omfile)\n"); + + pvals = nvlstGetParams(lst, &actpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "omfile: either the \"file\" or " + "\"dynfile\" parameter must be given"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("action param blk in omfile:\n"); + cnfparamsPrint(&actpblk, pvals); + } + + CHKiRet(createInstance(&pData)); + setInstParamDefaults(pData); + + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "dynafilecachesize")) { + pData->iDynaFileCacheSize = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "ziplevel")) { + pData->iZipLevel = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "flushinterval")) { + pData->iFlushInterval = pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "asyncwriting")) { + pData->bUseAsyncWriter = pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "flushontxend")) { + pData->bFlushOnTXEnd = pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "iobuffersize")) { + pData->iIOBufSize = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "dirowner")) { + pData->dirUID = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "dirgroup")) { + pData->dirGID = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "fileowner")) { + pData->fileUID = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "filegroup")) { + pData->fileGID = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "dircreatemode")) { + pData->fDirCreateMode = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "filecreatemode")) { + pData->fCreateMode = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "failonchownfailure")) { + pData->bFailOnChown = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "sync")) { + pData->bSyncFile = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "createdirs")) { + pData->bCreateDirs = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "file")) { + pData->f_fname = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + CODE_STD_STRING_REQUESTnewActInst(1) + pData->bDynamicName = 0; + } else if(!strcmp(actpblk.descr[i].name, "dynafile")) { + pData->f_fname = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + CODE_STD_STRING_REQUESTnewActInst(2) + pData->bDynamicName = 1; + } else if(!strcmp(actpblk.descr[i].name, "template")) { + pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("omfile: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + + if(pData->f_fname == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "omfile: either the \"file\" or " + "\"dynfile\" parameter must be given"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + CHKiRet(OMSRsetEntry(*ppOMSR, 0, ustrdup((pData->tplName == NULL) ? + (uchar*)"RSYSLOG_FileFormat" : (uchar*)"??"), + OMSR_NO_RQD_TPL_OPTS)); + + if(pData->bDynamicName) { + /* "filename" is actually a template name, we need this as string 1. So let's add it + * to the pOMSR. -- rgerhards, 2007-07-27 + */ + CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(pData->f_fname), OMSR_NO_RQD_TPL_OPTS)); + // TODO: create unified code for this (legacy+v6 system) + /* we now allocate the cache table */ + CHKmalloc(pData->dynCache = (dynaFileCacheEntry**) + calloc(cs.iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))); + pData->iCurrElt = -1; /* no current element */ + } +// TODO: add pData->iSizeLimit = 0; /* default value, use outchannels to configure! */ + +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + + BEGINparseSelectorAct + uchar fname[MAXFNAME]; CODESTARTparseSelectorAct /* Note: the indicator sequence permits us to use '$' to signify * outchannel, what otherwise is not possible due to truely @@ -738,13 +869,6 @@ CODESTARTparseSelectorAct */ if(!strncmp((char*) p, ":omfile:", sizeof(":omfile:") - 1)) { p += sizeof(":omfile:") - 1; - } else { - if(*p == '$') { - errmsg.LogError(0, RS_RET_OUTDATED_STMT, - "action '%s' treated as ':omfile:%s' - please " - "change syntax, '%s' will not be supported in " - "rsyslog v6 and above.", p, p, p); - } } if(!(*p == '$' || *p == '?' || *p == '/' || *p == '.' || *p == '-')) ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); @@ -778,39 +902,26 @@ CODESTARTparseSelectorAct */ CODE_STD_STRING_REQUESTparseSelectorAct(2) ++p; /* eat '?' */ - CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, + CHKiRet(cflineParseFileName(p, fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); + pData->f_fname = ustrdup(fname); + pData->bDynamicName = 1; + pData->iCurrElt = -1; /* no current element */ /* "filename" is actually a template name, we need this as string 1. So let's add it * to the pOMSR. -- rgerhards, 2007-07-27 */ CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(pData->f_fname), OMSR_NO_RQD_TPL_OPTS)); - - pData->bDynamicName = 1; - pData->iCurrElt = -1; /* no current element */ /* we now allocate the cache table */ CHKmalloc(pData->dynCache = (dynaFileCacheEntry**) calloc(cs.iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))); break; - /* case '|': while pipe support has been removed, I leave the code in in case we - * need high-performance pipes at a later stage (unlikely). -- rgerhards, 2010-02-28 - */ case '/': case '.': CODE_STD_STRING_REQUESTparseSelectorAct(1) - /* we now have *almost* the same semantics for files and pipes, but we still need - * to know we deal with a pipe, because we must do non-blocking opens in that case - * (to keep consistent with traditional semantics and prevent rsyslog from hanging). - */ - if(*p == '|') { - ++p; - pData->strmType = STREAMTYPE_NAMED_PIPE; - } else { - pData->strmType = STREAMTYPE_FILE_SINGLE; - } - - CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, + CHKiRet(cflineParseFileName(p, fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); + pData->f_fname = ustrdup(fname); pData->bDynamicName = 0; break; default: @@ -823,7 +934,6 @@ CODESTARTparseSelectorAct pData->fDirCreateMode = cs.fDirCreateMode; pData->bCreateDirs = cs.bCreateDirs; pData->bFailOnChown = cs.bFailOnChown; - pData->bForceChown = cs.bForceChown; pData->fileUID = cs.fileUID; pData->fileGID = cs.fileGID; pData->dirUID = cs.dirUID; @@ -833,18 +943,6 @@ CODESTARTparseSelectorAct pData->iIOBufSize = (int) cs.iIOBufSize; pData->iFlushInterval = cs.iFlushInterval; pData->bUseAsyncWriter = cs.bUseAsyncWriter; - - if(pData->bDynamicName == 0) { - /* try open and emit error message if not possible. At this stage, we ignore the - * return value of prepareFile, this is taken care of in later steps. - */ - prepareFile(pData, pData->f_fname); - - if(pData->pStrm == NULL) { - DBGPRINTF("Error opening log file: %s\n", pData->f_fname); - errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could not open output file '%s'", pData->f_fname); - } - } CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct @@ -859,7 +957,6 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a cs.dirUID = -1; cs.dirGID = -1; cs.bFailOnChown = 1; - cs.bForceChown = DFLT_bForceChown; cs.iDynaFileCacheSize = 10; cs.fCreateMode = 0644; cs.fDirCreateMode = 0700; @@ -902,6 +999,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */ CODEqueryEtryPt_doHUP ENDqueryEtryPt @@ -911,7 +1009,7 @@ BEGINmodInit(File) CODESTARTmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr -SCOPINGmodInit +INITLegCnfVars CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(strm, CORE_COMPONENT)); @@ -933,7 +1031,7 @@ SCOPINGmodInit CHKiRet(omsdRegCFSLineHdlr((uchar *)"filecreatemode", 0, eCmdHdlrFileCreateMode, NULL, &cs.fCreateMode, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"createdirs", 0, eCmdHdlrBinary, NULL, &cs.bCreateDirs, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"failonchownfailure", 0, eCmdHdlrBinary, NULL, &cs.bFailOnChown, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileForceChown", 0, eCmdHdlrBinary, NULL, &cs.bForceChown, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileforcechown", 0, eCmdHdlrGoneAway, NULL, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionfileenablesync", 0, eCmdHdlrBinary, NULL, &cs.bEnableSync, STD_LOADABLE_MODULE_ID)); CHKiRet(regCfSysLineHdlr((uchar *)"actionfiledefaulttemplate", 0, eCmdHdlrGetWord, NULL, &pszFileDfltTplName, NULL)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); diff --git a/tools/omfwd.c b/tools/omfwd.c index d5f113e7..96458941 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -4,30 +4,26 @@ * NOTE: read comments in module-template.h to understand how this file * works! * - * File begun on 2007-07-20 by RGerhards (extracted from syslogd.c) - * This file is under development and has not yet arrived at being fully - * self-contained and a real object. So far, it is mostly an excerpt - * of the "old" message code without any modifications. However, it - * helps to have things at the right place one we go to the meat of it. - * - * Copyright 2007, 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2012 Adiscon GmbH. * * This file is part of rsyslog. * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * A copy of the GPL can be found in the file "COPYING" in this distribution. + * TODO v6 config: + * - permitted peer *list* */ #include "config.h" #include "rsyslog.h" @@ -62,9 +58,11 @@ #include "module-template.h" #include "glbl.h" #include "errmsg.h" +#include "unicode-helper.h" MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omfwd") /* internal structures */ @@ -77,25 +75,27 @@ DEFobjCurrIf(netstrm) DEFobjCurrIf(tcpclt) typedef struct _instanceData { + uchar *tplName; /* name of assigned template */ netstrms_t *pNS; /* netstream subsystem */ netstrm_t *pNetstrm; /* our output netstream */ uchar *pszStrmDrvr; uchar *pszStrmDrvrAuthMode; permittedPeers_t *pPermPeers; int iStrmDrvrMode; - char *f_hname; + char *target; int *pSockArray; /* sockets to use for UDP */ int bIsConnected; /* are we connected to remote host? 0 - no, 1 - yes, UDP means addr resolved */ struct addrinfo *f_addr; int compressionLevel; /* 0 - no compression, else level for zlib */ char *port; int protocol; - int iUDPRebindInterval; /* rebind interval */ - int iTCPRebindInterval; /* rebind interval */ + int iRebindInterval; /* rebind interval */ int nXmit; /* number of transmissions since last (re-)bind */ # define FORW_UDP 0 # define FORW_TCP 1 /* following fields for TCP-based delivery */ + TCPFRAMINGMODE tcp_framing; + int bResendLastOnRecon; /* should the last message be re-sent on a successful reconnect? */ tcpclt_t *pTCPClt; /* our tcpclt object */ uchar sndBuf[16*1024]; /* this is intensionally fixed -- see no good reason to make configurable */ unsigned offsSndBuf; /* next free spot in send buffer */ @@ -108,12 +108,33 @@ typedef struct configSettings_s { int iStrmDrvrMode; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ int bResendLastOnRecon; /* should the last message be re-sent on a successful reconnect? */ uchar *pszStrmDrvrAuthMode; /* authentication mode to use */ - int iUDPRebindInterval; /* support for automatic re-binding (load balancers!). 0 - no rebind */ int iTCPRebindInterval; /* support for automatic re-binding (load balancers!). 0 - no rebind */ + int iUDPRebindInterval; /* support for automatic re-binding (load balancers!). 0 - no rebind */ permittedPeers_t *pPermPeers; } configSettings_t; +static configSettings_t cs; + +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "target", eCmdHdlrGetWord, 0 }, + { "port", eCmdHdlrGetWord, 0 }, + { "protocol", eCmdHdlrGetWord, 0 }, + { "tcp_framing", eCmdHdlrGetWord, 0 }, + { "ziplevel", eCmdHdlrInt, 0 }, + { "rebindinterval", eCmdHdlrInt, 0 }, + { "streamdriver", eCmdHdlrGetWord, 0 }, + { "streamdrivermode", eCmdHdlrInt, 0 }, + { "streamdriverauthmode", eCmdHdlrGetWord, 0 }, + { "streamdriverpermittedpeers", eCmdHdlrGetWord, 0 }, + { "resendlastmsgonreconnect", eCmdHdlrBinary, 0 }, +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -149,22 +170,6 @@ pData->bIsConnected = 0; // TODO: remove this variable altogether } -/* get the syslog forward port from selector_t. The passed in - * struct must be one that is setup for forwarding. - * rgerhards, 2007-06-28 - * We may change the implementation to try to lookup the port - * if it is unspecified. So far, we use the IANA default auf 514. - */ -static char *getFwdPt(instanceData *pData) -{ - assert(pData != NULL); - if(pData->port == NULL) - return("514"); - else - return(pData->port); -} - - /* destruct the TCP helper objects * This, for example, is needed after something went wrong. * This function is void because it "can not" fail. @@ -208,7 +213,7 @@ CODESTARTfreeInstance } free(pData->port); - free(pData->f_hname); + free(pData->target); free(pData->pszStrmDrvr); free(pData->pszStrmDrvrAuthMode); net.DestructPermittedPeers(&pData->pPermPeers); @@ -217,7 +222,7 @@ ENDfreeInstance BEGINdbgPrintInstInfo CODESTARTdbgPrintInstInfo - dbgprintf("%s", pData->f_hname); + dbgprintf("%s", pData->target); ENDdbgPrintInstInfo @@ -232,7 +237,7 @@ static rsRetVal UDPSend(instanceData *pData, char *msg, size_t len) unsigned lsent = 0; int bSendSuccess; - if(pData->iUDPRebindInterval && (pData->nXmit++ % pData->iUDPRebindInterval == 0)) { + if(pData->iRebindInterval && (pData->nXmit++ % pData->iRebindInterval == 0)) { dbgprintf("omfwd dropping UDP 'connection' (as configured)\n"); pData->nXmit = 1; /* else we have an addtl wrap at 2^31-1 */ CHKiRet(closeUDPSockets(pData)); @@ -309,7 +314,6 @@ TCPSendBuf(instanceData *pData, uchar *buf, unsigned len) ssize_t lenSend; alreadySent = 0; -dbgprintf("omfwd: XXXX: pData %p, pNetStrm %p\n", pData, pData->pNetstrm); netstrm.CheckConnection(pData->pNetstrm); /* hack for plain tcp syslog - see ptcp driver for details */ while(alreadySent != len) { lenSend = len - alreadySent; @@ -382,7 +386,7 @@ static rsRetVal TCPSendInit(void *pvData) if(pData->pNetstrm == NULL) { CHKiRet(netstrms.Construct(&pData->pNS)); /* the stream driver must be set before the object is finalized! */ - CHKiRet(netstrms.SetDrvrName(pData->pNS, cs.pszStrmDrvr)); + CHKiRet(netstrms.SetDrvrName(pData->pNS, pData->pszStrmDrvr)); CHKiRet(netstrms.ConstructFinalize(pData->pNS)); /* now create the actual stream and connect to the server */ @@ -398,7 +402,7 @@ static rsRetVal TCPSendInit(void *pvData) } /* params set, now connect */ CHKiRet(netstrm.Connect(pData->pNetstrm, glbl.GetDefPFFamily(), - (uchar*)getFwdPt(pData), (uchar*)pData->f_hname)); + (uchar*)pData->port, (uchar*)pData->target)); } finalize_it: @@ -424,23 +428,23 @@ static rsRetVal doTryResume(instanceData *pData) FINALIZE; /* The remote address is not yet known and needs to be obtained */ - dbgprintf(" %s\n", pData->f_hname); + dbgprintf(" %s\n", pData->target); if(pData->protocol == FORW_UDP) { memset(&hints, 0, sizeof(hints)); /* port must be numeric, because config file syntax requires this */ hints.ai_flags = AI_NUMERICSERV; hints.ai_family = glbl.GetDefPFFamily(); hints.ai_socktype = SOCK_DGRAM; - if((iErr = (getaddrinfo(pData->f_hname, getFwdPt(pData), &hints, &res))) != 0) { + if((iErr = (getaddrinfo(pData->target, pData->port, &hints, &res))) != 0) { dbgprintf("could not get addrinfo for hostname '%s':'%s': %d%s\n", - pData->f_hname, getFwdPt(pData), iErr, gai_strerror(iErr)); + pData->target, pData->port, iErr, gai_strerror(iErr)); ABORT_FINALIZE(RS_RET_SUSPENDED); } - dbgprintf("%s found, resuming.\n", pData->f_hname); + dbgprintf("%s found, resuming.\n", pData->target); pData->f_addr = res; pData->bIsConnected = 1; if(pData->pSockArray == NULL) { - pData->pSockArray = net.create_udp_socket((uchar*)pData->f_hname, NULL, 0); + pData->pSockArray = net.create_udp_socket((uchar*)pData->target, NULL, 0); } } else { CHKiRet(TCPSendInit((void*)pData)); @@ -472,15 +476,18 @@ ENDbeginTransaction BEGINdoAction - char *psz = NULL; /* temporary buffering */ + char *psz; /* temporary buffering */ register unsigned l; int iMaxLine; +# ifdef USE_NETZIP + Bytef *out = NULL; /* for compression */ +# endif CODESTARTdoAction CHKiRet(doTryResume(pData)); iMaxLine = glbl.GetMaxLine(); - dbgprintf(" %s:%s/%s\n", pData->f_hname, getFwdPt(pData), + dbgprintf(" %s:%s/%s\n", pData->target, pData->port, pData->protocol == FORW_UDP ? "udp" : "tcp"); psz = (char*) ppString[0]; @@ -498,7 +505,6 @@ CODESTARTdoAction * rgerhards, 2006-11-30 */ if(pData->compressionLevel && (l > CONF_MIN_SIZE_FOR_COMPRESS)) { - Bytef *out; uLongf destLen = iMaxLine + iMaxLine/100 +12; /* recommended value from zlib doc */ uLong srcLen = l; int ret; @@ -519,14 +525,11 @@ CODESTARTdoAction * rgerhards, 2006-11-30 */ dbgprintf("Compression failed, sending uncompressed message\n"); - free(out); } else if(destLen+1 < l) { /* only use compression if there is a gain in using it! */ dbgprintf("there is gain in compression, so we do it\n"); psz = (char*) out; l = destLen + 1; /* take care for the "z" at message start! */ - } else { - free(out); } ++destLen; } @@ -547,10 +550,7 @@ CODESTARTdoAction } finalize_it: # ifdef USE_NETZIP - if((psz != NULL) && (psz != (char*) ppString[0])) { - /* we need to free temporary buffer, alloced above - Naoya Nakazawa, 2010-01-11 */ - free(psz); - } + free(out); /* is NULL if it was never used... */ # endif ENDdoAction @@ -582,6 +582,184 @@ finalize_it: RETiRet; } + +/* initialize TCP structures (if necessary) after the instance has been + * created. + */ +static rsRetVal +initTCP(instanceData *pData) +{ + DEFiRet; + if(pData->protocol == FORW_TCP) { + /* create our tcpclt */ + CHKiRet(tcpclt.Construct(&pData->pTCPClt)); + CHKiRet(tcpclt.SetResendLastOnRecon(pData->pTCPClt, pData->bResendLastOnRecon)); + /* and set callbacks */ + CHKiRet(tcpclt.SetSendInit(pData->pTCPClt, TCPSendInit)); + CHKiRet(tcpclt.SetSendFrame(pData->pTCPClt, TCPSendFrame)); + CHKiRet(tcpclt.SetSendPrepRetry(pData->pTCPClt, TCPSendPrepRetry)); + CHKiRet(tcpclt.SetFraming(pData->pTCPClt, pData->tcp_framing)); + CHKiRet(tcpclt.SetRebindInterval(pData->pTCPClt, pData->iRebindInterval)); + pData->iStrmDrvrMode = cs.iStrmDrvrMode; + if(cs.pszStrmDrvr != NULL) + CHKmalloc(pData->pszStrmDrvr = (uchar*)strdup((char*)cs.pszStrmDrvr)); + if(cs.pszStrmDrvrAuthMode != NULL) + CHKmalloc(pData->pszStrmDrvrAuthMode = + (uchar*)strdup((char*)cs.pszStrmDrvrAuthMode)); + } +finalize_it: + RETiRet; +} + + +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->tplName = NULL; + pData->protocol = FORW_UDP; + pData->tcp_framing = TCP_FRAMING_OCTET_STUFFING; + pData->pszStrmDrvr = NULL; + pData->pszStrmDrvrAuthMode = NULL; + pData->iStrmDrvrMode = 0; + pData->iRebindInterval = 0; + pData->bResendLastOnRecon = 0; + pData->pPermPeers = NULL; + pData->compressionLevel = 0; +} + +BEGINnewActInst + struct cnfparamvals *pvals; + int i; + rsRetVal localRet; +CODESTARTnewActInst + DBGPRINTF("newActInst (omfwd)\n"); + + pvals = nvlstGetParams(lst, &actpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "omfwd: either the \"file\" or " + "\"dynfile\" parameter must be given"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("action param blk in omfwd:\n"); + cnfparamsPrint(&actpblk, pvals); + } + + CHKiRet(createInstance(&pData)); + setInstParamDefaults(pData); + + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "target")) { + pData->target = es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "port")) { + pData->port = es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "protocol")) { + if(!es_strcasebufcmp(pvals[i].val.d.estr, (uchar*)"udp", 3)) { + pData->protocol = FORW_UDP; + } else if(!es_strcasebufcmp(pvals[i].val.d.estr, (uchar*)"tcp", 3)) { + localRet = loadTCPSupport(); + if(localRet != RS_RET_OK) { + errmsg.LogError(0, localRet, "could not activate network stream modules for TCP " + "(internal error %d) - are modules missing?", localRet); + ABORT_FINALIZE(localRet); + } + pData->protocol = FORW_TCP; + } else { + uchar *str; + str = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_INVLD_PROTOCOL, + "omfwd: invalid protocol \"%s\"", str); + free(str); + ABORT_FINALIZE(RS_RET_INVLD_PROTOCOL); + } + } else if(!strcmp(actpblk.descr[i].name, "tcp_framing")) { + if(!es_strcasebufcmp(pvals[i].val.d.estr, (uchar*)"traditional", 11)) { + pData->tcp_framing = TCP_FRAMING_OCTET_STUFFING; + } else if(!es_strcasebufcmp(pvals[i].val.d.estr, (uchar*)"octet-counted", 13)) { + pData->tcp_framing = TCP_FRAMING_OCTET_COUNTING; + } else { + uchar *str; + str = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_CNF_INVLD_FRAMING, + "omfwd: invalid framing \"%s\"", str); + free(str); + ABORT_FINALIZE(RS_RET_CNF_INVLD_FRAMING ); + } + } else if(!strcmp(actpblk.descr[i].name, "rebindinterval")) { + pData->iRebindInterval = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "streamdriver")) { + pData->pszStrmDrvr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "streamdrivermode")) { + pData->iStrmDrvrMode = pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "streamdriverauthmode")) { + pData->pszStrmDrvrAuthMode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "streamdriverpermittedpeers")) { + uchar *start, *str; + uchar save; + uchar *p; + int lenStr; + str = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + start = str; + lenStr = ustrlen(start); /* we need length after '\0' has been dropped... */ + while(lenStr > 0) { + p = start; + while(*p && *p != ',' && lenStr--) + p++; + if(*p == ',') { + *p = '\0'; + } + save = *(p+1); /* we always have this, at least the \0 byte at EOS */ + *(p+1) = '\0'; + if(*start == '\0') { + DBGPRINTF("omfwd: ignoring empty permitted peer\n"); + } else { + dbgprintf("omfwd: adding permitted peer: '%s'\n", start); + CHKiRet(net.AddPermittedPeer(&(pData->pPermPeers), start)); + } + start = p+1; + if(lenStr) + --lenStr; + *(p+1) = save; + } + free(str); + } else if(!strcmp(actpblk.descr[i].name, "ziplevel")) { +# ifdef USE_NETZIP + int complevel = pvals[i].val.d.n; + if(complevel >= 0 && complevel <= 10) { + pData->compressionLevel = complevel; + } else { + errmsg.LogError(0, NO_ERRCODE, "Invalid ziplevel %d specified in " + "forwardig action - NOT turning on compression.", + complevel); + } +# else + errmsg.LogError(0, NO_ERRCODE, "Compression requested, but rsyslogd is not compiled " + "with compression support - request ignored."); +# endif /* #ifdef USE_NETZIP */ + } else if(!strcmp(actpblk.descr[i].name, "resendlastmsgonreconnect")) { + pData->bResendLastOnRecon = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "template")) { + pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + DBGPRINTF("omfwd: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + CODE_STD_STRING_REQUESTnewActInst(1) + + CHKiRet(OMSRsetEntry(*ppOMSR, 0, ustrdup((pData->tplName == NULL) ? + (uchar*)"RSYSLOG_TraditionalForwardFormat" : (uchar*)pData->tplName), + OMSR_NO_RQD_TPL_OPTS)); + + CHKiRet(initTCP(pData)); +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + + BEGINparseSelectorAct uchar *q; int i; @@ -687,6 +865,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) /* JUST SKIP */; } + pData->tcp_framing = tcp_framing; pData->port = NULL; if(*p == ':') { /* process port */ uchar * tmp; @@ -699,12 +878,16 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) if(pData->port == NULL) { errmsg.LogError(0, NO_ERRCODE, "Could not get memory to store syslog forwarding port, " "using default port, results may not be what you intend\n"); - /* we leave f_forw.port set to NULL, this is then handled by getFwdPt(). */ + /* we leave f_forw.port set to NULL, this is then handled below */ } else { memcpy(pData->port, tmp, i); *(pData->port + i) = '\0'; } } + /* check if no port is set. If so, we use the IANA-assigned port of 514 */ + if(pData->port == NULL) { + CHKmalloc(pData->port = strdup("514")); + } /* now skip to template */ while(*p && *p != ';' && *p != '#' && !isspace((int) *p)) @@ -714,30 +897,22 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) if(*p == ';' || *p == '#' || isspace(*p)) { uchar cTmp = *p; *p = '\0'; /* trick to obtain hostname (later)! */ - CHKmalloc(pData->f_hname = strdup((char*) q)); + CHKmalloc(pData->target = strdup((char*) q)); *p = cTmp; } else { - CHKmalloc(pData->f_hname = strdup((char*) q)); + CHKmalloc(pData->target = strdup((char*) q)); } /* copy over config data as needed */ - pData->iUDPRebindInterval = cs.iUDPRebindInterval; - pData->iTCPRebindInterval = cs.iTCPRebindInterval; + pData->iRebindInterval = (pData->protocol == FORW_TCP) ? + cs.iTCPRebindInterval : cs.iUDPRebindInterval; /* process template */ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (cs.pszTplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : cs.pszTplName)); if(pData->protocol == FORW_TCP) { - /* create our tcpclt */ - CHKiRet(tcpclt.Construct(&pData->pTCPClt)); - CHKiRet(tcpclt.SetResendLastOnRecon(pData->pTCPClt, cs.bResendLastOnRecon)); - /* and set callbacks */ - CHKiRet(tcpclt.SetSendInit(pData->pTCPClt, TCPSendInit)); - CHKiRet(tcpclt.SetSendFrame(pData->pTCPClt, TCPSendFrame)); - CHKiRet(tcpclt.SetSendPrepRetry(pData->pTCPClt, TCPSendPrepRetry)); - CHKiRet(tcpclt.SetFraming(pData->pTCPClt, tcp_framing)); - CHKiRet(tcpclt.SetRebindInterval(pData->pTCPClt, pData->iTCPRebindInterval)); + pData->bResendLastOnRecon = cs.bResendLastOnRecon; pData->iStrmDrvrMode = cs.iStrmDrvrMode; if(cs.pszStrmDrvr != NULL) CHKmalloc(pData->pszStrmDrvr = (uchar*)strdup((char*)cs.pszStrmDrvr)); @@ -749,7 +924,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) cs.pPermPeers = NULL; } } - + CHKiRet(initTCP(pData)); CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct @@ -780,7 +955,6 @@ CODESTARTmodExit objRelease(netstrm, LM_NETSTRMS_FILENAME); objRelease(netstrms, LM_NETSTRMS_FILENAME); objRelease(tcpclt, LM_TCPCLT_FILENAME); - freeConfigVars(); ENDmodExit @@ -788,6 +962,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */ ENDqueryEtryPt @@ -811,7 +986,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a BEGINmodInit(Fwd) CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(glbl, CORE_COMPONENT)); diff --git a/tools/ompipe.c b/tools/ompipe.c index 2bd7f7b2..30cb9bfc 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -57,6 +57,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("ompipe") /* internal structures */ @@ -69,15 +70,28 @@ DEFobjCurrIf(errmsg) typedef struct _instanceData { - uchar f_fname[MAXFNAME];/* pipe or template name (display only) */ - short fd; /* pipe descriptor for (current) pipe */ + uchar *pipe; /* pipe or template name (display only) */ + uchar *tplName; /* format template to use */ + short fd; /* pipe descriptor for (current) pipe */ + sbool bHadError; /* did we already have/report an error on this pipe? */ } instanceData; typedef struct configSettings_s { EMPTY_STRUCT } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t __attribute__((unused)) cs; + +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "pipe", eCmdHdlrString, CNFPARAM_REQUIRED }, + { "template", eCmdHdlrGetWord, 0 } +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -93,7 +107,7 @@ ENDisCompatibleWithFeature BEGINdbgPrintInstInfo CODESTARTdbgPrintInstInfo - dbgprintf("pipe %s", pData->f_fname); + dbgprintf("pipe %s", pData->pipe); if (pData->fd == -1) dbgprintf(" (unused)"); ENDdbgPrintInstInfo @@ -109,7 +123,18 @@ static inline rsRetVal preparePipe(instanceData *pData) { DEFiRet; - pData->fd = open((char*) pData->f_fname, O_RDWR|O_NONBLOCK|O_CLOEXEC); + pData->fd = open((char*) pData->pipe, O_RDWR|O_NONBLOCK|O_CLOEXEC); + if(pData->fd < 0 ) { + pData->fd = -1; + if(!pData->bHadError) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could no open output pipe '%s': %s", + pData->pipe, errStr); + pData->bHadError = 1; + } + DBGPRINTF("Error opening log pipe: %s\n", pData->pipe); + } RETiRet; } @@ -148,7 +173,7 @@ static rsRetVal writePipe(uchar **ppString, instanceData *pData) pData->fd = -1; /* tell that fd is no longer open! */ iRet = RS_RET_SUSPENDED; errno = e; - errmsg.LogError(0, NO_ERRCODE, "%s", pData->f_fname); + errmsg.LogError(0, NO_ERRCODE, "%s", pData->pipe); } finalize_it: @@ -158,12 +183,15 @@ finalize_it: BEGINcreateInstance CODESTARTcreateInstance + pData->pipe = NULL; pData->fd = -1; + pData->bHadError = 0; ENDcreateInstance BEGINfreeInstance CODESTARTfreeInstance + free(pData->pipe); if(pData->fd != -1) close(pData->fd); ENDfreeInstance @@ -175,11 +203,54 @@ ENDtryResume BEGINdoAction CODESTARTdoAction - DBGPRINTF(" (%s)\n", pData->f_fname); + DBGPRINTF(" (%s)\n", pData->pipe); iRet = writePipe(ppString, pData); ENDdoAction +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->tplName = NULL; +} + +BEGINnewActInst + struct cnfparamvals *pvals; + int i; +CODESTARTnewActInst + if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) { + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + CHKiRet(createInstance(&pData)); + setInstParamDefaults(pData); + + CODE_STD_STRING_REQUESTparseSelectorAct(1) + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "pipe")) { + pData->pipe = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "template")) { + pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("ompipe: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + + if(pData->tplName == NULL) { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, (uchar*) "RSYSLOG_FileFormat", + OMSR_NO_RQD_TPL_OPTS)); + } else { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, + (uchar*) strdup((char*) pData->tplName), + OMSR_NO_RQD_TPL_OPTS)); + } +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + BEGINparseSelectorAct CODESTARTparseSelectorAct /* yes, the if below is redundant, but I need it now. Will go away as @@ -199,25 +270,11 @@ CODESTARTparseSelectorAct } CODE_STD_STRING_REQUESTparseSelectorAct(1) + CHKmalloc(pData->pipe = malloc(512)); ++p; - /* rgerhards 2004-11-17: from now, we need to have different - * processing, because after the first comma, the template name - * to use is specified. So we need to scan for the first coma first - * and then look at the rest of the line. - */ - CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, + CHKiRet(cflineParseFileName(p, (uchar*) pData->pipe, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); - - /* at this stage, we ignore the return value of preparePipe, this is taken - * care of in later steps. -- rgerhards, 2009-03-19 - */ - preparePipe(pData); - if(pData->fd < 0 ) { - pData->fd = -1; - DBGPRINTF("Error opening log pipe: %s\n", pData->f_fname); - errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could not open output pipe '%s'", pData->f_fname); - } CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct @@ -240,12 +297,14 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES CODEqueryEtryPt_doHUP +CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES ENDqueryEtryPt BEGINmodInit(Pipe) CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); diff --git a/tools/omshell.c b/tools/omshell.c index 648d28a4..ac62fa62 100644 --- a/tools/omshell.c +++ b/tools/omshell.c @@ -1,6 +1,13 @@ /* omshell.c * This is the implementation of the build-in shell output module. * + * ************* DO NOT EXTEND THIS MODULE ************** + * This is pure legacy, omprog has much better and more + * secure functionality than this module. It is NOT + * recommended to base new work on it! + * 2012-01-19 rgerhards + * ****************************************************** + * * NOTE: read comments in module-template.h to understand how this file * works! * @@ -56,17 +63,6 @@ typedef struct _instanceData { uchar progName[MAXFNAME]; /* program to execute */ } instanceData; - -typedef struct configSettings_s { - EMPTY_STRUCT /* remove this when data members are added */ -} configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ - -BEGINinitConfVars /* (re)set config variables to default values */ -CODESTARTinitConfVars -ENDinitConfVars - BEGINcreateInstance CODESTARTcreateInstance ENDcreateInstance @@ -148,7 +144,6 @@ ENDqueryEtryPt BEGINmodInit(Shell) CODESTARTmodInit -SCOPINGmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); diff --git a/tools/omusrmsg.c b/tools/omusrmsg.c index dd5c8004..e57d7ef9 100644 --- a/tools/omusrmsg.c +++ b/tools/omusrmsg.c @@ -10,17 +10,6 @@ * * Copyright 2007-2012 Adiscon GmbH. * - * rgerhards, 2008-07-04 (happy Independence Day!): rsyslog inherited the - * wall functionality from sysklogd. Sysklogd was single-threaded and could - * not afford to spent a lot of time inside a single action. Thus, it forked - * off a new process to do the wall. In rsyslog, however, this creates some - * grief with the threading model. Also, we do not really need to de-couple - * processing, because we have ample ways to do it in rsyslog. Plus, the - * default main message queue will care for a somewhat longer execution time. - * So in short, the real fix to the problem is an architecture change. From - * now on, we will not fork off a new process but rather do the notification - * within the current one. This also reduces system overhead. - * * This file is part of rsyslog. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,6 +34,7 @@ #include <string.h> #include <assert.h> #include <signal.h> +#include <ctype.h> #include <sys/param.h> #ifdef HAVE_UTMP_H # include <utmp.h> @@ -84,6 +74,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omusrmsg") /* internal structures */ @@ -93,13 +84,26 @@ DEFobjCurrIf(errmsg) typedef struct _instanceData { int bIsWall; /* 1- is wall, 0 - individual users */ char uname[MAXUNAMES][UNAMESZ+1]; + uchar *tplName; } instanceData; typedef struct configSettings_s { EMPTY_STRUCT } configSettings_t; +static configSettings_t __attribute__((unused)) cs; + -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "users", eCmdHdlrString, CNFPARAM_REQUIRED }, + { "template", eCmdHdlrGetWord, 0 } +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -120,7 +124,7 @@ ENDisCompatibleWithFeature BEGINfreeInstance CODESTARTfreeInstance - /* TODO: free the instance pointer (currently a leak, will go away) */ + free(pData->tplName); ENDfreeInstance @@ -276,26 +280,123 @@ CODESTARTdoAction ENDdoAction -BEGINparseSelectorAct - uchar *q; +static inline void +populateUsers(instanceData *pData, es_str_t *usrs) +{ int i; + int iDst; + es_size_t iUsr; + es_size_t len; + uchar *c; + + len = es_strlen(usrs); + c = es_getBufAddr(usrs); + pData->bIsWall = 0; /* write to individual users */ + iUsr = 0; + for(i = 0 ; i < MAXUNAMES && iUsr < len ; ++i) { + for( iDst = 0 + ; iDst < UNAMESZ && iUsr < len && c[iUsr] != ',' + ; ++iDst, ++iUsr) { + pData->uname[i][iDst] = c[iUsr]; + } + pData->uname[i][iDst] = '\0'; + DBGPRINTF("omusrmsg: send to user '%s'\n", pData->uname[i]); + if(iUsr < len && c[iUsr] != ',') { + errmsg.LogError(0, RS_RET_ERR, "user name '%s...' too long - " + "ignored", pData->uname[i]); + --i; + ++iUsr; + while(iUsr < len && c[iUsr] != ',') + ++iUsr; /* skip to next name */ + } else if(iDst == 0) { + errmsg.LogError(0, RS_RET_ERR, "no user name given - " + "ignored"); + --i; + ++iUsr; + while(iUsr < len && c[iUsr] != ',') + ++iUsr; /* skip to next name */ + } + if(iUsr < len) { + ++iUsr; /* skip "," */ + while(iUsr < len && isspace(c[iUsr])) + ++iUsr; /* skip whitespace */ + } + } + if(i == MAXUNAMES && iUsr != len) { + errmsg.LogError(0, RS_RET_ERR, "omusrmsg supports only up to %d " + "user names in a single action - all others have been ignored", + MAXUNAMES); + } +} + + +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->bIsWall = 0; + pData->tplName = NULL; +} + +BEGINnewActInst + struct cnfparamvals *pvals; + int i; +CODESTARTnewActInst + if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) { + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + CHKiRet(createInstance(&pData)); + setInstParamDefaults(pData); + + CODE_STD_STRING_REQUESTparseSelectorAct(1) + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "users")) { + if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"*", 1)) { + pData->bIsWall = 1; + } else { + populateUsers(pData, pvals[i].val.d.estr); + } + } else if(!strcmp(actpblk.descr[i].name, "template")) { + pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("omusrmsg: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + + if(pData->tplName == NULL) { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, + (uchar*) strdup(pData->bIsWall ? " WallFmt" : " StdUsrMsgFmt"), + OMSR_NO_RQD_TPL_OPTS)); + } else { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, + (uchar*) strdup((char*) pData->tplName), + OMSR_NO_RQD_TPL_OPTS)); + } +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + + +BEGINparseSelectorAct + es_str_t *usrs; + int bHadWarning; CODESTARTparseSelectorAct CODE_STD_STRING_REQUESTparseSelectorAct(1) - /* User names must begin with a gnu e-regex: - * [a-zA-Z0-9_.] - * plus '*' for wall - */ if(!strncmp((char*) p, ":omusrmsg:", sizeof(":omusrmsg:") - 1)) { p += sizeof(":omusrmsg:") - 1; /* eat indicator sequence (-1 because of '\0'!) */ } else { if(!*p || !((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_' || *p == '.' || *p == '*')) { - ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); + ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); } else { errmsg.LogError(0, RS_RET_OUTDATED_STMT, "action '%s' treated as ':omusrmsg:%s' - please " "change syntax, '%s' will not be supported in the future", p, p, p); + bHadWarning = 1; } } @@ -307,30 +408,20 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) pData->bIsWall = 1; /* write to all users */ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) " WallFmt")); } else { - /* everything else beginning with the regex above - * is currently treated as a user name -- TODO: is this portable? - */ - dbgprintf("users: %s\n", p); /* ASP */ - pData->bIsWall = 0; /* write to individual users */ - for (i = 0; i < MAXUNAMES && *p && *p != ';'; i++) { - for (q = p; *q && *q != ',' && *q != ';'; ) - q++; - (void) strncpy((char*) pData->uname[i], (char*) p, UNAMESZ); - if ((q - p) > UNAMESZ) - pData->uname[i][UNAMESZ] = '\0'; - else - pData->uname[i][q - p] = '\0'; - while (*q == ',' || *q == ' ') - q++; - p = q; + /* everything else is currently treated as a user name */ + usrs = es_newStr(128); + while(*p && *p != ';') { + es_addChar(&usrs, *p); + ++p; } - /* done, on to the template - * TODO: we need to handle the case where i >= MAXUNAME! - */ + populateUsers(pData, usrs); + es_deleteStr(usrs); if((iRet = cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*)" StdUsrMsgFmt")) != RS_RET_OK) goto finalize_it; } + if(iRet == RS_RET_OK && bHadWarning) + iRet = RS_RET_OK_WARN; CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct @@ -343,12 +434,13 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES ENDqueryEtryPt BEGINmodInit(UsrMsg) CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); diff --git a/tools/syslogd.c b/tools/syslogd.c index 346d6bba..2e7a1e23 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -21,7 +21,7 @@ * For further information, please see http://www.rsyslog.com * * rsyslog - An Enhanced syslogd Replacement. - * Copyright 2003-2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2003-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -108,18 +108,6 @@ #include "action.h" #include "iminternal.h" #include "cfsysline.h" -#include "omshell.h" -#include "omusrmsg.h" -#include "omfwd.h" -#include "omfile.h" -#include "ompipe.h" -#include "omdiscard.h" -#include "pmrfc5424.h" -#include "pmrfc3164.h" -#include "smfile.h" -#include "smtradfile.h" -#include "smfwd.h" -#include "smtradfwd.h" #include "threads.h" #include "wti.h" #include "queue.h" @@ -133,8 +121,9 @@ #include "ruleset.h" #include "rule.h" #include "net.h" -#include "vm.h" #include "prop.h" +#include "rsconf.h" +#include "dnscache.h" #include "sd-daemon.h" /* definitions for objects we access */ @@ -142,13 +131,13 @@ DEFobjCurrIf(obj) DEFobjCurrIf(glbl) DEFobjCurrIf(datetime) /* TODO: make go away! */ DEFobjCurrIf(conf) -DEFobjCurrIf(expr) DEFobjCurrIf(module) DEFobjCurrIf(errmsg) DEFobjCurrIf(rule) DEFobjCurrIf(ruleset) DEFobjCurrIf(prop) DEFobjCurrIf(parser) +DEFobjCurrIf(rsconf) DEFobjCurrIf(net) /* TODO: make go away! */ @@ -198,6 +187,8 @@ static rsRetVal GlobalClassExit(void); # define _PATH_TTY "/dev/tty" #endif +rsconf_t *ourConf; /* our config object */ + 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 */ @@ -211,7 +202,7 @@ static int bFinished = 0; /* used by termination signal handler, read-only excep * is either 0 or the number of the signal that requested the * termination. */ -static int iConfigVerify = 0; /* is this just a config verify run? */ +int iConfigVerify = 0; /* is this just a config verify run? */ /* Intervals at which we flush out "message repeated" messages, * in seconds after previous message is logged. After each flush, @@ -224,115 +215,24 @@ int repeatinterval[2] = { 30, 60 }; /* # of secs before flush */ static pid_t ppid; /* This is a quick and dirty hack used for spliting main/startup thread */ -typedef struct legacyOptsLL_s { - uchar *line; - struct legacyOptsLL_s *next; -} legacyOptsLL_t; -legacyOptsLL_t *pLegacyOptsLL = NULL; - /* global variables for config file state */ int iCompatibilityMode = 0; /* version we should be compatible with; 0 means sysklogd. It is the default, so if no -c<n> option is given, we make ourselvs as compatible to sysklogd as possible. */ -#define DFLT_bLogStatusMsgs 1 -static int bLogStatusMsgs = DFLT_bLogStatusMsgs; /* log rsyslog start/stop/HUP messages? */ -static int bDebugPrintTemplateList = 1;/* output template list in debug mode? */ -static int bDebugPrintCfSysLineHandlerList = 1;/* output cfsyslinehandler list in debug mode? */ -static int bDebugPrintModuleList = 1;/* output module list in debug mode? */ -static int bErrMsgToStderr = 1; /* print error messages to stderr (in addition to everything else)? */ -int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */ -int bAbortOnUncleanConfig = 0; /* abort run (rather than starting with partial config) if there was any issue in conf */ /* end global config file state variables */ int MarkInterval = 20 * 60; /* interval between marks in seconds - read-only after startup */ int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */ static int NoFork = 0; /* don't fork - don't run in daemon mode - read-only after startup */ -static int bHaveMainQueue = 0;/* set to 1 if the main queue - in queueing mode - is available +int bHaveMainQueue = 0;/* set to 1 if the main queue - in queueing mode - is available * If the main queue is either not yet ready or not running in * queueing mode (mode DIRECT!), then this is set to 0. */ -static int uidDropPriv = 0; /* user-id to which priveleges should be dropped to (AFTER init()!) */ -static int gidDropPriv = 0; /* group-id to which priveleges should be dropped to (AFTER init()!) */ extern int errno; -static uchar *pszConfDAGFile = NULL; /* name of config DAG file, non-NULL means generate one */ /* main message queue and its configuration parameters */ qqueue_t *pMsgQueue = NULL; /* the main message queue */ -static int iMainMsgQueueSize = 10000; /* size of the main message queue above */ -static int iMainMsgQHighWtrMark = 8000; /* high water mark for disk-assisted queues */ -static int iMainMsgQLowWtrMark = 2000; /* low water mark for disk-assisted queues */ -static int iMainMsgQDiscardMark = 9800; /* begin to discard messages */ -static int iMainMsgQDiscardSeverity = 8; /* by default, discard nothing to prevent unintentional loss */ -static int iMainMsgQueueNumWorkers = 1; /* number of worker threads for the mm queue above */ -static queueType_t MainMsgQueType = QUEUETYPE_FIXED_ARRAY; /* type of the main message queue above */ -static uchar *pszMainMsgQFName = NULL; /* prefix for the main message queue file */ -static int64 iMainMsgQueMaxFileSize = 1024*1024; -static int iMainMsgQPersistUpdCnt = 0; /* persist queue info every n updates */ -static int bMainMsgQSyncQeueFiles = 0; /* sync queue files on every write? */ -static int iMainMsgQtoQShutdown = 1500; /* queue shutdown (ms) */ -static int iMainMsgQtoActShutdown = 1000; /* action shutdown (in phase 2) */ -static int iMainMsgQtoEnq = 2000; /* timeout for queue enque */ -static int iMainMsgQtoWrkShutdown = 60000; /* timeout for worker thread shutdown */ -static int iMainMsgQWrkMinMsgs = 100; /* minimum messages per worker needed to start a new one */ -static int iMainMsgQDeqSlowdown = 0; /* dequeue slowdown (simple rate limiting) */ -static int64 iMainMsgQueMaxDiskSpace = 0; /* max disk space allocated 0 ==> unlimited */ -static int64 iMainMsgQueDeqBatchSize = 32; /* dequeue batch size */ -static int bMainMsgQSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */ -static int iMainMsgQueueDeqtWinFromHr = 0; /* hour begin of time frame when queue is to be dequeued */ -static int iMainMsgQueueDeqtWinToHr = 25; /* hour begin of time frame when queue is to be dequeued */ - - -/* Reset config variables to default values. - * rgerhards, 2007-07-17 - */ -static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) -{ - bLogStatusMsgs = DFLT_bLogStatusMsgs; - bDebugPrintTemplateList = 1; - bDebugPrintCfSysLineHandlerList = 1; - bDebugPrintModuleList = 1; - bReduceRepeatMsgs = 0; - bAbortOnUncleanConfig = 0; - free(pszMainMsgQFName); - pszMainMsgQFName = NULL; - iMainMsgQueueSize = 10000; - iMainMsgQHighWtrMark = 8000; - iMainMsgQLowWtrMark = 2000; - iMainMsgQDiscardMark = 9800; - iMainMsgQDiscardSeverity = 8; - iMainMsgQueMaxFileSize = 1024 * 1024; - iMainMsgQueueNumWorkers = 1; - iMainMsgQPersistUpdCnt = 0; - bMainMsgQSyncQeueFiles = 0; - iMainMsgQtoQShutdown = 1500; - iMainMsgQtoActShutdown = 1000; - iMainMsgQtoEnq = 2000; - iMainMsgQtoWrkShutdown = 60000; - iMainMsgQWrkMinMsgs = 100; - iMainMsgQDeqSlowdown = 0; - bMainMsgQSaveOnShutdown = 1; - MainMsgQueType = QUEUETYPE_FIXED_ARRAY; - iMainMsgQueMaxDiskSpace = 0; - iMainMsgQueDeqBatchSize = 32; - - return RS_RET_OK; -} - - -/* hardcoded standard templates (used for defaults) */ -static uchar template_DebugFormat[] = "\"Debug line with all properties:\nFROMHOST: '%FROMHOST%', fromhost-ip: '%fromhost-ip%', HOSTNAME: '%HOSTNAME%', PRI: %PRI%,\nsyslogtag '%syslogtag%', programname: '%programname%', APP-NAME: '%APP-NAME%', PROCID: '%PROCID%', MSGID: '%MSGID%',\nTIMESTAMP: '%TIMESTAMP%', STRUCTURED-DATA: '%STRUCTURED-DATA%',\nmsg: '%msg%'\nescaped msg: '%msg:::drop-cc%'\ninputname: %inputname% rawmsg: '%rawmsg%'\n\n\""; -static uchar template_SyslogProtocol23Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n\""; -static uchar template_TraditionalFileFormat[] = "=RSYSLOG_TraditionalFileFormat"; -static uchar template_FileFormat[] = "=RSYSLOG_FileFormat"; -static uchar template_ForwardFormat[] = "=RSYSLOG_ForwardFormat"; -static uchar template_TraditionalForwardFormat[] = "=RSYSLOG_TraditionalForwardFormat"; -static uchar template_WallFmt[] = "\"\r\n\7Message from syslogd@%HOSTNAME% at %timegenerated% ...\r\n %syslogtag%%msg%\n\r\""; -static uchar template_StdUsrMsgFmt[] = "\" %syslogtag%%msg%\n\r\""; -static uchar template_StdDBFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag%')\",SQL"; -static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-pgsql%', '%timegenerated:::date-pgsql%', %iut%, '%syslogtag%')\",STDSQL"; -static uchar template_spoofadr[] = "\"%fromhost-ip%\""; -/* end templates */ /* up to the next comment, prototypes that should be removed by reordering */ @@ -456,8 +356,15 @@ void untty(void) #else { int i; + pid_t pid; if(!Debug) { + pid = getpid(); + if (setpgid(pid, pid) < 0) { + perror("setpgid"); + exit(1); + } + i = open(_PATH_TTY, O_RDWR|O_CLOEXEC); if (i >= 0) { # if !defined(__hpux) @@ -483,7 +390,7 @@ void untty(void) */ rsRetVal parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlType, - prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime) + prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime, ruleset_t *pRuleset) { prop_t *pProp = NULL; msg_t *pMsg; @@ -499,6 +406,7 @@ parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int fla MsgSetInputName(pMsg, pInputName); MsgSetRawMsg(pMsg, (char*)msg, len); MsgSetFlowControlType(pMsg, flowCtlType); + MsgSetRuleset(pMsg, pRuleset); pMsg->msgFlags = flags | NEEDS_PARSING; MsgSetRcvFromStr(pMsg, hname, ustrlen(hname), &pProp); @@ -565,7 +473,7 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags) * permits us to process unmodified config files which otherwise contain a * supressor statement. */ - if(((Debug == DEBUG_FULL || NoFork) && bErrMsgToStderr) || iConfigVerify) { + if(((Debug == DEBUG_FULL || NoFork) && ourConf->globals.bErrMsgToStderr) || iConfigVerify) { if(LOG_PRI(pri) == LOG_ERR) fprintf(stderr, "rsyslogd: %s\n", msg); } @@ -787,7 +695,7 @@ DEFFUNC_llExecFunc(flushRptdMsgsActions) assert(pAction != NULL); BEGINfunc - LockObj(pAction); + d_pthread_mutex_lock(&pAction->mutAction); /* TODO: time() performance: the call below could be moved to * the beginn of the llExec(). This makes it slightly less correct, but * in an acceptable way. -- rgerhards, 2008-09-16 @@ -799,7 +707,7 @@ DEFFUNC_llExecFunc(flushRptdMsgsActions) actionWriteToAction(pAction); BACKOFF(pAction); } - UnlockObj(pAction); + d_pthread_mutex_unlock(&pAction->mutAction); ENDfunc return RS_RET_OK; /* we ignore errors, we can not do anything either way */ @@ -811,7 +719,7 @@ DEFFUNC_llExecFunc(flushRptdMsgsActions) static void doFlushRptdMsgs(void) { - ruleset.IterateAllActions(flushRptdMsgsActions, NULL); + ruleset.IterateAllActions(runConf, flushRptdMsgsActions, NULL); } @@ -848,132 +756,6 @@ static void debug_switch() } -void legacyOptsEnq(uchar *line) -{ - legacyOptsLL_t *pNew; - - pNew = MALLOC(sizeof(legacyOptsLL_t)); - if(line == NULL) - pNew->line = NULL; - else - pNew->line = (uchar *) strdup((char *) line); - pNew->next = NULL; - - if(pLegacyOptsLL == NULL) - pLegacyOptsLL = pNew; - else { - legacyOptsLL_t *pThis = pLegacyOptsLL; - - while(pThis->next != NULL) - pThis = pThis->next; - pThis->next = pNew; - } -} - - -void legacyOptsFree(void) -{ - legacyOptsLL_t *pThis = pLegacyOptsLL, *pNext; - - while(pThis != NULL) { - if(pThis->line != NULL) - free(pThis->line); - pNext = pThis->next; - free(pThis); - pThis = pNext; - } -} - - -void legacyOptsHook(void) -{ - legacyOptsLL_t *pThis = pLegacyOptsLL; - - while(pThis != NULL) { - if(pThis->line != NULL) { - errno = 0; - errmsg.LogError(0, NO_ERRCODE, "Warning: backward compatibility layer added to following " - "directive to rsyslog.conf: %s", pThis->line); - conf.cfsysline(pThis->line); - } - pThis = pThis->next; - } -} - - -void legacyOptsParseTCP(char ch, char *arg) -{ - register int i; - register char *pArg = arg; - static char conflict = '\0'; - - if((conflict == 'g' && ch == 't') || (conflict == 't' && ch == 'g')) { - fprintf(stderr, "rsyslogd: If you want to use both -g and -t, use directives instead, -%c ignored.\n", ch); - return; - } else - conflict = ch; - - /* extract port */ - i = 0; - while(isdigit((int) *pArg)) - i = i * 10 + *pArg++ - '0'; - - /* number of sessions */ - if(*pArg == '\0' || *pArg == ',') { - if(ch == 't') - legacyOptsEnq((uchar *) "ModLoad imtcp"); - else if(ch == 'g') - legacyOptsEnq((uchar *) "ModLoad imgssapi"); - - if(i >= 0 && i <= 65535) { - uchar line[30]; - - if(ch == 't') { - snprintf((char *) line, sizeof(line), "InputTCPServerRun %d", i); - } else if(ch == 'g') { - snprintf((char *) line, sizeof(line), "InputGSSServerRun %d", i); - } - legacyOptsEnq(line); - } else { - if(ch == 't') { - fprintf(stderr, "rsyslogd: Invalid TCP listen port %d - changed to 514.\n", i); - legacyOptsEnq((uchar *) "InputTCPServerRun 514"); - } else if(ch == 'g') { - fprintf(stderr, "rsyslogd: Invalid GSS listen port %d - changed to 514.\n", i); - legacyOptsEnq((uchar *) "InputGSSServerRun 514"); - } - } - - if(*pArg == ',') { - ++pArg; - while(isspace((int) *pArg)) - ++pArg; - i = 0; - while(isdigit((int) *pArg)) { - i = i * 10 + *pArg++ - '0'; - } - if(i > 0) { - uchar line[30]; - - snprintf((char *) line, sizeof(line), "InputTCPMaxSessions %d", i); - legacyOptsEnq(line); - } else { - if(ch == 't') { - fprintf(stderr, "rsyslogd: TCP session max configured " - "to %d [-t %s] - changing to 1.\n", i, arg); - legacyOptsEnq((uchar *) "InputTCPMaxSessions 1"); - } else if (ch == 'g') { - fprintf(stderr, "rsyslogd: GSS session max configured " - "to %d [-g %s] - changing to 1.\n", i, arg); - legacyOptsEnq((uchar *) "InputTCPMaxSessions 1"); - } - } - } - } else - fprintf(stderr, "rsyslogd: Invalid -t %s command line option.\n", arg); -} - - /* doDie() is a signal handler. If called, it sets the bFinished variable * to indicate the program should terminate. However, it does not terminate * it itself, because that causes issues with multi-threading. The actual @@ -1011,9 +793,7 @@ static void doDie(int sig) static void freeAllDynMemForTermination(void) { - free(pszMainMsgQFName); - free(pModDir); - free(pszConfDAGFile); + free(ourConf->globals.pszConfDAGFile); } @@ -1022,7 +802,7 @@ freeAllDynMemForTermination(void) static inline void destructAllActions(void) { - ruleset.DestructAllActions(); + ruleset.DestructAllActions(runConf); bHaveMainQueue = 0; // flag that internal messages need to be temporarily stored } @@ -1060,7 +840,7 @@ die(int sig) thrdTerminateAll(); /* and THEN send the termination log message (see long comment above) */ - if(sig && bLogStatusMsgs) { + if(sig && runConf->globals.bLogStatusMsgs) { (void) snprintf(buf, sizeof(buf) / sizeof(char), " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"]" " exiting on signal %d.", @@ -1087,7 +867,7 @@ die(int sig) * ourselfs, this makes finding memory leaks a lot * easier. */ - tplDeleteAll(); + tplDeleteAll(runConf); /* de-init some modules */ modExitIminternal(); @@ -1099,8 +879,6 @@ die(int sig) */ unregCfSysLineHdlrs(); - legacyOptsFree(); - /* destruct our global properties */ if(pInternalInputName != NULL) prop.Destruct(&pInternalInputName); @@ -1138,110 +916,7 @@ static void doexit() exit(0); /* "good" exit, only during child-creation */ } - -/* set the maximum message size */ -static rsRetVal setMaxMsgSize(void __attribute__((unused)) *pVal, long iNewVal) -{ - return glbl.SetMaxLine(iNewVal); -} - - -/* set the action resume interval */ -static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int iNewVal) -{ - return actionSetGlobalResumeInterval(iNewVal); -} - - -/* set the processes max number ob files (upon configuration request) - * 2009-04-14 rgerhards - */ -static rsRetVal setMaxFiles(void __attribute__((unused)) *pVal, int iFiles) -{ - struct rlimit maxFiles; - char errStr[1024]; - DEFiRet; - - maxFiles.rlim_cur = iFiles; - maxFiles.rlim_max = iFiles; - - if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) { - /* NOTE: under valgrind, we seem to be unable to extend the size! */ - rs_strerror_r(errno, errStr, sizeof(errStr)); - errmsg.LogError(0, RS_RET_ERR_RLIM_NOFILE, "could not set process file limit to %d: %s [kernel max %ld]", - iFiles, errStr, (long) maxFiles.rlim_max); - ABORT_FINALIZE(RS_RET_ERR_RLIM_NOFILE); - } -#ifdef USE_UNLIMITED_SELECT - glbl.SetFdSetSize(howmany(iFiles, __NFDBITS) * sizeof (fd_mask)); -#endif - DBGPRINTF("Max number of files set to %d [kernel max %ld].\n", iFiles, (long) maxFiles.rlim_max); - -finalize_it: - RETiRet; -} - - -/* set the processes umask (upon configuration request) */ -static rsRetVal setUmask(void __attribute__((unused)) *pVal, int iUmask) -{ - umask(iUmask); - DBGPRINTF("umask set to 0%3.3o.\n", iUmask); - - return RS_RET_OK; -} - - -/* drop to specified group - * if something goes wrong, the function never returns - * Note that such an abort can cause damage to on-disk structures, so we should - * re-design the "interface" in the long term. -- rgerhards, 2008-11-26 - */ -static void doDropPrivGid(int iGid) -{ - int res; - uchar szBuf[1024]; - - res = setgroups(0, NULL); /* remove all supplementary group IDs */ - if(res) { - perror("could not remove supplemental group IDs"); - exit(1); - } - DBGPRINTF("setgroups(0, NULL): %d\n", res); - res = setgid(iGid); - if(res) { - /* if we can not set the userid, this is fatal, so let's unconditionally abort */ - perror("could not set requested group id"); - exit(1); - } - DBGPRINTF("setgid(%d): %d\n", iGid, res); - snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's groupid changed to %d", iGid); - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0); -} - - -/* drop to specified user - * if something goes wrong, the function never returns - * Note that such an abort can cause damage to on-disk structures, so we should - * re-design the "interface" in the long term. -- rgerhards, 2008-11-19 - */ -static void doDropPrivUid(int iUid) -{ - int res; - uchar szBuf[1024]; - - res = setuid(iUid); - if(res) { - /* if we can not set the userid, this is fatal, so let's unconditionally abort */ - perror("could not set requested userid"); - exit(1); - } - DBGPRINTF("setuid(%d): %d\n", iUid, res); - snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's userid changed to %d", iUid); - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0); -} - - +#if 0 /* TODO: re-enable, currently not used */ /* helper to generateConfigDAG, to print out all actions via * the llExecFunc() facility. * rgerhards, 2007-08-02 @@ -1426,104 +1101,7 @@ generateConfigDAG(uchar *pszDAGFile) finalize_it: RETiRet; } - - -/* print debug information as part of init(). This pretty much - * outputs the whole config of rsyslogd. I've moved this code - * out of init() to clean it somewhat up. - * rgerhards, 2007-07-31 - */ -static void dbgPrintInitInfo(void) -{ - ruleset.DebugPrintAll(); - DBGPRINTF("\n"); - if(bDebugPrintTemplateList) - tplPrintList(); - if(bDebugPrintModuleList) - module.PrintList(); - ochPrintList(); - - if(bDebugPrintCfSysLineHandlerList) - dbgPrintCfSysLineHandlers(); - - DBGPRINTF("Messages with malicious PTR DNS Records are %sdropped.\n", - glbl.GetDropMalPTRMsgs() ? "" : "not "); - - DBGPRINTF("Main queue size %d messages.\n", iMainMsgQueueSize); - DBGPRINTF("Main queue worker threads: %d, wThread shutdown: %d, Perists every %d updates.\n", - iMainMsgQueueNumWorkers, iMainMsgQtoWrkShutdown, iMainMsgQPersistUpdCnt); - DBGPRINTF("Main queue timeouts: shutdown: %d, action completion shutdown: %d, enq: %d\n", - iMainMsgQtoQShutdown, iMainMsgQtoActShutdown, iMainMsgQtoEnq); - DBGPRINTF("Main queue watermarks: high: %d, low: %d, discard: %d, discard-severity: %d\n", - iMainMsgQHighWtrMark, iMainMsgQLowWtrMark, iMainMsgQDiscardMark, iMainMsgQDiscardSeverity); - DBGPRINTF("Main queue save on shutdown %d, max disk space allowed %lld\n", - bMainMsgQSaveOnShutdown, iMainMsgQueMaxDiskSpace); - /* TODO: add - iActionRetryCount = 0; - iActionRetryInterval = 30000; - static int iMainMsgQtoWrkMinMsgs = 100; - static int iMainMsgQbSaveOnShutdown = 1; - iMainMsgQueMaxDiskSpace = 0; - setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100); - setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1); - */ - DBGPRINTF("Work Directory: '%s'.\n", glbl.GetWorkDir()); -} - - -/* Actually run the input modules. This happens after privileges are dropped, - * if that is requested. - */ -static rsRetVal -runInputModules(void) -{ - modInfo_t *pMod; - int bNeedsCancel; - - 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 */ - bNeedsCancel = (pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ? - 0 : 1; - thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun, bNeedsCancel); - } - 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 - * running. Almost no config option is taken. - * rgerhards, 2007-12-14 - */ -static rsRetVal -startInputModules(void) -{ - DEFiRet; - modInfo_t *pMod; - - /* loop through all modules and activate them (brr...) */ - pMod = module.GetNxtType(NULL, eMOD_IN); - while(pMod != NULL) { - 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); - } - - ENDfunc - return RS_RET_OK; /* intentional: we do not care about module errors */ -} +#endif /* create a main message queue, now also used for ruleset queues. This function @@ -1536,12 +1114,12 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName) DEFiRet; /* switch the message object to threaded operation, if necessary */ - if(MainMsgQueType == QUEUETYPE_DIRECT || iMainMsgQueueNumWorkers > 1) { + if(ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT || ourConf->globals.mainQ.iMainMsgQueueNumWorkers > 1) { MsgEnableThreadSafety(); } /* create message queue */ - CHKiRet_Hdlr(qqueueConstruct(ppQueue, MainMsgQueType, iMainMsgQueueNumWorkers, iMainMsgQueueSize, msgConsumer)) { + CHKiRet_Hdlr(qqueueConstruct(ppQueue, ourConf->globals.mainQ.MainMsgQueType, ourConf->globals.mainQ.iMainMsgQueueNumWorkers, ourConf->globals.mainQ.iMainMsgQueueSize, msgConsumer)) { /* no queue is fatal, we need to give up in that case... */ errmsg.LogError(0, iRet, "could not create (ruleset) main message queue"); \ } @@ -1558,25 +1136,25 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName) errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \ } - setQPROP(qqueueSetMaxFileSize, "$MainMsgQueueFileSize", iMainMsgQueMaxFileSize); - setQPROP(qqueueSetsizeOnDiskMax, "$MainMsgQueueMaxDiskSpace", iMainMsgQueMaxDiskSpace); - setQPROP(qqueueSetiDeqBatchSize, "$MainMsgQueueDequeueBatchSize", iMainMsgQueDeqBatchSize); - setQPROPstr(qqueueSetFilePrefix, "$MainMsgQueueFileName", pszMainMsgQFName); - setQPROP(qqueueSetiPersistUpdCnt, "$MainMsgQueueCheckpointInterval", iMainMsgQPersistUpdCnt); - setQPROP(qqueueSetbSyncQueueFiles, "$MainMsgQueueSyncQueueFiles", bMainMsgQSyncQeueFiles); - setQPROP(qqueueSettoQShutdown, "$MainMsgQueueTimeoutShutdown", iMainMsgQtoQShutdown ); - setQPROP(qqueueSettoActShutdown, "$MainMsgQueueTimeoutActionCompletion", iMainMsgQtoActShutdown); - setQPROP(qqueueSettoWrkShutdown, "$MainMsgQueueWorkerTimeoutThreadShutdown", iMainMsgQtoWrkShutdown); - setQPROP(qqueueSettoEnq, "$MainMsgQueueTimeoutEnqueue", iMainMsgQtoEnq); - setQPROP(qqueueSetiHighWtrMrk, "$MainMsgQueueHighWaterMark", iMainMsgQHighWtrMark); - setQPROP(qqueueSetiLowWtrMrk, "$MainMsgQueueLowWaterMark", iMainMsgQLowWtrMark); - setQPROP(qqueueSetiDiscardMrk, "$MainMsgQueueDiscardMark", iMainMsgQDiscardMark); - setQPROP(qqueueSetiDiscardSeverity, "$MainMsgQueueDiscardSeverity", iMainMsgQDiscardSeverity); - setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", iMainMsgQWrkMinMsgs); - setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", bMainMsgQSaveOnShutdown); - setQPROP(qqueueSetiDeqSlowdown, "$MainMsgQueueDequeueSlowdown", iMainMsgQDeqSlowdown); - setQPROP(qqueueSetiDeqtWinFromHr, "$MainMsgQueueDequeueTimeBegin", iMainMsgQueueDeqtWinFromHr); - setQPROP(qqueueSetiDeqtWinToHr, "$MainMsgQueueDequeueTimeEnd", iMainMsgQueueDeqtWinToHr); + setQPROP(qqueueSetMaxFileSize, "$MainMsgQueueFileSize", ourConf->globals.mainQ.iMainMsgQueMaxFileSize); + setQPROP(qqueueSetsizeOnDiskMax, "$MainMsgQueueMaxDiskSpace", ourConf->globals.mainQ.iMainMsgQueMaxDiskSpace); + setQPROP(qqueueSetiDeqBatchSize, "$MainMsgQueueDequeueBatchSize", ourConf->globals.mainQ.iMainMsgQueDeqBatchSize); + setQPROPstr(qqueueSetFilePrefix, "$MainMsgQueueFileName", ourConf->globals.mainQ.pszMainMsgQFName); + setQPROP(qqueueSetiPersistUpdCnt, "$MainMsgQueueCheckpointInterval", ourConf->globals.mainQ.iMainMsgQPersistUpdCnt); + setQPROP(qqueueSetbSyncQueueFiles, "$MainMsgQueueSyncQueueFiles", ourConf->globals.mainQ.bMainMsgQSyncQeueFiles); + setQPROP(qqueueSettoQShutdown, "$MainMsgQueueTimeoutShutdown", ourConf->globals.mainQ.iMainMsgQtoQShutdown ); + setQPROP(qqueueSettoActShutdown, "$MainMsgQueueTimeoutActionCompletion", ourConf->globals.mainQ.iMainMsgQtoActShutdown); + setQPROP(qqueueSettoWrkShutdown, "$MainMsgQueueWorkerTimeoutThreadShutdown", ourConf->globals.mainQ.iMainMsgQtoWrkShutdown); + setQPROP(qqueueSettoEnq, "$MainMsgQueueTimeoutEnqueue", ourConf->globals.mainQ.iMainMsgQtoEnq); + setQPROP(qqueueSetiHighWtrMrk, "$MainMsgQueueHighWaterMark", ourConf->globals.mainQ.iMainMsgQHighWtrMark); + setQPROP(qqueueSetiLowWtrMrk, "$MainMsgQueueLowWaterMark", ourConf->globals.mainQ.iMainMsgQLowWtrMark); + setQPROP(qqueueSetiDiscardMrk, "$MainMsgQueueDiscardMark", ourConf->globals.mainQ.iMainMsgQDiscardMark); + setQPROP(qqueueSetiDiscardSeverity, "$MainMsgQueueDiscardSeverity", ourConf->globals.mainQ.iMainMsgQDiscardSeverity); + setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", ourConf->globals.mainQ.iMainMsgQWrkMinMsgs); + setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", ourConf->globals.mainQ.bMainMsgQSaveOnShutdown); + setQPROP(qqueueSetiDeqSlowdown, "$MainMsgQueueDequeueSlowdown", ourConf->globals.mainQ.iMainMsgQDeqSlowdown); + setQPROP(qqueueSetiDeqtWinFromHr, "$MainMsgQueueDequeueTimeBegin", ourConf->globals.mainQ.iMainMsgQueueDeqtWinFromHr); + setQPROP(qqueueSetiDeqtWinToHr, "$MainMsgQueueDequeueTimeEnd", ourConf->globals.mainQ.iMainMsgQueueDeqtWinToHr); # undef setQPROP # undef setQPROPstr @@ -1597,142 +1175,22 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName) static rsRetVal init(void) { - rsRetVal localRet; - int iNbrActions; - int bHadConfigErr = 0; - ruleset_t *pRuleset; - char cbuf[BUFSIZ]; char bufStartUpMsg[512]; struct sigaction sigAct; DEFiRet; - DBGPRINTF("rsyslog %s - called init()\n", VERSION); - - /* construct the default ruleset */ - ruleset.Construct(&pRuleset); - ruleset.SetName(pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset")); - ruleset.ConstructFinalize(pRuleset); - - /* open the configuration file */ - localRet = conf.processConfFile(ConfFile); - CHKiRet(conf.GetNbrActActions(&iNbrActions)); - - if(localRet != RS_RET_OK) { - errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", ConfFile); - bHadConfigErr = 1; - } else if(iNbrActions == 0) { - errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no active actions configured. Inputs will " - "run, but no output whatsoever is created."); - bHadConfigErr = 1; - } - - if((localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) || iNbrActions == 0) { - /* rgerhards: this code is executed to set defaults when the - * config file could not be opened. We might think about - * abandoning the run in this case - but this, too, is not - * very clever... So we stick with what we have. - * We ignore any errors while doing this - we would be lost anyhow... - */ - errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!"); - - /* note: we previously used _POSIY_TTY_NAME_MAX+1, but this turned out to be - * too low on linux... :-S -- rgerhards, 2008-07-28 - */ - char szTTYNameBuf[128]; - rule_t *pRule = NULL; /* initialization to NULL is *vitally* important! */ - conf.cfline(UCHAR_CONSTANT("*.ERR\t" _PATH_CONSOLE), &pRule); - conf.cfline(UCHAR_CONSTANT("syslog.*\t" _PATH_CONSOLE), &pRule); - conf.cfline(UCHAR_CONSTANT("*.PANIC\t*"), &pRule); - conf.cfline(UCHAR_CONSTANT("syslog.*\troot"), &pRule); - if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) { - snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf); - conf.cfline((uchar*)cbuf, &pRule); - } else { - DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno); - } - ruleset.AddRule(ruleset.GetCurrent(), &pRule); - } - - legacyOptsHook(); - - /* some checks */ - if(iMainMsgQueueNumWorkers < 1) { - errmsg.LogError(0, NO_ERRCODE, "$MainMsgQueueNumWorkers must be at least 1! Set to 1.\n"); - iMainMsgQueueNumWorkers = 1; - } - - if(MainMsgQueType == QUEUETYPE_DISK) { - errno = 0; /* for logerror! */ - if(glbl.GetWorkDir() == NULL) { - errmsg.LogError(0, NO_ERRCODE, "No $WorkDirectory specified - can not run main message queue in 'disk' mode. " - "Using 'FixedArray' instead.\n"); - MainMsgQueType = QUEUETYPE_FIXED_ARRAY; - } - if(pszMainMsgQFName == NULL) { - errmsg.LogError(0, NO_ERRCODE, "No $MainMsgQueueFileName specified - can not run main message queue in " - "'disk' mode. Using 'FixedArray' instead.\n"); - MainMsgQueType = QUEUETYPE_FIXED_ARRAY; - } - } - - /* check if we need to generate a config DAG and, if so, do that */ - if(pszConfDAGFile != NULL) - generateConfigDAG(pszConfDAGFile); - - /* we are done checking the config - now validate if we should actually run or not. - * If not, terminate. -- rgerhards, 2008-07-25 - */ - if(iConfigVerify) { - if(bHadConfigErr) { - /* a bit dirty, but useful... */ - exit(1); - } - ABORT_FINALIZE(RS_RET_VALIDATION_RUN); - } - - if(bAbortOnUncleanConfig && bHadConfigErr) { - fprintf(stderr, "rsyslogd: $AbortOnUncleanConfig is set, and config is not clean.\n" - "Check error log for details, fix errors and restart. As a last\n" - "resort, you may want to remove $AbortOnUncleanConfig to permit a\n" - "startup with a dirty config.\n"); - exit(2); - } - - /* create message queue */ - CHKiRet_Hdlr(createMainQueue(&pMsgQueue, UCHAR_CONSTANT("main Q"))) { - /* no queue is fatal, we need to give up in that case... */ - fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet); - exit(1); - } - - bHaveMainQueue = (MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1; - 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 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(); - - if(Debug) { - dbgPrintInitInfo(); - } - memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); sigAct.sa_handler = sighup_handler; sigaction(SIGHUP, &sigAct, NULL); + CHKiRet(rsconf.Activate(ourConf)); DBGPRINTF(" started.\n"); /* we now generate the startup message. It now includes everything to * identify this instance. -- rgerhards, 2005-08-17 */ - if(bLogStatusMsgs) { + if(ourConf->globals.bLogStatusMsgs) { snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char), " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] start", @@ -1745,100 +1203,6 @@ finalize_it: } -/* Switch the default ruleset (that, what servcies bind to if nothing specific - * is specified). - * rgerhards, 2009-06-12 - */ -static rsRetVal -setDefaultRuleset(void __attribute__((unused)) *pVal, uchar *pszName) -{ - DEFiRet; - - CHKiRet(ruleset.SetDefaultRuleset(pszName)); - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - - -/* Put the rsyslog main thread to sleep for n seconds. This was introduced as - * a quick and dirty workaround for a privilege drop race in regard to listener - * startup, which itself was a result of the not-yet-done proper coding of - * privilege drop code (quite some effort). It may be useful for other occasions, too. - * is specified). - * rgerhards, 2009-06-12 - */ -static rsRetVal -putToSleep(void __attribute__((unused)) *pVal, int iNewVal) -{ - DEFiRet; - DBGPRINTF("rsyslog main thread put to sleep via $sleep %d directive...\n", iNewVal); - srSleep(iNewVal, 0); - DBGPRINTF("rsyslog main thread continues after $sleep %d\n", iNewVal); - RETiRet; -} - - -/* Switch to either an already existing rule set or start a new one. The - * named rule set becomes the new "current" rule set (what means that new - * actions are added to it). - * rgerhards, 2009-06-12 - */ -static rsRetVal -setCurrRuleset(void __attribute__((unused)) *pVal, uchar *pszName) -{ - ruleset_t *pRuleset; - rsRetVal localRet; - DEFiRet; - - localRet = ruleset.SetCurrRuleset(pszName); - - if(localRet == RS_RET_NOT_FOUND) { - DBGPRINTF("begin new current rule set '%s'\n", pszName); - CHKiRet(ruleset.Construct(&pRuleset)); - CHKiRet(ruleset.SetName(pRuleset, pszName)); - CHKiRet(ruleset.ConstructFinalize(pRuleset)); - } else { - ABORT_FINALIZE(localRet); - } - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - -/* set the main message queue mode - * rgerhards, 2008-01-03 - */ -static rsRetVal setMainMsgQueType(void __attribute__((unused)) *pVal, uchar *pszType) -{ - DEFiRet; - - if (!strcasecmp((char *) pszType, "fixedarray")) { - MainMsgQueType = QUEUETYPE_FIXED_ARRAY; - DBGPRINTF("main message queue type set to FIXED_ARRAY\n"); - } else if (!strcasecmp((char *) pszType, "linkedlist")) { - MainMsgQueType = QUEUETYPE_LINKEDLIST; - DBGPRINTF("main message queue type set to LINKEDLIST\n"); - } else if (!strcasecmp((char *) pszType, "disk")) { - MainMsgQueType = QUEUETYPE_DISK; - DBGPRINTF("main message queue type set to DISK\n"); - } else if (!strcasecmp((char *) pszType, "direct")) { - MainMsgQueType = QUEUETYPE_DIRECT; - DBGPRINTF("main message queue type set to DIRECT (no queueing at all)\n"); - } else { - errmsg.LogError(0, RS_RET_INVALID_PARAMS, "unknown mainmessagequeuetype parameter: %s", (char *) pszType); - iRet = RS_RET_INVALID_PARAMS; - } - free(pszType); /* no longer needed */ - - RETiRet; -} - - /* * The following function is resposible for handling a SIGHUP signal. Since * we are now doing mallocs/free as part of init we had better not being @@ -1900,7 +1264,7 @@ doHUP(void) { char buf[512]; - if(bLogStatusMsgs) { + if(ourConf->globals.bLogStatusMsgs) { snprintf(buf, sizeof(buf) / sizeof(char), " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] rsyslogd was HUPed", @@ -1909,7 +1273,7 @@ doHUP(void) logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0); } - ruleset.IterateAllActions(doHUPActions, NULL); + ruleset.IterateAllActions(ourConf, doHUPActions, NULL); } @@ -1939,7 +1303,7 @@ mainloop(void) * powertop, for example). In that case, we primarily wait for a signal, * but a once-a-day wakeup should be quite acceptable. -- rgerhards, 2008-06-09 */ - tvSelectTimeout.tv_sec = (bReduceRepeatMsgs == 1) ? TIMERINTVL : 86400 /*1 day*/; + tvSelectTimeout.tv_sec = (runConf->globals.bReduceRepeatMsgs == 1) ? TIMERINTVL : 86400 /*1 day*/; //tvSelectTimeout.tv_sec = TIMERINTVL; /* TODO: change this back to the above code when we have a better solution for apc */ tvSelectTimeout.tv_usec = 0; select(1, NULL, NULL, NULL, &tvSelectTimeout); @@ -1967,7 +1331,7 @@ mainloop(void) * for the time being, I think the remaining risk can be accepted. * rgerhards, 2008-01-10 */ - if(bReduceRepeatMsgs == 1) + if(runConf->globals.bReduceRepeatMsgs == 1) doFlushRptdMsgs(); if(bHadHUP) { @@ -1980,119 +1344,6 @@ mainloop(void) ENDfunc } - -/* load build-in modules - * very first version begun on 2007-07-23 by rgerhards - */ -static rsRetVal loadBuildInModules(void) -{ - DEFiRet; - - if((iRet = module.doModInit(modInitFile, UCHAR_CONSTANT("builtin-file"), NULL)) != RS_RET_OK) { - RETiRet; - } - if((iRet = module.doModInit(modInitPipe, UCHAR_CONSTANT("builtin-pipe"), NULL)) != RS_RET_OK) { - RETiRet; - } -#ifdef SYSLOG_INET - if((iRet = module.doModInit(modInitFwd, UCHAR_CONSTANT("builtin-fwd"), NULL)) != RS_RET_OK) { - RETiRet; - } -#endif - if((iRet = module.doModInit(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL)) != RS_RET_OK) { - RETiRet; - } - if((iRet = module.doModInit(modInitDiscard, UCHAR_CONSTANT("builtin-discard"), NULL)) != RS_RET_OK) { - RETiRet; - } - - /* dirty, but this must be for the time being: the usrmsg module must always be - * loaded as last module. This is because it processes any type of action selector. - * If we load it before other modules, these others will never have a chance of - * working with the config file. We may change that implementation so that a user name - * must start with an alnum, that would definitely help (but would it break backwards - * compatibility?). * rgerhards, 2007-07-23 - * User names now must begin with: - * [a-zA-Z0-9_.] - */ - CHKiRet(module.doModInit(modInitUsrMsg, (uchar*) "builtin-usrmsg", NULL)); - - /* load build-in parser modules */ - CHKiRet(module.doModInit(modInitpmrfc5424, UCHAR_CONSTANT("builtin-pmrfc5424"), NULL)); - CHKiRet(module.doModInit(modInitpmrfc3164, UCHAR_CONSTANT("builtin-pmrfc3164"), NULL)); - - /* and set default parser modules (order is *very* important, legacy (3164) parse needs to go last! */ - CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc5424"))); - CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc3164"))); - - /* load build-in strgen modules */ - CHKiRet(module.doModInit(modInitsmfile, UCHAR_CONSTANT("builtin-smfile"), NULL)); - CHKiRet(module.doModInit(modInitsmtradfile, UCHAR_CONSTANT("builtin-smtradfile"), NULL)); - CHKiRet(module.doModInit(modInitsmfwd, UCHAR_CONSTANT("builtin-smfwd"), NULL)); - CHKiRet(module.doModInit(modInitsmtradfwd, UCHAR_CONSTANT("builtin-smtradfwd"), NULL)); - - /* ok, initialization of the command handler probably does not 100% belong right in - * this space here. However, with the current design, this is actually quite a good - * place to put it. We might decide to shuffle it around later, but for the time - * being, the code has found its home here. A not-just-sideeffect of this decision - * is that rsyslog will terminate if we can not register our built-in config commands. - * This, I think, is the right thing to do. -- rgerhards, 2007-07-31 - */ - CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary, NULL, &bLogStatusMsgs, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, setDefaultRuleset, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, setCurrRuleset, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrInt, putToSleep, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszMainMsgQFName, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, NULL, &iMainMsgQueueSize, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQHighWtrMark, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuelowwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQLowWtrMark, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardmark", 0, eCmdHdlrInt, NULL, &iMainMsgQDiscardMark, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardseverity", 0, eCmdHdlrSeverity, NULL, &iMainMsgQDiscardSeverity, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuecheckpointinterval", 0, eCmdHdlrInt, NULL, &iMainMsgQPersistUpdCnt, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesyncqueuefiles", 0, eCmdHdlrBinary, NULL, &bMainMsgQSyncQeueFiles, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetype", 0, eCmdHdlrGetWord, setMainMsgQueType, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreads", 0, eCmdHdlrInt, NULL, &iMainMsgQueueNumWorkers, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutshutdown", 0, eCmdHdlrInt, NULL, &iMainMsgQtoQShutdown, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutactioncompletion", 0, eCmdHdlrInt, NULL, &iMainMsgQtoActShutdown, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutenqueue", 0, eCmdHdlrInt, NULL, &iMainMsgQtoEnq, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt, NULL, &iMainMsgQtoWrkShutdown, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeueslowdown", 0, eCmdHdlrInt, NULL, &iMainMsgQDeqSlowdown, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreadminimummessages", 0, eCmdHdlrInt, NULL, &iMainMsgQWrkMinMsgs, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxfilesize", 0, eCmdHdlrSize, NULL, &iMainMsgQueMaxFileSize, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuebatchsize", 0, eCmdHdlrSize, NULL, &iMainMsgQueDeqBatchSize, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxdiskspace", 0, eCmdHdlrSize, NULL, &iMainMsgQueMaxDiskSpace, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesaveonshutdown", 0, eCmdHdlrBinary, NULL, &bMainMsgQSaveOnShutdown, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimebegin", 0, eCmdHdlrInt, NULL, &iMainMsgQueueDeqtWinFromHr, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimeend", 0, eCmdHdlrInt, NULL, &iMainMsgQueueDeqtWinToHr, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"abortonuncleanconfig", 0, eCmdHdlrBinary, NULL, &bAbortOnUncleanConfig, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary, NULL, &bReduceRepeatMsgs, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_TEMPLATE, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"allowedsender", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_ALLOWEDSENDER, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, conf.doModLoad, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, conf.doIncludeLine, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode, setUmask, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"maxopenfiles", 0, eCmdHdlrInt, setMaxFiles, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary, NULL, &bDebugPrintTemplateList, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"debugprintmodulelist", 0, eCmdHdlrBinary, NULL, &bDebugPrintModuleList, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"debugprintcfsyslinehandlerlist", 0, eCmdHdlrBinary, - NULL, &bDebugPrintCfSysLineHandlerList, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord, NULL, &pModDir, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"generateconfiggraph", 0, eCmdHdlrGetWord, NULL, &pszConfDAGFile, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, NULL, &bErrMsgToStderr, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID, NULL, &uidDropPriv, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouserid", 0, eCmdHdlrInt, NULL, &uidDropPriv, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID, NULL, &gidDropPriv, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroupid", 0, eCmdHdlrGID, NULL, &gidDropPriv, NULL)); - -finalize_it: - RETiRet; -} - - /* print version and compile-time setting information. */ static void printVersion(void) @@ -2138,93 +1389,6 @@ static void printVersion(void) } -/* This function is called after initial initalization. It is used to - * move code out of the too-long main() function. - * rgerhards, 2007-10-17 - */ -static rsRetVal mainThread() -{ - DEFiRet; - uchar *pTmp; - - /* initialize the build-in templates */ - pTmp = template_DebugFormat; - tplAddLine("RSYSLOG_DebugFormat", &pTmp); - pTmp = template_SyslogProtocol23Format; - tplAddLine("RSYSLOG_SyslogProtocol23Format", &pTmp); - pTmp = template_FileFormat; /* new format for files with high-precision stamp */ - tplAddLine("RSYSLOG_FileFormat", &pTmp); - pTmp = template_TraditionalFileFormat; - tplAddLine("RSYSLOG_TraditionalFileFormat", &pTmp); - pTmp = template_WallFmt; - tplAddLine(" WallFmt", &pTmp); - pTmp = template_ForwardFormat; - tplAddLine("RSYSLOG_ForwardFormat", &pTmp); - pTmp = template_TraditionalForwardFormat; - tplAddLine("RSYSLOG_TraditionalForwardFormat", &pTmp); - pTmp = template_StdUsrMsgFmt; - tplAddLine(" StdUsrMsgFmt", &pTmp); - pTmp = template_StdDBFmt; - tplAddLine(" StdDBFmt", &pTmp); - pTmp = template_StdPgSQLFmt; - tplAddLine(" StdPgSQLFmt", &pTmp); - pTmp = template_spoofadr; - tplLastStaticInit(tplAddLine("RSYSLOG_omudpspoofDfltSourceTpl", &pTmp)); - - CHKiRet(init()); - - 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) - kill(ppid, SIGTERM); - - - /* If instructed to do so, we now drop privileges. Note that this is not 100% secure, - * 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 - * we should do over time. TODO -- rgerhards, 2008-11-19 - */ - if(gidDropPriv != 0) { - doDropPrivGid(gidDropPriv); - } - - if(uidDropPriv != 0) { - doDropPrivUid(uidDropPriv); - } - - /* finally let the inputs run... */ - runInputModules(); - - /* END OF INTIALIZATION - */ - 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 == DEBUG_FULL || NoFork)) { - close(1); - close(2); - bErrMsgToStderr = 0; - } - - mainloop(); - -finalize_it: - RETiRet; -} - - /* Method to initialize all global classes and use the objects that we need. * rgerhards, 2008-01-04 * rgerhards, 2008-04-16: the actual initialization is now carried out by the runtime @@ -2249,8 +1413,6 @@ InitGlobalClasses(void) CHKiRet(objUse(module, CORE_COMPONENT)); pErrObj = "datetime"; CHKiRet(objUse(datetime, CORE_COMPONENT)); - pErrObj = "expr"; - CHKiRet(objUse(expr, CORE_COMPONENT)); pErrObj = "rule"; CHKiRet(objUse(rule, CORE_COMPONENT)); pErrObj = "ruleset"; @@ -2261,6 +1423,8 @@ InitGlobalClasses(void) CHKiRet(objUse(prop, CORE_COMPONENT)); pErrObj = "parser"; CHKiRet(objUse(parser, CORE_COMPONENT)); + pErrObj = "rsconf"; + CHKiRet(objUse(rsconf, CORE_COMPONENT)); /* intialize some dummy classes that are not part of the runtime */ pErrObj = "action"; @@ -2271,6 +1435,7 @@ InitGlobalClasses(void) /* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */ pErrObj = "net"; CHKiRet(objUse(net, LM_NET_FILENAME)); + dnscacheInit(); finalize_it: if(iRet != RS_RET_OK) { @@ -2303,9 +1468,8 @@ GlobalClassExit(void) objRelease(conf, CORE_COMPONENT); objRelease(ruleset, CORE_COMPONENT); objRelease(rule, CORE_COMPONENT); - objRelease(expr, CORE_COMPONENT); - vmClassExit(); /* this is hack, currently core_modules do not get this automatically called */ parserClassExit(); /* this is hack, currently core_modules do not get this automatically called */ + rsconfClassExit(); /* this is hack, currently core_modules do not get this automatically called */ objRelease(datetime, CORE_COMPONENT); /* TODO: implement the rest of the deinit */ @@ -2318,6 +1482,7 @@ GlobalClassExit(void) CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); #endif + dnscacheDeinit(); rsrtExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */ RETiRet; @@ -2523,23 +1688,21 @@ doGlblProcessInit(void) */ int realMain(int argc, char **argv) { - DEFiRet; - + rsRetVal localRet; register uchar *p; int ch; struct hostent *hent; extern int optind; extern char *optarg; int bEOptionWasGiven = 0; - int bImUxSockLoaded = 0; /* already generated a $ModLoad imuxsock? */ int iHelperUOpt; int bChDirRoot = 1; /* change the current working directory to "/"? */ char *arg; /* for command line option processing */ - uchar legacyConfLine[80]; uchar *LocalHostName; uchar *LocalDomain; uchar *LocalFQDNName; char cwdbuf[128]; /* buffer to obtain/display current working directory */ + DEFiRet; /* first, parse the command line options. We do not carry out any actual work, just * see what we should do. This relieves us from certain anomalies and we can process @@ -2577,6 +1740,9 @@ int realMain(int argc, char **argv) case 'u': /* misc user settings */ case 'w': /* disable disallowed host warnings */ case 'x': /* disable dns for remote messages */ + case 'g': /* enable tcp gssapi logging */ + case 'r': /* accept remote messages */ + case 't': /* enable tcp logging */ CHKiRet(bufOptAdd(ch, optarg)); break; case 'c': /* compatibility mode */ @@ -2587,37 +1753,15 @@ int realMain(int argc, char **argv) Debug = 1; break; case 'e': /* log every message (no repeat message supression) */ - fprintf(stderr, "note: -e option is no longer supported, every message is now logged by default\n"); bEOptionWasGiven = 1; break; - case 'g': /* enable tcp gssapi logging */ -#if defined(SYSLOG_INET) && defined(USE_GSSAPI) - CHKiRet(bufOptAdd('g', optarg)); -#else - fprintf(stderr, "rsyslogd: -g not valid - not compiled with gssapi support"); -#endif - break; case 'M': /* default module load path -- this MUST be carried out immediately! */ glblModPath = (uchar*) optarg; break; - case 'r': /* accept remote messages */ -#ifdef SYSLOG_INET - CHKiRet(bufOptAdd(ch, optarg)); -#else - fprintf(stderr, "rsyslogd: -r not valid - not compiled with network support\n"); -#endif - break; - case 't': /* enable tcp logging */ -#ifdef SYSLOG_INET - CHKiRet(bufOptAdd(ch, optarg)); -#else - fprintf(stderr, "rsyslogd: -t not valid - not compiled with network support\n"); -#endif - break; case 'v': /* MUST be carried out immediately! */ printVersion(); exit(0); /* exit for -v option - so this is a "good one" */ - case '?': + case '?': default: usage(); } @@ -2730,11 +1874,6 @@ int realMain(int argc, char **argv) exit(1); /* "good" exit, leaving at init for fatal error */ } - if((iRet = loadBuildInModules()) != RS_RET_OK) { - fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n", - iRet); - exit(1); /* "good" exit, leaving at init for fatal error */ - } /* END core initializations - we now come back to carrying out command line options*/ @@ -2751,32 +1890,15 @@ int realMain(int argc, char **argv) send_to_all++; break; case 'a': - if(iCompatibilityMode < 3) { - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - bImUxSockLoaded = 1; - } - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "addunixlistensocket %s", arg); - legacyOptsEnq(legacyConfLine); - } else { - fprintf(stderr, "error -a is no longer supported, use module imuxsock instead"); - } + fprintf(stderr, "rsyslogd: error -a is no longer supported, use module imuxsock instead"); break; case 'f': /* configuration file */ ConfFile = (uchar*) arg; break; case 'g': /* enable tcp gssapi logging */ - if(iCompatibilityMode < 3) { - legacyOptsParseTCP(ch, arg); - } else - fprintf(stderr, "-g option only supported in compatibility modes 0 to 2 - ignored\n"); - break; + fprintf(stderr, "rsyslogd: -g option no longer supported - ignored\n"); case 'h': - if(iCompatibilityMode < 3) { - errmsg.LogError(0, NO_ERRCODE, "WARNING: -h option is no longer supported - ignored"); - } else { - usage(); /* for v3 and above, it simply is an error */ - } + fprintf(stderr, "rsyslogd: error -h is no longer supported - ignored"); break; case 'i': /* pid file name */ PidFile = arg; @@ -2789,11 +1911,7 @@ int realMain(int argc, char **argv) } break; case 'm': /* mark interval */ - if(iCompatibilityMode < 3) { - MarkInterval = atoi(arg) * 60; - } else - fprintf(stderr, - "-m option only supported in compatibility modes 0 to 2 - ignored\n"); + fprintf(stderr, "rsyslogd: error -m is no longer supported - use immark instead"); break; case 'n': /* don't fork */ NoFork = 1; @@ -2802,27 +1920,10 @@ int realMain(int argc, char **argv) iConfigVerify = atoi(arg); break; case 'o': - if(iCompatibilityMode < 3) { - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - bImUxSockLoaded = 1; - } - legacyOptsEnq((uchar *) "OmitLocalLogging"); - } else { - fprintf(stderr, "error -o is no longer supported, use module imuxsock instead"); - } + fprintf(stderr, "error -o is no longer supported, use module imuxsock instead"); break; case 'p': - if(iCompatibilityMode < 3) { - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - bImUxSockLoaded = 1; - } - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "SystemLogSocketName %s", arg); - legacyOptsEnq(legacyConfLine); - } else { - fprintf(stderr, "error -p is no longer supported, use module imuxsock instead"); - } + fprintf(stderr, "error -p is no longer supported, use module imuxsock instead"); break; case 'q': /* add hostname if DNS resolving has failed */ *(net.pACLAddHostnameOnFail) = 1; @@ -2831,12 +1932,7 @@ int realMain(int argc, char **argv) *(net.pACLDontResolve) = 1; break; case 'r': /* accept remote messages */ - if(iCompatibilityMode < 3) { - legacyOptsEnq((uchar *) "ModLoad imudp"); - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "UDPServerRun %s", arg); - legacyOptsEnq(legacyConfLine); - } else - fprintf(stderr, "-r option only supported in compatibility modes 0 to 2 - ignored\n"); + fprintf(stderr, "rsyslogd: error option -r is no longer supported - ignored"); break; case 's': if(glbl.GetStripDomains() != NULL) { @@ -2846,10 +1942,7 @@ int realMain(int argc, char **argv) } break; case 't': /* enable tcp logging */ - if(iCompatibilityMode < 3) { - legacyOptsParseTCP(ch, arg); - } else - fprintf(stderr, "-t option only supported in compatibility modes 0 to 2 - ignored\n"); + fprintf(stderr, "rsyslogd: error option -t is no longer supported - ignored"); break; case 'T':/* chroot() immediately at program startup, but only for testing, NOT security yet */ if(chroot(arg) != 0) { @@ -2884,32 +1977,30 @@ int realMain(int argc, char **argv) VERSION, iConfigVerify, ConfFile); } + localRet = rsconf.Load(&ourConf, ConfFile); + if(localRet == RS_RET_NONFATAL_CONFIG_ERR) { + if(loadConf->globals.bAbortOnUncleanConfig) { + fprintf(stderr, "rsyslogd: $AbortOnUncleanConfig is set, and config is not clean.\n" + "Check error log for details, fix errors and restart. As a last\n" + "resort, you may want to remove $AbortOnUncleanConfig to permit a\n" + "startup with a dirty config.\n"); + exit(2); + } + if(iConfigVerify) { + /* a bit dirty, but useful... */ + exit(1); + } + localRet = RS_RET_OK; + } + CHKiRet(localRet); + if(bChDirRoot) { if(chdir("/") != 0) fprintf(stderr, "Can not do 'cd /' - still trying to run\n"); } - /* process compatibility mode settings */ - if(iCompatibilityMode < 4) { - errmsg.LogError(0, NO_ERRCODE, "WARNING: rsyslogd is running in compatibility mode. Automatically " - "generated config directives may interfer with your rsyslog.conf settings. " - "We suggest upgrading your config and adding -c5 as the first " - "rsyslogd option."); - } - - if(iCompatibilityMode < 3) { - if(MarkInterval > 0) { - legacyOptsEnq((uchar *) "ModLoad immark"); - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "MarkMessagePeriod %d", MarkInterval); - legacyOptsEnq(legacyConfLine); - } - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - } - } - - if(bEOptionWasGiven && iCompatibilityMode < 3) { + if(bEOptionWasGiven) { errmsg.LogError(0, NO_ERRCODE, "WARNING: \"message repeated n times\" feature MUST be turned on in " "rsyslog.conf - CURRENTLY EVERY MESSAGE WILL BE LOGGED. Visit " "http://www.rsyslog.com/rptdmsgreduction to learn " @@ -2919,7 +2010,34 @@ int realMain(int argc, char **argv) if(!iConfigVerify) CHKiRet(doGlblProcessInit()); - CHKiRet(mainThread()); + CHKiRet(init()); + + 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) + kill(ppid, SIGTERM); + + + /* END OF INTIALIZATION */ + 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 == DEBUG_FULL || NoFork)) { + close(1); + close(2); + ourConf->globals.bErrMsgToStderr = 0; + } + + mainloop(); /* do any de-init's that need to be done AFTER this comment */ @@ -2931,7 +2049,7 @@ finalize_it: if(iRet == RS_RET_VALIDATION_RUN) { fprintf(stderr, "rsyslogd: End of config validation run. Bye.\n"); } else if(iRet != RS_RET_OK) { - fprintf(stderr, "rsyslogd run failed with error %d (see rsyslog.h " + fprintf(stderr, "rsyslogd: run failed with error %d (see rsyslog.h " "or try http://www.rsyslog.com/e/%d to learn what that number means)\n", iRet, iRet*-1); } diff --git a/tools/syslogd.h b/tools/syslogd.h index a3323d1f..88bbd5f3 100644 --- a/tools/syslogd.h +++ b/tools/syslogd.h @@ -26,7 +26,6 @@ #include "template.h" #include "action.h" #include "linkedlist.h" -#include "expr.h" /* the following prototypes should go away once we have an input * module interface -- rgerhards, 2007-12-12 |