1 /* rainerscript.c - routines to support RainerScript config language
2 *
3 * Module begun 2011-07-01 by Rainer Gerhards
4 *
5 * Copyright 2011-2019 Rainer Gerhards and Others.
6 *
7 * This file is part of the rsyslog runtime library.
8 *
9 * The rsyslog runtime library is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * The rsyslog runtime library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
21 *
22 * A copy of the GPL can be found in the file "COPYING" in this distribution.
23 * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
24 */
25 #include "config.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <glob.h>
31 #include <errno.h>
32 #include <pwd.h>
33 #include <grp.h>
34 #include <unistd.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <libestr.h>
38 #include <time.h>
39
40 #include "rsyslog.h"
41 #include "rainerscript.h"
42 #include "conf.h"
43 #include "parserif.h"
44 #include "parse.h"
45 #include "rsconf.h"
46 #include "grammar.h"
47 #include "queue.h"
48 #include "srUtils.h"
49 #include "regexp.h"
50 #include "datetime.h"
51 #include "obj.h"
52 #include "modules.h"
53 #include "ruleset.h"
54 #include "msg.h"
55 #include "wti.h"
56 #include "unicode-helper.h"
57 #include "errmsg.h"
58
59 PRAGMA_INGORE_Wswitch_enum
60
61 DEFobjCurrIf(obj)
62 DEFobjCurrIf(regexp)
63 DEFobjCurrIf(datetime)
64
65 struct cnfexpr* cnfexprOptimize(struct cnfexpr *expr);
66 static void cnfstmtOptimizePRIFilt(struct cnfstmt *stmt);
67 static void cnfarrayPrint(struct cnfarray *ar, int indent);
68 struct cnffunc * cnffuncNew_prifilt(int fac);
69
70 static struct cnfparamdescr incpdescr[] = {
71 { "file", eCmdHdlrString, 0 },
72 { "text", eCmdHdlrString, 0 },
73 { "mode", eCmdHdlrGetWord, 0 }
74 };
75 static struct cnfparamblk incpblk =
76 { CNFPARAMBLK_VERSION,
77 sizeof(incpdescr)/sizeof(struct cnfparamdescr),
78 incpdescr
79 };
80
81 /* debug support: convert token to a human-readable string. Note that
82 * this function only supports a single thread due to a static buffer.
83 * This is deemed a solid solution, as it is intended to be used during
84 * startup, only.
85 * NOTE: This function MUST be updated if new tokens are defined in the
86 * grammar.
87 */
88 static const char *
tokenToString(const int token)89 tokenToString(const int token)
90 {
91 const char *tokstr;
92 static char tokbuf[512];
93
94 switch(token) {
95 case NAME: tokstr = "NAME"; break;
96 case FUNC: tokstr = "FUNC"; break;
97 case BEGINOBJ: tokstr ="BEGINOBJ"; break;
98 case ENDOBJ: tokstr ="ENDOBJ"; break;
99 case BEGIN_ACTION: tokstr ="BEGIN_ACTION"; break;
100 case BEGIN_PROPERTY: tokstr ="BEGIN_PROPERTY"; break;
101 case BEGIN_CONSTANT: tokstr ="BEGIN_CONSTANT"; break;
102 case BEGIN_TPL: tokstr ="BEGIN_TPL"; break;
103 case BEGIN_RULESET: tokstr ="BEGIN_RULESET"; break;
104 case STOP: tokstr ="STOP"; break;
105 case SET: tokstr ="SET"; break;
106 case UNSET: tokstr ="UNSET"; break;
107 case CONTINUE: tokstr ="CONTINUE"; break;
108 case CALL: tokstr ="CALL"; break;
109 case LEGACY_ACTION: tokstr ="LEGACY_ACTION"; break;
110 case LEGACY_RULESET: tokstr ="LEGACY_RULESET"; break;
111 case PRIFILT: tokstr ="PRIFILT"; break;
112 case PROPFILT: tokstr ="PROPFILT"; break;
113 case IF: tokstr ="IF"; break;
114 case THEN: tokstr ="THEN"; break;
115 case ELSE: tokstr ="ELSE"; break;
116 case OR: tokstr ="OR"; break;
117 case AND: tokstr ="AND"; break;
118 case NOT: tokstr ="NOT"; break;
119 case VAR: tokstr ="VAR"; break;
120 case STRING: tokstr ="STRING"; break;
121 case NUMBER: tokstr ="NUMBER"; break;
122 case CMP_EQ: tokstr ="CMP_EQ"; break;
123 case CMP_NE: tokstr ="CMP_NE"; break;
124 case CMP_LE: tokstr ="CMP_LE"; break;
125 case CMP_GE: tokstr ="CMP_GE"; break;
126 case CMP_LT: tokstr ="CMP_LT"; break;
127 case CMP_GT: tokstr ="CMP_GT"; break;
128 case CMP_CONTAINS: tokstr ="CMP_CONTAINS"; break;
129 case CMP_CONTAINSI: tokstr ="CMP_CONTAINSI"; break;
130 case CMP_STARTSWITH: tokstr ="CMP_STARTSWITH"; break;
131 case CMP_STARTSWITHI: tokstr ="CMP_STARTSWITHI"; break;
132 case UMINUS: tokstr ="UMINUS"; break;
133 case '&': tokstr ="&"; break;
134 case '+': tokstr ="+"; break;
135 case '-': tokstr ="-"; break;
136 case '*': tokstr ="*"; break;
137 case '/': tokstr ="/"; break;
138 case '%': tokstr ="%"; break;
139 case 'M': tokstr ="M"; break;
140 case 'N': tokstr ="N"; break;
141 case 'S': tokstr ="S"; break;
142 case 'V': tokstr ="V"; break;
143 case 'F': tokstr ="F"; break;
144 case 'A': tokstr ="A"; break;
145 case S_FUNC_EXISTS: tokstr ="exists()"; break;
146 default: snprintf(tokbuf, sizeof(tokbuf), "%c[%d]", token, token);
147 tokstr = tokbuf; break;
148 }
149 return tokstr;
150 }
151
152
153 const char*
getFIOPName(const unsigned iFIOP)154 getFIOPName(const unsigned iFIOP)
155 {
156 const char *pRet;
157 switch(iFIOP) {
158 case FIOP_CONTAINS:
159 pRet = "contains";
160 break;
161 case FIOP_ISEQUAL:
162 pRet = "isequal";
163 break;
164 case FIOP_STARTSWITH:
165 pRet = "startswith";
166 break;
167 case FIOP_REGEX:
168 pRet = "regex";
169 break;
170 case FIOP_EREREGEX:
171 pRet = "ereregex";
172 break;
173 case FIOP_ISEMPTY:
174 pRet = "isempty";
175 break;
176 default:
177 pRet = "NOP";
178 break;
179 }
180 return pRet;
181 }
182
183 const char*
cnfFiltType2str(const enum cnfFiltType filttype)184 cnfFiltType2str(const enum cnfFiltType filttype)
185 {
186 switch(filttype) {
187 case CNFFILT_NONE:
188 return("filter:none");
189 case CNFFILT_PRI:
190 return("filter:pri");
191 case CNFFILT_PROP:
192 return("filter:prop");
193 case CNFFILT_SCRIPT:
194 return("filter:script");
195 default:
196 return("error:invalid_filter_type"); /* should never be reached */
197 }
198 }
199
200 const char*
cnfobjType2str(const enum cnfobjType ot)201 cnfobjType2str(const enum cnfobjType ot)
202 {
203 switch(ot) {
204 case CNFOBJ_ACTION:
205 return "action";
206 break;
207 case CNFOBJ_RULESET:
208 return "ruleset";
209 break;
210 case CNFOBJ_GLOBAL:
211 return "global";
212 break;
213 case CNFOBJ_INPUT:
214 return "input";
215 break;
216 case CNFOBJ_MODULE:
217 return "module";
218 break;
219 case CNFOBJ_TPL:
220 return "template";
221 break;
222 case CNFOBJ_PROPERTY:
223 return "property";
224 break;
225 case CNFOBJ_CONSTANT:
226 return "constant";
227 break;
228 case CNFOBJ_MAINQ:
229 return "main_queue";
230 case CNFOBJ_LOOKUP_TABLE:
231 return "lookup_table";
232 case CNFOBJ_PARSER:
233 return "parser";
234 break;
235 case CNFOBJ_TIMEZONE:
236 return "timezone";
237 break;
238 case CNFOBJ_DYN_STATS:
239 return "dyn_stats";
240 break;
241 case CNFOBJ_PERCTILE_STATS:
242 return "perctile_stats";
243 break;
244 default:return "error: invalid cnfobjType";
245 }
246 }
247
248 /* This function takes the filter part of a property
249 * based filter and decodes it. It processes the line up to the beginning
250 * of the action part.
251 */
252 static rsRetVal
DecodePropFilter(uchar * pline,struct cnfstmt * stmt)253 DecodePropFilter(uchar *pline, struct cnfstmt *stmt)
254 {
255 rsParsObj *pPars = NULL;
256 cstr_t *pCSCompOp = NULL;
257 cstr_t *pCSPropName = NULL;
258 int iOffset; /* for compare operations */
259 DEFiRet;
260
261 assert(pline != NULL);
262
263 DBGPRINTF("Decoding property-based filter '%s'\n", pline);
264
265 /* create parser object starting with line string without leading colon */
266 if((iRet = rsParsConstructFromSz(&pPars, pline+1)) != RS_RET_OK) {
267 parser_errmsg("error %d constructing parser object", iRet);
268 FINALIZE;
269 }
270
271 /* read property */
272 iRet = parsDelimCStr(pPars, &pCSPropName, ',', 1, 1, 1);
273 if(iRet != RS_RET_OK) {
274 parser_errmsg("error %d parsing filter property", iRet);
275 FINALIZE;
276 }
277 CHKiRet(msgPropDescrFill(&stmt->d.s_propfilt.prop, cstrGetSzStrNoNULL(pCSPropName),
278 cstrLen(pCSPropName)));
279
280 /* read operation */
281 iRet = parsDelimCStr(pPars, &pCSCompOp, ',', 1, 1, 1);
282 if(iRet != RS_RET_OK) {
283 parser_errmsg("error %d compare operation property - ignoring selector", iRet);
284 FINALIZE;
285 }
286
287 /* we now first check if the condition is to be negated. To do so, we first
288 * must make sure we have at least one char in the param and then check the
289 * first one.
290 * rgerhards, 2005-09-26
291 */
292 if(rsCStrLen(pCSCompOp) > 0) {
293 if(*rsCStrGetBufBeg(pCSCompOp) == '!') {
294 stmt->d.s_propfilt.isNegated = 1;
295 iOffset = 1; /* ignore '!' */
296 } else {
297 stmt->d.s_propfilt.isNegated = 0;
298 iOffset = 0;
299 }
300 } else {
301 stmt->d.s_propfilt.isNegated = 0;
302 iOffset = 0;
303 }
304
305 if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) {
306 stmt->d.s_propfilt.operation = FIOP_CONTAINS;
307 } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) {
308 stmt->d.s_propfilt.operation = FIOP_ISEQUAL;
309 } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) {
310 stmt->d.s_propfilt.operation = FIOP_ISEMPTY;
311 } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) {
312 stmt->d.s_propfilt.operation = FIOP_STARTSWITH;
313 } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) {
314 stmt->d.s_propfilt.operation = FIOP_REGEX;
315 } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "ereregex", 8)) {
316 stmt->d.s_propfilt.operation = FIOP_EREREGEX;
317 } else {
318 parser_errmsg("error: invalid compare operation '%s'",
319 (char*) rsCStrGetSzStrNoNULL(pCSCompOp));
320 ABORT_FINALIZE(RS_RET_ERR);
321 }
322
323 if(stmt->d.s_propfilt.operation != FIOP_ISEMPTY) {
324 /* read compare value */
325 iRet = parsQuotedCStr(pPars, &stmt->d.s_propfilt.pCSCompValue);
326 if(iRet != RS_RET_OK) {
327 parser_errmsg("error %d compare value property", iRet);
328 FINALIZE;
329 }
330 }
331
332 finalize_it:
333 if(pPars != NULL)
334 rsParsDestruct(pPars);
335 if(pCSCompOp != NULL)
336 rsCStrDestruct(&pCSCompOp);
337 if(pCSPropName != NULL)
338 cstrDestruct(&pCSPropName);
339 RETiRet;
340 }
341
342 static void
prifiltInvert(struct funcData_prifilt * __restrict__ const prifilt)343 prifiltInvert(struct funcData_prifilt *__restrict__ const prifilt)
344 {
345 int i;
346 for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) {
347 prifilt->pmask[i] = ~prifilt->pmask[i];
348 }
349 }
350
351 /* set prifilt so that it matches for some severities, sev is its numerical
352 * value. Mode is one of the compop tokens CMP_EQ, CMP_LT, CMP_LE, CMP_GT,
353 * CMP_GE, CMP_NE.
354 */
355 static void
prifiltSetSeverity(struct funcData_prifilt * prifilt,int sev,int mode)356 prifiltSetSeverity(struct funcData_prifilt *prifilt, int sev, int mode)
357 {
358 static int lessthanmasks[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
359 int i;
360 for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) {
361 if(mode == CMP_EQ || mode == CMP_NE)
362 prifilt->pmask[i] = 1 << sev;
363 else if(mode == CMP_LT)
364 prifilt->pmask[i] = lessthanmasks[sev];
365 else if(mode == CMP_LE)
366 prifilt->pmask[i] = lessthanmasks[sev+1];
367 else if(mode == CMP_GT)
368 prifilt->pmask[i] = ~lessthanmasks[sev+1];
369 else if(mode == CMP_GE)
370 prifilt->pmask[i] = ~lessthanmasks[sev];
371 else
372 DBGPRINTF("prifiltSetSeverity: program error, invalid mode %s\n",
373 tokenToString(mode));
374 }
375 if(mode == CMP_NE)
376 prifiltInvert(prifilt);
377 }
378
379 /* set prifilt so that it matches for some facilities, fac is its numerical
380 * value. Mode is one of the compop tokens CMP_EQ, CMP_LT, CMP_LE, CMP_GT,
381 * CMP_GE, CMP_NE. For the given facilities, all severities are enabled.
382 * NOTE: fac MUST be in the range 0..24 (not multiplied by 8)!
383 */
384 static void
prifiltSetFacility(struct funcData_prifilt * __restrict__ const prifilt,const int fac,const int mode)385 prifiltSetFacility(struct funcData_prifilt *__restrict__ const prifilt, const int fac, const int mode)
386 {
387 int i;
388
389 memset(prifilt->pmask, 0, sizeof(prifilt->pmask));
390 switch(mode) {
391 case CMP_EQ:
392 prifilt->pmask[fac] = TABLE_ALLPRI;
393 break;
394 case CMP_NE:
395 prifilt->pmask[fac] = TABLE_ALLPRI;
396 prifiltInvert(prifilt);
397 break;
398 case CMP_LT:
399 for(i = 0 ; i < fac ; ++i)
400 prifilt->pmask[i] = TABLE_ALLPRI;
401 break;
402 case CMP_LE:
403 for(i = 0 ; i < fac+1 ; ++i)
404 prifilt->pmask[i] = TABLE_ALLPRI;
405 break;
406 case CMP_GE:
407 for(i = fac ; i < LOG_NFACILITIES+1 ; ++i)
408 prifilt->pmask[i] = TABLE_ALLPRI;
409 break;
410 case CMP_GT:
411 for(i = fac+1 ; i < LOG_NFACILITIES+1 ; ++i)
412 prifilt->pmask[i] = TABLE_ALLPRI;
413 break;
414 default:break;
415 }
416 }
417
418 /* combine a prifilt with AND/OR (the respective token values are
419 * used to keep things simple).
420 */
421 static void
prifiltCombine(struct funcData_prifilt * __restrict__ const prifilt,struct funcData_prifilt * __restrict__ const prifilt2,const int mode)422 prifiltCombine(struct funcData_prifilt *__restrict__ const prifilt,
423 struct funcData_prifilt *__restrict__ const prifilt2,
424 const int mode)
425 {
426 int i;
427 for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) {
428 if(mode == AND)
429 prifilt->pmask[i] = prifilt->pmask[i] & prifilt2->pmask[i];
430 else
431 prifilt->pmask[i] = prifilt->pmask[i] | prifilt2->pmask[i];
432 }
433 }
434
435
436 void
readConfFile(FILE * const fp,es_str_t ** str)437 readConfFile(FILE * const fp, es_str_t **str)
438 {
439 char ln[10240];
440 char buf[512];
441 int lenBuf;
442 int bWriteLineno = 0;
443 int len, i;
444 int start; /* start index of to be submitted text */
445 int bContLine = 0;
446 int lineno = 0;
447
448 *str = es_newStr(4096);
449
450 while(fgets(ln, sizeof(ln), fp) != NULL) {
451 ++lineno;
452 if(bWriteLineno) {
453 bWriteLineno = 0;
454 lenBuf = sprintf(buf, "PreprocFileLineNumber(%d)\n", lineno);
455 es_addBuf(str, buf, lenBuf);
456 }
457 len = strlen(ln);
458 /* if we are continuation line, we need to drop leading WS */
459 if(bContLine) {
460 for(start = 0 ; start < len && isspace(ln[start]) ; ++start)
461 /* JUST SCAN */;
462 } else {
463 start = 0;
464 }
465 for(i = len - 1 ; i >= start && isspace(ln[i]) ; --i)
466 /* JUST SCAN */;
467 if(i >= 0) {
468 if(ln[i] == '\\') {
469 --i;
470 bContLine = 1;
471 } else {
472 if(bContLine) /* write line number if we had cont line */
473 bWriteLineno = 1;
474 bContLine = 0;
475 }
476 /* add relevant data to buffer */
477 es_addBuf(str, ln+start, i+1 - start);
478 }
479 if(!bContLine)
480 es_addChar(str, '\n');
481 }
482 /* indicate end of buffer to flex */
483 es_addChar(str, '\0');
484 es_addChar(str, '\0');
485 }
486
487 /* comparison function for qsort() and bsearch() string array compare */
488 static int
qs_arrcmp(const void * s1,const void * s2)489 qs_arrcmp(const void *s1, const void *s2)
490 {
491 return es_strcmp(*((es_str_t**)s1), *((es_str_t**)s2));
492 }
493
494
495 struct objlst*
objlstNew(struct cnfobj * o)496 objlstNew(struct cnfobj *o)
497 {
498 struct objlst *lst;
499
500 if((lst = malloc(sizeof(struct objlst))) != NULL) {
501 lst->next = NULL;
502 lst->obj = o;
503 }
504 cnfobjPrint(o);
505
506 return lst;
507 }
508
509 /* add object to end of object list, always returns pointer to root object */
510 struct objlst*
objlstAdd(struct objlst * root,struct cnfobj * o)511 objlstAdd(struct objlst *root, struct cnfobj *o)
512 {
513 struct objlst *l;
514 struct objlst *newl;
515
516 newl = objlstNew(o);
517 if(root == 0) {
518 root = newl;
519 } else { /* find last, linear search ok, as only during config phase */
520 for(l = root ; l->next != NULL ; l = l->next)
521 ;
522 l->next = newl;
523 }
524 return root;
525 }
526
527 /* add stmt to current script, always return root stmt pointer */
528 struct cnfstmt*
scriptAddStmt(struct cnfstmt * root,struct cnfstmt * s)529 scriptAddStmt(struct cnfstmt *root, struct cnfstmt *s)
530 {
531 struct cnfstmt *l;
532
533 if(root == NULL) {
534 root = s;
535 } else { /* find last, linear search ok, as only during config phase */
536 for(l = root ; l->next != NULL ; l = l->next)
537 ;
538 l->next = s;
539 }
540 return root;
541 }
542
543 void
objlstDestruct(struct objlst * lst)544 objlstDestruct(struct objlst *lst)
545 {
546 struct objlst *toDel;
547
548 while(lst != NULL) {
549 toDel = lst;
550 lst = lst->next;
551 cnfobjDestruct(toDel->obj);
552 free(toDel);
553 }
554 }
555
556 void
objlstPrint(struct objlst * lst)557 objlstPrint(struct objlst *lst)
558 {
559 dbgprintf("objlst %p:\n", lst);
560 while(lst != NULL) {
561 cnfobjPrint(lst->obj);
562 lst = lst->next;
563 }
564 }
565
566 struct nvlst* ATTR_NONNULL(1)
nvlstNewStr(es_str_t * const value)567 nvlstNewStr(es_str_t *const value)
568 {
569 struct nvlst *lst;
570
571 if((lst = malloc(sizeof(struct nvlst))) != NULL) {
572 lst->next = NULL;
573 lst->val.datatype = 'S';
574 lst->val.d.estr = value;
575 lst->bUsed = 0;
576 }
577
578 return lst;
579 }
580
581 struct nvlst* ATTR_NONNULL(1)
nvlstNewStrBackticks(es_str_t * const value)582 nvlstNewStrBackticks(es_str_t *const value)
583 {
584 es_str_t *val = NULL;
585 const char *realval;
586
587 char *const param = es_str2cstr(value, NULL);
588 if(param == NULL)
589 goto done;
590
591 if(strncmp(param, "echo $", sizeof("echo $")-1) != 0) {
592 parser_errmsg("invalid backtick parameter `%s` currently "
593 "only `echo $<var>` is supported - replaced by "
594 "empty strong (\"\")", param);
595 realval = NULL;
596 } else {
597 size_t i;
598 const size_t len = strlen(param);
599 for(i = len - 1 ; isspace(param[i]) ; --i) {
600 ; /* just go down */
601 }
602 if(i > 6 && i < len - 1) {
603 param[i+1] = '\0';
604 }
605 realval = getenv(param+6);
606 }
607
608 free((void*)param);
609 if(realval == NULL) {
610 realval = "";
611 }
612 val = es_newStrFromCStr(realval, strlen(realval));
613 es_deleteStr(value);
614
615 done:
616 return (val == NULL) ? NULL : nvlstNewStr(val);
617 }
618
619 struct nvlst*
nvlstNewArray(struct cnfarray * ar)620 nvlstNewArray(struct cnfarray *ar)
621 {
622 struct nvlst *lst;
623
624 if((lst = malloc(sizeof(struct nvlst))) != NULL) {
625 lst->next = NULL;
626 lst->val.datatype = 'A';
627 lst->val.d.ar = ar;
628 lst->bUsed = 0;
629 }
630
631 return lst;
632 }
633
634 struct nvlst*
nvlstSetName(struct nvlst * lst,es_str_t * name)635 nvlstSetName(struct nvlst *lst, es_str_t *name)
636 {
637 lst->name = name;
638 return lst;
639 }
640
641 void
nvlstDestruct(struct nvlst * lst)642 nvlstDestruct(struct nvlst *lst)
643 {
644 struct nvlst *toDel;
645
646 while(lst != NULL) {
647 toDel = lst;
648 lst = lst->next;
649 es_deleteStr(toDel->name);
650 varDelete(&toDel->val);
651 free(toDel);
652 }
653 }
654
655 void
nvlstPrint(struct nvlst * lst)656 nvlstPrint(struct nvlst *lst)
657 {
658 char *name, *value;
659 dbgprintf("nvlst %p:\n", lst);
660 while(lst != NULL) {
661 name = es_str2cstr(lst->name, NULL);
662 switch(lst->val.datatype) {
663 case 'A':
664 dbgprintf("\tname: '%s':\n", name);
665 cnfarrayPrint(lst->val.d.ar, 5);
666 break;
667 case 'S':
668 value = es_str2cstr(lst->val.d.estr, NULL);
669 dbgprintf("\tname: '%s', value '%s'\n", name, value);
670 free(value);
671 break;
672 default:dbgprintf("nvlstPrint: unknown type '%s'\n",
673 tokenToString(lst->val.datatype));
674 break;
675 }
676 free(name);
677 lst = lst->next;
678 }
679 }
680
681 /* find a name starting at node lst. Returns node with this
682 * name or NULL, if none found.
683 */
684 struct nvlst*
nvlstFindName(struct nvlst * lst,es_str_t * name)685 nvlstFindName(struct nvlst *lst, es_str_t *name)
686 {
687 while(lst != NULL && es_strcmp(lst->name, name))
688 lst = lst->next;
689 return lst;
690 }
691
692
693 /* find a name starting at node lst. Same as nvlstFindName, but
694 * for classical C strings. This is useful because the config system
695 * uses C string constants.
696 */
697 static struct nvlst*
nvlstFindNameCStr(struct nvlst * lst,const char * const __restrict__ name)698 nvlstFindNameCStr(struct nvlst *lst, const char *const __restrict__ name)
699 {
700 es_size_t lenName = strlen(name);
701 while(lst != NULL && es_strcasebufcmp(lst->name, (uchar*)name, lenName))
702 lst = lst->next;
703 return lst;
704 }
705
706 /* check if the nvlst is disabled, and mark config.enabled directive
707 * as used if it is not. Returns 1 if block is disabled, 0 otherwise.
708 */
nvlstChkDisabled(struct nvlst * lst)709 int nvlstChkDisabled(struct nvlst *lst)
710 {
711 struct nvlst *valnode;
712
713 if((valnode = nvlstFindNameCStr(lst, "config.enabled")) != NULL) {
714 valnode->bUsed = 1;
715 if(es_strbufcmp(valnode->val.d.estr, (unsigned char*) "on", 2)) {
716 return 1;
717 }
718 }
719 return 0;
720 }
721
722
723 /* check if there are duplicate names inside a nvlst and emit
724 * an error message, if so.
725 */
726 static void
nvlstChkDupes(struct nvlst * lst)727 nvlstChkDupes(struct nvlst *lst)
728 {
729 char *cstr;
730
731 while(lst != NULL) {
732 if(nvlstFindName(lst->next, lst->name) != NULL) {
733 cstr = es_str2cstr(lst->name, NULL);
734 parser_errmsg("duplicate parameter '%s' -- "
735 "interpretation is ambigious, one value "
736 "will be randomly selected. Fix this problem.",
737 cstr);
738 free(cstr);
739 }
740 lst = lst->next;
741 }
742 }
743
744
745 /* check for unused params and emit error message is found. This must
746 * be called after all config params have been pulled from the object
747 * (otherwise the flags are not correctly set).
748 */
749 void
nvlstChkUnused(struct nvlst * lst)750 nvlstChkUnused(struct nvlst *lst)
751 {
752 char *cstr;
753
754 while(lst != NULL) {
755 if(!lst->bUsed) {
756 cstr = es_str2cstr(lst->name, NULL);
757 parser_errmsg("parameter '%s' not known -- "
758 "typo in config file?",
759 cstr);
760 free(cstr);
761 }
762 lst = lst->next;
763 }
764 }
765
766
767 static int
doGetSize(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)768 doGetSize(struct nvlst *valnode, struct cnfparamdescr *param,
769 struct cnfparamvals *val)
770 {
771 unsigned char *c;
772 es_size_t i;
773 long long n;
774 int r;
775 c = es_getBufAddr(valnode->val.d.estr);
776 n = 0;
777 i = 0;
778 while(i < es_strlen(valnode->val.d.estr) && isdigit(*c)) {
779 n = 10 * n + *c - '0';
780 ++i;
781 ++c;
782 }
783 if(i < es_strlen(valnode->val.d.estr)) {
784 ++i;
785 switch(*c) {
786 /* traditional binary-based definitions */
787 case 'k': n *= 1024; break;
788 case 'm': n *= 1024 * 1024; break;
789 case 'g': n *= 1024 * 1024 * 1024; break;
790 case 't': n *= (int64) 1024 * 1024 * 1024 * 1024; break; /* tera */
791 case 'p': n *= (int64) 1024 * 1024 * 1024 * 1024 * 1024; break; /* peta */
792 case 'e': n *= (int64) 1024 * 1024 * 1024 * 1024 * 1024 * 1024; break; /* exa */
793 /* and now the "new" 1000-based definitions */
794 case 'K': n *= 1000; break;
795 case 'M': n *= 1000000; break;
796 case 'G': n *= 1000000000; break;
797 /* we need to use the multiplication below because otherwise
798 * the compiler gets an error during constant parsing */
799 case 'T': n *= (int64) 1000 * 1000000000; break; /* tera */
800 case 'P': n *= (int64) 1000000 * 1000000000; break; /* peta */
801 case 'E': n *= (int64) 1000000000 * 1000000000; break; /* exa */
802 default: --i; break; /* indicates error */
803 }
804 }
805 if(i == es_strlen(valnode->val.d.estr)) {
806 val->val.datatype = 'N';
807 val->val.d.n = n;
808 r = 1;
809 } else {
810 parser_errmsg("parameter '%s' does not contain a valid size",
811 param->name);
812 r = 0;
813 }
814 return r;
815 }
816
817
818 static int
doGetBinary(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)819 doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param,
820 struct cnfparamvals *val)
821 {
822 int r = 1;
823 val->val.datatype = 'N';
824 if(!es_strbufcmp(valnode->val.d.estr, (unsigned char*) "on", 2)) {
825 val->val.d.n = 1;
826 } else if(!es_strbufcmp(valnode->val.d.estr, (unsigned char*) "off", 3)) {
827 val->val.d.n = 0;
828 } else {
829 parser_errmsg("parameter '%s' must be \"on\" or \"off\" but "
830 "is neither. Results unpredictable.", param->name);
831 val->val.d.n = 0;
832 r = 0;
833 }
834 return r;
835 }
836
837 static int
doGetQueueType(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)838 doGetQueueType(struct nvlst *valnode, struct cnfparamdescr *param,
839 struct cnfparamvals *val)
840 {
841 char *cstr;
842 int r = 1;
843 if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"fixedarray", 10)) {
844 val->val.d.n = QUEUETYPE_FIXED_ARRAY;
845 } else if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"linkedlist", 10)) {
846 val->val.d.n = QUEUETYPE_LINKEDLIST;
847 } else if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"disk", 4)) {
848 val->val.d.n = QUEUETYPE_DISK;
849 } else if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"direct", 6)) {
850 val->val.d.n = QUEUETYPE_DIRECT;
851 } else {
852 cstr = es_str2cstr(valnode->val.d.estr, NULL);
853 parser_errmsg("param '%s': unknown queue type: '%s'",
854 param->name, cstr);
855 free(cstr);
856 r = 0;
857 }
858 val->val.datatype = 'N';
859 return r;
860 }
861
862
863 /* A file create-mode must be a four-digit octal number
864 * starting with '0'.
865 */
866 static int
doGetFileCreateMode(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)867 doGetFileCreateMode(struct nvlst *valnode, struct cnfparamdescr *param,
868 struct cnfparamvals *val)
869 {
870 int fmtOK = 0;
871 char *cstr;
872 uchar *c;
873 const int len_val = es_strlen(valnode->val.d.estr);
874
875 if(len_val >= 4) {
876 c = es_getBufAddr(valnode->val.d.estr);
877 if( (c[0] == '0')
878 && (c[1] >= '0' && c[1] <= '7')
879 && (c[2] >= '0' && c[2] <= '7')
880 && (c[3] >= '0' && c[3] <= '7') ) {
881 if(len_val == 5) {
882 if(c[4] >= '0' && c[4] <= '7') {
883 fmtOK = 1;
884 }
885 } else {
886 fmtOK = 1;
887 }
888 }
889 }
890
891 if(fmtOK) {
892 val->val.datatype = 'N';
893 val->val.d.n = (c[1]-'0') * 64 + (c[2]-'0') * 8 + (c[3]-'0');
894 if(len_val == 5) {
895 val->val.d.n = val->val.d.n * 8 + (c[4]-'0');
896 }
897 } else {
898 cstr = es_str2cstr(valnode->val.d.estr, NULL);
899 parser_errmsg("file modes need to be specified as "
900 "4- or 5-digit octal numbers starting with '0' -"
901 "parameter '%s=\"%s\"' is not a file mode",
902 param->name, cstr);
903 free(cstr);
904 }
905 return fmtOK;
906 }
907
908 static int
doGetGID(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)909 doGetGID(struct nvlst *valnode, struct cnfparamdescr *param,
910 struct cnfparamvals *val)
911 {
912 char *cstr;
913 int r;
914 struct group *resultBuf = NULL;
915 struct group wrkBuf;
916 char *stringBuf = NULL;
917 size_t bufSize = 1024;
918 int e;
919
920 cstr = es_str2cstr(valnode->val.d.estr, NULL);
921 do {
922 char *p;
923
924 /* Increase bufsize and try again.*/
925 bufSize *= 2;
926 p = realloc(stringBuf, bufSize);
927 if(!p) {
928 e = ENOMEM;
929 break;
930 }
931 stringBuf = p;
932 e = getgrnam_r(cstr, &wrkBuf, stringBuf, bufSize, &resultBuf);
933 } while(!resultBuf && (e == ERANGE));
934
935 if(resultBuf == NULL) {
936 if(e != 0) {
937 if(loadConf->globals.abortOnIDResolutionFail) {
938 fprintf(stderr, "parameter '%s': error to "
939 "obtaining group id for '%s'", param->name, cstr);
940 exit(1); /* good exit */
941 } else {
942 LogError(e, RS_RET_ERR, "parameter '%s': error to "
943 "obtaining group id for '%s'", param->name, cstr);
944 }
945 }
946 parser_errmsg("parameter '%s': ID for group %s could not "
947 "be found", param->name, cstr);
948 r = 0;
949 } else {
950 val->val.datatype = 'N';
951 val->val.d.n = resultBuf->gr_gid;
952 DBGPRINTF("param '%s': uid %d obtained for group '%s'\n",
953 param->name, (int) resultBuf->gr_gid, cstr);
954 r = 1;
955 }
956 free(stringBuf);
957 free(cstr);
958 return r;
959 }
960
961 static int
doGetUID(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)962 doGetUID(struct nvlst *valnode, struct cnfparamdescr *param,
963 struct cnfparamvals *val)
964 {
965 char *cstr;
966 int r;
967 struct passwd *resultBuf;
968 struct passwd wrkBuf;
969 char stringBuf[2048]; /* 2048 has been proven to be large enough */
970 char errStr[1024];
971
972 cstr = es_str2cstr(valnode->val.d.estr, NULL);
973 const int err_no = getpwnam_r(cstr, &wrkBuf, stringBuf, sizeof(stringBuf), &resultBuf);
974 if(resultBuf == NULL) {
975 rs_strerror_r((err_no == 0) ? ENOENT : errno, errStr, sizeof(errStr));
976 if(loadConf->globals.abortOnIDResolutionFail) {
977 fprintf(stderr, "parameter '%s': ID for user '%s' could not "
978 "be found: %s", param->name, cstr, errStr);
979 exit(1); /* good exit */
980 } else {
981 LogError(err_no, RS_RET_ERR, "parameter '%s': ID for user '%s' could not "
982 "be found: %s", param->name, cstr, errStr);
983 parser_errmsg("parameter '%s': ID for user '%s' could not "
984 "be found: %s", param->name, cstr, errStr);
985 }
986
987 r = 0;
988 } else {
989 val->val.datatype = 'N';
990 val->val.d.n = resultBuf->pw_uid;
991 DBGPRINTF("param '%s': uid %d obtained for user '%s'\n",
992 param->name, (int) resultBuf->pw_uid, cstr);
993 r = 1;
994 }
995 free(cstr);
996 return r;
997 }
998
999 /* note: we support all integer formats that es_str2num support,
1000 * so hex and octal representations are also valid.
1001 */
1002 static int
doGetInt(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)1003 doGetInt(struct nvlst *valnode, struct cnfparamdescr *param,
1004 struct cnfparamvals *val)
1005 {
1006 long long n;
1007 int bSuccess;
1008
1009 n = es_str2num(valnode->val.d.estr, &bSuccess);
1010 if(!bSuccess) {
1011 parser_errmsg("parameter '%s' is not a proper number",
1012 param->name);
1013 }
1014 val->val.datatype = 'N';
1015 val->val.d.n = n;
1016 return bSuccess;
1017 }
1018
1019 static int
doGetNonNegInt(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)1020 doGetNonNegInt(struct nvlst *valnode, struct cnfparamdescr *param,
1021 struct cnfparamvals *val)
1022 {
1023 int bSuccess;
1024
1025 if((bSuccess = doGetInt(valnode, param, val))) {
1026 if(val->val.d.n < 0) {
1027 parser_errmsg("parameter '%s' cannot be less than zero (was %lld)",
1028 param->name, val->val.d.n);
1029 bSuccess = 0;
1030 }
1031 }
1032 return bSuccess;
1033 }
1034
1035 static int
doGetPositiveInt(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)1036 doGetPositiveInt(struct nvlst *valnode, struct cnfparamdescr *param,
1037 struct cnfparamvals *val)
1038 {
1039 int bSuccess;
1040
1041 if((bSuccess = doGetInt(valnode, param, val))) {
1042 if(val->val.d.n < 1) {
1043 parser_errmsg("parameter '%s' cannot be less than one (was %lld)",
1044 param->name, val->val.d.n);
1045 bSuccess = 0;
1046 }
1047 }
1048 return bSuccess;
1049 }
1050
1051 static int
doGetWord(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)1052 doGetWord(struct nvlst *valnode, struct cnfparamdescr *param,
1053 struct cnfparamvals *val)
1054 {
1055 es_size_t i;
1056 int r = 1;
1057 unsigned char *c;
1058
1059 val->val.datatype = 'S';
1060 val->val.d.estr = es_newStr(32);
1061 c = es_getBufAddr(valnode->val.d.estr);
1062 for(i = 0 ; i < es_strlen(valnode->val.d.estr) && !isspace(c[i]) ; ++i) {
1063 es_addChar(&val->val.d.estr, c[i]);
1064 }
1065 if(i != es_strlen(valnode->val.d.estr)) {
1066 parser_errmsg("parameter '%s' contains whitespace, which is not "
1067 "permitted",
1068 param->name);
1069 r = 0;
1070 }
1071 return r;
1072 }
1073
1074 static int
doGetArray(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)1075 doGetArray(struct nvlst *valnode, struct cnfparamdescr *param,
1076 struct cnfparamvals *val)
1077 {
1078 int r = 1;
1079
1080 switch(valnode->val.datatype) {
1081 case 'S':
1082 /* a constant string is assumed to be a single-element array */
1083 val->val.datatype = 'A';
1084 val->val.d.ar = cnfarrayNew(es_strdup(valnode->val.d.estr));
1085 break;
1086 case 'A':
1087 val->val.datatype = 'A';
1088 val->val.d.ar = cnfarrayDup(valnode->val.d.ar);
1089 break;
1090 default:parser_errmsg("parameter '%s' must be an array, but is a "
1091 "different datatype", param->name);
1092 r = 0;
1093 break;
1094 }
1095 return r;
1096 }
1097
1098 static int
doGetChar(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)1099 doGetChar(struct nvlst *valnode, struct cnfparamdescr *param,
1100 struct cnfparamvals *val)
1101 {
1102 int r = 1;
1103 if(es_strlen(valnode->val.d.estr) != 1) {
1104 parser_errmsg("parameter '%s' must contain exactly one character "
1105 "but contains %d - cannot be processed",
1106 param->name, es_strlen(valnode->val.d.estr));
1107 r = 0;
1108 }
1109 val->val.datatype = 'S';
1110 val->val.d.estr = es_strdup(valnode->val.d.estr);
1111 return r;
1112 }
1113
1114 /* get a single parameter according to its definition. Helper to
1115 * nvlstGetParams. returns 1 if success, 0 otherwise
1116 */
1117 static int
nvlstGetParam(struct nvlst * valnode,struct cnfparamdescr * param,struct cnfparamvals * val)1118 nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param,
1119 struct cnfparamvals *val)
1120 {
1121 uchar *cstr;
1122 int r;
1123
1124 DBGPRINTF("nvlstGetParam: name '%s', type %d, valnode->bUsed %d\n",
1125 param->name, (int) param->type, valnode->bUsed);
1126 if(valnode->val.datatype != 'S' && param->type != eCmdHdlrArray) {
1127 parser_errmsg("parameter '%s' is not a string, which is not "
1128 "permitted",
1129 param->name);
1130 r = 0;
1131 goto done;
1132 }
1133 valnode->bUsed = 1;
1134 val->bUsed = 1;
1135 switch(param->type) {
1136 case eCmdHdlrQueueType:
1137 r = doGetQueueType(valnode, param, val);
1138 break;
1139 case eCmdHdlrUID:
1140 r = doGetUID(valnode, param, val);
1141 break;
1142 case eCmdHdlrGID:
1143 r = doGetGID(valnode, param, val);
1144 break;
1145 case eCmdHdlrBinary:
1146 r = doGetBinary(valnode, param, val);
1147 break;
1148 case eCmdHdlrFileCreateMode:
1149 r = doGetFileCreateMode(valnode, param, val);
1150 break;
1151 case eCmdHdlrInt:
1152 r = doGetInt(valnode, param, val);
1153 break;
1154 case eCmdHdlrNonNegInt:
1155 r = doGetNonNegInt(valnode, param, val);
1156 break;
1157 case eCmdHdlrPositiveInt:
1158 r = doGetPositiveInt(valnode, param, val);
1159 break;
1160 case eCmdHdlrSize:
1161 r = doGetSize(valnode, param, val);
1162 break;
1163 case eCmdHdlrGetChar:
1164 r = doGetChar(valnode, param, val);
1165 break;
1166 case eCmdHdlrFacility:
1167 cstr = (uchar*) es_str2cstr(valnode->val.d.estr, NULL);
1168 val->val.datatype = 'N';
1169 val->val.d.n = decodeSyslogName(cstr, syslogFacNames);
1170 free(cstr);
1171 r = 1;
1172 break;
1173 case eCmdHdlrSeverity:
1174 cstr = (uchar*) es_str2cstr(valnode->val.d.estr, NULL);
1175 val->val.datatype = 'N';
1176 val->val.d.n = decodeSyslogName(cstr, syslogPriNames);
1177 free(cstr);
1178 r = 1;
1179 break;
1180 case eCmdHdlrGetWord:
1181 r = doGetWord(valnode, param, val);
1182 break;
1183 case eCmdHdlrString:
1184 val->val.datatype = 'S';
1185 val->val.d.estr = es_strdup(valnode->val.d.estr);
1186 r = 1;
1187 break;
1188 case eCmdHdlrArray:
1189 r = doGetArray(valnode, param, val);
1190 break;
1191 case eCmdHdlrGoneAway:
1192 parser_errmsg("parameter '%s' is no longer supported",
1193 param->name);
1194 r = 1; /* this *is* valid! */
1195 break;
1196 default:
1197 DBGPRINTF("error: invalid param type\n");
1198 r = 0;
1199 break;
1200 }
1201 done: return r;
1202 }
1203
1204
1205 /* obtain conf params from an nvlst and emit error messages if
1206 * necessary. If an already-existing param value is passed, that is
1207 * used. If NULL is passed instead, a new one is allocated. In that case,
1208 * it is the caller's duty to free it when no longer needed.
1209 * NULL is returned on error, otherwise a pointer to the vals array.
1210 */
1211 struct cnfparamvals* ATTR_NONNULL(2)
nvlstGetParams(struct nvlst * lst,struct cnfparamblk * params,struct cnfparamvals * vals)1212 nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params,
1213 struct cnfparamvals *vals)
1214 {
1215 #ifndef __clang_analyzer__ /* I give up on this one - let Coverity do the work */
1216 int i;
1217 int bValsWasNULL;
1218 int bInError = 0;
1219 struct nvlst *valnode;
1220 struct cnfparamdescr *param;
1221
1222 if(params->version != CNFPARAMBLK_VERSION) {
1223 DBGPRINTF("nvlstGetParams: invalid param block version "
1224 "%d, expected %d\n",
1225 params->version, CNFPARAMBLK_VERSION);
1226 return NULL;
1227 }
1228
1229 if(vals == NULL) {
1230 bValsWasNULL = 1;
1231 if((vals = calloc(params->nParams,
1232 sizeof(struct cnfparamvals))) == NULL)
1233 return NULL;
1234 } else {
1235 bValsWasNULL = 0;
1236 }
1237
1238 for(i = 0 ; i < params->nParams ; ++i) {
1239 param = params->descr + i;
1240 if((valnode = nvlstFindNameCStr(lst, param->name)) == NULL) {
1241 if(param->flags & CNFPARAM_REQUIRED) {
1242 parser_errmsg("parameter '%s' required but not specified - "
1243 "fix config", param->name);
1244 bInError = 1;
1245 }
1246 continue;
1247 }
1248 if(param->flags & CNFPARAM_DEPRECATED) {
1249 parser_errmsg("parameter '%s' deprecated but accepted, consider "
1250 "removing or replacing it", param->name);
1251 }
1252 if(vals[i].bUsed) {
1253 parser_errmsg("parameter '%s' specified more than once - "
1254 "one instance is ignored. Fix config", param->name);
1255 continue;
1256 }
1257 if(!nvlstGetParam(valnode, param, vals + i)) {
1258 bInError = 1;
1259 }
1260 }
1261
1262 /* done parameter processing */
1263 if(bInError) {
1264 if(bValsWasNULL)
1265 cnfparamvalsDestruct(vals, params);
1266 vals = NULL;
1267 }
1268
1269 return vals;
1270 #else
1271 return NULL;
1272 #endif
1273 }
1274
1275
1276 /* check if at least one cnfparamval is actually set
1277 * returns 1 if so, 0 otherwise
1278 */
1279 int
cnfparamvalsIsSet(struct cnfparamblk * params,struct cnfparamvals * vals)1280 cnfparamvalsIsSet(struct cnfparamblk *params, struct cnfparamvals *vals)
1281 {
1282 int i;
1283
1284 if(vals == NULL)
1285 return 0;
1286 if(params->version != CNFPARAMBLK_VERSION) {
1287 DBGPRINTF("nvlstGetParams: invalid param block version "
1288 "%d, expected %d\n",
1289 params->version, CNFPARAMBLK_VERSION);
1290 return 0;
1291 }
1292 for(i = 0 ; i < params->nParams ; ++i) {
1293 if(vals[i].bUsed)
1294 return 1;
1295 }
1296 return 0;
1297 }
1298
1299
1300 void
cnfparamsPrint(const struct cnfparamblk * params,const struct cnfparamvals * vals)1301 cnfparamsPrint(const struct cnfparamblk *params, const struct cnfparamvals *vals)
1302 {
1303 int i;
1304 char *cstr;
1305
1306 if(!Debug)
1307 return;
1308
1309 for(i = 0 ; i < params->nParams ; ++i) {
1310 dbgprintf("%s: ", params->descr[i].name);
1311 if(vals[i].bUsed) {
1312 // TODO: other types!
1313 switch(vals[i].val.datatype) {
1314 case 'S':
1315 cstr = es_str2cstr(vals[i].val.d.estr, NULL);
1316 dbgprintf(" '%s'", cstr);
1317 free(cstr);
1318 break;
1319 case 'A':
1320 cnfarrayPrint(vals[i].val.d.ar, 0);
1321 break;
1322 case 'N':
1323 dbgprintf("%lld", vals[i].val.d.n);
1324 break;
1325 default:
1326 dbgprintf("(unsupported datatype %c)",
1327 vals[i].val.datatype);
1328 }
1329 } else {
1330 dbgprintf("(unset)");
1331 }
1332 dbgprintf("\n");
1333 }
1334 }
1335
1336 struct cnfobj*
cnfobjNew(enum cnfobjType objType,struct nvlst * lst)1337 cnfobjNew(enum cnfobjType objType, struct nvlst *lst)
1338 {
1339 struct cnfobj *o;
1340
1341 if((o = malloc(sizeof(struct cnfobj))) != NULL) {
1342 nvlstChkDupes(lst);
1343 o->objType = objType;
1344 o->nvlst = lst;
1345 o->subobjs = NULL;
1346 o->script = NULL;
1347 }
1348
1349 return o;
1350 }
1351
1352 void
cnfobjDestruct(struct cnfobj * o)1353 cnfobjDestruct(struct cnfobj *o)
1354 {
1355 if(o != NULL) {
1356 nvlstDestruct(o->nvlst);
1357 objlstDestruct(o->subobjs);
1358 free(o);
1359 }
1360 }
1361
1362 void
cnfobjPrint(struct cnfobj * o)1363 cnfobjPrint(struct cnfobj *o)
1364 {
1365 dbgprintf("obj: '%s'\n", cnfobjType2str(o->objType));
1366 nvlstPrint(o->nvlst);
1367 }
1368
1369
1370 struct cnfexpr*
cnfexprNew(unsigned nodetype,struct cnfexpr * l,struct cnfexpr * r)1371 cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r)
1372 {
1373 struct cnfexpr *expr;
1374
1375 /* optimize some constructs during parsing */
1376 if(nodetype == 'M' && r->nodetype == 'N') {
1377 ((struct cnfnumval*)r)->val *= -1;
1378 expr = r;
1379 goto done;
1380 }
1381
1382 if((expr = malloc(sizeof(struct cnfexpr))) != NULL) {
1383 expr->nodetype = nodetype;
1384 expr->l = l;
1385 expr->r = r;
1386 }
1387 done:
1388 return expr;
1389 }
1390
1391
1392 static int64_t
str2num(es_str_t * s,int * bSuccess)1393 str2num(es_str_t *s, int *bSuccess)
1394 {
1395 size_t i;
1396 int neg;
1397 int64_t num = 0;
1398 const uchar *const c = es_getBufAddr(s);
1399
1400 if(s->lenStr == 0) {
1401 DBGPRINTF("rainerscript: str2num: strlen == 0; invalid input (no string)\n");
1402 if(bSuccess != NULL) {
1403 *bSuccess = 1;
1404 }
1405 goto done;
1406 }
1407 if(c[0] == '-') {
1408 neg = -1;
1409 i = 1;
1410 } else {
1411 neg = 1;
1412 i = 0;
1413 }
1414 while(i < s->lenStr && isdigit(c[i])) {
1415 num = num * 10 + c[i] - '0';
1416 ++i;
1417 }
1418 num *= neg;
1419 if(bSuccess != NULL)
1420 *bSuccess = (i == s->lenStr) ? 1 : 0;
1421 done:
1422 return num;
1423 }
1424
1425 /* We support decimal integers. Unfortunately, previous versions
1426 * said they support oct and hex, but that wasn't really the case.
1427 * Everything based on JSON was just dec-converted. As this was/is
1428 * the norm, we fix that inconsistency. Luckly, oct and hex support
1429 * was never documented.
1430 * rgerhards, 2015-11-12
1431 */
1432 long long
var2Number(struct svar * r,int * bSuccess)1433 var2Number(struct svar *r, int *bSuccess)
1434 {
1435 long long n = 0;
1436 if(r->datatype == 'S') {
1437 n = str2num(r->d.estr, bSuccess);
1438 } else {
1439 if(r->datatype == 'J') {
1440 n = (r->d.json == NULL) ? 0 : json_object_get_int64(r->d.json);
1441 } else {
1442 n = r->d.n;
1443 }
1444 if(bSuccess != NULL)
1445 *bSuccess = 1;
1446 }
1447 return n;
1448 }
1449
1450 /* ensure that retval is a string
1451 */
1452 static es_str_t *
var2String(struct svar * __restrict__ const r,int * __restrict__ const bMustFree)1453 var2String(struct svar *__restrict__ const r, int *__restrict__ const bMustFree)
1454 {
1455 es_str_t *estr;
1456 const char *cstr;
1457 rs_size_t lenstr;
1458 if(r->datatype == 'N') {
1459 *bMustFree = 1;
1460 estr = es_newStrFromNumber(r->d.n);
1461 } else if(r->datatype == 'J') {
1462 *bMustFree = 1;
1463 if(r->d.json == NULL) {
1464 cstr = "",
1465 lenstr = 0;
1466 } else {
1467 cstr = (char*)json_object_get_string(r->d.json);
1468 lenstr = strlen(cstr);
1469 }
1470 estr = es_newStrFromCStr(cstr, lenstr);
1471 } else {
1472 *bMustFree = 0;
1473 estr = r->d.estr;
1474 }
1475 return estr;
1476 }
1477
1478 uchar*
var2CString(struct svar * __restrict__ const r,int * __restrict__ const bMustFree)1479 var2CString(struct svar *__restrict__ const r, int *__restrict__ const bMustFree)
1480 {
1481 uchar *cstr;
1482 es_str_t *estr;
1483 estr = var2String(r, bMustFree);
1484 cstr = (uchar*) es_str2cstr(estr, NULL);
1485 if(*bMustFree)
1486 es_deleteStr(estr);
1487 *bMustFree = 1;
1488 return cstr;
1489 }
1490
1491 /* frees struct svar members, but not the struct itself. This is because
1492 * it usually is allocated on the stack. Callers why dynamically allocate
1493 * struct svar need to free the struct themselfes!
1494 */
1495
1496 int SKIP_NOTHING = 0x0;
1497 int SKIP_STRING = 0x1;
1498
1499 static void
varFreeMembersSelectively(const struct svar * r,const int skipMask)1500 varFreeMembersSelectively(const struct svar *r, const int skipMask)
1501 {
1502 if(r->datatype == 'J') {
1503 json_object_put(r->d.json);
1504 } else if( !(skipMask & SKIP_STRING) && (r->datatype == 'S')) {
1505 es_deleteStr(r->d.estr);
1506 }
1507 }
1508
1509 void
varFreeMembers(const struct svar * r)1510 varFreeMembers(const struct svar *r)
1511 {
1512 varFreeMembersSelectively(r, SKIP_NOTHING);
1513 }
1514
1515
1516 static rsRetVal
doExtractFieldByChar(uchar * str,uchar delim,const int matchnbr,uchar ** resstr)1517 doExtractFieldByChar(uchar *str, uchar delim, const int matchnbr, uchar **resstr)
1518 {
1519 int iCurrFld;
1520 int allocLen;
1521 int iLen;
1522 uchar *pBuf;
1523 uchar *pFld;
1524 uchar *pFldEnd;
1525 DEFiRet;
1526
1527 /* first, skip to the field in question */
1528 iCurrFld = 1;
1529 pFld = str;
1530 while(*pFld && iCurrFld < matchnbr) {
1531 /* skip fields until the requested field or end of string is found */
1532 while(*pFld && (uchar) *pFld != delim)
1533 ++pFld; /* skip to field terminator */
1534 if(*pFld == delim) {
1535 ++pFld; /* eat it */
1536 ++iCurrFld;
1537 }
1538 }
1539 DBGPRINTF("field() field requested %d, field found %d\n", matchnbr, iCurrFld);
1540
1541 if(iCurrFld == matchnbr) {
1542 /* field found, now extract it */
1543 /* first of all, we need to find the end */
1544 pFldEnd = pFld;
1545 while(*pFldEnd && *pFldEnd != delim)
1546 ++pFldEnd;
1547 --pFldEnd; /* we are already at the delimiter - so we need to
1548 * step back a little not to copy it as part of the field. */
1549 /* we got our end pointer, now do the copy */
1550 iLen = pFldEnd - pFld + 1; /* the +1 is for an actual char, NOT \0! */
1551 allocLen = iLen + 1;
1552 # ifdef VALGRIND
1553 allocLen += (3 - (iLen % 4));
1554 /*older versions of valgrind have a problem with strlen inspecting 4-bytes at a time*/
1555 # endif
1556 CHKmalloc(pBuf = malloc(allocLen));
1557 /* now copy */
1558 memcpy(pBuf, pFld, iLen);
1559 pBuf[iLen] = '\0'; /* terminate it */
1560 *resstr = pBuf;
1561 } else {
1562 ABORT_FINALIZE(RS_RET_FIELD_NOT_FOUND);
1563 }
1564 finalize_it:
1565 RETiRet;
1566 }
1567
1568
1569 static rsRetVal
doExtractFieldByStr(uchar * str,char * delim,const rs_size_t lenDelim,const int matchnbr,uchar ** resstr)1570 doExtractFieldByStr(uchar *str, char *delim, const rs_size_t lenDelim, const int matchnbr, uchar **resstr)
1571 {
1572 int iCurrFld;
1573 int iLen;
1574 uchar *pBuf;
1575 uchar *pFld;
1576 uchar *pFldEnd;
1577 DEFiRet;
1578
1579 if (str == NULL || delim == NULL)
1580 ABORT_FINALIZE(RS_RET_FIELD_NOT_FOUND);
1581
1582 /* first, skip to the field in question */
1583 iCurrFld = 1;
1584 pFld = str;
1585 while(pFld != NULL && iCurrFld < matchnbr) {
1586 if((pFld = (uchar*) strstr((char*)pFld, delim)) != NULL) {
1587 pFld += lenDelim;
1588 ++iCurrFld;
1589 }
1590 }
1591 DBGPRINTF("field() field requested %d, field found %d\n", matchnbr, iCurrFld);
1592
1593 if(iCurrFld == matchnbr) {
1594 /* field found, now extract it */
1595 /* first of all, we need to find the end */
1596 pFldEnd = (uchar*) strstr((char*)pFld, delim);
1597 if(pFldEnd == NULL) {
1598 iLen = strlen((char*) pFld);
1599 } else { /* found delmiter! Note that pFldEnd *is* already on
1600 * the first delmi char, we don't need that. */
1601 iLen = pFldEnd - pFld;
1602 }
1603 /* we got our end pointer, now do the copy */
1604 CHKmalloc(pBuf = malloc(iLen + 1));
1605 /* now copy */
1606 memcpy(pBuf, pFld, iLen);
1607 pBuf[iLen] = '\0'; /* terminate it */
1608 *resstr = pBuf;
1609 } else {
1610 ABORT_FINALIZE(RS_RET_FIELD_NOT_FOUND);
1611 }
1612 finalize_it:
1613 RETiRet;
1614 }
1615
1616 static void
doFunc_re_extract(struct cnffunc * func,struct svar * ret,void * usrptr,wti_t * const pWti)1617 doFunc_re_extract(struct cnffunc *func, struct svar *ret, void* usrptr, wti_t *const pWti)
1618 {
1619 size_t submatchnbr;
1620 short matchnbr;
1621 regmatch_t pmatch[50];
1622 int bMustFree;
1623 es_str_t *estr = NULL; /* init just to keep compiler happy */
1624 char *str;
1625 struct svar r[CNFFUNC_MAX_ARGS];
1626 int iLenBuf;
1627 unsigned iOffs;
1628 short iTry = 0;
1629 uchar bFound = 0;
1630 iOffs = 0;
1631 sbool bHadNoMatch = 0;
1632
1633 cnfexprEval(func->expr[0], &r[0], usrptr, pWti);
1634 /* search string is already part of the compiled regex, so we don't
1635 * need it here!
1636 */
1637 cnfexprEval(func->expr[2], &r[2], usrptr, pWti);
1638 cnfexprEval(func->expr[3], &r[3], usrptr, pWti);
1639 str = (char*) var2CString(&r[0], &bMustFree);
1640 matchnbr = (short) var2Number(&r[2], NULL);
1641 submatchnbr = (size_t) var2Number(&r[3], NULL);
1642 if(submatchnbr >= sizeof(pmatch)/sizeof(regmatch_t)) {
1643 DBGPRINTF("re_extract() submatch %zd is too large\n", submatchnbr);
1644 bHadNoMatch = 1;
1645 goto finalize_it;
1646 }
1647
1648 /* first see if we find a match, iterating through the series of
1649 * potential matches over the string.
1650 */
1651 while(!bFound) {
1652 int iREstat;
1653 iREstat = regexp.regexec(func->funcdata, (char*)(str + iOffs),
1654 submatchnbr+1, pmatch, 0);
1655 DBGPRINTF("re_extract: regexec return is %d\n", iREstat);
1656 if(iREstat == 0) {
1657 if(pmatch[0].rm_so == -1) {
1658 DBGPRINTF("oops ... start offset of successful regexec is -1\n");
1659 break;
1660 }
1661 if(iTry == matchnbr) {
1662 bFound = 1;
1663 } else {
1664 DBGPRINTF("re_extract: regex found at offset %d, new offset %d, tries %d\n",
1665 iOffs, (int) (iOffs + pmatch[0].rm_eo), iTry);
1666 iOffs += pmatch[0].rm_eo;
1667 ++iTry;
1668 }
1669 } else {
1670 break;
1671 }
1672 }
1673 DBGPRINTF("re_extract: regex: end search, found %d\n", bFound);
1674 if(!bFound) {
1675 bHadNoMatch = 1;
1676 goto finalize_it;
1677 } else {
1678 /* Match- but did it match the one we wanted? */
1679 /* we got no match! */
1680 if(pmatch[submatchnbr].rm_so == -1) {
1681 bHadNoMatch = 1;
1682 goto finalize_it;
1683 }
1684 /* OK, we have a usable match - we now need to malloc pB */
1685 iLenBuf = pmatch[submatchnbr].rm_eo - pmatch[submatchnbr].rm_so;
1686 estr = es_newStrFromBuf(str + iOffs + pmatch[submatchnbr].rm_so,
1687 iLenBuf);
1688 }
1689
1690 finalize_it:
1691 if(bMustFree) free(str);
1692 varFreeMembers(&r[0]);
1693 varFreeMembers(&r[2]);
1694 varFreeMembers(&r[3]);
1695
1696 if(bHadNoMatch) {
1697 cnfexprEval(func->expr[4], &r[4], usrptr, pWti);
1698 estr = var2String(&r[4], &bMustFree);
1699 varFreeMembersSelectively(&r[4], SKIP_STRING);
1700 /* Note that we do NOT free the string that was returned/created
1701 * for r[4]. We pass it to the caller, which in turn frees it.
1702 * This saves us doing one unnecessary memory alloc & write.
1703 */
1704 }
1705 ret->datatype = 'S';
1706 ret->d.estr = estr;
1707 return;
1708 }
1709
1710
1711 /* note that we do not need to evaluate any parameters, as the template pointer
1712 * is set during initialization().
1713 * TODO: think if we can keep our buffer; but that may not be trival thinking about
1714 * multiple threads.
1715 */
1716 static void
doFunc_exec_template(struct cnffunc * __restrict__ const func,struct svar * __restrict__ const ret,void * const usrptr,wti_t * const pWti)1717 doFunc_exec_template(struct cnffunc *__restrict__ const func,
1718 struct svar *__restrict__ const ret,
1719 void *const usrptr,
1720 wti_t *const pWti __attribute__((unused)))
1721 {
1722 smsg_t *const pMsg = (smsg_t*) usrptr;
1723 rsRetVal localRet;
1724 actWrkrIParams_t iparam;
1725
1726 wtiInitIParam(&iparam);
1727 localRet = tplToString(func->funcdata, pMsg, &iparam, NULL);
1728 if(localRet == RS_RET_OK) {
1729 ret->d.estr = es_newStrFromCStr((char*)iparam.param, iparam.lenStr);
1730 } else {
1731 ret->d.estr = es_newStrFromCStr("", 0);
1732 }
1733 ret->datatype = 'S';
1734 free(iparam.param);
1735
1736 return;
1737 }
1738
1739 static es_str_t*
doFuncReplace(struct svar * __restrict__ const operandVal,struct svar * __restrict__ const findVal,struct svar * __restrict__ const replaceWithVal)1740 doFuncReplace(struct svar *__restrict__ const operandVal, struct svar *__restrict__ const findVal,
1741 struct svar *__restrict__ const replaceWithVal) {
1742 int freeOperand, freeFind, freeReplacement;
1743 es_str_t *str = var2String(operandVal, &freeOperand);
1744 es_str_t *findStr = var2String(findVal, &freeFind);
1745 es_str_t *replaceWithStr = var2String(replaceWithVal, &freeReplacement);
1746 uchar *find = es_getBufAddr(findStr);
1747 uchar *replaceWith = es_getBufAddr(replaceWithStr);
1748 uint lfind = es_strlen(findStr);
1749 uint lReplaceWith = es_strlen(replaceWithStr);
1750 uint lSrc = es_strlen(str);
1751 uint lDst = 0;
1752 uchar* src_buff = es_getBufAddr(str);
1753 uint i, j;
1754 for(i = j = 0; i <= lSrc; i++, lDst++) {
1755 if (j == lfind) {
1756 lDst = lDst - lfind + lReplaceWith;
1757 j = 0;
1758 }
1759 if (i == lSrc) break;
1760 if (src_buff[i] == find[j]) {
1761 j++;
1762 } else if (j > 0) {
1763 i -= (j - 1);
1764 lDst -= (j - 1);
1765 j = 0;
1766 }
1767 }
1768 es_str_t *res = es_newStr(lDst);
1769 unsigned char* dest = es_getBufAddr(res);
1770 uint k, s;
1771 for(i = j = s = 0; i <= lSrc; i++, s++) {
1772 if (j == lfind) {
1773 s -= j;
1774 for (k = 0; k < lReplaceWith; k++, s++) dest[s] = replaceWith[k];
1775 j = 0;
1776 }
1777 if (i == lSrc) break;
1778 if (src_buff[i] == find[j]) {
1779 j++;
1780 } else {
1781 if (j > 0) {
1782 i -= j;
1783 s -= j;
1784 j = 0;
1785 }
1786 dest[s] = src_buff[i];
1787 }
1788 }
1789 if (j > 0) {
1790 for (k = 1; k <= j; k++) dest[s - k] = src_buff[i - k];
1791 }
1792 res->lenStr = lDst;
1793 if(freeOperand) es_deleteStr(str);
1794 if(freeFind) es_deleteStr(findStr);
1795 if(freeReplacement) es_deleteStr(replaceWithStr);
1796 return res;
1797 }
1798
1799
ATTR_NONNULL()1800 static void ATTR_NONNULL()
1801 doFunc_parse_json(struct cnffunc *__restrict__ const func,
1802 struct svar *__restrict__ const ret,
1803 void *const usrptr,
1804 wti_t *const pWti)
1805 {
1806 struct svar srcVal[2];
1807 int bMustFree;
1808 int bMustFree2;
1809 smsg_t *const pMsg = (smsg_t*)usrptr;
1810 cnfexprEval(func->expr[0], &srcVal[0], usrptr, pWti);
1811 cnfexprEval(func->expr[1], &srcVal[1], usrptr, pWti);
1812 char *jsontext = (char*) var2CString(&srcVal[0], &bMustFree);
1813 char *container = (char*) var2CString(&srcVal[1], &bMustFree2);
1814 struct json_object *json;
1815
1816 int retVal;
1817 assert(jsontext != NULL);
1818 assert(container != NULL);
1819 assert(pMsg != NULL);
1820
1821 struct json_tokener *const tokener = json_tokener_new();
1822 if(tokener == NULL) {
1823 retVal = 1;
1824 goto finalize_it;
1825 }
1826 json = json_tokener_parse_ex(tokener, jsontext, strlen(jsontext));
1827 if(json == NULL) {
1828 retVal = RS_SCRIPT_EINVAL;
1829 } else {
1830 size_t off = (*container == '$') ? 1 : 0;
1831 msgAddJSON(pMsg, (uchar*)container+off, json, 0, 0);
1832 retVal = RS_SCRIPT_EOK;
1833 }
1834 wtiSetScriptErrno(pWti, retVal);
1835 json_tokener_free(tokener);
1836
1837
1838 finalize_it:
1839 ret->datatype = 'N';
1840 ret->d.n = retVal;
1841
1842 if(bMustFree) {
1843 free(jsontext);
1844 }
1845 if(bMustFree2) {
1846 free(container);
1847 }
1848 varFreeMembers(&srcVal[0]);
1849 varFreeMembers(&srcVal[1]);
1850 }
1851
1852
ATTR_NONNULL()1853 static void ATTR_NONNULL()
1854 doFunc_get_property(struct cnffunc *__restrict__ const func,
1855 struct svar *__restrict__ const ret,
1856 void *const usrptr,
1857 wti_t *const pWti)
1858 {
1859 int retVal = RS_SCRIPT_EOK;
1860 int bMustFree = 0;
1861 char *expr = NULL;
1862 struct svar srcVal[2] = {{.d={0}, .datatype=0}};
1863 struct json_object *json = NULL;
1864
1865 /* ignore string literals */
1866 if (func->expr[0]->nodetype == 'S') {
1867 retVal = RS_SCRIPT_EINVAL;
1868 FINALIZE;
1869 }
1870
1871 cnfexprEval(func->expr[0], &srcVal[0], usrptr, pWti);
1872 cnfexprEval(func->expr[1], &srcVal[1], usrptr, pWti);
1873 DBGPRINTF("srcval[0] datatype: %c\n", srcVal[0].datatype);
1874 DBGPRINTF("srcval[1] datatype: %c\n", srcVal[1].datatype);
1875
1876 switch (srcVal[0].datatype) {
1877 case 'J': {
1878 json = srcVal[0].d.json;
1879 break;
1880 }
1881 case 'S': {
1882 ret->d.estr = es_strdup(srcVal[0].d.estr);
1883 ret->datatype = 'S';
1884 FINALIZE;
1885 break;
1886 }
1887 default: {
1888 ret->d.estr = es_newStrFromCStr("", 1);
1889 ret->datatype = 'S';
1890 FINALIZE;
1891 break;
1892 }
1893 }
1894
1895 switch (json_object_get_type(json)) {
1896 case json_type_object: {
1897 expr = (char*) var2CString(&srcVal[1], &bMustFree);
1898 if (expr && expr[0] == '\0') {
1899 ret->d.json = json_object_get(json);
1900 ret->datatype = 'J';
1901 break;
1902 }
1903 if (expr && !json_object_object_get_ex(json, (char*)expr, &ret->d.json)) {
1904 retVal = RS_SCRIPT_EINVAL;
1905 FINALIZE;
1906 }
1907 if (ret->d.json) {
1908 ret->d.json = json_object_get(ret->d.json);
1909 ret->datatype = 'J';
1910 } else {
1911 ret->d.estr = es_newStrFromCStr("", 1);
1912 ret->datatype = 'S';
1913 }
1914 break;
1915 }
1916 case json_type_array: {
1917 int success = 0;
1918 long long index = var2Number(&srcVal[1], &success);
1919 if (!success || index < 0 || (size_t)index >= sizeof(size_t)) {
1920 retVal = RS_SCRIPT_EINVAL;
1921 FINALIZE;
1922 }
1923 ret->d.json = json_object_array_get_idx(json, index);
1924 if (ret->d.json) {
1925 ret->d.json = json_object_get(ret->d.json);
1926 ret->datatype = 'J';
1927 } else {
1928 ret->d.estr = es_newStrFromCStr("", 1);
1929 ret->datatype = 'S';
1930 }
1931 break;
1932 }
1933 case json_type_boolean:
1934 case json_type_int: {
1935 ret->d.n = json_object_get_int64(json);
1936 ret->datatype = 'N';
1937 break;
1938 }
1939 case json_type_double: {
1940 ret->d.n = json_object_get_double(json);
1941 ret->datatype = 'N';
1942 break;
1943 }
1944 case json_type_string: {
1945 ret->d.estr = es_newStrFromCStr(json_object_get_string(json), json_object_get_string_len(json));
1946 ret->datatype = 'S';
1947 break;
1948 }
1949 case json_type_null: {
1950 ret->datatype = 'S';
1951 ret->d.estr = es_newStrFromCStr("", 1);
1952 break;
1953 }
1954 default:
1955 LogError(0, RS_RET_INTERNAL_ERROR,
1956 "Warning - unhandled json type(%d) !!!!\n", json_object_get_type(json));
1957 retVal = RS_SCRIPT_EINVAL;
1958 break;
1959 }
1960
1961 finalize_it:
1962 wtiSetScriptErrno(pWti, retVal);
1963
1964 if (retVal != RS_SCRIPT_EOK) {
1965 ret->datatype = 'S';
1966 ret->d.estr = es_newStrFromCStr("", 1);
1967 }
1968 if (bMustFree) {
1969 free(expr);
1970 }
1971 varFreeMembers(&srcVal[0]);
1972 varFreeMembers(&srcVal[1]);
1973 }
1974
ATTR_NONNULL()1975 static void ATTR_NONNULL()
1976 doFunct_RandomGen(struct cnffunc *__restrict__ const func,
1977 struct svar *__restrict__ const ret,
1978 void *__restrict__ const usrptr,
1979 wti_t *__restrict__ const pWti)
1980 {
1981 int success = 0;
1982 struct svar srcVal;
1983 long long retVal;
1984 long int x;
1985
1986 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
1987 long long max = var2Number(&srcVal, &success);
1988 if (! success) {
1989 DBGPRINTF("rainerscript: random(max) didn't get a valid 'max' limit, defaulting random-number "
1990 "value to 0");
1991 retVal = 0;
1992 goto done;
1993 }
1994 if(max == 0) {
1995 DBGPRINTF("rainerscript: random(max) invalid, 'max' is zero, , defaulting random-number value to 0");
1996 retVal = 0;
1997 goto done;
1998 }
1999 x = labs(randomNumber());
2000 if (max > MAX_RANDOM_NUMBER) {
2001 DBGPRINTF("rainerscript: desired random-number range [0 - %lld] "
2002 "is wider than supported limit of [0 - %d)\n",
2003 max, MAX_RANDOM_NUMBER);
2004 }
2005
2006 retVal = (x % max);
2007 done:
2008 ret->d.n = retVal;
2009 ret->datatype = 'N';
2010 varFreeMembers(&srcVal);
2011 }
2012
ATTR_NONNULL()2013 static void ATTR_NONNULL()
2014 doFunct_LTrim(struct cnffunc *__restrict__ const func,
2015 struct svar *__restrict__ const ret,
2016 void *__restrict__ const usrptr,
2017 wti_t *__restrict__ const pWti)
2018 {
2019 struct svar srcVal;
2020 int bMustFree;
2021 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2022 char *str = (char*)var2CString(&srcVal, &bMustFree);
2023
2024 const int len = strlen(str);
2025 int i;
2026 es_str_t *estr = NULL;
2027
2028 for(i = 0; i < len; i++) {
2029 if(str[i] != ' ') {
2030 break;
2031 }
2032 }
2033
2034 estr = es_newStrFromCStr(str + i, len - i);
2035
2036 ret->d.estr = estr;
2037 ret->datatype = 'S';
2038 varFreeMembers(&srcVal);
2039 if(bMustFree)
2040 free(str);
2041 }
2042
ATTR_NONNULL()2043 static void ATTR_NONNULL()
2044 doFunct_RTrim(struct cnffunc *__restrict__ const func,
2045 struct svar *__restrict__ const ret,
2046 void *__restrict__ const usrptr,
2047 wti_t *__restrict__ const pWti)
2048 {
2049 struct svar srcVal;
2050 int bMustFree;
2051 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2052 char *str = (char*)var2CString(&srcVal, &bMustFree);
2053
2054 int len = strlen(str);
2055 int i;
2056 es_str_t *estr = NULL;
2057
2058 for(i = (len - 1); i > 0; i--) {
2059 if(str[i] != ' ') {
2060 break;
2061 }
2062 }
2063
2064 if(i > 0 || str[0] != ' ') {
2065 estr = es_newStrFromCStr(str, (i + 1));
2066 } else {
2067 estr = es_newStr(1);
2068 }
2069
2070 ret->d.estr = estr;
2071 ret->datatype = 'S';
2072 varFreeMembers(&srcVal);
2073 if(bMustFree)
2074 free(str);
2075 }
2076
ATTR_NONNULL()2077 static void ATTR_NONNULL()
2078 doFunct_Getenv(struct cnffunc *__restrict__ const func,
2079 struct svar *__restrict__ const ret,
2080 void *__restrict__ const usrptr,
2081 wti_t *__restrict__ const pWti)
2082 {
2083 /* note: the optimizer shall have replaced calls to getenv()
2084 * with a constant argument to a single string (once obtained via
2085 * getenv()). So we do NOT need to check if there is just a
2086 * string following.
2087 */
2088 struct svar srcVal;
2089 char *envvar;
2090 es_str_t *estr;
2091 char *str;
2092 int bMustFree;
2093
2094 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2095 estr = var2String(&srcVal, &bMustFree);
2096 str = (char*) es_str2cstr(estr, NULL);
2097 envvar = getenv(str);
2098 if(envvar == NULL) {
2099 ret->d.estr = es_newStr(0);
2100 } else {
2101 ret->d.estr = es_newStrFromCStr(envvar, strlen(envvar));
2102 }
2103 ret->datatype = 'S';
2104 if(bMustFree) {
2105 es_deleteStr(estr);
2106 }
2107 varFreeMembers(&srcVal);
2108 free(str);
2109
2110 }
2111
ATTR_NONNULL()2112 static void ATTR_NONNULL()
2113 doFunct_ToLower(struct cnffunc *__restrict__ const func,
2114 struct svar *__restrict__ const ret,
2115 void *__restrict__ const usrptr,
2116 wti_t *__restrict__ const pWti)
2117 {
2118 struct svar srcVal;
2119 es_str_t *estr;
2120 int bMustFree;
2121
2122 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2123 estr = var2String(&srcVal, &bMustFree);
2124 if(!bMustFree) {/* let caller handle that M) */
2125 estr = es_strdup(estr);
2126 }
2127 es_tolower(estr);
2128 ret->datatype = 'S';
2129 ret->d.estr = estr;
2130 varFreeMembers(&srcVal);
2131 }
2132
ATTR_NONNULL()2133 static void ATTR_NONNULL()
2134 doFunct_CStr(struct cnffunc *__restrict__ const func,
2135 struct svar *__restrict__ const ret,
2136 void *__restrict__ const usrptr,
2137 wti_t *__restrict__ const pWti)
2138 {
2139 struct svar srcVal;
2140 es_str_t *estr;
2141 int bMustFree;
2142
2143 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2144 estr = var2String(&srcVal, &bMustFree);
2145 if(!bMustFree) /* let caller handle that M) */
2146 estr = es_strdup(estr);
2147 ret->datatype = 'S';
2148 ret->d.estr = estr;
2149 varFreeMembers(&srcVal);
2150 }
2151
ATTR_NONNULL()2152 static void ATTR_NONNULL()
2153 doFunct_CNum(struct cnffunc *__restrict__ const func,
2154 struct svar *__restrict__ const ret,
2155 void *__restrict__ const usrptr,
2156 wti_t *__restrict__ const pWti)
2157 {
2158 struct svar srcVal;
2159
2160 if(func->expr[0]->nodetype == 'N') {
2161 ret->d.n = ((struct cnfnumval*)func->expr[0])->val;
2162 } else if(func->expr[0]->nodetype == 'S') {
2163 ret->d.n = es_str2num(((struct cnfstringval*) func->expr[0])->estr,
2164 NULL);
2165 } else {
2166 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2167 ret->d.n = var2Number(&srcVal, NULL);
2168 varFreeMembers(&srcVal);
2169 }
2170 ret->datatype = 'N';
2171 DBGPRINTF("JSONorString: cnum node type %c result %d\n", func->expr[0]->nodetype, (int) ret->d.n);
2172 }
2173
ATTR_NONNULL()2174 static void ATTR_NONNULL()
2175 doFunct_ReMatch(struct cnffunc *__restrict__ const func,
2176 struct svar *__restrict__ const ret,
2177 void *__restrict__ const usrptr,
2178 wti_t *__restrict__ const pWti)
2179 {
2180 struct svar srcVal;
2181 int bMustFree;
2182 char *str;
2183 int retval;
2184
2185 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2186 str = (char*) var2CString(&srcVal, &bMustFree);
2187 retval = regexp.regexec(func->funcdata, str, 0, NULL, 0);
2188 if(retval == 0)
2189 ret->d.n = 1;
2190 else {
2191 ret->d.n = 0;
2192 if(retval != REG_NOMATCH) {
2193 DBGPRINTF("re_match: regexec returned error %d\n", retval);
2194 }
2195 }
2196 ret->datatype = 'N';
2197 if(bMustFree) {
2198 free(str);
2199 }
2200 varFreeMembers(&srcVal);
2201 }
2202
ATTR_NONNULL()2203 static void ATTR_NONNULL()
2204 doFunct_Ipv42num(struct cnffunc *__restrict__ const func,
2205 struct svar *__restrict__ const ret,
2206 void *__restrict__ const usrptr,
2207 wti_t *__restrict__ const pWti)
2208 {
2209 struct svar srcVal;
2210 int bMustFree;
2211 char *str;
2212
2213 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2214 str = (char*)var2CString(&srcVal, &bMustFree);
2215
2216
2217 unsigned num[4] = {0, 0, 0, 0};
2218 long long value = -1;
2219 size_t len = strlen(str);
2220 int cyc = 0;
2221 int prevdot = 0;
2222 int startblank = 0;
2223 int endblank = 0;
2224 DBGPRINTF("rainerscript: (ipv42num) arg: '%s'\n", str);
2225 for(unsigned int i = 0 ; i < len ; i++) {
2226 switch(str[i]){
2227 case '0':
2228 case '1':
2229 case '2':
2230 case '3':
2231 case '4':
2232 case '5':
2233 case '6':
2234 case '7':
2235 case '8':
2236 case '9':
2237 if(endblank == 1){
2238 DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format "
2239 "(invalid space(1))\n");
2240 goto done;
2241 }
2242 prevdot = 0;
2243 startblank = 0;
2244 DBGPRINTF("rainerscript: (ipv42num) cycle: %d\n", cyc);
2245 num[cyc] = num[cyc]*10+(str[i]-'0');
2246 break;
2247 case ' ':
2248 prevdot = 0;
2249 if(i == 0 || startblank == 1){
2250 startblank = 1;
2251 break;
2252 }
2253 else{
2254 endblank = 1;
2255 break;
2256 }
2257 case '.':
2258 if(endblank == 1){
2259 DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format "
2260 "(inalid space(2))\n");
2261 goto done;
2262 }
2263 startblank = 0;
2264 if(prevdot == 1){
2265 DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format "
2266 "(two dots after one another)\n");
2267 goto done;
2268 }
2269 prevdot = 1;
2270 cyc++;
2271 if(cyc > 3){
2272 DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format "
2273 "(too many dots)\n");
2274 goto done;
2275 }
2276 break;
2277 default:
2278 DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format (invalid charakter)\n");
2279 goto done;
2280 }
2281 }
2282 if(cyc != 3){
2283 DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format (wrong number of dots)\n");
2284 goto done;
2285 }
2286 value = num[0]*256*256*256+num[1]*256*256+num[2]*256+num[3];
2287 done:
2288 DBGPRINTF("rainerscript: (ipv42num): return value:'%lld'\n",value);
2289 ret->datatype = 'N';
2290 ret->d.n = value;
2291 varFreeMembers(&srcVal);
2292 if(bMustFree)
2293 free(str);
2294 }
2295
ATTR_NONNULL()2296 static void ATTR_NONNULL()
2297 doFunct_Int2Hex(struct cnffunc *__restrict__ const func,
2298 struct svar *__restrict__ const ret,
2299 void *__restrict__ const usrptr,
2300 wti_t *__restrict__ const pWti)
2301 {
2302 struct svar srcVal;
2303 int success = 0;
2304 char str[18];
2305 es_str_t* estr = NULL;
2306 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2307 long long num = var2Number(&srcVal, &success);
2308
2309 if (!success) {
2310 DBGPRINTF("rainerscript: (int2hex) couldn't access number\n");
2311 estr = es_newStrFromCStr("NAN", strlen("NAN"));
2312 goto done;
2313 }
2314
2315 snprintf(str, 18, "%llx", num);
2316 estr = es_newStrFromCStr(str, strlen(str));
2317
2318 done:
2319 ret->d.estr = estr;
2320 ret->datatype = 'S';
2321 varFreeMembers(&srcVal);
2322 }
2323
ATTR_NONNULL()2324 static void ATTR_NONNULL()
2325 doFunct_Replace(struct cnffunc *__restrict__ const func,
2326 struct svar *__restrict__ const ret,
2327 void *__restrict__ const usrptr,
2328 wti_t *__restrict__ const pWti)
2329 {
2330 struct svar srcVal[3];
2331
2332 cnfexprEval(func->expr[0], &srcVal[0], usrptr, pWti);
2333 cnfexprEval(func->expr[1], &srcVal[1], usrptr, pWti);
2334 cnfexprEval(func->expr[2], &srcVal[2], usrptr, pWti);
2335 ret->d.estr = doFuncReplace(&srcVal[0], &srcVal[1], &srcVal[2]);
2336 ret->datatype = 'S';
2337 varFreeMembers(&srcVal[0]);
2338 varFreeMembers(&srcVal[1]);
2339 varFreeMembers(&srcVal[2]);
2340 }
2341
ATTR_NONNULL()2342 static void ATTR_NONNULL()
2343 doFunct_Wrap(struct cnffunc *__restrict__ const func,
2344 struct svar *__restrict__ const ret,
2345 void *__restrict__ const usrptr,
2346 wti_t *__restrict__ const pWti)
2347 {
2348 struct svar sourceVal;
2349 struct svar wrapperVal;
2350 struct svar escaperVal;
2351 int freeSource, freeWrapper;
2352 es_str_t *sourceStr;
2353
2354 cnfexprEval(func->expr[0], &sourceVal, usrptr, pWti);
2355 cnfexprEval(func->expr[1], &wrapperVal, usrptr, pWti);
2356 if(func->nParams == 3) {
2357 cnfexprEval(func->expr[2], &escaperVal, usrptr, pWti);
2358 sourceStr = doFuncReplace(&sourceVal, &wrapperVal, &escaperVal);
2359 freeSource = 1;
2360
2361 } else {
2362 sourceStr = var2String(&sourceVal, &freeSource);
2363 }
2364 es_str_t *wrapperStr = var2String(&wrapperVal, &freeWrapper);
2365 uchar *src = es_getBufAddr(sourceStr);
2366 uchar *wrapper = es_getBufAddr(wrapperStr);
2367 uint lWrapper = es_strlen(wrapperStr);
2368 uint lSrc = es_strlen(sourceStr);
2369 uint totalLen = lSrc + 2 * lWrapper;
2370 es_str_t *res = es_newStr(totalLen);
2371 uchar* resBuf = es_getBufAddr(res);
2372 memcpy(resBuf, wrapper, lWrapper);
2373 memcpy(resBuf + lWrapper, src, lSrc);
2374 memcpy(resBuf + lSrc + lWrapper, wrapper, lWrapper);
2375 res->lenStr = totalLen;
2376 if (freeSource) {
2377 es_deleteStr(sourceStr);
2378 }
2379 if (freeWrapper) {
2380 es_deleteStr(wrapperStr);
2381 }
2382
2383 ret->d.estr = res;
2384 ret->datatype = 'S';
2385 varFreeMembers(&sourceVal);
2386 varFreeMembers(&wrapperVal);
2387 if(func->nParams == 3) varFreeMembers(&escaperVal);
2388 }
2389
ATTR_NONNULL()2390 static void ATTR_NONNULL()
2391 doFunct_StrLen(struct cnffunc *__restrict__ const func,
2392 struct svar *__restrict__ const ret,
2393 void *__restrict__ const usrptr,
2394 wti_t *__restrict__ const pWti)
2395 {
2396 struct svar srcVal;
2397 int bMustFree;
2398 es_str_t *estr;
2399
2400 if(func->expr[0]->nodetype == 'S') {
2401 /* if we already have a string, we do not need to
2402 * do one more recursive call.
2403 */
2404 ret->d.n = es_strlen(((struct cnfstringval*) func->expr[0])->estr);
2405 } else {
2406 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2407 estr = var2String(&srcVal, &bMustFree);
2408 ret->d.n = es_strlen(estr);
2409 if(bMustFree) {
2410 es_deleteStr(estr);
2411 }
2412 varFreeMembers(&srcVal);
2413 }
2414 ret->datatype = 'N';
2415 }
2416
ATTR_NONNULL()2417 static void ATTR_NONNULL()
2418 doFunct_Substring(struct cnffunc *__restrict__ const func,
2419 struct svar *__restrict__ const ret,
2420 void *__restrict__ const usrptr,
2421 wti_t *__restrict__ const pWti)
2422 { //TODO: generalize parameter getter? jgerhards, 2018-02-26
2423 int bMustFree;
2424 struct svar srcVal[3];
2425
2426 cnfexprEval(func->expr[0], &srcVal[0], usrptr, pWti);
2427 cnfexprEval(func->expr[1], &srcVal[1], usrptr, pWti);
2428 cnfexprEval(func->expr[2], &srcVal[2], usrptr, pWti);
2429 es_str_t *es = var2String(&srcVal[0], &bMustFree);
2430 const int start = var2Number(&srcVal[1], NULL);
2431 const int subStrLen = var2Number(&srcVal[2], NULL);
2432
2433 ret->datatype = 'S';
2434 ret->d.estr = es_newStrFromSubStr(es, (es_size_t)start, (es_size_t)subStrLen);
2435 if(bMustFree) es_deleteStr(es);
2436 varFreeMembers(&srcVal[0]);
2437 varFreeMembers(&srcVal[1]);
2438 varFreeMembers(&srcVal[2]);
2439 }
2440
ATTR_NONNULL()2441 static void ATTR_NONNULL()
2442 doFunct_Field(struct cnffunc *__restrict__ const func,
2443 struct svar *__restrict__ const ret,
2444 void *__restrict__ const usrptr,
2445 wti_t *__restrict__ const pWti)
2446 {
2447 struct svar srcVal[3];
2448 int bMustFree;
2449 char *str;
2450 uchar *resStr;
2451 int matchnbr;
2452 int delim;
2453 rsRetVal localRet;
2454
2455 cnfexprEval(func->expr[0], &srcVal[0], usrptr, pWti);
2456 cnfexprEval(func->expr[1], &srcVal[1], usrptr, pWti);
2457 cnfexprEval(func->expr[2], &srcVal[2], usrptr, pWti);
2458 str = (char*) var2CString(&srcVal[0], &bMustFree);
2459 matchnbr = var2Number(&srcVal[2], NULL);
2460 if(srcVal[1].datatype == 'S') {
2461 char *delimstr;
2462 delimstr = (char*) es_str2cstr(srcVal[1].d.estr, NULL);
2463 localRet = doExtractFieldByStr((uchar*)str, delimstr, es_strlen(srcVal[1].d.estr),
2464 matchnbr, &resStr);
2465 free(delimstr);
2466 } else {
2467 delim = var2Number(&srcVal[1], NULL);
2468 localRet = doExtractFieldByChar((uchar*)str, (char) delim, matchnbr, &resStr);
2469 }
2470 if(localRet == RS_RET_OK) {
2471 ret->d.estr = es_newStrFromCStr((char*)resStr, strlen((char*)resStr));
2472 free(resStr);
2473 } else if(localRet == RS_RET_FIELD_NOT_FOUND) {
2474 ret->d.estr = es_newStrFromCStr("***FIELD NOT FOUND***",
2475 sizeof("***FIELD NOT FOUND***")-1);
2476 } else {
2477 ret->d.estr = es_newStrFromCStr("***ERROR in field() FUNCTION***",
2478 sizeof("***ERROR in field() FUNCTION***")-1);
2479 }
2480 ret->datatype = 'S';
2481 if(bMustFree) free(str);
2482 varFreeMembers(&srcVal[0]);
2483 varFreeMembers(&srcVal[1]);
2484 varFreeMembers(&srcVal[2]);
2485 }
2486
ATTR_NONNULL()2487 static void ATTR_NONNULL()
2488 doFunct_Prifilt(struct cnffunc *__restrict__ const func,
2489 struct svar *__restrict__ const ret,
2490 void *__restrict__ const usrptr,
2491 wti_t *const pWti __attribute__((unused)))
2492 {
2493 struct funcData_prifilt *pPrifilt;
2494
2495 pPrifilt = (struct funcData_prifilt*) func->funcdata;
2496 if( (pPrifilt->pmask[((smsg_t*)usrptr)->iFacility] == TABLE_NOPRI) ||
2497 ((pPrifilt->pmask[((smsg_t*)usrptr)->iFacility]
2498 & (1<<((smsg_t*)usrptr)->iSeverity)) == 0) )
2499 ret->d.n = 0;
2500 else
2501 ret->d.n = 1;
2502 ret->datatype = 'N';
2503 }
2504
ATTR_NONNULL()2505 static void ATTR_NONNULL()
2506 doFunct_Lookup(struct cnffunc *__restrict__ const func,
2507 struct svar *__restrict__ const ret,
2508 void *__restrict__ const usrptr,
2509 wti_t *__restrict__ const pWti)
2510 {
2511 struct svar srcVal;
2512 lookup_key_t key;
2513 uint8_t lookup_key_type;
2514 lookup_ref_t *lookup_table_ref;
2515 lookup_t *lookup_table;
2516 int bMustFree;
2517
2518 ret->datatype = 'S';
2519 if(func->funcdata == NULL) {
2520 ret->d.estr = es_newStrFromCStr("TABLE-NOT-FOUND", sizeof("TABLE-NOT-FOUND")-1);
2521 return;
2522 }
2523 cnfexprEval(func->expr[1], &srcVal, usrptr, pWti);
2524 lookup_table_ref = (lookup_ref_t*) func->funcdata;
2525 pthread_rwlock_rdlock(&lookup_table_ref->rwlock);
2526 lookup_table = lookup_table_ref->self;
2527 if (lookup_table != NULL) {
2528 lookup_key_type = lookup_table->key_type;
2529 bMustFree = 0;
2530 if (lookup_key_type == LOOKUP_KEY_TYPE_STRING) {
2531 key.k_str = (uchar*) var2CString(&srcVal, &bMustFree);
2532 } else if (lookup_key_type == LOOKUP_KEY_TYPE_UINT) {
2533 key.k_uint = var2Number(&srcVal, NULL);
2534 } else {
2535 DBGPRINTF("program error in %s:%d: lookup_key_type unknown\n",
2536 __FILE__, __LINE__);
2537 key.k_uint = 0;
2538 }
2539 ret->d.estr = lookupKey((lookup_ref_t*)func->funcdata, key);
2540 if(bMustFree) {
2541 free(key.k_str);
2542 }
2543 } else {
2544 ret->d.estr = es_newStrFromCStr("", 1);
2545 }
2546 pthread_rwlock_unlock(&lookup_table_ref->rwlock);
2547 varFreeMembers(&srcVal);
2548 }
2549
ATTR_NONNULL()2550 static void ATTR_NONNULL()
2551 doFunct_DynInc(struct cnffunc *__restrict__ const func,
2552 struct svar *__restrict__ const ret,
2553 void *__restrict__ const usrptr,
2554 wti_t *__restrict__ const pWti)
2555 {
2556 struct svar srcVal;
2557 int bMustFree;
2558 char *str;
2559
2560 ret->datatype = 'N';
2561 if(func->funcdata == NULL) {
2562 ret->d.n = -1;
2563 return;
2564 }
2565 cnfexprEval(func->expr[1], &srcVal, usrptr, pWti);
2566 str = (char*) var2CString(&srcVal, &bMustFree);
2567 ret->d.n = dynstats_inc(func->funcdata, (uchar*)str);
2568 if(bMustFree) free(str);
2569 varFreeMembers(&srcVal);
2570 }
2571
ATTR_NONNULL()2572 static void ATTR_NONNULL()
2573 doFunct_FormatTime(struct cnffunc *__restrict__ const func,
2574 struct svar *__restrict__ const ret,
2575 void *__restrict__ const usrptr,
2576 wti_t *__restrict__ const pWti)
2577 {
2578 struct svar srcVal[2];
2579 int bMustFree;
2580 char *str;
2581 int retval;
2582 long long unixtime;
2583 const int resMax = 64;
2584 char result[resMax];
2585 char *formatstr = NULL;
2586
2587 cnfexprEval(func->expr[0], &srcVal[0], usrptr, pWti);
2588 cnfexprEval(func->expr[1], &srcVal[1], usrptr, pWti);
2589
2590 unixtime = var2Number(&srcVal[0], &retval);
2591
2592 // Make sure that the timestamp we got can fit into
2593 // time_t on older systems.
2594 if (sizeof(time_t) == sizeof(int)) {
2595 if (unixtime < INT_MIN || unixtime > INT_MAX) {
2596 LogMsg(
2597 0, RS_RET_VAL_OUT_OF_RANGE, LOG_WARNING,
2598 "Timestamp value %lld is out of range for this system (time_t is "
2599 "32bits)!\n", unixtime
2600 );
2601 retval = 0;
2602 }
2603 }
2604
2605 // We want the string form too so we can return it as the
2606 // default if we run into problems parsing the number.
2607 str = (char*) var2CString(&srcVal[0], &bMustFree);
2608 formatstr = (char*) es_str2cstr(srcVal[1].d.estr, NULL);
2609
2610 ret->datatype = 'S';
2611
2612 if (objUse(datetime, CORE_COMPONENT) != RS_RET_OK) {
2613 ret->d.estr = es_newStr(0);
2614 } else {
2615 if (!retval || datetime.formatUnixTimeFromTime_t(unixtime, formatstr, result, resMax) == -1) {
2616 strncpy(result, str, resMax);
2617 result[resMax - 1] = '\0';
2618 }
2619 ret->d.estr = es_newStrFromCStr(result, strlen(result));
2620 }
2621
2622 if (bMustFree) {
2623 free(str);
2624 }
2625 free(formatstr);
2626
2627 varFreeMembers(&srcVal[0]);
2628 varFreeMembers(&srcVal[1]);
2629
2630 }
2631
2632 /*
2633 * Uses the given (current) year/month to decide which year
2634 * the incoming month likely belongs in.
2635 *
2636 * cy - Current Year (actual)
2637 * cm - Current Month (actual)
2638 * im - "Incoming" Month
2639 */
2640 static int
estimateYear(int cy,int cm,int im)2641 estimateYear(int cy, int cm, int im) {
2642 im += 12;
2643
2644 if ((im - cm) == 1) {
2645 if (cm == 12 && im == 13)
2646 return cy + 1;
2647 }
2648
2649 if ((im - cm) > 13)
2650 return cy - 1;
2651
2652 return cy;
2653 }
2654
ATTR_NONNULL()2655 static void ATTR_NONNULL()
2656 doFunct_ParseTime(struct cnffunc *__restrict__ const func,
2657 struct svar *__restrict__ const ret,
2658 void *__restrict__ const usrptr,
2659 wti_t *__restrict__ const pWti)
2660 {
2661 struct svar srcVal;
2662 int bMustFree;
2663 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2664 char *str = (char*) var2CString(&srcVal, &bMustFree);
2665 ret->datatype = 'N';
2666 ret->d.n = 0;
2667 wtiSetScriptErrno(pWti, RS_SCRIPT_EOK);
2668
2669 if (objUse(datetime, CORE_COMPONENT) == RS_RET_OK) {
2670 struct syslogTime s;
2671 int len = strlen(str);
2672 uchar *pszTS = (uchar*) str;
2673 memset(&s, 0, sizeof(struct syslogTime));
2674 // Attempt to parse the date/time string
2675 if (datetime.ParseTIMESTAMP3339(&s, (uchar**) &pszTS, &len) == RS_RET_OK) {
2676 ret->d.n = datetime.syslogTime2time_t(&s);
2677 DBGPRINTF("parse_time: RFC3339 format found\n");
2678 } else if (datetime.ParseTIMESTAMP3164(&s, (uchar**) &pszTS, &len,
2679 NO_PARSE3164_TZSTRING, NO_PERMIT_YEAR_AFTER_TIME) == RS_RET_OK) {
2680 time_t t = time(NULL);
2681 struct tm tm;
2682 gmtime_r(&t, &tm); // Get the current UTC date
2683 // Since properly formatted RFC 3164 timestamps do not have a YEAR
2684 // specified, we have to assume one that seems reasonable - SW.
2685 s.year = estimateYear(tm.tm_year + 1900, tm.tm_mon + 1, s.month);
2686 ret->d.n = datetime.syslogTime2time_t(&s);
2687 DBGPRINTF("parse_time: RFC3164 format found\n");
2688 } else {
2689 DBGPRINTF("parse_time: no valid format found\n");
2690 wtiSetScriptErrno(pWti, RS_SCRIPT_EINVAL);
2691 }
2692 }
2693
2694 if(bMustFree) {
2695 free(str);
2696 }
2697 varFreeMembers(&srcVal);
2698
2699 }
2700
2701 static int ATTR_NONNULL(1,3,4)
doFunc_is_time(const char * __restrict__ const str,const char * __restrict__ const fmt,struct svar * __restrict__ const r,wti_t * pWti)2702 doFunc_is_time(const char *__restrict__ const str,
2703 const char *__restrict__ const fmt,
2704 struct svar *__restrict__ const r,
2705 wti_t *pWti) {
2706
2707 assert(str != NULL);
2708 assert(r != NULL);
2709 assert(pWti != NULL);
2710
2711 int ret = 0;
2712
2713 wtiSetScriptErrno(pWti, RS_SCRIPT_EOK);
2714
2715 if (objUse(datetime, CORE_COMPONENT) == RS_RET_OK) {
2716 struct syslogTime s;
2717 int len = strlen(str);
2718 uchar *pszTS = (uchar*) str;
2719
2720 int numFormats = 3;
2721 dateTimeFormat_t formats[] = { DATE_RFC3164, DATE_RFC3339, DATE_UNIX };
2722 dateTimeFormat_t pf[] = { DATE_INVALID };
2723 dateTimeFormat_t *p = formats;
2724
2725 // Check if a format specifier was explicitly provided
2726 if (fmt != NULL) {
2727 numFormats = 1;
2728 *pf = getDateTimeFormatFromStr(fmt);
2729 p = pf;
2730 }
2731
2732 // Enumerate format specifier options, looking for the first match
2733 for (int i = 0; i < numFormats; i++) {
2734 dateTimeFormat_t f = p[i];
2735
2736 if (f == DATE_RFC3339) {
2737 if (datetime.ParseTIMESTAMP3339(&s, (uchar**) &pszTS, &len) == RS_RET_OK) {
2738 DBGPRINTF("is_time: RFC3339 format found.\n");
2739 ret = 1;
2740 break;
2741 }
2742 } else if (f == DATE_RFC3164) {
2743 if (datetime.ParseTIMESTAMP3164(&s, (uchar**) &pszTS, &len,
2744 NO_PARSE3164_TZSTRING, NO_PERMIT_YEAR_AFTER_TIME) == RS_RET_OK) {
2745 DBGPRINTF("is_time: RFC3164 format found.\n");
2746 ret = 1;
2747 break;
2748 }
2749 } else if (f == DATE_UNIX) {
2750 int result;
2751 var2Number(r, &result);
2752
2753 if (result) {
2754 DBGPRINTF("is_time: UNIX format found.\n");
2755 ret = 1;
2756 break;
2757 }
2758 } else {
2759 DBGPRINTF("is_time: %s is not a valid date/time format specifier!\n", fmt);
2760 break;
2761 }
2762 }
2763 }
2764
2765 // If not a valid date/time string, set 'errno'
2766 if (ret == 0) {
2767 DBGPRINTF("is_time: Invalid date-time string: %s.\n", str);
2768 wtiSetScriptErrno(pWti, RS_SCRIPT_EINVAL);
2769 }
2770
2771 return ret;
2772 }
2773
ATTR_NONNULL()2774 static void ATTR_NONNULL()
2775 doFunct_IsTime(struct cnffunc *__restrict__ const func,
2776 struct svar *__restrict__ const ret,
2777 void *__restrict__ const usrptr,
2778 wti_t *__restrict__ const pWti)
2779 {
2780 struct svar srcVal[2];
2781 int bMustFree;
2782 int bMustFree2;
2783 char *fmt = NULL;
2784
2785 cnfexprEval(func->expr[0], &srcVal[0], usrptr, pWti);
2786 char *str = (char*) var2CString(&srcVal[0], &bMustFree);
2787
2788 bMustFree2 = 0;
2789
2790 // Check if the optional 2nd parameter was provided
2791 if(func->nParams == 2) {
2792 cnfexprEval(func->expr[1], &srcVal[1], usrptr, pWti);
2793 fmt = (char*) var2CString(&srcVal[1], &bMustFree2);
2794 }
2795
2796 ret->datatype = 'N';
2797 ret->d.n = doFunc_is_time(str, fmt, &srcVal[0], pWti);
2798
2799 if(bMustFree) {
2800 free(str);
2801 }
2802 if(bMustFree2) {
2803 free(fmt);
2804 }
2805 varFreeMembers(&srcVal[0]);
2806 if(func->nParams == 2) {
2807 varFreeMembers(&srcVal[1]);
2808 }
2809 }
2810
ATTR_NONNULL()2811 static void ATTR_NONNULL()
2812 doFunct_ScriptError(struct cnffunc *const func __attribute__((unused)),
2813 struct svar *__restrict__ const ret,
2814 void *const usrptr __attribute__((unused)),
2815 wti_t *__restrict__ const pWti)
2816 {
2817 ret->datatype = 'N';
2818 ret->d.n = wtiGetScriptErrno(pWti);
2819 DBGPRINTF("script_error() is %d\n", (int) ret->d.n);
2820 }
2821
ATTR_NONNULL()2822 static void ATTR_NONNULL()
2823 doFunct_PreviousActionSuspended(struct cnffunc *const func __attribute__((unused)),
2824 struct svar *__restrict__ const ret,
2825 void *const usrptr __attribute__((unused)),
2826 wti_t *__restrict__ const pWti)
2827 {
2828 ret->datatype = 'N';
2829 ret->d.n = wtiGetPrevWasSuspended(pWti);
2830 DBGPRINTF("previous_action_suspended() is %d\n", (int) ret->d.n);
2831 }
2832
ATTR_NONNULL()2833 static void ATTR_NONNULL()
2834 doFunct_num2ipv4(struct cnffunc *__restrict__ const func,
2835 struct svar *__restrict__ const ret,
2836 void *__restrict__ const usrptr,
2837 wti_t *__restrict__ const pWti)
2838 {
2839 struct svar srcVal;
2840 cnfexprEval(func->expr[0], &srcVal, usrptr, pWti);
2841 int success = 0;
2842 long long num = var2Number(&srcVal, &success);
2843 varFreeMembers(&srcVal);
2844
2845 int numip[4];
2846 char str[16];
2847 size_t len;
2848 DBGPRINTF("rainrescript: (num2ipv4) var2Number output: '%lld\n'", num);
2849 if (! success) {
2850 DBGPRINTF("rainerscript: (num2ipv4) couldn't access number\n");
2851 len = snprintf(str, 16, "-1");
2852 goto done;
2853 }
2854 if(num < 0 || num > 4294967295) {
2855 DBGPRINTF("rainerscript: (num2ipv4) invalid number(too big/negative); does "
2856 "not represent IPv4 address\n");
2857 len = snprintf(str, 16, "-1");
2858 goto done;
2859 }
2860 for(int i = 0 ; i < 4 ; i++){
2861 numip[i] = num % 256;
2862 num = num / 256;
2863 }
2864 DBGPRINTF("rainerscript: (num2ipv4) Numbers: 1:'%d' 2:'%d' 3:'%d' 4:'%d'\n",
2865 numip[0], numip[1], numip[2], numip[3]);
2866 len = snprintf(str, 16, "%d.%d.%d.%d", numip[3], numip[2], numip[1], numip[0]);
2867 done:
2868 DBGPRINTF("rainerscript: (num2ipv4) ipv4-Address: %s, lengh: %zu\n", str, len);
2869 ret->d.estr = es_newStrFromCStr(str, len);
2870 ret->datatype = 'S';
2871 }
2872
2873
2874 /* Perform a function call. This has been moved out of cnfExprEval in order
2875 * to keep the code small and easier to maintain.
2876 */
ATTR_NONNULL()2877 static void ATTR_NONNULL()
2878 doFuncCall(struct cnffunc *__restrict__ const func, struct svar *__restrict__ const ret,
2879 void *__restrict__ const usrptr,
2880 wti_t *__restrict__ const pWti)
2881 {
2882
2883 if(Debug) {
2884 char *fname = es_str2cstr(func->fname, NULL);
2885 DBGPRINTF("rainerscript: executing function id %s\n", fname);
2886 free(fname);
2887 }
2888 if(func->fPtr == NULL) {
2889 char *fname = es_str2cstr(func->fname, NULL);
2890 LogError(0, RS_RET_INTERNAL_ERROR,
2891 "rainerscript: internal error: NULL pointer for function named '%s'\n",
2892 fname);
2893 free(fname);
2894 ret->datatype = 'N';
2895 ret->d.n = 0;
2896 } else {
2897 func->fPtr(func, ret, usrptr, pWti);
2898 }
2899 }
2900
2901
2902 /* Perform the special "exists()" function to check presence of a variable.
2903 */
ATTR_NONNULL()2904 static int ATTR_NONNULL()
2905 evalFuncExists(struct cnffuncexists *__restrict__ const fexists, void *__restrict__ const usrptr)
2906 {
2907 int r = 0;
2908 rsRetVal localRet;
2909
2910 if(fexists->prop.id == PROP_CEE ||
2911 fexists->prop.id == PROP_LOCAL_VAR ||
2912 fexists->prop.id == PROP_GLOBAL_VAR ) {
2913 localRet = msgCheckVarExists((smsg_t*)usrptr, &fexists->prop);
2914 if(localRet == RS_RET_OK) {
2915 r = 1;
2916 }
2917 }
2918
2919 return r;
2920 }
2921
2922 static void
evalVar(struct cnfvar * __restrict__ const var,void * __restrict__ const usrptr,struct svar * __restrict__ const ret)2923 evalVar(struct cnfvar *__restrict__ const var, void *__restrict__ const usrptr,
2924 struct svar *__restrict__ const ret)
2925 {
2926 rs_size_t propLen;
2927 uchar *pszProp = NULL;
2928 unsigned short bMustBeFreed = 0;
2929 rsRetVal localRet;
2930 struct json_object *json;
2931 uchar *cstr;
2932
2933 if(var->prop.id == PROP_CEE ||
2934 var->prop.id == PROP_LOCAL_VAR ||
2935 var->prop.id == PROP_GLOBAL_VAR ) {
2936 localRet = msgGetJSONPropJSONorString((smsg_t*)usrptr, &var->prop, &json, &cstr);
2937 if(json != NULL) {
2938 assert(cstr == NULL);
2939 ret->datatype = 'J';
2940 ret->d.json = (localRet == RS_RET_OK) ? json : NULL;
2941 DBGPRINTF("rainerscript: (json) var %d:%s: '%s'\n",
2942 var->prop.id, var->prop.name,
2943 (ret->d.json == NULL) ? "" : json_object_get_string(ret->d.json));
2944 } else { /* we have a string */
2945 DBGPRINTF("rainerscript: (json/string) var %d: '%s'\n", var->prop.id, cstr);
2946 ret->datatype = 'S';
2947 ret->d.estr = (localRet != RS_RET_OK || cstr == NULL) ?
2948 es_newStr(1)
2949 : es_newStrFromCStr((char*) cstr, strlen((char*) cstr));
2950 free(cstr);
2951 }
2952 } else {
2953 ret->datatype = 'S';
2954 pszProp = (uchar*) MsgGetProp((smsg_t*)usrptr, NULL, &var->prop, &propLen, &bMustBeFreed, NULL);
2955 ret->d.estr = es_newStrFromCStr((char*)pszProp, propLen);
2956 DBGPRINTF("rainerscript: (string) var %d: '%s'\n", var->prop.id, pszProp);
2957 if(bMustBeFreed)
2958 free(pszProp);
2959 }
2960
2961 }
2962
2963 /* perform a string comparision operation against a while array. Semantic is
2964 * that one one comparison is true, the whole construct is true.
2965 * TODO: we can obviously optimize this process. One idea is to
2966 * compile a regex, which should work faster than serial comparison.
2967 * Note: compiling a regex does NOT work at all. I experimented with that
2968 * and it was generally 5 to 10 times SLOWER than what we do here...
2969 */
2970 static int
evalStrArrayCmp(es_str_t * const estr_l,const struct cnfarray * __restrict__ const ar,const int cmpop)2971 evalStrArrayCmp(es_str_t *const estr_l,
2972 const struct cnfarray *__restrict__ const ar,
2973 const int cmpop)
2974 {
2975 int i;
2976 int r = 0;
2977 es_str_t **res;
2978 if(cmpop == CMP_EQ) {
2979 res = bsearch(&estr_l, ar->arr, ar->nmemb, sizeof(es_str_t*), qs_arrcmp);
2980 r = res != NULL;
2981 } else if(cmpop == CMP_NE) {
2982 res = bsearch(&estr_l, ar->arr, ar->nmemb, sizeof(es_str_t*), qs_arrcmp);
2983 r = res == NULL;
2984 } else {
2985 for(i = 0 ; (r == 0) && (i < ar->nmemb) ; ++i) {
2986 switch(cmpop) {
2987 case CMP_STARTSWITH:
2988 r = es_strncmp(estr_l, ar->arr[i], es_strlen(ar->arr[i])) == 0;
2989 break;
2990 case CMP_STARTSWITHI:
2991 r = es_strncasecmp(estr_l, ar->arr[i], es_strlen(ar->arr[i])) == 0;
2992 break;
2993 case CMP_CONTAINS:
2994 r = es_strContains(estr_l, ar->arr[i]) != -1;
2995 break;
2996 case CMP_CONTAINSI:
2997 r = es_strCaseContains(estr_l, ar->arr[i]) != -1;
2998 break;
2999 }
3000 }
3001 }
3002 return r;
3003 }
3004
3005 #define FREE_BOTH_RET \
3006 varFreeMembers(&r); \
3007 varFreeMembers(&l)
3008
3009 #define COMP_NUM_BINOP(x) \
3010 cnfexprEval(expr->l, &l, usrptr, pWti); \
3011 cnfexprEval(expr->r, &r, usrptr, pWti); \
3012 ret->datatype = 'N'; \
3013 ret->d.n = var2Number(&l, &convok_l) x var2Number(&r, &convok_r); \
3014 FREE_BOTH_RET
3015
3016 #define COMP_NUM_BINOP_DIV(x) \
3017 cnfexprEval(expr->l, &l, usrptr, pWti); \
3018 cnfexprEval(expr->r, &r, usrptr, pWti); \
3019 ret->datatype = 'N'; \
3020 if((ret->d.n = var2Number(&r, &convok_r)) == 0) { \
3021 /* division by zero */ \
3022 } else { \
3023 ret->d.n = var2Number(&l, &convok_l) x ret->d.n; \
3024 } \
3025 FREE_BOTH_RET
3026
3027 /* NOTE: array as right-hand argument MUST be handled by user */
3028 #define PREP_TWO_STRINGS \
3029 cnfexprEval(expr->l, &l, usrptr, pWti); \
3030 estr_l = var2String(&l, &bMustFree2); \
3031 if(expr->r->nodetype == 'S') { \
3032 estr_r = ((struct cnfstringval*)expr->r)->estr;\
3033 bMustFree = 0; \
3034 } else if(expr->r->nodetype != 'A') { \
3035 cnfexprEval(expr->r, &r, usrptr, pWti); \
3036 estr_r = var2String(&r, &bMustFree); \
3037 } else { \
3038 /* Note: this is not really necessary, but if we do not */ \
3039 /* do it, we get a very irritating compiler warning... */ \
3040 estr_r = NULL; \
3041 }
3042
3043 #define FREE_TWO_STRINGS \
3044 if(bMustFree) es_deleteStr(estr_r); \
3045 if(expr->r->nodetype != 'S' && expr->r->nodetype != 'A') varFreeMembers(&r); \
3046 if(bMustFree2) es_deleteStr(estr_l); \
3047 varFreeMembers(&l)
3048
3049 /* evaluate an expression.
3050 * Note that we try to avoid malloc whenever possible (because of
3051 * the large overhead it has, especially on highly threaded programs).
3052 * As such, the each caller level must provide buffer space for the
3053 * result on its stack during recursion. This permits the callee to store
3054 * the return value without malloc. As the value is a somewhat larger
3055 * struct, we could otherwise not return it without malloc.
3056 * Note that we implement boolean shortcut operations. For our needs, there
3057 * simply is no case where full evaluation would make any sense at all.
3058 */
ATTR_NONNULL()3059 void ATTR_NONNULL()
3060 cnfexprEval(const struct cnfexpr *__restrict__ const expr,
3061 struct svar *__restrict__ const ret,
3062 void *__restrict__ const usrptr,
3063 wti_t *__restrict__ const pWti)
3064 {
3065 struct svar r, l; /* memory for subexpression results */
3066 es_str_t *__restrict__ estr_r, *__restrict__ estr_l;
3067 int convok_r, convok_l;
3068 int bMustFree, bMustFree2;
3069 long long n_r, n_l;
3070
3071 DBGPRINTF("eval expr %p, type '%s'\n", expr, tokenToString(expr->nodetype));
3072 switch(expr->nodetype) {
3073 /* note: comparison operations are extremely similar. The code can be copyied, only
3074 * places flagged with "CMP" need to be changed.
3075 */
3076 case CMP_EQ:
3077 /* this is optimized in regard to right param as a PoC for all compOps
3078 * So this is a NOT yet the copy template!
3079 */
3080 cnfexprEval(expr->l, &l, usrptr, pWti);
3081 ret->datatype = 'N';
3082 if(l.datatype == 'S') {
3083 if(expr->r->nodetype == 'S') {
3084 ret->d.n = !es_strcmp(l.d.estr, ((struct cnfstringval*)expr->r)->estr); /*CMP*/
3085 } else if(expr->r->nodetype == 'A') {
3086 ret->d.n = evalStrArrayCmp(l.d.estr, (struct cnfarray*) expr->r, CMP_EQ);
3087 } else {
3088 cnfexprEval(expr->r, &r, usrptr, pWti);
3089 if(r.datatype == 'S') {
3090 ret->d.n = !es_strcmp(l.d.estr, r.d.estr); /*CMP*/
3091 } else {
3092 n_l = var2Number(&l, &convok_l);
3093 if(convok_l) {
3094 ret->d.n = (n_l == r.d.n); /*CMP*/
3095 } else {
3096 estr_r = var2String(&r, &bMustFree);
3097 ret->d.n = !es_strcmp(l.d.estr, estr_r); /*CMP*/
3098 if(bMustFree) es_deleteStr(estr_r);
3099 }
3100 }
3101 varFreeMembers(&r);
3102 }
3103 } else if(l.datatype == 'J') {
3104 estr_l = var2String(&l, &bMustFree);
3105 if(expr->r->nodetype == 'S') {
3106 ret->d.n = !es_strcmp(estr_l, ((struct cnfstringval*)expr->r)->estr); /*CMP*/
3107 } else if(expr->r->nodetype == 'A') {
3108 ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_EQ);
3109 } else {
3110 cnfexprEval(expr->r, &r, usrptr, pWti);
3111 if(r.datatype == 'S') {
3112 ret->d.n = !es_strcmp(estr_l, r.d.estr); /*CMP*/
3113 } else {
3114 n_l = var2Number(&l, &convok_l);
3115 if(convok_l) {
3116 ret->d.n = (n_l == r.d.n); /*CMP*/
3117 } else {
3118 estr_r = var2String(&r, &bMustFree2);
3119 ret->d.n = !es_strcmp(estr_l, estr_r); /*CMP*/
3120 if(bMustFree2) es_deleteStr(estr_r);
3121 }
3122 }
3123 varFreeMembers(&r);
3124 }
3125 if(bMustFree) es_deleteStr(estr_l);
3126 } else {
3127 cnfexprEval(expr->r, &r, usrptr, pWti);
3128 if(r.datatype == 'S') {
3129 n_r = var2Number(&r, &convok_r);
3130 if(convok_r) {
3131 ret->d.n = (l.d.n == n_r); /*CMP*/
3132 } else {
3133 estr_l = var2String(&l, &bMustFree);
3134 ret->d.n = !es_strcmp(r.d.estr, estr_l); /*CMP*/
3135 if(bMustFree) es_deleteStr(estr_l);
3136 }
3137 } else {
3138 ret->d.n = (l.d.n == r.d.n); /*CMP*/
3139 }
3140 varFreeMembers(&r);
3141 }
3142 varFreeMembers(&l);
3143 break;
3144 case CMP_NE:
3145 cnfexprEval(expr->l, &l, usrptr, pWti);
3146 cnfexprEval(expr->r, &r, usrptr, pWti);
3147 ret->datatype = 'N';
3148 if(l.datatype == 'S') {
3149 if(expr->r->nodetype == 'S') {
3150 ret->d.n = es_strcmp(l.d.estr, ((struct cnfstringval*)expr->r)->estr); /*CMP*/
3151 } else if(expr->r->nodetype == 'A') {
3152 ret->d.n = evalStrArrayCmp(l.d.estr, (struct cnfarray*) expr->r, CMP_NE);
3153 } else {
3154 if(r.datatype == 'S') {
3155 ret->d.n = es_strcmp(l.d.estr, r.d.estr); /*CMP*/
3156 } else {
3157 n_l = var2Number(&l, &convok_l);
3158 if(convok_l) {
3159 ret->d.n = (n_l != r.d.n); /*CMP*/
3160 } else {
3161 estr_r = var2String(&r, &bMustFree);
3162 ret->d.n = es_strcmp(l.d.estr, estr_r); /*CMP*/
3163 if(bMustFree) es_deleteStr(estr_r);
3164 }
3165 }
3166 }
3167 } else if(l.datatype == 'J') {
3168 estr_l = var2String(&l, &bMustFree);
3169 if(r.datatype == 'S') {
3170 ret->d.n = es_strcmp(estr_l, r.d.estr); /*CMP*/
3171 } else {
3172 n_l = var2Number(&l, &convok_l);
3173 if(convok_l) {
3174 ret->d.n = (n_l != r.d.n); /*CMP*/
3175 } else {
3176 estr_r = var2String(&r, &bMustFree2);
3177 ret->d.n = es_strcmp(estr_l, estr_r); /*CMP*/
3178 if(bMustFree2) es_deleteStr(estr_r);
3179 }
3180 }
3181 if(bMustFree) es_deleteStr(estr_l);
3182 } else {
3183 if(r.datatype == 'S') {
3184 n_r = var2Number(&r, &convok_r);
3185 if(convok_r) {
3186 ret->d.n = (l.d.n != n_r); /*CMP*/
3187 } else {
3188 estr_l = var2String(&l, &bMustFree);
3189 ret->d.n = es_strcmp(r.d.estr, estr_l); /*CMP*/
3190 if(bMustFree) es_deleteStr(estr_l);
3191 }
3192 } else {
3193 ret->d.n = (l.d.n != r.d.n); /*CMP*/
3194 }
3195 }
3196 FREE_BOTH_RET;
3197 break;
3198 case CMP_LE:
3199 cnfexprEval(expr->l, &l, usrptr, pWti);
3200 cnfexprEval(expr->r, &r, usrptr, pWti);
3201 ret->datatype = 'N';
3202 if(l.datatype == 'S') {
3203 if(r.datatype == 'S') {
3204 ret->d.n = es_strcmp(l.d.estr, r.d.estr) <= 0; /*CMP*/
3205 } else {
3206 n_l = var2Number(&l, &convok_l);
3207 if(convok_l) {
3208 ret->d.n = (n_l <= r.d.n); /*CMP*/
3209 } else {
3210 estr_r = var2String(&r, &bMustFree);
3211 ret->d.n = es_strcmp(l.d.estr, estr_r) <= 0; /*CMP*/
3212 if(bMustFree) es_deleteStr(estr_r);
3213 }
3214 }
3215 } else if(l.datatype == 'J') {
3216 estr_l = var2String(&l, &bMustFree);
3217 if(r.datatype == 'S') {
3218 ret->d.n = es_strcmp(estr_l, r.d.estr) <= 0; /*CMP*/
3219 } else {
3220 n_l = var2Number(&l, &convok_l);
3221 if(convok_l) {
3222 ret->d.n = (n_l <= r.d.n); /*CMP*/
3223 } else {
3224 estr_r = var2String(&r, &bMustFree2);
3225 ret->d.n = es_strcmp(estr_l, estr_r) <= 0; /*CMP*/
3226 if(bMustFree2) es_deleteStr(estr_r);
3227 }
3228 }
3229 if(bMustFree) es_deleteStr(estr_l);
3230 } else {
3231 if(r.datatype == 'S') {
3232 n_r = var2Number(&r, &convok_r);
3233 if(convok_r) {
3234 ret->d.n = (l.d.n <= n_r); /*CMP*/
3235 } else {
3236 estr_l = var2String(&l, &bMustFree);
3237 ret->d.n = es_strcmp(r.d.estr, estr_l) <= 0; /*CMP*/
3238 if(bMustFree) es_deleteStr(estr_l);
3239 }
3240 } else {
3241 ret->d.n = (l.d.n <= r.d.n); /*CMP*/
3242 }
3243 }
3244 FREE_BOTH_RET;
3245 break;
3246 case CMP_GE:
3247 cnfexprEval(expr->l, &l, usrptr, pWti);
3248 cnfexprEval(expr->r, &r, usrptr, pWti);
3249 ret->datatype = 'N';
3250 if(l.datatype == 'S') {
3251 if(r.datatype == 'S') {
3252 ret->d.n = es_strcmp(l.d.estr, r.d.estr) >= 0; /*CMP*/
3253 } else {
3254 n_l = var2Number(&l, &convok_l);
3255 if(convok_l) {
3256 ret->d.n = (n_l >= r.d.n); /*CMP*/
3257 } else {
3258 estr_r = var2String(&r, &bMustFree);
3259 ret->d.n = es_strcmp(l.d.estr, estr_r) >= 0; /*CMP*/
3260 if(bMustFree) es_deleteStr(estr_r);
3261 }
3262 }
3263 } else if(l.datatype == 'J') {
3264 estr_l = var2String(&l, &bMustFree);
3265 if(r.datatype == 'S') {
3266 ret->d.n = es_strcmp(estr_l, r.d.estr) >= 0; /*CMP*/
3267 } else {
3268 n_l = var2Number(&l, &convok_l);
3269 if(convok_l) {
3270 ret->d.n = (n_l >= r.d.n); /*CMP*/
3271 } else {
3272 estr_r = var2String(&r, &bMustFree2);
3273 ret->d.n = es_strcmp(estr_l, estr_r) >= 0; /*CMP*/
3274 if(bMustFree2) es_deleteStr(estr_r);
3275 }
3276 }
3277 if(bMustFree) es_deleteStr(estr_l);
3278 } else {
3279 if(r.datatype == 'S') {
3280 n_r = var2Number(&r, &convok_r);
3281 if(convok_r) {
3282 ret->d.n = (l.d.n >= n_r); /*CMP*/
3283 } else {
3284 estr_l = var2String(&l, &bMustFree);
3285 ret->d.n = es_strcmp(r.d.estr, estr_l) >= 0; /*CMP*/
3286 if(bMustFree) es_deleteStr(estr_l);
3287 }
3288 } else {
3289 ret->d.n = (l.d.n >= r.d.n); /*CMP*/
3290 }
3291 }
3292 FREE_BOTH_RET;
3293 break;
3294 case CMP_LT:
3295 cnfexprEval(expr->l, &l, usrptr, pWti);
3296 cnfexprEval(expr->r, &r, usrptr, pWti);
3297 ret->datatype = 'N';
3298 if(l.datatype == 'S') {
3299 if(r.datatype == 'S') {
3300 ret->d.n = es_strcmp(l.d.estr, r.d.estr) < 0; /*CMP*/
3301 } else {
3302 n_l = var2Number(&l, &convok_l);
3303 if(convok_l) {
3304 ret->d.n = (n_l < r.d.n); /*CMP*/
3305 } else {
3306 estr_r = var2String(&r, &bMustFree);
3307 ret->d.n = es_strcmp(l.d.estr, estr_r) < 0; /*CMP*/
3308 if(bMustFree) es_deleteStr(estr_r);
3309 }
3310 }
3311 } else if(l.datatype == 'J') {
3312 estr_l = var2String(&l, &bMustFree);
3313 if(r.datatype == 'S') {
3314 ret->d.n = es_strcmp(estr_l, r.d.estr) < 0; /*CMP*/
3315 } else {
3316 n_l = var2Number(&l, &convok_l);
3317 if(convok_l) {
3318 ret->d.n = (n_l < r.d.n); /*CMP*/
3319 } else {
3320 estr_r = var2String(&r, &bMustFree2);
3321 ret->d.n = es_strcmp(estr_l, estr_r) < 0; /*CMP*/
3322 if(bMustFree2) es_deleteStr(estr_r);
3323 }
3324 }
3325 if(bMustFree) es_deleteStr(estr_l);
3326 } else {
3327 if(r.datatype == 'S') {
3328 n_r = var2Number(&r, &convok_r);
3329 if(convok_r) {
3330 ret->d.n = (l.d.n < n_r); /*CMP*/
3331 } else {
3332 estr_l = var2String(&l, &bMustFree);
3333 ret->d.n = es_strcmp(r.d.estr, estr_l) < 0; /*CMP*/
3334 if(bMustFree) es_deleteStr(estr_l);
3335 }
3336 } else {
3337 ret->d.n = (l.d.n < r.d.n); /*CMP*/
3338 }
3339 }
3340 FREE_BOTH_RET;
3341 break;
3342 case CMP_GT:
3343 cnfexprEval(expr->l, &l, usrptr, pWti);
3344 cnfexprEval(expr->r, &r, usrptr, pWti);
3345 ret->datatype = 'N';
3346 if(l.datatype == 'S') {
3347 if(r.datatype == 'S') {
3348 ret->d.n = es_strcmp(l.d.estr, r.d.estr) > 0; /*CMP*/
3349 } else {
3350 n_l = var2Number(&l, &convok_l);
3351 if(convok_l) {
3352 ret->d.n = (n_l > r.d.n); /*CMP*/
3353 } else {
3354 estr_r = var2String(&r, &bMustFree);
3355 ret->d.n = es_strcmp(l.d.estr, estr_r) > 0; /*CMP*/
3356 if(bMustFree) es_deleteStr(estr_r);
3357 }
3358 }
3359 } else if(l.datatype == 'J') {
3360 estr_l = var2String(&l, &bMustFree);
3361 if(r.datatype == 'S') {
3362 ret->d.n = es_strcmp(estr_l, r.d.estr) > 0; /*CMP*/
3363 } else {
3364 n_l = var2Number(&l, &convok_l);
3365 if(convok_l) {
3366 ret->d.n = (n_l > r.d.n); /*CMP*/
3367 } else {
3368 estr_r = var2String(&r, &bMustFree2);
3369 ret->d.n = es_strcmp(estr_l, estr_r) > 0; /*CMP*/
3370 if(bMustFree2) es_deleteStr(estr_r);
3371 }
3372 }
3373 if(bMustFree) es_deleteStr(estr_l);
3374 } else {
3375 if(r.datatype == 'S') {
3376 n_r = var2Number(&r, &convok_r);
3377 if(convok_r) {
3378 ret->d.n = (l.d.n > n_r); /*CMP*/
3379 } else {
3380 estr_l = var2String(&l, &bMustFree);
3381 ret->d.n = es_strcmp(r.d.estr, estr_l) > 0; /*CMP*/
3382 if(bMustFree) es_deleteStr(estr_l);
3383 }
3384 } else {
3385 ret->d.n = (l.d.n > r.d.n); /*CMP*/
3386 }
3387 }
3388 FREE_BOTH_RET;
3389 break;
3390 case CMP_STARTSWITH:
3391 PREP_TWO_STRINGS;
3392 ret->datatype = 'N';
3393 if(expr->r->nodetype == 'A') {
3394 ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_STARTSWITH);
3395 bMustFree = 0;
3396 } else {
3397 ret->d.n = es_strncmp(estr_l, estr_r, estr_r->lenStr) == 0;
3398 }
3399 FREE_TWO_STRINGS;
3400 break;
3401 case CMP_STARTSWITHI:
3402 PREP_TWO_STRINGS;
3403 ret->datatype = 'N';
3404 if(expr->r->nodetype == 'A') {
3405 ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_STARTSWITHI);
3406 bMustFree = 0;
3407 } else {
3408 ret->d.n = es_strncasecmp(estr_l, estr_r, estr_r->lenStr) == 0;
3409 }
3410 FREE_TWO_STRINGS;
3411 break;
3412 case CMP_CONTAINS:
3413 PREP_TWO_STRINGS;
3414 ret->datatype = 'N';
3415 if(expr->r->nodetype == 'A') {
3416 ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_CONTAINS);
3417 bMustFree = 0;
3418 } else {
3419 ret->d.n = es_strContains(estr_l, estr_r) != -1;
3420 }
3421 FREE_TWO_STRINGS;
3422 break;
3423 case CMP_CONTAINSI:
3424 PREP_TWO_STRINGS;
3425 ret->datatype = 'N';
3426 if(expr->r->nodetype == 'A') {
3427 ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_CONTAINSI);
3428 bMustFree = 0;
3429 } else {
3430 ret->d.n = es_strCaseContains(estr_l, estr_r) != -1;
3431 }
3432 FREE_TWO_STRINGS;
3433 break;
3434 case OR:
3435 cnfexprEval(expr->l, &l, usrptr, pWti);
3436 ret->datatype = 'N';
3437 if(var2Number(&l, &convok_l)) {
3438 ret->d.n = 1ll;
3439 } else {
3440 cnfexprEval(expr->r, &r, usrptr, pWti);
3441 if(var2Number(&r, &convok_r))
3442 ret->d.n = 1ll;
3443 else
3444 ret->d.n = 0ll;
3445 varFreeMembers(&r);
3446 }
3447 varFreeMembers(&l);
3448 break;
3449 case AND:
3450 cnfexprEval(expr->l, &l, usrptr, pWti);
3451 ret->datatype = 'N';
3452 if(var2Number(&l, &convok_l)) {
3453 cnfexprEval(expr->r, &r, usrptr, pWti);
3454 if(var2Number(&r, &convok_r))
3455 ret->d.n = 1ll;
3456 else
3457 ret->d.n = 0ll;
3458 varFreeMembers(&r);
3459 } else {
3460 ret->d.n = 0ll;
3461 }
3462 varFreeMembers(&l);
3463 break;
3464 case NOT:
3465 cnfexprEval(expr->r, &r, usrptr, pWti);
3466 ret->datatype = 'N';
3467 ret->d.n = !var2Number(&r, &convok_r);
3468 varFreeMembers(&r);
3469 break;
3470 case 'N':
3471 ret->datatype = 'N';
3472 ret->d.n = ((struct cnfnumval*)expr)->val;
3473 break;
3474 case 'S':
3475 ret->datatype = 'S';
3476 ret->d.estr = es_strdup(((struct cnfstringval*)expr)->estr);
3477 break;
3478 case 'A':
3479 /* if an array is used with "normal" operations, it just evaluates
3480 * to its first element.
3481 */
3482 ret->datatype = 'S';
3483 ret->d.estr = es_strdup(((struct cnfarray*)expr)->arr[0]);
3484 break;
3485 case 'V':
3486 evalVar((struct cnfvar*)expr, usrptr, ret);
3487 break;
3488 case '&':
3489 /* TODO: think about optimization, should be possible ;) */
3490 PREP_TWO_STRINGS;
3491 if(expr->r->nodetype == 'A') {
3492 estr_r = ((struct cnfarray*)expr->r)->arr[0];
3493 bMustFree = 0;
3494 }
3495 ret->datatype = 'S';
3496 ret->d.estr = es_strdup(estr_l);
3497 es_addStr(&ret->d.estr, estr_r);
3498 FREE_TWO_STRINGS;
3499 break;
3500 case '+':
3501 COMP_NUM_BINOP(+);
3502 break;
3503 case '-':
3504 COMP_NUM_BINOP(-);
3505 break;
3506 case '*':
3507 COMP_NUM_BINOP(*);
3508 break;
3509 case '/':
3510 COMP_NUM_BINOP_DIV(/);
3511 break;
3512 case '%':
3513 COMP_NUM_BINOP_DIV(%);
3514 break;
3515 case 'M':
3516 cnfexprEval(expr->r, &r, usrptr, pWti);
3517 ret->datatype = 'N';
3518 ret->d.n = -var2Number(&r, &convok_r);
3519 varFreeMembers(&r);
3520 break;
3521 case 'F':
3522 doFuncCall((struct cnffunc*) expr, ret, usrptr, pWti);
3523 break;
3524 case S_FUNC_EXISTS:
3525 ret->datatype = 'N';
3526 ret->d.n = evalFuncExists((struct cnffuncexists*) expr, usrptr);
3527 break;
3528 default:
3529 ret->datatype = 'N';
3530 ret->d.n = 0ll;
3531 DBGPRINTF("eval error: unknown nodetype %u['%c']\n",
3532 (unsigned) expr->nodetype, (char) expr->nodetype);
3533 assert(0); /* abort on debug builds, this must not happen! */
3534 break;
3535 }
3536 DBGPRINTF("eval expr %p, return datatype '%c':%d\n", expr, ret->datatype,
3537 (ret->datatype == 'N') ? (int)ret->d.n: 0);
3538 }
3539
3540 //---------------------------------------------------------
3541
3542 void
cnfarrayContentDestruct(struct cnfarray * ar)3543 cnfarrayContentDestruct(struct cnfarray *ar)
3544 {
3545 unsigned short i;
3546 for(i = 0 ; i < ar->nmemb ; ++i) {
3547 es_deleteStr(ar->arr[i]);
3548 }
3549 free(ar->arr);
3550 }
3551
3552 static void
regex_destruct(struct cnffunc * func)3553 regex_destruct(struct cnffunc *func) {
3554 if(func->funcdata != NULL) {
3555 regexp.regfree(func->funcdata);
3556 }
3557 }
3558
3559 static rsRetVal
initFunc_dyn_stats(struct cnffunc * func)3560 initFunc_dyn_stats(struct cnffunc *func)
3561 {
3562 uchar *cstr = NULL;
3563 DEFiRet;
3564
3565 func->destructable_funcdata = 0;
3566
3567 if(func->nParams != 2) {
3568 parser_errmsg("rsyslog logic error in line %d of file %s\n",
3569 __LINE__, __FILE__);
3570 FINALIZE;
3571 }
3572
3573 func->funcdata = NULL;
3574 if(func->expr[0]->nodetype != 'S') {
3575 parser_errmsg("dyn-stats bucket-name (param 1) of dyn-stats manipulating "
3576 "functions like dyn_inc must be a constant string");
3577 FINALIZE;
3578 }
3579
3580 cstr = (uchar*)es_str2cstr(((struct cnfstringval*) func->expr[0])->estr, NULL);
3581 if((func->funcdata = dynstats_findBucket(cstr)) == NULL) {
3582 parser_errmsg("dyn-stats bucket '%s' not found", cstr);
3583 FINALIZE;
3584 }
3585
3586 finalize_it:
3587 free(cstr);
3588 RETiRet;
3589 }
3590
3591 static rsRetVal
initFunc_perctile_obs(struct cnffunc * func)3592 initFunc_perctile_obs(struct cnffunc *func)
3593 {
3594 uchar *cstr = NULL;
3595 DEFiRet;
3596
3597 func->destructable_funcdata = 0;
3598 if (func->nParams != 3) {
3599 parser_errmsg("rsyslog logic error in line %d of file %s\n",
3600 __LINE__, __FILE__);
3601 FINALIZE;
3602 }
3603
3604 func->funcdata = NULL;
3605 if (func->expr[0]->nodetype != 'S') {
3606 parser_errmsg("percentile-stats bucket-name (param 1) of perctile-stats manipulating "
3607 "functions like percentile_observe must be a constant string");
3608 FINALIZE;
3609 }
3610
3611 cstr = (uchar*) es_str2cstr(((struct cnfstringval*) func->expr[0])->estr, NULL);
3612 if ( (func->funcdata = perctile_findBucket(cstr)) == NULL) {
3613 parser_errmsg("perctile-stats bucket '%s' not found", cstr);
3614 FINALIZE;
3615 }
3616
3617 finalize_it:
3618 free(cstr);
3619 RETiRet;
3620 }
3621
ATTR_NONNULL()3622 static void ATTR_NONNULL()
3623 doFunc_percentile_obs(struct cnffunc *__restrict__ const func,
3624 struct svar *__restrict__ const ret,
3625 void *__restrict__ const usrptr,
3626 wti_t *__restrict__ const pWti)
3627 {
3628 uchar *cstr = NULL;
3629 struct svar srcVal;
3630 int bMustFree;
3631
3632 ret->datatype = 'N';
3633 if(func->funcdata == NULL) {
3634 ret->d.n = -1;
3635 return;
3636 }
3637
3638 cnfexprEval(func->expr[1], &srcVal, usrptr, pWti);
3639 cstr = (uchar*) var2CString(&srcVal, &bMustFree);
3640
3641 int success = 0;
3642 struct svar srcVal2;
3643 long long retVal;
3644 cnfexprEval(func->expr[2], &srcVal2, usrptr, pWti);
3645 long long val = var2Number(&srcVal2, &success);
3646 if (!success) {
3647 char *cstr2 = es_str2cstr(srcVal2.d.estr, NULL);
3648 parser_errmsg("rainerscript: percentile_obs - didn't get a valid number: %s\n", cstr2);
3649 free(cstr2);
3650 retVal = 0;
3651 FINALIZE;
3652 }
3653
3654 retVal = perctile_obs(func->funcdata, cstr, val);
3655
3656 finalize_it:
3657 if (bMustFree) {
3658 free(cstr);
3659 }
3660 varFreeMembers(&srcVal);
3661 varFreeMembers(&srcVal2);
3662 ret->d.n = retVal;
3663 ret->datatype = 'N';
3664 }
3665
3666 static rsRetVal
initFunc_re_match_generic(struct cnffunc * const func,const unsigned flags)3667 initFunc_re_match_generic(struct cnffunc *const func, const unsigned flags)
3668 {
3669 rsRetVal localRet;
3670 char *regex = NULL;
3671 regex_t *re;
3672 DEFiRet;
3673
3674 if(func->nParams < 2) {
3675 parser_errmsg("rsyslog logic error in line %d of file %s\n",
3676 __LINE__, __FILE__);
3677 FINALIZE;
3678 }
3679
3680 func->funcdata = NULL;
3681 if(func->expr[1]->nodetype != 'S') {
3682 parser_errmsg("param 2 of re_match/extract() must be a constant string");
3683 FINALIZE;
3684 }
3685
3686 CHKmalloc(re = malloc(sizeof(regex_t)));
3687 func->funcdata = re;
3688
3689 regex = es_str2cstr(((struct cnfstringval*) func->expr[1])->estr, NULL);
3690
3691 if((localRet = objUse(regexp, LM_REGEXP_FILENAME)) == RS_RET_OK) {
3692 int errcode;
3693 if((errcode = regexp.regcomp(re, (char*) regex, REG_EXTENDED | flags)) != 0) {
3694 char errbuff[512];
3695 regexp.regerror(errcode, re, errbuff, sizeof(errbuff));
3696 parser_errmsg("cannot compile regex '%s': %s", regex, errbuff);
3697 ABORT_FINALIZE(RS_RET_ERR);
3698 }
3699 } else { /* regexp object could not be loaded */
3700 parser_errmsg("could not load regex support - regex ignored");
3701 ABORT_FINALIZE(localRet);
3702 }
3703
3704 finalize_it:
3705 free(regex);
3706 RETiRet;
3707 }
3708
3709 static rsRetVal
initFunc_re_match(struct cnffunc * func)3710 initFunc_re_match(struct cnffunc *func)
3711 {
3712 return initFunc_re_match_generic(func, 0);
3713 }
3714
3715 static rsRetVal
initFunc_re_match_i(struct cnffunc * func)3716 initFunc_re_match_i(struct cnffunc *func)
3717 {
3718 return initFunc_re_match_generic(func, REG_ICASE);
3719 }
3720
3721 static rsRetVal
initFunc_exec_template(struct cnffunc * func)3722 initFunc_exec_template(struct cnffunc *func)
3723 {
3724 char *tplName = NULL;
3725 DEFiRet;
3726
3727 func->destructable_funcdata = 0;
3728
3729 if(func->nParams != 1) {
3730 parser_errmsg("rsyslog logic error in line %d of file %s\n",
3731 __LINE__, __FILE__);
3732 FINALIZE;
3733 }
3734
3735 if(func->expr[0]->nodetype != 'S') {
3736 parser_errmsg("exec_template(): param 1 must be a constant string");
3737 FINALIZE;
3738 }
3739
3740 tplName = es_str2cstr(((struct cnfstringval*) func->expr[0])->estr, NULL);
3741 func->funcdata = tplFind(ourConf, tplName, strlen(tplName));
3742 if(func->funcdata == NULL) {
3743 parser_errmsg("exec_template(): template '%s' could not be found", tplName);
3744 FINALIZE;
3745 }
3746
3747
3748 finalize_it:
3749 free(tplName);
3750 RETiRet;
3751 }
3752
3753 static rsRetVal
initFunc_prifilt(struct cnffunc * func)3754 initFunc_prifilt(struct cnffunc *func)
3755 {
3756 struct funcData_prifilt *pData;
3757 uchar *cstr;
3758 DEFiRet;
3759
3760 if(func->nParams != 1) {
3761 parser_errmsg("rsyslog logic error in line %d of file %s\n",
3762 __LINE__, __FILE__);
3763 FINALIZE;
3764 }
3765
3766 func->funcdata = NULL;
3767 if(func->expr[0]->nodetype != 'S') {
3768 parser_errmsg("param 1 of prifilt() must be a constant string");
3769 FINALIZE;
3770 }
3771
3772 CHKmalloc(pData = calloc(1, sizeof(struct funcData_prifilt)));
3773 func->funcdata = pData;
3774 cstr = (uchar*)es_str2cstr(((struct cnfstringval*) func->expr[0])->estr, NULL);
3775 CHKiRet(DecodePRIFilter(cstr, pData->pmask));
3776 free(cstr);
3777 finalize_it:
3778 RETiRet;
3779 }
3780
3781 static rsRetVal
resolveLookupTable(struct cnffunc * func)3782 resolveLookupTable(struct cnffunc *func)
3783 {
3784 uchar *cstr = NULL;
3785 char *fn_name = NULL;
3786 DEFiRet;
3787
3788 func->destructable_funcdata = 0;
3789
3790 if(func->nParams == 0) {/*we assume first arg is lookup-table-name*/
3791 parser_errmsg("rsyslog logic error in line %d of file %s\n",
3792 __LINE__, __FILE__);
3793 FINALIZE;
3794 }
3795
3796 CHKmalloc(fn_name = es_str2cstr(func->fname, NULL));
3797
3798 func->funcdata = NULL;
3799 if(func->expr[0]->nodetype != 'S') {
3800 parser_errmsg("table name (param 1) of %s() must be a constant string", fn_name);
3801 FINALIZE;
3802 }
3803
3804 CHKmalloc(cstr = (uchar*)es_str2cstr(((struct cnfstringval*) func->expr[0])->estr, NULL));
3805 if((func->funcdata = lookupFindTable(cstr)) == NULL) {
3806 parser_errmsg("lookup table '%s' not found (used in function: %s)", cstr, fn_name);
3807 FINALIZE;
3808 }
3809
3810 finalize_it:
3811 free(cstr);
3812 free(fn_name);
3813 RETiRet;
3814 }
3815
3816 struct modListNode {
3817 int version;
3818 struct scriptFunct *modFcts;
3819 struct modListNode *next;
3820 };
3821
3822 static struct modListNode *modListRoot = NULL;
3823 static struct modListNode *modListLast = NULL;
3824
3825 static struct scriptFunct functions[] = {
3826 {"strlen", 1, 1, doFunct_StrLen, NULL, NULL},
3827 {"getenv", 1, 1, doFunct_Getenv, NULL, NULL},
3828 {"num2ipv4", 1, 1, doFunct_num2ipv4, NULL, NULL},
3829 {"int2hex", 1, 1, doFunct_Int2Hex, NULL, NULL},
3830 {"substring", 3, 3, doFunct_Substring, NULL, NULL},
3831 {"ltrim", 1, 1, doFunct_LTrim, NULL, NULL},
3832 {"rtrim", 1, 1, doFunct_RTrim, NULL, NULL},
3833 {"tolower", 1, 1, doFunct_ToLower, NULL, NULL},
3834 {"cstr", 1, 1, doFunct_CStr, NULL, NULL},
3835 {"cnum", 1, 1, doFunct_CNum, NULL, NULL},
3836 {"ip42num", 1, 1, doFunct_Ipv42num, NULL, NULL},
3837 {"ipv42num", 1, 1, doFunct_Ipv42num, NULL, NULL},
3838 {"re_match", 2, 2, doFunct_ReMatch, initFunc_re_match, regex_destruct},
3839 {"re_match_i", 2, 2, doFunct_ReMatch, initFunc_re_match_i, regex_destruct},
3840 {"re_extract", 5, 5, doFunc_re_extract, initFunc_re_match, regex_destruct},
3841 {"re_extract_i", 5, 5, doFunc_re_extract, initFunc_re_match_i, regex_destruct},
3842 {"field", 3, 3, doFunct_Field, NULL, NULL},
3843 {"exec_template", 1, 1, doFunc_exec_template, initFunc_exec_template, NULL},
3844 {"prifilt", 1, 1, doFunct_Prifilt, initFunc_prifilt, NULL},
3845 {"lookup", 2, 2, doFunct_Lookup, resolveLookupTable, NULL},
3846 {"dyn_inc", 2, 2, doFunct_DynInc, initFunc_dyn_stats, NULL},
3847 {"percentile_observe", 3, 3, doFunc_percentile_obs, initFunc_perctile_obs, NULL},
3848 {"replace", 3, 3, doFunct_Replace, NULL, NULL},
3849 {"wrap", 2, 3, doFunct_Wrap, NULL, NULL},
3850 {"random", 1, 1, doFunct_RandomGen, NULL, NULL},
3851 {"format_time", 2, 2, doFunct_FormatTime, NULL, NULL},
3852 {"parse_time", 1, 1, doFunct_ParseTime, NULL, NULL},
3853 {"is_time", 1, 2, doFunct_IsTime, NULL, NULL},
3854 {"parse_json", 2, 2, doFunc_parse_json, NULL, NULL},
3855 {"get_property", 2, 2, doFunc_get_property, NULL, NULL},
3856 {"script_error", 0, 0, doFunct_ScriptError, NULL, NULL},
3857 {"previous_action_suspended", 0, 0, doFunct_PreviousActionSuspended, NULL, NULL},
3858 {NULL, 0, 0, NULL, NULL, NULL} //last element to check end of array
3859 };
3860
ATTR_NONNULL()3861 static rscriptFuncPtr ATTR_NONNULL()
3862 extractFuncPtr(const struct scriptFunct *const funct, const unsigned int nParams)
3863 {
3864 rscriptFuncPtr retPtr = NULL;
3865
3866 if(funct->minParams == funct->maxParams) {
3867 if(nParams == funct->maxParams) {
3868 retPtr = funct->fPtr;
3869 } else {
3870 parser_errmsg("number of parameters for %s() must be %hu but is %d.",
3871 funct->fname, funct->maxParams, nParams);
3872 }
3873 } else {
3874 if(nParams < funct->minParams) {
3875 parser_errmsg("number of parameters for %s() must be at least %hu but is %d.",
3876 funct->fname, funct->minParams, nParams);
3877 } else if(nParams > funct->maxParams) {
3878 parser_errmsg("number of parameters for %s() must be at most %hu but is %d.",
3879 funct->fname, funct->maxParams, nParams);
3880 } else {
3881 retPtr = funct->fPtr;
3882 }
3883 }
3884
3885 return retPtr;
3886 }
3887
ATTR_NONNULL()3888 static struct scriptFunct* ATTR_NONNULL()
3889 searchFunctArray(const char *const fname, struct scriptFunct *functArray)
3890 {
3891 struct scriptFunct *retPtr = NULL;
3892 int i = 0;
3893 while(functArray[i].fname != NULL) {
3894 if(!strcmp(fname, functArray[i].fname)){
3895 retPtr = functArray + i;
3896 goto done;
3897 }
3898 i++;
3899 }
3900 done:
3901 return retPtr;
3902 }
3903
ATTR_NONNULL()3904 static struct scriptFunct* ATTR_NONNULL()
3905 searchModList(const char *const fname)
3906 {
3907 struct modListNode *modListCurr = modListRoot;
3908 struct scriptFunct *foundFunct;
3909
3910 do {
3911 foundFunct = searchFunctArray(fname, modListCurr->modFcts);
3912 if(foundFunct != NULL) {
3913 return foundFunct;
3914 }
3915 modListCurr = modListCurr->next;
3916 } while(modListCurr != NULL);
3917 return NULL;
3918 }
3919
3920 static void
cnffuncDestruct(struct cnffunc * func)3921 cnffuncDestruct(struct cnffunc *func)
3922 {
3923 unsigned short i;
3924
3925 for(i = 0 ; i < func->nParams ; ++i) {
3926 cnfexprDestruct(func->expr[i]);
3927 }
3928
3929 /* some functions require special destruction */
3930 char *cstr = es_str2cstr(func->fname, NULL);
3931 struct scriptFunct *foundFunc = searchModList(cstr);
3932 free(cstr);
3933 if(foundFunc->destruct != NULL) {
3934 foundFunc->destruct(func);
3935 }
3936
3937 if(func->destructable_funcdata) {
3938 free(func->funcdata);
3939 }
3940 free(func->fname);
3941 }
3942
3943 /* Destruct an expression and all sub-expressions contained in it.
3944 */
3945 void
cnfexprDestruct(struct cnfexpr * __restrict__ const expr)3946 cnfexprDestruct(struct cnfexpr *__restrict__ const expr)
3947 {
3948
3949 if(expr == NULL) {
3950 /* this is valid and can happen during optimizer run! */
3951 DBGPRINTF("cnfexprDestruct got NULL ptr - valid, so doing nothing\n");
3952 return;
3953 }
3954
3955 DBGPRINTF("cnfexprDestruct expr %p, type '%s'\n", expr, tokenToString(expr->nodetype));
3956 switch(expr->nodetype) {
3957 case CMP_NE:
3958 case CMP_EQ:
3959 case CMP_LE:
3960 case CMP_GE:
3961 case CMP_LT:
3962 case CMP_GT:
3963 case CMP_STARTSWITH:
3964 case CMP_STARTSWITHI:
3965 case CMP_CONTAINS:
3966 case CMP_CONTAINSI:
3967 case OR:
3968 case AND:
3969 case '&':
3970 case '+':
3971 case '-':
3972 case '*':
3973 case '/':
3974 case '%': /* binary */
3975 cnfexprDestruct(expr->l);
3976 cnfexprDestruct(expr->r);
3977 break;
3978 case NOT:
3979 case 'M': /* unary */
3980 cnfexprDestruct(expr->r);
3981 break;
3982 case 'N':
3983 break;
3984 case 'S':
3985 es_deleteStr(((struct cnfstringval*)expr)->estr);
3986 break;
3987 case 'V':
3988 free(((struct cnfvar*)expr)->name);
3989 msgPropDescrDestruct(&(((struct cnfvar*)expr)->prop));
3990 break;
3991 case 'F':
3992 cnffuncDestruct((struct cnffunc*)expr);
3993 break;
3994 case 'A':
3995 cnfarrayContentDestruct((struct cnfarray*)expr);
3996 break;
3997 default:break;
3998 }
3999 free(expr);
4000 }
4001
4002 //---- END
4003
4004
4005 /* Evaluate an expression as a bool. This is added because expressions are
4006 * mostly used inside filters, and so this function is quite common and
4007 * important.
4008 */
4009 int
cnfexprEvalBool(struct cnfexpr * __restrict__ const expr,void * __restrict__ const usrptr,wti_t * const pWti)4010 cnfexprEvalBool(struct cnfexpr *__restrict__ const expr, void *__restrict__ const usrptr, wti_t *const pWti)
4011 {
4012 int convok;
4013 struct svar ret;
4014 cnfexprEval(expr, &ret, usrptr, pWti);
4015 int retVal = var2Number(&ret, &convok);
4016 varFreeMembers(&ret);
4017 return retVal;
4018 }
4019
4020 struct json_object*
cnfexprEvalCollection(struct cnfexpr * __restrict__ const expr,void * __restrict__ const usrptr,wti_t * const pWti)4021 cnfexprEvalCollection(struct cnfexpr *__restrict__ const expr, void *__restrict__ const usrptr, wti_t *const pWti)
4022 {
4023 struct svar ret;
4024 void *retptr;
4025 cnfexprEval(expr, &ret, usrptr, pWti);
4026 if(ret.datatype == 'J') {
4027 retptr = ret.d.json; /*caller is supposed to free the returned json-object*/
4028 } else {
4029 retptr = NULL;
4030 varFreeMembers(&ret); /* we must free the element */
4031 }
4032 return retptr;
4033 }
4034
4035 static void
doIndent(int indent)4036 doIndent(int indent)
4037 {
4038 int i;
4039 for(i = 0 ; i < indent ; ++i)
4040 dbgprintf(" ");
4041 }
4042
4043 static void
pmaskPrint(uchar * pmask,int indent)4044 pmaskPrint(uchar *pmask, int indent)
4045 {
4046 int i;
4047 doIndent(indent);
4048 dbgprintf("pmask: ");
4049 for (i = 0; i <= LOG_NFACILITIES; i++)
4050 if (pmask[i] == TABLE_NOPRI)
4051 dbgprintf(" X ");
4052 else
4053 dbgprintf("%2X ", pmask[i]);
4054 dbgprintf("\n");
4055 }
4056
4057 static void
cnfarrayPrint(struct cnfarray * ar,int indent)4058 cnfarrayPrint(struct cnfarray *ar, int indent)
4059 {
4060 int i;
4061 doIndent(indent); dbgprintf("ARRAY:\n");
4062 for(i = 0 ; i < ar->nmemb ; ++i) {
4063 doIndent(indent+1);
4064 cstrPrint("string '", ar->arr[i]);
4065 dbgprintf("'\n");
4066 }
4067 }
4068
4069 void
cnfexprPrint(struct cnfexpr * expr,int indent)4070 cnfexprPrint(struct cnfexpr *expr, int indent)
4071 {
4072 struct cnffunc *func;
4073 char *fname;
4074 int i;
4075
4076 switch(expr->nodetype) {
4077 case CMP_EQ:
4078 cnfexprPrint(expr->l, indent+1);
4079 doIndent(indent);
4080 dbgprintf("==\n");
4081 cnfexprPrint(expr->r, indent+1);
4082 break;
4083 case CMP_NE:
4084 cnfexprPrint(expr->l, indent+1);
4085 doIndent(indent);
4086 dbgprintf("!=\n");
4087 cnfexprPrint(expr->r, indent+1);
4088 break;
4089 case CMP_LE:
4090 cnfexprPrint(expr->l, indent+1);
4091 doIndent(indent);
4092 dbgprintf("<=\n");
4093 cnfexprPrint(expr->r, indent+1);
4094 break;
4095 case CMP_GE:
4096 cnfexprPrint(expr->l, indent+1);
4097 doIndent(indent);
4098 dbgprintf(">=\n");
4099 cnfexprPrint(expr->r, indent+1);
4100 break;
4101 case CMP_LT:
4102 cnfexprPrint(expr->l, indent+1);
4103 doIndent(indent);
4104 dbgprintf("<\n");
4105 cnfexprPrint(expr->r, indent+1);
4106 break;
4107 case CMP_GT:
4108 cnfexprPrint(expr->l, indent+1);
4109 doIndent(indent);
4110 dbgprintf(">\n");
4111 cnfexprPrint(expr->r, indent+1);
4112 break;
4113 case CMP_CONTAINS:
4114 cnfexprPrint(expr->l, indent+1);
4115 doIndent(indent);
4116 dbgprintf("CONTAINS\n");
4117 cnfexprPrint(expr->r, indent+1);
4118 break;
4119 case CMP_CONTAINSI:
4120 cnfexprPrint(expr->l, indent+1);
4121 doIndent(indent);
4122 dbgprintf("CONTAINS_I\n");
4123 cnfexprPrint(expr->r, indent+1);
4124 break;
4125 case CMP_STARTSWITH:
4126 cnfexprPrint(expr->l, indent+1);
4127 doIndent(indent);
4128 dbgprintf("STARTSWITH\n");
4129 cnfexprPrint(expr->r, indent+1);
4130 break;
4131 case CMP_STARTSWITHI:
4132 cnfexprPrint(expr->l, indent+1);
4133 doIndent(indent);
4134 dbgprintf("STARTSWITH_I\n");
4135 cnfexprPrint(expr->r, indent+1);
4136 break;
4137 case OR:
4138 cnfexprPrint(expr->l, indent+1);
4139 doIndent(indent);
4140 dbgprintf("OR\n");
4141 cnfexprPrint(expr->r, indent+1);
4142 break;
4143 case AND:
4144 cnfexprPrint(expr->l, indent+1);
4145 doIndent(indent);
4146 dbgprintf("AND\n");
4147 cnfexprPrint(expr->r, indent+1);
4148 break;
4149 case NOT:
4150 doIndent(indent);
4151 dbgprintf("NOT\n");
4152 cnfexprPrint(expr->r, indent+1);
4153 break;
4154 case S_FUNC_EXISTS:
4155 doIndent(indent);
4156 dbgprintf("exists(%s)\n", ((struct cnffuncexists*)expr)->varname);
4157 break;
4158 case 'S':
4159 doIndent(indent);
4160 cstrPrint("string '", ((struct cnfstringval*)expr)->estr);
4161 dbgprintf("'\n");
4162 break;
4163 case 'A':
4164 cnfarrayPrint((struct cnfarray*)expr, indent);
4165 break;
4166 case 'N':
4167 doIndent(indent);
4168 dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val);
4169 break;
4170 case 'V':
4171 doIndent(indent);
4172 dbgprintf("var '%s'\n", ((struct cnfvar*)expr)->name);
4173 break;
4174 case 'F':
4175 doIndent(indent);
4176 func = (struct cnffunc*) expr;
4177 cstrPrint("function '", func->fname);
4178 fname = es_str2cstr(func->fname, NULL);
4179 dbgprintf("' (name:%s, params:%hu)\n", fname, func->nParams);
4180 free(fname);
4181 if(func->fPtr == doFunct_Prifilt) {
4182 struct funcData_prifilt *pD;
4183 pD = (struct funcData_prifilt*) func->funcdata;
4184 pmaskPrint(pD->pmask, indent+1);
4185 }
4186 for(i = 0 ; i < func->nParams ; ++i) {
4187 cnfexprPrint(func->expr[i], indent+1);
4188 }
4189 break;
4190 case '&':
4191 case '+':
4192 case '-':
4193 case '*':
4194 case '/':
4195 case '%':
4196 case 'M':
4197 if(expr->l != NULL)
4198 cnfexprPrint(expr->l, indent+1);
4199 doIndent(indent);
4200 dbgprintf("%c\n", (char) expr->nodetype);
4201 cnfexprPrint(expr->r, indent+1);
4202 break;
4203 default:
4204 dbgprintf("error: unknown nodetype %u['%c']\n",
4205 (unsigned) expr->nodetype, (char) expr->nodetype);
4206 assert(0); /* abort on debug builds, this must not happen! */
4207 break;
4208 }
4209 }
4210
4211 /* print only the given stmt
4212 * if "subtree" equals 1, the full statement subtree is printed, else
4213 * really only the statement.
4214 */
4215 void
cnfstmtPrintOnly(struct cnfstmt * stmt,int indent,sbool subtree)4216 cnfstmtPrintOnly(struct cnfstmt *stmt, int indent, sbool subtree)
4217 {
4218 char *cstr;
4219 switch(stmt->nodetype) {
4220 case S_NOP:
4221 doIndent(indent); dbgprintf("NOP\n");
4222 break;
4223 case S_STOP:
4224 doIndent(indent); dbgprintf("STOP\n");
4225 break;
4226 case S_CALL:
4227 cstr = es_str2cstr(stmt->d.s_call.name, NULL);
4228 doIndent(indent); dbgprintf("CALL [%s, queue:%d]\n", cstr,
4229 stmt->d.s_call.ruleset == NULL ? 0 : 1);
4230 free(cstr);
4231 break;
4232 case S_CALL_INDIRECT:
4233 doIndent(indent); dbgprintf("CALL_INDIRECT\n");
4234 cnfexprPrint(stmt->d.s_call_ind.expr, indent+1);
4235 break;
4236 case S_ACT:
4237 doIndent(indent); dbgprintf("ACTION %d [%s:%s]\n", stmt->d.act->iActionNbr,
4238 modGetName(stmt->d.act->pMod), stmt->printable);
4239 break;
4240 case S_IF:
4241 doIndent(indent); dbgprintf("IF\n");
4242 cnfexprPrint(stmt->d.s_if.expr, indent+1);
4243 if(subtree) {
4244 doIndent(indent); dbgprintf("THEN\n");
4245 cnfstmtPrint(stmt->d.s_if.t_then, indent+1);
4246 if(stmt->d.s_if.t_else != NULL) {
4247 doIndent(indent); dbgprintf("ELSE\n");
4248 cnfstmtPrint(stmt->d.s_if.t_else, indent+1);
4249 }
4250 doIndent(indent); dbgprintf("END IF\n");
4251 }
4252 break;
4253 case S_FOREACH:
4254 doIndent(indent); dbgprintf("FOREACH %s IN\n", stmt->d.s_foreach.iter->var);
4255 cnfexprPrint(stmt->d.s_foreach.iter->collection, indent+1);
4256 if(subtree) {
4257 doIndent(indent); dbgprintf("DO\n");
4258 cnfstmtPrint(stmt->d.s_foreach.body, indent+1);
4259 doIndent(indent); dbgprintf("END FOREACH\n");
4260 }
4261 break;
4262 case S_SET:
4263 doIndent(indent); dbgprintf("SET %s =\n",
4264 stmt->d.s_set.varname);
4265 cnfexprPrint(stmt->d.s_set.expr, indent+1);
4266 doIndent(indent); dbgprintf("END SET\n");
4267 break;
4268 case S_UNSET:
4269 doIndent(indent); dbgprintf("UNSET %s\n",
4270 stmt->d.s_unset.varname);
4271 break;
4272 case S_RELOAD_LOOKUP_TABLE:
4273 doIndent(indent);
4274 dbgprintf("RELOAD_LOOKUP_TABLE table(%s) (stub with '%s' on error)",
4275 stmt->d.s_reload_lookup_table.table_name,
4276 stmt->d.s_reload_lookup_table.stub_value);
4277 break;
4278 case S_PRIFILT:
4279 doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable);
4280 pmaskPrint(stmt->d.s_prifilt.pmask, indent);
4281 if(subtree) {
4282 cnfstmtPrint(stmt->d.s_prifilt.t_then, indent+1);
4283 if(stmt->d.s_prifilt.t_else != NULL) {
4284 doIndent(indent); dbgprintf("ELSE\n");
4285 cnfstmtPrint(stmt->d.s_prifilt.t_else, indent+1);
4286 }
4287 doIndent(indent); dbgprintf("END PRIFILT\n");
4288 }
4289 break;
4290 case S_PROPFILT:
4291 doIndent(indent); dbgprintf("PROPFILT\n");
4292 doIndent(indent); dbgprintf("\tProperty.: '%s'\n",
4293 propIDToName(stmt->d.s_propfilt.prop.id));
4294 if(stmt->d.s_propfilt.prop.id == PROP_CEE ||
4295 stmt->d.s_propfilt.prop.id == PROP_LOCAL_VAR ||
4296 stmt->d.s_propfilt.prop.id == PROP_GLOBAL_VAR) {
4297 doIndent(indent);
4298 dbgprintf("\tCEE-Prop.: '%s'\n", stmt->d.s_propfilt.prop.name);
4299 }
4300 doIndent(indent); dbgprintf("\tOperation: ");
4301 if(stmt->d.s_propfilt.isNegated)
4302 dbgprintf("NOT ");
4303 dbgprintf("'%s'\n", getFIOPName(stmt->d.s_propfilt.operation));
4304 if(stmt->d.s_propfilt.pCSCompValue != NULL) {
4305 doIndent(indent); dbgprintf("\tValue....: '%s'\n",
4306 rsCStrGetSzStrNoNULL(stmt->d.s_propfilt.pCSCompValue));
4307 }
4308 if(subtree) {
4309 doIndent(indent); dbgprintf("THEN\n");
4310 cnfstmtPrint(stmt->d.s_propfilt.t_then, indent+1);
4311 doIndent(indent); dbgprintf("END PROPFILT\n");
4312 }
4313 break;
4314 default:
4315 dbgprintf("error: unknown stmt type %u\n",
4316 (unsigned) stmt->nodetype);
4317 break;
4318 }
4319 }
4320 void
cnfstmtPrint(struct cnfstmt * root,int indent)4321 cnfstmtPrint(struct cnfstmt *root, int indent)
4322 {
4323 struct cnfstmt *stmt;
4324 for(stmt = root ; stmt != NULL ; stmt = stmt->next) {
4325 cnfstmtPrintOnly(stmt, indent, 1);
4326 }
4327 }
4328
4329 struct cnfnumval*
cnfnumvalNew(const long long val)4330 cnfnumvalNew(const long long val)
4331 {
4332 struct cnfnumval *numval;
4333 if((numval = malloc(sizeof(struct cnfnumval))) != NULL) {
4334 numval->nodetype = 'N';
4335 numval->val = val;
4336 }
4337 return numval;
4338 }
4339
4340 struct cnfstringval*
cnfstringvalNew(es_str_t * const estr)4341 cnfstringvalNew(es_str_t *const estr)
4342 {
4343 struct cnfstringval *strval;
4344 if((strval = malloc(sizeof(struct cnfstringval))) != NULL) {
4345 strval->nodetype = 'S';
4346 strval->estr = estr;
4347 }
4348 return strval;
4349 }
4350
4351 /* creates array AND adds first element to it */
4352 struct cnfarray*
cnfarrayNew(es_str_t * val)4353 cnfarrayNew(es_str_t *val)
4354 {
4355 struct cnfarray *ar;
4356 if((ar = malloc(sizeof(struct cnfarray))) != NULL) {
4357 ar->nodetype = 'A';
4358 ar->nmemb = 1;
4359 if((ar->arr = malloc(sizeof(es_str_t*))) == NULL) {
4360 free(ar);
4361 ar = NULL;
4362 goto done;
4363 }
4364 ar->arr[0] = val;
4365 }
4366 done: return ar;
4367 }
4368
4369 struct cnfarray*
cnfarrayAdd(struct cnfarray * __restrict__ const ar,es_str_t * __restrict__ val)4370 cnfarrayAdd(struct cnfarray *__restrict__ const ar, es_str_t *__restrict__ val)
4371 {
4372 es_str_t **newptr;
4373 if((newptr = realloc(ar->arr, (ar->nmemb+1)*sizeof(es_str_t*))) == NULL) {
4374 DBGPRINTF("cnfarrayAdd: realloc failed, item ignored, ar->arr=%p\n", ar->arr);
4375 goto done;
4376 } else {
4377 ar->arr = newptr;
4378 ar->arr[ar->nmemb] = val;
4379 ar->nmemb++;
4380 }
4381 done: return ar;
4382 }
4383
4384 /* duplicate an array (deep copy) */
4385 struct cnfarray*
cnfarrayDup(struct cnfarray * old)4386 cnfarrayDup(struct cnfarray *old)
4387 {
4388 int i;
4389 struct cnfarray *ar;
4390 ar = cnfarrayNew(es_strdup(old->arr[0]));
4391 for(i = 1 ; i < old->nmemb ; ++i) {
4392 cnfarrayAdd(ar, es_strdup(old->arr[i]));
4393 }
4394 return ar;
4395 }
4396
4397 struct cnfvar*
cnfvarNew(char * name)4398 cnfvarNew(char *name)
4399 {
4400 struct cnfvar *var;
4401 if((var = malloc(sizeof(struct cnfvar))) != NULL) {
4402 var->nodetype = 'V';
4403 var->name = name;
4404 msgPropDescrFill(&var->prop, (uchar*)var->name, strlen(var->name));
4405 }
4406 return var;
4407 }
4408
4409 struct cnfstmt *
cnfstmtNew(unsigned s_type)4410 cnfstmtNew(unsigned s_type)
4411 {
4412 struct cnfstmt* cnfstmt;
4413 if((cnfstmt = malloc(sizeof(struct cnfstmt))) != NULL) {
4414 cnfstmt->nodetype = s_type;
4415 cnfstmt->printable = NULL;
4416 cnfstmt->next = NULL;
4417 }
4418 return cnfstmt;
4419 }
4420
4421 /* This function disables a cnfstmt by setting it to NOP. This is
4422 * useful when we detect errors late in the parsing processing, where
4423 * we need to return a valid cnfstmt. The optimizer later removes the
4424 * NOPs, so all is well.
4425 * NOTE: this call assumes that no dynamic data structures have been
4426 * allocated. If so, these MUST be freed before calling cnfstmtDisable().
4427 */
4428 static void
cnfstmtDisable(struct cnfstmt * cnfstmt)4429 cnfstmtDisable(struct cnfstmt *cnfstmt)
4430 {
4431 cnfstmt->nodetype = S_NOP;
4432 }
4433
4434 void cnfstmtDestructLst(struct cnfstmt *root);
4435
4436 static void cnfIteratorDestruct(struct cnfitr *itr);
4437
4438 /* delete a single stmt */
4439 static void
cnfstmtDestruct(struct cnfstmt * stmt)4440 cnfstmtDestruct(struct cnfstmt *stmt)
4441 {
4442 switch(stmt->nodetype) {
4443 case S_NOP:
4444 case S_STOP:
4445 break;
4446 case S_CALL:
4447 es_deleteStr(stmt->d.s_call.name);
4448 break;
4449 case S_CALL_INDIRECT:
4450 cnfexprDestruct(stmt->d.s_call_ind.expr);
4451 break;
4452 case S_ACT:
4453 actionDestruct(stmt->d.act);
4454 break;
4455 case S_IF:
4456 cnfexprDestruct(stmt->d.s_if.expr);
4457 if(stmt->d.s_if.t_then != NULL) {
4458 cnfstmtDestructLst(stmt->d.s_if.t_then);
4459 }
4460 if(stmt->d.s_if.t_else != NULL) {
4461 cnfstmtDestructLst(stmt->d.s_if.t_else);
4462 }
4463 break;
4464 case S_FOREACH:
4465 cnfIteratorDestruct(stmt->d.s_foreach.iter);
4466 cnfstmtDestructLst(stmt->d.s_foreach.body);
4467 break;
4468 case S_SET:
4469 free(stmt->d.s_set.varname);
4470 cnfexprDestruct(stmt->d.s_set.expr);
4471 break;
4472 case S_UNSET:
4473 free(stmt->d.s_set.varname);
4474 break;
4475 case S_PRIFILT:
4476 cnfstmtDestructLst(stmt->d.s_prifilt.t_then);
4477 cnfstmtDestructLst(stmt->d.s_prifilt.t_else);
4478 break;
4479 case S_PROPFILT:
4480 msgPropDescrDestruct(&stmt->d.s_propfilt.prop);
4481 if(stmt->d.s_propfilt.regex_cache != NULL)
4482 rsCStrRegexDestruct(&stmt->d.s_propfilt.regex_cache);
4483 if(stmt->d.s_propfilt.pCSCompValue != NULL)
4484 cstrDestruct(&stmt->d.s_propfilt.pCSCompValue);
4485 cnfstmtDestructLst(stmt->d.s_propfilt.t_then);
4486 break;
4487 case S_RELOAD_LOOKUP_TABLE:
4488 if (stmt->d.s_reload_lookup_table.table_name != NULL) {
4489 free(stmt->d.s_reload_lookup_table.table_name);
4490 }
4491 if (stmt->d.s_reload_lookup_table.stub_value != NULL) {
4492 free(stmt->d.s_reload_lookup_table.stub_value);
4493 }
4494 break;
4495 default:
4496 DBGPRINTF("error: unknown stmt type during destruct %u\n",
4497 (unsigned) stmt->nodetype);
4498 break;
4499 }
4500 free(stmt->printable);
4501 free(stmt);
4502 }
4503
4504 /* delete a stmt and all others following it */
4505 void
cnfstmtDestructLst(struct cnfstmt * root)4506 cnfstmtDestructLst(struct cnfstmt *root)
4507 {
4508 struct cnfstmt *stmt, *todel;
4509 for(stmt = root ; stmt != NULL ; ) {
4510 todel = stmt;
4511 stmt = stmt->next;
4512 cnfstmtDestruct(todel);
4513 }
4514 }
4515
4516 struct cnfitr *
cnfNewIterator(char * var,struct cnfexpr * collection)4517 cnfNewIterator(char *var, struct cnfexpr *collection)
4518 {
4519 struct cnfitr* itr;
4520 if ((itr = malloc(sizeof(struct cnfitr))) != NULL) {
4521 itr->var = var;
4522 itr->collection = collection;
4523 }
4524 return itr;
4525 }
4526
4527 static void
cnfIteratorDestruct(struct cnfitr * itr)4528 cnfIteratorDestruct(struct cnfitr *itr)
4529 {
4530 free(itr->var);
4531 if(itr->collection != NULL)
4532 cnfexprDestruct(itr->collection);
4533 free(itr);
4534 }
4535
4536 struct cnfstmt *
cnfstmtNewSet(char * var,struct cnfexpr * expr,int force_reset)4537 cnfstmtNewSet(char *var, struct cnfexpr *expr, int force_reset)
4538 {
4539 propid_t propid;
4540 struct cnfstmt* cnfstmt;
4541 if((cnfstmt = cnfstmtNew(S_SET)) != NULL) {
4542 if(propNameToID((uchar *)var, &propid) == RS_RET_OK
4543 && ( propid == PROP_CEE
4544 || propid == PROP_LOCAL_VAR
4545 || propid == PROP_GLOBAL_VAR)
4546 ) {
4547 cnfstmt->d.s_set.varname = (uchar*) var;
4548 cnfstmt->d.s_set.expr = expr;
4549 cnfstmt->d.s_set.force_reset = force_reset;
4550 } else {
4551 parser_errmsg("invalid variable '%s' in set statement.", var);
4552 free(var);
4553 cnfstmtDisable(cnfstmt);
4554 }
4555 }
4556 return cnfstmt;
4557 }
4558
4559 struct cnfstmt *
cnfstmtNewCall(es_str_t * name)4560 cnfstmtNewCall(es_str_t *name)
4561 {
4562 struct cnfstmt* cnfstmt;
4563 if((cnfstmt = cnfstmtNew(S_CALL)) != NULL) {
4564 cnfstmt->d.s_call.name = name;
4565 cnfstmt->d.s_call.ruleset = NULL;
4566 }
4567 return cnfstmt;
4568 }
4569
4570 struct cnfstmt *
cnfstmtNewReloadLookupTable(struct cnffparamlst * fparams)4571 cnfstmtNewReloadLookupTable(struct cnffparamlst *fparams)
4572 {
4573 int nParams;
4574 struct cnffparamlst *param, *nxt;
4575 struct cnfstmt* cnfstmt;
4576 uint8_t failed = 0;
4577 if((cnfstmt = cnfstmtNew(S_RELOAD_LOOKUP_TABLE)) != NULL) {
4578 nParams = 0;
4579 for(param = fparams ; param != NULL ; param = param->next) {
4580 ++nParams;
4581 }
4582 cnfstmt->d.s_reload_lookup_table.table_name = cnfstmt->d.s_reload_lookup_table.stub_value = NULL;
4583 switch(nParams) {
4584 case 2:
4585 param = fparams->next;
4586 if (param->expr->nodetype != 'S') {
4587 parser_errmsg("statement ignored: reload_lookup_table(table_name, "
4588 "optional:stub_value_in_case_reload_fails) "
4589 "expects a litteral string for second argument\n");
4590 failed = 1;
4591 }
4592 if ((cnfstmt->d.s_reload_lookup_table.stub_value =
4593 (uchar*) es_str2cstr(((struct cnfstringval*)param->expr)->estr, NULL)) == NULL) {
4594 parser_errmsg("statement ignored: reload_lookup_table statement "
4595 "failed to allocate memory for lookup-table stub-value\n");
4596 failed = 1;
4597 }
4598 CASE_FALLTHROUGH
4599 case 1:
4600 param = fparams;
4601 if (param->expr->nodetype != 'S') {
4602 parser_errmsg("statement ignored: reload_lookup_table(table_name, "
4603 "optional:stub_value_in_case_reload_fails) "
4604 "expects a litteral string for first argument\n");
4605 failed = 1;
4606 }
4607 if ((cnfstmt->d.s_reload_lookup_table.table_name =
4608 (uchar*) es_str2cstr(((struct cnfstringval*)param->expr)->estr, NULL)) == NULL) {
4609 parser_errmsg("statement ignored: reload_lookup_table statement "
4610 "failed to allocate memory for lookup-table name\n");
4611 failed = 1;
4612 }
4613 break;
4614 default:
4615 parser_errmsg("statement ignored: reload_lookup_table(table_name, optional:"
4616 "stub_value_in_case_reload_fails) "
4617 "expected 1 or 2 arguments, but found '%d'\n", nParams);
4618 failed = 1;
4619 }
4620 }
4621 param = fparams;
4622 while(param != NULL) {
4623 nxt = param->next;
4624 if (param->expr != NULL) cnfexprDestruct(param->expr);
4625 free(param);
4626 param = nxt;
4627 }
4628 if (failed) {
4629 cnfstmt->nodetype = S_NOP;
4630 if (cnfstmt->d.s_reload_lookup_table.table_name != NULL) {
4631 free(cnfstmt->d.s_reload_lookup_table.table_name);
4632 }
4633 if (cnfstmt->d.s_reload_lookup_table.stub_value != NULL) {
4634 free(cnfstmt->d.s_reload_lookup_table.stub_value);
4635 }
4636 }
4637 return cnfstmt;
4638 }
4639
4640 struct cnfstmt *
cnfstmtNewUnset(char * var)4641 cnfstmtNewUnset(char *var)
4642 {
4643 propid_t propid;
4644 struct cnfstmt* cnfstmt;
4645 if((cnfstmt = cnfstmtNew(S_UNSET)) != NULL) {
4646 if(propNameToID((uchar *)var, &propid) == RS_RET_OK
4647 && ( propid == PROP_CEE
4648 || propid == PROP_LOCAL_VAR
4649 || propid == PROP_GLOBAL_VAR)
4650 ) {
4651 cnfstmt->d.s_unset.varname = (uchar*) var;
4652 } else {
4653 parser_errmsg("invalid variable '%s' in unset statement.", var);
4654 free(var);
4655 cnfstmtDisable(cnfstmt);
4656 }
4657 }
4658 return cnfstmt;
4659 }
4660
4661 struct cnfstmt *
cnfstmtNewContinue(void)4662 cnfstmtNewContinue(void)
4663 {
4664 return cnfstmtNew(S_NOP);
4665 }
4666
4667 struct cnfstmt *
cnfstmtNewPRIFILT(char * prifilt,struct cnfstmt * t_then)4668 cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then)
4669 {
4670 struct cnfstmt* cnfstmt;
4671 if((cnfstmt = cnfstmtNew(S_PRIFILT)) != NULL) {
4672 cnfstmt->printable = (uchar*)prifilt;
4673 cnfstmt->d.s_prifilt.t_then = t_then;
4674 cnfstmt->d.s_prifilt.t_else = NULL;
4675 DecodePRIFilter((uchar*)prifilt, cnfstmt->d.s_prifilt.pmask);
4676 }
4677 return cnfstmt;
4678 }
4679
4680 struct cnfstmt *
cnfstmtNewPROPFILT(char * propfilt,struct cnfstmt * t_then)4681 cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then)
4682 {
4683 struct cnfstmt* cnfstmt;
4684 if((cnfstmt = cnfstmtNew(S_PROPFILT)) != NULL) {
4685 cnfstmt->printable = (uchar*)propfilt;
4686 cnfstmt->d.s_propfilt.t_then = t_then;
4687 cnfstmt->d.s_propfilt.regex_cache = NULL;
4688 cnfstmt->d.s_propfilt.pCSCompValue = NULL;
4689 if(DecodePropFilter((uchar*)propfilt, cnfstmt) != RS_RET_OK) {
4690 cnfstmt->nodetype = S_NOP; /* disable action! */
4691 cnfstmtDestructLst(t_then); /* we do no longer need this */
4692 }
4693 }
4694 return cnfstmt;
4695 }
4696
4697 struct cnfstmt *
cnfstmtNewAct(struct nvlst * lst)4698 cnfstmtNewAct(struct nvlst *lst)
4699 {
4700 struct cnfstmt* cnfstmt;
4701 char namebuf[256];
4702 rsRetVal localRet;
4703 if((cnfstmt = cnfstmtNew(S_ACT)) == NULL) {
4704 goto done;
4705 }
4706 if (nvlstChkDisabled(lst)) {
4707 dbgprintf("action disabled by configuration\n");
4708 cnfstmt->nodetype = S_NOP;
4709 }
4710 localRet = actionNewInst(lst, &cnfstmt->d.act);
4711 if(localRet == RS_RET_OK_WARN) {
4712 parser_errmsg("warnings occured in file '%s' around line %d",
4713 cnfcurrfn, yylineno);
4714 } else if(localRet != RS_RET_OK) {
4715 parser_errmsg("errors occured in file '%s' around line %d",
4716 cnfcurrfn, yylineno);
4717 cnfstmt->nodetype = S_NOP; /* disable action! */
4718 goto done;
4719 }
4720 snprintf(namebuf, sizeof(namebuf)-1, "action(type=\"%s\" ...)",
4721 modGetName(cnfstmt->d.act->pMod));
4722 namebuf[255] = '\0'; /* be on safe side */
4723 cnfstmt->printable = (uchar*)strdup(namebuf);
4724 nvlstChkUnused(lst);
4725 nvlstDestruct(lst);
4726 done: return cnfstmt;
4727 }
4728
4729 struct cnfstmt *
cnfstmtNewLegaAct(char * actline)4730 cnfstmtNewLegaAct(char *actline)
4731 {
4732 struct cnfstmt* cnfstmt;
4733 rsRetVal localRet;
4734 if((cnfstmt = cnfstmtNew(S_ACT)) == NULL)
4735 goto done;
4736 cnfstmt->printable = (uchar*)strdup((char*)actline);
4737 localRet = cflineDoAction(loadConf, (uchar**)&actline, &cnfstmt->d.act);
4738 if(localRet != RS_RET_OK) {
4739 parser_errmsg("%s occured in file '%s' around line %d",
4740 (localRet == RS_RET_OK_WARN) ? "warnings" : "errors",
4741 cnfcurrfn, yylineno);
4742 if(localRet != RS_RET_OK_WARN) {
4743 cnfstmt->nodetype = S_NOP; /* disable action! */
4744 goto done;
4745 }
4746 }
4747 done: return cnfstmt;
4748 }
4749
4750
4751 /* returns 1 if the two expressions are constants, 0 otherwise
4752 * if both are constants, the expression subtrees are destructed
4753 * (this is an aid for constant folding optimizing)
4754 */
4755 static int
getConstNumber(struct cnfexpr * expr,long long * l,long long * r)4756 getConstNumber(struct cnfexpr *expr, long long *l, long long *r)
4757 {
4758 int ret = 0;
4759 cnfexprOptimize(expr->l);
4760 cnfexprOptimize(expr->r);
4761 if(expr->l->nodetype == 'N') {
4762 if(expr->r->nodetype == 'N') {
4763 ret = 1;
4764 *l = ((struct cnfnumval*)expr->l)->val;
4765 *r = ((struct cnfnumval*)expr->r)->val;
4766 cnfexprDestruct(expr->l);
4767 cnfexprDestruct(expr->r);
4768 } else if(expr->r->nodetype == 'S') {
4769 ret = 1;
4770 *l = ((struct cnfnumval*)expr->l)->val;
4771 *r = es_str2num(((struct cnfstringval*)expr->r)->estr, NULL);
4772 cnfexprDestruct(expr->l);
4773 cnfexprDestruct(expr->r);
4774 }
4775 } else if(expr->l->nodetype == 'S') {
4776 if(expr->r->nodetype == 'N') {
4777 ret = 1;
4778 *l = es_str2num(((struct cnfstringval*)expr->l)->estr, NULL);
4779 *r = ((struct cnfnumval*)expr->r)->val;
4780 cnfexprDestruct(expr->l);
4781 cnfexprDestruct(expr->r);
4782 } else if(expr->r->nodetype == 'S') {
4783 ret = 1;
4784 *l = es_str2num(((struct cnfstringval*)expr->l)->estr, NULL);
4785 *r = es_str2num(((struct cnfstringval*)expr->r)->estr, NULL);
4786 cnfexprDestruct(expr->l);
4787 cnfexprDestruct(expr->r);
4788 }
4789 }
4790 return ret;
4791 }
4792
4793
4794 /* constant folding for string concatenation */
4795 static void
constFoldConcat(struct cnfexpr * expr)4796 constFoldConcat(struct cnfexpr *expr)
4797 {
4798 es_str_t *estr;
4799 cnfexprOptimize(expr->l);
4800 cnfexprOptimize(expr->r);
4801 if(expr->l->nodetype == 'S') {
4802 if(expr->r->nodetype == 'S') {
4803 estr = ((struct cnfstringval*)expr->l)->estr;
4804 ((struct cnfstringval*)expr->l)->estr = NULL;
4805 es_addStr(&estr, ((struct cnfstringval*)expr->r)->estr);
4806 cnfexprDestruct(expr->l);
4807 cnfexprDestruct(expr->r);
4808 expr->nodetype = 'S';
4809 ((struct cnfstringval*)expr)->estr = estr;
4810 } else if(expr->r->nodetype == 'N') {
4811 es_str_t *numstr;
4812 estr = ((struct cnfstringval*)expr->l)->estr;
4813 ((struct cnfstringval*)expr->l)->estr = NULL;
4814 numstr = es_newStrFromNumber(((struct cnfnumval*)expr->r)->val);
4815 es_addStr(&estr, numstr);
4816 es_deleteStr(numstr);
4817 cnfexprDestruct(expr->l);
4818 cnfexprDestruct(expr->r);
4819 expr->nodetype = 'S';
4820 ((struct cnfstringval*)expr)->estr = estr;
4821 }
4822 } else if(expr->l->nodetype == 'N') {
4823 if(expr->r->nodetype == 'S') {
4824 estr = es_newStrFromNumber(((struct cnfnumval*)expr->l)->val);
4825 es_addStr(&estr, ((struct cnfstringval*)expr->r)->estr);
4826 cnfexprDestruct(expr->l);
4827 cnfexprDestruct(expr->r);
4828 expr->nodetype = 'S';
4829 ((struct cnfstringval*)expr)->estr = estr;
4830 } else if(expr->r->nodetype == 'N') {
4831 es_str_t *numstr;
4832 estr = es_newStrFromNumber(((struct cnfnumval*)expr->l)->val);
4833 numstr = es_newStrFromNumber(((struct cnfnumval*)expr->r)->val);
4834 es_addStr(&estr, numstr);
4835 es_deleteStr(numstr);
4836 cnfexprDestruct(expr->l);
4837 cnfexprDestruct(expr->r);
4838 expr->nodetype = 'S';
4839 ((struct cnfstringval*)expr)->estr = estr;
4840 }
4841 }
4842 }
4843
4844
4845 /* optimize comparisons with syslog severity/facility. This is a special
4846 * handler as the numerical values also support GT, LT, etc ops.
4847 */
4848 static struct cnfexpr*
cnfexprOptimize_CMP_severity_facility(struct cnfexpr * expr)4849 cnfexprOptimize_CMP_severity_facility(struct cnfexpr *expr)
4850 {
4851 struct cnffunc *func;
4852
4853 if(expr->l->nodetype != 'V')
4854 FINALIZE;
4855
4856 if(!strcmp("syslogseverity", ((struct cnfvar*)expr->l)->name)) {
4857 if(expr->r->nodetype == 'N') {
4858 int sev = (int) ((struct cnfnumval*)expr->r)->val;
4859 if(sev >= 0 && sev <= 7) {
4860 DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n");
4861 func = cnffuncNew_prifilt(0); /* fac is irrelevant, set below... */
4862 prifiltSetSeverity(func->funcdata, sev, expr->nodetype);
4863 cnfexprDestruct(expr);
4864 expr = (struct cnfexpr*) func;
4865 } else {
4866 parser_errmsg("invalid syslogseverity %d, expression will always "
4867 "evaluate to FALSE", sev);
4868 }
4869 }
4870 } else if(!strcmp("syslogfacility", ((struct cnfvar*)expr->l)->name)) {
4871 if(expr->r->nodetype == 'N') {
4872 int fac = (int) ((struct cnfnumval*)expr->r)->val;
4873 if(fac >= 0 && fac <= 24) {
4874 DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n");
4875 func = cnffuncNew_prifilt(0); /* fac is irrelevant, set below... */
4876 prifiltSetFacility(func->funcdata, fac, expr->nodetype);
4877 cnfexprDestruct(expr);
4878 expr = (struct cnfexpr*) func;
4879 } else {
4880 parser_errmsg("invalid syslogfacility %d, expression will always "
4881 "evaluate to FALSE", fac);
4882 }
4883 }
4884 }
4885 finalize_it:
4886 return expr;
4887 }
4888
4889 /* optimize a comparison with a variable as left-hand operand
4890 * NOTE: Currently support CMP_EQ, CMP_NE only and code NEEDS
4891 * TO BE CHANGED fgr other comparisons!
4892 */
4893 static struct cnfexpr*
cnfexprOptimize_CMP_var(struct cnfexpr * expr)4894 cnfexprOptimize_CMP_var(struct cnfexpr *expr)
4895 {
4896 struct cnffunc *func;
4897
4898 if(!strcmp("syslogfacility-text", ((struct cnfvar*)expr->l)->name)) {
4899 if(expr->r->nodetype == 'S') {
4900 char *cstr = es_str2cstr(((struct cnfstringval*)expr->r)->estr, NULL);
4901 int fac = decodeSyslogName((uchar*)cstr, syslogFacNames);
4902 if(fac == -1) {
4903 parser_errmsg("invalid facility '%s', expression will always "
4904 "evaluate to FALSE", cstr);
4905 } else {
4906 /* we can actually optimize! */
4907 DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n");
4908 func = cnffuncNew_prifilt(fac);
4909 if(expr->nodetype == CMP_NE)
4910 prifiltInvert(func->funcdata);
4911 cnfexprDestruct(expr);
4912 expr = (struct cnfexpr*) func;
4913 }
4914 free(cstr);
4915 }
4916 } else if(!strcmp("syslogseverity-text", ((struct cnfvar*)expr->l)->name)) {
4917 if(expr->r->nodetype == 'S') {
4918 char *cstr = es_str2cstr(((struct cnfstringval*)expr->r)->estr, NULL);
4919 int sev = decodeSyslogName((uchar*)cstr, syslogPriNames);
4920 if(sev == -1) {
4921 parser_errmsg("invalid syslogseverity '%s', expression will always "
4922 "evaluate to FALSE", cstr);
4923 } else {
4924 /* we can acutally optimize! */
4925 DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n");
4926 func = cnffuncNew_prifilt(0);
4927 prifiltSetSeverity(func->funcdata, sev, expr->nodetype);
4928 cnfexprDestruct(expr);
4929 expr = (struct cnfexpr*) func;
4930 }
4931 free(cstr);
4932 }
4933 } else {
4934 expr = cnfexprOptimize_CMP_severity_facility(expr);
4935 }
4936 return expr;
4937 }
4938
4939 static struct cnfexpr*
cnfexprOptimize_NOT(struct cnfexpr * expr)4940 cnfexprOptimize_NOT(struct cnfexpr *expr)
4941 {
4942 struct cnffunc *func;
4943
4944 if(expr->r->nodetype == 'F') {
4945 func = (struct cnffunc *)expr->r;
4946 if(func->fPtr == doFunct_Prifilt) {
4947 DBGPRINTF("optimize NOT prifilt() to inverted prifilt()\n");
4948 expr->r = NULL;
4949 cnfexprDestruct(expr);
4950 prifiltInvert(func->funcdata);
4951 expr = (struct cnfexpr*) func;
4952 }
4953 }
4954 return expr;
4955 }
4956
4957 static struct cnfexpr*
cnfexprOptimize_AND_OR(struct cnfexpr * expr)4958 cnfexprOptimize_AND_OR(struct cnfexpr *expr)
4959 {
4960 struct cnffunc *funcl, *funcr;
4961
4962 if(expr->l->nodetype == 'F') {
4963 if(expr->r->nodetype == 'F') {
4964 funcl = (struct cnffunc *)expr->l;
4965 funcr = (struct cnffunc *)expr->r;
4966 if(funcl->fPtr == doFunct_Prifilt && funcr->fPtr == doFunct_Prifilt) {
4967 DBGPRINTF("optimize combine AND/OR prifilt()\n");
4968 expr->l = NULL;
4969 prifiltCombine(funcl->funcdata, funcr->funcdata, expr->nodetype);
4970 cnfexprDestruct(expr);
4971 expr = (struct cnfexpr*) funcl;
4972 }
4973 }
4974 }
4975 return expr;
4976 }
4977
4978
4979 /* optimize array for EQ/NEQ comparisons. We sort the array in
4980 * this case so that we can apply binary search later on.
4981 */
4982 static inline void
cnfexprOptimize_CMPEQ_arr(struct cnfarray * arr)4983 cnfexprOptimize_CMPEQ_arr(struct cnfarray *arr)
4984 {
4985 DBGPRINTF("optimizer: sorting array of %d members for CMP_EQ/NEQ comparison\n", arr->nmemb);
4986 qsort(arr->arr, arr->nmemb, sizeof(es_str_t*), qs_arrcmp);
4987 }
4988
4989
4990 /* (recursively) optimize an expression */
4991 struct cnfexpr*
cnfexprOptimize(struct cnfexpr * expr)4992 cnfexprOptimize(struct cnfexpr *expr)
4993 {
4994 long long ln, rn;
4995 struct cnfexpr *exprswap;
4996
4997 DBGPRINTF("optimize expr %p, type '%s'\n", expr, tokenToString(expr->nodetype));
4998 switch(expr->nodetype) {
4999 case '&':
5000 constFoldConcat(expr);
5001 break;
5002 case '+':
5003 if(getConstNumber(expr, &ln, &rn)) {
5004 expr->nodetype = 'N';
5005 ((struct cnfnumval*)expr)->val = ln + rn;
5006 }
5007 break;
5008 case '-':
5009 if(getConstNumber(expr, &ln, &rn)) {
5010 expr->nodetype = 'N';
5011 ((struct cnfnumval*)expr)->val = ln - rn;
5012 }
5013 break;
5014 case '*':
5015 if(getConstNumber(expr, &ln, &rn)) {
5016 expr->nodetype = 'N';
5017 ((struct cnfnumval*)expr)->val = ln * rn;
5018 }
5019 break;
5020 case '/':
5021 if(getConstNumber(expr, &ln, &rn)) {
5022 expr->nodetype = 'N';
5023 if(rn == 0) {
5024 /* division by zero */
5025 ((struct cnfnumval*)expr)->val = 0;
5026 } else {
5027 ((struct cnfnumval*)expr)->val = ln / rn;
5028 }
5029 }
5030 break;
5031 case '%':
5032 if(getConstNumber(expr, &ln, &rn)) {
5033 expr->nodetype = 'N';
5034 if(rn == 0) {
5035 /* division by zero */
5036 ((struct cnfnumval*)expr)->val = 0;
5037 } else {
5038 ((struct cnfnumval*)expr)->val = ln % rn;
5039 }
5040 }
5041 break;
5042 case CMP_NE:
5043 case CMP_EQ:
5044 expr->l = cnfexprOptimize(expr->l);
5045 expr->r = cnfexprOptimize(expr->r);
5046 if(expr->l->nodetype == 'A') {
5047 if(expr->r->nodetype == 'A') {
5048 parser_errmsg("warning: '==' or '<>' "
5049 "comparison of two constant string "
5050 "arrays makes no sense");
5051 } else { /* swap for simpler execution step */
5052 exprswap = expr->l;
5053 expr->l = expr->r;
5054 expr->r = exprswap;
5055 }
5056 }
5057 if(expr->r->nodetype == 'A') {
5058 cnfexprOptimize_CMPEQ_arr((struct cnfarray *)expr->r);
5059 }
5060 /* This should be evaluated last because it may change expr
5061 * to a function.
5062 */
5063 if(expr->l->nodetype == 'V') {
5064 expr = cnfexprOptimize_CMP_var(expr);
5065 }
5066 break;
5067 case CMP_LE:
5068 case CMP_GE:
5069 case CMP_LT:
5070 case CMP_GT:
5071 expr->l = cnfexprOptimize(expr->l);
5072 expr->r = cnfexprOptimize(expr->r);
5073 expr = cnfexprOptimize_CMP_severity_facility(expr);
5074 break;
5075 case CMP_CONTAINS:
5076 case CMP_CONTAINSI:
5077 case CMP_STARTSWITH:
5078 case CMP_STARTSWITHI:
5079 expr->l = cnfexprOptimize(expr->l);
5080 expr->r = cnfexprOptimize(expr->r);
5081 break;
5082 case AND:
5083 case OR:
5084 expr->l = cnfexprOptimize(expr->l);
5085 expr->r = cnfexprOptimize(expr->r);
5086 expr = cnfexprOptimize_AND_OR(expr);
5087 break;
5088 case NOT:
5089 expr->r = cnfexprOptimize(expr->r);
5090 expr = cnfexprOptimize_NOT(expr);
5091 break;
5092 default:/* nodetypes we cannot optimize */
5093 break;
5094 }
5095 return expr;
5096 }
5097
5098 /* removes NOPs from a statement list and returns the
5099 * first non-NOP entry.
5100 */
5101 static struct cnfstmt *
removeNOPs(struct cnfstmt * const root)5102 removeNOPs(struct cnfstmt *const root)
5103 {
5104 struct cnfstmt *stmt, *toDel, *prevstmt = NULL;
5105 struct cnfstmt *newRoot = NULL;
5106
5107 if(root == NULL) goto done;
5108 stmt = root;
5109 while(stmt != NULL) {
5110 if(stmt->nodetype == S_NOP) {
5111 if(prevstmt != NULL)
5112 /* end chain, is rebuild if more non-NOPs follow */
5113 prevstmt->next = NULL;
5114 toDel = stmt;
5115 stmt = stmt->next;
5116 cnfstmtDestruct(toDel);
5117 } else {
5118 if(newRoot == NULL)
5119 newRoot = stmt;
5120 if(prevstmt != NULL)
5121 prevstmt->next = stmt;
5122 prevstmt = stmt;
5123 stmt = stmt->next;
5124 }
5125 }
5126 done: return newRoot;
5127 }
5128
5129 static void
cnfstmtOptimizeForeach(struct cnfstmt * stmt)5130 cnfstmtOptimizeForeach(struct cnfstmt *stmt)
5131 {
5132 stmt->d.s_foreach.iter->collection = cnfexprOptimize(stmt->d.s_foreach.iter->collection);
5133 stmt->d.s_foreach.body = cnfstmtOptimize(stmt->d.s_foreach.body);
5134 }
5135
5136
5137 static void
cnfstmtOptimizeIf(struct cnfstmt * stmt)5138 cnfstmtOptimizeIf(struct cnfstmt *stmt)
5139 {
5140 struct cnfstmt *t_then, *t_else;
5141 struct cnfexpr *expr;
5142 struct cnffunc *func;
5143 struct funcData_prifilt *prifilt;
5144
5145 assert(stmt->nodetype == S_IF);
5146 expr = stmt->d.s_if.expr = cnfexprOptimize(stmt->d.s_if.expr);
5147 stmt->d.s_if.t_then = cnfstmtOptimize(stmt->d.s_if.t_then);
5148 stmt->d.s_if.t_else = cnfstmtOptimize(stmt->d.s_if.t_else);
5149
5150 if(stmt->d.s_if.t_then == NULL && stmt->d.s_if.t_else == NULL) {
5151 /* pointless if, probably constructed by config mgmt system */
5152 DBGPRINTF("optimizer: if with both empty then and else - remove\n");
5153 cnfexprDestruct(stmt->d.s_if.expr);
5154 /* set to NOP, this will be removed in later stage */
5155 stmt->nodetype = S_NOP;
5156 goto done;
5157 }
5158
5159 assert(stmt->nodetype == S_IF);
5160 if(stmt->d.s_if.expr->nodetype == 'F') {
5161 func = (struct cnffunc*)expr;
5162 if(func->fPtr == doFunct_Prifilt) {
5163 DBGPRINTF("optimizer: change IF to PRIFILT\n");
5164 t_then = stmt->d.s_if.t_then;
5165 t_else = stmt->d.s_if.t_else;
5166 stmt->nodetype = S_PRIFILT;
5167 prifilt = (struct funcData_prifilt*) func->funcdata;
5168 memcpy(stmt->d.s_prifilt.pmask, prifilt->pmask,
5169 sizeof(prifilt->pmask));
5170 stmt->d.s_prifilt.t_then = t_then;
5171 stmt->d.s_prifilt.t_else = t_else;
5172 if(func->nParams == 0)
5173 stmt->printable = (uchar*)strdup("[Optimizer Result]");
5174 else
5175 stmt->printable = (uchar*)
5176 es_str2cstr(((struct cnfstringval*)func->expr[0])->estr, NULL);
5177 cnfexprDestruct(expr);
5178 cnfstmtOptimizePRIFilt(stmt);
5179 }
5180 }
5181 done: return;
5182 }
5183
5184 static void
cnfstmtOptimizeAct(struct cnfstmt * stmt)5185 cnfstmtOptimizeAct(struct cnfstmt *stmt)
5186 {
5187 action_t *pAct;
5188
5189 pAct = stmt->d.act;
5190 if(!strcmp((char*)modGetName(pAct->pMod), "builtin:omdiscard")) {
5191 DBGPRINTF("optimizer: replacing omdiscard by STOP\n");
5192 actionDestruct(stmt->d.act);
5193 stmt->nodetype = S_STOP;
5194 }
5195 }
5196
5197 static void
cnfstmtOptimizePRIFilt(struct cnfstmt * stmt)5198 cnfstmtOptimizePRIFilt(struct cnfstmt *stmt)
5199 {
5200 int i;
5201 int isAlways = 1;
5202 struct cnfstmt *subroot, *last;
5203
5204 stmt->d.s_prifilt.t_then = cnfstmtOptimize(stmt->d.s_prifilt.t_then);
5205
5206 for(i = 0; i <= LOG_NFACILITIES; i++)
5207 if(stmt->d.s_prifilt.pmask[i] != 0xff) {
5208 isAlways = 0;
5209 break;
5210 }
5211 if(!isAlways)
5212 goto done;
5213
5214 DBGPRINTF("optimizer: removing always-true PRIFILT %p\n", stmt);
5215 if(stmt->d.s_prifilt.t_else != NULL) {
5216 parser_errmsg("error: always-true PRI filter has else part!\n");
5217 cnfstmtDestructLst(stmt->d.s_prifilt.t_else);
5218 }
5219 free(stmt->printable);
5220 stmt->printable = NULL;
5221 subroot = stmt->d.s_prifilt.t_then;
5222 if(subroot == NULL) {
5223 /* very strange, we set it to NOP, best we can do
5224 * This case is NOT expected in practice
5225 */
5226 stmt->nodetype = S_NOP;
5227 goto done;
5228 }
5229 for(last = subroot ; last->next != NULL ; last = last->next)
5230 /* find last node in subtree */;
5231 last->next = stmt->next;
5232 memcpy(stmt, subroot, sizeof(struct cnfstmt));
5233 free(subroot);
5234
5235 done: return;
5236 }
5237
5238 static void
cnfstmtOptimizeReloadLookupTable(struct cnfstmt * stmt)5239 cnfstmtOptimizeReloadLookupTable(struct cnfstmt *stmt) {
5240 if((stmt->d.s_reload_lookup_table.table = lookupFindTable(stmt->d.s_reload_lookup_table.table_name))
5241 == NULL) {
5242 parser_errmsg("lookup table '%s' not found\n", stmt->d.s_reload_lookup_table.table_name);
5243 }
5244 }
5245
5246 /* we abuse "optimize" a bit. Actually, we obtain a ruleset pointer, as
5247 * all rulesets are only known later in the process (now!).
5248 */
5249 static void
cnfstmtOptimizeCall(struct cnfstmt * stmt)5250 cnfstmtOptimizeCall(struct cnfstmt *stmt)
5251 {
5252 ruleset_t *pRuleset;
5253 rsRetVal localRet;
5254 uchar *rsName;
5255
5256 rsName = (uchar*) es_str2cstr(stmt->d.s_call.name, NULL);
5257 localRet = rulesetGetRuleset(loadConf, &pRuleset, rsName);
5258 if(localRet != RS_RET_OK) {
5259 /* in that case, we accept that a NOP will "survive" */
5260 parser_errmsg("ruleset '%s' cannot be found\n", rsName);
5261 es_deleteStr(stmt->d.s_call.name);
5262 stmt->nodetype = S_NOP;
5263 goto done;
5264 }
5265 DBGPRINTF("CALL obtained ruleset ptr %p for ruleset '%s' [hasQueue:%d]\n",
5266 pRuleset, rsName, rulesetHasQueue(pRuleset));
5267 if(rulesetHasQueue(pRuleset)) {
5268 stmt->d.s_call.ruleset = pRuleset;
5269 } else {
5270 stmt->d.s_call.ruleset = NULL;
5271 stmt->d.s_call.stmt = pRuleset->root;
5272 }
5273 done:
5274 free(rsName);
5275 return;
5276 }
5277 /* (recursively) optimize a statement */
5278 struct cnfstmt *
cnfstmtOptimize(struct cnfstmt * root)5279 cnfstmtOptimize(struct cnfstmt *root)
5280 {
5281 struct cnfstmt *stmt;
5282 if(root == NULL) goto done;
5283 for(stmt = root ; stmt != NULL ; stmt = stmt->next) {
5284 DBGPRINTF("optimizing cnfstmt type %d\n", (int) stmt->nodetype);
5285 switch(stmt->nodetype) {
5286 case S_IF:
5287 cnfstmtOptimizeIf(stmt);
5288 break;
5289 case S_FOREACH:
5290 cnfstmtOptimizeForeach(stmt);
5291 break;
5292 case S_PRIFILT:
5293 cnfstmtOptimizePRIFilt(stmt);
5294 break;
5295 case S_PROPFILT:
5296 stmt->d.s_propfilt.t_then = cnfstmtOptimize(stmt->d.s_propfilt.t_then);
5297 break;
5298 case S_SET:
5299 stmt->d.s_set.expr = cnfexprOptimize(stmt->d.s_set.expr);
5300 break;
5301 case S_ACT:
5302 cnfstmtOptimizeAct(stmt);
5303 break;
5304 case S_CALL:
5305 cnfstmtOptimizeCall(stmt);
5306 break;
5307 case S_CALL_INDIRECT:
5308 stmt->d.s_call_ind.expr = cnfexprOptimize(stmt->d.s_call_ind.expr);
5309 break;
5310 case S_STOP:
5311 if(stmt->next != NULL)
5312 parser_warnmsg("STOP is followed by unreachable statements!\n");
5313 break;
5314 case S_UNSET: /* nothing to do */
5315 break;
5316 case S_RELOAD_LOOKUP_TABLE:
5317 cnfstmtOptimizeReloadLookupTable(stmt);
5318 break;
5319 case S_NOP:
5320 // TODO: fix optimizer, re-enable. see:
5321 // https://github.com/rsyslog/rsyslog/issues/2524
5322 //LogError(0, RS_RET_INTERNAL_ERROR,
5323 // "optimizer error: we see a NOP, how come?");
5324 dbgprintf("optimizer error: we see a NOP, how come?");
5325 break;
5326 default:
5327 LogError(0, RS_RET_INTERNAL_ERROR,
5328 "internal error: unknown stmt type %u during optimizer run\n",
5329 (unsigned) stmt->nodetype);
5330 break;
5331 }
5332 }
5333 root = removeNOPs(root);
5334 done: return root;
5335 }
5336
5337
5338 struct cnffparamlst *
cnffparamlstNew(struct cnfexpr * expr,struct cnffparamlst * next)5339 cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next)
5340 {
5341 struct cnffparamlst* lst;
5342 if((lst = malloc(sizeof(struct cnffparamlst))) != NULL) {
5343 lst->nodetype = 'P';
5344 lst->expr = expr;
5345 lst->next = next;
5346 }
5347 return lst;
5348 }
5349
5350 /* Obtain function id from name AND number of params. Issues the
5351 * relevant error messages if errors are detected.
5352 */
5353 static rscriptFuncPtr
funcName2Ptr(char * const fname,const unsigned short nParams)5354 funcName2Ptr(char *const fname, const unsigned short nParams)
5355 {
5356 struct scriptFunct *foundFunc = searchModList(fname);
5357 if(foundFunc == NULL) {
5358 parser_errmsg("function '%s' not found", fname);
5359 return NULL;
5360 } else {
5361 return extractFuncPtr(foundFunc, nParams);
5362 }
5363 }
5364
5365 rsRetVal
addMod2List(const int version,struct scriptFunct * functArray)5366 addMod2List(const int __attribute__((unused)) version, struct scriptFunct *functArray)
5367 /*version currently not used, might be needed later for versin check*/
5368 {
5369 DEFiRet;
5370 int i;
5371 struct modListNode *newNode;
5372 CHKmalloc(newNode = (struct modListNode*) malloc(sizeof(struct modListNode)));
5373 newNode->version = 1;
5374 newNode->next = NULL;
5375
5376 i = 0;
5377 while(functArray[i].fname != NULL) {
5378 if(searchModList(functArray[i].fname) != NULL) {
5379 parser_errmsg("function %s defined multiple times, second time will be ignored",
5380 functArray[i].fname);
5381 }
5382 i++;
5383 }
5384 newNode->modFcts = functArray;
5385
5386 modListLast->next = newNode;
5387 modListLast = newNode;
5388 finalize_it:
5389 RETiRet;
5390 }
5391
5392
5393 struct cnffunc *
cnffuncNew(es_str_t * fname,struct cnffparamlst * paramlst)5394 cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst)
5395 {
5396 struct cnffunc* func;
5397 struct cnffparamlst *param, *toDel;
5398 unsigned short i;
5399 unsigned short nParams;
5400 char *cstr;
5401
5402 /* we first need to find out how many params we have */
5403 nParams = 0;
5404 for(param = paramlst ; param != NULL ; param = param->next)
5405 ++nParams;
5406 if((func = malloc(sizeof(struct cnffunc) + (nParams * sizeof(struct cnfexp*))))
5407 != NULL) {
5408 func->nodetype = 'F';
5409 func->fname = fname;
5410 func->nParams = nParams;
5411 func->funcdata = NULL;
5412 func->destructable_funcdata = 1;
5413 cstr = es_str2cstr(fname, NULL);
5414 func->fPtr = funcName2Ptr(cstr, nParams);
5415
5416 /* parse error if we have an unknown function */
5417 if (func->fPtr == NULL) {
5418 parser_errmsg("Invalid function %s", cstr);
5419 }
5420
5421 /* shuffle params over to array (access speed!) */
5422 param = paramlst;
5423 for(i = 0 ; i < nParams ; ++i) {
5424 func->expr[i] = param->expr;
5425 toDel = param;
5426 param = param->next;
5427 free(toDel);
5428 }
5429 /* some functions require special initialization */
5430 struct scriptFunct *foundFunc = searchModList(cstr);
5431 if(foundFunc->initFunc != NULL) {
5432 foundFunc->initFunc(func);
5433 }
5434 free(cstr);
5435 }
5436 return func;
5437 }
5438
5439
5440 /* A special function to create a prifilt() expression during optimization
5441 * phase.
5442 */
5443 struct cnffunc *
cnffuncNew_prifilt(int fac)5444 cnffuncNew_prifilt(int fac)
5445 {
5446 struct cnffunc* func;
5447
5448 fac >>= 3;
5449 if (fac >= LOG_NFACILITIES + 1 || fac < 0)
5450 return NULL;
5451
5452 if((func = malloc(sizeof(struct cnffunc))) != NULL) {
5453 if ((func->funcdata = calloc(1, sizeof(struct funcData_prifilt))) == NULL) {
5454 free(func);
5455 return NULL;
5456 }
5457 func->nodetype = 'F';
5458 func->fname = es_newStrFromCStr("prifilt", sizeof("prifilt")-1);
5459 func->nParams = 0;
5460 func->fPtr = doFunct_Prifilt;
5461 func->destructable_funcdata = 1;
5462 ((struct funcData_prifilt *)func->funcdata)->pmask[fac] = TABLE_ALLPRI;
5463 }
5464 return func;
5465 }
5466
5467
5468 /* The check-if-variable exists "exists($!var)" is a special beast and as such
5469 * also needs special code (we must not evaluate the var but need its name).
5470 */
ATTR_NONNULL()5471 struct cnffuncexists * ATTR_NONNULL()
5472 cnffuncexistsNew(const char *const varname)
5473 {
5474 struct cnffuncexists* f_exists;
5475
5476 if((f_exists = malloc(sizeof(struct cnffuncexists))) != NULL) {
5477 f_exists->nodetype = S_FUNC_EXISTS;
5478 f_exists->varname = varname;
5479 msgPropDescrFill(&f_exists->prop, (uchar*)varname, strlen(varname));
5480 }
5481 return f_exists;
5482 }
5483
5484
5485 /* returns 0 if everything is OK and config parsing shall continue,
5486 * and 1 if things are so wrong that config parsing shall be aborted.
5487 */
ATTR_NONNULL()5488 int ATTR_NONNULL()
5489 cnfDoInclude(const char *const name, const int optional)
5490 {
5491 char *cfgFile;
5492 const char *finalName;
5493 int i;
5494 int result;
5495 glob_t cfgFiles;
5496 int ret = 0;
5497 struct stat fileInfo;
5498 char errStr[1024];
5499 char nameBuf[MAXFNAME+1];
5500 char cwdBuf[MAXFNAME+1];
5501
5502 DBGPRINTF("cnfDoInclude: file: '%s', optional: %d\n", name, optional);
5503 finalName = name;
5504 if(stat(name, &fileInfo) == 0) {
5505 /* stat usually fails if we have a wildcard - so this does NOT indicate error! */
5506 if(S_ISDIR(fileInfo.st_mode)) {
5507 /* if we have a directory, we need to add "*" to get its files */
5508 snprintf(nameBuf, sizeof(nameBuf), "%s*", name);
5509 finalName = nameBuf;
5510 }
5511 }
5512
5513 /* Use GLOB_MARK to append a trailing slash for directories. */
5514 /* Use GLOB_NOMAGIC to detect wildcards that match nothing. */
5515 #ifdef HAVE_GLOB_NOMAGIC
5516 /* Silently ignore wildcards that match nothing */
5517 result = glob(finalName, GLOB_MARK | GLOB_NOMAGIC, NULL, &cfgFiles);
5518 if(result == GLOB_NOMATCH) {
5519 #else
5520 result = glob(finalName, GLOB_MARK, NULL, &cfgFiles);
5521 if(result == GLOB_NOMATCH && containsGlobWildcard((char*)finalName)) {
5522 #endif /* HAVE_GLOB_NOMAGIC */
5523 goto done;
5524 }
5525
5526 if(result == GLOB_NOSPACE || result == GLOB_ABORTED) {
5527 if(optional == 0) {
5528 rs_strerror_r(errno, errStr, sizeof(errStr));
5529 if(getcwd(cwdBuf, sizeof(cwdBuf)) == NULL)
5530 strcpy(cwdBuf, "??getcwd() failed??");
5531 parser_errmsg("error accessing config file or directory '%s' "
5532 "[cwd:%s]: %s", finalName, cwdBuf, errStr);
5533 ret = 1;
5534 }
5535 goto done;
5536 }
5537
5538 /* note: bison "stacks" the files, so we need to submit them
5539 * in reverse order to the *stack* in order to get the proper
5540 * parsing order. Also see
5541 * http://bugzilla.adiscon.com/show_bug.cgi?id=411
5542 */
5543 for(i = cfgFiles.gl_pathc - 1; i >= 0 ; i--) {
5544 cfgFile = cfgFiles.gl_pathv[i];
5545 if(stat(cfgFile, &fileInfo) != 0) {
5546 if(optional == 0) {
5547 rs_strerror_r(errno, errStr, sizeof(errStr));
5548 if(getcwd(cwdBuf, sizeof(cwdBuf)) == NULL)
5549 strcpy(cwdBuf, "??getcwd() failed??");
5550 parser_errmsg("error accessing config file or directory '%s' "
5551 "[cwd: %s]: %s", cfgFile, cwdBuf, errStr);
5552 ret = 1;
5553 }
5554 goto done;
5555 }
5556
5557 if(S_ISREG(fileInfo.st_mode)) { /* config file */
5558 DBGPRINTF("requested to include config file '%s'\n", cfgFile);
5559 cnfSetLexFile(cfgFile);
5560 } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */
5561 DBGPRINTF("requested to include directory '%s'\n", cfgFile);
5562 cnfDoInclude(cfgFile, optional);
5563 } else {
5564 DBGPRINTF("warning: unable to process IncludeConfig directive '%s'\n", cfgFile);
5565 }
5566 }
5567
5568 done:
5569 globfree(&cfgFiles);
5570 return ret;
5571 }
5572
5573
5574 /* Process include() objects */
5575 void
5576 includeProcessCnf(struct nvlst *const lst)
5577 {
5578 struct cnfparamvals *pvals = NULL;
5579 const char *inc_file = NULL;
5580 const char *text = NULL;
5581 int optional = 0;
5582 int abort_if_missing = 0;
5583 int i;
5584
5585 if(lst == NULL) {
5586 parser_errmsg("include() must have either 'file' or 'text' "
5587 "parameter - ignored");
5588 goto done;
5589 }
5590
5591 if (nvlstChkDisabled(lst)) {
5592 DBGPRINTF("include statement disabled\n");
5593 goto done;
5594 }
5595
5596 pvals = nvlstGetParams(lst, &incpblk, NULL);
5597 if(pvals == NULL) {
5598 goto done;
5599 }
5600 DBGPRINTF("include param blk after includeProcessCnf:\n");
5601 cnfparamsPrint(&incpblk, pvals);
5602 for(i = 0 ; i < incpblk.nParams ; ++i) {
5603 if(!pvals[i].bUsed) {
5604 continue;
5605 }
5606
5607 if(!strcmp(incpblk.descr[i].name, "file")) {
5608 inc_file = es_str2cstr(pvals[i].val.d.estr, NULL);
5609 } else if(!strcmp(incpblk.descr[i].name, "text")) {
5610 text = es_str2cstr(pvals[i].val.d.estr, NULL);
5611 } else if(!strcmp(incpblk.descr[i].name, "mode")) {
5612 char *const md = es_str2cstr(pvals[i].val.d.estr, NULL);
5613 if(!strcmp(md, "abort-if-missing")) {
5614 optional = 0;
5615 abort_if_missing = 1;
5616 } else if(!strcmp(md, "required")) {
5617 optional = 0;
5618 } else if(!strcmp(md, "optional")) {
5619 optional = 1;
5620 } else {
5621 parser_errmsg("invalid 'mode' paramter: '%s' - ignored", md);
5622 }
5623 free((void*)md);
5624 } else {
5625 LogError(0, RS_RET_INTERNAL_ERROR,
5626 "rainerscript/include: program error, non-handled inclpblk "
5627 "param '%s' in includeProcessCnf()", incpblk.descr[i].name);
5628 }
5629 }
5630
5631 if(text != NULL && inc_file != NULL) {
5632 parser_errmsg("include() must have either 'file' or 'text' "
5633 "parameter, but both are set - ignored");
5634 goto done;
5635 }
5636
5637 if(inc_file != NULL) {
5638 if(cnfDoInclude(inc_file, optional) != 0 && abort_if_missing) {
5639 fprintf(stderr, "include file '%s' mode is set to abort-if-missing "
5640 "and the file is indeed missing - thus aborting rsyslog\n",
5641 inc_file);
5642 exit(1); /* "good exit" - during config processing, requested by user */
5643 }
5644 } else if(text != NULL) {
5645 es_str_t *estr = es_newStrFromCStr((char*)text, strlen(text));
5646 /* lex needs 2 \0 bytes as terminator indication (wtf ;-)) */
5647 es_addChar(&estr, '\0');
5648 es_addChar(&estr, '\0');
5649 cnfAddConfigBuffer(estr, "text");
5650 } else {
5651 parser_errmsg("include must have either 'file' or 'text' "
5652 "parameter - ignored");
5653 goto done;
5654 }
5655
5656 done:
5657 free((void*)text);
5658 free((void*)inc_file);
5659 nvlstDestruct(lst);
5660 if(pvals != NULL)
5661 cnfparamvalsDestruct(pvals, &incpblk);
5662 return;
5663 }
5664
5665
5666 void
5667 varDelete(const struct svar *v)
5668 {
5669 switch(v->datatype) {
5670 case 'S':
5671 case 'J':
5672 varFreeMembers(v);
5673 break;
5674 case 'A':
5675 cnfarrayContentDestruct(v->d.ar);
5676 free(v->d.ar);
5677 break;
5678 default:break;
5679 }
5680 }
5681
5682 void
5683 cnfparamvalsDestruct(const struct cnfparamvals *paramvals, const struct cnfparamblk *blk)
5684 {
5685 int i;
5686 if(paramvals == NULL)
5687 return;
5688 for(i = 0 ; i < blk->nParams ; ++i) {
5689 if(paramvals[i].bUsed) {
5690 varDelete(¶mvals[i].val);
5691 }
5692 }
5693 free((void*)paramvals);
5694 }
5695
5696 /* find the index (or -1!) for a config param by name. This is used to
5697 * address the parameter array. Of course, we could use with static
5698 * indices, but that would create some extra bug potential. So we
5699 * resort to names. As we do this only during the initial config parsing
5700 * stage the (considerable!) extra overhead is OK. -- rgerhards, 2011-07-19
5701 */
5702 int
5703 cnfparamGetIdx(struct cnfparamblk *params, const char *name)
5704 {
5705 int i;
5706 for(i = 0 ; i < params->nParams ; ++i)
5707 if(!strcmp(params->descr[i].name, name))
5708 break;
5709 if(i == params->nParams)
5710 i = -1; /* not found */
5711 return i;
5712 }
5713
5714
5715 void
5716 cstrPrint(const char *text, es_str_t *estr)
5717 {
5718 char *str;
5719 str = es_str2cstr(estr, NULL);
5720 dbgprintf("%s%s", text, str);
5721 free(str);
5722 }
5723
5724 char *
5725 rmLeadingSpace(char *s)
5726 {
5727 char *p;
5728 for(p = s ; *p && isspace(*p) ; ++p)
5729 ;
5730 return(p);
5731 }
5732
5733 /* init must be called once before any parsing of the script files start */
5734 rsRetVal
5735 initRainerscript(void)
5736 {
5737 DEFiRet;
5738 CHKmalloc(modListRoot = (struct modListNode*) malloc(sizeof(struct modListNode)));
5739 modListRoot->version = 1;
5740 modListRoot->modFcts = functions;
5741 modListRoot->next = NULL;
5742 modListLast = modListRoot;
5743 iRet = objGetObjInterface(&obj);
5744 finalize_it:
5745 RETiRet;
5746 }
5747
5748 /* we need a function to check for octal digits */
5749 static inline int
5750 isodigit(uchar c)
5751 {
5752 return(c >= '0' && c <= '7');
5753 }
5754
5755 /**
5756 * Get numerical value of a hex digit. This is a helper function.
5757 * @param[in] c a character containing 0..9, A..Z, a..z anything else
5758 * is an (undetected) error.
5759 */
5760 static int
5761 hexDigitVal(char c)
5762 {
5763 int r;
5764 if(c < 'A')
5765 r = c - '0';
5766 else if(c < 'a')
5767 r = c - 'A' + 10;
5768 else
5769 r = c - 'a' + 10;
5770 return r;
5771 }
5772
5773 /* Handle the actual unescaping.
5774 * a helper to unescapeStr(), to help make the function easier to read.
5775 */
5776 static void
5777 doUnescape(unsigned char *c, int len, int *iSrc, int iDst)
5778 {
5779 if(c[*iSrc] == '\\') {
5780 if(++(*iSrc) == len) {
5781 /* error, incomplete escape, treat as single char */
5782 c[iDst] = '\\';
5783 }
5784 /* regular case, unescape */
5785 switch(c[*iSrc]) {
5786 case 'a':
5787 c[iDst] = '\007';
5788 break;
5789 case 'b':
5790 c[iDst] = '\b';
5791 break;
5792 case 'f':
5793 c[iDst] = '\014';
5794 break;
5795 case 'n':
5796 c[iDst] = '\n';
5797 break;
5798 case 'r':
5799 c[iDst] = '\r';
5800 break;
5801 case 't':
5802 c[iDst] = '\t';
5803 break;
5804 case '\'':
5805 c[iDst] = '\'';
5806 break;
5807 case '"':
5808 c[iDst] = '"';
5809 break;
5810 case '?':
5811 c[iDst] = '?';
5812 break;
5813 case '$':
5814 c[iDst] = '$';
5815 break;
5816 case '\\':
5817 c[iDst] = '\\';
5818 break;
5819 case 'x':
5820 if( (*iSrc)+2 >= len
5821 || !isxdigit(c[(*iSrc)+1])
5822 || !isxdigit(c[(*iSrc)+2])) {
5823 /* error, incomplete escape, use as is */
5824 c[iDst] = '\\';
5825 --(*iSrc);
5826 }
5827 c[iDst] = (hexDigitVal(c[(*iSrc)+1]) << 4) +
5828 hexDigitVal(c[(*iSrc)+2]);
5829 *iSrc += 2;
5830 break;
5831 case '0': /* octal escape */
5832 case '1':
5833 case '2':
5834 case '3':
5835 case '4':
5836 case '5':
5837 case '6':
5838 case '7':
5839 if( (*iSrc)+2 >= len
5840 || !isodigit(c[(*iSrc)+1])
5841 || !isodigit(c[(*iSrc)+2])) {
5842 /* error, incomplete escape, use as is */
5843 c[iDst] = '\\';
5844 --(*iSrc);
5845 }
5846 c[iDst] = ((c[(*iSrc) ] - '0') << 6) +
5847 ((c[(*iSrc)+1] - '0') << 3) +
5848 ( c[(*iSrc)+2] - '0');
5849 *iSrc += 2;
5850 break;
5851 default:
5852 /* error, incomplete escape, indicate by '?' */
5853 c[iDst] = '?';
5854 break;
5855 }
5856 } else {
5857 /* regular character */
5858 c[iDst] = c[*iSrc];
5859 }
5860 }
5861
5862 void
5863 unescapeStr(uchar *s, int len)
5864 {
5865 int iSrc, iDst;
5866 assert(s != NULL);
5867
5868 /* scan for first escape sequence (if we are luky, there is none!) */
5869 iSrc = 0;
5870 while(iSrc < len && s[iSrc] != '\\')
5871 ++iSrc;
5872 /* now we have a sequence or end of string. In any case, we process
5873 * all remaining characters (maybe 0!) and unescape.
5874 */
5875 if(iSrc != len) {
5876 iDst = iSrc;
5877 while(iSrc < len) {
5878 doUnescape(s, len, &iSrc, iDst);
5879 ++iSrc;
5880 ++iDst;
5881 }
5882 s[iDst] = '\0';
5883 }
5884 }
5885
5886 const char *
5887 tokenval2str(const int tok)
5888 {
5889 if(tok < 256) return "";
5890 switch(tok) {
5891 case NAME: return "NAME";
5892 case FUNC: return "FUNC";
5893 case BEGINOBJ: return "BEGINOBJ";
5894 case ENDOBJ: return "ENDOBJ";
5895 case BEGIN_ACTION: return "BEGIN_ACTION";
5896 case BEGIN_PROPERTY: return "BEGIN_PROPERTY";
5897 case BEGIN_CONSTANT: return "BEGIN_CONSTANT";
5898 case BEGIN_TPL: return "BEGIN_TPL";
5899 case BEGIN_INCLUDE: return "BEGIN_INCLUDE";
5900 case BEGIN_RULESET: return "BEGIN_RULESET";
5901 case STOP: return "STOP";
5902 case SET: return "SET";
5903 case UNSET: return "UNSET";
5904 case CONTINUE: return "CONTINUE";
5905 case CALL: return "CALL";
5906 case LEGACY_ACTION: return "LEGACY_ACTION";
5907 case LEGACY_RULESET: return "LEGACY_RULESET";
5908 case PRIFILT: return "PRIFILT";
5909 case PROPFILT: return "PROPFILT";
5910 case BSD_TAG_SELECTOR: return "BSD_TAG_SELECTOR";
5911 case BSD_HOST_SELECTOR: return "BSD_HOST_SELECTOR";
5912 case IF: return "IF";
5913 case THEN: return "THEN";
5914 case ELSE: return "ELSE";
5915 case OR: return "OR";
5916 case AND: return "AND";
5917 case NOT: return "NOT";
5918 case VAR: return "VAR";
5919 case STRING: return "STRING";
5920 case NUMBER: return "NUMBER";
5921 case CMP_EQ: return "CMP_EQ";
5922 case CMP_NE: return "CMP_NE";
5923 case CMP_LE: return "CMP_LE";
5924 case CMP_GE: return "CMP_GE";
5925 case CMP_LT: return "CMP_LT";
5926 case CMP_GT: return "CMP_GT";
5927 case CMP_CONTAINS: return "CMP_CONTAINS";
5928 case CMP_CONTAINSI: return "CMP_CONTAINSI";
5929 case CMP_STARTSWITH: return "CMP_STARTSWITH";
5930 case CMP_STARTSWITHI: return "CMP_STARTSWITHI";
5931 case UMINUS: return "UMINUS";
5932 default: return "UNKNOWN TOKEN";
5933 }
5934 }
5935