1 /* omruleset.c
2  * This is a very special output module. It permits to pass a message object
3  * to another rule set. While this is a very simple action, it enables very
4  * complex configurations, e.g. it supports high-speed "and" conditions, sending
5  * data to the same file in a non-racy way, include functionality as well as
6  * some high-performance optimizations (in case the rule sets have the necessary
7  * queue definitions). So while this code is small, it is pretty important.
8  *
9  * NOTE: read comments in module-template.h for details on the calling interface!
10  *
11  * File begun on 2009-11-02 by RGerhards
12  *
13  * Copyright 2009-2016 Rainer Gerhards and Adiscon GmbH.
14  *
15  * This file is part of rsyslog.
16  *
17  * Licensed under the Apache License, Version 2.0 (the "License");
18  * you may not use this file except in compliance with the License.
19  * You may obtain a copy of the License at
20  *
21  *       http://www.apache.org/licenses/LICENSE-2.0
22  *       -or-
23  *       see COPYING.ASL20 in the source distribution
24  *
25  * Unless required by applicable law or agreed to in writing, software
26  * distributed under the License is distributed on an "AS IS" BASIS,
27  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28  * See the License for the specific language governing permissions and
29  * limitations under the License.
30  */
31 #include "config.h"
32 #include "rsyslog.h"
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <signal.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include "conf.h"
42 #include "syslogd-types.h"
43 #include "template.h"
44 #include "module-template.h"
45 #include "errmsg.h"
46 #include "ruleset.h"
47 #include "cfsysline.h"
48 #include "dirty.h"
49 
50 MODULE_TYPE_OUTPUT
51 MODULE_TYPE_NOKEEP
52 MODULE_CNFNAME("omruleset")
53 
54 static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
55 
56 /* static data */
57 DEFobjCurrIf(ruleset);
58 
59 /* internal structures
60  */
61 DEF_OMOD_STATIC_DATA
62 
63 /* config variables */
64 
65 
66 typedef struct _instanceData {
67 	ruleset_t *pRuleset;	/* ruleset to enqueue to */
68 	uchar *pszRulesetName;	/* primarily for debugging/display purposes */
69 } instanceData;
70 
71 typedef struct wrkrInstanceData {
72 	instanceData *pData;
73 } wrkrInstanceData_t;
74 
75 typedef struct configSettings_s {
76 	ruleset_t *pRuleset;	/* ruleset to enqueue message to (NULL = Default, not recommended) */
77 	uchar *pszRulesetName;
78 } configSettings_t;
79 static configSettings_t cs;
80 
81 BEGINinitConfVars		/* (re)set config variables to default values */
82 CODESTARTinitConfVars
83 	resetConfigVariables(NULL, NULL);
84 ENDinitConfVars
85 
86 
87 BEGINcreateInstance
88 CODESTARTcreateInstance
89 ENDcreateInstance
90 
91 
92 BEGINcreateWrkrInstance
93 CODESTARTcreateWrkrInstance
94 ENDcreateWrkrInstance
95 
96 
97 BEGINisCompatibleWithFeature
98 CODESTARTisCompatibleWithFeature
99 ENDisCompatibleWithFeature
100 
101 
102 BEGINfreeWrkrInstance
103 CODESTARTfreeWrkrInstance
104 ENDfreeWrkrInstance
105 
106 
107 BEGINfreeInstance
108 CODESTARTfreeInstance
109 	free(pData->pszRulesetName);
110 ENDfreeInstance
111 
112 
113 BEGINdbgPrintInstInfo
114 CODESTARTdbgPrintInstInfo
115 	dbgprintf("omruleset target %s[%p]\n", (char*) pData->pszRulesetName, pData->pRuleset);
116 ENDdbgPrintInstInfo
117 
118 
119 BEGINtryResume
120 CODESTARTtryResume
121 ENDtryResume
122 
123 /* Note that we change the flow control type to "no delay", because at this point in
124  * rsyslog procesing we can not really slow down the producer any longer, as we already
125  * work off a queue. So a delay would just block out execution for longer than needed.
126  */
127 BEGINdoAction_NoStrings
128 	smsg_t **ppMsg = (smsg_t **) pMsgData;
129 	smsg_t *pMsg;
130 CODESTARTdoAction
131 	CHKmalloc(pMsg = MsgDup(ppMsg[0]));
132 	DBGPRINTF(":omruleset: forwarding message %p to ruleset %s[%p]\n", pMsg,
133 		  (char*) pWrkrData->pData->pszRulesetName, pWrkrData->pData->pRuleset);
134 	MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY);
135 	MsgSetRuleset(pMsg, pWrkrData->pData->pRuleset);
136 	/* Note: we intentionally use submitMsg2() here, as we process messages
137 	 * that were already run through the rate-limiter. So it is (at least)
138 	 * questionable if they were rate-limited again.
139 	 */
140 	submitMsg2(pMsg);
141 finalize_it:
142 ENDdoAction
143 
144 /* set the ruleset name */
145 static rsRetVal
setRuleset(void * pVal,uchar * pszName)146 setRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
147 {
148 	rsRetVal localRet;
149 	DEFiRet;
150 
151 	localRet = ruleset.GetRuleset(ourConf, &cs.pRuleset, pszName);
152 	if(localRet == RS_RET_NOT_FOUND) {
153 		LogError(0, RS_RET_RULESET_NOT_FOUND, "error: ruleset '%s' not found - ignored", pszName);
154 	}
155 	CHKiRet(localRet);
156 	cs.pszRulesetName = pszName; /* save for later display purposes */
157 
158 finalize_it:
159 	if(iRet != RS_RET_OK) { /* cleanup needed? */
160 		free(pszName);
161 	}
162 	RETiRet;
163 }
164 
165 
166 BEGINparseSelectorAct
167 	int iTplOpts;
168 CODESTARTparseSelectorAct
169 CODE_STD_STRING_REQUESTparseSelectorAct(1)
170 	/* first check if this config line is actually for us */
171 	if(strncmp((char*) p, ":omruleset:", sizeof(":omruleset:") - 1)) {
172 		ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
173 	}
174 
175 	if(cs.pRuleset == NULL) {
176 		LogError(0, RS_RET_NO_RULESET, "error: no ruleset was specified, use "
177 				"$ActionOmrulesetRulesetName directive first!");
178 		ABORT_FINALIZE(RS_RET_NO_RULESET);
179 	}
180 
181 	/* ok, if we reach this point, we have something for us */
182 	p += sizeof(":omruleset:") - 1; /* eat indicator sequence  (-1 because of '\0'!) */
183 	CHKiRet(createInstance(&pData));
184 
185 	LogMsg(0, RS_RET_DEPRECATED, LOG_WARNING,
186 			"warning: omruleset is deprecated, consider "
187 			"using the 'call' statement instead");
188 
189 	/* check if a non-standard template is to be applied */
190 	if(*(p-1) == ';')
191 		--p;
192 	iTplOpts = OMSR_TPL_AS_MSG;
193 	/* we call the message below because we need to call it via our interface definition. However,
194 	 * the format specified (if any) is always ignored.
195 	 */
196 	CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, iTplOpts, (uchar*) "RSYSLOG_FileFormat"));
197 	pData->pRuleset = cs.pRuleset;
198 	pData->pszRulesetName = cs.pszRulesetName;
199 	cs.pRuleset = NULL;
200 /* re-set, because there is a high risk of unwanted behavior if we leave it in! */
201 	cs.pszRulesetName = NULL;
202 /* note: we must not free, as we handed over this pointer to the instanceDat to the instanceDataa! */
203 CODE_STD_FINALIZERparseSelectorAct
204 ENDparseSelectorAct
205 
206 
207 BEGINmodExit
208 CODESTARTmodExit
209 	free(cs.pszRulesetName);
210 	objRelease(ruleset, CORE_COMPONENT);
211 ENDmodExit
212 
213 
214 BEGINqueryEtryPt
215 CODESTARTqueryEtryPt
216 CODEqueryEtryPt_STD_OMOD_QUERIES
217 CODEqueryEtryPt_STD_OMOD8_QUERIES
218 CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES
219 ENDqueryEtryPt
220 
221 
222 
223 /* Reset config variables for this module to default values.
224  */
resetConfigVariables(uchar * pp,void * pVal)225 static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
226 {
227 	DEFiRet;
228 	cs.pRuleset = NULL;
229 	free(cs.pszRulesetName);
230 	cs.pszRulesetName = NULL;
231 	RETiRet;
232 }
233 
234 
235 BEGINmodInit()
236 	rsRetVal localRet;
237 	rsRetVal (*pomsrGetSupportedTplOpts)(unsigned long *pOpts);
238 	unsigned long opts;
239 	int bMsgPassingSupported;		/* does core support template passing as an array? */
240 CODESTARTmodInit
241 INITLegCnfVars
242 	*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
243 CODEmodInit_QueryRegCFSLineHdlr
244 	/* check if the rsyslog core supports parameter passing code */
245 	bMsgPassingSupported = 0;
246 	localRet = pHostQueryEtryPt((uchar*)"OMSRgetSupportedTplOpts", &pomsrGetSupportedTplOpts);
247 	if(localRet == RS_RET_OK) {
248 		/* found entry point, so let's see if core supports msg passing */
249 		CHKiRet((*pomsrGetSupportedTplOpts)(&opts));
250 		if(opts & OMSR_TPL_AS_MSG)
251 			bMsgPassingSupported = 1;
252 	} else if(localRet != RS_RET_ENTRY_POINT_NOT_FOUND) {
253 		ABORT_FINALIZE(localRet); /* Something else went wrong, what is not acceptable */
254 	}
255 
256 	if(!bMsgPassingSupported) {
257 		DBGPRINTF("omruleset: msg-passing is not supported by rsyslog core, can not continue.\n");
258 		ABORT_FINALIZE(RS_RET_NO_MSG_PASSING);
259 	}
260 
261 	CHKiRet(objUse(ruleset, CORE_COMPONENT));
262 
263 	LogMsg(0, RS_RET_DEPRECATED, LOG_WARNING,
264 			"warning: omruleset is deprecated, consider "
265 			"using the 'call' statement instead");
266 
267 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomrulesetrulesetname", 0, eCmdHdlrGetWord,
268 				    setRuleset, NULL, STD_LOADABLE_MODULE_ID));
269 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
270 				    resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
271 ENDmodInit
272 
273 /* vi:set ai:
274  */
275