diff --git a/SOURCES/rsyslog-8.2102.0-imtcp-param-refactor.patch b/SOURCES/rsyslog-8.2102.0-imtcp-param-refactor.patch new file mode 100644 index 0000000..224533e --- /dev/null +++ b/SOURCES/rsyslog-8.2102.0-imtcp-param-refactor.patch @@ -0,0 +1,908 @@ +diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c +index 3e27ee4d36..d57dd5661c 100644 +--- a/plugins/imdiag/imdiag.c ++++ b/plugins/imdiag/imdiag.c +@@ -566,28 +566,33 @@ setInjectDelayMode(void __attribute__((unused)) *pVal, uchar *const pszMode) + } + + +-static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVal) ++static rsRetVal ++addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVal) + { ++ tcpLstnParams_t *cnf_params = NULL; + DEFiRet; + +- if(pOurTcpsrv == NULL) { +- CHKiRet(tcpsrv.Construct(&pOurTcpsrv)); +- CHKiRet(tcpsrv.SetSessMax(pOurTcpsrv, iTCPSessMax)); +- CHKiRet(tcpsrv.SetCBIsPermittedHost(pOurTcpsrv, isPermittedHost)); +- CHKiRet(tcpsrv.SetCBRcvData(pOurTcpsrv, doRcvData)); +- CHKiRet(tcpsrv.SetCBOpenLstnSocks(pOurTcpsrv, doOpenLstnSocks)); +- CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose)); +- CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose)); +- CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, iStrmDrvrMode)); +- CHKiRet(tcpsrv.SetOnMsgReceive(pOurTcpsrv, OnMsgReceived)); +- CHKiRet(tcpsrv.SetLstnPortFileName(pOurTcpsrv, pszLstnPortFileName)); +- /* now set optional params, but only if they were actually configured */ +- if(pszStrmDrvrAuthMode != NULL) { +- CHKiRet(tcpsrv.SetDrvrAuthMode(pOurTcpsrv, pszStrmDrvrAuthMode)); +- } +- if(pPermPeersRoot != NULL) { +- CHKiRet(tcpsrv.SetDrvrPermPeers(pOurTcpsrv, pPermPeersRoot)); +- } ++ if(pOurTcpsrv != NULL) { ++ LogError(0, NO_ERRCODE, "imdiag: only a single listener is supported, " ++ "trying to add a second"); ++ ABORT_FINALIZE(RS_RET_ERR); ++ } ++ CHKmalloc(cnf_params = (tcpLstnParams_t*) calloc(1, sizeof(tcpLstnParams_t))); ++ CHKiRet(tcpsrv.Construct(&pOurTcpsrv)); ++ CHKiRet(tcpsrv.SetSessMax(pOurTcpsrv, iTCPSessMax)); ++ CHKiRet(tcpsrv.SetCBIsPermittedHost(pOurTcpsrv, isPermittedHost)); ++ CHKiRet(tcpsrv.SetCBRcvData(pOurTcpsrv, doRcvData)); ++ CHKiRet(tcpsrv.SetCBOpenLstnSocks(pOurTcpsrv, doOpenLstnSocks)); ++ CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose)); ++ CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose)); ++ CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, iStrmDrvrMode)); ++ CHKiRet(tcpsrv.SetOnMsgReceive(pOurTcpsrv, OnMsgReceived)); ++ /* now set optional params, but only if they were actually configured */ ++ if(pszStrmDrvrAuthMode != NULL) { ++ CHKiRet(tcpsrv.SetDrvrAuthMode(pOurTcpsrv, pszStrmDrvrAuthMode)); ++ } ++ if(pPermPeersRoot != NULL) { ++ CHKiRet(tcpsrv.SetDrvrPermPeers(pOurTcpsrv, pPermPeersRoot)); + } + + /* initialized, now add socket */ +@@ -595,7 +600,11 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa + UCHAR_CONSTANT("imdiag") : pszInputName)); + CHKiRet(tcpsrv.SetOrigin(pOurTcpsrv, (uchar*)"imdiag")); + /* we support octect-counted frame (constant 1 below) */ +- tcpsrv.configureTCPListen(pOurTcpsrv, pNewVal, 1, NULL, pszLstnPortFileName); ++ cnf_params->pszPort = pNewVal; ++ cnf_params->bSuppOctetFram = 1; ++ CHKmalloc(cnf_params->pszLstnPortFileName = (const uchar*) strdup((const char*)pszLstnPortFileName)); ++ tcpsrv.configureTCPListen(pOurTcpsrv, cnf_params); ++ cnf_params = NULL; + + finalize_it: + if(iRet != RS_RET_OK) { +@@ -603,7 +612,7 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa + if(pOurTcpsrv != NULL) + tcpsrv.Destruct(&pOurTcpsrv); + } +- free(pNewVal); ++ free(cnf_params); + RETiRet; + } + +@@ -760,6 +769,7 @@ CODESTARTmodExit + + /* free some globals to keep valgrind happy */ + free(pszInputName); ++fprintf(stderr, "FINAL FREE %p\n", pszLstnPortFileName); + free(pszLstnPortFileName); + free(pszStrmDrvrAuthMode); + +diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c +index e0cab01664..4041e88b14 100644 +--- a/plugins/imgssapi/imgssapi.c ++++ b/plugins/imgssapi/imgssapi.c +@@ -334,34 +334,38 @@ static rsRetVal + actGSSListener(uchar *port) + { + DEFiRet; ++ tcpLstnParams_t *cnf_params = NULL; + gsssrv_t *pGSrv = NULL; + +- if(pOurTcpsrv == NULL) { +- /* first create/init the gsssrv "object" */ +- if((pGSrv = calloc(1, sizeof(gsssrv_t))) == NULL) +- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); +- +- pGSrv->allowedMethods = ALLOWEDMETHOD_GSS; +- if(bPermitPlainTcp) +- pGSrv->allowedMethods |= ALLOWEDMETHOD_TCP; +- /* gsssrv initialized */ +- +- CHKiRet(tcpsrv.Construct(&pOurTcpsrv)); +- CHKiRet(tcpsrv.SetUsrP(pOurTcpsrv, pGSrv)); +- CHKiRet(tcpsrv.SetCBOnSessConstructFinalize(pOurTcpsrv, OnSessConstructFinalize)); +- CHKiRet(tcpsrv.SetCBOnSessDestruct(pOurTcpsrv, OnSessDestruct)); +- CHKiRet(tcpsrv.SetCBIsPermittedHost(pOurTcpsrv, isPermittedHost)); +- CHKiRet(tcpsrv.SetCBRcvData(pOurTcpsrv, doRcvData)); +- CHKiRet(tcpsrv.SetCBOpenLstnSocks(pOurTcpsrv, doOpenLstnSocks)); +- CHKiRet(tcpsrv.SetCBOnSessAccept(pOurTcpsrv, onSessAccept)); +- CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose)); +- CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose)); +- CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, UCHAR_CONSTANT("imgssapi"))); +- CHKiRet(tcpsrv.SetKeepAlive(pOurTcpsrv, bKeepAlive)); +- CHKiRet(tcpsrv.SetOrigin(pOurTcpsrv, UCHAR_CONSTANT("imgssapi"))); +- tcpsrv.configureTCPListen(pOurTcpsrv, port, 1, NULL, NULL); +- CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv)); +- } ++ assert(pOurTcpsrv == NULL); ++ CHKmalloc(cnf_params = (tcpLstnParams_t*) calloc(1, sizeof(tcpLstnParams_t))); ++ /* first create/init the gsssrv "object" */ ++ if((pGSrv = calloc(1, sizeof(gsssrv_t))) == NULL) ++ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); ++ ++ pGSrv->allowedMethods = ALLOWEDMETHOD_GSS; ++ if(bPermitPlainTcp) ++ pGSrv->allowedMethods |= ALLOWEDMETHOD_TCP; ++ /* gsssrv initialized */ ++ ++ CHKiRet(tcpsrv.Construct(&pOurTcpsrv)); ++ CHKiRet(tcpsrv.SetUsrP(pOurTcpsrv, pGSrv)); ++ CHKiRet(tcpsrv.SetCBOnSessConstructFinalize(pOurTcpsrv, OnSessConstructFinalize)); ++ CHKiRet(tcpsrv.SetCBOnSessDestruct(pOurTcpsrv, OnSessDestruct)); ++ CHKiRet(tcpsrv.SetCBIsPermittedHost(pOurTcpsrv, isPermittedHost)); ++ CHKiRet(tcpsrv.SetCBRcvData(pOurTcpsrv, doRcvData)); ++ CHKiRet(tcpsrv.SetCBOpenLstnSocks(pOurTcpsrv, doOpenLstnSocks)); ++ CHKiRet(tcpsrv.SetCBOnSessAccept(pOurTcpsrv, onSessAccept)); ++ CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose)); ++ CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose)); ++ CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, UCHAR_CONSTANT("imgssapi"))); ++ CHKiRet(tcpsrv.SetKeepAlive(pOurTcpsrv, bKeepAlive)); ++ CHKiRet(tcpsrv.SetOrigin(pOurTcpsrv, UCHAR_CONSTANT("imgssapi"))); ++ cnf_params->pszPort = port; ++ cnf_params->bSuppOctetFram = 1; ++ tcpsrv.configureTCPListen(pOurTcpsrv, cnf_params); ++ CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv)); ++ cnf_params = NULL; + + finalize_it: + if(iRet != RS_RET_OK) { +@@ -370,6 +374,7 @@ actGSSListener(uchar *port) + tcpsrv.Destruct(&pOurTcpsrv); + free(pGSrv); + } ++ free(cnf_params); + RETiRet; + } + +diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c +index cf74d4c616..c336e6c24d 100644 +--- a/plugins/imtcp/imtcp.c ++++ b/plugins/imtcp/imtcp.c +@@ -4,7 +4,7 @@ + * File begun on 2007-12-21 by RGerhards (extracted from syslogd.c, + * which at the time of the rsyslog fork was BSD-licensed) + * +- * Copyright 2007-2017 Adiscon GmbH. ++ * Copyright 2007-2020 Adiscon GmbH. + * + * This file is part of rsyslog. + * +@@ -112,9 +112,7 @@ static struct configSettings_s { + } cs; + + struct instanceConf_s { +- uchar *pszBindPort; /* port to bind to */ +- uchar *pszLstnPortFileName; /* file dynamic port is written to */ +- uchar *pszBindAddr; /* IP to bind socket to */ ++ tcpLstnParams_t *cnf_params; /**< listener config parameters */ + uchar *pszBindRuleset; /* name of ruleset to bind to */ + ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */ + uchar *pszInputName; /* value for inputname property, NULL is OK and handled by core engine */ +@@ -122,7 +120,6 @@ struct instanceConf_s { + sbool bSPFramingFix; + unsigned int ratelimitInterval; + unsigned int ratelimitBurst; +- int bSuppOctetFram; + struct instanceConf_s *next; + }; + +@@ -288,19 +285,20 @@ setPermittedPeer(void __attribute__((unused)) *pVal, uchar *pszID) + static rsRetVal + createInstance(instanceConf_t **pinst) + { +- instanceConf_t *inst; ++ instanceConf_t *inst = NULL; ++ + DEFiRet; + CHKmalloc(inst = malloc(sizeof(instanceConf_t))); ++ CHKmalloc(inst->cnf_params = (tcpLstnParams_t*) calloc(1, sizeof(tcpLstnParams_t))); + inst->next = NULL; + inst->pszBindRuleset = NULL; + inst->pszInputName = NULL; +- inst->pszBindAddr = NULL; + inst->dfltTZ = NULL; +- inst->bSuppOctetFram = -1; /* unset */ ++ inst->cnf_params->bSuppOctetFram = -1; /* unset */ + inst->bSPFramingFix = 0; + inst->ratelimitInterval = 0; + inst->ratelimitBurst = 10000; +- inst->pszLstnPortFileName = NULL; ++ inst->cnf_params->pszLstnPortFileName = NULL; + + /* node created, let's add to config */ + if(loadModConf->tail == NULL) { +@@ -312,6 +310,9 @@ createInstance(instanceConf_t **pinst) + + *pinst = inst; + finalize_it: ++ if(iRet != RS_RET_OK) { ++ free(inst); ++ } + RETiRet; + } + +@@ -328,7 +329,7 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) + + CHKiRet(createInstance(&inst)); + +- CHKmalloc(inst->pszBindPort = ustrdup((pNewVal == NULL || *pNewVal == '\0') ++ CHKmalloc(inst->cnf_params->pszPort = ustrdup((pNewVal == NULL || *pNewVal == '\0') + ? (uchar*) "10514" : pNewVal)); + if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) { + inst->pszBindRuleset = NULL; +@@ -336,14 +337,14 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) + CHKmalloc(inst->pszBindRuleset = ustrdup(cs.pszBindRuleset)); + } + if((cs.lstnIP == NULL) || (cs.lstnIP[0] == '\0')) { +- inst->pszBindAddr = NULL; ++ inst->cnf_params->pszAddr = NULL; + } else { +- CHKmalloc(inst->pszBindAddr = ustrdup(cs.lstnIP)); ++ CHKmalloc(inst->cnf_params->pszAddr = ustrdup(cs.lstnIP)); + } + if((cs.lstnPortFile == NULL) || (cs.lstnPortFile[0] == '\0')) { +- inst->pszBindAddr = NULL; ++ inst->cnf_params->pszAddr = NULL; + } else { +- CHKmalloc(inst->pszLstnPortFileName = ustrdup(cs.lstnPortFile)); ++ CHKmalloc(inst->cnf_params->pszLstnPortFileName = ustrdup(cs.lstnPortFile)); + } + + if((cs.pszInputName == NULL) || (cs.pszInputName[0] == '\0')) { +@@ -351,7 +352,7 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) + } else { + CHKmalloc(inst->pszInputName = ustrdup(cs.pszInputName)); + } +- inst->bSuppOctetFram = cs.bSuppOctetFram; ++ inst->cnf_params->bSuppOctetFram = cs.bSuppOctetFram; + + finalize_it: + free(pNewVal); +@@ -407,7 +408,7 @@ addListner(modConfData_t *modConf, instanceConf_t *inst) + } + + /* initialized, now add socket and listener params */ +- DBGPRINTF("imtcp: trying to add port *:%s\n", inst->pszBindPort); ++ DBGPRINTF("imtcp: trying to add port *:%s\n", inst->cnf_params->pszPort); + CHKiRet(tcpsrv.SetRuleset(pOurTcpsrv, inst->pBindRuleset)); + CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, inst->pszInputName == NULL ? + UCHAR_CONSTANT("imtcp") : inst->pszInputName)); +@@ -416,12 +417,12 @@ addListner(modConfData_t *modConf, instanceConf_t *inst) + CHKiRet(tcpsrv.SetbSPFramingFix(pOurTcpsrv, inst->bSPFramingFix)); + CHKiRet(tcpsrv.SetLinuxLikeRatelimiters(pOurTcpsrv, inst->ratelimitInterval, inst->ratelimitBurst)); + +- if((ustrcmp(inst->pszBindPort, UCHAR_CONSTANT("0")) == 0 && inst->pszLstnPortFileName == NULL) +- || ustrcmp(inst->pszBindPort, UCHAR_CONSTANT("0")) < 0) { +- CHKmalloc(inst->pszBindPort = (uchar*)strdup("514")); ++ if((ustrcmp(inst->cnf_params->pszPort, UCHAR_CONSTANT("0")) == 0 ++ && inst->cnf_params->pszLstnPortFileName == NULL) ++ || ustrcmp(inst->cnf_params->pszPort, UCHAR_CONSTANT("0")) < 0) { ++ CHKmalloc(inst->cnf_params->pszPort = (uchar*)strdup("514")); + } +- tcpsrv.configureTCPListen(pOurTcpsrv, inst->pszBindPort, inst->bSuppOctetFram, +- inst->pszBindAddr, inst->pszLstnPortFileName); ++ tcpsrv.configureTCPListen(pOurTcpsrv, inst->cnf_params); + + finalize_it: + if(iRet != RS_RET_OK) { +@@ -456,9 +457,9 @@ CODESTARTnewInpInst + if(!pvals[i].bUsed) + continue; + if(!strcmp(inppblk.descr[i].name, "port")) { +- inst->pszBindPort = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); ++ inst->cnf_params->pszPort = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "address")) { +- inst->pszBindAddr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); ++ inst->cnf_params->pszAddr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "name")) { + inst->pszInputName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "defaulttz")) { +@@ -468,13 +469,13 @@ CODESTARTnewInpInst + } else if(!strcmp(inppblk.descr[i].name, "ruleset")) { + inst->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "supportoctetcountedframing")) { +- inst->bSuppOctetFram = (int) pvals[i].val.d.n; ++ inst->cnf_params->bSuppOctetFram = (int) pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "ratelimit.burst")) { + inst->ratelimitBurst = (unsigned int) pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "ratelimit.interval")) { + inst->ratelimitInterval = (unsigned int) pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "listenportfilename")) { +- inst->pszLstnPortFileName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); ++ inst->cnf_params->pszLstnPortFileName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("imtcp: program error, non-handled " + "param '%s'\n", inppblk.descr[i].name); +@@ -656,7 +657,7 @@ std_checkRuleset_genErrMsg(__attribute__((unused)) modConfData_t *modConf, insta + { + LogError(0, NO_ERRCODE, "imtcp: ruleset '%s' for port %s not found - " + "using default ruleset instead", inst->pszBindRuleset, +- inst->pszBindPort); ++ inst->cnf_params->pszPort); + } + + BEGINcheckCnf +@@ -664,8 +665,8 @@ BEGINcheckCnf + CODESTARTcheckCnf + for(inst = pModConf->root ; inst != NULL ; inst = inst->next) { + std_checkRuleset(pModConf, inst); +- if(inst->bSuppOctetFram == FRAMING_UNSET) +- inst->bSuppOctetFram = pModConf->bSuppOctetFram; ++ if(inst->cnf_params->bSuppOctetFram == FRAMING_UNSET) ++ inst->cnf_params->bSuppOctetFram = pModConf->bSuppOctetFram; + } + if(pModConf->root == NULL) { + LogError(0, RS_RET_NO_LISTNERS , "imtcp: module loaded, but " +@@ -713,12 +714,9 @@ CODESTARTfreeCnf + free(pModConf->permittedPeers); + } + for(inst = pModConf->root ; inst != NULL ; ) { +- free(inst->pszBindPort); +- free(inst->pszLstnPortFileName); +- free(inst->pszBindAddr); +- free(inst->pszBindRuleset); +- free(inst->pszInputName); +- free(inst->dfltTZ); ++ free((void*)inst->pszBindRuleset); ++ free((void*)inst->pszInputName); ++ free((void*)inst->dfltTZ); + del = inst; + inst = inst->next; + free(del); +diff --git a/runtime/netstrm.c b/runtime/netstrm.c +index 8a394a02eb..2c1db46378 100644 +--- a/runtime/netstrm.c ++++ b/runtime/netstrm.c +@@ -12,12 +12,18 @@ + * to carry out its work (including, and most importantly, transport + * drivers). + * ++ * Note on processing: ++ * - Initiating a listener may be driver-specific, but in regard to TLS/non-TLS ++ * it actually is not. This is because TLS is negotiated after a connection ++ * has been established. So it is the "acceptConnReq" driver entry where TLS ++ * params need to be applied. ++ * + * Work on this module begun 2008-04-17 by Rainer Gerhards. This code + * borrows from librelp's tcp.c/.h code. librelp is dual licensed and + * Rainer Gerhards and Adiscon GmbH have agreed to permit using the code + * under the terms of the GNU Lesser General Public License. + * +- * Copyright 2007-2009 Rainer Gerhards and Adiscon GmbH. ++ * Copyright 2007-2020 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * +@@ -134,18 +140,17 @@ AcceptConnReq(netstrm_t *pThis, netstrm_t **ppNew) + * pLstnPort must point to a port name or number. NULL is NOT permitted. + * rgerhards, 2008-04-22 + */ +-static rsRetVal ++static rsRetVal ATTR_NONNULL(1,3,5) + LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), +- uchar *pLstnPort, uchar *pLstnIP, int iSessMax, +- uchar *pszLstnPortFileName) ++ const int iSessMax, const tcpLstnParams_t *const cnf_params) + { + DEFiRet; + + ISOBJ_TYPE_assert(pNS, netstrms); + assert(fAddLstn != NULL); +- assert(pLstnPort != NULL); ++ assert(cnf_params->pszPort != NULL); + +- CHKiRet(pNS->Drvr.LstnInit(pNS, pUsr, fAddLstn, pLstnPort, pLstnIP, iSessMax, pszLstnPortFileName)); ++ CHKiRet(pNS->Drvr.LstnInit(pNS, pUsr, fAddLstn, iSessMax, cnf_params)); + + finalize_it: + RETiRet; +diff --git a/runtime/netstrm.h b/runtime/netstrm.h +index 2e28d7e2e6..4ca35805e7 100644 +--- a/runtime/netstrm.h ++++ b/runtime/netstrm.h +@@ -1,6 +1,6 @@ + /* Definitions for the stream-based netstrmworking class. + * +- * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. ++ * Copyright 2007-2020 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * +@@ -24,6 +24,7 @@ + #ifndef INCLUDED_NETSTRM_H + #define INCLUDED_NETSTRM_H + ++#include "tcpsrv.h" + #include "netstrms.h" + + /* the netstrm object */ +@@ -31,6 +32,7 @@ struct netstrm_s { + BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ + nsd_t *pDrvrData; /**< the driver's data elements (at most other places, this is called pNsd) */ + nsd_if_t Drvr; /**< our stream driver */ ++ uchar *pszDrvrAuthMode; /**< auth mode of the stream driver to use */ + void *pUsr; /**< pointer to user-provided data structure */ + netstrms_t *pNS; /**< pointer to our netstream subsystem object */ + }; +@@ -76,8 +78,8 @@ BEGINinterface(netstrm) /* name must also be changed in ENDinterface macro! */ + rsRetVal (*SetKeepAliveIntvl)(netstrm_t *pThis, int keepAliveIntvl); + rsRetVal (*SetGnutlsPriorityString)(netstrm_t *pThis, uchar *priorityString); + /* v11 -- Parameter pszLstnFileName added to LstnInit*/ +- rsRetVal (*LstnInit)(netstrms_t *pNS, void *pUsr, rsRetVal(*)(void*,netstrm_t*), +- uchar *pLstnPort, uchar *pLstnIP, int iSessMax, uchar *pszLstnPortFileName); ++ rsRetVal (ATTR_NONNULL(1,3,5) *LstnInit)(netstrms_t *pNS, void *pUsr, rsRetVal(*)(void*,netstrm_t*), ++ const int iSessMax, const tcpLstnParams_t *const cnf_params); + /* v12 -- two new binary flags added to gtls driver enabling stricter operation */ + rsRetVal (*SetDrvrCheckExtendedKeyUsage)(netstrm_t *pThis, int ChkExtendedKeyUsage); + rsRetVal (*SetDrvrPrioritizeSAN)(netstrm_t *pThis, int prioritizeSan); +diff --git a/runtime/nsd.h b/runtime/nsd.h +index e862348fd6..eecffed05e 100644 +--- a/runtime/nsd.h ++++ b/runtime/nsd.h +@@ -84,8 +84,8 @@ BEGINinterface(nsd) /* name must also be changed in ENDinterface macro! */ + rsRetVal (*SetKeepAliveTime)(nsd_t *pThis, int keepAliveTime); + rsRetVal (*SetGnutlsPriorityString)(nsd_t *pThis, uchar *gnutlsPriorityString); + /* v12 -- parameter pszLstnPortFileName added to LstnInit()*/ +- rsRetVal (*LstnInit)(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), +- uchar *pLstnPort, uchar *pLstnIP, int iSessMax, uchar *pszLstnPortFileName); ++ rsRetVal (ATTR_NONNULL(1,3,5) *LstnInit)(netstrms_t *pNS, void *pUsr, rsRetVal(*)(void*,netstrm_t*), ++ const int iSessMax, const tcpLstnParams_t *const cnf_params); + /* v13 -- two new binary flags added to gtls driver enabling stricter operation */ + rsRetVal (*SetCheckExtendedKeyUsage)(nsd_t *pThis, int ChkExtendedKeyUsage); + rsRetVal (*SetPrioritizeSAN)(nsd_t *pThis, int prioritizeSan); +diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c +index da90c2e096..55f6713d62 100644 +--- a/runtime/nsd_gtls.c ++++ b/runtime/nsd_gtls.c +@@ -1692,14 +1692,13 @@ Abort(nsd_t *pNsd) + * a session, but not during listener setup. + * gerhards, 2008-04-25 + */ +-static rsRetVal ++static rsRetVal ATTR_NONNULL(1,3,5) + LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), +- uchar *pLstnPort, uchar *pLstnIP, int iSessMax, +- uchar *pszLstnPortFileName) ++ const int iSessMax, const tcpLstnParams_t *const cnf_params) + { + DEFiRet; + CHKiRet(gtlsGlblInitLstn()); +- iRet = nsd_ptcp.LstnInit(pNS, pUsr, fAddLstn, pLstnPort, pLstnIP, iSessMax, pszLstnPortFileName); ++ iRet = nsd_ptcp.LstnInit(pNS, pUsr, fAddLstn, iSessMax, cnf_params); + finalize_it: + RETiRet; + } +@@ -1785,6 +1784,7 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew) + FINALIZE; + } + /* copy Properties to pnew first */ ++dbgprintf("RGER: pThis %p pNew %p, authMode %d\n", pThis, pNew, pThis->authMode); + pNew->authMode = pThis->authMode; + pNew->permitExpiredCerts = pThis->permitExpiredCerts; + pNew->pPermPeers = pThis->pPermPeers; +diff --git a/runtime/nsd_ossl.c b/runtime/nsd_ossl.c +index 431ea738b8..79347916e4 100644 +--- a/runtime/nsd_ossl.c ++++ b/runtime/nsd_ossl.c +@@ -1308,16 +1308,15 @@ Abort(nsd_t *pNsd) + */ + static rsRetVal + LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), +- uchar *pLstnPort, uchar *pLstnIP, int iSessMax, uchar *pszLstnPortFileName) ++ const int iSessMax, const tcpLstnParams_t *const cnf_params) + { + DEFiRet; + + dbgprintf("LstnInit for openssl: entering LstnInit (%p) for %s:%s SessMax=%d\n", +- fAddLstn, pLstnIP, pLstnPort, iSessMax); ++ fAddLstn, cnf_params->pszAddr, cnf_params->pszPort, iSessMax); + + /* Init TCP Listener using base ptcp class */ +- iRet = nsd_ptcp.LstnInit(pNS, pUsr, fAddLstn, pLstnPort, pLstnIP, +- iSessMax, pszLstnPortFileName); ++ iRet = nsd_ptcp.LstnInit(pNS, pUsr, fAddLstn, iSessMax, cnf_params); + RETiRet; + } + +diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c +index c35138fb7a..2f9e77ba03 100644 +--- a/runtime/nsd_ptcp.c ++++ b/runtime/nsd_ptcp.c +@@ -474,10 +474,9 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew) + * number of sessions permitted. + * rgerhards, 2008-04-22 + */ +-static rsRetVal ++static rsRetVal ATTR_NONNULL(1,3,5) + LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), +- uchar *pLstnPort, uchar *pLstnIP, int iSessMax, +- uchar *pszLstnPortFileName) ++ const int iSessMax, const tcpLstnParams_t *const cnf_params) + { + DEFiRet; + netstrm_t *pNewStrm = NULL; +@@ -497,20 +496,20 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), + + ISOBJ_TYPE_assert(pNS, netstrms); + assert(fAddLstn != NULL); +- assert(pLstnPort != NULL); ++ assert(cnf_params->pszPort != NULL); + assert(iSessMax >= 0); + +- dbgprintf("creating tcp listen socket on port %s\n", pLstnPort); ++ dbgprintf("creating tcp listen socket on port %s\n", cnf_params->pszPort); + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = glbl.GetDefPFFamily(); + hints.ai_socktype = SOCK_STREAM; + +- error = getaddrinfo((char*)pLstnIP, (char*) pLstnPort, &hints, &res); ++ error = getaddrinfo((const char*)cnf_params->pszAddr, (const char*) cnf_params->pszPort, &hints, &res); + if(error) { + LogError(0, RS_RET_INVALID_PORT, "error querying port '%s': %s", +- pLstnPort, gai_strerror(error)); ++ cnf_params->pszAddr, gai_strerror(error)); + ABORT_FINALIZE(RS_RET_INVALID_PORT); + } + +@@ -622,9 +621,9 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), + r->ai_addrlen = socklen_r; + savecast.sa = (struct sockaddr*)r->ai_addr; + port_override = (isIPv6) ? savecast.ipv6->sin6_port : savecast.ipv4->sin_port; +- if(pszLstnPortFileName != NULL) { ++ if(cnf_params->pszLstnPortFileName != NULL) { + FILE *fp; +- if((fp = fopen((const char*)pszLstnPortFileName, "w+")) == NULL) { ++ if((fp = fopen((const char*)cnf_params->pszLstnPortFileName, "w+")) == NULL) { + LogError(errno, RS_RET_IO_ERROR, "nsd_ptcp: ListenPortFileName: " + "error while trying to open file"); + ABORT_FINALIZE(RS_RET_IO_ERROR); +diff --git a/runtime/nsd_ptcp.h b/runtime/nsd_ptcp.h +index 137b7c3ce7..1c91718c19 100644 +--- a/runtime/nsd_ptcp.h ++++ b/runtime/nsd_ptcp.h +@@ -1,6 +1,6 @@ + /* An implementation of the nsd interface for plain tcp sockets. + * +- * Copyright 2007-2012 Adiscon GmbH. ++ * Copyright 2007-2020 Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * +@@ -23,6 +23,7 @@ + #define INCLUDED_NSD_PTCP_H + + #include ++#include "tcpsrv.h" + + #include "nsd.h" + typedef nsd_if_t nsd_ptcp_if_t; /* we just *implement* this interface */ +diff --git a/runtime/tcps_sess.c b/runtime/tcps_sess.c +index 58528c81ec..845e944582 100644 +--- a/runtime/tcps_sess.c ++++ b/runtime/tcps_sess.c +@@ -194,8 +194,8 @@ SetLstnInfo(tcps_sess_t *pThis, tcpLstnPortList_t *pLstnInfo) + assert(pLstnInfo != NULL); + pThis->pLstnInfo = pLstnInfo; + /* set cached elements */ +- pThis->bSuppOctetFram = pLstnInfo->bSuppOctetFram; +- pThis->bSPFramingFix = pLstnInfo->bSPFramingFix; ++ pThis->bSuppOctetFram = pLstnInfo->cnf_params->bSuppOctetFram; ++ pThis->bSPFramingFix = pLstnInfo->cnf_params->bSPFramingFix; + RETiRet; + } + +@@ -235,6 +235,7 @@ defaultDoSubmitMessage(tcps_sess_t *pThis, struct syslogTime *stTime, time_t ttG + DEFiRet; + + ISOBJ_TYPE_assert(pThis, tcps_sess); ++ const tcpLstnParams_t *const cnf_params = pThis->pLstnInfo->cnf_params; + + if(pThis->iMsg == 0) { + DBGPRINTF("discarding zero-sized message\n"); +@@ -249,15 +250,15 @@ defaultDoSubmitMessage(tcps_sess_t *pThis, struct syslogTime *stTime, time_t ttG + /* we now create our own message object and submit it to the queue */ + CHKiRet(msgConstructWithTime(&pMsg, stTime, ttGenTime)); + MsgSetRawMsg(pMsg, (char*)pThis->pMsg, pThis->iMsg); +- MsgSetInputName(pMsg, pThis->pLstnInfo->pInputName); +- if(pThis->pLstnInfo->dfltTZ[0] != '\0') +- MsgSetDfltTZ(pMsg, (char*) pThis->pLstnInfo->dfltTZ); ++ MsgSetInputName(pMsg, cnf_params->pInputName); ++ if(cnf_params->dfltTZ[0] != '\0') ++ MsgSetDfltTZ(pMsg, (char*) cnf_params->dfltTZ); + MsgSetFlowControlType(pMsg, pThis->pSrv->bUseFlowControl + ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY); + pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME; + MsgSetRcvFrom(pMsg, pThis->fromHost); + CHKiRet(MsgSetRcvFromIP(pMsg, pThis->fromHostIP)); +- MsgSetRuleset(pMsg, pThis->pLstnInfo->pRuleset); ++ MsgSetRuleset(pMsg, cnf_params->pRuleset); + + STATSCOUNTER_INC(pThis->pLstnInfo->ctrSubmit, pThis->pLstnInfo->mutCtrSubmit); + ratelimitAddMsg(pThis->pLstnInfo->ratelimiter, pMultiSub, pMsg); +diff --git a/runtime/tcpsrv.c b/runtime/tcpsrv.c +index 76a50357c3..ab9573e5b8 100644 +--- a/runtime/tcpsrv.c ++++ b/runtime/tcpsrv.c +@@ -123,9 +123,7 @@ static int wrkrRunning; + * rgerhards, 2009-05-21 + */ + static rsRetVal ATTR_NONNULL(1, 2) +-addNewLstnPort(tcpsrv_t *const pThis, const uchar *const pszPort, +- const int bSuppOctetFram, const uchar *const pszAddr, +- const uchar *const pszLstnPortFileName) ++addNewLstnPort(tcpsrv_t *const pThis, tcpLstnParams_t *const cnf_params) + { + tcpLstnPortList_t *pEntry; + uchar statname[64]; +@@ -135,25 +133,17 @@ addNewLstnPort(tcpsrv_t *const pThis, const uchar *const pszPort, + + /* create entry */ + CHKmalloc(pEntry = (tcpLstnPortList_t*)calloc(1, sizeof(tcpLstnPortList_t))); +- CHKmalloc(pEntry->pszPort = ustrdup(pszPort)); ++ pEntry->cnf_params = cnf_params; + +- pEntry->pszAddr = NULL; +- /* only if a bind adress is defined copy it in struct */ +- if (pszAddr != NULL) { +- CHKmalloc(pEntry->pszAddr = ustrdup(pszAddr)); +- } +- +- strcpy((char*)pEntry->dfltTZ, (char*)pThis->dfltTZ); +- pEntry->bSPFramingFix = pThis->bSPFramingFix; ++ strcpy((char*)pEntry->cnf_params->dfltTZ, (char*)pThis->dfltTZ); ++ pEntry->cnf_params->bSPFramingFix = pThis->bSPFramingFix; ++ pEntry->cnf_params->pRuleset = pThis->pRuleset; + pEntry->pSrv = pThis; +- pEntry->pRuleset = pThis->pRuleset; +- pEntry->bSuppOctetFram = bSuppOctetFram; +- pEntry->pszLstnPortFileName = pszLstnPortFileName; + + /* we need to create a property */ +- CHKiRet(prop.Construct(&pEntry->pInputName)); +- CHKiRet(prop.SetString(pEntry->pInputName, pThis->pszInputName, ustrlen(pThis->pszInputName))); +- CHKiRet(prop.ConstructFinalize(pEntry->pInputName)); ++ CHKiRet(prop.Construct(&pEntry->cnf_params->pInputName)); ++ CHKiRet(prop.SetString(pEntry->cnf_params->pInputName, pThis->pszInputName, ustrlen(pThis->pszInputName))); ++ CHKiRet(prop.ConstructFinalize(pEntry->cnf_params->pInputName)); + + /* support statistics gathering */ + CHKiRet(ratelimitNew(&pEntry->ratelimiter, "tcperver", NULL)); +@@ -161,7 +151,7 @@ addNewLstnPort(tcpsrv_t *const pThis, const uchar *const pszPort, + ratelimitSetThreadSafe(pEntry->ratelimiter); + + CHKiRet(statsobj.Construct(&(pEntry->stats))); +- snprintf((char*)statname, sizeof(statname), "%s(%s)", pThis->pszInputName, pszPort); ++ snprintf((char*)statname, sizeof(statname), "%s(%s)", pThis->pszInputName, cnf_params->pszPort); + statname[sizeof(statname)-1] = '\0'; /* just to be on the save side... */ + CHKiRet(statsobj.SetName(pEntry->stats, statname)); + CHKiRet(statsobj.SetOrigin(pEntry->stats, pThis->pszOrigin)); +@@ -177,10 +167,8 @@ addNewLstnPort(tcpsrv_t *const pThis, const uchar *const pszPort, + finalize_it: + if(iRet != RS_RET_OK) { + if(pEntry != NULL) { +- free(pEntry->pszAddr); +- free(pEntry->pszPort); +- if(pEntry->pInputName != NULL) { +- prop.Destruct(&pEntry->pInputName); ++ if(pEntry->cnf_params->pInputName != NULL) { ++ prop.Destruct(&pEntry->cnf_params->pInputName); + } + if(pEntry->ratelimiter != NULL) { + ratelimitDestruct(pEntry->ratelimiter); +@@ -201,29 +189,25 @@ addNewLstnPort(tcpsrv_t *const pThis, const uchar *const pszPort, + * rgerhards, 2008-03-20 + */ + static rsRetVal ATTR_NONNULL(1,2) +-configureTCPListen(tcpsrv_t *const pThis, +- const uchar *const pszPort, +- const int bSuppOctetFram, +- const uchar *const pszAddr, +- const uchar *const pszLstnPortFileName) ++configureTCPListen(tcpsrv_t *const pThis, tcpLstnParams_t *const cnf_params) + { ++ assert(cnf_params->pszPort != NULL); + int i; +- const uchar *pPort = pszPort; + DEFiRet; + +- assert(pszPort != NULL); + ISOBJ_TYPE_assert(pThis, tcpsrv); + + /* extract port */ ++ const uchar *pPort = cnf_params->pszPort; + i = 0; + while(isdigit((int) *pPort)) { + i = i * 10 + *pPort++ - '0'; + } + + if(i >= 0 && i <= 65535) { +- CHKiRet(addNewLstnPort(pThis, pszPort, bSuppOctetFram, pszAddr, pszLstnPortFileName)); ++ CHKiRet(addNewLstnPort(pThis, cnf_params)); + } else { +- LogError(0, NO_ERRCODE, "Invalid TCP listen port %s - ignored.\n", pszPort); ++ LogError(0, NO_ERRCODE, "Invalid TCP listen port %s - ignored.\n", cnf_params->pszPort); + } + + finalize_it: +@@ -331,8 +315,11 @@ deinit_tcp_listener(tcpsrv_t *const pThis) + /* free list of tcp listen ports */ + pEntry = pThis->pLstnPorts; + while(pEntry != NULL) { +- free(pEntry->pszPort); +- prop.Destruct(&pEntry->pInputName); ++ prop.Destruct(&pEntry->cnf_params->pInputName); ++ free((void*)pEntry->cnf_params->pszPort); ++ free((void*)pEntry->cnf_params->pszAddr); ++ free((void*)pEntry->cnf_params->pszLstnPortFileName); ++ free((void*)pEntry->cnf_params); + ratelimitDestruct(pEntry->ratelimiter); + statsobj.Destruct(&(pEntry->stats)); + pDel = pEntry; +@@ -373,22 +360,21 @@ addTcpLstn(void *pUsr, netstrm_t *pLstn) + + + /* Initialize TCP listener socket for a single port ++ * Note: at this point, TLS vs. non-TLS does not matter; TLS params are ++ * set on connect! + * rgerhards, 2009-05-21 + */ + static rsRetVal + initTCPListener(tcpsrv_t *pThis, tcpLstnPortList_t *pPortEntry) + { + DEFiRet; +- uchar *TCPLstnPort; + + ISOBJ_TYPE_assert(pThis, tcpsrv); + assert(pPortEntry != NULL); + +- TCPLstnPort = pPortEntry->pszPort; +- + // pPortEntry->pszAddr = NULL ==> bind to all interfaces +- CHKiRet(netstrm.LstnInit(pThis->pNS, (void*)pPortEntry, addTcpLstn, TCPLstnPort, +- pPortEntry->pszAddr, pThis->iSessMax, (uchar*)pPortEntry->pszLstnPortFileName)); ++ CHKiRet(netstrm.LstnInit(pThis->pNS, (void*)pPortEntry, addTcpLstn, ++ pThis->iSessMax, pPortEntry->cnf_params)); + + finalize_it: + RETiRet; +@@ -408,11 +394,12 @@ create_tcp_socket(tcpsrv_t *pThis) + /* init all configured ports */ + pEntry = pThis->pLstnPorts; + while(pEntry != NULL) { ++dbgprintf("RGER: configuring listener %p\n", pEntry); + localRet = initTCPListener(pThis, pEntry); + if(localRet != RS_RET_OK) { + LogError(0, localRet, "Could not create tcp listener, ignoring port " +- "%s bind-address %s.", pEntry->pszPort, +- (pEntry->pszAddr == NULL) ? "(null)" : (const char*)pEntry->pszAddr); ++ "%s bind-address %s.", pEntry->cnf_params->pszPort, ++ (pEntry->cnf_params->pszAddr == NULL) ? "(null)" : (const char*)pEntry->cnf_params->pszAddr); + } + pEntry = pEntry->pNext; + } +@@ -1236,15 +1223,6 @@ SetGnutlsPriorityString(tcpsrv_t *pThis, uchar *iVal) + RETiRet; + } + +-static rsRetVal +-SetLstnPortFileName(tcpsrv_t *pThis, uchar *iVal) +-{ +- DEFiRet; +- DBGPRINTF("tcpsrv: LstnPortFileName set to %s\n", +- (iVal == NULL) ? "(null)" : (const char*) iVal); +- pThis->pszLstnPortFileName = iVal; +- RETiRet; +-} + + static rsRetVal + SetOnMsgReceive(tcpsrv_t *pThis, rsRetVal (*OnMsgReceive)(tcps_sess_t*, uchar*, int)) +@@ -1309,6 +1287,7 @@ SetDfltTZ(tcpsrv_t *const pThis, uchar *const tz) + { + DEFiRet; + ISOBJ_TYPE_assert(pThis, tcpsrv); ++dbgprintf("dfltTZ prev: %s\n", pThis->dfltTZ); + strncpy((char*)pThis->dfltTZ, (char*)tz, sizeof(pThis->dfltTZ)); + pThis->dfltTZ[sizeof(pThis->dfltTZ)-1] = '\0'; + RETiRet; +@@ -1557,7 +1536,6 @@ CODESTARTobjQueryInterface(tcpsrv) + pIf->SetKeepAliveProbes = SetKeepAliveProbes; + pIf->SetKeepAliveTime = SetKeepAliveTime; + pIf->SetGnutlsPriorityString = SetGnutlsPriorityString; +- pIf->SetLstnPortFileName = SetLstnPortFileName; + pIf->SetUsrP = SetUsrP; + pIf->SetInputName = SetInputName; + pIf->SetOrigin = SetOrigin; +diff --git a/runtime/tcpsrv.h b/runtime/tcpsrv.h +index db5a1d110a..bae7e3b8b9 100644 +--- a/runtime/tcpsrv.h ++++ b/runtime/tcpsrv.h +@@ -1,6 +1,6 @@ + /* Definitions for tcpsrv class. + * +- * Copyright 2008-2015 Adiscon GmbH. ++ * Copyright 2008-2020 Adiscon GmbH. + * + * This file is part of rsyslog. + * +@@ -23,6 +23,7 @@ + + #include "obj.h" + #include "prop.h" ++#include "net.h" + #include "tcps_sess.h" + #include "statsobj.h" + +@@ -34,19 +35,24 @@ typedef enum ETCPsyslogFramingAnomaly { + } eTCPsyslogFramingAnomaly; + + ++/* config parameters for TCP listeners */ ++struct tcpLstnParams_s { ++ const uchar *pszPort; /**< the ports the listener shall listen on */ ++ const uchar *pszAddr; /**< the addrs the listener shall listen on */ ++ sbool bSuppOctetFram; /**< do we support octect-counted framing? (if no->legay only!)*/ ++ sbool bSPFramingFix; /**< support work-around for broken Cisco ASA framing? */ ++ const uchar *pszLstnPortFileName; /**< File in which the dynamic port is written */ ++ prop_t *pInputName; ++ ruleset_t *pRuleset; /**< associated ruleset */ ++ uchar dfltTZ[8]; /**< default TZ if none in timestamp; '\0' =No Default */ ++}; ++ + /* list of tcp listen ports */ + struct tcpLstnPortList_s { +- uchar *pszPort; /**< the ports the listener shall listen on */ +- uchar *pszAddr; /**< the addrs the listener shall listen on */ +- prop_t *pInputName; ++ tcpLstnParams_t *cnf_params; /**< listener config parameters */ + tcpsrv_t *pSrv; /**< pointer to higher-level server instance */ +- ruleset_t *pRuleset; /**< associated ruleset */ + statsobj_t *stats; /**< associated stats object */ +- sbool bSuppOctetFram; /**< do we support octect-counted framing? (if no->legay only!)*/ + ratelimit_t *ratelimiter; +- uchar dfltTZ[8]; /**< default TZ if none in timestamp; '\0' =No Default */ +- sbool bSPFramingFix; /**< support work-around for broken Cisco ASA framing? */ +- const uchar *pszLstnPortFileName; /**< File in which the dynamic port is written */ + STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) + tcpLstnPortList_t *pNext; /**< next port or NULL */ + }; +@@ -130,8 +136,7 @@ BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */ + rsRetVal (*Construct)(tcpsrv_t **ppThis); + rsRetVal (*ConstructFinalize)(tcpsrv_t __attribute__((unused)) *pThis); + rsRetVal (*Destruct)(tcpsrv_t **ppThis); +- rsRetVal (*ATTR_NONNULL(1,2) configureTCPListen)(tcpsrv_t*, +- const uchar *pszPort, int bSuppOctetFram, const uchar *pszAddr, const uchar *); ++ rsRetVal (*ATTR_NONNULL(1,2) configureTCPListen)(tcpsrv_t*, tcpLstnParams_t *const cnf_params); + rsRetVal (*create_tcp_socket)(tcpsrv_t *pThis); + rsRetVal (*Run)(tcpsrv_t *pThis); + /* set methods */ +@@ -188,8 +193,6 @@ BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */ + rsRetVal (*SetGnutlsPriorityString)(tcpsrv_t*, uchar*); + /* added v21 -- Preserve case in fromhost, 2018-08-16 */ + rsRetVal (*SetPreserveCase)(tcpsrv_t *pThis, int bPreserveCase); +- /* added v22 -- File for dynamic Port, 2018-08-29 */ +- rsRetVal (*SetLstnPortFileName)(tcpsrv_t*, uchar*); + /* added v23 -- Options for stricter driver behavior, 2019-08-16 */ + rsRetVal (*SetDrvrCheckExtendedKeyUsage)(tcpsrv_t *pThis, int ChkExtendedKeyUsage); + rsRetVal (*SetDrvrPrioritizeSAN)(tcpsrv_t *pThis, int prioritizeSan); +diff --git a/runtime/typedefs.h b/runtime/typedefs.h +index 06f5c25a8c..000b4da4fe 100644 +--- a/runtime/typedefs.h ++++ b/runtime/typedefs.h +@@ -123,6 +123,7 @@ typedef int rs_size_t; /* we do never need more than 2Gig strings, signed permit + typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */ + typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerously few */ + ++typedef struct tcpLstnParams_s tcpLstnParams_t; + typedef struct tcpLstnPortList_s tcpLstnPortList_t; // TODO: rename? + typedef struct strmLstnPortList_s strmLstnPortList_t; // TODO: rename? + typedef struct actWrkrIParams actWrkrIParams_t; diff --git a/SOURCES/rsyslog-8.2102.0-nsd_ossl-better-logs.patch b/SOURCES/rsyslog-8.2102.0-nsd_ossl-better-logs.patch new file mode 100644 index 0000000..b45f19a --- /dev/null +++ b/SOURCES/rsyslog-8.2102.0-nsd_ossl-better-logs.patch @@ -0,0 +1,124 @@ +diff --git a/runtime/nsd_ossl.c b/runtime/nsd_ossl.c +index e55b014b2c..431ea738b8 100644 +--- a/runtime/nsd_ossl.c ++++ b/runtime/nsd_ossl.c +@@ -210,7 +210,8 @@ void osslLastSSLErrorMsg(int ret, SSL *ssl, int severity, const char* pszCallSou + + /* Loop through ERR_get_error */ + while ((un_error = ERR_get_error()) > 0){ +- LogMsg(0, RS_RET_NO_ERRCODE, severity, "OpenSSL Error Stack: %s", ERR_error_string(un_error, NULL) ); ++ LogMsg(0, RS_RET_NO_ERRCODE, severity, ++ "nsd_ossl:OpenSSL Error Stack: %s", ERR_error_string(un_error, NULL) ); + } + } + +@@ -721,9 +722,10 @@ osslChkPeerFingerprint(nsd_ossl_t *pThis, X509 *pCert) + if(pThis->bReportAuthErr == 1) { + errno = 0; + LogError(0, RS_RET_INVALID_FINGERPRINT, +- "nsd_ossl:error:" +- " peer fingerprint '%s' unknown - we are " +- "not permitted to talk to it", cstrGetSzStrNoNULL(pstrFingerprint)); ++ "nsd_ossl:error: peer fingerprint '%s' unknown - we are " ++ "not permitted to talk to it", cstrGetSzStrNoNULL(pstrFingerprint)); ++ LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, ++ "nsd_ossl:TLS session terminated with remote syslog server."); + pThis->bReportAuthErr = 0; + } + ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT); +@@ -834,8 +836,10 @@ osslChkPeerName(nsd_ossl_t *pThis, X509 *pCert) + cstrFinalize(pStr); + errno = 0; + LogError(0, RS_RET_INVALID_FINGERPRINT, "nsd_ossl:error: peer name not authorized - " +- "not permitted to talk to it. Names: %s", +- cstrGetSzStrNoNULL(pStr)); ++ "not permitted to talk to it. Names: %s", ++ cstrGetSzStrNoNULL(pStr)); ++ LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, ++ "nsd_ossl:TLS session terminated with remote syslog server."); + pThis->bReportAuthErr = 0; + } + ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT); +@@ -871,8 +875,10 @@ osslChkPeerID(nsd_ossl_t *pThis) + if(pThis->bReportAuthErr == 1) { + errno = 0; + LogError(0, RS_RET_TLS_NO_CERT, "nsd_ossl:error: peer did not provide a certificate, " +- "not permitted to talk to it"); ++ "not permitted to talk to it"); + pThis->bReportAuthErr = 0; ++ LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, ++ "nsd_ossl:TLS session terminated with remote syslog server."); + } + ABORT_FINALIZE(RS_RET_TLS_NO_CERT); + } +@@ -905,15 +911,19 @@ osslChkPeerCertValidity(nsd_ossl_t *pThis) + if (iVerErr == X509_V_ERR_CERT_HAS_EXPIRED) { + if (pThis->permitExpiredCerts == OSSL_EXPIRED_DENY) { + LogError(0, RS_RET_CERT_EXPIRED, +- "nsd_ossl:CertValidity check" +-"- not permitted to talk to peer: certificate expired: %s", ++ "nsd_ossl:CertValidity check - not permitted to talk to peer: " ++ "certificate expired: %s", + X509_verify_cert_error_string(iVerErr)); ++ LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, ++ "nsd_ossl:TLS session terminated with remote syslog server."); + ABORT_FINALIZE(RS_RET_CERT_EXPIRED); + } else if (pThis->permitExpiredCerts == OSSL_EXPIRED_WARN) { + LogMsg(0, RS_RET_NO_ERRCODE, LOG_WARNING, +- "nsd_ossl:CertValidity check" +-"- warning talking to peer: certificate expired: %s", ++ "nsd_ossl:CertValidity check - warning talking to peer: " ++ "certificate expired: %s", + X509_verify_cert_error_string(iVerErr)); ++ LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, ++ "nsd_ossl:TLS session terminated with remote syslog server."); + } else { + dbgprintf("osslChkPeerCertValidity: talking to peer: certificate expired: %s\n", + X509_verify_cert_error_string(iVerErr)); +@@ -921,6 +931,8 @@ osslChkPeerCertValidity(nsd_ossl_t *pThis) + } else { + LogError(0, RS_RET_CERT_INVALID, "nsd_ossl:not permitted to talk to peer: " + "certificate validation failed: %s", X509_verify_cert_error_string(iVerErr)); ++ LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, ++ "nsd_ossl:TLS session terminated with remote syslog server."); + ABORT_FINALIZE(RS_RET_CERT_INVALID); + } + } else { +@@ -1384,7 +1396,7 @@ osslPostHandshakeCheck(nsd_ossl_t *pNsd) + #if OPENSSL_VERSION_NUMBER >= 0x10002000L + if(SSL_get_shared_curve(pNsd->ssl, -1) == 0) { + LogError(0, RS_RET_NO_ERRCODE, "nsd_ossl:" +-"No shared curve between syslog client and server."); ++ "No shared curve between syslog client and server."); + } + #endif + sslCipher = (const SSL_CIPHER*) SSL_get_current_cipher(pNsd->ssl); +@@ -1446,8 +1458,6 @@ osslHandshakeCheck(nsd_ossl_t *pNsd) + resErr == SSL_ERROR_WANT_WRITE) { + pNsd->rtryCall = osslRtry_handshake; + pNsd->rtryOsslErr = resErr; /* Store SSL ErrorCode into*/ +- LogError(0, RS_RET_NO_ERRCODE, "nsd_ossl:" +-"TLS handshake failed between syslog client and server."); + dbgprintf("osslHandshakeCheck: OpenSSL Client handshake does not complete " + "immediately - setting to retry (this is OK and normal)\n"); + FINALIZE; +@@ -1458,6 +1468,8 @@ osslHandshakeCheck(nsd_ossl_t *pNsd) + ABORT_FINALIZE(RS_RET_NO_ERRCODE /*RS_RET_RETRY*/); + } else { + osslLastSSLErrorMsg(res, pNsd->ssl, LOG_ERR, "osslHandshakeCheck Client"); ++ LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, ++ "nsd_ossl:TLS session terminated with remote syslog server."); + ABORT_FINALIZE(RS_RET_NO_ERRCODE); + } + } +@@ -1738,8 +1750,8 @@ Connect(nsd_t *pNsd, int family, uchar *port, uchar *host, char *device) + conn = BIO_new_socket(pPtcp->sock, BIO_CLOSE /*BIO_NOCLOSE*/); + dbgprintf("Connect: Init conn BIO[%p] done\n", (void *)conn); + +- LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, "nsd_ossl:" +-"TLS Connection initiated with remote syslog server."); ++ LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, "nsd_ossl: " ++ "TLS Connection initiated with remote syslog server."); + /*if we reach this point we are in tls mode */ + DBGPRINTF("Connect: TLS Mode\n"); + if(!(pThis->ssl = SSL_new(ctx))) { diff --git a/SOURCES/rsyslog-8.2102.0-nsd_ossl-memory-leak.patch b/SOURCES/rsyslog-8.2102.0-nsd_ossl-memory-leak.patch new file mode 100644 index 0000000..7b75773 --- /dev/null +++ b/SOURCES/rsyslog-8.2102.0-nsd_ossl-memory-leak.patch @@ -0,0 +1,25 @@ +diff --git a/runtime/nsd_ossl.c b/runtime/nsd_ossl.c +index 79347916e4..69ec57af09 100644 +--- a/runtime/nsd_ossl.c ++++ b/runtime/nsd_ossl.c +@@ -1821,11 +1821,8 @@ BIO_set_nbio( conn, 1 ); + } + + +-/* Empty wrapper for GNUTLS helper function +- * TODO: implement a similar capability +- */ + static rsRetVal +-SetGnutlsPriorityString(__attribute__((unused)) nsd_t *pNsd, __attribute__((unused)) uchar *gnutlsPriorityString) ++SetGnutlsPriorityString(nsd_t *const pNsd, uchar *const gnutlsPriorityString) + { + DEFiRet; + nsd_ossl_t* pThis = (nsd_ossl_t*) pNsd; +@@ -1905,6 +1902,7 @@ SetGnutlsPriorityString(__attribute__((unused)) nsd_t *pNsd, __attribute__((unus + pThis->gnutlsPriorityString); + osslLastSSLErrorMsg(0, NULL, LOG_ERR, "SetGnutlsPriorityString"); + } ++ SSL_CONF_CTX_free(cctx); + } + #else + dbgprintf("gnutlsPriorityString: set to '%s'\n", gnutlsPriorityString); diff --git a/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-doc.patch b/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-doc.patch new file mode 100644 index 0000000..b717972 --- /dev/null +++ b/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-doc.patch @@ -0,0 +1,47 @@ +diff -up rsyslog-8.2102.0/doc/configuration/modules/imfile.html.state-file-leaking-doc rsyslog-8.2102.0/doc/configuration/modules/imfile.html +--- rsyslog-8.2102.0/doc/configuration/modules/imfile.html.state-file-leaking-doc 2021-02-15 12:53:31.000000000 +0100 ++++ rsyslog-8.2102.0/doc/configuration/modules/imfile.html 2022-03-29 10:35:07.187827004 +0200 +@@ -294,6 +294,28 @@ rsyslog needs write permissions to work + also might require SELinux definitions (or similar for other enhanced security + systems).

+ ++
++

deleteStateOnFileMove

++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
typedefaultmandatoryobsolete legacy directive
binaryoffnonone
++

This parameter controls if state files are deleted if their associated main file is rotated via move. Usually, this is a good idea, because otherwise state files are not deleted when log rotation occurs.

++ ++

However, there is one situation where not deleting associated state file after log rotation makes sense: this is the case if a monitored file is later moved back to the same location as it was before.

++
+ +
+

Input Parameters

+@@ -1214,6 +1236,7 @@ and Others.

+
  • sortFiles
  • +
  • PollingInterval
  • +
  • statefile.directory
  • ++
  • deleteStateOnFileMove
  • + + +
  • Input Parameters
      +@@ -1311,4 +1334,4 @@ and Others.

      + + +- +\ No newline at end of file ++ diff --git a/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-fix.patch b/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-fix.patch new file mode 100644 index 0000000..161f90c --- /dev/null +++ b/SOURCES/rsyslog-8.2102.0-rhbz1909639-statefiles-fix.patch @@ -0,0 +1,162 @@ +diff -up rsyslog-8.2102.0/plugins/imfile/imfile.c.state-file-leaking rsyslog-8.2102.0/plugins/imfile/imfile.c +--- rsyslog-8.2102.0/plugins/imfile/imfile.c.state-file-leaking 2021-01-18 11:21:14.000000000 +0100 ++++ rsyslog-8.2102.0/plugins/imfile/imfile.c 2022-03-28 12:51:03.572554843 +0200 +@@ -259,6 +259,7 @@ struct modConfData_s { + Must be manually reset to 0 if desired. Helper for + polling mode. + */ ++ sbool deleteStateOnFileMove; + }; + static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ + static modConfData_t *runModConf = NULL;/* modConf ptr to use for run process */ +@@ -305,7 +306,8 @@ static struct cnfparamdescr modpdescr[] + { "sortfiles", eCmdHdlrBinary, 0 }, + { "statefile.directory", eCmdHdlrString, 0 }, + { "normalizepath", eCmdHdlrBinary, 0 }, +- { "mode", eCmdHdlrGetWord, 0 } ++ { "mode", eCmdHdlrGetWord, 0 }, ++ { "deletestateonfilemove", eCmdHdlrBinary, 0 } + }; + static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, +@@ -545,11 +547,20 @@ static int + in_setupWatch(act_obj_t *const act, const int is_file) + { + int wd = -1; ++ int flags; + if(runModConf->opMode != OPMODE_INOTIFY) + goto done; + +- wd = inotify_add_watch(ino_fd, act->name, +- (is_file) ? IN_MODIFY|IN_DONT_FOLLOW : IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO); ++ // wd = inotify_add_watch(ino_fd, act->name, ++ // (is_file) ? IN_MODIFY|IN_DONT_FOLLOW : IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO); ++ if(is_file) ++ flags = IN_MODIFY|IN_DONT_FOLLOW; ++ else if(runModConf->deleteStateOnFileMove) ++ flags = IN_CREATE|IN_DELETE|IN_MOVED_TO; ++ else ++ flags = IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO; ++ wd = inotify_add_watch(ino_fd, act->name, flags); ++ + if(wd < 0) { + if (errno == EACCES) { /* There is high probability of selinux denial on top-level paths */ + DBGPRINTF("imfile: permission denied when adding watch for '%s'\n", act->name); +@@ -713,7 +724,7 @@ act_obj_add(fs_edge_t *const edge, const + char basename[MAXFNAME]; + DEFiRet; + int fd = -1; +- ++ + DBGPRINTF("act_obj_add: edge %p, name '%s' (source '%s')\n", edge, name, source? source : "---"); + for(act = edge->active ; act != NULL ; act = act->next) { + if(!strcmp(act->name, name)) { +@@ -977,9 +988,18 @@ act_obj_destroy(act_obj_t *const act, co + if(act == NULL) + return; + +- DBGPRINTF("act_obj_destroy: act %p '%s' (source '%s'), wd %d, pStrm %p, is_deleted %d, in_move %d\n", +- act, act->name, act->source_name? act->source_name : "---", act->wd, act->pStrm, is_deleted, +- act->in_move); ++ // DBGPRINTF("act_obj_destroy: act %p '%s' (source '%s'), wd %d, pStrm %p, is_deleted %d, in_move %d\n", ++ // act, act->name, act->source_name? act->source_name : "---", act->wd, act->pStrm, is_deleted, ++ // act->in_move); ++ if (runModConf->deleteStateOnFileMove) { ++ DBGPRINTF("act_obj_destroy: act %p '%s' (source '%s'), wd %d, pStrm %p, is_deleted %d\n", ++ act, act->name, act->source_name? act->source_name : "---", act->wd, act->pStrm, is_deleted); ++ } else { ++ DBGPRINTF("act_obj_destroy: act %p '%s' (source '%s'), wd %d, pStrm %p, is_deleted %d, in_move %d\n", ++ act, act->name, act->source_name? act->source_name : "---", act->wd, act->pStrm, ++ is_deleted, act->in_move); ++ } ++ + if(act->is_symlink && is_deleted) { + act_obj_t *target_act; + for(target_act = act->edge->active ; target_act != NULL ; target_act = target_act->next) { +@@ -996,13 +1016,15 @@ act_obj_destroy(act_obj_t *const act, co + pollFile(act); /* get any left-over data */ + if(inst->bRMStateOnDel) { + statefn = getStateFileName(act, statefile, sizeof(statefile)); +- getFullStateFileName(statefn, "", toDel, sizeof(toDel)); // TODO: check! ++ // getFullStateFileName(statefn, "", toDel, sizeof(toDel)); // TODO: check! ++ getFullStateFileName(statefn, act->file_id, toDel, sizeof(toDel)); // TODO: check! + statefn = toDel; + } + persistStrmState(act); + strm.Destruct(&act->pStrm); + /* we delete state file after destruct in case strm obj initiated a write */ +- if(is_deleted && !act->in_move && inst->bRMStateOnDel) { ++ // if(is_deleted && !act->in_move && inst->bRMStateOnDel) { ++ if(is_deleted && inst->bRMStateOnDel && (runModConf->deleteStateOnFileMove || !act->in_move)) { + DBGPRINTF("act_obj_destroy: deleting state file %s\n", statefn); + unlink((char*)statefn); + } +@@ -1012,6 +1034,7 @@ act_obj_destroy(act_obj_t *const act, co + } + #ifdef HAVE_INOTIFY_INIT + if(act->wd != -1) { ++ inotify_rm_watch(ino_fd, act->wd); + wdmapDel(act->wd); + } + #endif +@@ -2026,6 +2049,7 @@ CODESTARTbeginCnfLoad + loadModConf->timeoutGranularity = 1000; /* default: 1 second */ + loadModConf->haveReadTimeouts = 0; /* default: no timeout */ + loadModConf->normalizePath = 1; ++ loadModConf->deleteStateOnFileMove = 0; + loadModConf->sortFiles = GLOB_NOSORT; + loadModConf->stateFileDirectory = NULL; + loadModConf->conf_tree = calloc(sizeof(fs_node_t), 1); +@@ -2085,6 +2109,8 @@ CODESTARTsetModCnf + loadModConf->stateFileDirectory = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(modpblk.descr[i].name, "normalizepath")) { + loadModConf->normalizePath = (sbool) pvals[i].val.d.n; ++ } else if(!strcmp(modpblk.descr[i].name, "deletestateonfilemove")) { ++ loadModConf->deleteStateOnFileMove = (sbool) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "mode")) { + if(!es_strconstcmp(pvals[i].val.d.estr, "polling")) + loadModConf->opMode = OPMODE_POLLING; +@@ -2388,16 +2414,35 @@ in_processEvent(struct inotify_event *ev + DBGPRINTF("in_processEvent process Event %x is_file %d, act->name '%s'\n", + ev->mask, etry->act->edge->is_file, etry->act->name); + +- if((ev->mask & IN_MOVED_FROM)) { +- flag_in_move(etry->act->edge->node->edges, ev->name); +- } +- if(ev->mask & (IN_MOVED_FROM | IN_MOVED_TO)) { +- fs_node_walk(etry->act->edge->node, poll_tree); +- } else if(etry->act->edge->is_file && !(etry->act->is_symlink)) { +- in_handleFileEvent(ev, etry); // esentially poll_file()! ++ // if((ev->mask & IN_MOVED_FROM)) { ++ // flag_in_move(etry->act->edge->node->edges, ev->name); ++ // } ++ // if(ev->mask & (IN_MOVED_FROM | IN_MOVED_TO)) { ++ // fs_node_walk(etry->act->edge->node, poll_tree); ++ // } else if(etry->act->edge->is_file && !(etry->act->is_symlink)) { ++ // in_handleFileEvent(ev, etry); // esentially poll_file()! ++ // } else { ++ // fs_node_walk(etry->act->edge->node, poll_tree); ++ // } ++ if(!runModConf->deleteStateOnFileMove) { ++ if((ev->mask & IN_MOVED_FROM)) { ++ flag_in_move(etry->act->edge->node->edges, ev->name); ++ } ++ if(ev->mask & (IN_MOVED_FROM | IN_MOVED_TO)) { ++ fs_node_walk(etry->act->edge->node, poll_tree); ++ } else if(etry->act->edge->is_file && !(etry->act->is_symlink)) { ++ in_handleFileEvent(ev, etry); // esentially poll_file()! ++ } else { ++ fs_node_walk(etry->act->edge->node, poll_tree); ++ } + } else { +- fs_node_walk(etry->act->edge->node, poll_tree); ++ if((ev->mask & IN_MODIFY) && etry->act->edge->is_file && !(etry->act->is_symlink)) { ++ in_handleFileEvent(ev, etry); // esentially poll_file()! ++ } else { ++ fs_node_walk(etry->act->edge->node, poll_tree); ++ } + } ++ + done: return; + } + diff --git a/SOURCES/rsyslog-8.2102.0-rhbz1962318-errfile-maxsize.patch b/SOURCES/rsyslog-8.2102.0-rhbz1962318-errfile-maxsize.patch new file mode 100644 index 0000000..912a8b1 --- /dev/null +++ b/SOURCES/rsyslog-8.2102.0-rhbz1962318-errfile-maxsize.patch @@ -0,0 +1,190 @@ +--- rsyslog-8.2102.0/action.c 2021-02-15 12:06:16.000000000 +0100 ++++ rsyslog-8.2102.0-changes/action.c 2022-03-08 15:55:33.989525382 +0100 +@@ -198,6 +198,7 @@ + { "name", eCmdHdlrGetWord, 0 }, /* legacy: actionname */ + { "type", eCmdHdlrString, CNFPARAM_REQUIRED }, /* legacy: actionname */ + { "action.errorfile", eCmdHdlrString, 0 }, ++ { "action.errorfile.maxsize", eCmdHdlrInt, 0 }, + { "action.writeallmarkmessages", eCmdHdlrBinary, 0 }, /* legacy: actionwriteallmarkmessages */ + { "action.execonlyeverynthtime", eCmdHdlrInt, 0 }, /* legacy: actionexeconlyeverynthtime */ + { "action.execonlyeverynthtimetimeout", eCmdHdlrInt, 0 }, /* legacy: actionexeconlyeverynthtimetimeout */ +@@ -400,6 +401,8 @@ + pThis->iResumeRetryCount = 0; + pThis->pszName = NULL; + pThis->pszErrFile = NULL; ++ pThis->maxErrFileSize = 0; ++ pThis->errFileWritten = 0; + pThis->pszExternalStateFile = NULL; + pThis->fdErrFile = -1; + pThis->bWriteAllMarkMsgs = 1; +@@ -1436,6 +1439,12 @@ + pThis->pszName, pThis->pszErrFile); + goto done; + } ++ struct stat statbuf; ++ if (fstat(pThis->fdErrFile, &statbuf) == -1) { ++ LogError(errno, RS_RET_ERR, "failed to fstat %s", pThis->pszErrFile); ++ goto done; ++ } ++ pThis->errFileWritten += statbuf.st_size; + } + + for(int i = 0 ; i < nparams ; ++i) { +@@ -1454,16 +1463,26 @@ + char *const rendered = strdup((char*)fjson_object_to_json_string(etry)); + if(rendered == NULL) + goto done; +- const size_t toWrite = strlen(rendered) + 1; +- /* note: we use the '\0' inside the string to store a LF - we do not +- * otherwise need it and it safes us a copy/realloc. +- */ +- rendered[toWrite-1] = '\n'; /* NO LONGER A STRING! */ +- const ssize_t wrRet = write(pThis->fdErrFile, rendered, toWrite); +- if(wrRet != (ssize_t) toWrite) { +- LogError(errno, RS_RET_IO_ERROR, +- "action %s: error writing errorFile %s, write returned %lld", +- pThis->pszName, pThis->pszErrFile, (long long) wrRet); ++ size_t toWrite = strlen(rendered) + 1; ++ // Check if need to truncate the amount of bytes to write ++ if (pThis->maxErrFileSize > 0) { ++ if (pThis->errFileWritten + toWrite > pThis->maxErrFileSize) { ++ // Truncate to the pending available ++ toWrite = pThis->maxErrFileSize - pThis->errFileWritten; ++ } ++ pThis->errFileWritten += toWrite; ++ } ++ if(toWrite > 0) { ++ /* note: we use the '\0' inside the string to store a LF - we do not ++ * otherwise need it and it safes us a copy/realloc. ++ */ ++ rendered[toWrite-1] = '\n'; /* NO LONGER A STRING! */ ++ const ssize_t wrRet = write(pThis->fdErrFile, rendered, toWrite); ++ if(wrRet != (ssize_t) toWrite) { ++ LogError(errno, RS_RET_IO_ERROR, ++ "action %s: error writing errorFile %s, write returned %lld", ++ pThis->pszName, pThis->pszErrFile, (long long) wrRet); ++ } + } + free(rendered); + +@@ -2048,6 +2067,8 @@ + continue; /* this is handled seperately during module select! */ + } else if(!strcmp(pblk.descr[i].name, "action.errorfile")) { + pAction->pszErrFile = es_str2cstr(pvals[i].val.d.estr, NULL); ++ } else if(!strcmp(pblk.descr[i].name, "action.errorfile.maxsize")) { ++ pAction->maxErrFileSize = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "action.externalstate.file")) { + pAction->pszExternalStateFile = es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(pblk.descr[i].name, "action.writeallmarkmessages")) { +--- rsyslog-8.2102.0-ori/action.h 2020-10-03 19:06:47.000000000 +0200 ++++ rsyslog-8.2102.0-changes/action.h 2022-03-04 11:36:47.024588972 +0100 +@@ -77,6 +77,8 @@ + /* error file */ + const char *pszErrFile; + int fdErrFile; ++ size_t maxErrFileSize; ++ size_t errFileWritten; + pthread_mutex_t mutErrFile; + /* external stat file system */ + const char *pszExternalStateFile; +--- rsyslog-8.2102.0-ori/tests/Makefile.am 2021-02-15 12:06:16.000000000 +0100 ++++ rsyslog-8.2102.0-changes/tests/Makefile.am 2022-03-04 11:38:01.625095709 +0100 +@@ -695,7 +695,8 @@ + mysql-actq-mt.sh \ + mysql-actq-mt-withpause.sh \ + action-tx-single-processing.sh \ +- action-tx-errfile.sh ++ action-tx-errfile.sh \ ++ action-tx-errfile-maxsize.sh + + mysql-basic.log: mysqld-start.log + mysql-basic-cnf6.log: mysqld-start.log +@@ -2156,6 +2157,8 @@ + sndrcv_omudpspoof_nonstdpt.sh \ + sndrcv_gzip.sh \ + action-tx-single-processing.sh \ ++ omfwd-errfile-maxsize.sh \ ++ action-tx-errfile-maxsize.sh \ + action-tx-errfile.sh \ + testsuites/action-tx-errfile.result \ + pipeaction.sh \ +--- rsyslog-8.2102.0-ori/tests/omfwd-errfile-maxsize.sh 1970-01-01 01:00:00.000000000 +0100 ++++ rsyslog-8.2102.0-changes/tests/omfwd-errfile-maxsize.sh 2022-03-04 11:39:02.060506234 +0100 +@@ -0,0 +1,17 @@ ++#!/bin/bash ++# part of the rsyslog project, released under ASL 2.0 ++. ${srcdir:=.}/diag.sh init ++ ++export MAX_ERROR_SIZE=1999 ++ ++generate_conf ++add_conf ' ++action(type="omfwd" target="1.2.3.4" port="1234" Protocol="tcp" NetworkNamespace="doesNotExist" ++ action.errorfile="'$RSYSLOG2_OUT_LOG'" action.errorfile.maxsize="'$MAX_ERROR_SIZE'") ++' ++startup ++shutdown_when_empty ++wait_shutdown ++check_file_exists ${RSYSLOG2_OUT_LOG} ++file_size_check ${RSYSLOG2_OUT_LOG} ${MAX_ERROR_SIZE} ++exit_test +--- rsyslog-8.2102.0-ori/tests/action-tx-errfile-maxsize.sh 1970-01-01 01:00:00.000000000 +0100 ++++ rsyslog-8.2102.0-changes/tests/action-tx-errfile-maxsize.sh 2022-03-04 11:59:22.592796989 +0100 +@@ -0,0 +1,35 @@ ++#!/bin/bash ++# part of the rsyslog project, released under ASL 2.0 ++ ++. ${srcdir:=.}/diag.sh init ++ ++export NUMMESSAGES=50 # enough to generate big file ++export MAX_ERROR_SIZE=100 ++ ++generate_conf ++add_conf ' ++$ModLoad ../plugins/ommysql/.libs/ommysql ++global(errormessagestostderr.maxnumber="5") ++ ++template(type="string" name="tpl" string="insert into SystemEvents (Message, Facility) values (\"%msg%\", %$!facility%)" option.sql="on") ++ ++if((not($msg contains "error")) and ($msg contains "msgnum:")) then { ++ set $.num = field($msg, 58, 2); ++ if $.num % 2 == 0 then { ++ set $!facility = $syslogfacility; ++ } else { ++ set $/cntr = 0; ++ } ++ action(type="ommysql" name="mysql_action_errfile_maxsize" server="127.0.0.1" template="tpl" ++ db="'$RSYSLOG_DYNNAME'" uid="rsyslog" pwd="testbench" action.errorfile="'$RSYSLOG2_OUT_LOG'" action.errorfile.maxsize="'$MAX_ERROR_SIZE'") ++} ++' ++mysql_prep_for_test ++startup ++injectmsg ++shutdown_when_empty ++wait_shutdown ++mysql_get_data ++check_file_exists ${RSYSLOG2_OUT_LOG} ++file_size_check ${RSYSLOG2_OUT_LOG} ${MAX_ERROR_SIZE} ++exit_test +--- rsyslog-8.2102.0/tests/omfwd-errfile-maxsize-filled.sh 1970-01-01 01:00:00.000000000 +0100 ++++ rsyslog-8.2102.0-changes/tests/omfwd-errfile-maxsize-filled.sh 2022-03-08 16:24:01.174365289 +0100 +@@ -0,0 +1,19 @@ ++#!/bin/bash ++# part of the rsyslog project, released under ASL 2.0 ++. ${srcdir:=.}/diag.sh init ++ERRFILE=$(mktemp) ++export MAX_ERROR_SIZE=1999 ++export INITIAL_FILE_SIZE=$((MAX_ERROR_SIZE - 100)) ++dd if=/dev/urandom of=${ERRFILE} bs=1 count=${INITIAL_FILE_SIZE} ++generate_conf ++add_conf ' ++action(type="omfwd" target="1.2.3.4" port="1234" Protocol="tcp" NetworkNamespace="doesNotExist" ++ action.errorfile="'$ERRFILE'" action.errorfile.maxsize="'$MAX_ERROR_SIZE'") ++' ++startup ++shutdown_when_empty ++wait_shutdown ++check_file_exists ${ERRFILE} ++file_size_check ${ERRFILE} ${MAX_ERROR_SIZE} ++exit_test ++rm ${ERRFILE} diff --git a/SOURCES/rsyslog-8.2102.0-rhbz2046158-correct-custom-ciphers-behaviour.patch b/SOURCES/rsyslog-8.2102.0-rhbz2046158-correct-custom-ciphers-behaviour.patch new file mode 100644 index 0000000..e98ead2 --- /dev/null +++ b/SOURCES/rsyslog-8.2102.0-rhbz2046158-correct-custom-ciphers-behaviour.patch @@ -0,0 +1,354 @@ +diff -up rsyslog-8.2102.0/runtime/nsd_ossl.c.orig rsyslog-8.2102.0/runtime/nsd_ossl.c +--- rsyslog-8.2102.0/runtime/nsd_ossl.c.orig 2022-04-15 13:42:05.320615894 +0200 ++++ rsyslog-8.2102.0/runtime/nsd_ossl.c 2022-04-15 14:33:43.472482696 +0200 +@@ -609,10 +609,10 @@ finalize_it: + } + + static rsRetVal +-osslInitSession(nsd_ossl_t *pThis) /* , nsd_ossl_t *pServer) */ ++osslInitSession(nsd_ossl_t *pThis, osslSslState_t osslType) /* , nsd_ossl_t *pServer) */ + { + DEFiRet; +- BIO *client; ++ BIO *conn; + char pristringBuf[4096]; + nsd_ptcp_t *pPtcp = (nsd_ptcp_t*) pThis->pTcp; + +@@ -633,10 +633,8 @@ osslInitSession(nsd_ossl_t *pThis) /* , + if (pThis->DrvrVerifyDepth != 0) { + SSL_set_verify_depth(pThis->ssl, pThis->DrvrVerifyDepth); + } +- } +- +- if (bAnonInit == 1) { /* no mutex needed, read-only after init */ +- /* Allow ANON Ciphers */ ++ } else if (bAnonInit == 1 && pThis->gnutlsPriorityString == NULL) { ++ /* Allow ANON Ciphers only in ANON Mode and if no custom priority string is defined */ + #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + /* NOTE: do never use: +eNULL, it DISABLES encryption! */ + strncpy(pristringBuf, "ALL:+COMPLEMENTOFDEFAULT:+ADH:+ECDH:+aNULL@SECLEVEL=0", +@@ -653,21 +651,28 @@ osslInitSession(nsd_ossl_t *pThis) /* , + } + } + +- /* Create BIO from ptcp socket! */ +- client = BIO_new_socket(pPtcp->sock, BIO_CLOSE /*BIO_NOCLOSE*/); +- dbgprintf("osslInitSession: Init client BIO[%p] done\n", (void *)client); + +- /* Set debug Callback for client BIO as well! */ +- BIO_set_callback(client, BIO_debug_callback); ++ /* Create BIO from ptcp socket! */ ++ conn = BIO_new_socket(pPtcp->sock, BIO_CLOSE /*BIO_NOCLOSE*/); ++ dbgprintf("osslInitSession: Init conn BIO[%p] done\n", (void *)conn); + +-/* TODO: still needed? Set to NON blocking ! */ +-BIO_set_nbio( client, 1 ); ++ /* Set debug Callback for conn BIO as well! */ ++ BIO_set_callback(conn, BIO_debug_callback); + +- SSL_set_bio(pThis->ssl, client, client); +- SSL_set_accept_state(pThis->ssl); /* sets ssl to work in server mode. */ ++ /* TODO: still needed? Set to NON blocking ! */ ++ BIO_set_nbio( conn, 1 ); ++ SSL_set_bio(pThis->ssl, conn, conn); + ++ if (osslType == osslServer) { ++ /* Server Socket */ ++ SSL_set_accept_state(pThis->ssl); /* sets ssl to work in server mode. */ ++ pThis->sslState = osslServer; /*set Server state */ ++ } else { ++ /* Client Socket */ ++ SSL_set_connect_state(pThis->ssl); /*sets ssl to work in client mode.*/ ++ pThis->sslState = osslClient; /*set Client state */ ++ } + pThis->bHaveSess = 1; +- pThis->sslState = osslServer; /*set Server state */ + + /* we are done */ + FINALIZE; +@@ -1136,8 +1141,8 @@ SetAuthMode(nsd_t *const pNsd, uchar *co + ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED); + } + +- /* Init Anon OpenSSL stuff */ +- CHKiRet(osslAnonInit()); ++ /* Init Anon OpenSSL stuff */ ++ CHKiRet(osslAnonInit()); + + dbgprintf("SetAuthMode: Set Mode %s/%d\n", mode, pThis->authMode); + +@@ -1394,8 +1399,9 @@ osslPostHandshakeCheck(nsd_ossl_t *pNsd) + + #if OPENSSL_VERSION_NUMBER >= 0x10002000L + if(SSL_get_shared_curve(pNsd->ssl, -1) == 0) { +- LogError(0, RS_RET_NO_ERRCODE, "nsd_ossl:" +- "No shared curve between syslog client and server."); ++ // This is not a failure ++ LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, "nsd_ossl: " ++ "Information, no shared curve between syslog client and server"); + } + #endif + sslCipher = (const SSL_CIPHER*) SSL_get_current_cipher(pNsd->ssl); +@@ -1518,7 +1524,7 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew + pNew->permitExpiredCerts = pThis->permitExpiredCerts; + pNew->pPermPeers = pThis->pPermPeers; + pNew->DrvrVerifyDepth = pThis->DrvrVerifyDepth; +- CHKiRet(osslInitSession(pNew)); ++ CHKiRet(osslInitSession(pNew, osslServer)); + + /* Store nsd_ossl_t* reference in SSL obj */ + SSL_set_ex_data(pNew->ssl, 0, pThis); +@@ -1729,9 +1735,6 @@ Connect(nsd_t *pNsd, int family, uchar * + DEFiRet; + DBGPRINTF("openssl: entering Connect family=%d, device=%s\n", family, device); + nsd_ossl_t* pThis = (nsd_ossl_t*) pNsd; +- nsd_ptcp_t* pPtcp = (nsd_ptcp_t*) pThis->pTcp; +- BIO *conn; +- char pristringBuf[4096]; + + ISOBJ_TYPE_assert(pThis, nsd_ossl); + assert(port != NULL); +@@ -1745,61 +1748,13 @@ Connect(nsd_t *pNsd, int family, uchar * + FINALIZE; + } + +- /* Create BIO from ptcp socket! */ +- conn = BIO_new_socket(pPtcp->sock, BIO_CLOSE /*BIO_NOCLOSE*/); +- dbgprintf("Connect: Init conn BIO[%p] done\n", (void *)conn); +- + LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO, "nsd_ossl: " + "TLS Connection initiated with remote syslog server."); + /*if we reach this point we are in tls mode */ + DBGPRINTF("Connect: TLS Mode\n"); +- if(!(pThis->ssl = SSL_new(ctx))) { +- pThis->ssl = NULL; +- osslLastSSLErrorMsg(0, pThis->ssl, LOG_ERR, "Connect"); +- ABORT_FINALIZE(RS_RET_NO_ERRCODE); +- } + +- // Set SSL_MODE_AUTO_RETRY to SSL obj +- SSL_set_mode(pThis->ssl, SSL_MODE_AUTO_RETRY); +- +- if (pThis->authMode != OSSL_AUTH_CERTANON) { +- dbgprintf("Connect: enable certificate checking (Mode=%d, VerifyDepth=%d)\n", +- pThis->authMode, pThis->DrvrVerifyDepth); +- /* Enable certificate valid checking */ +- SSL_set_verify(pThis->ssl, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); +- if (pThis->DrvrVerifyDepth != 0) { +- SSL_set_verify_depth(pThis->ssl, pThis->DrvrVerifyDepth); +- } +- } +- +- if (bAnonInit == 1) { /* no mutex needed, read-only after init */ +- /* Allow ANON Ciphers */ +- #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +- /* NOTE: do never use: +eNULL, it DISABLES encryption! */ +- strncpy(pristringBuf, "ALL:+COMPLEMENTOFDEFAULT:+ADH:+ECDH:+aNULL@SECLEVEL=0", +- sizeof(pristringBuf)); +- #else +- strncpy(pristringBuf, "ALL:+COMPLEMENTOFDEFAULT:+ADH:+ECDH:+aNULL", +- sizeof(pristringBuf)); +- #endif +- +- dbgprintf("Connect: setting anon ciphers: %s\n", pristringBuf); +- if ( SSL_set_cipher_list(pThis->ssl, pristringBuf) == 0 ){ +- dbgprintf("Connect: Error setting ciphers '%s'\n", pristringBuf); +- ABORT_FINALIZE(RS_RET_SYS_ERR); +- } +- } +- +- /* Set debug Callback for client BIO as well! */ +- BIO_set_callback(conn, BIO_debug_callback); +- +-/* TODO: still needed? Set to NON blocking ! */ +-BIO_set_nbio( conn, 1 ); +- +- SSL_set_bio(pThis->ssl, conn, conn); +- SSL_set_connect_state(pThis->ssl); /*sets ssl to work in client mode.*/ +- pThis->sslState = osslClient; /*set Client state */ +- pThis->bHaveSess = 1; ++ /* Do SSL Session init */ ++ CHKiRet(osslInitSession(pThis, osslClient)); + + /* Store nsd_ossl_t* reference in SSL obj */ + SSL_set_ex_data(pThis->ssl, 0, pThis); +@@ -1828,90 +1783,106 @@ SetGnutlsPriorityString(nsd_t *const pNs + nsd_ossl_t* pThis = (nsd_ossl_t*) pNsd; + ISOBJ_TYPE_assert(pThis, nsd_ossl); + +- pThis->gnutlsPriorityString = gnutlsPriorityString; ++ dbgprintf("gnutlsPriorityString: set to '%s'\n", ++ (gnutlsPriorityString != NULL ? (char*)gnutlsPriorityString : "NULL")); + + /* Skip function if function is NULL gnutlsPriorityString */ +- if (gnutlsPriorityString == NULL) { +- RETiRet; +- } else { +- dbgprintf("gnutlsPriorityString: set to '%s'\n", gnutlsPriorityString); + #if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) +- char *pCurrentPos; +- char *pNextPos; +- char *pszCmd; +- char *pszValue; +- int iConfErr; +- +- /* Set working pointer */ +- pCurrentPos = (char*) pThis->gnutlsPriorityString; +- if (pCurrentPos != NULL && strlen(pCurrentPos) > 0) { +- // Create CTX Config Helper +- SSL_CONF_CTX *cctx; +- cctx = SSL_CONF_CTX_new(); +- if (pThis->sslState == osslServer) { +- SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); +- } else { +- SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); +- } +- SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); +- SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SHOW_ERRORS); +- SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); +- +- do +- { +- pNextPos = index(pCurrentPos, '='); +- if (pNextPos != NULL) { +- while ( *pCurrentPos != '\0' && +- (*pCurrentPos == ' ' || *pCurrentPos == '\t') ) +- pCurrentPos++; +- pszCmd = strndup(pCurrentPos, pNextPos-pCurrentPos); +- pCurrentPos = pNextPos+1; +- pNextPos = index(pCurrentPos, '\n'); +- pszValue = (pNextPos == NULL ? +- strdup(pCurrentPos) : +- strndup(pCurrentPos, pNextPos - pCurrentPos)); +- pCurrentPos = (pNextPos == NULL ? NULL : pNextPos+1); +- +- /* Add SSL Conf Command */ +- iConfErr = SSL_CONF_cmd(cctx, pszCmd, pszValue); +- if (iConfErr > 0) { +- dbgprintf("gnutlsPriorityString: Successfully added Command " +- "'%s':'%s'\n", +- pszCmd, pszValue); +- } +- else { +- LogError(0, RS_RET_SYS_ERR, "Failed to added Command: %s:'%s' " +- "in gnutlsPriorityString with error '%d'", +- pszCmd, pszValue, iConfErr); +- } ++ sbool ApplySettings = 0; ++ if ((gnutlsPriorityString != NULL && pThis->gnutlsPriorityString == NULL) || ++ (gnutlsPriorityString != NULL && ++ strcmp( (const char*)pThis->gnutlsPriorityString, (const char*)gnutlsPriorityString) != 0) ++ ) { ++ ApplySettings = 1; ++ } ++ ++ pThis->gnutlsPriorityString = gnutlsPriorityString; ++ dbgprintf("gnutlsPriorityString: set to '%s' Apply %s\n", ++ (gnutlsPriorityString != NULL ? (char*)gnutlsPriorityString : "NULL"), ++ (ApplySettings == 1? "TRUE" : "FALSE")); + +- free(pszCmd); +- free(pszValue); ++ if (ApplySettings) { ++ ++ if (gnutlsPriorityString == NULL || ctx == NULL) { ++ RETiRet; ++ } else { ++ dbgprintf("gnutlsPriorityString: set to '%s'\n", gnutlsPriorityString); ++ char *pCurrentPos; ++ char *pNextPos; ++ char *pszCmd; ++ char *pszValue; ++ int iConfErr; ++ ++ /* Set working pointer */ ++ pCurrentPos = (char*) pThis->gnutlsPriorityString; ++ if (pCurrentPos != NULL && strlen(pCurrentPos) > 0) { ++ // Create CTX Config Helper ++ SSL_CONF_CTX *cctx; ++ cctx = SSL_CONF_CTX_new(); ++ if (pThis->sslState == osslServer) { ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); + } else { +- /* Abort further parsing */ +- pCurrentPos = NULL; ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); + } +- } +- while (pCurrentPos != NULL); ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SHOW_ERRORS); ++ SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); ++ ++ do ++ { ++ pNextPos = index(pCurrentPos, '='); ++ if (pNextPos != NULL) { ++ while ( *pCurrentPos != '\0' && ++ (*pCurrentPos == ' ' || *pCurrentPos == '\t') ) ++ pCurrentPos++; ++ pszCmd = strndup(pCurrentPos, pNextPos-pCurrentPos); ++ pCurrentPos = pNextPos+1; ++ pNextPos = index(pCurrentPos, '\n'); ++ pszValue = (pNextPos == NULL ? ++ strdup(pCurrentPos) : ++ strndup(pCurrentPos, pNextPos - pCurrentPos)); ++ pCurrentPos = (pNextPos == NULL ? NULL : pNextPos+1); ++ ++ /* Add SSL Conf Command */ ++ iConfErr = SSL_CONF_cmd(cctx, pszCmd, pszValue); ++ if (iConfErr > 0) { ++ dbgprintf("gnutlsPriorityString: Successfully added Command " ++ "'%s':'%s'\n", ++ pszCmd, pszValue); ++ } ++ else { ++ LogError(0, RS_RET_SYS_ERR, "Failed to added Command: %s:'%s' " ++ "in gnutlsPriorityString with error '%d'", ++ pszCmd, pszValue, iConfErr); ++ } ++ ++ free(pszCmd); ++ free(pszValue); ++ } else { ++ /* Abort further parsing */ ++ pCurrentPos = NULL; ++ } ++ } ++ while (pCurrentPos != NULL); + +- /* Finalize SSL Conf */ +- iConfErr = SSL_CONF_CTX_finish(cctx); +- if (!iConfErr) { +- LogError(0, RS_RET_SYS_ERR, "Error: setting openssl command parameters: %s" +- "Open ssl error info may follow in next messages", +- pThis->gnutlsPriorityString); +- osslLastSSLErrorMsg(0, NULL, LOG_ERR, "SetGnutlsPriorityString"); ++ /* Finalize SSL Conf */ ++ iConfErr = SSL_CONF_CTX_finish(cctx); ++ if (!iConfErr) { ++ LogError(0, RS_RET_SYS_ERR, "Error: setting openssl command parameters: %s" ++ "Open ssl error info may follow in next messages", ++ pThis->gnutlsPriorityString); ++ osslLastSSLErrorMsg(0, NULL, LOG_ERR, "SetGnutlsPriorityString"); ++ } ++ SSL_CONF_CTX_free(cctx); + } +- SSL_CONF_CTX_free(cctx); + } ++ } + #else +- dbgprintf("gnutlsPriorityString: set to '%s'\n", gnutlsPriorityString); +- LogError(0, RS_RET_SYS_ERR, "Warning: TLS library does not support SSL_CONF_cmd API" +- "(maybe it is too old?). Cannot use gnutlsPriorityString ('%s'). For more see: " +- "https://www.rsyslog.com/doc/master/configuration/modules/imtcp.html#gnutlsprioritystring", +- gnutlsPriorityString); ++ LogError(0, RS_RET_SYS_ERR, "Warning: TLS library does not support SSL_CONF_cmd API" ++ "(maybe it is too old?). Cannot use gnutlsPriorityString ('%s'). For more see: " ++ "https://www.rsyslog.com/doc/master/configuration/modules/imtcp.html#gnutlsprioritystring", ++ gnutlsPriorityString); + #endif +- } + + RETiRet; + } diff --git a/SOURCES/rsyslog-8.2102.0-rhbz2046158-gnutls-broken-connection.patch b/SOURCES/rsyslog-8.2102.0-rhbz2046158-gnutls-broken-connection.patch new file mode 100644 index 0000000..0c3a3a7 --- /dev/null +++ b/SOURCES/rsyslog-8.2102.0-rhbz2046158-gnutls-broken-connection.patch @@ -0,0 +1,215 @@ +diff -up rsyslog-8.2102.0/runtime/nsd_gtls.c.orig rsyslog-8.2102.0/runtime/nsd_gtls.c +--- rsyslog-8.2102.0/runtime/nsd_gtls.c.orig 2022-04-11 09:26:17.826271989 +0200 ++++ rsyslog-8.2102.0/runtime/nsd_gtls.c 2022-04-11 09:33:28.702012052 +0200 +@@ -556,7 +556,9 @@ gtlsRecordRecv(nsd_gtls_t *pThis) + DEFiRet; + + ISOBJ_TYPE_assert(pThis, nsd_gtls); +- DBGPRINTF("gtlsRecordRecv: start\n"); ++ DBGPRINTF("gtlsRecordRecv: start (Pending Data: %zd | Wanted Direction: %s)\n", ++ gnutls_record_check_pending(pThis->sess), ++ (gnutls_record_get_direction(pThis->sess) == gtlsDir_READ ? "READ" : "WRITE") ); + + lenRcvd = gnutls_record_recv(pThis->sess, pThis->pszRcvBuf, NSD_GTLS_MAX_RCVBUF); + if(lenRcvd >= 0) { +@@ -581,14 +583,30 @@ gtlsRecordRecv(nsd_gtls_t *pThis) + (NSD_GTLS_MAX_RCVBUF+lenRcvd)); + pThis->lenRcvBuf = NSD_GTLS_MAX_RCVBUF+lenRcvd; + } else { +- goto sslerr; ++ if (lenRcvd == GNUTLS_E_AGAIN || lenRcvd == GNUTLS_E_INTERRUPTED) { ++ goto sslerragain; /* Go to ERR AGAIN handling */ ++ } else { ++ /* Do all other error handling */ ++ int gnuRet = lenRcvd; ++ ABORTgnutls; ++ } + } + } + } else if(lenRcvd == GNUTLS_E_AGAIN || lenRcvd == GNUTLS_E_INTERRUPTED) { +-sslerr: +- pThis->rtryCall = gtlsRtry_recv; +- dbgprintf("GnuTLS receive requires a retry (this most probably is OK and no error condition)\n"); +- ABORT_FINALIZE(RS_RET_RETRY); ++sslerragain: ++ /* Check if the underlaying file descriptor needs to read or write data!*/ ++ if (gnutls_record_get_direction(pThis->sess) == gtlsDir_READ) { ++ pThis->rtryCall = gtlsRtry_recv; ++ dbgprintf("GnuTLS receive requires a retry, this most probably is OK and no error condition\n"); ++ ABORT_FINALIZE(RS_RET_RETRY); ++ } else { ++ uchar *pErr = gtlsStrerror(lenRcvd); ++ LogError(0, RS_RET_GNUTLS_ERR, "GnuTLS receive error %zd has wrong read direction(wants write) " ++ "- this could be caused by a broken connection. GnuTLS reports: %s\n", ++ lenRcvd, pErr); ++ free(pErr); ++ ABORT_FINALIZE(RS_RET_GNUTLS_ERR); ++ } + } else { + int gnuRet = lenRcvd; + ABORTgnutls; +@@ -1978,6 +1996,7 @@ static rsRetVal + Send(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf) + { + int iSent; ++ int wantsWriteData = 0; + nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd; + DEFiRet; + ISOBJ_TYPE_assert(pThis, nsd_gtls); +@@ -1998,10 +2017,12 @@ Send(nsd_t *pNsd, uchar *pBuf, ssize_t * + break; + } + if(iSent != GNUTLS_E_INTERRUPTED && iSent != GNUTLS_E_AGAIN) { ++ /* Check if the underlaying file descriptor needs to read or write data!*/ ++ wantsWriteData = gnutls_record_get_direction(pThis->sess); + uchar *pErr = gtlsStrerror(iSent); +- LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d - this " +- "could be caused by a broken connection. GnuTLS reports: %s \n", +- iSent, pErr); ++ LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d, wantsWriteData=%d - this " ++ "could be caused by a broken connection. GnuTLS reports: %s\n", ++ iSent, wantsWriteData, pErr); + free(pErr); + gnutls_perror(iSent); + ABORT_FINALIZE(RS_RET_GNUTLS_ERR); +diff -up rsyslog-8.2102.0/runtime/nsd_gtls.h.orig rsyslog-8.2102.0/runtime/nsd_gtls.h +--- rsyslog-8.2102.0/runtime/nsd_gtls.h.orig 2022-04-11 09:26:32.744262781 +0200 ++++ rsyslog-8.2102.0/runtime/nsd_gtls.h 2022-04-11 09:34:29.909982895 +0200 +@@ -33,6 +33,11 @@ typedef enum { + gtlsRtry_recv = 2 + } gtlsRtryCall_t; /**< IDs of calls that needs to be retried */ + ++typedef enum { ++ gtlsDir_READ = 0, /**< GNUTLS wants READ */ ++ gtlsDir_WRITE = 1 /**< GNUTLS wants WRITE */ ++} gtlsDirection_t; ++ + typedef nsd_if_t nsd_gtls_if_t; /* we just *implement* this interface */ + + /* the nsd_gtls object */ +diff -up rsyslog-8.2102.0/runtime/nsdsel_gtls.c.orig rsyslog-8.2102.0/runtime/nsdsel_gtls.c +--- rsyslog-8.2102.0/runtime/nsdsel_gtls.c.orig 2022-04-11 09:26:42.529256742 +0200 ++++ rsyslog-8.2102.0/runtime/nsdsel_gtls.c 2022-04-11 09:38:27.425869737 +0200 +@@ -81,6 +81,7 @@ Add(nsdsel_t *pNsdsel, nsd_t *pNsd, nsds + + ISOBJ_TYPE_assert(pThis, nsdsel_gtls); + ISOBJ_TYPE_assert(pNsdGTLS, nsd_gtls); ++ DBGPRINTF("Add on nsd %p:\n", pNsdGTLS); + if(pNsdGTLS->iMode == 1) { + if(waitOp == NSDSEL_RD && gtlsHasRcvInBuffer(pNsdGTLS)) { + ++pThis->iBufferRcvReady; +@@ -99,6 +100,8 @@ Add(nsdsel_t *pNsdsel, nsd_t *pNsd, nsds + } + } + ++ dbgprintf("nsdsel_gtls: reached end on nsd %p, calling nsdsel_ptcp.Add with waitOp %d... \n", pNsdGTLS, waitOp); ++ + /* if we reach this point, we need no special handling */ + CHKiRet(nsdsel_ptcp.Add(pThis->pTcp, pNsdGTLS->pTcp, waitOp)); + +@@ -120,7 +123,8 @@ Select(nsdsel_t *pNsdsel, int *piNumRead + if(pThis->iBufferRcvReady > 0) { + /* we still have data ready! */ + *piNumReady = pThis->iBufferRcvReady; +- dbgprintf("nsdsel_gtls: doing dummy select, data present\n"); ++ dbgprintf("nsdsel_gtls: doing dummy select for %p->iBufferRcvReady=%d, data present\n", ++ pThis, pThis->iBufferRcvReady); + } else { + iRet = nsdsel_ptcp.Select(pThis->pTcp, piNumReady); + } +@@ -138,7 +142,7 @@ doRetry(nsd_gtls_t *pNsd) + DEFiRet; + int gnuRet; + +- dbgprintf("GnuTLS requested retry of %d operation - executing\n", pNsd->rtryCall); ++ dbgprintf("doRetry: GnuTLS requested retry of %d operation - executing\n", pNsd->rtryCall); + + /* We follow a common scheme here: first, we do the systen call and + * then we check the result. So far, the result is checked after the +@@ -151,7 +155,7 @@ doRetry(nsd_gtls_t *pNsd) + case gtlsRtry_handshake: + gnuRet = gnutls_handshake(pNsd->sess); + if(gnuRet == GNUTLS_E_AGAIN || gnuRet == GNUTLS_E_INTERRUPTED) { +- dbgprintf("GnuTLS handshake retry did not finish - " ++ dbgprintf("doRetry: GnuTLS handshake retry did not finish - " + "setting to retry (this is OK and can happen)\n"); + FINALIZE; + } else if(gnuRet == 0) { +@@ -167,9 +171,20 @@ doRetry(nsd_gtls_t *pNsd) + } + break; + case gtlsRtry_recv: +- dbgprintf("retrying gtls recv, nsd: %p\n", pNsd); +- CHKiRet(gtlsRecordRecv(pNsd)); +- pNsd->rtryCall = gtlsRtry_None; /* we are done */ ++ dbgprintf("doRetry: retrying gtls recv, nsd: %p\n", pNsd); ++ iRet = gtlsRecordRecv(pNsd); ++ if (iRet == RS_RET_RETRY) { ++ // Check if there is pending data ++ size_t stBytesLeft = gnutls_record_check_pending(pNsd->sess); ++ if (stBytesLeft > 0) { ++ // We are in retry and more data waiting, finalize it ++ goto finalize_it; ++ } else { ++ dbgprintf("doRetry: gtlsRecordRecv returned RETRY, but there is no pending" ++ "data on nsd: %p\n", pNsd); ++ } ++ } ++ pNsd->rtryCall = gtlsRtry_None; /* no more data, we are done */ + gnuRet = 0; + break; + case gtlsRtry_None: +@@ -241,7 +256,7 @@ IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd, + * socket. -- rgerhards, 2010-11-20 + */ + if(pThis->iBufferRcvReady) { +- dbgprintf("nsd_gtls: dummy read, buffer not available for this FD\n"); ++ dbgprintf("nsd_gtls: dummy read, %p->buffer not available for this FD\n", pThis); + *pbIsReady = 0; + FINALIZE; + } +diff -up rsyslog-8.2102.0/runtime/tcpsrv.c.orig rsyslog-8.2102.0/runtime/tcpsrv.c +--- rsyslog-8.2102.0/runtime/tcpsrv.c.orig 2022-04-11 09:27:00.376245726 +0200 ++++ rsyslog-8.2102.0/runtime/tcpsrv.c 2022-04-11 09:41:57.885777708 +0200 +@@ -609,14 +609,15 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t * + int oserr = 0; + + ISOBJ_TYPE_assert(pThis, tcpsrv); +- DBGPRINTF("netstream %p with new data\n", (*ppSess)->pStrm); ++ prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer); ++ DBGPRINTF("netstream %p with new data from remote peer %s\n", (*ppSess)->pStrm, pszPeer); + /* Receive message */ + iRet = pThis->pRcvData(*ppSess, buf, sizeof(buf), &iRcvd, &oserr); + switch(iRet) { + case RS_RET_CLOSED: + if(pThis->bEmitMsgOnClose) { + errno = 0; +- prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer); ++ // prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer); + LogError(0, RS_RET_PEER_CLOSED_CONN, "Netstream session %p closed by remote " + "peer %s.\n", (*ppSess)->pStrm, pszPeer); + } +@@ -632,13 +633,13 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t * + /* in this case, something went awfully wrong. + * We are instructed to terminate the session. + */ +- prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer); ++ // prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer); + LogError(oserr, localRet, "Tearing down TCP Session from %s", pszPeer); + CHKiRet(closeSess(pThis, ppSess, pPoll)); + } + break; + default: +- prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer); ++ // prop.GetString((*ppSess)->fromHostIP, &pszPeer, &lenPeer); + LogError(oserr, iRet, "netstream session %p from %s will be closed due to error", + (*ppSess)->pStrm, pszPeer); + CHKiRet(closeSess(pThis, ppSess, pPoll)); +@@ -838,6 +839,7 @@ RunSelect(tcpsrv_t *pThis, nsd_epworkset + while(iTCPSess != -1) { + /* TODO: access to pNsd is NOT really CLEAN, use method... */ + CHKiRet(nssel.Add(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD)); ++ DBGPRINTF("tcpsrv process session %d:\n", iTCPSess); + /* now get next... */ + iTCPSess = TCPSessGetNxtSess(pThis, iTCPSess); + } diff --git a/SPECS/rsyslog.spec b/SPECS/rsyslog.spec index c9c3b12..7a10898 100644 --- a/SPECS/rsyslog.spec +++ b/SPECS/rsyslog.spec @@ -6,7 +6,7 @@ Summary: Enhanced system logging and kernel message trapping daemon Name: rsyslog Version: 8.2102.0 -Release: 7%{?dist}.1 +Release: 10%{?dist} License: (GPLv3+ and ASL 2.0) Group: System Environment/Daemons ExcludeArch: i686 @@ -48,14 +48,22 @@ Provides: syslog Obsoletes: sysklogd < 1.5-11 # imjournal: adds "journal" when tag/process name is missing -Patch0: rsyslog-8.1911.0-rhbz1659898-imjournal-default-tag.patch -Patch1: rsyslog-8.2102.0-rhbz1960536-fdleak-on-fsync.patch -Patch2: rsyslog-8.2102.0-rhbz1886400-reduce-default-timeout.patch -Patch3: rsyslog-8.2102.0-rhbz1866877-unexpected-length.patch -Patch4: rsyslog-8.2102.0-rhbz1984616-imuxsock-ratelimit.patch -Patch5: rsyslog-8.2102.0-rhbz1984489-remove-abort-on-id-resolution-fail.patch -Patch6: rsyslog-8.2102.0-rhbz1832368-prioritize-SAN.patch -Patch7: rsyslog-8.37.0-rhbz2081396-CVE-2022-24903.patch +Patch0: rsyslog-8.1911.0-rhbz1659898-imjournal-default-tag.patch +Patch1: rsyslog-8.2102.0-rhbz1960536-fdleak-on-fsync.patch +Patch2: rsyslog-8.2102.0-rhbz1886400-reduce-default-timeout.patch +Patch3: rsyslog-8.2102.0-rhbz1866877-unexpected-length.patch +Patch4: rsyslog-8.2102.0-rhbz1984616-imuxsock-ratelimit.patch +Patch5: rsyslog-8.2102.0-rhbz1984489-remove-abort-on-id-resolution-fail.patch +Patch6: rsyslog-8.2102.0-rhbz1832368-prioritize-SAN.patch +Patch7: rsyslog-8.2102.0-rhbz1962318-errfile-maxsize.patch +Patch8: rsyslog-8.2102.0-rhbz1909639-statefiles-fix.patch +Patch9: rsyslog-8.2102.0-rhbz1909639-statefiles-doc.patch +Patch10: rsyslog-8.2102.0-nsd_ossl-better-logs.patch +Patch11: rsyslog-8.2102.0-imtcp-param-refactor.patch +Patch12: rsyslog-8.2102.0-nsd_ossl-memory-leak.patch +Patch13: rsyslog-8.2102.0-rhbz2046158-correct-custom-ciphers-behaviour.patch +Patch14: rsyslog-8.37.0-rhbz2081396-CVE-2022-24903.patch +Patch15: rsyslog-8.2102.0-rhbz2046158-gnutls-broken-connection.patch %package crypto Summary: Encryption support @@ -280,14 +288,22 @@ mv build doc %setup -q -D %setup -q -D -T -b 5 -%patch0 -p1 -b .default-tag -%patch1 -p1 -b .fd-leak-on-fsync -%patch2 -p1 -b .timeout -%patch3 -p1 -b .unexpected-priority-length -%patch4 -p1 -b .imuxsock-rate-limit -%patch5 -p1 -b .abort-on-id-resolution-fail -%patch6 -p1 -b .prioritizeSAN -%patch7 -p1 -b .CVE-24903 +%patch0 -p1 -b .default-tag +%patch1 -p1 -b .fd-leak-on-fsync +%patch2 -p1 -b .timeout +%patch3 -p1 -b .unexpected-priority-length +%patch4 -p1 -b .imuxsock-rate-limit +%patch5 -p1 -b .abort-on-id-resolution-fail +%patch6 -p1 -b .prioritizeSAN +%patch7 -p1 -b .errfile-maxsize +%patch8 -p1 -b .state-file-leaking +%patch9 -p1 -b .state-file-leaking-doc +%patch10 -p1 -b .ossl-better-logs +%patch11 -p1 -b .imtcp-refactor-params +%patch12 -p1 -b .ossl-memory-leak +%patch13 -p1 -b .ossl-ciphers-behaviour +%patch14 -p1 -b .CVE-24903 +%patch15 -p1 -b .gnutls-error-handling %build %ifarch sparc64 @@ -532,9 +548,22 @@ done %{_libdir}/rsyslog/omudpspoof.so %changelog -* Mon May 09 2022 Attila Lakatos - 8.2102.0-7.1 +* Wed Apr 13 2022 Attila Lakatos - 8.2102.0-10 +- openssl: Correct gnutlsPriorityString (custom ciphers) behaviour +- Fix error handling in gtlsRecordRecv that can cause 100 percent CPU usage + resolves: rhbz#2046158 - Address CVE-2022-24903, Heap-based overflow in TCP syslog server - resolves: rhbz#2081400 + resolves: rhbz#2081401 + +* Mon Mar 28 2022 Attila Lakatos - 8.2102.0-9 +- Add deleteStateOnFileMove imfile module option + resolves: rhbz#1909639 +- Add inotify_rm_watch() inotify API call when object needs to be destroyed + resolves: rhbz#2052403 + +* Fri Mar 04 2022 Sergio Arroutbi - 8.2102.0-8 +- Include maxsize for error files + resolves: rhbz#1962318 * Mon Nov 22 2021 Attila Lakatos - 8.2102.0-7 - Propagate prioritizeSAN when accepting new connection