summaryrefslogtreecommitdiffstats
path: root/plugins/imrelp/imrelp.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/imrelp/imrelp.c')
-rw-r--r--plugins/imrelp/imrelp.c954
1 files changed, 954 insertions, 0 deletions
diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c
new file mode 100644
index 0000000..4f9295c
--- /dev/null
+++ b/plugins/imrelp/imrelp.c
@@ -0,0 +1,954 @@
+/* imrelp.c
+ *
+ * This is the implementation of the RELP input module.
+ *
+ * File begun on 2008-03-13 by RGerhards
+ *
+ * Copyright 2008-2019 Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * 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 <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <librelp.h>
+#include "rsyslog.h"
+#include "dirty.h"
+#include "errmsg.h"
+#include "cfsysline.h"
+#include "module-template.h"
+#include "net.h"
+#include "msg.h"
+#include "unicode-helper.h"
+#include "prop.h"
+#include "ruleset.h"
+#include "glbl.h"
+#include "statsobj.h"
+#include "srUtils.h"
+#include "parserif.h"
+
+MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
+MODULE_CNFNAME("imrelp")
+
+/* static data */
+DEF_IMOD_STATIC_DATA
+DEFobjCurrIf(net)
+DEFobjCurrIf(prop)
+DEFobjCurrIf(ruleset)
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(statsobj)
+
+/* forward definitions */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
+
+
+/* Module static data */
+/* config vars for legacy config system */
+static relpEngine_t *pRelpEngine; /* our relp engine */
+
+/* config settings */
+typedef struct configSettings_s {
+ uchar *pszBindRuleset; /* name of Ruleset to bind to */
+} configSettings_t;
+static configSettings_t cs;
+
+struct instanceConf_s {
+ uchar *pszBindPort; /* port to bind to */
+ uchar *pszBindAddr; /* address to bind to */
+ uchar *pszBindRuleset; /* name of ruleset to bind to */
+ uchar *pszInputName; /* value for inputname property */
+ prop_t *pInputName; /* InputName in property format for fast access */
+ ruleset_t *pBindRuleset; /* ruleset to bind listener to */
+ sbool bKeepAlive; /* support keep-alive packets */
+ sbool bEnableTLS;
+ sbool bEnableTLSZip;
+ sbool bEnableLstn; /* flag to permit disabling of listener in error case */
+ int dhBits;
+ size_t maxDataSize;
+ int oversizeMode;
+ uchar *pristring; /* GnuTLS priority string (NULL if not to be provided) */
+ uchar *authmode; /* TLS auth mode */
+ uchar *caCertFile;
+ uchar *myCertFile;
+ uchar *myPrivKeyFile;
+#if defined(HAVE_RELPENGINESETTLSCFGCMD)
+ uchar *tlscfgcmd;
+#endif
+ int iKeepAliveIntvl;
+ int iKeepAliveProbes;
+ int iKeepAliveTime;
+ flowControl_t flowCtlType;
+ struct {
+ int nmemb;
+ uchar **name;
+ } permittedPeers;
+
+ struct instanceConf_s *next;
+ /* with librelp, this module does not have any own specific session
+ * or listener active data item. As a "work-around", we keep some
+ * data items inside the configuration object. To keep things
+ * decently clean, we put them all into their dedicated struct. So
+ * it is easy to judge what is actual configuration and what is
+ * dynamic runtime data. -- rgerhards, 2013-06-18
+ */
+ struct {
+ statsobj_t *stats; /* listener stats */
+ STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit)
+ } data;
+};
+
+
+struct modConfData_s {
+ rsconf_t *pConf; /* our overall config object */
+ instanceConf_t *root, *tail;
+ const char *tlslib;
+ uchar *pszBindRuleset; /* default name of Ruleset to bind to */
+};
+
+static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
+static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */
+
+/* module-global parameters */
+static struct cnfparamdescr modpdescr[] = {
+ { "ruleset", eCmdHdlrGetWord, 0 },
+ { "tls.tlslib", eCmdHdlrString, 0 }
+};
+static struct cnfparamblk modpblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(modpdescr)/sizeof(struct cnfparamdescr),
+ modpdescr
+ };
+
+/* input instance parameters */
+static struct cnfparamdescr inppdescr[] = {
+ { "port", eCmdHdlrString, CNFPARAM_REQUIRED },
+ { "address", eCmdHdlrString, 0 },
+ { "name", eCmdHdlrString, 0 },
+ { "ruleset", eCmdHdlrString, 0 },
+ { "keepalive", eCmdHdlrBinary, 0 },
+ { "keepalive.probes", eCmdHdlrInt, 0 },
+ { "keepalive.time", eCmdHdlrInt, 0 },
+ { "keepalive.interval", eCmdHdlrInt, 0 },
+ { "maxdatasize", eCmdHdlrSize, 0 },
+ { "oversizemode", eCmdHdlrString, 0 },
+ { "flowcontrol", eCmdHdlrGetWord, 0 },
+ { "tls", eCmdHdlrBinary, 0 },
+ { "tls.permittedpeer", eCmdHdlrArray, 0 },
+ { "tls.authmode", eCmdHdlrString, 0 },
+ { "tls.dhbits", eCmdHdlrInt, 0 },
+ { "tls.prioritystring", eCmdHdlrString, 0 },
+ { "tls.cacert", eCmdHdlrString, 0 },
+ { "tls.mycert", eCmdHdlrString, 0 },
+ { "tls.myprivkey", eCmdHdlrString, 0 },
+ { "tls.tlscfgcmd", eCmdHdlrString, 0 },
+ { "tls.compression", eCmdHdlrBinary, 0 }
+};
+static struct cnfparamblk inppblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(inppdescr)/sizeof(struct cnfparamdescr),
+ inppdescr
+ };
+
+#include "im-helper.h" /* must be included AFTER the type definitions! */
+static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */
+
+/* ------------------------------ callbacks ------------------------------ */
+
+PRAGMA_DIAGNOSTIC_PUSH
+PRAGMA_IGNORE_Wformat_nonliteral
+static void __attribute__((format(printf, 1, 2)))
+imrelp_dbgprintf(const char *fmt, ...)
+{
+ va_list ap;
+ char pszWriteBuf[32*1024+1]; //this function has to be able to
+ /*generate a buffer longer than that of r_dbgprintf, so
+ r_dbgprintf can properly truncate*/
+
+ if(!(Debug && debugging_on)) {
+ return;
+ }
+
+ va_start(ap, fmt);
+ vsnprintf(pszWriteBuf, sizeof(pszWriteBuf), fmt, ap);
+ va_end(ap);
+ r_dbgprintf("imrelp.c", "%s", pszWriteBuf);
+}
+PRAGMA_DIAGNOSTIC_POP
+
+static void
+onErr(void *pUsr, char *objinfo, char* errmesg, __attribute__((unused)) relpRetVal errcode)
+{
+ instanceConf_t *inst = (instanceConf_t*) pUsr;
+ LogError(0, RS_RET_RELP_AUTH_FAIL, "imrelp[%s]: error '%s', object "
+ " '%s' - input may not work as intended",
+ inst->pszBindPort, errmesg, objinfo);
+}
+
+static void
+onGenericErr(char *objinfo, char* errmesg, __attribute__((unused)) relpRetVal errcode)
+{
+ LogError(0, RS_RET_RELP_ERR, "imrelp: librelp error '%s', object "
+ " '%s' - input may not work as intended", errmesg, objinfo);
+}
+
+static void
+onAuthErr(void *pUsr, char *authinfo, char* errmesg, __attribute__((unused)) relpRetVal errcode)
+{
+ instanceConf_t *inst = (instanceConf_t*) pUsr;
+ LogError(0, RS_RET_RELP_AUTH_FAIL, "imrelp[%s]: authentication error '%s', peer "
+ "is '%s'", inst->pszBindPort, errmesg, authinfo);
+}
+
+/* callback for receiving syslog messages. This function is invoked from the
+ * RELP engine when a syslog message arrived. It must return a relpRetVal,
+ * with anything else but RELP_RET_OK terminating the relp session. Please note
+ * that RELP_RET_OK is equal to RS_RET_OK and the other libRELP error codes
+ * are different from our rsRetVal. So we can simply use our own iRet system
+ * to fulfill the requirement.
+ * rgerhards, 2008-03-21
+ * Note: librelp 1.0.0 is required in order to receive the IP address, otherwise
+ * we will only see the hostname (twice). -- rgerhards, 2009-10-14
+ */
+static relpRetVal
+onSyslogRcv(void *pUsr, uchar *pHostname, uchar *pIP, uchar *msg, size_t lenMsg)
+{
+ prop_t *pProp = NULL;
+ smsg_t *pMsg;
+ instanceConf_t *inst = (instanceConf_t*) pUsr;
+ DEFiRet;
+
+ CHKiRet(msgConstruct(&pMsg));
+ MsgSetInputName(pMsg, inst->pInputName);
+ MsgSetRawMsg(pMsg, (char*)msg, lenMsg);
+ MsgSetFlowControlType(pMsg, inst->flowCtlType);
+ MsgSetRuleset(pMsg, inst->pBindRuleset);
+ pMsg->msgFlags = PARSE_HOSTNAME | NEEDS_PARSING;
+
+ /* TODO: optimize this, we can store it inside the session */
+ MsgSetRcvFromStr(pMsg, pHostname, ustrlen(pHostname), &pProp);
+ CHKiRet(prop.Destruct(&pProp));
+ CHKiRet(MsgSetRcvFromIPStr(pMsg, pIP, ustrlen(pIP), &pProp));
+ CHKiRet(prop.Destruct(&pProp));
+ CHKiRet(submitMsg2(pMsg));
+ STATSCOUNTER_INC(inst->data.ctrSubmit, inst->data.mutCtrSubmit);
+
+finalize_it:
+
+ RETiRet;
+}
+
+
+/* ------------------------------ end callbacks ------------------------------ */
+
+/* create input instance, set default parameters, and
+ * add it to the list of instances.
+ */
+static rsRetVal
+createInstance(instanceConf_t **pinst)
+{
+ instanceConf_t *inst;
+ DEFiRet;
+ CHKmalloc(inst = malloc(sizeof(instanceConf_t)));
+ inst->next = NULL;
+
+ inst->pszBindPort = NULL;
+ inst->pszBindAddr = NULL;
+ inst->pszBindRuleset = NULL;
+ inst->pszInputName = NULL;
+ inst->pBindRuleset = NULL;
+ inst->bKeepAlive = 0;
+ inst->iKeepAliveIntvl = 0;
+ inst->iKeepAliveProbes = 0;
+ inst->iKeepAliveTime = 0;
+ inst->bEnableTLS = 0;
+ inst->bEnableTLSZip = 0;
+ inst->bEnableLstn = 0;
+ inst->dhBits = 0;
+ inst->pristring = NULL;
+ inst->authmode = NULL;
+ inst->permittedPeers.nmemb = 0;
+ inst->caCertFile = NULL;
+ inst->myCertFile = NULL;
+ inst->myPrivKeyFile = NULL;
+#if defined(HAVE_RELPENGINESETTLSCFGCMD)
+ inst->tlscfgcmd = NULL;
+#endif
+ inst->maxDataSize = 0;
+ inst->flowCtlType = eFLOWCTL_LIGHT_DELAY;
+#ifdef HAVE_RELPSRVSETOVERSIZEMODE
+ inst->oversizeMode = RELP_OVERSIZE_TRUNCATE;
+#endif
+
+ /* node created, let's add to config */
+ if(loadModConf->tail == NULL) {
+ loadModConf->tail = loadModConf->root = inst;
+ } else {
+ loadModConf->tail->next = inst;
+ loadModConf->tail = inst;
+ }
+
+ *pinst = inst;
+finalize_it:
+ RETiRet;
+}
+
+
+/* function to generate an error message if the ruleset cannot be found */
+static inline void
+std_checkRuleset_genErrMsg(__attribute__((unused)) modConfData_t *modConf, instanceConf_t *inst)
+{
+ LogError(0, NO_ERRCODE, "imrelp[%s]: ruleset '%s' not found - "
+ "using default ruleset instead",
+ inst->pszBindPort, inst->pszBindRuleset);
+}
+
+
+/* This function is called when a new listener instance shall be added to
+ * the current config object via the legacy config system. It just shuffles
+ * all parameters to the listener in-memory instance.
+ * rgerhards, 2011-05-04
+ */
+static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal)
+{
+ instanceConf_t *inst;
+ DEFiRet;
+
+ CHKiRet(createInstance(&inst));
+
+ if(pNewVal == NULL || *pNewVal == '\0') {
+ LogError(0, NO_ERRCODE, "imrelp: port number must be specified, listener ignored");
+ }
+ if((pNewVal == NULL) || (*pNewVal == '\0')) {
+ inst->pszBindPort = NULL;
+ } else {
+ CHKmalloc(inst->pszBindPort = ustrdup(pNewVal));
+ }
+ if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) {
+ inst->pszBindRuleset = NULL;
+ } else {
+ CHKmalloc(inst->pszBindRuleset = ustrdup(cs.pszBindRuleset));
+ }
+ inst->pBindRuleset = NULL;
+
+ inst->bEnableLstn = -1; /* all ok, ready to start up */
+finalize_it:
+ free(pNewVal);
+ RETiRet;
+}
+
+
+static rsRetVal
+addListner(modConfData_t __attribute__((unused)) *modConf, instanceConf_t *inst)
+{
+ relpSrv_t *pSrv;
+ int relpRet;
+ uchar statname[64];
+ int i;
+ DEFiRet;
+
+ if(!inst->bEnableLstn) {
+ DBGPRINTF("listener not started because it is disabled by config error\n");
+ FINALIZE;
+ }
+
+ if(pRelpEngine == NULL) {
+ CHKiRet(relpEngineConstruct(&pRelpEngine));
+ CHKiRet(relpEngineSetDbgprint(pRelpEngine, (void (*)(char *, ...))imrelp_dbgprintf));
+ CHKiRet(relpEngineSetFamily(pRelpEngine, glbl.GetDefPFFamily(runModConf->pConf)));
+ CHKiRet(relpEngineSetEnableCmd(pRelpEngine, (uchar*) "syslog", eRelpCmdState_Required));
+ CHKiRet(relpEngineSetSyslogRcv2(pRelpEngine, onSyslogRcv));
+ CHKiRet(relpEngineSetOnErr(pRelpEngine, onErr));
+ CHKiRet(relpEngineSetOnGenericErr(pRelpEngine, onGenericErr));
+ CHKiRet(relpEngineSetOnAuthErr(pRelpEngine, onAuthErr));
+ if (!glbl.GetDisableDNS(runModConf->pConf)) {
+ CHKiRet(relpEngineSetDnsLookupMode(pRelpEngine, 1));
+ }
+ #if defined(HAVE_RELPENGINESETTLSLIBBYNAME)
+ if(modConf->tlslib != NULL) {
+ if(relpEngineSetTLSLibByName(pRelpEngine, modConf->tlslib) != RELP_RET_OK) {
+ LogMsg(0, RS_RET_CONF_PARAM_INVLD, LOG_WARNING,
+ "imrelp: tlslib '%s' not accepted as valid by librelp - using default",
+ modConf->tlslib);
+ }
+ }
+ #endif
+ }
+
+ CHKiRet(relpEngineListnerConstruct(pRelpEngine, &pSrv));
+ CHKiRet(relpSrvSetMaxDataSize(pSrv, inst->maxDataSize));
+ CHKiRet(relpSrvSetLstnPort(pSrv, inst->pszBindPort));
+ #if defined(HAVE_RELPSRVSETLSTNADDR)
+ CHKiRet(relpSrvSetLstnAddr(pSrv, inst->pszBindAddr));
+ #endif
+
+#ifdef HAVE_RELPSRVSETOVERSIZEMODE
+ CHKiRet(relpSrvSetOversizeMode(pSrv, inst->oversizeMode));
+#endif
+ inst->pszInputName = ustrdup((inst->pszInputName == NULL) ? UCHAR_CONSTANT("imrelp") : inst->pszInputName);
+ CHKiRet(prop.Construct(&inst->pInputName));
+ CHKiRet(prop.SetString(inst->pInputName, inst->pszInputName, ustrlen(inst->pszInputName)));
+ CHKiRet(prop.ConstructFinalize(inst->pInputName));
+ /* support statistics gathering */
+ CHKiRet(statsobj.Construct(&(inst->data.stats)));
+ snprintf((char*)statname, sizeof(statname), "%s(%s)",
+ inst->pszInputName, inst->pszBindPort);
+ statname[sizeof(statname)-1] = '\0'; /* just to be on the save side... */
+ CHKiRet(statsobj.SetName(inst->data.stats, statname));
+ CHKiRet(statsobj.SetOrigin(inst->data.stats, (uchar*)"imrelp"));
+ STATSCOUNTER_INIT(inst->data.ctrSubmit, inst->data.mutCtrSubmit);
+ CHKiRet(statsobj.AddCounter(inst->data.stats, UCHAR_CONSTANT("submitted"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(inst->data.ctrSubmit)));
+ CHKiRet(statsobj.ConstructFinalize(inst->data.stats));
+ /* end stats counters */
+ relpSrvSetUsrPtr(pSrv, inst);
+ relpSrvSetKeepAlive(pSrv, inst->bKeepAlive, inst->iKeepAliveIntvl,
+ inst->iKeepAliveProbes, inst->iKeepAliveTime);
+ if(inst->bEnableTLS) {
+ relpRet = relpSrvEnableTLS2(pSrv);
+ if(relpRet == RELP_RET_ERR_NO_TLS) {
+ LogError(0, RS_RET_RELP_NO_TLS,
+ "imrelp: could not activate relp TLS, librelp "
+ "does not support it (most probably GnuTLS lib "
+ "is too old)!");
+ ABORT_FINALIZE(RS_RET_RELP_NO_TLS);
+ } else if(relpRet == RELP_RET_ERR_NO_TLS_AUTH) {
+ LogError(0, RS_RET_RELP_NO_TLS_AUTH,
+ "imrelp: could not activate relp TLS with "
+ "authentication, librelp does not support it "
+ "(most probably GnuTLS lib is too old)! "
+ "Note: anonymous TLS is probably supported.");
+ ABORT_FINALIZE(RS_RET_RELP_NO_TLS_AUTH);
+ } else if(relpRet != RELP_RET_OK) {
+ LogError(0, RS_RET_RELP_ERR,
+ "imrelp: could not activate relp TLS, code %d", relpRet);
+ ABORT_FINALIZE(RS_RET_RELP_ERR);
+ }
+ if(inst->bEnableTLSZip) {
+ relpSrvEnableTLSZip2(pSrv);
+ }
+ if(inst->dhBits) {
+ relpSrvSetDHBits(pSrv, inst->dhBits);
+ }
+ relpSrvSetGnuTLSPriString(pSrv, (char*)inst->pristring);
+ if(relpSrvSetAuthMode(pSrv, (char*)inst->authmode) != RELP_RET_OK) {
+ LogError(0, RS_RET_RELP_ERR,
+ "imrelp: invalid auth mode '%s'", inst->authmode);
+ ABORT_FINALIZE(RS_RET_RELP_ERR);
+ }
+ if(relpSrvSetCACert(pSrv, (char*) inst->caCertFile) != RELP_RET_OK)
+ ABORT_FINALIZE(RS_RET_RELP_ERR);
+ if(relpSrvSetOwnCert(pSrv, (char*) inst->myCertFile) != RELP_RET_OK)
+ ABORT_FINALIZE(RS_RET_RELP_ERR);
+ if(relpSrvSetPrivKey(pSrv, (char*) inst->myPrivKeyFile) != RELP_RET_OK)
+ ABORT_FINALIZE(RS_RET_RELP_ERR);
+#if defined(HAVE_RELPENGINESETTLSCFGCMD)
+ if (inst->tlscfgcmd != NULL) {
+ if(relpSrvSetTlsConfigCmd(pSrv, (char*) inst->tlscfgcmd) != RELP_RET_OK)
+ ABORT_FINALIZE(RS_RET_RELP_ERR);
+ }
+#endif
+ for(i = 0 ; i < inst->permittedPeers.nmemb ; ++i) {
+ relpSrvAddPermittedPeer(pSrv, (char*)inst->permittedPeers.name[i]);
+ }
+ }
+ relpRet = relpEngineListnerConstructFinalize(pRelpEngine, pSrv);
+ /* re-check error TLS error codes. librelp seems to emit them only
+ * after finalize in some cases...
+ */
+ if(relpRet == RELP_RET_ERR_NO_TLS) {
+ LogError(0, RS_RET_RELP_NO_TLS,
+ "imrelp: could not activate relp TLS listener, librelp "
+ "does not support it (most probably GnuTLS lib "
+ "is too old)!");
+ ABORT_FINALIZE(RS_RET_RELP_NO_TLS);
+ } else if(relpRet == RELP_RET_ERR_NO_TLS_AUTH) {
+ LogError(0, RS_RET_RELP_NO_TLS_AUTH,
+ "imrelp: could not activate relp TLS listener with "
+ "authentication, librelp does not support it "
+ "(most probably GnuTLS lib is too old)! "
+ "Note: anonymous TLS is probably supported.");
+ ABORT_FINALIZE(RS_RET_RELP_NO_TLS_AUTH);
+ } else if(relpRet != RELP_RET_OK) {
+ LogError(0, RS_RET_RELP_ERR,
+ "imrelp: could not activate relp listener, code %d", relpRet);
+ ABORT_FINALIZE(RS_RET_RELP_ERR);
+ }
+
+ DBGPRINTF("imrelp: max data size %zd\n", inst->maxDataSize);
+ resetConfigVariables(NULL,NULL);
+
+finalize_it:
+ RETiRet;
+}
+
+
+BEGINnewInpInst
+ struct cnfparamvals *pvals;
+ instanceConf_t *inst = NULL;
+ int i,j;
+ FILE *fp;
+CODESTARTnewInpInst
+ DBGPRINTF("newInpInst (imrelp)\n");
+
+ if((pvals = nvlstGetParams(lst, &inppblk, NULL)) == NULL) {
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ if(Debug) {
+ dbgprintf("input param blk in imrelp:\n");
+ cnfparamsPrint(&inppblk, pvals);
+ }
+
+ CHKiRet(createInstance(&inst));
+
+ for(i = 0 ; i < inppblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(inppblk.descr[i].name, "port")) {
+ inst->pszBindPort = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "address")) {
+ #if defined(HAVE_RELPSRVSETLSTNADDR)
+ inst->pszBindAddr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ #else
+ parser_errmsg("imrelp: librelp does not support input parameter 'address'; "
+ "it probably is too old (1.2.16 should be fine); ignoring setting now, "
+ "listening on all interfaces");
+ #endif
+ } 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, "ruleset")) {
+ inst->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "maxdatasize")) {
+ inst->maxDataSize = (size_t) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "flowcontrol")) {
+ if(!es_strconstcmp(pvals[i].val.d.estr, "none")) {
+ inst->flowCtlType = eFLOWCTL_NO_DELAY;
+ } else if(!es_strconstcmp(pvals[i].val.d.estr, "light")) {
+ inst->flowCtlType = eFLOWCTL_LIGHT_DELAY;
+ } else if(!es_strconstcmp(pvals[i].val.d.estr, "full")) {
+ inst->flowCtlType = eFLOWCTL_FULL_DELAY;
+ } else {
+ const char *const mode = es_str2cstr(pvals[i].val.d.estr, NULL);
+ parser_errmsg("imrelp: wrong flowcontrol parameter "
+ "value '%s', using default: 'light'; possible "
+ "values: 'no', 'light', 'full'\n", mode);
+ free((void*)mode);
+ }
+ } else if(!strcmp(inppblk.descr[i].name, "oversizemode")) {
+#ifdef HAVE_RELPSRVSETOVERSIZEMODE
+ char *mode = es_str2cstr(pvals[i].val.d.estr, NULL);
+ if(!strcmp(mode, "abort")) {
+ inst->oversizeMode = RELP_OVERSIZE_ABORT;
+ } else if(!strcmp(mode, "truncate")) {
+ inst->oversizeMode = RELP_OVERSIZE_TRUNCATE;
+ } else if(!strcmp(mode, "accept")) {
+ inst->oversizeMode = RELP_OVERSIZE_ACCEPT;
+ } else {
+ parser_errmsg("imrelp: wrong oversizeMode parameter "
+ "value %s, using default: truncate\n", mode);
+ inst->oversizeMode = RELP_OVERSIZE_TRUNCATE;
+ }
+#else
+ parser_errmsg("imrelp: parameter oversizeMode is not available in "
+ "this relp version and is therefore disabled.");
+#endif
+ } else if(!strcmp(inppblk.descr[i].name, "keepalive")) {
+ inst->bKeepAlive = (sbool) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "keepalive.probes")) {
+ inst->iKeepAliveProbes = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "keepalive.time")) {
+ inst->iKeepAliveTime = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "keepalive.interval")) {
+ inst->iKeepAliveIntvl = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "tls")) {
+ inst->bEnableTLS = (unsigned) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "tls.dhbits")) {
+ inst->dhBits = (unsigned) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "tls.prioritystring")) {
+ inst->pristring = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "tls.authmode")) {
+ inst->authmode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "tls.compression")) {
+ inst->bEnableTLSZip = (unsigned) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "tls.cacert")) {
+ inst->caCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ fp = fopen((const char*)inst->caCertFile, "r");
+ if(fp == NULL) {
+ char errStr[1024];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ LogError(0, RS_RET_NO_FILE_ACCESS,
+ "error: certificate file %s couldn't be accessed: %s\n",
+ inst->caCertFile, errStr);
+ } else {
+ fclose(fp);
+ }
+ } else if(!strcmp(inppblk.descr[i].name, "tls.mycert")) {
+ inst->myCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ fp = fopen((const char*)inst->myCertFile, "r");
+ if(fp == NULL) {
+ char errStr[1024];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ LogError(0, RS_RET_NO_FILE_ACCESS,
+ "error: certificate file %s couldn't be accessed: %s\n",
+ inst->myCertFile, errStr);
+ } else {
+ fclose(fp);
+ }
+ } else if(!strcmp(inppblk.descr[i].name, "tls.myprivkey")) {
+ inst->myPrivKeyFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ fp = fopen((const char*)inst->myPrivKeyFile, "r");
+ if(fp == NULL) {
+ char errStr[1024];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ LogError(0, RS_RET_NO_FILE_ACCESS,
+ "error: certificate file %s couldn't be accessed: %s\n",
+ inst->myPrivKeyFile, errStr);
+ } else {
+ fclose(fp);
+ }
+ } else if(!strcmp(inppblk.descr[i].name, "tls.tlscfgcmd")) {
+#if defined(HAVE_RELPENGINESETTLSCFGCMD)
+ inst->tlscfgcmd = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+#else
+ parser_errmsg("imrelp: librelp does not support input parameter 'tls.tlscfgcmd'; "
+ "it probably is too old (1.5.0 or higher should be fine); ignoring setting now.");
+#endif
+ } else if(!strcmp(inppblk.descr[i].name, "tls.permittedpeer")) {
+ inst->permittedPeers.nmemb = pvals[i].val.d.ar->nmemb;
+ CHKmalloc(inst->permittedPeers.name =
+ malloc(sizeof(uchar*) * inst->permittedPeers.nmemb));
+ for(j = 0 ; j < pvals[i].val.d.ar->nmemb ; ++j) {
+ inst->permittedPeers.name[j] = (uchar*)es_str2cstr(pvals[i].val.d.ar->arr[j], NULL);
+ }
+ } else {
+ dbgprintf("imrelp: program error, non-handled "
+ "param '%s'\n", inppblk.descr[i].name);
+ }
+ }
+
+ if(inst->myCertFile != NULL && inst->myPrivKeyFile == NULL) {
+ LogError(0, RS_RET_ERR, "imrelp: certificate file given but no corresponding "
+ "private key file - this is invalid, listener cannot be started");
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ if(inst->myCertFile == NULL && inst->myPrivKeyFile != NULL) {
+ LogError(0, RS_RET_ERR, "imrelp: private key file given but no corresponding "
+ "certificate file - this is invalid, listener cannot be started");
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+ inst->bEnableLstn = -1; /* all ok, ready to start up */
+
+finalize_it:
+CODE_STD_FINALIZERnewInpInst
+ cnfparamvalsDestruct(pvals, &inppblk);
+ if(iRet != RS_RET_OK) {
+ if(inst != NULL) {
+ free(inst->myCertFile);
+ inst->myCertFile = NULL;
+ free(inst->myPrivKeyFile);
+ inst->myPrivKeyFile = NULL;
+ }
+ }
+ENDnewInpInst
+
+
+BEGINbeginCnfLoad
+CODESTARTbeginCnfLoad
+ loadModConf = pModConf;
+ pModConf->pConf = pConf;
+ pModConf->pszBindRuleset = NULL;
+ pModConf->tlslib = NULL;
+ /* init legacy config variables */
+ cs.pszBindRuleset = NULL;
+ bLegacyCnfModGlobalsPermitted = 1;
+ENDbeginCnfLoad
+
+
+BEGINsetModCnf
+ struct cnfparamvals *pvals = NULL;
+ int i;
+CODESTARTsetModCnf
+ pvals = nvlstGetParams(lst, &modpblk, NULL);
+ if(pvals == NULL) {
+ LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module "
+ "config parameters [module(...)]");
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ if(Debug) {
+ dbgprintf("module (global) param blk for imrelp:\n");
+ cnfparamsPrint(&modpblk, pvals);
+ }
+
+ for(i = 0 ; i < modpblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(modpblk.descr[i].name, "ruleset")) {
+ loadModConf->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(modpblk.descr[i].name, "tls.tlslib")) {
+ #if defined(HAVE_RELPENGINESETTLSLIBBYNAME)
+ loadModConf->tlslib = es_str2cstr(pvals[i].val.d.estr, NULL);
+ #else
+ LogError(0, RS_RET_NOT_IMPLEMENTED,
+ "imrelp warning: parameter tls.tlslib ignored - librelp does not support "
+ "this API call. Using whatever librelp was compiled with.");
+ #endif
+ } else {
+ dbgprintf("imrelp: program error, non-handled "
+ "param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
+ }
+ }
+ /* remove all of our legacy module handlers, as they can not used in addition
+ * the the new-style config method.
+ */
+ bLegacyCnfModGlobalsPermitted = 0;
+finalize_it:
+ if(pvals != NULL)
+ cnfparamvalsDestruct(pvals, &modpblk);
+ENDsetModCnf
+
+BEGINendCnfLoad
+CODESTARTendCnfLoad
+ if(loadModConf->pszBindRuleset == NULL) {
+ if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) {
+ loadModConf->pszBindRuleset = NULL;
+ } else {
+ CHKmalloc(loadModConf->pszBindRuleset = ustrdup(cs.pszBindRuleset));
+ }
+ } else {
+ if((cs.pszBindRuleset != NULL) && (cs.pszBindRuleset[0] != '\0')) {
+ LogError(0, RS_RET_DUP_PARAM, "imrelp: ruleset "
+ "set via legacy directive ignored");
+ }
+ }
+finalize_it:
+ free(cs.pszBindRuleset);
+ cs.pszBindRuleset = NULL;
+ loadModConf = NULL; /* done loading */
+ENDendCnfLoad
+
+BEGINcheckCnf
+ instanceConf_t *inst;
+ size_t maxMessageSize;
+CODESTARTcheckCnf
+ for(inst = pModConf->root ; inst != NULL ; inst = inst->next) {
+ if(inst->pszBindRuleset == NULL && pModConf->pszBindRuleset != NULL) {
+ CHKmalloc(inst->pszBindRuleset = ustrdup(pModConf->pszBindRuleset));
+ }
+ std_checkRuleset(pModConf, inst);
+
+
+ if(inst->maxDataSize == 0) {
+ /* We set default value for maxDataSize here because
+ * otherwise the maxMessageSize isn't set.
+ */
+ inst->maxDataSize = glbl.GetMaxLine(loadConf);
+ }
+ maxMessageSize = (size_t)glbl.GetMaxLine(loadConf);
+ if(inst->maxDataSize < maxMessageSize) {
+ LogError(0, RS_RET_INVALID_PARAMS, "error: "
+ "maxDataSize (%zu) is smaller than global parameter "
+ "maxMessageSize (%zu) - global parameter will be used.",
+ inst->maxDataSize, maxMessageSize);
+ inst->maxDataSize = maxMessageSize;
+ }
+ }
+
+finalize_it:
+ENDcheckCnf
+
+
+BEGINactivateCnfPrePrivDrop
+ instanceConf_t *inst;
+CODESTARTactivateCnfPrePrivDrop
+ runModConf = pModConf;
+ for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
+ addListner(pModConf, inst);
+ }
+ if(pRelpEngine == NULL) {
+ LogError(0, RS_RET_NO_LSTN_DEFINED, "imrelp: no RELP listener defined, module can not run.");
+ ABORT_FINALIZE(RS_RET_NO_RUN);
+ }
+finalize_it:
+ENDactivateCnfPrePrivDrop
+
+BEGINactivateCnf
+CODESTARTactivateCnf
+ENDactivateCnf
+
+
+BEGINfreeCnf
+ instanceConf_t *inst, *del;
+ int i;
+CODESTARTfreeCnf
+ for(inst = pModConf->root ; inst != NULL ; ) {
+ free(inst->pszBindPort);
+ if (inst->pszBindAddr != NULL) {
+ free(inst->pszBindAddr);
+ }
+ free(inst->pszBindRuleset);
+ free(inst->pszInputName);
+ free(inst->pristring);
+ free(inst->authmode);
+ for(i = 0 ; i < inst->permittedPeers.nmemb ; ++i) {
+ free(inst->permittedPeers.name[i]);
+ }
+ if(inst->bEnableLstn) {
+ prop.Destruct(&inst->pInputName);
+ statsobj.Destruct(&(inst->data.stats));
+ }
+ del = inst;
+ inst = inst->next;
+ free(del);
+ }
+ free(pModConf->pszBindRuleset);
+ENDfreeCnf
+
+/* This is used to terminate the plugin. Note that the signal handler blocks
+ * other activity on the thread. As such, it is safe to request the stop. When
+ * we terminate, relpEngine is called, and it's select() loop interrupted. But
+ * only *after this function is done*. So we do not have a race!
+ */
+static void
+doSIGTTIN(int __attribute__((unused)) sig)
+{
+ const int bTerminate = ATOMIC_FETCH_32BIT(&bTerminateInputs, &mutTerminateInputs);
+ if(bTerminate && (pRelpEngine != NULL)) {
+ relpEngineSetStop(pRelpEngine);
+ }
+}
+
+
+/* This function is called to gather input.
+ */
+BEGINrunInput
+ sigset_t sigSet;
+ struct sigaction sigAct;
+CODESTARTrunInput
+ /* we want to support non-cancel input termination. To do so, we must signal librelp
+ * when to stop. As we run on the same thread, we need to register as SIGTTIN handler,
+ * which will be used to put the terminating condition into librelp.
+ */
+ sigfillset(&sigSet);
+ pthread_sigmask(SIG_BLOCK, &sigSet, NULL);
+ sigemptyset(&sigSet);
+ sigaddset(&sigSet, SIGTTIN);
+ pthread_sigmask(SIG_UNBLOCK, &sigSet, NULL);
+ memset(&sigAct, 0, sizeof (sigAct));
+ sigemptyset(&sigAct.sa_mask);
+ sigAct.sa_handler = doSIGTTIN;
+ sigaction(SIGTTIN, &sigAct, NULL);
+
+ iRet = relpEngineRun(pRelpEngine);
+ENDrunInput
+
+
+BEGINwillRun
+CODESTARTwillRun
+ENDwillRun
+
+
+BEGINafterRun
+CODESTARTafterRun
+ /* do cleanup here */
+ENDafterRun
+
+
+BEGINmodExit
+CODESTARTmodExit
+ struct sigaction newAct;
+ memset(&newAct, 0, sizeof (newAct));
+ sigemptyset(&newAct.sa_mask);
+ newAct.sa_handler = SIG_IGN;
+ sigaction(SIGTTIN, &newAct, NULL);
+
+ if(pRelpEngine != NULL)
+ iRet = relpEngineDestruct(&pRelpEngine);
+
+ /* release objects we used */
+ objRelease(statsobj, CORE_COMPONENT);
+ objRelease(ruleset, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
+ objRelease(net, LM_NET_FILENAME);
+ENDmodExit
+
+
+static rsRetVal
+resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ free(cs.pszBindRuleset);
+ cs.pszBindRuleset = NULL;
+ return RS_RET_OK;
+}
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURENonCancelInputTermination)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_IMOD_QUERIES
+CODEqueryEtryPt_STD_CONF2_QUERIES
+CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES
+CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES
+CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ pRelpEngine = NULL;
+ /* request objects we use */
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
+ CHKiRet(objUse(net, LM_NET_FILENAME));
+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
+ CHKiRet(objUse(statsobj, CORE_COMPONENT));
+
+ #ifndef HAVE_RELPSRVSETOVERSIZEMODE
+ LogMsg(0, RS_RET_OK_WARN, LOG_WARNING, "imrelp: librelp too old, oversizemode "
+ "defaults to \"abort\"");
+ #endif
+
+ /* register config file handlers */
+ CHKiRet(regCfSysLineHdlr2((uchar*)"inputrelpserverbindruleset", 0, eCmdHdlrGetWord,
+ NULL, &cs.pszBindRuleset, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrelpserverrun", 0, eCmdHdlrGetWord,
+ addInstance, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ENDmodInit