summaryrefslogtreecommitdiffstats
path: root/grammar/rainerscript.c
diff options
context:
space:
mode:
Diffstat (limited to 'grammar/rainerscript.c')
-rw-r--r--grammar/rainerscript.c1377
1 files changed, 1170 insertions, 207 deletions
diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c
index 9e0d04c7..733ebef4 100644
--- a/grammar/rainerscript.c
+++ b/grammar/rainerscript.c
@@ -2,7 +2,7 @@
*
* Module begun 2011-07-01 by Rainer Gerhards
*
- * Copyright 2011 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2011-2012 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -22,7 +22,6 @@
* A copy of the GPL can be found in the file "COPYING" in this distribution.
* A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
*/
-
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
@@ -37,16 +36,55 @@
#include <libestr.h>
#include "rsyslog.h"
#include "rainerscript.h"
+#include "conf.h"
#include "parserif.h"
+#include "rsconf.h"
#include "grammar.h"
#include "queue.h"
#include "srUtils.h"
#include "regexp.h"
#include "obj.h"
+#include "modules.h"
+#include "ruleset.h"
DEFobjCurrIf(obj)
DEFobjCurrIf(regexp)
+void cnfexprOptimize(struct cnfexpr *expr);
+static void cnfstmtOptimizePRIFilt(struct cnfstmt *stmt);
+static void cnfarrayPrint(struct cnfarray *ar, int indent);
+
+char*
+getFIOPName(unsigned iFIOP)
+{
+ char *pRet;
+ switch(iFIOP) {
+ case FIOP_CONTAINS:
+ pRet = "contains";
+ break;
+ case FIOP_ISEQUAL:
+ pRet = "isequal";
+ break;
+ case FIOP_STARTSWITH:
+ pRet = "startswith";
+ break;
+ case FIOP_REGEX:
+ pRet = "regex";
+ break;
+ case FIOP_EREREGEX:
+ pRet = "ereregex";
+ break;
+ case FIOP_ISEMPTY:
+ pRet = "isempty";
+ break;
+ default:
+ pRet = "NOP";
+ break;
+ }
+ return pRet;
+}
+
+
void
readConfFile(FILE *fp, es_str_t **str)
{
@@ -107,7 +145,6 @@ objlstNew(struct cnfobj *o)
lst->next = NULL;
lst->obj = o;
}
-dbgprintf("AAAA: creating new objlst\n");
cnfobjPrint(o);
return lst;
@@ -131,6 +168,22 @@ objlstAdd(struct objlst *root, struct cnfobj *o)
return root;
}
+/* add stmt to current script, always return root stmt pointer */
+struct cnfstmt*
+scriptAddStmt(struct cnfstmt *root, struct cnfstmt *s)
+{
+ struct cnfstmt *l;
+
+ if(root == NULL) {
+ root = s;
+ } else { /* find last, linear search ok, as only during config phase */
+ for(l = root ; l->next != NULL ; l = l->next)
+ ;
+ l->next = s;
+ }
+ return root;
+}
+
void
objlstDestruct(struct objlst *lst)
{
@@ -155,13 +208,12 @@ objlstPrint(struct objlst *lst)
}
struct nvlst*
-nvlstNew(es_str_t *name, es_str_t *value)
+nvlstNewStr(es_str_t *value)
{
struct nvlst *lst;
if((lst = malloc(sizeof(struct nvlst))) != NULL) {
lst->next = NULL;
- lst->name = name;
lst->val.datatype = 'S';
lst->val.d.estr = value;
lst->bUsed = 0;
@@ -170,6 +222,28 @@ nvlstNew(es_str_t *name, es_str_t *value)
return lst;
}
+struct nvlst*
+nvlstNewArray(struct cnfarray *ar)
+{
+ struct nvlst *lst;
+
+ if((lst = malloc(sizeof(struct nvlst))) != NULL) {
+ lst->next = NULL;
+ lst->val.datatype = 'A';
+ lst->val.d.ar = ar;
+ lst->bUsed = 0;
+ }
+
+ return lst;
+}
+
+struct nvlst*
+nvlstSetName(struct nvlst *lst, es_str_t *name)
+{
+ lst->name = name;
+ return lst;
+}
+
void
nvlstDestruct(struct nvlst *lst)
{
@@ -179,8 +253,7 @@ nvlstDestruct(struct nvlst *lst)
toDel = lst;
lst = lst->next;
es_deleteStr(toDel->name);
- if(toDel->val.datatype == 'S')
- es_deleteStr(toDel->val.d.estr);
+ varDelete(&toDel->val);
free(toDel);
}
}
@@ -192,11 +265,21 @@ nvlstPrint(struct nvlst *lst)
dbgprintf("nvlst %p:\n", lst);
while(lst != NULL) {
name = es_str2cstr(lst->name, NULL);
- // TODO: support for non-string types
- value = es_str2cstr(lst->val.d.estr, NULL);
- dbgprintf("\tname: '%s', value '%s'\n", name, value);
+ switch(lst->val.datatype) {
+ case 'A':
+ dbgprintf("\tname: '%s':\n", name);
+ cnfarrayPrint(lst->val.d.ar, 5);
+ break;
+ case 'S':
+ value = es_str2cstr(lst->val.d.estr, NULL);
+ dbgprintf("\tname: '%s', value '%s'\n", name, value);
+ free(value);
+ break;
+ default:dbgprintf("nvlstPrint: unknown type '%c' [%d]\n",
+ lst->val.datatype, lst->val.datatype);
+ break;
+ }
free(name);
- free(value);
lst = lst->next;
}
}
@@ -515,6 +598,7 @@ doGetWord(struct nvlst *valnode, struct cnfparamdescr *param,
es_size_t i;
int r = 1;
unsigned char *c;
+
val->val.datatype = 'S';
val->val.d.estr = es_newStr(32);
c = es_getBufAddr(valnode->val.d.estr);
@@ -523,7 +607,7 @@ doGetWord(struct nvlst *valnode, struct cnfparamdescr *param,
}
if(i != es_strlen(valnode->val.d.estr)) {
parser_errmsg("parameter '%s' contains whitespace, which is not "
- "permitted - data after first whitespace ignored",
+ "permitted",
param->name);
r = 0;
}
@@ -531,6 +615,30 @@ doGetWord(struct nvlst *valnode, struct cnfparamdescr *param,
}
static inline int
+doGetArray(struct nvlst *valnode, struct cnfparamdescr *param,
+ struct cnfparamvals *val)
+{
+ int r = 1;
+
+ switch(valnode->val.datatype) {
+ case 'S':
+ /* a constant string is assumed to be a single-element array */
+ val->val.datatype = 'A';
+ val->val.d.ar = cnfarrayNew(es_strdup(valnode->val.d.estr));
+ break;
+ case 'A':
+ val->val.datatype = 'A';
+ val->val.d.ar = cnfarrayDup(valnode->val.d.ar);
+ break;
+ default:parser_errmsg("parameter '%s' must be an array, but is a "
+ "different datatype", param->name);
+ r = 0;
+ break;
+ }
+ return r;
+}
+
+static inline int
doGetChar(struct nvlst *valnode, struct cnfparamdescr *param,
struct cnfparamvals *val)
{
@@ -556,8 +664,15 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param,
uchar *cstr;
int r;
- dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d, valnode->bUsed %d\n",
+ DBGPRINTF("nvlstGetParam: name '%s', type %d, valnode->bUsed %d\n",
param->name, (int) param->type, valnode->bUsed);
+ if(valnode->val.datatype != 'S' && param->type != eCmdHdlrArray) {
+ parser_errmsg("parameter '%s' is not a string, which is not "
+ "permitted",
+ param->name);
+ r = 0;
+ goto done;
+ }
valnode->bUsed = 1;
val->bUsed = 1;
switch(param->type) {
@@ -613,6 +728,9 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param,
val->val.d.estr = es_strdup(valnode->val.d.estr);
r = 1;
break;
+ case eCmdHdlrArray:
+ r = doGetArray(valnode, param, val);
+ break;
case eCmdHdlrGoneAway:
parser_errmsg("parameter '%s' is no longer supported",
param->name);
@@ -623,7 +741,7 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param,
r = 0;
break;
}
- return r;
+done: return r;
}
@@ -680,7 +798,6 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params,
vals = NULL;
}
-dbgprintf("DDDD: vals %p\n", vals);
return vals;
}
@@ -701,6 +818,9 @@ cnfparamsPrint(struct cnfparamblk *params, struct cnfparamvals *vals)
dbgprintf(" '%s'", cstr);
free(cstr);
break;
+ case 'A':
+ cnfarrayPrint(vals[i].val.d.ar, 0);
+ break;
case 'N':
dbgprintf("%lld", vals[i].val.d.n);
break;
@@ -725,6 +845,7 @@ cnfobjNew(enum cnfobjType objType, struct nvlst *lst)
o->objType = objType;
o->nvlst = lst;
o->subobjs = NULL;
+ o->script = NULL;
}
return o;
@@ -748,116 +869,6 @@ cnfobjPrint(struct cnfobj *o)
}
-struct cnfactlst*
-cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine)
-{
- struct cnfactlst *actlst;
-
- if((actlst = malloc(sizeof(struct cnfactlst))) != NULL) {
- actlst->next = NULL;
- actlst->syslines = NULL;
- actlst->actType = actType;
- actlst->lineno = yylineno;
- actlst->cnfFile = strdup(cnfcurrfn);
- if(actType == CNFACT_V2)
- actlst->data.lst = lst;
- else
- actlst->data.legActLine = actLine;
- }
- return actlst;
-}
-
-struct cnfactlst*
-cnfactlstAddSysline(struct cnfactlst* actlst, char *line)
-{
- struct cnfcfsyslinelst *cflst;
-
- if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) {
- cflst->line = line;
- if(actlst->syslines == NULL) {
- cflst->next = NULL;
- } else {
- cflst->next = actlst->syslines;
- }
- actlst->syslines = cflst;
- }
- return actlst;
-}
-
-
-void
-cnfactlstDestruct(struct cnfactlst *actlst)
-{
- struct cnfactlst *toDel;
-
- while(actlst != NULL) {
- toDel = actlst;
- actlst = actlst->next;
- free(toDel->cnfFile);
- cnfcfsyslinelstDestruct(toDel->syslines);
- if(toDel->actType == CNFACT_V2)
- nvlstDestruct(toDel->data.lst);
- else
- free(toDel->data.legActLine);
- free(toDel);
- }
-
-}
-
-static inline struct cnfcfsyslinelst*
-cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst)
-{
- struct cnfcfsyslinelst *curr, *prev;
- if(lst == NULL)
- return NULL;
- prev = NULL;
- while(lst != NULL) {
- curr = lst;
- lst = lst->next;
- curr->next = prev;
- prev = curr;
- }
- return prev;
-}
-
-struct cnfactlst*
-cnfactlstReverse(struct cnfactlst *actlst)
-{
- struct cnfactlst *curr, *prev;
-
- prev = NULL;
- while(actlst != NULL) {
- curr = actlst;
- actlst = actlst->next;
- curr->syslines = cnfcfsyslinelstReverse(curr->syslines);
- curr->next = prev;
- prev = curr;
- }
- return prev;
-}
-
-void
-cnfactlstPrint(struct cnfactlst *actlst)
-{
- struct cnfcfsyslinelst *cflst;
-
- while(actlst != NULL) {
- dbgprintf("aclst %p: ", actlst);
- if(actlst->actType == CNFACT_V2) {
- dbgprintf("V2 action type: ");
- nvlstPrint(actlst->data.lst);
- } else {
- dbgprintf("legacy action line: '%s'\n",
- actlst->data.legActLine);
- }
- for( cflst = actlst->syslines
- ; cflst != NULL ; cflst = cflst->next) {
- dbgprintf("action:cfsysline: '%s'\n", cflst->line);
- }
- actlst = actlst->next;
- }
-}
-
struct cnfexpr*
cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r)
{
@@ -884,15 +895,19 @@ done:
* try to convert it to one. The semantics from es_str2num()
* are used (bSuccess tells if the conversion went well or not).
*/
-static inline long long
+static long long
var2Number(struct var *r, int *bSuccess)
{
long long n;
if(r->datatype == 'S') {
n = es_str2num(r->d.estr, bSuccess);
} else {
- n = r->d.n;
- if(bSuccess)
+ if(r->datatype == 'J') {
+ n = (r->d.json == NULL) ? 0 : json_object_get_int(r->d.json);
+ } else {
+ n = r->d.n;
+ }
+ if(bSuccess != NULL)
*bSuccess = 1;
}
return n;
@@ -903,12 +918,88 @@ var2Number(struct var *r, int *bSuccess)
static inline es_str_t *
var2String(struct var *r, int *bMustFree)
{
+ es_str_t *estr;
+ char *cstr;
+ rs_size_t lenstr;
if(r->datatype == 'N') {
*bMustFree = 1;
- return es_newStrFromNumber(r->d.n);
+ estr = es_newStrFromNumber(r->d.n);
+ } else if(r->datatype == 'J') {
+ *bMustFree = 1;
+ if(r->d.json == NULL) {
+ cstr = "",
+ lenstr = 0;
+ } else {
+ cstr = (char*)json_object_get_string(r->d.json);
+ lenstr = strlen(cstr);
+ }
+ estr = es_newStrFromCStr(cstr, lenstr);
+ } else {
+ *bMustFree = 0;
+ estr = r->d.estr;
+ }
+ return estr;
+}
+
+static uchar*
+var2CString(struct var *r, int *bMustFree)
+{
+ uchar *cstr;
+ es_str_t *estr;
+ estr = var2String(r, bMustFree);
+ cstr = (uchar*) es_str2cstr(estr, NULL);
+ if(*bMustFree)
+ es_deleteStr(estr);
+ *bMustFree = 1;
+ return cstr;
+}
+
+rsRetVal
+doExtractField(uchar *str, uchar delim, int matchnbr, uchar **resstr)
+{
+ int iCurrFld;
+ int iLen;
+ uchar *pBuf;
+ uchar *pFld;
+ uchar *pFldEnd;
+ DEFiRet;
+
+ /* first, skip to the field in question */
+ iCurrFld = 1;
+ pFld = str;
+ while(*pFld && iCurrFld < matchnbr) {
+ /* skip fields until the requested field or end of string is found */
+ while(*pFld && (uchar) *pFld != delim)
+ ++pFld; /* skip to field terminator */
+ if(*pFld == delim) {
+ ++pFld; /* eat it */
+ ++iCurrFld;
+ }
+ }
+ dbgprintf("field() field requested %d, field found %d\n", matchnbr, iCurrFld);
+
+ if(iCurrFld == matchnbr) {
+ /* field found, now extract it */
+ /* first of all, we need to find the end */
+ pFldEnd = pFld;
+ while(*pFldEnd && *pFldEnd != delim)
+ ++pFldEnd;
+ --pFldEnd; /* we are already at the delimiter - so we need to
+ * step back a little not to copy it as part of the field. */
+ /* we got our end pointer, now do the copy */
+ iLen = pFldEnd - pFld + 1; /* the +1 is for an actual char, NOT \0! */
+ CHKmalloc(pBuf = MALLOC((iLen + 1) * sizeof(char)));
+ /* now copy */
+ memcpy(pBuf, pFld, iLen);
+ pBuf[iLen] = '\0'; /* terminate it */
+ if(*(pFldEnd+1) != '\0')
+ ++pFldEnd; /* OK, skip again over delimiter char */
+ *resstr = pBuf;
+ } else {
+ ABORT_FINALIZE(RS_RET_FIELD_NOT_FOUND);
}
- *bMustFree = 0;
- return r->d.estr;
+finalize_it:
+ RETiRet;
}
/* Perform a function call. This has been moved out of cnfExprEval in order
@@ -922,8 +1013,13 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr)
int bMustFree;
es_str_t *estr;
char *str;
+ uchar *resStr;
int retval;
struct var r[CNFFUNC_MAX_ARGS];
+ int delim;
+ int matchnbr;
+ struct funcData_prifilt *pPrifilt;
+ rsRetVal localRet;
dbgprintf("rainerscript: executing function id %d\n", func->fID);
switch(func->fID) {
@@ -991,8 +1087,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr)
break;
case CNFFUNC_RE_MATCH:
cnfexprEval(func->expr[0], &r[0], usrptr);
- estr = var2String(&r[0], &bMustFree);
- str = es_str2cstr(estr, NULL);
+ str = (char*) var2CString(&r[0], &bMustFree);
retval = regexp.regexec(func->funcdata, str, 0, NULL, 0);
if(retval == 0)
ret->d.n = 1;
@@ -1003,10 +1098,44 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr)
}
}
ret->datatype = 'N';
- if(bMustFree) es_deleteStr(estr);
+ if(bMustFree) free(str);
free(str);
if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr);
break;
+ case CNFFUNC_FIELD:
+ cnfexprEval(func->expr[0], &r[0], usrptr);
+ cnfexprEval(func->expr[1], &r[1], usrptr);
+ cnfexprEval(func->expr[2], &r[2], usrptr);
+ str = (char*) var2CString(&r[0], &bMustFree);
+ delim = var2Number(&r[1], NULL);
+ matchnbr = var2Number(&r[2], NULL);
+ localRet = doExtractField((uchar*)str, (char) delim, matchnbr, &resStr);
+ if(localRet == RS_RET_OK) {
+ ret->d.estr = es_newStrFromCStr((char*)resStr, strlen((char*)resStr));
+ free(resStr);
+ } else if(localRet == RS_RET_OK) {
+ ret->d.estr = es_newStrFromCStr("***FIELD NOT FOUND***",
+ sizeof("***FIELD NOT FOUND***")-1);
+ } else {
+ ret->d.estr = es_newStrFromCStr("***ERROR in field() FUNCTION***",
+ sizeof("***ERROR in field() FUNCTION***")-1);
+ }
+ ret->datatype = 'S';
+ if(bMustFree) free(str);
+ if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr);
+ if(r[1].datatype == 'S') es_deleteStr(r[1].d.estr);
+ if(r[2].datatype == 'S') es_deleteStr(r[2].d.estr);
+ break;
+ case CNFFUNC_PRIFILT:
+ pPrifilt = (struct funcData_prifilt*) func->funcdata;
+ if( (pPrifilt->pmask[((msg_t*)usrptr)->iFacility] == TABLE_NOPRI) ||
+ ((pPrifilt->pmask[((msg_t*)usrptr)->iFacility]
+ & (1<<((msg_t*)usrptr)->iSeverity)) == 0) )
+ ret->d.n = 0;
+ else
+ ret->d.n = 1;
+ ret->datatype = 'N';
+ break;
default:
if(Debug) {
fname = es_str2cstr(func->fname, NULL);
@@ -1019,6 +1148,64 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr)
}
}
+static inline void
+evalVar(struct cnfvar *var, void *usrptr, struct var *ret)
+{
+ rsRetVal localRet;
+ es_str_t *estr;
+ struct json_object *json;
+
+ if(var->name[0] == '$' && var->name[1] == '!') {
+ /* TODO: unify string libs */
+ estr = es_newStrFromBuf(var->name+1, strlen(var->name)-1);
+ localRet = msgGetCEEPropJSON((msg_t*)usrptr, estr, &json);
+ es_deleteStr(estr);
+ ret->datatype = 'J';
+ ret->d.json = (localRet == RS_RET_OK) ? json : NULL;
+ } else {
+ ret->datatype = 'S';
+ ret->d.estr = cnfGetVar(var->name, usrptr);
+ }
+
+}
+
+/* perform a string comparision operation against a while array. Semantic is
+ * that one one comparison is true, the whole construct is true.
+ * TODO: we can obviously optimize this process. One idea is to
+ * compile a regex, which should work faster than serial comparison.
+ * Note: compiling a regex does NOT work at all. I experimented with that
+ * and it was generally 5 to 10 times SLOWER than what we do here...
+ */
+static int
+evalStrArrayCmp(es_str_t *estr_l, struct cnfarray* ar, int cmpop)
+{
+ int i;
+ int r = 0;
+ for(i = 0 ; (r == 0) && (i < ar->nmemb) ; ++i) {
+ switch(cmpop) {
+ case CMP_EQ:
+ r = es_strcmp(estr_l, ar->arr[i]) == 0;
+ break;
+ case CMP_NE:
+ r = es_strcmp(estr_l, ar->arr[i]) != 0;
+ break;
+ case CMP_STARTSWITH:
+ r = es_strncmp(estr_l, ar->arr[i], es_strlen(ar->arr[i])) == 0;
+ break;
+ case CMP_STARTSWITHI:
+ r = es_strncasecmp(estr_l, ar->arr[i], es_strlen(ar->arr[i])) == 0;
+ break;
+ case CMP_CONTAINS:
+ r = es_strContains(estr_l, ar->arr[i]) != -1;
+ break;
+ case CMP_CONTAINSI:
+ r = es_strCaseContains(estr_l, ar->arr[i]) != -1;
+ break;
+ }
+ }
+ return r;
+}
+
#define FREE_BOTH_RET \
if(r.datatype == 'S') es_deleteStr(r.d.estr); \
if(l.datatype == 'S') es_deleteStr(l.d.estr)
@@ -1030,16 +1217,23 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr)
ret->d.n = var2Number(&l, &convok_l) x var2Number(&r, &convok_r); \
FREE_BOTH_RET
+/* NOTE: array as right-hand argument MUST be handled by user */
#define PREP_TWO_STRINGS \
cnfexprEval(expr->l, &l, usrptr); \
estr_l = var2String(&l, &bMustFree2); \
- cnfexprEval(expr->r, &r, usrptr); \
- estr_r = var2String(&r, &bMustFree)
+ if(expr->r->nodetype == 'S') { \
+ estr_r = ((struct cnfstringval*)expr->r)->estr;\
+ bMustFree = 0; \
+ } else if(expr->r->nodetype != 'A') { \
+ cnfexprEval(expr->r, &r, usrptr); \
+ estr_r = var2String(&r, &bMustFree); \
+ }
#define FREE_TWO_STRINGS \
- if(bMustFree) es_deleteStr(estr_r); \
- if(bMustFree2) es_deleteStr(estr_l); \
- FREE_BOTH_RET
+ if(bMustFree) es_deleteStr(estr_r); \
+ if(expr->r->nodetype != 'A' && r.datatype == 'S') es_deleteStr(r.d.estr); \
+ if(bMustFree2) es_deleteStr(estr_l); \
+ if(l.datatype == 'S') es_deleteStr(l.d.estr)
/* evaluate an expression.
* Note that we try to avoid malloc whenever possible (because of
@@ -1066,23 +1260,34 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr)
* places flagged with "CMP" need to be changed.
*/
case CMP_EQ:
+ /* this is optimized in regard to right param as a PoC for all compOps
+ * So this is a NOT yet the copy template!
+ */
cnfexprEval(expr->l, &l, usrptr);
- cnfexprEval(expr->r, &r, usrptr);
ret->datatype = 'N';
if(l.datatype == 'S') {
- if(r.datatype == 'S') {
- ret->d.n = !es_strcmp(l.d.estr, r.d.estr); /*CMP*/
+ if(expr->r->nodetype == 'S') {
+ ret->d.n = !es_strcmp(l.d.estr, ((struct cnfstringval*)expr->r)->estr); /*CMP*/
+ } else if(expr->r->nodetype == 'A') {
+ ret->d.n = evalStrArrayCmp(l.d.estr, (struct cnfarray*) expr->r, CMP_EQ);
} else {
- n_l = var2Number(&l, &convok_l);
- if(convok_l) {
- ret->d.n = (n_l == r.d.n); /*CMP*/
+ cnfexprEval(expr->r, &r, usrptr);
+ if(r.datatype == 'S') {
+ ret->d.n = !es_strcmp(l.d.estr, r.d.estr); /*CMP*/
} else {
- estr_r = var2String(&r, &bMustFree);
- ret->d.n = !es_strcmp(l.d.estr, estr_r); /*CMP*/
- if(bMustFree) es_deleteStr(estr_r);
+ n_l = var2Number(&l, &convok_l);
+ if(convok_l) {
+ ret->d.n = (n_l == r.d.n); /*CMP*/
+ } else {
+ estr_r = var2String(&r, &bMustFree);
+ ret->d.n = !es_strcmp(l.d.estr, estr_r); /*CMP*/
+ if(bMustFree) es_deleteStr(estr_r);
+ }
}
+ if(r.datatype == 'S') es_deleteStr(r.d.estr);
}
} else {
+ cnfexprEval(expr->r, &r, usrptr);
if(r.datatype == 'S') {
n_r = var2Number(&r, &convok_r);
if(convok_r) {
@@ -1095,24 +1300,31 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr)
} else {
ret->d.n = (l.d.n == r.d.n); /*CMP*/
}
+ if(r.datatype == 'S') es_deleteStr(r.d.estr);
}
- FREE_BOTH_RET;
+ if(l.datatype == 'S') es_deleteStr(l.d.estr);
break;
case CMP_NE:
cnfexprEval(expr->l, &l, usrptr);
cnfexprEval(expr->r, &r, usrptr);
ret->datatype = 'N';
if(l.datatype == 'S') {
- if(r.datatype == 'S') {
- ret->d.n = es_strcmp(l.d.estr, r.d.estr); /*CMP*/
+ if(expr->r->nodetype == 'S') {
+ ret->d.n = es_strcmp(l.d.estr, ((struct cnfstringval*)expr->r)->estr); /*CMP*/
+ } else if(expr->r->nodetype == 'A') {
+ ret->d.n = evalStrArrayCmp(l.d.estr, (struct cnfarray*) expr->r, CMP_NE);
} else {
- n_l = var2Number(&l, &convok_l);
- if(convok_l) {
- ret->d.n = (n_l != r.d.n); /*CMP*/
+ if(r.datatype == 'S') {
+ ret->d.n = es_strcmp(l.d.estr, r.d.estr); /*CMP*/
} else {
- estr_r = var2String(&r, &bMustFree);
- ret->d.n = es_strcmp(l.d.estr, estr_r); /*CMP*/
- if(bMustFree) es_deleteStr(estr_r);
+ n_l = var2Number(&l, &convok_l);
+ if(convok_l) {
+ ret->d.n = (n_l != r.d.n); /*CMP*/
+ } else {
+ estr_r = var2String(&r, &bMustFree);
+ ret->d.n = es_strcmp(l.d.estr, estr_r); /*CMP*/
+ if(bMustFree) es_deleteStr(estr_r);
+ }
}
}
} else {
@@ -1266,25 +1478,45 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr)
case CMP_STARTSWITH:
PREP_TWO_STRINGS;
ret->datatype = 'N';
- ret->d.n = es_strncmp(estr_l, estr_r, estr_r->lenStr) == 0;
+ if(expr->r->nodetype == 'A') {
+ ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_STARTSWITH);
+ bMustFree = 0;
+ } else {
+ ret->d.n = es_strncmp(estr_l, estr_r, estr_r->lenStr) == 0;
+ }
FREE_TWO_STRINGS;
break;
case CMP_STARTSWITHI:
PREP_TWO_STRINGS;
ret->datatype = 'N';
- ret->d.n = es_strncasecmp(estr_l, estr_r, estr_r->lenStr) == 0;
+ if(expr->r->nodetype == 'A') {
+ ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_STARTSWITHI);
+ bMustFree = 0;
+ } else {
+ ret->d.n = es_strncasecmp(estr_l, estr_r, estr_r->lenStr) == 0;
+ }
FREE_TWO_STRINGS;
break;
case CMP_CONTAINS:
PREP_TWO_STRINGS;
ret->datatype = 'N';
- ret->d.n = es_strContains(estr_l, estr_r) != -1;
+ if(expr->r->nodetype == 'A') {
+ ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_CONTAINS);
+ bMustFree = 0;
+ } else {
+ ret->d.n = es_strContains(estr_l, estr_r) != -1;
+ }
FREE_TWO_STRINGS;
break;
case CMP_CONTAINSI:
PREP_TWO_STRINGS;
ret->datatype = 'N';
- ret->d.n = es_strCaseContains(estr_l, estr_r) != -1;
+ if(expr->r->nodetype == 'A') {
+ ret->d.n = evalStrArrayCmp(estr_l, (struct cnfarray*) expr->r, CMP_CONTAINSI);
+ bMustFree = 0;
+ } else {
+ ret->d.n = es_strCaseContains(estr_l, estr_r) != -1;
+ }
FREE_TWO_STRINGS;
break;
case OR:
@@ -1331,9 +1563,27 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr)
ret->datatype = 'S';
ret->d.estr = es_strdup(((struct cnfstringval*)expr)->estr);
break;
+ case 'A':
+ /* if an array is used with "normal" operations, it just evaluates
+ * to its first element.
+ */
+ ret->datatype = 'S';
+ ret->d.estr = es_strdup(((struct cnfarray*)expr)->arr[0]);
+ break;
case 'V':
+ evalVar((struct cnfvar*)expr, usrptr, ret);
+ break;
+ case '&':
+ /* TODO: think about optimization, should be possible ;) */
+ PREP_TWO_STRINGS;
+ if(expr->r->nodetype == 'A') {
+ estr_r = ((struct cnfarray*)expr->r)->arr[0];
+ bMustFree = 0;
+ }
ret->datatype = 'S';
- ret->d.estr = cnfGetVar(((struct cnfvar*)expr)->name, usrptr);
+ ret->d.estr = es_strdup(estr_l);
+ es_addStr(&ret->d.estr, estr_r);
+ FREE_TWO_STRINGS;
break;
case '+':
COMP_NUM_BINOP(+);
@@ -1370,6 +1620,16 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr)
//---------------------------------------------------------
+void
+cnfarrayContentDestruct(struct cnfarray *ar)
+{
+ unsigned short i;
+ for(i = 0 ; i < ar->nmemb ; ++i) {
+ es_deleteStr(ar->arr[i]);
+ }
+ free(ar->arr);
+}
+
static inline void
cnffuncDestruct(struct cnffunc *func)
{
@@ -1381,12 +1641,13 @@ cnffuncDestruct(struct cnffunc *func)
/* some functions require special destruction */
switch(func->fID) {
case CNFFUNC_RE_MATCH:
- regexp.regfree(func->funcdata);
- free(func->funcdata);
- free(func->fname);
+ if(func->funcdata != NULL)
+ regexp.regfree(func->funcdata);
break;
default:break;
}
+ free(func->funcdata);
+ free(func->fname);
}
/* Destruct an expression and all sub-expressions contained in it.
@@ -1409,6 +1670,7 @@ cnfexprDestruct(struct cnfexpr *expr)
case CMP_CONTAINSI:
case OR:
case AND:
+ case '&':
case '+':
case '-':
case '*':
@@ -1432,6 +1694,9 @@ cnfexprDestruct(struct cnfexpr *expr)
case 'F':
cnffuncDestruct((struct cnffunc*)expr);
break;
+ case 'A':
+ cnfarrayContentDestruct((struct cnfarray*)expr);
+ break;
default:break;
}
free(expr);
@@ -1460,13 +1725,39 @@ doIndent(int indent)
for(i = 0 ; i < indent ; ++i)
dbgprintf(" ");
}
+
+static void
+pmaskPrint(uchar *pmask, int indent)
+{
+ int i;
+ doIndent(indent);
+ dbgprintf("pmask: ");
+ for (i = 0; i <= LOG_NFACILITIES; i++)
+ if (pmask[i] == TABLE_NOPRI)
+ dbgprintf(" X ");
+ else
+ dbgprintf("%2X ", pmask[i]);
+ dbgprintf("\n");
+}
+
+static void
+cnfarrayPrint(struct cnfarray *ar, int indent)
+{
+ int i;
+ doIndent(indent); dbgprintf("ARRAY:\n");
+ for(i = 0 ; i < ar->nmemb ; ++i) {
+ doIndent(indent+1);
+ cstrPrint("string '", ar->arr[i]);
+ dbgprintf("'\n");
+ }
+}
+
void
cnfexprPrint(struct cnfexpr *expr, int indent)
{
struct cnffunc *func;
int i;
- //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype);
switch(expr->nodetype) {
case CMP_EQ:
cnfexprPrint(expr->l, indent+1);
@@ -1550,6 +1841,9 @@ cnfexprPrint(struct cnfexpr *expr, int indent)
cstrPrint("string '", ((struct cnfstringval*)expr)->estr);
dbgprintf("'\n");
break;
+ case 'A':
+ cnfarrayPrint((struct cnfarray*)expr, indent);
+ break;
case 'N':
doIndent(indent);
dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val);
@@ -1563,10 +1857,16 @@ cnfexprPrint(struct cnfexpr *expr, int indent)
func = (struct cnffunc*) expr;
cstrPrint("function '", func->fname);
dbgprintf("' (id:%d, params:%hu)\n", func->fID, func->nParams);
+ if(func->fID == CNFFUNC_PRIFILT) {
+ struct funcData_prifilt *pD;
+ pD = (struct funcData_prifilt*) func->funcdata;
+ pmaskPrint(pD->pmask, indent+1);
+ }
for(i = 0 ; i < func->nParams ; ++i) {
cnfexprPrint(func->expr[i], indent+1);
}
break;
+ case '&':
case '+':
case '-':
case '*':
@@ -1580,11 +1880,93 @@ cnfexprPrint(struct cnfexpr *expr, int indent)
cnfexprPrint(expr->r, indent+1);
break;
default:
- dbgprintf("error: unknown nodetype %u\n",
- (unsigned) expr->nodetype);
+ dbgprintf("error: unknown nodetype %u['%c']\n",
+ (unsigned) expr->nodetype, (char) expr->nodetype);
break;
}
}
+void
+cnfstmtPrint(struct cnfstmt *root, int indent)
+{
+ struct cnfstmt *stmt;
+ char *cstr;
+ //dbgprintf("stmt %p, indent %d, type '%c'\n", expr, indent, expr->nodetype);
+ for(stmt = root ; stmt != NULL ; stmt = stmt->next) {
+ switch(stmt->nodetype) {
+ case S_NOP:
+ doIndent(indent); dbgprintf("NOP\n");
+ break;
+ case S_STOP:
+ doIndent(indent); dbgprintf("STOP\n");
+ break;
+ case S_CALL:
+ cstr = es_str2cstr(stmt->d.s_call.name, NULL);
+ doIndent(indent); dbgprintf("CALL [%s]\n", cstr);
+ free(cstr);
+ break;
+ case S_ACT:
+ doIndent(indent); dbgprintf("ACTION %p [%s]\n", stmt->d.act, stmt->printable);
+ break;
+ case S_IF:
+ doIndent(indent); dbgprintf("IF\n");
+ cnfexprPrint(stmt->d.s_if.expr, indent+1);
+ doIndent(indent); dbgprintf("THEN\n");
+ cnfstmtPrint(stmt->d.s_if.t_then, indent+1);
+ if(stmt->d.s_if.t_else != NULL) {
+ doIndent(indent); dbgprintf("ELSE\n");
+ cnfstmtPrint(stmt->d.s_if.t_else, indent+1);
+ }
+ doIndent(indent); dbgprintf("END IF\n");
+ break;
+ case S_SET:
+ doIndent(indent); dbgprintf("SET %s =\n",
+ stmt->d.s_set.varname);
+ cnfexprPrint(stmt->d.s_set.expr, indent+1);
+ doIndent(indent); dbgprintf("END SET\n");
+ break;
+ case S_UNSET:
+ doIndent(indent); dbgprintf("UNSET %s\n",
+ stmt->d.s_unset.varname);
+ break;
+ case S_PRIFILT:
+ doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable);
+ pmaskPrint(stmt->d.s_prifilt.pmask, indent);
+ cnfstmtPrint(stmt->d.s_prifilt.t_then, indent+1);
+ if(stmt->d.s_prifilt.t_else != NULL) {
+ doIndent(indent); dbgprintf("ELSE\n");
+ cnfstmtPrint(stmt->d.s_prifilt.t_else, indent+1);
+ }
+ doIndent(indent); dbgprintf("END PRIFILT\n");
+ break;
+ case S_PROPFILT:
+ doIndent(indent); dbgprintf("PROPFILT\n");
+ doIndent(indent); dbgprintf("\tProperty.: '%s'\n",
+ propIDToName(stmt->d.s_propfilt.propID));
+ if(stmt->d.s_propfilt.propName != NULL) {
+ cstr = es_str2cstr(stmt->d.s_propfilt.propName, NULL);
+ doIndent(indent);
+ dbgprintf("\tCEE-Prop.: '%s'\n", cstr);
+ free(cstr);
+ }
+ doIndent(indent); dbgprintf("\tOperation: ");
+ if(stmt->d.s_propfilt.isNegated)
+ dbgprintf("NOT ");
+ dbgprintf("'%s'\n", getFIOPName(stmt->d.s_propfilt.operation));
+ if(stmt->d.s_propfilt.pCSCompValue != NULL) {
+ doIndent(indent); dbgprintf("\tValue....: '%s'\n",
+ rsCStrGetSzStrNoNULL(stmt->d.s_propfilt.pCSCompValue));
+ }
+ doIndent(indent); dbgprintf("THEN\n");
+ cnfstmtPrint(stmt->d.s_propfilt.t_then, indent+1);
+ doIndent(indent); dbgprintf("END PROPFILT\n");
+ break;
+ default:
+ dbgprintf("error: unknown stmt type %u\n",
+ (unsigned) stmt->nodetype);
+ break;
+ }
+ }
+}
struct cnfnumval*
cnfnumvalNew(long long val)
@@ -1608,6 +1990,52 @@ cnfstringvalNew(es_str_t *estr)
return strval;
}
+/* creates array AND adds first element to it */
+struct cnfarray*
+cnfarrayNew(es_str_t *val)
+{
+ struct cnfarray *ar;
+ if((ar = malloc(sizeof(struct cnfarray))) != NULL) {
+ ar->nodetype = 'A';
+ ar->nmemb = 1;
+ if((ar->arr = malloc(sizeof(es_str_t*))) == NULL) {
+ free(ar);
+ ar = NULL;
+ goto done;
+ }
+ ar->arr[0] = val;
+ }
+done: return ar;
+}
+
+struct cnfarray*
+cnfarrayAdd(struct cnfarray *ar, es_str_t *val)
+{
+ es_str_t **newptr;
+ if((newptr = realloc(ar->arr, (ar->nmemb+1)*sizeof(es_str_t*))) == NULL) {
+ DBGPRINTF("cnfarrayAdd: realloc failed, item ignored, ar->arr=%p\n", ar->arr);
+ goto done;
+ } else {
+ ar->arr = newptr;
+ ar->arr[ar->nmemb] = val;
+ ar->nmemb++;
+ }
+done: return ar;
+}
+
+/* duplicate an array (deep copy) */
+struct cnfarray*
+cnfarrayDup(struct cnfarray *old)
+{
+ int i;
+ struct cnfarray *ar;
+ ar = cnfarrayNew(es_strdup(old->arr[0]));
+ for(i = 1 ; i < old->nmemb ; ++i) {
+ cnfarrayAdd(ar, es_strdup(old->arr[i]));
+ }
+ return ar;
+}
+
struct cnfvar*
cnfvarNew(char *name)
{
@@ -1619,63 +2047,538 @@ cnfvarNew(char *name)
return var;
}
-struct cnfrule *
-cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst)
+struct cnfstmt *
+cnfstmtNew(unsigned s_type)
+{
+ struct cnfstmt* cnfstmt;
+ if((cnfstmt = malloc(sizeof(struct cnfstmt))) != NULL) {
+ cnfstmt->nodetype = s_type;
+ cnfstmt->printable = NULL;
+ cnfstmt->next = NULL;
+ }
+ return cnfstmt;
+}
+
+void
+cnfstmtDestruct(struct cnfstmt *root)
+{
+ struct cnfstmt *stmt, *todel;
+ for(stmt = root ; stmt != NULL ; ) {
+ switch(stmt->nodetype) {
+ case S_NOP:
+ case S_STOP:
+ break;
+ case S_CALL:
+ es_deleteStr(stmt->d.s_call.name);
+ break;
+ case S_ACT:
+ actionDestruct(stmt->d.act);
+ break;
+ case S_IF:
+ cnfexprDestruct(stmt->d.s_if.expr);
+ if(stmt->d.s_if.t_then != NULL) {
+ cnfstmtDestruct(stmt->d.s_if.t_then);
+ }
+ if(stmt->d.s_if.t_else != NULL) {
+ cnfstmtDestruct(stmt->d.s_if.t_else);
+ }
+ break;
+ case S_SET:
+ free(stmt->d.s_set.varname);
+ cnfexprDestruct(stmt->d.s_set.expr);
+ break;
+ case S_UNSET:
+ free(stmt->d.s_set.varname);
+ break;
+ case S_PRIFILT:
+ cnfstmtDestruct(stmt->d.s_prifilt.t_then);
+ cnfstmtDestruct(stmt->d.s_prifilt.t_else);
+ break;
+ case S_PROPFILT:
+ if(stmt->d.s_propfilt.propName != NULL)
+ es_deleteStr(stmt->d.s_propfilt.propName);
+ if(stmt->d.s_propfilt.regex_cache != NULL)
+ rsCStrRegexDestruct(&stmt->d.s_propfilt.regex_cache);
+ if(stmt->d.s_propfilt.pCSCompValue != NULL)
+ cstrDestruct(&stmt->d.s_propfilt.pCSCompValue);
+ cnfstmtDestruct(stmt->d.s_propfilt.t_then);
+ break;
+ default:
+ dbgprintf("error: unknown stmt type during destruct %u\n",
+ (unsigned) stmt->nodetype);
+ break;
+ }
+ free(stmt->printable);
+ todel = stmt;
+ stmt = stmt->next;
+ free(todel);
+ }
+}
+
+struct cnfstmt *
+cnfstmtNewSet(char *var, struct cnfexpr *expr)
+{
+ struct cnfstmt* cnfstmt;
+ if((cnfstmt = cnfstmtNew(S_SET)) != NULL) {
+ cnfstmt->d.s_set.varname = (uchar*) var;
+ cnfstmt->d.s_set.expr = expr;
+ }
+ return cnfstmt;
+}
+
+struct cnfstmt *
+cnfstmtNewCall(es_str_t *name)
+{
+ struct cnfstmt* cnfstmt;
+ if((cnfstmt = cnfstmtNew(S_CALL)) != NULL) {
+ cnfstmt->d.s_call.name = name;
+ }
+ return cnfstmt;
+}
+
+struct cnfstmt *
+cnfstmtNewUnset(char *var)
+{
+ struct cnfstmt* cnfstmt;
+ if((cnfstmt = cnfstmtNew(S_UNSET)) != NULL) {
+ cnfstmt->d.s_unset.varname = (uchar*) var;
+ }
+ return cnfstmt;
+}
+
+struct cnfstmt *
+cnfstmtNewContinue(void)
+{
+ return cnfstmtNew(S_NOP);
+}
+
+struct cnfstmt *
+cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then)
+{
+ struct cnfstmt* cnfstmt;
+ if((cnfstmt = cnfstmtNew(S_PRIFILT)) != NULL) {
+ cnfstmt->printable = (uchar*)prifilt;
+ cnfstmt->d.s_prifilt.t_then = t_then;
+ cnfstmt->d.s_prifilt.t_else = NULL;
+ DecodePRIFilter((uchar*)prifilt, cnfstmt->d.s_prifilt.pmask);
+ }
+ return cnfstmt;
+}
+
+struct cnfstmt *
+cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then)
{
- struct cnfrule* cnfrule;
- if((cnfrule = malloc(sizeof(struct cnfrule))) != NULL) {
- cnfrule->nodetype = 'R';
- cnfrule->filttype = filttype;
- cnfrule->actlst = cnfactlstReverse(actlst);
+ struct cnfstmt* cnfstmt;
+ rsRetVal lRet;
+ if((cnfstmt = cnfstmtNew(S_PROPFILT)) != NULL) {
+ cnfstmt->printable = (uchar*)propfilt;
+ cnfstmt->d.s_propfilt.t_then = t_then;
+ cnfstmt->d.s_propfilt.propName = NULL;
+ cnfstmt->d.s_propfilt.regex_cache = NULL;
+ cnfstmt->d.s_propfilt.pCSCompValue = NULL;
+ lRet = DecodePropFilter((uchar*)propfilt, cnfstmt);
+ }
+ return cnfstmt;
+}
+
+struct cnfstmt *
+cnfstmtNewAct(struct nvlst *lst)
+{
+ struct cnfstmt* cnfstmt;
+ char namebuf[256];
+ rsRetVal localRet;
+ if((cnfstmt = cnfstmtNew(S_ACT)) == NULL)
+ goto done;
+ localRet = actionNewInst(lst, &cnfstmt->d.act);
+ if(localRet == RS_RET_OK_WARN) {
+ parser_errmsg("warnings occured in file '%s' around line %d",
+ cnfcurrfn, yylineno);
+ } else if(localRet != RS_RET_OK) {
+ parser_errmsg("errors occured in file '%s' around line %d",
+ cnfcurrfn, yylineno);
+ cnfstmt->nodetype = S_NOP; /* disable action! */
+ goto done;
+ }
+ snprintf(namebuf, sizeof(namebuf)-1, "action(type=\"%s\" ...)",
+ modGetName(cnfstmt->d.act->pMod));
+ namebuf[255] = '\0'; /* be on safe side */
+ cnfstmt->printable = (uchar*)strdup(namebuf);
+ nvlstChkUnused(lst);
+ nvlstDestruct(lst);
+done: return cnfstmt;
+}
+
+struct cnfstmt *
+cnfstmtNewLegaAct(char *actline)
+{
+ struct cnfstmt* cnfstmt;
+ rsRetVal localRet;
+ if((cnfstmt = cnfstmtNew(S_ACT)) == NULL)
+ goto done;
+ cnfstmt->printable = (uchar*)strdup((char*)actline);
+ localRet = cflineDoAction(loadConf, (uchar**)&actline, &cnfstmt->d.act);
+ if(localRet != RS_RET_OK && localRet != RS_RET_OK_WARN) {
+ parser_errmsg("%s occured in file '%s' around line %d",
+ (localRet == RS_RET_OK_WARN) ? "warnings" : "errors",
+ cnfcurrfn, yylineno);
+ if(localRet != RS_RET_OK_WARN) {
+ cnfstmt->nodetype = S_NOP; /* disable action! */
+ goto done;
+ }
+ }
+done: return cnfstmt;
+}
+
+
+/* returns 1 if the two expressions are constants, 0 otherwise
+ * if both are constants, the expression subtrees are destructed
+ * (this is an aid for constant folding optimizing)
+ */
+static int
+getConstNumber(struct cnfexpr *expr, long long *l, long long *r)
+{
+ int ret = 0;
+ cnfexprOptimize(expr->l);
+ cnfexprOptimize(expr->r);
+ if(expr->l->nodetype == 'N') {
+ if(expr->r->nodetype == 'N') {
+ ret = 1;
+ *l = ((struct cnfnumval*)expr->l)->val;
+ *r = ((struct cnfnumval*)expr->r)->val;
+ cnfexprDestruct(expr->l);
+ cnfexprDestruct(expr->r);
+ } else if(expr->r->nodetype == 'S') {
+ ret = 1;
+ *l = ((struct cnfnumval*)expr->l)->val;
+ *r = es_str2num(((struct cnfstringval*)expr->r)->estr, NULL);
+ cnfexprDestruct(expr->l);
+ cnfexprDestruct(expr->r);
+ }
+ } else if(expr->l->nodetype == 'S') {
+ if(expr->r->nodetype == 'N') {
+ ret = 1;
+ *l = es_str2num(((struct cnfstringval*)expr->l)->estr, NULL);
+ *r = ((struct cnfnumval*)expr->r)->val;
+ cnfexprDestruct(expr->l);
+ cnfexprDestruct(expr->r);
+ } else if(expr->r->nodetype == 'S') {
+ ret = 1;
+ *l = es_str2num(((struct cnfstringval*)expr->l)->estr, NULL);
+ *r = es_str2num(((struct cnfstringval*)expr->r)->estr, NULL);
+ cnfexprDestruct(expr->l);
+ cnfexprDestruct(expr->r);
+ }
+ }
+ return ret;
+}
+
+
+/* constant folding for string concatenation */
+static inline void
+constFoldConcat(struct cnfexpr *expr)
+{
+ es_str_t *estr;
+ cnfexprOptimize(expr->l);
+ cnfexprOptimize(expr->r);
+ if(expr->l->nodetype == 'S') {
+ if(expr->r->nodetype == 'S') {
+ estr = ((struct cnfstringval*)expr->l)->estr;
+ ((struct cnfstringval*)expr->l)->estr = NULL;
+ es_addStr(&estr, ((struct cnfstringval*)expr->r)->estr);
+ cnfexprDestruct(expr->l);
+ cnfexprDestruct(expr->r);
+ expr->nodetype = 'S';
+ ((struct cnfstringval*)expr)->estr = estr;
+ } else if(expr->r->nodetype == 'N') {
+ es_str_t *numstr;
+ estr = ((struct cnfstringval*)expr->l)->estr;
+ ((struct cnfstringval*)expr->l)->estr = NULL;
+ numstr = es_newStrFromNumber(((struct cnfnumval*)expr->r)->val);
+ es_addStr(&estr, numstr);
+ es_deleteStr(numstr);
+ cnfexprDestruct(expr->l);
+ cnfexprDestruct(expr->r);
+ expr->nodetype = 'S';
+ ((struct cnfstringval*)expr)->estr = estr;
+ }
+ } else if(expr->l->nodetype == 'N') {
+ if(expr->r->nodetype == 'S') {
+ estr = es_newStrFromNumber(((struct cnfnumval*)expr->l)->val);
+ es_addStr(&estr, ((struct cnfstringval*)expr->r)->estr);
+ cnfexprDestruct(expr->l);
+ cnfexprDestruct(expr->r);
+ expr->nodetype = 'S';
+ ((struct cnfstringval*)expr)->estr = estr;
+ } else if(expr->r->nodetype == 'S') {
+ es_str_t *numstr;
+ estr = es_newStrFromNumber(((struct cnfnumval*)expr->l)->val);
+ numstr = es_newStrFromNumber(((struct cnfnumval*)expr->r)->val);
+ es_addStr(&estr, numstr);
+ es_deleteStr(numstr);
+ cnfexprDestruct(expr->l);
+ cnfexprDestruct(expr->r);
+ expr->nodetype = 'S';
+ ((struct cnfstringval*)expr)->estr = estr;
+ }
}
- return cnfrule;
}
+
+/* (recursively) optimize an expression */
void
-cnfrulePrint(struct cnfrule *rule)
+cnfexprOptimize(struct cnfexpr *expr)
{
- dbgprintf("------ start rule %p:\n", rule);
- dbgprintf("%s: ", cnfFiltType2str(rule->filttype));
- switch(rule->filttype) {
- case CNFFILT_NONE:
+ long long ln, rn;
+ struct cnfexpr *exprswap;
+
+ dbgprintf("optimize expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype);
+ switch(expr->nodetype) {
+ case '&':
+ constFoldConcat(expr);
+ break;
+ case '+':
+ if(getConstNumber(expr, &ln, &rn)) {
+ expr->nodetype = 'N';
+ ((struct cnfnumval*)expr)->val = ln + rn;
+ }
break;
- case CNFFILT_PRI:
- case CNFFILT_PROP:
- dbgprintf("%s\n", rule->filt.s);
+ case '-':
+ if(getConstNumber(expr, &ln, &rn)) {
+ expr->nodetype = 'N';
+ ((struct cnfnumval*)expr)->val = ln - rn;
+ }
break;
- case CNFFILT_SCRIPT:
- dbgprintf("\n");
- cnfexprPrint(rule->filt.expr, 0);
+ case '*':
+ if(getConstNumber(expr, &ln, &rn)) {
+ expr->nodetype = 'N';
+ ((struct cnfnumval*)expr)->val = ln * rn;
+ }
+ break;
+ case '/':
+ if(getConstNumber(expr, &ln, &rn)) {
+ expr->nodetype = 'N';
+ ((struct cnfnumval*)expr)->val = ln / rn;
+ }
+ break;
+ case '%':
+ if(getConstNumber(expr, &ln, &rn)) {
+ expr->nodetype = 'N';
+ ((struct cnfnumval*)expr)->val = ln % rn;
+ }
+ break;
+ case CMP_NE:
+ case CMP_EQ:
+ if(expr->l->nodetype == 'A') {
+ if(expr->r->nodetype == 'A') {
+ parser_errmsg("warning: '==' or '<>' "
+ "comparison of two constant string "
+ "arrays makes no sense");
+ } else { /* swap for simpler execution step */
+ exprswap = expr->l;
+ expr->l = expr->r;
+ expr->r = exprswap;
+ }
+ }
+ default:/* nodetype we cannot optimize */
break;
}
- cnfactlstPrint(rule->actlst);
- dbgprintf("------ end rule %p\n", rule);
+
}
-/* note: the sysline itself was already freed during processing
- * and as such MUST NOT be freed again!
+/* removes NOPs from a statement list and returns the
+ * first non-NOP entry.
*/
-void
-cnfcfsyslinelstDestruct(struct cnfcfsyslinelst *cfslst)
+static inline struct cnfstmt *
+removeNOPs(struct cnfstmt *root)
{
- struct cnfcfsyslinelst *toDel;
- while(cfslst != NULL) {
- toDel = cfslst;
- cfslst = cfslst->next;
- free(toDel);
+ struct cnfstmt *stmt, *toDel, *prevstmt = NULL;
+ struct cnfstmt *newRoot = NULL;
+
+ if(root == NULL) goto done;
+ stmt = root;
+ while(stmt != NULL) {
+ if(stmt->nodetype == S_NOP) {
+ if(prevstmt != NULL)
+ /* end chain, is rebuild if more non-NOPs follow */
+ prevstmt->next = NULL;
+ toDel = stmt;
+ stmt = stmt->next;
+ cnfstmtDestruct(toDel);
+ } else {
+ if(newRoot == NULL)
+ newRoot = stmt;
+ if(prevstmt != NULL)
+ prevstmt->next = stmt;
+ prevstmt = stmt;
+ stmt = stmt->next;
+ }
}
+done: return newRoot;
}
-void
-cnfruleDestruct(struct cnfrule *rule)
+
+static inline void
+cnfstmtOptimizeIf(struct cnfstmt *stmt)
+{
+ struct cnfstmt *t_then, *t_else;
+ struct cnfexpr *expr;
+ struct cnffunc *func;
+ struct funcData_prifilt *prifilt;
+
+ expr = stmt->d.s_if.expr;
+ cnfexprOptimize(expr);
+ stmt->d.s_if.t_then = removeNOPs(stmt->d.s_if.t_then);
+ stmt->d.s_if.t_else = removeNOPs(stmt->d.s_if.t_else);
+ cnfstmtOptimize(stmt->d.s_if.t_then);
+ cnfstmtOptimize(stmt->d.s_if.t_else);
+
+ if(stmt->d.s_if.expr->nodetype == 'F') {
+ func = (struct cnffunc*)expr;
+ if(func->fID == CNFFUNC_PRIFILT) {
+ DBGPRINTF("optimizer: change IF to PRIFILT\n");
+ t_then = stmt->d.s_if.t_then;
+ t_else = stmt->d.s_if.t_else;
+ stmt->nodetype = S_PRIFILT;
+ prifilt = (struct funcData_prifilt*) func->funcdata;
+ memcpy(stmt->d.s_prifilt.pmask, prifilt->pmask,
+ sizeof(prifilt->pmask));
+ stmt->d.s_prifilt.t_then = t_then;
+ stmt->d.s_prifilt.t_else = t_else;
+ stmt->printable = (uchar*)
+ es_str2cstr(((struct cnfstringval*)func->expr[0])->estr, NULL);
+ cnfexprDestruct(expr);
+ cnfstmtOptimizePRIFilt(stmt);
+ }
+ }
+}
+
+static inline void
+cnfstmtOptimizeAct(struct cnfstmt *stmt)
+{
+ action_t *pAct;
+
+ pAct = stmt->d.act;
+ if(!strcmp((char*)modGetName(pAct->pMod), "builtin:omdiscard")) {
+ DBGPRINTF("optimizer: replacing omdiscard by STOP\n");
+ actionDestruct(stmt->d.act);
+ stmt->nodetype = S_STOP;
+ }
+}
+
+static void
+cnfstmtOptimizePRIFilt(struct cnfstmt *stmt)
+{
+ int i;
+ int isAlways = 1;
+ struct cnfstmt *subroot, *last;
+
+ stmt->d.s_prifilt.t_then = removeNOPs(stmt->d.s_prifilt.t_then);
+ cnfstmtOptimize(stmt->d.s_prifilt.t_then);
+
+ for(i = 0; i <= LOG_NFACILITIES; i++)
+ if(stmt->d.s_prifilt.pmask[i] != 0xff) {
+ isAlways = 0;
+ break;
+ }
+ if(!isAlways)
+ goto done;
+
+ DBGPRINTF("optimizer: removing always-true PRIFILT %p\n", stmt);
+ if(stmt->d.s_prifilt.t_else != NULL) {
+ parser_errmsg("error: always-true PRI filter has else part!\n");
+ cnfstmtDestruct(stmt->d.s_prifilt.t_else);
+ }
+ free(stmt->printable);
+ stmt->printable = NULL;
+ subroot = stmt->d.s_prifilt.t_then;
+ if(subroot == NULL) {
+ /* very strange, we set it to NOP, best we can do
+ * This case is NOT expected in practice
+ */
+ stmt->nodetype = S_NOP;
+ goto done;
+ }
+ for(last = subroot ; last->next != NULL ; last = last->next)
+ /* find last node in subtree */;
+ last->next = stmt->next;
+ memcpy(stmt, subroot, sizeof(struct cnfstmt));
+ free(subroot);
+
+done: return;
+}
+
+/* we abuse "optimize" a bit. Actually, we obtain a ruleset pointer, as
+ * all rulesets are only known later in the process (now!).
+ */
+static void
+cnfstmtOptimizeCall(struct cnfstmt *stmt)
{
- if( rule->filttype == CNFFILT_PRI
- || rule->filttype == CNFFILT_PROP)
- free(rule->filt.s);
- cnfactlstDestruct(rule->actlst);
- free(rule);
+ ruleset_t *pRuleset;
+ rsRetVal localRet;
+ uchar *rsName;
+
+ rsName = (uchar*) es_str2cstr(stmt->d.s_call.name, NULL);
+ localRet = rulesetGetRuleset(loadConf, &pRuleset, rsName);
+ if(localRet != RS_RET_OK) {
+ /* in that case, we accept that a NOP will "survive" */
+ parser_errmsg("ruleset '%s' cannot be found\n", rsName);
+ es_deleteStr(stmt->d.s_call.name);
+ stmt->nodetype = S_NOP;
+ goto done;
+ }
+ DBGPRINTF("CALL obtained ruleset ptr %p for ruleset %s\n", pRuleset, rsName);
+ stmt->d.s_call.stmt = pRuleset->root;
+done:
+ free(rsName);
+ return;
+}
+/* (recursively) optimize a statement */
+void
+cnfstmtOptimize(struct cnfstmt *root)
+{
+ struct cnfstmt *stmt;
+ if(root == NULL) goto done;
+ for(stmt = root ; stmt != NULL ; stmt = stmt->next) {
+dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype);
+ switch(stmt->nodetype) {
+ case S_IF:
+ cnfstmtOptimizeIf(stmt);
+ break;
+ case S_PRIFILT:
+ cnfstmtOptimizePRIFilt(stmt);
+ break;
+ case S_PROPFILT:
+ stmt->d.s_propfilt.t_then = removeNOPs(stmt->d.s_propfilt.t_then);
+ cnfstmtOptimize(stmt->d.s_propfilt.t_then);
+ break;
+ case S_SET:
+ cnfexprOptimize(stmt->d.s_set.expr);
+ break;
+ case S_ACT:
+ cnfstmtOptimizeAct(stmt);
+ break;
+ case S_CALL:
+ cnfstmtOptimizeCall(stmt);
+ break;
+ case S_STOP:
+ if(stmt->next != NULL)
+ parser_errmsg("STOP is followed by unreachable statements!\n");
+ break;
+ case S_UNSET: /* nothing to do */
+ break;
+ case S_NOP:
+ DBGPRINTF("optimizer error: we see a NOP, how come?\n");
+ break;
+ default:
+ dbgprintf("error: unknown stmt type %u during optimizer run\n",
+ (unsigned) stmt->nodetype);
+ break;
+ }
+ }
+done: return;
}
+
struct cnffparamlst *
cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next)
{
@@ -1736,6 +2639,20 @@ funcName2ID(es_str_t *fname, unsigned short nParams)
return CNFFUNC_INVALID;
}
return CNFFUNC_RE_MATCH;
+ } else if(!es_strbufcmp(fname, (unsigned char*)"field", sizeof("field") - 1)) {
+ if(nParams != 3) {
+ parser_errmsg("number of parameters for field() must be three "
+ "but is %d.", nParams);
+ return CNFFUNC_INVALID;
+ }
+ return CNFFUNC_FIELD;
+ } else if(!es_strbufcmp(fname, (unsigned char*)"prifilt", sizeof("prifilt") - 1)) {
+ if(nParams != 1) {
+ parser_errmsg("number of parameters for prifilt() must be one "
+ "but is %d.", nParams);
+ return CNFFUNC_INVALID;
+ }
+ return CNFFUNC_PRIFILT;
} else {
return CNFFUNC_INVALID;
}
@@ -1776,6 +2693,29 @@ finalize_it:
RETiRet;
}
+
+static inline rsRetVal
+initFunc_prifilt(struct cnffunc *func)
+{
+ struct funcData_prifilt *pData;
+ uchar *cstr;
+ DEFiRet;
+
+ func->funcdata = NULL;
+ if(func->expr[0]->nodetype != 'S') {
+ parser_errmsg("param 1 of prifilt() must be a constant string");
+ FINALIZE;
+ }
+
+ CHKmalloc(pData = calloc(1, sizeof(struct funcData_prifilt)));
+ func->funcdata = pData;
+ cstr = (uchar*)es_str2cstr(((struct cnfstringval*) func->expr[0])->estr, NULL);
+ CHKiRet(DecodePRIFilter(cstr, pData->pmask));
+ free(cstr);
+finalize_it:
+ RETiRet;
+}
+
struct cnffunc *
cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst)
{
@@ -1793,6 +2733,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst)
func->nodetype = 'F';
func->fname = fname;
func->nParams = nParams;
+ func->funcdata = NULL;
func->fID = funcName2ID(fname, nParams);
/* shuffle params over to array (access speed!) */
param = paramlst;
@@ -1808,6 +2749,9 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst)
/* need to compile the regexp in param 2, so this MUST be a constant */
initFunc_re_match(func);
break;
+ case CNFFUNC_PRIFILT:
+ initFunc_prifilt(func);
+ break;
default:break;
}
}
@@ -1866,8 +2810,16 @@ cnfDoInclude(char *name)
void
varDelete(struct var *v)
{
- if(v->datatype == 'S')
+ switch(v->datatype) {
+ case 'S':
es_deleteStr(v->d.estr);
+ break;
+ case 'A':
+ cnfarrayContentDestruct(v->d.ar);
+ free(v->d.ar);
+ break;
+ default:break;
+ }
}
void
@@ -1875,7 +2827,9 @@ cnfparamvalsDestruct(struct cnfparamvals *paramvals, struct cnfparamblk *blk)
{
int i;
for(i = 0 ; i < blk->nParams ; ++i) {
- varDelete(&paramvals[i].val);
+ if(paramvals[i].bUsed) {
+ varDelete(&paramvals[i].val);
+ }
}
free(paramvals);
}
@@ -1908,6 +2862,15 @@ cstrPrint(char *text, es_str_t *estr)
free(str);
}
+char *
+rmLeadingSpace(char *s)
+{
+ char *p;
+ for(p = s ; *p && isspace(*p) ; ++p)
+ ;
+ return(p);
+}
+
/* init must be called once before any parsing of the script files start */
rsRetVal
initRainerscript(void)