diff options
Diffstat (limited to 'template.c')
-rw-r--r-- | template.c | 328 |
1 files changed, 238 insertions, 90 deletions
@@ -44,6 +44,7 @@ #include "errmsg.h" #include "strgen.h" #include "rsconf.h" +#include "msg.h" #include "unicode-helper.h" /* static data */ @@ -54,9 +55,10 @@ DEFobjCurrIf(strgen) /* tables for interfacing with the v6 config system */ static struct cnfparamdescr cnfparamdescr[] = { { "name", eCmdHdlrString, 1 }, - { "type", eCmdHdlrString, 0 }, + { "type", eCmdHdlrString, 1 }, { "string", eCmdHdlrString, 0 }, { "plugin", eCmdHdlrString, 0 }, + { "subtree", eCmdHdlrString, 0 }, { "option.stdsql", eCmdHdlrBinary, 0 }, { "option.sql", eCmdHdlrBinary, 0 }, { "option.json", eCmdHdlrBinary, 0 } @@ -77,6 +79,7 @@ static struct cnfparamdescr cnfparamdescrProperty[] = { { "format", eCmdHdlrString, 0 }, { "position.from", eCmdHdlrInt, 0 }, { "position.to", eCmdHdlrInt, 0 }, + { "position.relativetoend", eCmdHdlrBinary, 0 }, { "field.number", eCmdHdlrInt, 0 }, { "field.delimiter", eCmdHdlrInt, 0 }, { "regex.expression", eCmdHdlrString, 0 }, @@ -139,14 +142,16 @@ finalize_it: * offers big performance improvements. * rewritten 2009-06-19 rgerhards */ -rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar **ppBuf, size_t *pLenBuf) +rsRetVal +tplToString(struct template *pTpl, msg_t *pMsg, uchar **ppBuf, size_t *pLenBuf, + struct syslogTime *ttNow) { DEFiRet; struct templateEntry *pTpe; size_t iBuf; unsigned short bMustBeFreed = 0; uchar *pVal; - size_t iLenVal = 0; + rs_size_t iLenVal = 0; assert(pTpl != NULL); assert(pMsg != NULL); @@ -158,6 +163,23 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar **ppBuf, size_t * FINALIZE; } + if(pTpl->subtree != NULL) { + /* only a single CEE subtree must be provided */ + /* note: we could optimize the code below, however, this is + * not worth the effort, as this passing mode is not expected + * in subtree mode and so most probably only used for debug & test. + */ + getCEEPropVal(pMsg, pTpl->subtree, &pVal, &iLenVal, &bMustBeFreed); + if(iLenVal >= (rs_size_t)*pLenBuf) /* we reserve one char for the final \0! */ + CHKiRet(ExtendBuf(ppBuf, pLenBuf, iLenVal + 1)); + memcpy(*ppBuf, pVal, iLenVal+1); + if(bMustBeFreed) + free(pVal); + FINALIZE; + } + + /* we have a "regular" template with template entries */ + /* loop through the template. We obtain one value * and copy it over to our dynamic string buffer. Then, we * free the obtained value (if requested). We continue this @@ -172,7 +194,8 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar **ppBuf, size_t * bMustBeFreed = 0; } else if(pTpe->eEntryType == FIELD) { pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, - pTpe->data.field.propName, &iLenVal, &bMustBeFreed); + pTpe->data.field.propName, &iLenVal, + &bMustBeFreed, ttNow); /* we now need to check if we should use SQL option. In this case, * we must go over the generated string and escape '\'' characters. * rgerhards, 2005-09-22: the option values below look somewhat misplaced, @@ -226,13 +249,14 @@ finalize_it: * is indicated by a NULL pointer. * rgerhards, 2009-04-03 */ -rsRetVal tplToArray(struct template *pTpl, msg_t *pMsg, uchar*** ppArr) +rsRetVal +tplToArray(struct template *pTpl, msg_t *pMsg, uchar*** ppArr, struct syslogTime *ttNow) { DEFiRet; struct templateEntry *pTpe; uchar **pArr; int iArr; - size_t propLen; + rs_size_t propLen; unsigned short bMustBeFreed; uchar *pVal; @@ -240,11 +264,24 @@ rsRetVal tplToArray(struct template *pTpl, msg_t *pMsg, uchar*** ppArr) assert(pMsg != NULL); assert(ppArr != NULL); + if(pTpl->subtree) { + /* Note: this mode is untested, as there is no official plugin + * using array passing, so I simply could not test it. + */ + CHKmalloc(pArr = calloc(2, sizeof(uchar*))); + getCEEPropVal(pMsg, pTpl->subtree, &pVal, &propLen, &bMustBeFreed); + if(bMustBeFreed) { /* if it must be freed, it is our own private copy... */ + pArr[0] = pVal; /* ... so we can use it! */ + } else { + CHKmalloc(pArr[0] = (uchar*)strdup((char*) pVal)); + } + FINALIZE; + } + /* loop through the template. We obtain one value, create a * private copy (if necessary), add it to the string array * and then on to the next until we have processed everything. */ - CHKmalloc(pArr = calloc(pTpl->tpenElements + 1, sizeof(uchar*))); iArr = 0; @@ -254,7 +291,8 @@ rsRetVal tplToArray(struct template *pTpl, msg_t *pMsg, uchar*** ppArr) CHKmalloc(pArr[iArr] = (uchar*)strdup((char*) pTpe->data.constant.pConstant)); } else if(pTpe->eEntryType == FIELD) { pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, - pTpe->data.field.propName, &propLen, &bMustBeFreed); + pTpe->data.field.propName, &propLen, + &bMustBeFreed, ttNow); if(bMustBeFreed) { /* if it must be freed, it is our own private copy... */ pArr[iArr] = pVal; /* ... so we can use it! */ } else { @@ -277,15 +315,28 @@ finalize_it: * tpltoString(). * rgerhards, 2012-08-29 */ -rsRetVal tplToJSON(struct template *pTpl, msg_t *pMsg, struct json_object **pjson) +rsRetVal +tplToJSON(struct template *pTpl, msg_t *pMsg, struct json_object **pjson, struct syslogTime *ttNow) { struct templateEntry *pTpe; - size_t propLen; + rs_size_t propLen; unsigned short bMustBeFreed; uchar *pVal; struct json_object *json, *jsonf; + rsRetVal localRet; DEFiRet; + if(pTpl->subtree != NULL){ + localRet = jsonFind(pMsg, pTpl->subtree, pjson); + if(*pjson == NULL) { + /* we need to have a root object! */ + *pjson = json_object_new_object(); + } else { + json_object_get(*pjson); /* inc refcount */ + } + FINALIZE; + } + json = json_object_new_object(); for(pTpe = pTpl->pEntryRoot ; pTpe != NULL ; pTpe = pTpe->pNext) { if(pTpe->eEntryType == CONSTANT) { @@ -294,19 +345,34 @@ rsRetVal tplToJSON(struct template *pTpl, msg_t *pMsg, struct json_object **pjso jsonf = json_object_new_string((char*) pTpe->data.constant.pConstant); json_object_object_add(json, (char*)pTpe->fieldName, jsonf); } else if(pTpe->eEntryType == FIELD) { - pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, - pTpe->data.field.propName, &propLen, &bMustBeFreed); - if(pTpe->data.field.options.bMandatory || propLen > 0) { - jsonf = json_object_new_string_len((char*)pVal, propLen); - json_object_object_add(json, (char*)pTpe->fieldName, jsonf); - } - if(bMustBeFreed) { /* json-c makes its own private copy! */ - free(pVal); + if(pTpe->data.field.propid == PROP_CEE) { + localRet = msgGetCEEPropJSON(pMsg, pTpe->data.field.propName, &jsonf); + if(localRet == RS_RET_OK) { + json_object_object_add(json, (char*)pTpe->fieldName, json_object_get(jsonf)); + } else { + DBGPRINTF("tplToJSON: error %d looking up property\n", + localRet); + if(pTpe->data.field.options.bMandatory) { + json_object_object_add(json, (char*)pTpe->fieldName, NULL); + } + } + } else { + pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, + pTpe->data.field.propName, &propLen, + &bMustBeFreed, ttNow); + if(pTpe->data.field.options.bMandatory || propLen > 0) { + jsonf = json_object_new_string_len((char*)pVal, propLen); + json_object_object_add(json, (char*)pTpe->fieldName, jsonf); + } + if(bMustBeFreed) { /* json-c makes its own private copy! */ + free(pVal); + } } } } - *pjson = (iRet == RS_RET_OK) ? json : NULL; + +finalize_it: RETiRet; } @@ -364,7 +430,7 @@ static void doEmergencyEscape(register uchar *p, int mode) * 2005-09-22 rgerhards */ rsRetVal -doEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int mode) +doEscape(uchar **pp, rs_size_t *pLen, unsigned short *pbMustBeFreed, int mode) { DEFiRet; uchar *p = NULL; @@ -487,14 +553,20 @@ tplConstruct(rsconf_t *conf) /* helper to tplAddLine. Parses a constant and generates * the necessary structure. - * returns: 0 - ok, 1 - failure + * Paramter "bDoEscapes" is to support legacy vs. v6+ config system. In + * legacy, we must do escapes ourselves, whereas v6+ passes in already + * escaped strings (which we are NOT permitted to further escape, this would + * cause invalid result strings!). Note: if escapes are not permitted, + * quotes (") are just a regular character and do NOT terminate the constant! */ -static int do_Constant(unsigned char **pp, struct template *pTpl) +static rsRetVal +do_Constant(unsigned char **pp, struct template *pTpl, int bDoEscapes) { register unsigned char *p; cstr_t *pStrB; struct templateEntry *pTpe; int i; + DEFiRet; assert(pp != NULL); assert(*pp != NULL); @@ -502,13 +574,12 @@ static int do_Constant(unsigned char **pp, struct template *pTpl) p = *pp; - if(cstrConstruct(&pStrB) != RS_RET_OK) - return 1; + CHKiRet(cstrConstruct(&pStrB)); /* process the message and expand escapes * (additional escapes can be added here if needed) */ - while(*p && *p != '%' && *p != '\"') { - if(*p == '\\') { + while(*p && *p != '%' && !(bDoEscapes && *p == '\"')) { + if(bDoEscapes && *p == '\\') { switch(*++p) { case '\0': /* the best we can do - it's invalid anyhow... */ @@ -557,7 +628,7 @@ static int do_Constant(unsigned char **pp, struct template *pTpl) if((pTpe = tpeConstruct(pTpl)) == NULL) { rsCStrDestruct(&pStrB); - return 1; + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); } pTpe->eEntryType = CONSTANT; cstrFinalize(pStrB); @@ -567,12 +638,12 @@ static int do_Constant(unsigned char **pp, struct template *pTpl) * 2005-09-09 rgerhards */ pTpe->data.constant.iLenConstant = rsCStrLen(pStrB); - if(cstrConvSzStrAndDestruct(pStrB, &pTpe->data.constant.pConstant, 0) != RS_RET_OK) - return 1; + CHKiRet(cstrConvSzStrAndDestruct(pStrB, &pTpe->data.constant.pConstant, 0)); *pp = p; - return 0; +finalize_it: + RETiRet; } @@ -642,6 +713,8 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe) pTpe->data.field.options.bSecPathDrop = 1; } else if(!strcmp((char*)Buf, "secpath-replace")) { pTpe->data.field.options.bSecPathReplace = 1; + } else if(!strcmp((char*)Buf, "pos-end-relative")) { + pTpe->data.field.options.bFromPosEndRelative = 1; } else if(!strcmp((char*)Buf, "csv")) { if(pTpe->data.field.options.bJSON || pTpe->data.field.options.bJSONf) { errmsg.LogError(0, NO_ERRCODE, "error: can only specify " @@ -677,11 +750,11 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe) /* helper to tplAddLine. Parses a parameter and generates * the necessary structure. - * returns: 0 - ok, 1 - failure */ -static int do_Parameter(unsigned char **pp, struct template *pTpl) +static rsRetVal +do_Parameter(uchar **pp, struct template *pTpl) { - unsigned char *p; + uchar *p; cstr_t *pStrProp; cstr_t *pStrField = NULL; struct templateEntry *pTpe; @@ -693,21 +766,15 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) unsigned char *regex_char; unsigned char *regex_end; #endif + DEFiRet; assert(pp != NULL); assert(*pp != NULL); assert(pTpl != NULL); - p = (unsigned char*) *pp; - - if(cstrConstruct(&pStrProp) != RS_RET_OK) - return 1; - - if((pTpe = tpeConstruct(pTpl)) == NULL) { - /* TODO: add handler */ - dbgprintf("Could not allocate memory for template parameter!\n"); - return 1; - } + p = (uchar*) *pp; + CHKiRet(cstrConstruct(&pStrProp)); + CHKmalloc(pTpe = tpeConstruct(pTpl)); pTpe->eEntryType = FIELD; while(*p && *p != '%' && *p != ':') { @@ -719,19 +786,22 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) cstrFinalize(pStrProp); if(propNameToID(pStrProp, &pTpe->data.field.propid) != RS_RET_OK) { + errmsg.LogError(0, RS_RET_TPL_INVLD_PROP, "template '%s': invalid parameter '%s'", + pTpl->pszName, cstrGetSzStrNoNULL(pStrProp)); cstrDestruct(&pStrProp); - return 1; + ABORT_FINALIZE(RS_RET_TPL_INVLD_PROP); } if(pTpe->data.field.propid == PROP_CEE) { /* in CEE case, we need to preserve the actual property name */ - if((pTpe->data.field.propName = es_newStrFromCStr((char*)cstrGetSzStrNoNULL(pStrProp)+2, cstrLen(pStrProp)-2)) == NULL) { + if((pTpe->data.field.propName = es_newStrFromCStr((char*)cstrGetSzStrNoNULL(pStrProp)+1, cstrLen(pStrProp)-1)) == NULL) { cstrDestruct(&pStrProp); - return 1; + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); } } /* Check frompos, if it has an R, then topos should be a regex */ if(*p == ':') { + pTpe->bComplexProcessing = 1; ++p; /* eat ':' */ #ifdef FEATURE_REGEXP if(*p == 'R') { @@ -791,8 +861,8 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) * comma itself is already part of the next field. */ } else { - errmsg.LogError(0, NO_ERRCODE, "error: invalid regular expression type, rest of line %s", - (char*) p); + errmsg.LogError(0, NO_ERRCODE, "template %s error: invalid regular expression type, rest of line %s", + pTpl->pszName, (char*) p); } } @@ -898,9 +968,7 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) #ifdef FEATURE_REGEXP if (pTpe->data.field.has_regex) { - dbgprintf("debug: has regex \n"); - /* APR 2005-09 I need the string that represent the regex */ /* The regex end is: "--end" */ /* TODO : this is hardcoded and cant be escaped, please change */ @@ -916,16 +984,13 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) if(regex_char == NULL) { dbgprintf("Could not allocate memory for template parameter!\n"); pTpe->data.field.has_regex = 0; - return 1; - /* TODO: RGer: check if we can recover better... (probably not) */ + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); } /* Get the regex string for compiling later */ memcpy(regex_char, p, longitud); regex_char[longitud] = '\0'; - dbgprintf("debug: regex detected: '%s'\n", regex_char); - /* Now i compile the regex */ /* Remember that the re is an attribute of the Template entry */ if((iRetLocal = objUse(regexp, LM_REGEXP_FILENAME)) == RS_RET_OK) { @@ -995,23 +1060,31 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) #endif /* #ifdef FEATURE_REGEXP */ } - if(pTpe->data.field.iToPos < pTpe->data.field.iFromPos) { - iNum = pTpe->data.field.iToPos; - pTpe->data.field.iToPos = pTpe->data.field.iFromPos; - pTpe->data.field.iFromPos = iNum; - } - /* check options */ if(*p == ':') { ++p; /* eat ':' */ doOptions(&p, pTpe); } + if(pTpe->data.field.options.bFromPosEndRelative) { + if(pTpe->data.field.iToPos > pTpe->data.field.iFromPos) { + iNum = pTpe->data.field.iToPos; + pTpe->data.field.iToPos = pTpe->data.field.iFromPos; + pTpe->data.field.iFromPos = iNum; + } + } else { + if(pTpe->data.field.iToPos < pTpe->data.field.iFromPos) { + iNum = pTpe->data.field.iToPos; + pTpe->data.field.iToPos = pTpe->data.field.iFromPos; + pTpe->data.field.iFromPos = iNum; + } + } + + /* check field name */ if(*p == ':') { ++p; /* eat ':' */ - if(cstrConstruct(&pStrField) != RS_RET_OK) - return 1; + CHKiRet(cstrConstruct(&pStrField)); while(*p != ':' && *p != '%' && *p != '\0') { cstrAppendChar(pStrField, *p); ++p; @@ -1031,18 +1104,18 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) } } else { pTpe->fieldName = ustrdup(cstrGetSzStrNoNULL(pStrField)); - pTpe->lenFieldName = cstrLen(pStrProp); + pTpe->lenFieldName = ustrlen(pTpe->fieldName); cstrDestruct(&pStrField); } - if(pTpe->fieldName == NULL) - return 1; - + if(pTpe->fieldName == NULL) { + DBGPRINTF("template/do_Parameter: fieldName is NULL!\n"); + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); + } cstrDestruct(&pStrProp); - if(*p) ++p; /* eat '%' */ - *pp = p; - return 0; +finalize_it: + RETiRet; } @@ -1108,10 +1181,10 @@ struct template *tplAddLine(rsconf_t *conf, char* pName, uchar** ppRestOfConfLin assert(pName != NULL); assert(ppRestOfConfLine != NULL); - if((pTpl = tplConstruct(conf)) == NULL) return NULL; + DBGPRINTF("tplAddLine processing template '%s'\n", pName); pTpl->iLenName = strlen(pName); pTpl->pszName = (char*) MALLOC(sizeof(char) * (pTpl->iLenName + 1)); if(pTpl->pszName == NULL) { @@ -1171,10 +1244,13 @@ struct template *tplAddLine(rsconf_t *conf, char* pName, uchar** ppRestOfConfLin break; case '%': /* parameter */ ++p; /* eat '%' */ - do_Parameter(&p, pTpl); + if(do_Parameter(&p, pTpl) != RS_RET_OK) { + dbgprintf("tplAddLine error: parameter invalid"); + return NULL; + }; break; default: /* constant */ - do_Constant(&p, pTpl); + do_Constant(&p, pTpl, 1); break; } if(*p == '"') {/* end of template string? */ @@ -1235,7 +1311,7 @@ static rsRetVal createConstantTpe(struct template *pTpl, struct cnfobj *o) { struct templateEntry *pTpe; - es_str_t *value; + es_str_t *value = NULL; /* init just to keep compiler happy - mandatory parameter */ int i; struct cnfparamvals *pvals = NULL; uchar *outname = NULL; @@ -1292,6 +1368,8 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) int fielddelim = 9; /* default is HT (USACSII 9) */ int re_matchToUse = 0; int re_submatchToUse = 0; + int bComplexProcessing = 0; + int bPosRelativeToEnd = 0; char *re_expr = NULL; struct cnfparamvals *pvals = NULL; enum {F_NONE, F_CSV, F_JSON, F_JSONF} formatType = F_NONE; @@ -1317,23 +1395,33 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) free(tmpstr); } else if(!strcmp(pblkProperty.descr[i].name, "droplastlf")) { droplastlf = pvals[i].val.d.n; + bComplexProcessing = 1; } else if(!strcmp(pblkProperty.descr[i].name, "mandatory")) { mandatory = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "spifno1stsp")) { spifno1stsp = pvals[i].val.d.n; + bComplexProcessing = 1; } else if(!strcmp(pblkProperty.descr[i].name, "outname")) { outname = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else if(!strcmp(pblkProperty.descr[i].name, "position.from")) { frompos = pvals[i].val.d.n; + bComplexProcessing = 1; } else if(!strcmp(pblkProperty.descr[i].name, "position.to")) { topos = pvals[i].val.d.n; + bComplexProcessing = 1; + } else if(!strcmp(pblkProperty.descr[i].name, "position.relativetoend")) { + bPosRelativeToEnd = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "field.number")) { fieldnum = pvals[i].val.d.n; + bComplexProcessing = 1; } else if(!strcmp(pblkProperty.descr[i].name, "field.delimiter")) { fielddelim = pvals[i].val.d.n; + bComplexProcessing = 1; } else if(!strcmp(pblkProperty.descr[i].name, "regex.expression")) { re_expr = es_str2cstr(pvals[i].val.d.estr, NULL); + bComplexProcessing = 1; } else if(!strcmp(pblkProperty.descr[i].name, "regex.type")) { + bComplexProcessing = 1; if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"BRE", sizeof("BRE")-1)) { re_type = TPL_REGEX_BRE; } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"ERE", sizeof("ERE")-1)) { @@ -1346,6 +1434,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) ABORT_FINALIZE(RS_RET_ERR); } } else if(!strcmp(pblkProperty.descr[i].name, "regex.nomatchmode")) { + bComplexProcessing = 1; if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"DFLT", sizeof("DFLT")-1)) { re_nomatchType = TPL_REGEX_NOMATCH_USE_DFLTSTR; } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"BLANK", sizeof("BLANK")-1)) { @@ -1362,10 +1451,13 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) ABORT_FINALIZE(RS_RET_ERR); } } else if(!strcmp(pblkProperty.descr[i].name, "regex.match")) { + bComplexProcessing = 1; re_matchToUse = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "regex.submatch")) { + bComplexProcessing = 1; re_submatchToUse = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "format")) { + bComplexProcessing = 1; if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"csv", sizeof("csv")-1)) { formatType = F_CSV; } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"json", sizeof("json")-1)) { @@ -1380,6 +1472,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) ABORT_FINALIZE(RS_RET_ERR); } } else if(!strcmp(pblkProperty.descr[i].name, "controlcharacters")) { + bComplexProcessing = 1; if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"escape", sizeof("escape")-1)) { controlchr = CC_ESCAPE; } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"space", sizeof("space")-1)) { @@ -1394,6 +1487,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) ABORT_FINALIZE(RS_RET_ERR); } } else if(!strcmp(pblkProperty.descr[i].name, "securepath")) { + bComplexProcessing = 1; if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"drop", sizeof("drop")-1)) { secpath = SP_DROP; } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"replace", sizeof("replace")-1)) { @@ -1406,6 +1500,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) ABORT_FINALIZE(RS_RET_ERR); } } else if(!strcmp(pblkProperty.descr[i].name, "caseconversion")) { + bComplexProcessing = 1; if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"lower", sizeof("lower")-1)) { caseconv = tplCaseConvLower; } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"upper", sizeof("upper")-1)) { @@ -1458,10 +1553,18 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) topos = 2000000000; /* large enough ;) */ if(frompos == -1 && topos != -1) frompos = 0; - if(topos < frompos) { - errmsg.LogError(0, RS_RET_ERR, "position.to=%d is lower than postion.from=%d\n", - topos, frompos); - ABORT_FINALIZE(RS_RET_ERR); + if(bPosRelativeToEnd) { + if(topos > frompos) { + errmsg.LogError(0, RS_RET_ERR, "position.to=%d is higher than postion.from=%d in 'relativeToEnd' mode\n", + topos, frompos); + ABORT_FINALIZE(RS_RET_ERR); + } + } else { + if(topos < frompos) { + errmsg.LogError(0, RS_RET_ERR, "position.to=%d is lower than postion.from=%d\n", + topos, frompos); + ABORT_FINALIZE(RS_RET_ERR); + } } if(fieldnum != -1 && re_expr != NULL) { errmsg.LogError(0, RS_RET_ERR, "both field extraction and regex extraction " @@ -1475,8 +1578,8 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) CHKiRet(propNameToID(name, &pTpe->data.field.propid)); if(pTpe->data.field.propid == PROP_CEE) { /* in CEE case, we need to preserve the actual property name */ - pTpe->data.field.propName = es_newStrFromCStr((char*)cstrGetSzStrNoNULL(name)+2, - cstrLen(name)-2); + pTpe->data.field.propName = es_newStrFromCStr((char*)cstrGetSzStrNoNULL(name)+1, + cstrLen(name)-1); } pTpe->data.field.options.bDropLastLF = droplastlf; pTpe->data.field.options.bSPIffNo1stSP = spifno1stsp; @@ -1524,6 +1627,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) pTpe->fieldName = outname; if(outname != NULL) pTpe->lenFieldName = ustrlen(outname); + pTpe->bComplexProcessing = bComplexProcessing; pTpe->data.field.eDateFormat = datefmt; if(fieldnum != -1) { pTpe->data.field.has_fields = 1; @@ -1533,6 +1637,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) if(frompos != -1) { pTpe->data.field.iFromPos = frompos; pTpe->data.field.iToPos = topos; + pTpe->data.field.options.bFromPosEndRelative = bPosRelativeToEnd; } if(re_expr != NULL) { rsRetVal iRetLocal; @@ -1604,12 +1709,14 @@ tplProcessCnf(struct cnfobj *o) { struct template *pTpl = NULL; struct cnfparamvals *pvals = NULL; - int lenName; + int lenName = 0; /* init just to keep compiler happy: mandatory parameter */ char *name = NULL; uchar *tplStr = NULL; uchar *plugin = NULL; + es_str_t *subtree = NULL; uchar *p; - enum { T_STRING, T_PLUGIN, T_LIST } tplType; + enum { T_STRING, T_PLUGIN, T_LIST, T_SUBTREE } + tplType = T_STRING; /* init just to keep compiler happy: mandatory parameter */ int i; int o_sql=0, o_stdsql=0, o_json=0; /* options */ int numopts; @@ -1632,6 +1739,8 @@ tplProcessCnf(struct cnfobj *o) tplType = T_PLUGIN; } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"list", sizeof("list")-1)) { tplType = T_LIST; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"subtree", sizeof("subtree")-1)) { + tplType = T_SUBTREE; } else { uchar *typeStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); errmsg.LogError(0, RS_RET_ERR, "invalid template type '%s'", @@ -1641,6 +1750,22 @@ tplProcessCnf(struct cnfobj *o) } } else if(!strcmp(pblk.descr[i].name, "string")) { tplStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(pblk.descr[i].name, "subtree")) { + uchar *st_str = es_getBufAddr(pvals[i].val.d.estr); + if(st_str[0] != '$' || st_str[1] != '!') { + char *cstr = es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_ERR, "invalid subtree " + "parameter, variable must start with '$!' but " + "var name is '%s'", cstr); + free(cstr); + free(name); /* overall assigned */ + ABORT_FINALIZE(RS_RET_ERR); + } else { + /* TODO: unify strings! */ + char *cstr = es_str2cstr(pvals[i].val.d.estr, NULL); + subtree = es_newStrFromBuf(cstr+1, es_strlen(pvals[i].val.d.estr)-1); + free(cstr); + } } else if(!strcmp(pblk.descr[i].name, "plugin")) { plugin = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); } else if(!strcmp(pblk.descr[i].name, "option.stdsql")) { @@ -1682,6 +1807,19 @@ tplProcessCnf(struct cnfobj *o) } } + if(subtree == NULL) { + if(tplType == T_SUBTREE) { + errmsg.LogError(0, RS_RET_ERR, "template '%s' of type subtree needs " + "subtree parameter", name); + ABORT_FINALIZE(RS_RET_ERR); + } + } else { + if(tplType != T_SUBTREE) { + errmsg.LogError(0, RS_RET_ERR, "template '%s' is not a subtree " + "template but has a subtree specified - ignored", name); + } + } + if(o->subobjs == NULL) { if(tplType == T_LIST) { errmsg.LogError(0, RS_RET_ERR, "template '%s' of type list has " @@ -1719,10 +1857,10 @@ tplProcessCnf(struct cnfobj *o) switch(*p) { case '%': /* parameter */ ++p; /* eat '%' */ - do_Parameter(&p, pTpl); + CHKiRet(do_Parameter(&p, pTpl)); break; default: /* constant */ - do_Constant(&p, pTpl); + do_Constant(&p, pTpl, 0); break; } } @@ -1739,6 +1877,8 @@ tplProcessCnf(struct cnfobj *o) break; case T_LIST: createListTpl(pTpl, o); break; + case T_SUBTREE: pTpl->subtree = subtree; + break; } pTpl->optFormatEscape = NO_ESCAPE; @@ -1840,8 +1980,9 @@ void tplDeleteAll(rsconf_t *conf) } pTplDel = pTpl; pTpl = pTpl->pNext; - if(pTplDel->pszName != NULL) - free(pTplDel->pszName); + free(pTplDel->pszName); + if(pTplDel->subtree != NULL) + es_deleteStr(pTplDel->subtree); free(pTplDel); } ENDfunc @@ -1898,8 +2039,9 @@ void tplDeleteNew(rsconf_t *conf) } pTplDel = pTpl; pTpl = pTpl->pNext; - if(pTplDel->pszName != NULL) - free(pTplDel->pszName); + free(pTplDel->pszName); + if(pTplDel->subtree != NULL) + es_deleteStr(pTplDel->subtree); free(pTplDel); } ENDfunc @@ -1965,8 +2107,14 @@ void tplPrintList(rsconf_t *conf) case tplFmtUnixDate: dbgprintf("[Format as Unix timestamp] "); break; + case tplFmtSecFrac: + dbgprintf("[fractional seconds, only] "); + break; + case tplFmtRFC3164BuggyDate: + dbgprintf("[Format as buggy RFC3164-Date] "); + break; default: - dbgprintf("[INVALID eDateFormat %d] ", pTpe->data.field.eDateFormat); + dbgprintf("[UNKNOWN eDateFormat %d] ", pTpe->data.field.eDateFormat); } switch(pTpe->data.field.eCaseConv) { case tplCaseConvNo: @@ -2022,6 +2170,8 @@ void tplPrintList(rsconf_t *conf) } break; } + if(pTpe->bComplexProcessing) + dbgprintf("[COMPLEX]"); dbgprintf("\n"); pTpe = pTpe->pNext; } @@ -2035,8 +2185,6 @@ int tplGetEntryCount(struct template *pTpl) return(pTpl->tpenElements); } -/* our init function. TODO: remove once converted to a class - */ rsRetVal templateInit() { DEFiRet; |