diff options
Diffstat (limited to 'runtime/glbl.c')
-rw-r--r-- | runtime/glbl.c | 1523 |
1 files changed, 1523 insertions, 0 deletions
diff --git a/runtime/glbl.c b/runtime/glbl.c new file mode 100644 index 0000000..6b4cb29 --- /dev/null +++ b/runtime/glbl.c @@ -0,0 +1,1523 @@ +/* glbl.c - this module holds global defintions and data items. + * These are shared among the runtime library. Their use should be + * limited to cases where it is actually needed. The main intension for + * implementing them was support for the transistion from v2 to v4 + * (with fully modular design), but it turned out that there may also + * be some other good use cases besides backwards-compatibility. + * + * Module begun 2008-04-16 by Rainer Gerhards + * + * Copyright 2008-2023 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include <stdlib.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <unistd.h> +#include <pthread.h> +#include <ctype.h> +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> + +#include "rsyslog.h" +#include "obj.h" +#include "unicode-helper.h" +#include "cfsysline.h" +#include "glbl.h" +#include "prop.h" +#include "atomic.h" +#include "errmsg.h" +#include "action.h" +#include "parserif.h" +#include "rainerscript.h" +#include "srUtils.h" +#include "operatingstate.h" +#include "net.h" +#include "rsconf.h" +#include "queue.h" +#include "dnscache.h" +#include "parser.h" +#include "timezones.h" + +/* some defaults */ +#ifndef DFLT_NETSTRM_DRVR +# define DFLT_NETSTRM_DRVR ((uchar*)"ptcp") +#endif + +/* static data */ +DEFobjStaticHelpers +DEFobjCurrIf(prop) +DEFobjCurrIf(net) + +/* static data + * For this object, these variables are obviously what makes the "meat" of the + * class... + */ + +static struct cnfobj *mainqCnfObj = NULL;/* main queue object, to be used later in startup sequence */ +static int bPreserveFQDN = 0; /* should FQDNs always be preserved? */ +static prop_t *propLocalIPIF = NULL;/* IP address to report for the local host (default is 127.0.0.1) */ +static int propLocalIPIF_set = 0; /* is propLocalIPIF already set? */ +static prop_t *propLocalHostName = NULL;/* our hostname as FQDN - read-only after startup */ +static prop_t *propLocalHostNameToDelete = NULL;/* see GenerateLocalHostName function hdr comment! */ +static uchar *LocalHostName = NULL;/* our hostname - read-only after startup, except HUP */ +static uchar *LocalHostNameOverride = NULL;/* user-overridden hostname - read-only after startup */ +static uchar *LocalFQDNName = NULL;/* our hostname as FQDN - read-only after startup, except HUP */ +static uchar *LocalDomain = NULL;/* our local domain name - read-only after startup, except HUP */ +static int iMaxLine = 8096; +int bTerminateInputs = 0; /* global switch that inputs shall terminate ASAP (1=> terminate) */ +int glblUnloadModules = 1; +char** glblDbgFiles = NULL; +size_t glblDbgFilesNum = 0; +int glblDbgWhitelist = 1; +int glblPermitCtlC = 0; + +pid_t glbl_ourpid; +#ifndef HAVE_ATOMIC_BUILTINS +DEF_ATOMIC_HELPER_MUT(mutTerminateInputs); +#endif +#ifdef USE_UNLIMITED_SELECT +static int iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); /* size of select() bitmask in bytes */ +#endif +static uchar *SourceIPofLocalClient = NULL; /* [ar] Source IP for local client to be used on multihomed host */ + +/* tables for interfacing with the v6 config system */ +static struct cnfparamdescr cnfparamdescr[] = { + { "workdirectory", eCmdHdlrString, 0 }, + { "operatingstatefile", eCmdHdlrString, 0 }, + { "dropmsgswithmaliciousdnsptrrecords", eCmdHdlrBinary, 0 }, + { "localhostname", eCmdHdlrGetWord, 0 }, + { "preservefqdn", eCmdHdlrBinary, 0 }, + { "debug.onshutdown", eCmdHdlrBinary, 0 }, + { "debug.logfile", eCmdHdlrString, 0 }, + { "debug.gnutls", eCmdHdlrNonNegInt, 0 }, + { "debug.unloadmodules", eCmdHdlrBinary, 0 }, + { "defaultnetstreamdrivercafile", eCmdHdlrString, 0 }, + { "defaultnetstreamdrivercrlfile", eCmdHdlrString, 0 }, + { "defaultnetstreamdriverkeyfile", eCmdHdlrString, 0 }, + { "defaultnetstreamdrivercertfile", eCmdHdlrString, 0 }, + { "defaultnetstreamdriver", eCmdHdlrString, 0 }, + { "netstreamdrivercaextrafiles", eCmdHdlrString, 0 }, + { "maxmessagesize", eCmdHdlrSize, 0 }, + { "oversizemsg.errorfile", eCmdHdlrGetWord, 0 }, + { "oversizemsg.report", eCmdHdlrBinary, 0 }, + { "oversizemsg.input.mode", eCmdHdlrGetWord, 0 }, + { "reportchildprocessexits", eCmdHdlrGetWord, 0 }, + { "action.reportsuspension", eCmdHdlrBinary, 0 }, + { "action.reportsuspensioncontinuation", eCmdHdlrBinary, 0 }, + { "parser.controlcharacterescapeprefix", eCmdHdlrGetChar, 0 }, + { "parser.droptrailinglfonreception", eCmdHdlrBinary, 0 }, + { "parser.escapecontrolcharactersonreceive", eCmdHdlrBinary, 0 }, + { "parser.spacelfonreceive", eCmdHdlrBinary, 0 }, + { "parser.escape8bitcharactersonreceive", eCmdHdlrBinary, 0}, + { "parser.escapecontrolcharactertab", eCmdHdlrBinary, 0}, + { "parser.escapecontrolcharacterscstyle", eCmdHdlrBinary, 0 }, + { "parser.parsehostnameandtag", eCmdHdlrBinary, 0 }, + { "parser.permitslashinprogramname", eCmdHdlrBinary, 0 }, + { "stdlog.channelspec", eCmdHdlrString, 0 }, + { "janitor.interval", eCmdHdlrPositiveInt, 0 }, + { "senders.reportnew", eCmdHdlrBinary, 0 }, + { "senders.reportgoneaway", eCmdHdlrBinary, 0 }, + { "senders.timeoutafter", eCmdHdlrPositiveInt, 0 }, + { "senders.keeptrack", eCmdHdlrBinary, 0 }, + { "inputs.timeout.shutdown", eCmdHdlrPositiveInt, 0 }, + { "privdrop.group.keepsupplemental", eCmdHdlrBinary, 0 }, + { "privdrop.group.id", eCmdHdlrPositiveInt, 0 }, + { "privdrop.group.name", eCmdHdlrGID, 0 }, + { "privdrop.user.id", eCmdHdlrPositiveInt, 0 }, + { "privdrop.user.name", eCmdHdlrUID, 0 }, + { "net.ipprotocol", eCmdHdlrGetWord, 0 }, + { "net.acladdhostnameonfail", eCmdHdlrBinary, 0 }, + { "net.aclresolvehostname", eCmdHdlrBinary, 0 }, + { "net.enabledns", eCmdHdlrBinary, 0 }, + { "net.permitACLwarning", eCmdHdlrBinary, 0 }, + { "abortonuncleanconfig", eCmdHdlrBinary, 0 }, + { "abortonfailedqueuestartup", eCmdHdlrBinary, 0 }, + { "variables.casesensitive", eCmdHdlrBinary, 0 }, + { "environment", eCmdHdlrArray, 0 }, + { "processinternalmessages", eCmdHdlrBinary, 0 }, + { "umask", eCmdHdlrFileCreateMode, 0 }, + { "security.abortonidresolutionfail", eCmdHdlrBinary, 0 }, + { "internal.developeronly.options", eCmdHdlrInt, 0 }, + { "internalmsg.ratelimit.interval", eCmdHdlrPositiveInt, 0 }, + { "internalmsg.ratelimit.burst", eCmdHdlrPositiveInt, 0 }, + { "internalmsg.severity", eCmdHdlrSeverity, 0 }, + { "errormessagestostderr.maxnumber", eCmdHdlrPositiveInt, 0 }, + { "shutdown.enable.ctlc", eCmdHdlrBinary, 0 }, + { "default.action.queue.timeoutshutdown", eCmdHdlrInt, 0 }, + { "default.action.queue.timeoutactioncompletion", eCmdHdlrInt, 0 }, + { "default.action.queue.timeoutenqueue", eCmdHdlrInt, 0 }, + { "default.action.queue.timeoutworkerthreadshutdown", eCmdHdlrInt, 0 }, + { "default.ruleset.queue.timeoutshutdown", eCmdHdlrInt, 0 }, + { "default.ruleset.queue.timeoutactioncompletion", eCmdHdlrInt, 0 }, + { "default.ruleset.queue.timeoutenqueue", eCmdHdlrInt, 0 }, + { "default.ruleset.queue.timeoutworkerthreadshutdown", eCmdHdlrInt, 0 }, + { "reverselookup.cache.ttl.default", eCmdHdlrNonNegInt, 0 }, + { "reverselookup.cache.ttl.enable", eCmdHdlrBinary, 0 }, + { "parser.supportcompressionextension", eCmdHdlrBinary, 0 }, + { "shutdown.queue.doublesize", eCmdHdlrBinary, 0 }, + { "debug.files", eCmdHdlrArray, 0 }, + { "debug.whitelist", eCmdHdlrBinary, 0 }, + { "libcapng.default", eCmdHdlrBinary, 0 }, + { "libcapng.enable", eCmdHdlrBinary, 0 }, +}; +static struct cnfparamblk paramblk = + { CNFPARAMBLK_VERSION, + sizeof(cnfparamdescr)/sizeof(struct cnfparamdescr), + cnfparamdescr + }; + +static struct cnfparamvals *cnfparamvals = NULL; +/* we need to support multiple calls into our param block, so we need + * to persist the current settings. Note that this must be re-set + * each time a new config load begins (TODO: create interface?) + */ + +int +glblGetMaxLine(rsconf_t *cnf) +{ + /* glblGetMaxLine might be invoked before our configuration exists */ + return((cnf != NULL) ? cnf->globals.iMaxLine : iMaxLine); +} + + +int +GetGnuTLSLoglevel(rsconf_t *cnf) +{ + return(cnf->globals.iGnuTLSLoglevel); +} + +/* define a macro for the simple properties' set and get functions + * (which are always the same). This is only suitable for pretty + * simple cases which require neither checks nor memory allocation. + */ +#define SIMP_PROP(nameFunc, nameVar, dataType) \ + SIMP_PROP_GET(nameFunc, nameVar, dataType) \ + SIMP_PROP_SET(nameFunc, nameVar, dataType) +#define SIMP_PROP_SET(nameFunc, nameVar, dataType) \ +static rsRetVal Set##nameFunc(dataType newVal) \ +{ \ + nameVar = newVal; \ + return RS_RET_OK; \ +} +#define SIMP_PROP_GET(nameFunc, nameVar, dataType) \ +static dataType Get##nameFunc(void) \ +{ \ + return(nameVar); \ +} + +SIMP_PROP(PreserveFQDN, bPreserveFQDN, int) +SIMP_PROP(mainqCnfObj, mainqCnfObj, struct cnfobj *) +#ifdef USE_UNLIMITED_SELECT +SIMP_PROP(FdSetSize, iFdSetSize, int) +#endif + +#undef SIMP_PROP +#undef SIMP_PROP_SET +#undef SIMP_PROP_GET + +/* This is based on the previous SIMP_PROP but as a getter it uses + * additional parameter specifying the configuration it belongs to. + * The setter uses loadConf + */ +#define SIMP_PROP(nameFunc, nameVar, dataType) \ + SIMP_PROP_GET(nameFunc, nameVar, dataType) \ + SIMP_PROP_SET(nameFunc, nameVar, dataType) +#define SIMP_PROP_SET(nameFunc, nameVar, dataType) \ +static rsRetVal Set##nameFunc(dataType newVal) \ +{ \ + loadConf->globals.nameVar = newVal; \ + return RS_RET_OK; \ +} +#define SIMP_PROP_GET(nameFunc, nameVar, dataType) \ +static dataType Get##nameFunc(rsconf_t *cnf) \ +{ \ + return(cnf->globals.nameVar); \ +} + +SIMP_PROP(DropMalPTRMsgs, bDropMalPTRMsgs, int) +SIMP_PROP(DisableDNS, bDisableDNS, int) +SIMP_PROP(ParserEscapeControlCharactersCStyle, parser.bParserEscapeCCCStyle, int) +SIMP_PROP(ParseHOSTNAMEandTAG, parser.bParseHOSTNAMEandTAG, int) +SIMP_PROP(OptionDisallowWarning, optionDisallowWarning, int) +/* We omit setter on purpose, because we want to customize it */ +SIMP_PROP_GET(DfltNetstrmDrvrCAF, pszDfltNetstrmDrvrCAF, uchar*) +SIMP_PROP_GET(DfltNetstrmDrvrCRLF, pszDfltNetstrmDrvrCRLF, uchar*) +SIMP_PROP_GET(DfltNetstrmDrvrCertFile, pszDfltNetstrmDrvrCertFile, uchar*) +SIMP_PROP_GET(DfltNetstrmDrvrKeyFile, pszDfltNetstrmDrvrKeyFile, uchar*) +SIMP_PROP_GET(NetstrmDrvrCAExtraFiles, pszNetstrmDrvrCAExtraFiles, uchar*) +SIMP_PROP_GET(ParserControlCharacterEscapePrefix, parser.cCCEscapeChar, uchar) +SIMP_PROP_GET(ParserDropTrailingLFOnReception, parser.bDropTrailingLF, int) +SIMP_PROP_GET(ParserEscapeControlCharactersOnReceive, parser.bEscapeCCOnRcv, int) +SIMP_PROP_GET(ParserSpaceLFOnReceive, parser.bSpaceLFOnRcv, int) +SIMP_PROP_GET(ParserEscape8BitCharactersOnReceive, parser.bEscape8BitChars, int) +SIMP_PROP_GET(ParserEscapeControlCharacterTab, parser.bEscapeTab, int) + +#undef SIMP_PROP +#undef SIMP_PROP_SET +#undef SIMP_PROP_GET + +/* return global input termination status + * rgerhards, 2009-07-20 + */ +static int GetGlobalInputTermState(void) +{ + return ATOMIC_FETCH_32BIT(&bTerminateInputs, &mutTerminateInputs); +} + + +/* set global termination state to "terminate". Note that this is a + * "once in a lifetime" action which can not be undone. -- gerhards, 2009-07-20 + */ +static void SetGlobalInputTermination(void) +{ + ATOMIC_STORE_1_TO_INT(&bTerminateInputs, &mutTerminateInputs); +} + + +/* set the local host IP address to a specific string. Helper to + * small set of functions. No checks done, caller must ensure it is + * ok to call. Most importantly, the IP address must not already have + * been set. -- rgerhards, 2012-03-21 + */ +static rsRetVal +storeLocalHostIPIF(uchar *myIP) +{ + DEFiRet; + if(propLocalIPIF != NULL) { + CHKiRet(prop.Destruct(&propLocalIPIF)); + } + CHKiRet(prop.Construct(&propLocalIPIF)); + CHKiRet(prop.SetString(propLocalIPIF, myIP, ustrlen(myIP))); + CHKiRet(prop.ConstructFinalize(propLocalIPIF)); + DBGPRINTF("rsyslog/glbl: using '%s' as localhost IP\n", myIP); +finalize_it: + RETiRet; +} + + +/* This function is used to set the IP address that is to be + * reported for the local host. Note that in order to ease things + * for the v6 config interface, we do not allow this to be set more + * than once. + * rgerhards, 2012-03-21 + */ +static rsRetVal +setLocalHostIPIF(void __attribute__((unused)) *pVal, uchar *pNewVal) +{ + uchar myIP[128]; + rsRetVal localRet; + DEFiRet; + + CHKiRet(objUse(net, CORE_COMPONENT)); + + if(propLocalIPIF_set) { + LogError(0, RS_RET_ERR, "$LocalHostIPIF is already set " + "and cannot be reset; place it at TOP OF rsyslog.conf!"); + ABORT_FINALIZE(RS_RET_ERR); + } + + localRet = net.GetIFIPAddr(pNewVal, AF_UNSPEC, myIP, (int) sizeof(myIP)); + if(localRet != RS_RET_OK) { + LogError(0, RS_RET_ERR, "$LocalHostIPIF: IP address for interface " + "'%s' cannnot be obtained - ignoring directive", pNewVal); + } else { + storeLocalHostIPIF(myIP); + } + + +finalize_it: + free(pNewVal); /* no longer needed -> is in prop! */ + RETiRet; +} + + +/* This function is used to set the global work directory name. + * It verifies that the provided directory actually exists and + * emits an error message if not. + * rgerhards, 2011-02-16 + */ +static rsRetVal setWorkDir(void __attribute__((unused)) *pVal, uchar *pNewVal) +{ + size_t lenDir; + int i; + struct stat sb; + DEFiRet; + + /* remove trailing slashes */ + lenDir = ustrlen(pNewVal); + i = lenDir - 1; + while(i > 0 && pNewVal[i] == '/') { + --i; + } + + if(i < 0) { + LogError(0, RS_RET_ERR_WRKDIR, "$WorkDirectory: empty value " + "- directive ignored"); + ABORT_FINALIZE(RS_RET_ERR_WRKDIR); + } + + if(i != (int) lenDir - 1) { + pNewVal[i+1] = '\0'; + LogError(0, RS_RET_WRN_WRKDIR, "$WorkDirectory: trailing slashes " + "removed, new value is '%s'", pNewVal); + } + + if(stat((char*) pNewVal, &sb) != 0) { + LogError(0, RS_RET_ERR_WRKDIR, "$WorkDirectory: %s can not be " + "accessed, probably does not exist - directive ignored", pNewVal); + ABORT_FINALIZE(RS_RET_ERR_WRKDIR); + } + + if(!S_ISDIR(sb.st_mode)) { + LogError(0, RS_RET_ERR_WRKDIR, "$WorkDirectory: %s not a directory - directive ignored", + pNewVal); + ABORT_FINALIZE(RS_RET_ERR_WRKDIR); + } + + free(loadConf->globals.pszWorkDir); + loadConf->globals.pszWorkDir = pNewVal; + +finalize_it: + RETiRet; +} + + +static rsRetVal +setDfltNetstrmDrvrCAF(void __attribute__((unused)) *pVal, uchar *pNewVal) { + DEFiRet; + FILE *fp; + free(loadConf->globals.pszDfltNetstrmDrvrCAF); + loadConf->globals.pszDfltNetstrmDrvrCAF = pNewVal; + fp = fopen((const char*)pNewVal, "r"); + if(fp == NULL) { + LogError(errno, RS_RET_NO_FILE_ACCESS, + "error: defaultnetstreamdrivercafile file '%s' " + "could not be accessed", pNewVal); + } else { + fclose(fp); + } + + RETiRet; +} + +static rsRetVal +setNetstrmDrvrCAExtraFiles(void __attribute__((unused)) *pVal, uchar *pNewVal) { + DEFiRet; + FILE *fp; + char* token; + int error = 0; + free(loadConf->globals.pszNetstrmDrvrCAExtraFiles); + + token = strtok((char*)pNewVal, ","); + // Here, fopen per strtok ... + while(token != NULL) { + fp = fopen((const char*)token, "r"); + if(fp == NULL) { + LogError(errno, RS_RET_NO_FILE_ACCESS, + "error: netstreamdrivercaextrafiles file '%s' " + "could not be accessed", token); + error = 1; + } else { + fclose(fp); + } + token = strtok(NULL, ","); + } + if(!error) { + loadConf->globals.pszNetstrmDrvrCAExtraFiles = pNewVal; + } else { + loadConf->globals.pszNetstrmDrvrCAExtraFiles = NULL; + } + RETiRet; +} + +static rsRetVal +setDfltNetstrmDrvrCRLF(void __attribute__((unused)) *pVal, uchar *pNewVal) { + DEFiRet; + FILE *fp; + free(loadConf->globals.pszDfltNetstrmDrvrCRLF); + loadConf->globals.pszDfltNetstrmDrvrCRLF = pNewVal; + fp = fopen((const char*)pNewVal, "r"); + if(fp == NULL) { + LogError(errno, RS_RET_NO_FILE_ACCESS, + "error: defaultnetstreamdrivercrlfile file '%s' " + "could not be accessed", pNewVal); + } else { + fclose(fp); + } + + RETiRet; +} + + +static rsRetVal +setDfltNetstrmDrvrCertFile(void __attribute__((unused)) *pVal, uchar *pNewVal) { + DEFiRet; + FILE *fp; + + free(loadConf->globals.pszDfltNetstrmDrvrCertFile); + loadConf->globals.pszDfltNetstrmDrvrCertFile = pNewVal; + fp = fopen((const char*)pNewVal, "r"); + if(fp == NULL) { + LogError(errno, RS_RET_NO_FILE_ACCESS, + "error: defaultnetstreamdrivercertfile '%s' " + "could not be accessed", pNewVal); + } else { + fclose(fp); + } + + RETiRet; +} + +static rsRetVal +setDfltNetstrmDrvrKeyFile(void __attribute__((unused)) *pVal, uchar *pNewVal) { + DEFiRet; + FILE *fp; + + free(loadConf->globals.pszDfltNetstrmDrvrKeyFile); + loadConf->globals.pszDfltNetstrmDrvrKeyFile = pNewVal; + fp = fopen((const char*)pNewVal, "r"); + if(fp == NULL) { + LogError(errno, RS_RET_NO_FILE_ACCESS, + "error: defaultnetstreamdriverkeyfile '%s' " + "could not be accessed", pNewVal); + } else { + fclose(fp); + } + + RETiRet; +} + +static rsRetVal +setDfltNetstrmDrvr(void __attribute__((unused)) *pVal, uchar *pNewVal) { + DEFiRet; + free(loadConf->globals.pszDfltNetstrmDrvr); + loadConf->globals.pszDfltNetstrmDrvr = pNewVal; + RETiRet; +} + +static rsRetVal +setParserControlCharacterEscapePrefix(void __attribute__((unused)) *pVal, uchar *pNewVal) { + DEFiRet; + loadConf->globals.parser.cCCEscapeChar = *pNewVal; + RETiRet; +} + +static rsRetVal +setParserDropTrailingLFOnReception(void __attribute__((unused)) *pVal, int pNewVal) { + DEFiRet; + loadConf->globals.parser.bDropTrailingLF = pNewVal; + RETiRet; +} + +static rsRetVal +setParserEscapeControlCharactersOnReceive(void __attribute__((unused)) *pVal, int pNewVal) { + DEFiRet; + loadConf->globals.parser.bEscapeCCOnRcv = pNewVal; + RETiRet; +} + +static rsRetVal +setParserSpaceLFOnReceive(void __attribute__((unused)) *pVal, int pNewVal) { + DEFiRet; + loadConf->globals.parser.bSpaceLFOnRcv = pNewVal; + RETiRet; +} + +static rsRetVal +setParserEscape8BitCharactersOnReceive(void __attribute__((unused)) *pVal, int pNewVal) { + DEFiRet; + loadConf->globals.parser.bEscape8BitChars = pNewVal; + RETiRet; +} + +static rsRetVal +setParserEscapeControlCharacterTab(void __attribute__((unused)) *pVal, int pNewVal) { + DEFiRet; + loadConf->globals.parser.bEscapeTab = pNewVal; + RETiRet; +} + +/* This function is used both by legacy and RainerScript conf. It is a real setter. */ +static void +setMaxLine(const int64_t iNew) +{ + if(iNew < 128) { + LogError(0, RS_RET_INVALID_VALUE, "maxMessageSize tried to set " + "to %lld, but cannot be less than 128 - set to 128 " + "instead", (long long) iNew); + loadConf->globals.iMaxLine = 128; + } else if(iNew > (int64_t) INT_MAX) { + LogError(0, RS_RET_INVALID_VALUE, "maxMessageSize larger than " + "INT_MAX (%d) - reduced to INT_MAX", INT_MAX); + loadConf->globals.iMaxLine = INT_MAX; + } else { + loadConf->globals.iMaxLine = (int) iNew; + } +} + + + +static rsRetVal +legacySetMaxMessageSize(void __attribute__((unused)) *pVal, int64_t iNew) +{ + setMaxLine(iNew); + return RS_RET_OK; +} + +static rsRetVal +setDebugFile(void __attribute__((unused)) *pVal, uchar *pNewVal) +{ + DEFiRet; + dbgSetDebugFile(pNewVal); + free(pNewVal); + RETiRet; +} + +static rsRetVal +setDebugLevel(void __attribute__((unused)) *pVal, int level) +{ + DEFiRet; + dbgSetDebugLevel(level); + dbgprintf("debug level %d set via config file\n", level); + dbgprintf("This is rsyslog version " VERSION "\n"); + RETiRet; +} + +static rsRetVal ATTR_NONNULL() +setOversizeMsgInputMode(const uchar *const mode) +{ + DEFiRet; + if(!strcmp((char*)mode, "truncate")) { + loadConf->globals.oversizeMsgInputMode = glblOversizeMsgInputMode_Truncate; + } else if(!strcmp((char*)mode, "split")) { + loadConf->globals.oversizeMsgInputMode = glblOversizeMsgInputMode_Split; + } else if(!strcmp((char*)mode, "accept")) { + loadConf->globals.oversizeMsgInputMode = glblOversizeMsgInputMode_Accept; + } else { + loadConf->globals.oversizeMsgInputMode = glblOversizeMsgInputMode_Truncate; + } + RETiRet; +} + +static rsRetVal ATTR_NONNULL() +setReportChildProcessExits(const uchar *const mode) +{ + DEFiRet; + if(!strcmp((char*)mode, "none")) { + loadConf->globals.reportChildProcessExits = REPORT_CHILD_PROCESS_EXITS_NONE; + } else if(!strcmp((char*)mode, "errors")) { + loadConf->globals.reportChildProcessExits = REPORT_CHILD_PROCESS_EXITS_ERRORS; + } else if(!strcmp((char*)mode, "all")) { + loadConf->globals.reportChildProcessExits = REPORT_CHILD_PROCESS_EXITS_ALL; + } else { + LogError(0, RS_RET_CONF_PARAM_INVLD, + "invalid value '%s' for global parameter reportChildProcessExits -- ignored", + mode); + iRet = RS_RET_CONF_PARAM_INVLD; + } + RETiRet; +} + +static int +getDefPFFamily(rsconf_t *cnf) +{ + return cnf->globals.iDefPFFamily; +} + +/* return our local IP. + * If no local IP is set, "127.0.0.1" is selected *and* set. This + * is an intensional side effect that we do in order to keep things + * consistent and avoid config errors (this will make us not accept + * setting the local IP address once a module has obtained it - so + * it forces the $LocalHostIPIF directive high up in rsyslog.conf) + * rgerhards, 2012-03-21 + */ +static prop_t* +GetLocalHostIP(void) +{ + assert(propLocalIPIF != NULL); + return(propLocalIPIF); +} + + +/* set our local hostname. Free previous hostname, if it was already set. + * Note that we do now do this in a thread. As such, the method here + * is NOT 100% clean. If we run into issues, we need to think about + * refactoring the whole way we handle the local host name processing. + * Possibly using a PROP might be the right solution then. + */ +static rsRetVal +SetLocalHostName(uchar *const newname) +{ + uchar *toFree; + if(LocalHostName == NULL || strcmp((const char*)LocalHostName, (const char*) newname)) { + toFree = LocalHostName; + LocalHostName = newname; + } else { + toFree = newname; + } + free(toFree); + return RS_RET_OK; +} + + +/* return our local hostname. if it is not set, "[localhost]" is returned + */ +uchar* +glblGetLocalHostName(void) +{ + uchar *pszRet; + + if(LocalHostNameOverride != NULL) { + pszRet = LocalHostNameOverride; + goto done; + } + + if(LocalHostName == NULL) + pszRet = (uchar*) "[localhost]"; + else { + if(GetPreserveFQDN() == 1) + pszRet = LocalFQDNName; + else + pszRet = LocalHostName; + } +done: + return(pszRet); +} + + +/* return the name of the file where oversize messages are written to + */ +uchar* +glblGetOversizeMsgErrorFile(rsconf_t *cnf) +{ + return cnf->globals.oversizeMsgErrorFile; +} + +const uchar* +glblGetOperatingStateFile(rsconf_t *cnf) +{ + return cnf->globals.operatingStateFile; +} + +/* return the mode with which oversize messages will be put forward + */ +int +glblGetOversizeMsgInputMode(rsconf_t *cnf) +{ + return cnf->globals.oversizeMsgInputMode; +} + +int +glblReportOversizeMessage(rsconf_t *cnf) +{ + return cnf->globals.reportOversizeMsg; +} + + +/* logs a message indicating that a child process has terminated. + * If name != NULL, prints it as the program name. + */ +void +glblReportChildProcessExit(rsconf_t *cnf, const uchar *name, pid_t pid, int status) +{ + DBGPRINTF("waitpid for child %ld returned status: %2.2x\n", (long) pid, status); + + if(cnf->globals.reportChildProcessExits == REPORT_CHILD_PROCESS_EXITS_NONE + || (cnf->globals.reportChildProcessExits == REPORT_CHILD_PROCESS_EXITS_ERRORS + && WIFEXITED(status) && WEXITSTATUS(status) == 0)) { + return; + } + + if(WIFEXITED(status)) { + int severity = WEXITSTATUS(status) == 0 ? LOG_INFO : LOG_WARNING; + if(name != NULL) { + LogMsg(0, NO_ERRCODE, severity, "program '%s' (pid %ld) exited with status %d", + name, (long) pid, WEXITSTATUS(status)); + } else { + LogMsg(0, NO_ERRCODE, severity, "child process (pid %ld) exited with status %d", + (long) pid, WEXITSTATUS(status)); + } + } else if(WIFSIGNALED(status)) { + if(name != NULL) { + LogMsg(0, NO_ERRCODE, LOG_WARNING, "program '%s' (pid %ld) terminated by signal %d", + name, (long) pid, WTERMSIG(status)); + } else { + LogMsg(0, NO_ERRCODE, LOG_WARNING, "child process (pid %ld) terminated by signal %d", + (long) pid, WTERMSIG(status)); + } + } +} + + +/* set our local domain name. Free previous domain, if it was already set. + */ +static rsRetVal +SetLocalDomain(uchar *newname) +{ + free(LocalDomain); + LocalDomain = newname; + return RS_RET_OK; +} + + +/* return our local hostname. if it is not set, "[localhost]" is returned + */ +static uchar* +GetLocalDomain(void) +{ + return LocalDomain; +} + + +/* generate the local hostname property. This must be done after the hostname info + * has been set as well as PreserveFQDN. + * rgerhards, 2009-06-30 + * NOTE: This function tries to avoid locking by not destructing the previous value + * immediately. This is so that current readers can continue to use the previous name. + * Otherwise, we would need to use read/write locks to protect the update process. + * In order to do so, we save the previous value and delete it when we are called again + * the next time. Note that this in theory is racy and can lead to a double-free. + * In practice, however, the window of exposure to trigger this is extremely short + * and as this functions is very infrequently being called (on HUP), the trigger + * condition for this bug is so highly unlikely that it never occurs in practice. + * Probably if you HUP rsyslog every few milliseconds, but who does that... + * To further reduce risk potential, we do only update the property when there + * actually is a hostname change, which makes it even less likely. + * rgerhards, 2013-10-28 + */ +static rsRetVal +GenerateLocalHostNameProperty(void) +{ + uchar *pszPrev; + int lenPrev; + prop_t *hostnameNew; + uchar *pszName; + DEFiRet; + + if(propLocalHostNameToDelete != NULL) + prop.Destruct(&propLocalHostNameToDelete); + + if(LocalHostNameOverride == NULL) { + if(LocalHostName == NULL) + pszName = (uchar*) "[localhost]"; + else { + if(GetPreserveFQDN() == 1) + pszName = LocalFQDNName; + else + pszName = LocalHostName; + } + } else { /* local hostname is overriden via config */ + pszName = LocalHostNameOverride; + } + DBGPRINTF("GenerateLocalHostName uses '%s'\n", pszName); + + if(propLocalHostName == NULL) + pszPrev = (uchar*)""; /* make sure strcmp() below does not match */ + else + prop.GetString(propLocalHostName, &pszPrev, &lenPrev); + + if(ustrcmp(pszPrev, pszName)) { + /* we need to update */ + CHKiRet(prop.Construct(&hostnameNew)); + CHKiRet(prop.SetString(hostnameNew, pszName, ustrlen(pszName))); + CHKiRet(prop.ConstructFinalize(hostnameNew)); + propLocalHostNameToDelete = propLocalHostName; + propLocalHostName = hostnameNew; + } + +finalize_it: + RETiRet; +} + + +/* return our local hostname as a string property + */ +static prop_t* +GetLocalHostNameProp(void) +{ + return(propLocalHostName); +} + + +static rsRetVal +SetLocalFQDNName(uchar *newname) +{ + free(LocalFQDNName); + LocalFQDNName = newname; + return RS_RET_OK; +} + +/* return the current localhost name as FQDN (requires FQDN to be set) + * TODO: we should set the FQDN ourselfs in here! + */ +static uchar* +GetLocalFQDNName(void) +{ + return(LocalFQDNName == NULL ? (uchar*) "[localhost]" : LocalFQDNName); +} + + +/* return the current working directory */ +static uchar* +GetWorkDir(rsconf_t *cnf) +{ + return(cnf->globals.pszWorkDir == NULL ? (uchar*) "" : cnf->globals.pszWorkDir); +} + +/* return the "raw" working directory, which means + * NULL if unset. + */ +const uchar * +glblGetWorkDirRaw(rsconf_t *cnf) +{ + return cnf->globals.pszWorkDir; +} + +/* return the current default netstream driver */ +static uchar* +GetDfltNetstrmDrvr(rsconf_t *cnf) +{ + return(cnf->globals.pszDfltNetstrmDrvr == NULL ? DFLT_NETSTRM_DRVR : cnf->globals.pszDfltNetstrmDrvr); +} + +/* [ar] Source IP for local client to be used on multihomed host */ +static rsRetVal +SetSourceIPofLocalClient(uchar *newname) +{ + if(SourceIPofLocalClient != NULL) { + free(SourceIPofLocalClient); } + SourceIPofLocalClient = newname; + return RS_RET_OK; +} + +static uchar* +GetSourceIPofLocalClient(void) +{ + return(SourceIPofLocalClient); +} + + +/* queryInterface function + * rgerhards, 2008-02-21 + */ +BEGINobjQueryInterface(glbl) +CODESTARTobjQueryInterface(glbl) + if(pIf->ifVersion != glblCURR_IF_VERSION) { /* check for current version, increment on each change */ + ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); + } + + /* ok, we have the right interface, so let's fill it + * Please note that we may also do some backwards-compatibility + * work here (if we can support an older interface version - that, + * of course, also affects the "if" above). + */ + pIf->GetWorkDir = GetWorkDir; + pIf->GenerateLocalHostNameProperty = GenerateLocalHostNameProperty; + pIf->GetLocalHostNameProp = GetLocalHostNameProp; + pIf->GetLocalHostIP = GetLocalHostIP; + pIf->SetGlobalInputTermination = SetGlobalInputTermination; + pIf->GetGlobalInputTermState = GetGlobalInputTermState; + pIf->GetSourceIPofLocalClient = GetSourceIPofLocalClient; /* [ar] */ + pIf->SetSourceIPofLocalClient = SetSourceIPofLocalClient; /* [ar] */ + pIf->GetDefPFFamily = getDefPFFamily; + pIf->GetDisableDNS = GetDisableDNS; + pIf->GetMaxLine = glblGetMaxLine; + pIf->GetOptionDisallowWarning = GetOptionDisallowWarning; + pIf->GetDfltNetstrmDrvrCAF = GetDfltNetstrmDrvrCAF; + pIf->GetDfltNetstrmDrvrCRLF = GetDfltNetstrmDrvrCRLF; + pIf->GetDfltNetstrmDrvrCertFile = GetDfltNetstrmDrvrCertFile; + pIf->GetDfltNetstrmDrvrKeyFile = GetDfltNetstrmDrvrKeyFile; + pIf->GetDfltNetstrmDrvr = GetDfltNetstrmDrvr; + pIf->GetNetstrmDrvrCAExtraFiles = GetNetstrmDrvrCAExtraFiles; + pIf->GetParserControlCharacterEscapePrefix = GetParserControlCharacterEscapePrefix; + pIf->GetParserDropTrailingLFOnReception = GetParserDropTrailingLFOnReception; + pIf->GetParserEscapeControlCharactersOnReceive = GetParserEscapeControlCharactersOnReceive; + pIf->GetParserSpaceLFOnReceive = GetParserSpaceLFOnReceive; + pIf->GetParserEscape8BitCharactersOnReceive = GetParserEscape8BitCharactersOnReceive; + pIf->GetParserEscapeControlCharacterTab = GetParserEscapeControlCharacterTab; + pIf->GetLocalHostName = glblGetLocalHostName; + pIf->SetLocalHostName = SetLocalHostName; +#define SIMP_PROP(name) \ + pIf->Get##name = Get##name; \ + pIf->Set##name = Set##name; + SIMP_PROP(PreserveFQDN); + SIMP_PROP(DropMalPTRMsgs); + SIMP_PROP(mainqCnfObj); + SIMP_PROP(LocalFQDNName) + SIMP_PROP(LocalDomain) + SIMP_PROP(ParserEscapeControlCharactersCStyle) + SIMP_PROP(ParseHOSTNAMEandTAG) +#ifdef USE_UNLIMITED_SELECT + SIMP_PROP(FdSetSize) +#endif +#undef SIMP_PROP +finalize_it: +ENDobjQueryInterface(glbl) + +/* Reset config variables to default values. + * rgerhards, 2008-04-17 + */ +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + free(loadConf->globals.pszDfltNetstrmDrvr); + loadConf->globals.pszDfltNetstrmDrvr = NULL; + free(loadConf->globals.pszDfltNetstrmDrvrCAF); + loadConf->globals.pszDfltNetstrmDrvrCAF = NULL; + free(loadConf->globals.pszDfltNetstrmDrvrCRLF); + loadConf->globals.pszDfltNetstrmDrvrCRLF = NULL; + free(loadConf->globals.pszDfltNetstrmDrvrKeyFile); + loadConf->globals.pszDfltNetstrmDrvrKeyFile = NULL; + free(loadConf->globals.pszDfltNetstrmDrvrCertFile); + loadConf->globals.pszDfltNetstrmDrvrCertFile = NULL; + free(LocalHostNameOverride); + LocalHostNameOverride = NULL; + free(loadConf->globals.oversizeMsgErrorFile); + loadConf->globals.oversizeMsgErrorFile = NULL; + loadConf->globals.oversizeMsgInputMode = glblOversizeMsgInputMode_Accept; + loadConf->globals.reportChildProcessExits = REPORT_CHILD_PROCESS_EXITS_ERRORS; + free(loadConf->globals.pszWorkDir); + loadConf->globals.pszWorkDir = NULL; + free((void*)loadConf->globals.operatingStateFile); + loadConf->globals.operatingStateFile = NULL; + loadConf->globals.bDropMalPTRMsgs = 0; + bPreserveFQDN = 0; + loadConf->globals.iMaxLine = 8192; + loadConf->globals.reportOversizeMsg = 1; + loadConf->globals.parser.cCCEscapeChar = '#'; + loadConf->globals.parser.bDropTrailingLF = 1; + loadConf->globals.parser.bEscapeCCOnRcv = 1; /* default is to escape control characters */ + loadConf->globals.parser.bSpaceLFOnRcv = 0; + loadConf->globals.parser.bEscape8BitChars = 0; /* default is not to escape control characters */ + loadConf->globals.parser.bEscapeTab = 1; /* default is to escape tab characters */ + loadConf->globals.parser.bParserEscapeCCCStyle = 0; +#ifdef USE_UNLIMITED_SELECT + iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); +#endif + return RS_RET_OK; +} + + +/* Prepare for new config + */ +void +glblPrepCnf(void) +{ + free(mainqCnfObj); + mainqCnfObj = NULL; + free(cnfparamvals); + cnfparamvals = NULL; +} + +/* handle the timezone() object. Each incarnation adds one additional + * zone info to the global table of time zones. + */ + +int +bs_arrcmp_glblDbgFiles(const void *s1, const void *s2) +{ + return strcmp((char*)s1, *(char**)s2); +} + + + +/* handle a global config object. Note that multiple global config statements + * are permitted (because of plugin support), so once we got a param block, + * we need to hold to it. + * rgerhards, 2011-07-19 + */ +void +glblProcessCnf(struct cnfobj *o) +{ + int i; + + cnfparamvals = nvlstGetParams(o->nvlst, ¶mblk, cnfparamvals); + if(cnfparamvals == NULL) { + LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing global " + "config parameters [global(...)]"); + goto done; + } + if(Debug) { + dbgprintf("glbl param blk after glblProcessCnf:\n"); + cnfparamsPrint(¶mblk, cnfparamvals); + } + + /* The next thing is a bit hackish and should be changed in higher + * versions. There are a select few parameters which we need to + * act on immediately. These are processed here. + */ + for(i = 0 ; i < paramblk.nParams ; ++i) { + if(!cnfparamvals[i].bUsed) + continue; + if(!strcmp(paramblk.descr[i].name, "processinternalmessages")) { + loadConf->globals.bProcessInternalMessages = (int) cnfparamvals[i].val.d.n; + cnfparamvals[i].bUsed = TRUE; + } else if(!strcmp(paramblk.descr[i].name, "internal.developeronly.options")) { + loadConf->globals.glblDevOptions = (uint64_t) cnfparamvals[i].val.d.n; + cnfparamvals[i].bUsed = TRUE; + } else if(!strcmp(paramblk.descr[i].name, "stdlog.channelspec")) { +#ifndef ENABLE_LIBLOGGING_STDLOG + LogError(0, RS_RET_ERR, "rsyslog wasn't " + "compiled with liblogging-stdlog support. " + "The 'stdlog.channelspec' parameter " + "is ignored. Note: the syslog API is used instead.\n"); +#else + loadConf->globals.stdlog_chanspec = (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + /* we need to re-open with the new channel */ + stdlog_close(loadConf->globals.stdlog_hdl); + loadConf->globals.stdlog_hdl = stdlog_open("rsyslogd", 0, STDLOG_SYSLOG, + (char*) loadConf->globals.stdlog_chanspec); + cnfparamvals[i].bUsed = TRUE; +#endif + } else if(!strcmp(paramblk.descr[i].name, "operatingstatefile")) { + if(loadConf->globals.operatingStateFile != NULL) { + LogError(errno, RS_RET_PARAM_ERROR, + "error: operatingStateFile already set to '%s' - " + "new value ignored", loadConf->globals.operatingStateFile); + } else { + loadConf->globals.operatingStateFile = + (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + osf_open(); + } + } else if(!strcmp(paramblk.descr[i].name, "security.abortonidresolutionfail")) { + loadConf->globals.abortOnIDResolutionFail = (int) cnfparamvals[i].val.d.n; + cnfparamvals[i].bUsed = TRUE; + } + } +done: return; +} + +/* Set mainq parameters. Note that when this is not called, we'll use the + * legacy parameter config. mainq parameters can only be set once. + */ +void +glblProcessMainQCnf(struct cnfobj *o) +{ + if(mainqCnfObj == NULL) { + mainqCnfObj = o; + } else { + LogError(0, RS_RET_ERR, "main_queue() object can only be specified " + "once - all but first ignored\n"); + } +} + +/* destruct the main q cnf object after it is no longer needed. This is + * also used to do some final checks. + */ +void +glblDestructMainqCnfObj(void) +{ + /* Only destruct if not NULL! */ + if (mainqCnfObj != NULL) { + nvlstChkUnused(mainqCnfObj->nvlst); + cnfobjDestruct(mainqCnfObj); + mainqCnfObj = NULL; + } +} + +static int +qs_arrcmp_glblDbgFiles(const void *s1, const void *s2) +{ + return strcmp(*((char**)s1), *((char**)s2)); +} + +/* set an environment variable */ +static rsRetVal +do_setenv(const char *const var) +{ + char varname[128]; + const char *val = var; + size_t i; + DEFiRet; + + for(i = 0 ; *val != '=' ; ++i, ++val) { + if(i == sizeof(varname)-i) { + parser_errmsg("environment variable name too long " + "[max %zu chars] or malformed entry: '%s'", + sizeof(varname)-1, var); + ABORT_FINALIZE(RS_RET_ERR_SETENV); + } + if(*val == '\0') { + parser_errmsg("environment variable entry is missing " + "equal sign (for value): '%s'", var); + ABORT_FINALIZE(RS_RET_ERR_SETENV); + } + varname[i] = *val; + } + varname[i] = '\0'; + ++val; + DBGPRINTF("do_setenv, var '%s', val '%s'\n", varname, val); + + if(setenv(varname, val, 1) != 0) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + parser_errmsg("error setting environment variable " + "'%s' to '%s': %s", varname, val, errStr); + ABORT_FINALIZE(RS_RET_ERR_SETENV); + } + + +finalize_it: + RETiRet; +} + + +/* This processes the "regular" parameters which are to be set after the + * config has been fully loaded. + */ +rsRetVal +glblDoneLoadCnf(void) +{ + int i; + unsigned char *cstr; + DEFiRet; + CHKiRet(objUse(net, CORE_COMPONENT)); + + sortTimezones(loadConf); + DBGPRINTF("Timezone information table (%d entries):\n", loadConf->timezones.ntzinfos); + displayTimezones(loadConf); + + if(cnfparamvals == NULL) + goto finalize_it; + + for(i = 0 ; i < paramblk.nParams ; ++i) { + if(!cnfparamvals[i].bUsed) + continue; + if(!strcmp(paramblk.descr[i].name, "workdirectory")) { + cstr = (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setWorkDir(NULL, cstr); + } else if(!strcmp(paramblk.descr[i].name, "libcapng.default")) { +#ifdef ENABLE_LIBCAPNG + loadConf->globals.bAbortOnFailedLibcapngSetup = (int) cnfparamvals[i].val.d.n; +#else + LogError(0, RS_RET_ERR, "rsyslog wasn't " + "compiled with libcap-ng support."); +#endif + } else if(!strcmp(paramblk.descr[i].name, "libcapng.enable")) { +#ifdef ENABLE_LIBCAPNG + loadConf->globals.bCapabilityDropEnabled = (int) cnfparamvals[i].val.d.n; +#else + LogError(0, RS_RET_ERR, "rsyslog wasn't " + "compiled with libcap-ng support."); +#endif + } else if(!strcmp(paramblk.descr[i].name, "variables.casesensitive")) { + const int val = (int) cnfparamvals[i].val.d.n; + fjson_global_do_case_sensitive_comparison(val); + DBGPRINTF("global/config: set case sensitive variables to %d\n", + val); + } else if(!strcmp(paramblk.descr[i].name, "localhostname")) { + free(LocalHostNameOverride); + LocalHostNameOverride = (uchar*) + es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + } else if(!strcmp(paramblk.descr[i].name, "defaultnetstreamdriverkeyfile")) { + cstr = (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setDfltNetstrmDrvrKeyFile(NULL, cstr); + } else if(!strcmp(paramblk.descr[i].name, "defaultnetstreamdrivercertfile")) { + cstr = (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setDfltNetstrmDrvrCertFile(NULL, cstr); + } else if(!strcmp(paramblk.descr[i].name, "defaultnetstreamdrivercafile")) { + cstr = (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setDfltNetstrmDrvrCAF(NULL, cstr); + } else if(!strcmp(paramblk.descr[i].name, "defaultnetstreamdrivercrlfile")) { + cstr = (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setDfltNetstrmDrvrCRLF(NULL, cstr); + } else if(!strcmp(paramblk.descr[i].name, "defaultnetstreamdriver")) { + cstr = (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setDfltNetstrmDrvr(NULL, cstr); + } else if(!strcmp(paramblk.descr[i].name, "netstreamdrivercaextrafiles")) { + cstr = (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setNetstrmDrvrCAExtraFiles(NULL, cstr); + } else if(!strcmp(paramblk.descr[i].name, "preservefqdn")) { + bPreserveFQDN = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, + "dropmsgswithmaliciousdnsptrrecords")) { + loadConf->globals.bDropMalPTRMsgs = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "action.reportsuspension")) { + loadConf->globals.bActionReportSuspension = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "action.reportsuspensioncontinuation")) { + loadConf->globals.bActionReportSuspensionCont = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "maxmessagesize")) { + setMaxLine(cnfparamvals[i].val.d.n); + } else if(!strcmp(paramblk.descr[i].name, "oversizemsg.errorfile")) { + free(loadConf->globals.oversizeMsgErrorFile); + loadConf->globals.oversizeMsgErrorFile = (uchar*)es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + } else if(!strcmp(paramblk.descr[i].name, "oversizemsg.report")) { + loadConf->globals.reportOversizeMsg = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "oversizemsg.input.mode")) { + const char *const tmp = es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setOversizeMsgInputMode((uchar*) tmp); + free((void*)tmp); + } else if(!strcmp(paramblk.descr[i].name, "reportchildprocessexits")) { + const char *const tmp = es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setReportChildProcessExits((uchar*) tmp); + free((void*)tmp); + } else if(!strcmp(paramblk.descr[i].name, "debug.onshutdown")) { + loadConf->globals.debugOnShutdown = (int) cnfparamvals[i].val.d.n; + LogError(0, RS_RET_OK, "debug: onShutdown set to %d", loadConf->globals.debugOnShutdown); + } else if(!strcmp(paramblk.descr[i].name, "debug.gnutls")) { + loadConf->globals.iGnuTLSLoglevel = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "debug.unloadmodules")) { + glblUnloadModules = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "parser.controlcharacterescapeprefix")) { + uchar* tmp = (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setParserControlCharacterEscapePrefix(NULL, tmp); + free(tmp); + } else if(!strcmp(paramblk.descr[i].name, "parser.droptrailinglfonreception")) { + const int tmp = (int) cnfparamvals[i].val.d.n; + setParserDropTrailingLFOnReception(NULL, tmp); + } else if(!strcmp(paramblk.descr[i].name, "parser.escapecontrolcharactersonreceive")) { + const int tmp = (int) cnfparamvals[i].val.d.n; + setParserEscapeControlCharactersOnReceive(NULL, tmp); + } else if(!strcmp(paramblk.descr[i].name, "parser.spacelfonreceive")) { + const int tmp = (int) cnfparamvals[i].val.d.n; + setParserSpaceLFOnReceive(NULL, tmp); + } else if(!strcmp(paramblk.descr[i].name, "parser.escape8bitcharactersonreceive")) { + const int tmp = (int) cnfparamvals[i].val.d.n; + setParserEscape8BitCharactersOnReceive(NULL, tmp); + } else if(!strcmp(paramblk.descr[i].name, "parser.escapecontrolcharactertab")) { + const int tmp = (int) cnfparamvals[i].val.d.n; + setParserEscapeControlCharacterTab(NULL, tmp); + } else if(!strcmp(paramblk.descr[i].name, "parser.escapecontrolcharacterscstyle")) { + const int tmp = (int) cnfparamvals[i].val.d.n; + SetParserEscapeControlCharactersCStyle(tmp); + } else if(!strcmp(paramblk.descr[i].name, "parser.parsehostnameandtag")) { + const int tmp = (int) cnfparamvals[i].val.d.n; + SetParseHOSTNAMEandTAG(tmp); + } else if(!strcmp(paramblk.descr[i].name, "parser.permitslashinprogramname")) { + loadConf->globals.parser.bPermitSlashInProgramname = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "debug.logfile")) { + if(pszAltDbgFileName == NULL) { + pszAltDbgFileName = es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + /* can actually happen if debug system also opened altdbg */ + if(altdbg != -1) { + close(altdbg); + } + if((altdbg = open(pszAltDbgFileName, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY + |O_CLOEXEC, S_IRUSR|S_IWUSR)) == -1) { + LogError(0, RS_RET_ERR, "debug log file '%s' could not be opened", + pszAltDbgFileName); + } + } + LogError(0, RS_RET_OK, "debug log file is '%s', fd %d", pszAltDbgFileName, altdbg); + } else if(!strcmp(paramblk.descr[i].name, "janitor.interval")) { + loadConf->globals.janitorInterval = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "net.ipprotocol")) { + char *proto = es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + if(!strcmp(proto, "unspecified")) { + loadConf->globals.iDefPFFamily = PF_UNSPEC; + } else if(!strcmp(proto, "ipv4-only")) { + loadConf->globals.iDefPFFamily = PF_INET; + } else if(!strcmp(proto, "ipv6-only")) { + loadConf->globals.iDefPFFamily = PF_INET6; + } else{ + LogError(0, RS_RET_ERR, "invalid net.ipprotocol " + "parameter '%s' -- ignored", proto); + } + free(proto); + } else if(!strcmp(paramblk.descr[i].name, "senders.reportnew")) { + loadConf->globals.reportNewSenders = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "senders.reportgoneaway")) { + loadConf->globals.reportGoneAwaySenders = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "senders.timeoutafter")) { + loadConf->globals.senderStatsTimeout = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "senders.keeptrack")) { + loadConf->globals.senderKeepTrack = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "inputs.timeout.shutdown")) { + loadConf->globals.inputTimeoutShutdown = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "privdrop.group.keepsupplemental")) { + loadConf->globals.gidDropPrivKeepSupplemental = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "privdrop.group.id")) { + loadConf->globals.gidDropPriv = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "privdrop.group.name")) { + loadConf->globals.gidDropPriv = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "privdrop.user.id")) { + loadConf->globals.uidDropPriv = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "privdrop.user.name")) { + loadConf->globals.uidDropPriv = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "security.abortonidresolutionfail")) { + loadConf->globals.abortOnIDResolutionFail = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "net.acladdhostnameonfail")) { + loadConf->globals.ACLAddHostnameOnFail = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "net.aclresolvehostname")) { + loadConf->globals.ACLDontResolve = !((int) cnfparamvals[i].val.d.n); + } else if(!strcmp(paramblk.descr[i].name, "net.enabledns")) { + SetDisableDNS(!((int) cnfparamvals[i].val.d.n)); + } else if(!strcmp(paramblk.descr[i].name, "net.permitwarning")) { + SetOptionDisallowWarning(!((int) cnfparamvals[i].val.d.n)); + } else if(!strcmp(paramblk.descr[i].name, "abortonuncleanconfig")) { + loadConf->globals.bAbortOnUncleanConfig = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "abortonfailedqueuestartup")) { + loadConf->globals.bAbortOnFailedQueueStartup = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "internalmsg.ratelimit.burst")) { + loadConf->globals.intMsgRateLimitBurst = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "internalmsg.ratelimit.interval")) { + loadConf->globals.intMsgRateLimitItv = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "internalmsg.severity")) { + loadConf->globals.intMsgsSeverityFilter = (int) cnfparamvals[i].val.d.n; + if((loadConf->globals.intMsgsSeverityFilter < 0) || + (loadConf->globals.intMsgsSeverityFilter > 7)) { + parser_errmsg("invalid internalmsg.severity value"); + loadConf->globals.intMsgsSeverityFilter = DFLT_INT_MSGS_SEV_FILTER; + } + } else if(!strcmp(paramblk.descr[i].name, "environment")) { + for(int j = 0 ; j < cnfparamvals[i].val.d.ar->nmemb ; ++j) { + char *const var = es_str2cstr(cnfparamvals[i].val.d.ar->arr[j], NULL); + do_setenv(var); + free(var); + } + } else if(!strcmp(paramblk.descr[i].name, "errormessagestostderr.maxnumber")) { + loadConf->globals.maxErrMsgToStderr = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "debug.files")) { + free(glblDbgFiles); /* "fix" Coverity false positive */ + glblDbgFilesNum = cnfparamvals[i].val.d.ar->nmemb; + glblDbgFiles = (char**) malloc(cnfparamvals[i].val.d.ar->nmemb * sizeof(char*)); + for(int j = 0 ; j < cnfparamvals[i].val.d.ar->nmemb ; ++j) { + glblDbgFiles[j] = es_str2cstr(cnfparamvals[i].val.d.ar->arr[j], NULL); + } + qsort(glblDbgFiles, glblDbgFilesNum, sizeof(char*), qs_arrcmp_glblDbgFiles); + } else if(!strcmp(paramblk.descr[i].name, "debug.whitelist")) { + glblDbgWhitelist = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "shutdown.queue.doublesize")) { + loadConf->globals.shutdownQueueDoubleSize = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "umask")) { + loadConf->globals.umask = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "shutdown.enable.ctlc")) { + loadConf->globals.permitCtlC = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "default.action.queue.timeoutshutdown")) { + loadConf->globals.actq_dflt_toQShutdown = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "default.action.queue.timeoutactioncompletion")) { + loadConf->globals.actq_dflt_toActShutdown = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "default.action.queue.timeoutenqueue")) { + loadConf->globals.actq_dflt_toEnq = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "default.action.queue.timeoutworkerthreadshutdown")) { + loadConf->globals.actq_dflt_toWrkShutdown = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "default.ruleset.queue.timeoutshutdown")) { + loadConf->globals.ruleset_dflt_toQShutdown = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "default.ruleset.queue.timeoutactioncompletion")) { + loadConf->globals.ruleset_dflt_toActShutdown = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "default.ruleset.queue.timeoutenqueue")) { + loadConf->globals.ruleset_dflt_toEnq = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "default.ruleset.queue.timeoutworkerthreadshutdown")) { + loadConf->globals.ruleset_dflt_toWrkShutdown = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "reverselookup.cache.ttl.default")) { + loadConf->globals.dnscacheDefaultTTL = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "reverselookup.cache.ttl.enable")) { + loadConf->globals.dnscacheEnableTTL = cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "parser.supportcompressionextension")) { + loadConf->globals.bSupportCompressionExtension = cnfparamvals[i].val.d.n; + } else { + dbgprintf("glblDoneLoadCnf: program error, non-handled " + "param '%s'\n", paramblk.descr[i].name); + } + } + + if(loadConf->globals.debugOnShutdown && Debug != DEBUG_FULL) { + Debug = DEBUG_ONDEMAND; + stddbg = -1; + } + +finalize_it: + /* we have now read the config. We need to query the local host name now + * as it was set by the config. + * + * Note: early messages are already emited, and have "[localhost]" as + * hostname. These messages are currently in iminternal queue. Once they + * are taken from that queue, the hostname will be adapted. + */ + queryLocalHostname(loadConf); + RETiRet; +} + + +/* Initialize the glbl class. Must be called as the very first method + * before anything else is called inside this class. + * rgerhards, 2008-02-19 + */ +BEGINAbstractObjClassInit(glbl, 1, OBJ_IS_CORE_MODULE) /* class, version */ + /* request objects we use */ + CHKiRet(objUse(prop, CORE_COMPONENT)); + + /* intialize properties */ + storeLocalHostIPIF((uchar*)"127.0.0.1"); + + /* config handlers are never unregistered and need not be - we are always loaded ;) */ + CHKiRet(regCfSysLineHdlr((uchar *)"debugfile", 0, eCmdHdlrGetWord, setDebugFile, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"debuglevel", 0, eCmdHdlrInt, setDebugLevel, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"workdirectory", 0, eCmdHdlrGetWord, setWorkDir, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"dropmsgswithmaliciousdnsptrrecords", 0, eCmdHdlrBinary, SetDropMalPTRMsgs, + NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriver", 0, eCmdHdlrGetWord, setDfltNetstrmDrvr, NULL, + NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercafile", 0, eCmdHdlrGetWord, + setDfltNetstrmDrvrCAF, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercrlfile", 0, eCmdHdlrGetWord, + setDfltNetstrmDrvrCRLF, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriverkeyfile", 0, eCmdHdlrGetWord, + setDfltNetstrmDrvrKeyFile, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercertfile", 0, eCmdHdlrGetWord, + setDfltNetstrmDrvrCertFile, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"localhostname", 0, eCmdHdlrGetWord, NULL, &LocalHostNameOverride, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"localhostipif", 0, eCmdHdlrGetWord, setLocalHostIPIF, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"netstreamdrivercaextrafiles", 0, eCmdHdlrGetWord, setNetstrmDrvrCAExtraFiles, + NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"optimizeforuniprocessor", 0, eCmdHdlrGoneAway, NULL, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"preservefqdn", 0, eCmdHdlrBinary, NULL, &bPreserveFQDN, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, legacySetMaxMessageSize, NULL, NULL)); + + /* Deprecated parser config options */ + CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, + setParserControlCharacterEscapePrefix, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, + setParserDropTrailingLFOnReception, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, + setParserEscapeControlCharactersOnReceive, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"spacelfonreceive", 0, eCmdHdlrBinary, + setParserSpaceLFOnReceive, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"escape8bitcharactersonreceive", 0, eCmdHdlrBinary, + setParserEscape8BitCharactersOnReceive, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactertab", 0, eCmdHdlrBinary, + setParserEscapeControlCharacterTab, NULL, NULL)); + + CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, + resetConfigVariables, NULL, NULL)); + + INIT_ATOMIC_HELPER_MUT(mutTerminateInputs); +ENDObjClassInit(glbl) + + +/* Exit the glbl class. + * rgerhards, 2008-04-17 + */ +BEGINObjClassExit(glbl, OBJ_IS_CORE_MODULE) /* class, version */ + free(LocalDomain); + free(LocalHostName); + free(LocalHostNameOverride); + free(LocalFQDNName); + objRelease(prop, CORE_COMPONENT); + if(propLocalHostNameToDelete != NULL) + prop.Destruct(&propLocalHostNameToDelete); + DESTROY_ATOMIC_HELPER_MUT(mutTerminateInputs); +ENDObjClassExit(glbl) |