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