diff options
Diffstat (limited to 'template.c')
-rw-r--r-- | template.c | 177 |
1 files changed, 115 insertions, 62 deletions
@@ -37,6 +37,7 @@ #include "obj.h" #include "errmsg.h" #include "strgen.h" +#include "rsconf.h" #include "unicode-helper.h" /* static data */ @@ -49,12 +50,6 @@ DEFobjCurrIf(regexp) static int bFirstRegexpErrmsg = 1; /**< did we already do a "can't load regexp" error message? */ #endif -static struct template *tplRoot = NULL; /* the root of the template list */ -static struct template *tplLast = NULL; /* points to the last element of the template list */ -static struct template *tplLastStatic = NULL; /* last static element of the template list */ - - - /* helper to tplToString and strgen's, extends buffer */ #define ALLOC_INC 128 rsRetVal @@ -116,17 +111,20 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar **ppBuf, size_t * iLenVal = pTpe->data.constant.iLenConstant; bMustBeFreed = 0; } else if(pTpe->eEntryType == FIELD) { - pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, &iLenVal, &bMustBeFreed); + pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, + pTpe->data.field.propName, &iLenVal, &bMustBeFreed); /* 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, * but they are handled in this way because of legacy (don't break any * existing thing). */ - if(pTpl->optFormatForSQL == 1) - doSQLEscape(&pVal, &iLenVal, &bMustBeFreed, 1); - else if(pTpl->optFormatForSQL == 2) - doSQLEscape(&pVal, &iLenVal, &bMustBeFreed, 0); + if(pTpl->optFormatEscape == SQL_ESCAPE) + doEscape(&pVal, &iLenVal, &bMustBeFreed, SQL_ESCAPE); + else if(pTpl->optFormatEscape == JSON_ESCAPE) + doEscape(&pVal, &iLenVal, &bMustBeFreed, JSON_ESCAPE); + else if(pTpl->optFormatEscape == STDSQL_ESCAPE) + doEscape(&pVal, &iLenVal, &bMustBeFreed, STDSQL_ESCAPE); } /* got source, now copy over */ if(iLenVal > 0) { /* may be zero depending on property */ @@ -195,7 +193,8 @@ rsRetVal tplToArray(struct template *pTpl, msg_t *pMsg, uchar*** ppArr) if(pTpe->eEntryType == CONSTANT) { CHKmalloc(pArr[iArr] = (uchar*)strdup((char*) pTpe->data.constant.pConstant)); } else if(pTpe->eEntryType == FIELD) { - pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, &propLen, &bMustBeFreed); + pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, + pTpe->data.field.propName, &propLen, &bMustBeFreed); if(bMustBeFreed) { /* if it must be freed, it is our own private copy... */ pArr[iArr] = pVal; /* ... so we can use it! */ } else { @@ -213,27 +212,29 @@ finalize_it: } -/* Helper to doSQLEscape. This is called if doSQLEscape +/* Helper to doEscape. This is called if doEscape * runs out of memory allocating the escaped string. * Then we are in trouble. We can * NOT simply return the unmodified string because this * may cause SQL injection. But we also can not simply * abort the run, this would be a DoS. I think an appropriate - * measure is to remove the dangerous \' characters. We + * measure is to remove the dangerous \' characters (SQL). We * replace them by \", which will break the message and * signatures eventually present - but this is the * best thing we can do now (or does anybody * have a better idea?). rgerhards 2004-11-23 - * added support for "escapeMode" (so doSQLEscape for details). - * if mode = 1, then backslashes are changed to slashes. + * added support for escape mode (see doEscape for details). + * if mode = SQL_ESCAPE, then backslashes are changed to slashes. * rgerhards 2005-09-22 */ -static void doSQLEmergencyEscape(register uchar *p, int escapeMode) +static void doEmergencyEscape(register uchar *p, int mode) { while(*p) { - if(*p == '\'') + if((mode == SQL_ESCAPE||mode == STDSQL_ESCAPE) && *p == '\'') *p = '"'; - else if((escapeMode == 1) && (*p == '\\')) + else if((mode == JSON_ESCAPE) && *p == '"') + *p = '\''; + else if((mode == SQL_ESCAPE) && *p == '\\') *p = '/'; ++p; } @@ -258,14 +259,16 @@ static void doSQLEmergencyEscape(register uchar *p, int escapeMode) * smartness depends on config settings. So we add a new option to this * function that allows the caller to select if they want to standard or * "smart" encoding ;) - * new parameter escapeMode is 0 - standard sql, 1 - "smart" engines + * -- + * Parameter "mode" is STDSQL_ESCAPE, SQL_ESCAPE "smart" SQL engines, or + * JSON_ESCAPE for everyone requiring escaped JSON (e.g. ElasticSearch). * 2005-09-22 rgerhards */ rsRetVal -doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode) +doEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int mode) { DEFiRet; - uchar *p; + uchar *p = NULL; int iLen; cstr_t *pStrB = NULL; uchar *pszGenerated; @@ -276,26 +279,32 @@ doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeM assert(pbMustBeFreed != NULL); /* first check if we need to do anything at all... */ - if(escapeMode == 0) + if(mode == STDSQL_ESCAPE) for(p = *pp ; *p && *p != '\'' ; ++p) ; - else + else if(mode == SQL_ESCAPE) for(p = *pp ; *p && *p != '\'' && *p != '\\' ; ++p) ; + else if(mode == JSON_ESCAPE) + for(p = *pp ; *p && *p != '"' ; ++p) + ; /* when we get out of the loop, we are either at the - * string terminator or the first \'. */ - if(*p == '\0') + * string terminator or the first character to escape */ + if(p && *p == '\0') FINALIZE; /* nothing to do in this case! */ p = *pp; iLen = *pLen; CHKiRet(cstrConstruct(&pStrB)); - + while(*p) { - if(*p == '\'') { - CHKiRet(cstrAppendChar(pStrB, (escapeMode == 0) ? '\'' : '\\')); + if((mode == SQL_ESCAPE || mode == STDSQL_ESCAPE) && *p == '\'') { + CHKiRet(cstrAppendChar(pStrB, (mode == STDSQL_ESCAPE) ? '\'' : '\\')); iLen++; /* reflect the extra character */ - } else if((escapeMode == 1) && (*p == '\\')) { + } else if((mode == SQL_ESCAPE) && *p == '\\') { + CHKiRet(cstrAppendChar(pStrB, '\\')); + iLen++; /* reflect the extra character */ + } else if((mode == JSON_ESCAPE) && *p == '"') { CHKiRet(cstrAppendChar(pStrB, '\\')); iLen++; /* reflect the extra character */ } @@ -314,7 +323,7 @@ doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeM finalize_it: if(iRet != RS_RET_OK) { - doSQLEmergencyEscape(*pp, escapeMode); + doEmergencyEscape(*pp, mode); if(pStrB != NULL) cstrDestruct(&pStrB); } @@ -355,7 +364,8 @@ struct templateEntry* tpeConstruct(struct template *pTpl) /* Constructs a template list object. Returns pointer to it * or NULL (if it fails). */ -struct template* tplConstruct(void) +static struct template* +tplConstruct(rsconf_t *conf) { struct template *pTpl; if((pTpl = calloc(1, sizeof(struct template))) == NULL) @@ -364,12 +374,12 @@ struct template* tplConstruct(void) /* basic initialisation is done via calloc() - need to * initialize only values != 0. */ - if(tplLast == NULL) { + if(conf->templates.last == NULL) { /* we are the first element! */ - tplRoot = tplLast = pTpl; + conf->templates.root = conf->templates.last = pTpl; } else { - tplLast->pNext = pTpl; - tplLast = pTpl; + conf->templates.last->pNext = pTpl; + conf->templates.last = pTpl; } return(pTpl); @@ -511,6 +521,8 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe) pTpe->data.field.eDateFormat = tplFmtRFC3164BuggyDate; } else if(!strcmp((char*)Buf, "date-rfc3339")) { pTpe->data.field.eDateFormat = tplFmtRFC3339Date; + } else if(!strcmp((char*)Buf, "date-unixtimestamp")) { + pTpe->data.field.eDateFormat = tplFmtUnixDate; } else if(!strcmp((char*)Buf, "date-subseconds")) { pTpe->data.field.eDateFormat = tplFmtSecFrac; } else if(!strcmp((char*)Buf, "lowercase")) { @@ -532,7 +544,19 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe) } else if(!strcmp((char*)Buf, "secpath-replace")) { pTpe->data.field.options.bSecPathReplace = 1; } else if(!strcmp((char*)Buf, "csv")) { - pTpe->data.field.options.bCSV = 1; + if(pTpe->data.field.options.bJSON) { + errmsg.LogError(0, NO_ERRCODE, "error: can not specify " + "both csv and json options - csv ignored"); + } else { + pTpe->data.field.options.bCSV = 1; + } + } else if(!strcmp((char*)Buf, "json")) { + if(pTpe->data.field.options.bCSV) { + errmsg.LogError(0, NO_ERRCODE, "error: can not specify " + "both csv and json options - json ignored"); + } else { + pTpe->data.field.options.bJSON = 1; + } } else { dbgprintf("Invalid field option '%s' specified - ignored.\n", Buf); } @@ -588,7 +612,14 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) cstrDestruct(&pStrB); return 1; } - cstrDestruct(&pStrB); /* no longer needed, now use ID */ + 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(pStrB)+2, cstrLen(pStrB)-2)) == NULL) { + cstrDestruct(&pStrB); + return 1; + } + } + cstrDestruct(&pStrB); /* Check frompos, if it has an R, then topos should be a regex */ if(*p == ':') { @@ -883,11 +914,14 @@ tplAddTplMod(struct template *pTpl, uchar** ppRestOfConfLine) * acknowledged implementing the option. -- rgerhards, 2011-03-21 */ if(lenMod > 6 && !strcasecmp((char*) szMod + lenMod - 7, ",stdsql")) { - pTpl->optFormatForSQL = 2; - DBGPRINTF("strgen suports the stdsql option\n"); + pTpl->optFormatEscape = STDSQL_ESCAPE; + DBGPRINTF("strgen supports the stdsql option\n"); } else if(lenMod > 3 && !strcasecmp((char*) szMod+ lenMod - 4, ",sql")) { - pTpl->optFormatForSQL = 1; - DBGPRINTF("strgen suports the sql option\n"); + pTpl->optFormatEscape = SQL_ESCAPE; + DBGPRINTF("strgen supports the sql option\n"); + } else if(lenMod > 4 && !strcasecmp((char*) szMod+ lenMod - 4, ",json")) { + pTpl->optFormatEscape = JSON_ESCAPE; + DBGPRINTF("strgen supports the json option\n"); } finalize_it: @@ -898,7 +932,7 @@ finalize_it: /* Add a new template line * returns pointer to new object if it succeeds, NULL otherwise. */ -struct template *tplAddLine(char* pName, uchar** ppRestOfConfLine) +struct template *tplAddLine(rsconf_t *conf, char* pName, uchar** ppRestOfConfLine) { struct template *pTpl; unsigned char *p; @@ -910,7 +944,7 @@ struct template *tplAddLine(char* pName, uchar** ppRestOfConfLine) assert(pName != NULL); assert(ppRestOfConfLine != NULL); - if((pTpl = tplConstruct()) == NULL) + if((pTpl = tplConstruct(conf)) == NULL) return NULL; pTpl->iLenName = strlen(pName); @@ -1015,11 +1049,13 @@ struct template *tplAddLine(char* pName, uchar** ppRestOfConfLine) * it anyhow... ;) rgerhards 2004-11-22 */ if(!strcmp(optBuf, "stdsql")) { - pTpl->optFormatForSQL = 2; + pTpl->optFormatEscape = STDSQL_ESCAPE; + } else if(!strcmp(optBuf, "json")) { + pTpl->optFormatEscape = JSON_ESCAPE; } else if(!strcmp(optBuf, "sql")) { - pTpl->optFormatForSQL = 1; + pTpl->optFormatEscape = SQL_ESCAPE; } else if(!strcmp(optBuf, "nosql")) { - pTpl->optFormatForSQL = 0; + pTpl->optFormatEscape = NO_ESCAPE; } else { dbgprintf("Invalid option '%s' ignored.\n", optBuf); } @@ -1037,13 +1073,13 @@ struct template *tplAddLine(char* pName, uchar** ppRestOfConfLine) * NULL otherwise. * rgerhards 2004-11-17 */ -struct template *tplFind(char *pName, int iLenName) +struct template *tplFind(rsconf_t *conf, char *pName, int iLenName) { struct template *pTpl; assert(pName != NULL); - pTpl = tplRoot; + pTpl = conf->templates.root; while(pTpl != NULL && !(pTpl->iLenName == iLenName && !strcmp(pTpl->pszName, pName) @@ -1061,13 +1097,13 @@ struct template *tplFind(char *pName, int iLenName) * "normal" debugging. Uncomment them, if they are needed. * rgerhards, 2007-07-05 */ -void tplDeleteAll(void) +void tplDeleteAll(rsconf_t *conf) { struct template *pTpl, *pTplDel; struct templateEntry *pTpe, *pTpeDel; BEGINfunc - pTpl = tplRoot; + pTpl = conf->templates.root; while(pTpl != NULL) { /* dbgprintf("Delete Template: Name='%s'\n ", pTpl->pszName == NULL? "NULL" : pTpl->pszName);*/ pTpe = pTpl->pEntryRoot; @@ -1092,6 +1128,8 @@ void tplDeleteAll(void) regexp.regfree(&(pTpeDel->data.field.re)); } } + if(pTpeDel->data.field.propName != NULL) + es_deleteStr(pTpeDel->data.field.propName); #endif break; } @@ -1111,19 +1149,19 @@ void tplDeleteAll(void) /* Destroy all templates obtained from conf file * preserving hardcoded ones. This is called from init(). */ -void tplDeleteNew(void) +void tplDeleteNew(rsconf_t *conf) { struct template *pTpl, *pTplDel; struct templateEntry *pTpe, *pTpeDel; BEGINfunc - if(tplRoot == NULL || tplLastStatic == NULL) + if(conf->templates.root == NULL || conf->templates.lastStatic == NULL) return; - pTpl = tplLastStatic->pNext; - tplLastStatic->pNext = NULL; - tplLast = tplLastStatic; + pTpl = conf->templates.lastStatic->pNext; + conf->templates.lastStatic->pNext = NULL; + conf->templates.last = conf->templates.lastStatic; while(pTpl != NULL) { /* dbgprintf("Delete Template: Name='%s'\n ", pTpl->pszName == NULL? "NULL" : pTpl->pszName);*/ pTpe = pTpl->pEntryRoot; @@ -1148,6 +1186,8 @@ void tplDeleteNew(void) regexp.regfree(&(pTpeDel->data.field.re)); } } + if(pTpeDel->data.field.propName != NULL) + es_deleteStr(pTpeDel->data.field.propName); #endif break; } @@ -1164,25 +1204,27 @@ void tplDeleteNew(void) } /* Store the pointer to the last hardcoded teplate */ -void tplLastStaticInit(struct template *tpl) +void tplLastStaticInit(rsconf_t *conf, struct template *tpl) { - tplLastStatic = tpl; + conf->templates.lastStatic = tpl; } /* Print the template structure. This is more or less a * debug or test aid, but anyhow I think it's worth it... */ -void tplPrintList(void) +void tplPrintList(rsconf_t *conf) { struct template *pTpl; struct templateEntry *pTpe; - pTpl = tplRoot; + pTpl = conf->templates.root; while(pTpl != NULL) { dbgprintf("Template: Name='%s' ", pTpl->pszName == NULL? "NULL" : pTpl->pszName); - if(pTpl->optFormatForSQL == 1) + if(pTpl->optFormatEscape == SQL_ESCAPE) dbgprintf("[SQL-Format (MySQL)] "); - else if(pTpl->optFormatForSQL == 2) + else if(pTpl->optFormatEscape == JSON_ESCAPE) + dbgprintf("[JSON-Escaped Format] "); + else if(pTpl->optFormatEscape == STDSQL_ESCAPE) dbgprintf("[SQL-Format (standard SQL)] "); dbgprintf("\n"); pTpe = pTpl->pEntryRoot; @@ -1198,6 +1240,11 @@ void tplPrintList(void) break; case FIELD: dbgprintf("(FIELD), value: '%d' ", pTpe->data.field.propid); + if(pTpe->data.field.propid == PROP_CEE) { + char *cstr = es_str2cstr(pTpe->data.field.propName, NULL); + dbgprintf("[EE-Property: '%s'] ", cstr); + free(cstr); + } switch(pTpe->data.field.eDateFormat) { case tplFmtDefault: break; @@ -1213,6 +1260,9 @@ void tplPrintList(void) case tplFmtRFC3339Date: dbgprintf("[Format as RFC3339-Date] "); break; + case tplFmtUnixDate: + dbgprintf("[Format as Unix timestamp] "); + break; default: dbgprintf("[INVALID eDateFormat %d] ", pTpe->data.field.eDateFormat); } @@ -1247,6 +1297,9 @@ void tplPrintList(void) if(pTpe->data.field.options.bCSV) { dbgprintf("[format as CSV (RFC4180)]"); } + if(pTpe->data.field.options.bJSON) { + dbgprintf("[format as JSON"); + } if(pTpe->data.field.options.bDropLastLF) { dbgprintf("[drop last LF in msg] "); } |