1 /* imrelp.c
2  *
3  * This is the implementation of the RELP input module.
4  *
5  * File begun on 2008-03-13 by RGerhards
6  *
7  * Copyright 2008-2019 Adiscon GmbH.
8  *
9  * This file is part of rsyslog.
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  *       http://www.apache.org/licenses/LICENSE-2.0
16  *       -or-
17  *       see COPYING.ASL20 in the source distribution
18  *
19  * Unless required by applicable law or agreed to in writing, software
20  * distributed under the License is distributed on an "AS IS" BASIS,
21  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  * See the License for the specific language governing permissions and
23  * limitations under the License.
24  */
25 #include "config.h"
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <stdarg.h>
32 #include <ctype.h>
33 #include <netinet/in.h>
34 #include <netdb.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <signal.h>
38 #include <librelp.h>
39 #include "rsyslog.h"
40 #include "dirty.h"
41 #include "errmsg.h"
42 #include "cfsysline.h"
43 #include "module-template.h"
44 #include "net.h"
45 #include "msg.h"
46 #include "unicode-helper.h"
47 #include "prop.h"
48 #include "ruleset.h"
49 #include "glbl.h"
50 #include "statsobj.h"
51 #include "srUtils.h"
52 #include "parserif.h"
53 
54 MODULE_TYPE_INPUT
55 MODULE_TYPE_NOKEEP
56 MODULE_CNFNAME("imrelp")
57 
58 /* static data */
59 DEF_IMOD_STATIC_DATA
60 DEFobjCurrIf(net)
61 DEFobjCurrIf(prop)
62 DEFobjCurrIf(ruleset)
63 DEFobjCurrIf(glbl)
64 DEFobjCurrIf(statsobj)
65 
66 /* forward definitions */
67 static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
68 
69 
70 /* Module static data */
71 /* config vars for legacy config system */
72 static relpEngine_t *pRelpEngine;	/* our relp engine */
73 
74 /* config settings */
75 typedef struct configSettings_s {
76 	uchar *pszBindRuleset;		/* name of Ruleset to bind to */
77 } configSettings_t;
78 static configSettings_t cs;
79 
80 struct instanceConf_s {
81 	uchar *pszBindPort;		/* port to bind to */
82 	uchar *pszBindAddr;		/* address to bind to */
83 	uchar *pszBindRuleset;		/* name of ruleset to bind to */
84 	uchar *pszInputName;		/* value for inputname property */
85 	prop_t *pInputName;		/* InputName in property format for fast access */
86 	ruleset_t *pBindRuleset;	/* ruleset to bind listener to */
87 	sbool bKeepAlive;		/* support keep-alive packets */
88 	sbool bEnableTLS;
89 	sbool bEnableTLSZip;
90 	sbool bEnableLstn;		/* flag to permit disabling of listener in error case */
91 	int dhBits;
92 	size_t maxDataSize;
93 	int oversizeMode;
94 	uchar *pristring;		/* GnuTLS priority string (NULL if not to be provided) */
95 	uchar *authmode;		/* TLS auth mode */
96 	uchar *caCertFile;
97 	uchar *myCertFile;
98 	uchar *myPrivKeyFile;
99 #if defined(HAVE_RELPENGINESETTLSCFGCMD)
100 	uchar *tlscfgcmd;
101 #endif
102 	int iKeepAliveIntvl;
103 	int iKeepAliveProbes;
104 	int iKeepAliveTime;
105 	flowControl_t flowCtlType;
106 	struct {
107 		int nmemb;
108 		uchar **name;
109 	} permittedPeers;
110 
111 	struct instanceConf_s *next;
112 	/* with librelp, this module does not have any own specific session
113 	 * or listener active data item. As a "work-around", we keep some
114 	 * data items inside the configuration object. To keep things
115 	 * decently clean, we put them all into their dedicated struct. So
116 	 * it is easy to judge what is actual configuration and what is
117 	 * dynamic runtime data. -- rgerhards, 2013-06-18
118 	 */
119 	struct {
120 		statsobj_t *stats;	/* listener stats */
121 		STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit)
122 	} data;
123 };
124 
125 
126 struct modConfData_s {
127 	rsconf_t *pConf;		/* our overall config object */
128 	instanceConf_t *root, *tail;
129 	const char *tlslib;
130 	uchar *pszBindRuleset;		/* default name of Ruleset to bind to */
131 };
132 
133 static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
134 static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */
135 
136 /* module-global parameters */
137 static struct cnfparamdescr modpdescr[] = {
138 	{ "ruleset", eCmdHdlrGetWord, 0 },
139 	{ "tls.tlslib", eCmdHdlrString, 0 }
140 };
141 static struct cnfparamblk modpblk =
142 	{ CNFPARAMBLK_VERSION,
143 	  sizeof(modpdescr)/sizeof(struct cnfparamdescr),
144 	  modpdescr
145 	};
146 
147 /* input instance parameters */
148 static struct cnfparamdescr inppdescr[] = {
149 	{ "port", eCmdHdlrString, CNFPARAM_REQUIRED },
150 	{ "address", eCmdHdlrString, 0 },
151 	{ "name", eCmdHdlrString, 0 },
152 	{ "ruleset", eCmdHdlrString, 0 },
153 	{ "keepalive", eCmdHdlrBinary, 0 },
154 	{ "keepalive.probes", eCmdHdlrInt, 0 },
155 	{ "keepalive.time", eCmdHdlrInt, 0 },
156 	{ "keepalive.interval", eCmdHdlrInt, 0 },
157 	{ "maxdatasize", eCmdHdlrSize, 0 },
158 	{ "oversizemode", eCmdHdlrString, 0 },
159 	{ "flowcontrol", eCmdHdlrGetWord, 0 },
160 	{ "tls", eCmdHdlrBinary, 0 },
161 	{ "tls.permittedpeer", eCmdHdlrArray, 0 },
162 	{ "tls.authmode", eCmdHdlrString, 0 },
163 	{ "tls.dhbits", eCmdHdlrInt, 0 },
164 	{ "tls.prioritystring", eCmdHdlrString, 0 },
165 	{ "tls.cacert", eCmdHdlrString, 0 },
166 	{ "tls.mycert", eCmdHdlrString, 0 },
167 	{ "tls.myprivkey", eCmdHdlrString, 0 },
168 	{ "tls.tlscfgcmd", eCmdHdlrString, 0 },
169 	{ "tls.compression", eCmdHdlrBinary, 0 }
170 };
171 static struct cnfparamblk inppblk =
172 	{ CNFPARAMBLK_VERSION,
173 	  sizeof(inppdescr)/sizeof(struct cnfparamdescr),
174 	  inppdescr
175 	};
176 
177 #include "im-helper.h" /* must be included AFTER the type definitions! */
178 static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */
179 
180 /* ------------------------------ callbacks ------------------------------ */
181 
182 PRAGMA_DIAGNOSTIC_PUSH
183 PRAGMA_IGNORE_Wformat_nonliteral
184 static void __attribute__((format(printf, 1, 2)))
imrelp_dbgprintf(const char * fmt,...)185 imrelp_dbgprintf(const char *fmt, ...)
186 {
187 	va_list ap;
188 	char pszWriteBuf[32*1024+1]; //this function has to be able to
189 					/*generate a buffer longer than that of r_dbgprintf, so
190 					r_dbgprintf can properly truncate*/
191 
192 	if(!(Debug && debugging_on)) {
193 		return;
194 	}
195 
196 	va_start(ap, fmt);
197 	vsnprintf(pszWriteBuf, sizeof(pszWriteBuf), fmt, ap);
198 	va_end(ap);
199 	r_dbgprintf("imrelp.c", "%s", pszWriteBuf);
200 }
201 PRAGMA_DIAGNOSTIC_POP
202 
203 static void
onErr(void * pUsr,char * objinfo,char * errmesg,relpRetVal errcode)204 onErr(void *pUsr, char *objinfo, char* errmesg, __attribute__((unused)) relpRetVal errcode)
205 {
206 	instanceConf_t *inst = (instanceConf_t*) pUsr;
207 	LogError(0, RS_RET_RELP_AUTH_FAIL, "imrelp[%s]: error '%s', object "
208 			" '%s' - input may not work as intended",
209 			inst->pszBindPort, errmesg, objinfo);
210 }
211 
212 static void
onGenericErr(char * objinfo,char * errmesg,relpRetVal errcode)213 onGenericErr(char *objinfo, char* errmesg, __attribute__((unused)) relpRetVal errcode)
214 {
215 	LogError(0, RS_RET_RELP_ERR, "imrelp: librelp error '%s', object "
216 			" '%s' - input may not work as intended", errmesg, objinfo);
217 }
218 
219 static void
onAuthErr(void * pUsr,char * authinfo,char * errmesg,relpRetVal errcode)220 onAuthErr(void *pUsr, char *authinfo, char* errmesg, __attribute__((unused)) relpRetVal errcode)
221 {
222 	instanceConf_t *inst = (instanceConf_t*) pUsr;
223 	LogError(0, RS_RET_RELP_AUTH_FAIL, "imrelp[%s]: authentication error '%s', peer "
224 			"is '%s'", inst->pszBindPort, errmesg, authinfo);
225 }
226 
227 /* callback for receiving syslog messages. This function is invoked from the
228  * RELP engine when a syslog message arrived. It must return a relpRetVal,
229  * with anything else but RELP_RET_OK terminating the relp session. Please note
230  * that RELP_RET_OK is equal to RS_RET_OK and the other libRELP error codes
231  * are different from our rsRetVal. So we can simply use our own iRet system
232  * to fulfill the requirement.
233  * rgerhards, 2008-03-21
234  * Note: librelp 1.0.0 is required in order to receive the IP address, otherwise
235  * we will only see the hostname (twice). -- rgerhards, 2009-10-14
236  */
237 static relpRetVal
onSyslogRcv(void * pUsr,uchar * pHostname,uchar * pIP,uchar * msg,size_t lenMsg)238 onSyslogRcv(void *pUsr, uchar *pHostname, uchar *pIP, uchar *msg, size_t lenMsg)
239 {
240 	prop_t *pProp = NULL;
241 	smsg_t *pMsg;
242 	instanceConf_t *inst = (instanceConf_t*) pUsr;
243 	DEFiRet;
244 
245 	CHKiRet(msgConstruct(&pMsg));
246 	MsgSetInputName(pMsg, inst->pInputName);
247 	MsgSetRawMsg(pMsg, (char*)msg, lenMsg);
248 	MsgSetFlowControlType(pMsg, inst->flowCtlType);
249 	MsgSetRuleset(pMsg, inst->pBindRuleset);
250 	pMsg->msgFlags  = PARSE_HOSTNAME | NEEDS_PARSING;
251 
252 	/* TODO: optimize this, we can store it inside the session */
253 	MsgSetRcvFromStr(pMsg, pHostname, ustrlen(pHostname), &pProp);
254 	CHKiRet(prop.Destruct(&pProp));
255 	CHKiRet(MsgSetRcvFromIPStr(pMsg, pIP, ustrlen(pIP), &pProp));
256 	CHKiRet(prop.Destruct(&pProp));
257 	CHKiRet(submitMsg2(pMsg));
258 	STATSCOUNTER_INC(inst->data.ctrSubmit, inst->data.mutCtrSubmit);
259 
260 finalize_it:
261 
262 	RETiRet;
263 }
264 
265 
266 /* ------------------------------ end callbacks ------------------------------ */
267 
268 /* create input instance, set default parameters, and
269  * add it to the list of instances.
270  */
271 static rsRetVal
createInstance(instanceConf_t ** pinst)272 createInstance(instanceConf_t **pinst)
273 {
274 	instanceConf_t *inst;
275 	DEFiRet;
276 	CHKmalloc(inst = malloc(sizeof(instanceConf_t)));
277 	inst->next = NULL;
278 
279 	inst->pszBindPort = NULL;
280 	inst->pszBindAddr = NULL;
281 	inst->pszBindRuleset = NULL;
282 	inst->pszInputName = NULL;
283 	inst->pBindRuleset = NULL;
284 	inst->bKeepAlive = 0;
285 	inst->iKeepAliveIntvl = 0;
286 	inst->iKeepAliveProbes = 0;
287 	inst->iKeepAliveTime = 0;
288 	inst->bEnableTLS = 0;
289 	inst->bEnableTLSZip = 0;
290 	inst->bEnableLstn = 0;
291 	inst->dhBits = 0;
292 	inst->pristring = NULL;
293 	inst->authmode = NULL;
294 	inst->permittedPeers.nmemb = 0;
295 	inst->caCertFile = NULL;
296 	inst->myCertFile = NULL;
297 	inst->myPrivKeyFile = NULL;
298 #if defined(HAVE_RELPENGINESETTLSCFGCMD)
299 	inst->tlscfgcmd = NULL;
300 #endif
301 	inst->maxDataSize = 0;
302 	inst->flowCtlType = eFLOWCTL_LIGHT_DELAY;
303 #ifdef HAVE_RELPSRVSETOVERSIZEMODE
304 	inst->oversizeMode = RELP_OVERSIZE_TRUNCATE;
305 #endif
306 
307 	/* node created, let's add to config */
308 	if(loadModConf->tail == NULL) {
309 		loadModConf->tail = loadModConf->root = inst;
310 	} else {
311 		loadModConf->tail->next = inst;
312 		loadModConf->tail = inst;
313 	}
314 
315 	*pinst = inst;
316 finalize_it:
317 	RETiRet;
318 }
319 
320 
321 /* function to generate an error message if the ruleset cannot be found */
322 static inline void
std_checkRuleset_genErrMsg(modConfData_t * modConf,instanceConf_t * inst)323 std_checkRuleset_genErrMsg(__attribute__((unused)) modConfData_t *modConf, instanceConf_t *inst)
324 {
325 	LogError(0, NO_ERRCODE, "imrelp[%s]: ruleset '%s' not found - "
326 			"using default ruleset instead",
327 			inst->pszBindPort, inst->pszBindRuleset);
328 }
329 
330 
331 /* This function is called when a new listener instance shall be added to
332  * the current config object via the legacy config system. It just shuffles
333  * all parameters to the listener in-memory instance.
334  * rgerhards, 2011-05-04
335  */
addInstance(void * pVal,uchar * pNewVal)336 static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal)
337 {
338 	instanceConf_t *inst;
339 	DEFiRet;
340 
341 	CHKiRet(createInstance(&inst));
342 
343 	if(pNewVal == NULL || *pNewVal == '\0') {
344 		LogError(0, NO_ERRCODE, "imrelp: port number must be specified, listener ignored");
345 	}
346 	if((pNewVal == NULL) || (*pNewVal == '\0')) {
347 		inst->pszBindPort = NULL;
348 	} else {
349 		CHKmalloc(inst->pszBindPort = ustrdup(pNewVal));
350 	}
351 	if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) {
352 		inst->pszBindRuleset = NULL;
353 	} else {
354 		CHKmalloc(inst->pszBindRuleset = ustrdup(cs.pszBindRuleset));
355 	}
356 	inst->pBindRuleset = NULL;
357 
358 	inst->bEnableLstn = -1; /* all ok, ready to start up */
359 finalize_it:
360 	free(pNewVal);
361 	RETiRet;
362 }
363 
364 
365 static rsRetVal
addListner(modConfData_t * modConf,instanceConf_t * inst)366 addListner(modConfData_t __attribute__((unused)) *modConf, instanceConf_t *inst)
367 {
368 	relpSrv_t *pSrv;
369 	int relpRet;
370 	uchar statname[64];
371 	int i;
372 	DEFiRet;
373 
374 	if(!inst->bEnableLstn) {
375 		DBGPRINTF("listener not started because it is disabled by config error\n");
376 		FINALIZE;
377 	}
378 
379 	if(pRelpEngine == NULL) {
380 		CHKiRet(relpEngineConstruct(&pRelpEngine));
381 		CHKiRet(relpEngineSetDbgprint(pRelpEngine, (void (*)(char *, ...))imrelp_dbgprintf));
382 		CHKiRet(relpEngineSetFamily(pRelpEngine, glbl.GetDefPFFamily()));
383 		CHKiRet(relpEngineSetEnableCmd(pRelpEngine, (uchar*) "syslog", eRelpCmdState_Required));
384 		CHKiRet(relpEngineSetSyslogRcv2(pRelpEngine, onSyslogRcv));
385 		CHKiRet(relpEngineSetOnErr(pRelpEngine, onErr));
386 		CHKiRet(relpEngineSetOnGenericErr(pRelpEngine, onGenericErr));
387 		CHKiRet(relpEngineSetOnAuthErr(pRelpEngine, onAuthErr));
388 		if (!glbl.GetDisableDNS()) {
389 			CHKiRet(relpEngineSetDnsLookupMode(pRelpEngine, 1));
390 		}
391 		#if defined(HAVE_RELPENGINESETTLSLIBBYNAME)
392 			if(modConf->tlslib != NULL) {
393 				if(relpEngineSetTLSLibByName(pRelpEngine, modConf->tlslib) != RELP_RET_OK) {
394 					LogMsg(0, RS_RET_CONF_PARAM_INVLD, LOG_WARNING,
395 						"imrelp: tlslib '%s' not accepted as valid by librelp - using default",
396 						modConf->tlslib);
397 				}
398 			}
399 		#endif
400 	}
401 
402 	CHKiRet(relpEngineListnerConstruct(pRelpEngine, &pSrv));
403 	CHKiRet(relpSrvSetMaxDataSize(pSrv, inst->maxDataSize));
404 	CHKiRet(relpSrvSetLstnPort(pSrv, inst->pszBindPort));
405 	#if defined(HAVE_RELPSRVSETLSTNADDR)
406 		CHKiRet(relpSrvSetLstnAddr(pSrv, inst->pszBindAddr));
407 	#endif
408 
409 #ifdef HAVE_RELPSRVSETOVERSIZEMODE
410 	CHKiRet(relpSrvSetOversizeMode(pSrv, inst->oversizeMode));
411 #endif
412 	inst->pszInputName = ustrdup((inst->pszInputName == NULL) ?  UCHAR_CONSTANT("imrelp") : inst->pszInputName);
413 	CHKiRet(prop.Construct(&inst->pInputName));
414 	CHKiRet(prop.SetString(inst->pInputName, inst->pszInputName, ustrlen(inst->pszInputName)));
415 	CHKiRet(prop.ConstructFinalize(inst->pInputName));
416 	/* support statistics gathering */
417 	CHKiRet(statsobj.Construct(&(inst->data.stats)));
418 	snprintf((char*)statname, sizeof(statname), "%s(%s)",
419 		 inst->pszInputName, inst->pszBindPort);
420 	statname[sizeof(statname)-1] = '\0'; /* just to be on the save side... */
421 	CHKiRet(statsobj.SetName(inst->data.stats, statname));
422 	CHKiRet(statsobj.SetOrigin(inst->data.stats, (uchar*)"imrelp"));
423 	STATSCOUNTER_INIT(inst->data.ctrSubmit, inst->data.mutCtrSubmit);
424 	CHKiRet(statsobj.AddCounter(inst->data.stats, UCHAR_CONSTANT("submitted"),
425 		ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(inst->data.ctrSubmit)));
426 	CHKiRet(statsobj.ConstructFinalize(inst->data.stats));
427 	/* end stats counters */
428 	relpSrvSetUsrPtr(pSrv, inst);
429 	relpSrvSetKeepAlive(pSrv, inst->bKeepAlive, inst->iKeepAliveIntvl,
430 			    inst->iKeepAliveProbes, inst->iKeepAliveTime);
431 	if(inst->bEnableTLS) {
432 		relpRet = relpSrvEnableTLS2(pSrv);
433 		if(relpRet == RELP_RET_ERR_NO_TLS) {
434 			LogError(0, RS_RET_RELP_NO_TLS,
435 					"imrelp: could not activate relp TLS, librelp "
436 					"does not support it (most probably GnuTLS lib "
437 					"is too old)!");
438 			ABORT_FINALIZE(RS_RET_RELP_NO_TLS);
439 		} else if(relpRet == RELP_RET_ERR_NO_TLS_AUTH) {
440 			LogError(0, RS_RET_RELP_NO_TLS_AUTH,
441 					"imrelp: could not activate relp TLS with "
442 					"authentication, librelp does not support it "
443 					"(most probably GnuTLS lib is too old)! "
444 					"Note: anonymous TLS is probably supported.");
445 			ABORT_FINALIZE(RS_RET_RELP_NO_TLS_AUTH);
446 		} else if(relpRet != RELP_RET_OK) {
447 			LogError(0, RS_RET_RELP_ERR,
448 					"imrelp: could not activate relp TLS, code %d", relpRet);
449 			ABORT_FINALIZE(RS_RET_RELP_ERR);
450 		}
451 		if(inst->bEnableTLSZip) {
452 			relpSrvEnableTLSZip2(pSrv);
453 		}
454 		if(inst->dhBits) {
455 			relpSrvSetDHBits(pSrv, inst->dhBits);
456 		}
457 		relpSrvSetGnuTLSPriString(pSrv, (char*)inst->pristring);
458 		if(relpSrvSetAuthMode(pSrv, (char*)inst->authmode) != RELP_RET_OK) {
459 			LogError(0, RS_RET_RELP_ERR,
460 					"imrelp: invalid auth mode '%s'", inst->authmode);
461 			ABORT_FINALIZE(RS_RET_RELP_ERR);
462 		}
463 		if(relpSrvSetCACert(pSrv, (char*) inst->caCertFile) != RELP_RET_OK)
464 			ABORT_FINALIZE(RS_RET_RELP_ERR);
465 		if(relpSrvSetOwnCert(pSrv, (char*) inst->myCertFile) != RELP_RET_OK)
466 			ABORT_FINALIZE(RS_RET_RELP_ERR);
467 		if(relpSrvSetPrivKey(pSrv, (char*) inst->myPrivKeyFile) != RELP_RET_OK)
468 			ABORT_FINALIZE(RS_RET_RELP_ERR);
469 #if defined(HAVE_RELPENGINESETTLSCFGCMD)
470 		if (inst->tlscfgcmd != NULL) {
471 			if(relpSrvSetTlsConfigCmd(pSrv, (char*) inst->tlscfgcmd) != RELP_RET_OK)
472 				ABORT_FINALIZE(RS_RET_RELP_ERR);
473 		}
474 #endif
475 		for(i = 0 ; i <  inst->permittedPeers.nmemb ; ++i) {
476 			relpSrvAddPermittedPeer(pSrv, (char*)inst->permittedPeers.name[i]);
477 		}
478 	}
479 	relpRet = relpEngineListnerConstructFinalize(pRelpEngine, pSrv);
480 	/* re-check error TLS error codes. librelp seems to emit them only
481 	 * after finalize in some cases...
482 	 */
483 	if(relpRet == RELP_RET_ERR_NO_TLS) {
484 		LogError(0, RS_RET_RELP_NO_TLS,
485 				"imrelp: could not activate relp TLS listener, librelp "
486 				"does not support it (most probably GnuTLS lib "
487 				"is too old)!");
488 		ABORT_FINALIZE(RS_RET_RELP_NO_TLS);
489 	} else if(relpRet == RELP_RET_ERR_NO_TLS_AUTH) {
490 		LogError(0, RS_RET_RELP_NO_TLS_AUTH,
491 				"imrelp: could not activate relp TLS listener with "
492 				"authentication, librelp does not support it "
493 				"(most probably GnuTLS lib is too old)! "
494 				"Note: anonymous TLS is probably supported.");
495 		ABORT_FINALIZE(RS_RET_RELP_NO_TLS_AUTH);
496 	} else if(relpRet != RELP_RET_OK) {
497 		LogError(0, RS_RET_RELP_ERR,
498 				"imrelp: could not activate relp listener, code %d", relpRet);
499 		ABORT_FINALIZE(RS_RET_RELP_ERR);
500 	}
501 
502 	DBGPRINTF("imrelp: max data size %zd\n", inst->maxDataSize);
503 	resetConfigVariables(NULL,NULL);
504 
505 finalize_it:
506 	RETiRet;
507 }
508 
509 
510 BEGINnewInpInst
511 	struct cnfparamvals *pvals;
512 	instanceConf_t *inst = NULL;
513 	int i,j;
514 	FILE *fp;
515 CODESTARTnewInpInst
516 	DBGPRINTF("newInpInst (imrelp)\n");
517 
518 	if((pvals = nvlstGetParams(lst, &inppblk, NULL)) == NULL) {
519 		ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
520 	}
521 
522 	if(Debug) {
523 		dbgprintf("input param blk in imrelp:\n");
524 		cnfparamsPrint(&inppblk, pvals);
525 	}
526 
527 	CHKiRet(createInstance(&inst));
528 
529 	for(i = 0 ; i < inppblk.nParams ; ++i) {
530 		if(!pvals[i].bUsed)
531 			continue;
532 		if(!strcmp(inppblk.descr[i].name, "port")) {
533 			inst->pszBindPort = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
534 		} else if(!strcmp(inppblk.descr[i].name, "address")) {
535 			#if defined(HAVE_RELPSRVSETLSTNADDR)
536 				inst->pszBindAddr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
537 			#else
538 				parser_errmsg("imrelp: librelp does not support input parameter 'address'; "
539 					"it probably is too old (1.2.16 should be fine); ignoring setting now, "
540 					"listening on all interfaces");
541 			#endif
542 		} else if(!strcmp(inppblk.descr[i].name, "name")) {
543 			inst->pszInputName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
544 		} else if(!strcmp(inppblk.descr[i].name, "ruleset")) {
545 			inst->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
546 		} else if(!strcmp(inppblk.descr[i].name, "maxdatasize")) {
547 			inst->maxDataSize = (size_t) pvals[i].val.d.n;
548 		} else if(!strcmp(inppblk.descr[i].name, "flowcontrol")) {
549 			if(!es_strconstcmp(pvals[i].val.d.estr, "none")) {
550 				inst->flowCtlType = eFLOWCTL_NO_DELAY;
551 			} else if(!es_strconstcmp(pvals[i].val.d.estr, "light")) {
552 				inst->flowCtlType = eFLOWCTL_LIGHT_DELAY;
553 			} else if(!es_strconstcmp(pvals[i].val.d.estr, "full")) {
554 				inst->flowCtlType = eFLOWCTL_FULL_DELAY;
555 			} else {
556 				const char *const mode = es_str2cstr(pvals[i].val.d.estr, NULL);
557 				parser_errmsg("imrelp: wrong flowcontrol parameter "
558 					"value '%s', using default: 'light'; possible "
559 					"values: 'no', 'light', 'full'\n", mode);
560 				free((void*)mode);
561 			}
562 		} else if(!strcmp(inppblk.descr[i].name, "oversizemode")) {
563 #ifdef HAVE_RELPSRVSETOVERSIZEMODE
564 			char *mode = es_str2cstr(pvals[i].val.d.estr, NULL);
565 			if(!strcmp(mode, "abort")) {
566 				inst->oversizeMode = RELP_OVERSIZE_ABORT;
567 			} else if(!strcmp(mode, "truncate")) {
568 				inst->oversizeMode = RELP_OVERSIZE_TRUNCATE;
569 			} else if(!strcmp(mode, "accept")) {
570 				inst->oversizeMode = RELP_OVERSIZE_ACCEPT;
571 			} else {
572 				parser_errmsg("imrelp: wrong oversizeMode parameter "
573 					"value %s, using default: truncate\n", mode);
574 				inst->oversizeMode = RELP_OVERSIZE_TRUNCATE;
575 			}
576 #else
577 			parser_errmsg("imrelp: parameter oversizeMode is not available in "
578 				"this relp version and is therefore disabled.");
579 #endif
580 		} else if(!strcmp(inppblk.descr[i].name, "keepalive")) {
581 			inst->bKeepAlive = (sbool) pvals[i].val.d.n;
582 		} else if(!strcmp(inppblk.descr[i].name, "keepalive.probes")) {
583 			inst->iKeepAliveProbes = (int) pvals[i].val.d.n;
584 		} else if(!strcmp(inppblk.descr[i].name, "keepalive.time")) {
585 			inst->iKeepAliveTime = (int) pvals[i].val.d.n;
586 		} else if(!strcmp(inppblk.descr[i].name, "keepalive.interval")) {
587 			inst->iKeepAliveIntvl = (int) pvals[i].val.d.n;
588 		} else if(!strcmp(inppblk.descr[i].name, "tls")) {
589 			inst->bEnableTLS = (unsigned) pvals[i].val.d.n;
590 		} else if(!strcmp(inppblk.descr[i].name, "tls.dhbits")) {
591 			inst->dhBits = (unsigned) pvals[i].val.d.n;
592 		} else if(!strcmp(inppblk.descr[i].name, "tls.prioritystring")) {
593 			inst->pristring = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
594 		} else if(!strcmp(inppblk.descr[i].name, "tls.authmode")) {
595 			inst->authmode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
596 		} else if(!strcmp(inppblk.descr[i].name, "tls.compression")) {
597 			inst->bEnableTLSZip = (unsigned) pvals[i].val.d.n;
598 		} else if(!strcmp(inppblk.descr[i].name, "tls.cacert")) {
599 			inst->caCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
600 			fp = fopen((const char*)inst->caCertFile, "r");
601 			if(fp == NULL) {
602 				char errStr[1024];
603 				rs_strerror_r(errno, errStr, sizeof(errStr));
604 				LogError(0, RS_RET_NO_FILE_ACCESS,
605 				"error: certificate file %s couldn't be accessed: %s\n",
606 				inst->caCertFile, errStr);
607 			} else {
608 				fclose(fp);
609 			}
610 		} else if(!strcmp(inppblk.descr[i].name, "tls.mycert")) {
611 			inst->myCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
612 			fp = fopen((const char*)inst->myCertFile, "r");
613 			if(fp == NULL) {
614 				char errStr[1024];
615 				rs_strerror_r(errno, errStr, sizeof(errStr));
616 				LogError(0, RS_RET_NO_FILE_ACCESS,
617 				"error: certificate file %s couldn't be accessed: %s\n",
618 				inst->myCertFile, errStr);
619 			} else {
620 				fclose(fp);
621 			}
622 		} else if(!strcmp(inppblk.descr[i].name, "tls.myprivkey")) {
623 			inst->myPrivKeyFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
624 			fp = fopen((const char*)inst->myPrivKeyFile, "r");
625 			if(fp == NULL) {
626 				char errStr[1024];
627 				rs_strerror_r(errno, errStr, sizeof(errStr));
628 				LogError(0, RS_RET_NO_FILE_ACCESS,
629 				"error: certificate file %s couldn't be accessed: %s\n",
630 				inst->myPrivKeyFile, errStr);
631 			} else {
632 				fclose(fp);
633 			}
634 		} else if(!strcmp(inppblk.descr[i].name, "tls.tlscfgcmd")) {
635 #if defined(HAVE_RELPENGINESETTLSCFGCMD)
636 			inst->tlscfgcmd = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
637 #else
638 			parser_errmsg("imrelp: librelp does not support input parameter 'tls.tlscfgcmd'; "
639 				"it probably is too old (1.5.0 or higher should be fine); ignoring setting now.");
640 #endif
641 		} else if(!strcmp(inppblk.descr[i].name, "tls.permittedpeer")) {
642 			inst->permittedPeers.nmemb = pvals[i].val.d.ar->nmemb;
643 			CHKmalloc(inst->permittedPeers.name =
644 				malloc(sizeof(uchar*) * inst->permittedPeers.nmemb));
645 			for(j = 0 ; j <  pvals[i].val.d.ar->nmemb ; ++j) {
646 				inst->permittedPeers.name[j] = (uchar*)es_str2cstr(pvals[i].val.d.ar->arr[j], NULL);
647 			}
648 		} else {
649 			dbgprintf("imrelp: program error, non-handled "
650 			  "param '%s'\n", inppblk.descr[i].name);
651 		}
652 	}
653 
654 	if(inst->myCertFile  != NULL && inst->myPrivKeyFile == NULL) {
655 		LogError(0, RS_RET_ERR, "imrelp: certificate file given but no corresponding "
656 			"private key file - this is invalid, listener cannot be started");
657 		ABORT_FINALIZE(RS_RET_ERR);
658 	}
659 	if(inst->myCertFile  == NULL && inst->myPrivKeyFile != NULL) {
660 		LogError(0, RS_RET_ERR, "imrelp: private key file given but no corresponding "
661 			"certificate file - this is invalid, listener cannot be started");
662 		ABORT_FINALIZE(RS_RET_ERR);
663 	}
664 
665 	inst->bEnableLstn = -1; /* all ok, ready to start up */
666 
667 finalize_it:
668 CODE_STD_FINALIZERnewInpInst
669 	cnfparamvalsDestruct(pvals, &inppblk);
670 	if(iRet != RS_RET_OK) {
671 		if(inst != NULL) {
672 			free(inst->myCertFile);
673 			inst->myCertFile = NULL;
674 			free(inst->myPrivKeyFile);
675 			inst->myPrivKeyFile = NULL;
676 		}
677 	}
678 ENDnewInpInst
679 
680 
681 BEGINbeginCnfLoad
682 CODESTARTbeginCnfLoad
683 	loadModConf = pModConf;
684 	pModConf->pConf = pConf;
685 	pModConf->pszBindRuleset = NULL;
686 	pModConf->tlslib = NULL;
687 	/* init legacy config variables */
688 	cs.pszBindRuleset = NULL;
689 	bLegacyCnfModGlobalsPermitted = 1;
690 ENDbeginCnfLoad
691 
692 
693 BEGINsetModCnf
694 	struct cnfparamvals *pvals = NULL;
695 	int i;
696 CODESTARTsetModCnf
697 	pvals = nvlstGetParams(lst, &modpblk, NULL);
698 	if(pvals == NULL) {
699 		LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module "
700 				"config parameters [module(...)]");
701 		ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
702 	}
703 
704 	if(Debug) {
705 		dbgprintf("module (global) param blk for imrelp:\n");
706 		cnfparamsPrint(&modpblk, pvals);
707 	}
708 
709 	for(i = 0 ; i < modpblk.nParams ; ++i) {
710 		if(!pvals[i].bUsed)
711 			continue;
712 		if(!strcmp(modpblk.descr[i].name, "ruleset")) {
713 			loadModConf->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
714 		} else if(!strcmp(modpblk.descr[i].name, "tls.tlslib")) {
715 			#if defined(HAVE_RELPENGINESETTLSLIBBYNAME)
716 				loadModConf->tlslib = es_str2cstr(pvals[i].val.d.estr, NULL);
717 			#else
718 				LogError(0, RS_RET_NOT_IMPLEMENTED,
719 					"imrelp warning: parameter tls.tlslib ignored - librelp does not support "
720 					"this API call. Using whatever librelp was compiled with.");
721 			#endif
722 		} else {
723 			dbgprintf("imrelp: program error, non-handled "
724 			  "param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
725 		}
726 	}
727 	/* remove all of our legacy module handlers, as they can not used in addition
728 	 * the the new-style config method.
729 	 */
730 	bLegacyCnfModGlobalsPermitted = 0;
731 finalize_it:
732 	if(pvals != NULL)
733 		cnfparamvalsDestruct(pvals, &modpblk);
734 ENDsetModCnf
735 
736 BEGINendCnfLoad
737 CODESTARTendCnfLoad
738 	if(loadModConf->pszBindRuleset == NULL) {
739 		if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) {
740 			loadModConf->pszBindRuleset = NULL;
741 		} else {
742 			CHKmalloc(loadModConf->pszBindRuleset = ustrdup(cs.pszBindRuleset));
743 		}
744 	} else {
745 		if((cs.pszBindRuleset != NULL) && (cs.pszBindRuleset[0] != '\0')) {
746 			LogError(0, RS_RET_DUP_PARAM, "imrelp: ruleset "
747 					"set via legacy directive ignored");
748 		}
749 	}
750 finalize_it:
751 	free(cs.pszBindRuleset);
752 	cs.pszBindRuleset = NULL;
753 	loadModConf = NULL; /* done loading */
754 ENDendCnfLoad
755 
756 BEGINcheckCnf
757 	instanceConf_t *inst;
758 	size_t maxMessageSize;
759 CODESTARTcheckCnf
760 	for(inst = pModConf->root ; inst != NULL ; inst = inst->next) {
761 		if(inst->pszBindRuleset == NULL && pModConf->pszBindRuleset != NULL) {
762 			CHKmalloc(inst->pszBindRuleset = ustrdup(pModConf->pszBindRuleset));
763 		}
764 		std_checkRuleset(pModConf, inst);
765 
766 
767 		if(inst->maxDataSize == 0) {
768 			/* We set default value for maxDataSize here because
769 			 * otherwise the maxMessageSize isn't set.
770 			 */
771 			inst->maxDataSize = glbl.GetMaxLine();
772 		}
773 		maxMessageSize = (size_t)glbl.GetMaxLine();
774 		if(inst->maxDataSize < maxMessageSize) {
775 			LogError(0, RS_RET_INVALID_PARAMS, "error: "
776 					"maxDataSize (%zu) is smaller than global parameter "
777 					"maxMessageSize (%zu) - global parameter will be used.",
778 					inst->maxDataSize, maxMessageSize);
779 			inst->maxDataSize = maxMessageSize;
780 		}
781 	}
782 
783 finalize_it:
784 ENDcheckCnf
785 
786 
787 BEGINactivateCnfPrePrivDrop
788 	instanceConf_t *inst;
789 CODESTARTactivateCnfPrePrivDrop
790 	runModConf = pModConf;
791 	for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
792 		addListner(pModConf, inst);
793 	}
794 	if(pRelpEngine == NULL) {
795 		LogError(0, RS_RET_NO_LSTN_DEFINED, "imrelp: no RELP listener defined, module can not run.");
796 		ABORT_FINALIZE(RS_RET_NO_RUN);
797 	}
798 finalize_it:
799 ENDactivateCnfPrePrivDrop
800 
801 BEGINactivateCnf
802 CODESTARTactivateCnf
803 ENDactivateCnf
804 
805 
806 BEGINfreeCnf
807 	instanceConf_t *inst, *del;
808 	int i;
809 CODESTARTfreeCnf
810 	for(inst = pModConf->root ; inst != NULL ; ) {
811 		free(inst->pszBindPort);
812 		if (inst->pszBindAddr != NULL) {
813 			free(inst->pszBindAddr);
814 		}
815 		free(inst->pszBindRuleset);
816 		free(inst->pszInputName);
817 		free(inst->pristring);
818 		free(inst->authmode);
819 		for(i = 0 ; i <  inst->permittedPeers.nmemb ; ++i) {
820 			free(inst->permittedPeers.name[i]);
821 		}
822 		if(inst->bEnableLstn) {
823 			prop.Destruct(&inst->pInputName);
824 			statsobj.Destruct(&(inst->data.stats));
825 		}
826 		del = inst;
827 		inst = inst->next;
828 		free(del);
829 	}
830 	free(pModConf->pszBindRuleset);
831 ENDfreeCnf
832 
833 /* This is used to terminate the plugin. Note that the signal handler blocks
834  * other activity on the thread. As such, it is safe to request the stop. When
835  * we terminate, relpEngine is called, and it's select() loop interrupted. But
836  * only *after this function is done*. So we do not have a race!
837  */
838 static void
doSIGTTIN(int sig)839 doSIGTTIN(int __attribute__((unused)) sig)
840 {
841 	const int bTerminate = ATOMIC_FETCH_32BIT(&bTerminateInputs, &mutTerminateInputs);
842 	if(bTerminate) {
843 		relpEngineSetStop(pRelpEngine);
844 	}
845 }
846 
847 
848 /* This function is called to gather input.
849  */
850 BEGINrunInput
851 	sigset_t sigSet;
852 	struct sigaction sigAct;
853 CODESTARTrunInput
854 	/* we want to support non-cancel input termination. To do so, we must signal librelp
855 	 * when to stop. As we run on the same thread, we need to register as SIGTTIN handler,
856 	 * which will be used to put the terminating condition into librelp.
857 	 */
858 	sigfillset(&sigSet);
859 	pthread_sigmask(SIG_BLOCK, &sigSet, NULL);
860 	sigemptyset(&sigSet);
861 	sigaddset(&sigSet, SIGTTIN);
862 	pthread_sigmask(SIG_UNBLOCK, &sigSet, NULL);
863 	memset(&sigAct, 0, sizeof (sigAct));
864 	sigemptyset(&sigAct.sa_mask);
865 	sigAct.sa_handler = doSIGTTIN;
866 	sigaction(SIGTTIN, &sigAct, NULL);
867 
868 	iRet = relpEngineRun(pRelpEngine);
869 ENDrunInput
870 
871 
872 BEGINwillRun
873 CODESTARTwillRun
874 ENDwillRun
875 
876 
877 BEGINafterRun
878 CODESTARTafterRun
879 	/* do cleanup here */
880 ENDafterRun
881 
882 
883 BEGINmodExit
884 CODESTARTmodExit
885 	if(pRelpEngine != NULL)
886 		iRet = relpEngineDestruct(&pRelpEngine);
887 
888 	/* release objects we used */
889 	objRelease(statsobj, CORE_COMPONENT);
890 	objRelease(ruleset, CORE_COMPONENT);
891 	objRelease(glbl, CORE_COMPONENT);
892 	objRelease(prop, CORE_COMPONENT);
893 	objRelease(net, LM_NET_FILENAME);
894 ENDmodExit
895 
896 
897 static rsRetVal
resetConfigVariables(uchar * pp,void * pVal)898 resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
899 {
900 	free(cs.pszBindRuleset);
901 	cs.pszBindRuleset = NULL;
902 	return RS_RET_OK;
903 }
904 
905 
906 BEGINisCompatibleWithFeature
907 CODESTARTisCompatibleWithFeature
908 	if(eFeat == sFEATURENonCancelInputTermination)
909 		iRet = RS_RET_OK;
910 ENDisCompatibleWithFeature
911 
912 
913 BEGINqueryEtryPt
914 CODESTARTqueryEtryPt
915 CODEqueryEtryPt_STD_IMOD_QUERIES
916 CODEqueryEtryPt_STD_CONF2_QUERIES
917 CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES
918 CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES
919 CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES
920 CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
921 ENDqueryEtryPt
922 
923 
924 BEGINmodInit()
925 CODESTARTmodInit
926 	*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
927 CODEmodInit_QueryRegCFSLineHdlr
928 	pRelpEngine = NULL;
929 	/* request objects we use */
930 	CHKiRet(objUse(glbl, CORE_COMPONENT));
931 	CHKiRet(objUse(prop, CORE_COMPONENT));
932 	CHKiRet(objUse(net, LM_NET_FILENAME));
933 	CHKiRet(objUse(ruleset, CORE_COMPONENT));
934 	CHKiRet(objUse(statsobj, CORE_COMPONENT));
935 
936 	#ifndef HAVE_RELPSRVSETOVERSIZEMODE
937 		LogMsg(0, RS_RET_OK_WARN, LOG_WARNING, "imrelp: librelp too old, oversizemode "
938 			"defaults to \"abort\"");
939 	#endif
940 
941 	/* register config file handlers */
942 	CHKiRet(regCfSysLineHdlr2((uchar*)"inputrelpserverbindruleset", 0, eCmdHdlrGetWord,
943 				   NULL, &cs.pszBindRuleset, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
944 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrelpserverrun", 0, eCmdHdlrGetWord,
945 				   addInstance, NULL, STD_LOADABLE_MODULE_ID));
946 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
947 		resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
948 ENDmodInit
949