diff options
Diffstat (limited to 'template.c')
-rw-r--r-- | template.c | 275 |
1 files changed, 207 insertions, 68 deletions
@@ -1,14 +1,28 @@ /* This is the template processing code of rsyslog. * Please see syslogd.c for license information. - * This code is placed under the GPL. * begun 2004-11-17 rgerhards + * + * Copyright 2004, 2007 Rainer Gerhards and Adiscon + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. */ #include "config.h" -#ifdef __FreeBSD__ -#define BSD -#endif - #include "rsyslog.h" #include <stdio.h> #include <stdlib.h> @@ -19,8 +33,16 @@ #include "syslogd-types.h" #include "template.h" #include "msg.h" -#include "syslogd.h" +#include "dirty.h" +#include "obj.h" +#include "errmsg.h" +/* static data */ +DEFobjCurrIf(obj) +DEFobjCurrIf(errmsg) +DEFobjCurrIf(regexp) + +static int bFirstRegexpErrmsg = 1; /**< did we already do a "can't load regexp" error message? */ 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 */ @@ -50,7 +72,7 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar** ppSz) { DEFiRet; struct templateEntry *pTpe; - rsCStrObj *pCStr; + cstr_t *pCStr; unsigned short bMustBeFreed; uchar *pVal; size_t iLenVal; @@ -64,10 +86,7 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar** ppSz) * free the obtained value (if requested). We continue this * loop until we got hold of all values. */ - if((pCStr = rsCStrConstruct()) == NULL) { - dbgprintf("memory shortage, tplToString failed\n"); - ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); - } + CHKiRet(rsCStrConstruct(&pCStr)); pTpe = pTpl->pEntryRoot; while(pTpe != NULL) { @@ -78,7 +97,7 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar** ppSz) ) { dbgprintf("error %d during tplToString()\n", iRet); /* it does not make sense to continue now */ - rsCStrDestruct(pCStr); + rsCStrDestruct(&pCStr); FINALIZE; } } else if(pTpe->eEntryType == FIELD) { @@ -98,7 +117,7 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar** ppSz) CHKiRet_Hdlr(rsCStrAppendStrWithLen(pCStr, (uchar*) pVal, iLenVal)) { dbgprintf("error %d during tplToString()\n", iRet); /* it does not make sense to continue now */ - rsCStrDestruct(pCStr); + rsCStrDestruct(&pCStr); if(bMustBeFreed) free(pVal); FINALIZE; @@ -118,7 +137,7 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar** ppSz) finalize_it: *ppSz = (iRet == RS_RET_OK) ? pVal : NULL; - return iRet; + RETiRet; } /* Helper to doSQLEscape. This is called if doSQLEscape @@ -169,11 +188,13 @@ static void doSQLEmergencyEscape(register uchar *p, int escapeMode) * new parameter escapeMode is 0 - standard sql, 1 - "smart" engines * 2005-09-22 rgerhards */ -void doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode) +rsRetVal +doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode) { + DEFiRet; uchar *p; int iLen; - rsCStrObj *pStrB; + cstr_t *pStrB = NULL; uchar *pszGenerated; assert(pp != NULL); @@ -191,44 +212,25 @@ void doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int es /* when we get out of the loop, we are either at the * string terminator or the first \'. */ if(*p == '\0') - return; /* nothing to do in this case! */ + FINALIZE; /* nothing to do in this case! */ p = *pp; iLen = *pLen; - if((pStrB = rsCStrConstruct()) == NULL) { - /* oops - no mem ... Do emergency... */ - doSQLEmergencyEscape(p, escapeMode); - return; - } + CHKiRet(rsCStrConstruct(&pStrB)); while(*p) { if(*p == '\'') { - if(rsCStrAppendChar(pStrB, (escapeMode == 0) ? '\'' : '\\') != RS_RET_OK) { - doSQLEmergencyEscape(*pp, escapeMode); - rsCStrDestruct(pStrB); - return; - } + CHKiRet(rsCStrAppendChar(pStrB, (escapeMode == 0) ? '\'' : '\\')); iLen++; /* reflect the extra character */ } else if((escapeMode == 1) && (*p == '\\')) { - if(rsCStrAppendChar(pStrB, '\\') != RS_RET_OK) { - doSQLEmergencyEscape(*pp, escapeMode); - rsCStrDestruct(pStrB); - return; - } + CHKiRet(rsCStrAppendChar(pStrB, '\\')); iLen++; /* reflect the extra character */ } - if(rsCStrAppendChar(pStrB, *p) != RS_RET_OK) { - doSQLEmergencyEscape(*pp, escapeMode); - rsCStrDestruct(pStrB); - return; - } + CHKiRet(rsCStrAppendChar(pStrB, *p)); ++p; } - rsCStrFinish(pStrB); - if(rsCStrConvSzStrAndDestruct(pStrB, &pszGenerated, 0) != RS_RET_OK) { - doSQLEmergencyEscape(*pp, escapeMode); - return; - } + CHKiRet(rsCStrFinish(pStrB)); + CHKiRet(rsCStrConvSzStrAndDestruct(pStrB, &pszGenerated, 0)); if(*pbMustBeFreed) free(*pp); /* discard previous value */ @@ -236,6 +238,15 @@ void doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int es *pp = pszGenerated; *pLen = iLen; *pbMustBeFreed = 1; + +finalize_it: + if(iRet != RS_RET_OK) { + doSQLEmergencyEscape(*pp, escapeMode); + if(pStrB != NULL) + rsCStrDestruct(&pStrB); + } + + RETiRet; } @@ -299,7 +310,7 @@ struct template* tplConstruct(void) static int do_Constant(unsigned char **pp, struct template *pTpl) { register unsigned char *p; - rsCStrObj *pStrB; + cstr_t *pStrB; struct templateEntry *pTpe; int i; @@ -309,7 +320,7 @@ static int do_Constant(unsigned char **pp, struct template *pTpl) p = *pp; - if((pStrB = rsCStrConstruct()) == NULL) + if(rsCStrConstruct(&pStrB) != RS_RET_OK) return 1; rsCStrSetAllocIncrement(pStrB, 32); /* process the message and expand escapes @@ -366,7 +377,6 @@ static int do_Constant(unsigned char **pp, struct template *pTpl) if((pTpe = tpeConstruct(pTpl)) == NULL) { /* OK, we are out of luck. Let's invalidate the * entry and that's it. - * TODO: add panic message once we have a mechanism for this */ pTpe->eEntryType = UNDEFINED; return 1; @@ -430,10 +440,14 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe) pTpe->data.field.eDateFormat = tplFmtRFC3164Date; } else if(!strcmp((char*)Buf, "date-rfc3339")) { pTpe->data.field.eDateFormat = tplFmtRFC3339Date; + } else if(!strcmp((char*)Buf, "date-subseconds")) { + pTpe->data.field.eDateFormat = tplFmtSecFrac; } else if(!strcmp((char*)Buf, "lowercase")) { pTpe->data.field.eCaseConv = tplCaseConvLower; } else if(!strcmp((char*)Buf, "uppercase")) { pTpe->data.field.eCaseConv = tplCaseConvUpper; + } else if(!strcmp((char*)Buf, "sp-if-no-1st-sp")) { + pTpe->data.field.options.bSPIffNo1stSP = 1; } else if(!strcmp((char*)Buf, "escape-cc")) { pTpe->data.field.options.bEscapeCC = 1; } else if(!strcmp((char*)Buf, "drop-cc")) { @@ -462,14 +476,15 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe) static int do_Parameter(unsigned char **pp, struct template *pTpl) { unsigned char *p; - rsCStrObj *pStrB; + cstr_t *pStrB; struct templateEntry *pTpe; int iNum; /* to compute numbers */ + rsRetVal iRetLocal; #ifdef FEATURE_REGEXP - /* APR: variables for regex */
- int longitud;
- unsigned char *regex_char;
+ /* APR: variables for regex */ + int longitud; + unsigned char *regex_char; unsigned char *regex_end; #endif @@ -479,7 +494,7 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) p = (unsigned char*) *pp; - if((pStrB = rsCStrConstruct()) == NULL) + if(rsCStrConstruct(&pStrB) != RS_RET_OK) return 1; if((pTpe = tpeConstruct(pTpl)) == NULL) { @@ -490,7 +505,8 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) pTpe->eEntryType = FIELD; while(*p && *p != '%' && *p != ':') { - rsCStrAppendChar(pStrB, *p++); + rsCStrAppendChar(pStrB, tolower(*p)); + ++p; /* do NOT do this in tolower()! */ } /* got the name*/ @@ -502,18 +518,90 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) if(*p == ':') { ++p; /* eat ':' */ #ifdef FEATURE_REGEXP - if (*p == 'R') { + if(*p == 'R') { /* APR: R found! regex alarm ! :) */ ++p; /* eat ':' */ - if (*p != ':') { + /* first come the regex type */ + if(*p == ',') { + ++p; /* eat ',' */ + if(p[0] == 'B' && p[1] == 'R' && p[2] == 'E' && (p[3] == ',' || p[3] == ':')) { + pTpe->data.field.typeRegex = TPL_REGEX_BRE; + p += 3; /* eat indicator sequence */ + } else if(p[0] == 'E' && p[1] == 'R' && p[2] == 'E' && (p[3] == ',' || p[3] == ':')) { + pTpe->data.field.typeRegex = TPL_REGEX_ERE; + p += 3; /* eat indicator sequence */ + } else { + errmsg.LogError(0, NO_ERRCODE, "error: invalid regular expression type, rest of line %s", + (char*) p); + } + } + + /* now check for submatch ID */ + pTpe->data.field.iSubMatchToUse = 0; + if(*p == ',') { + /* in this case a number follows, which indicates which match + * shall be used. This must be a single digit. + */ + ++p; /* eat ',' */ + if(isdigit((int) *p)) { + pTpe->data.field.iSubMatchToUse = *p - '0'; + ++p; /* eat digit */ + } + } + + /* now pull what to do if we do not find a match */ + if(*p == ',') { + ++p; /* eat ',' */ + if(p[0] == 'D' && p[1] == 'F' && p[2] == 'L' && p[3] == 'T' + && (p[4] == ',' || p[4] == ':')) { + pTpe->data.field.nomatchAction = TPL_REGEX_NOMATCH_USE_DFLTSTR; + p += 4; /* eat indicator sequence */ + } else if(p[0] == 'B' && p[1] == 'L' && p[2] == 'A' && p[3] == 'N' && p[4] == 'K' + && (p[5] == ',' || p[5] == ':')) { + pTpe->data.field.nomatchAction = TPL_REGEX_NOMATCH_USE_BLANK; + p += 5; /* eat indicator sequence */ + } else if(p[0] == 'F' && p[1] == 'I' && p[2] == 'E' && p[3] == 'L' && p[4] == 'D' + && (p[5] == ',' || p[5] == ':')) { + pTpe->data.field.nomatchAction = TPL_REGEX_NOMATCH_USE_WHOLE_FIELD; + p += 5; /* eat indicator sequence */ + } else if(p[0] == 'Z' && p[1] == 'E' && p[2] == 'R' && p[3] == 'O' + && (p[4] == ',' || p[4] == ':')) { + pTpe->data.field.nomatchAction = TPL_REGEX_NOMATCH_USE_ZERO; + p += 4; /* eat indicator sequence */ + } else if(p[0] == ',') { /* empty, use default */ + pTpe->data.field.nomatchAction = TPL_REGEX_NOMATCH_USE_DFLTSTR; + /* do NOT eat indicator sequence, as this was already eaten - the + * 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); + } + } + + /* now check for match ID */ + pTpe->data.field.iMatchToUse = 0; + if(*p == ',') { + /* in this case a number follows, which indicates which match + * shall be used. This must be a single digit. + */ + ++p; /* eat ',' */ + if(isdigit((int) *p)) { + pTpe->data.field.iMatchToUse = *p - '0'; + ++p; /* eat digit */ + } + } + + if(*p != ':') { /* There is something more than an R , this is invalid ! */ /* Complain on extra characters */ - logerrorSz - ("error: invalid character in frompos after \"R\", property: '%%%s'", + errmsg.LogError(0, NO_ERRCODE, "error: invalid character in frompos after \"R\", property: '%%%s'", (char*) *pp); } else { pTpe->data.field.has_regex = 1; + dbgprintf("we have a regexp and use match #%d, submatch #%d\n", + pTpe->data.field.iMatchToUse, pTpe->data.field.iSubMatchToUse); } } else { /* now we fall through the "regular" FromPos code */ @@ -534,8 +622,7 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) pTpe->data.field.has_fields = 1; if(!isdigit((int)*p)) { /* complain and use default */ - logerrorSz - ("error: invalid character in frompos after \"F,\", property: '%%%s' - using 9 (HT) as field delimiter", + errmsg.LogError(0, NO_ERRCODE, "error: invalid character in frompos after \"F,\", property: '%%%s' - using 9 (HT) as field delimiter", (char*) *pp); pTpe->data.field.field_delim = 9; } else { @@ -543,8 +630,7 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) while(isdigit((int)*p)) iNum = iNum * 10 + *p++ - '0'; if(iNum < 0 || iNum > 255) { - logerrorInt - ("error: non-USASCII delimiter character value in template - using 9 (HT) as substitute", iNum); + errmsg.LogError(0, NO_ERRCODE, "error: non-USASCII delimiter character value %d in template - using 9 (HT) as substitute", iNum); pTpe->data.field.field_delim = 9; } else { pTpe->data.field.field_delim = iNum; @@ -554,8 +640,7 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) /* invalid character after F, so we need to reject * this. */ - logerrorSz - ("error: invalid character in frompos after \"F\", property: '%%%s'", + errmsg.LogError(0, NO_ERRCODE, "error: invalid character in frompos after \"F\", property: '%%%s'", (char*) *pp); } } else { @@ -596,9 +681,8 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) longitud = regex_end - p; /* Malloc for the regex string */ regex_char = (unsigned char *) malloc(longitud + 1); - if (regex_char == NULL) { - dbgprintf - ("Could not allocate memory for template parameter!\n"); + 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) */ @@ -612,8 +696,22 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) /* Now i compile the regex */ /* Remember that the re is an attribute of the Template entry */ - if(regcomp(&(pTpe->data.field.re), (char*) regex_char, 0) != 0) { - dbgprintf("error: can not compile regex: '%s'\n", regex_char); + if((iRetLocal = objUse(regexp, LM_REGEXP_FILENAME)) == RS_RET_OK) { + int iOptions; + iOptions = (pTpe->data.field.typeRegex == TPL_REGEX_ERE) ? REG_EXTENDED : 0; + if(regexp.regcomp(&(pTpe->data.field.re), (char*) regex_char, iOptions) != 0) { + dbgprintf("error: can not compile regex: '%s'\n", regex_char); + pTpe->data.field.has_regex = 2; + } + } else { + /* regexp object could not be loaded */ + dbgprintf("error %d trying to load regexp library - this may be desired and thus OK", + iRetLocal); + if(bFirstRegexpErrmsg) { /* prevent flood of messages, maybe even an endless loop! */ + bFirstRegexpErrmsg = 0; + errmsg.LogError(0, NO_ERRCODE, "regexp library could not be loaded (error %d), " + "regexp ignored", iRetLocal); + } pTpe->data.field.has_regex = 2; } @@ -651,7 +749,6 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) #endif /* #ifdef FEATURE_REGEXP */ } - /* TODO: add more sanity checks. For now, we do the bare minimum */ if((pTpe->data.field.has_fields == 0) && (pTpe->data.field.iToPos < pTpe->data.field.iFromPos)) { iNum = pTpe->data.field.iToPos; pTpe->data.field.iToPos = pTpe->data.field.iFromPos; @@ -822,6 +919,8 @@ void tplDeleteAll(void) { struct template *pTpl, *pTplDel; struct templateEntry *pTpe, *pTpeDel; + rsRetVal iRetLocal; + BEGINfunc pTpl = tplRoot; while(pTpl != NULL) { @@ -841,6 +940,12 @@ void tplDeleteAll(void) free(pTpeDel->data.constant.pConstant); break; case FIELD: + /* check if we have a regexp and, if so, delete it */ + if(pTpeDel->data.field.has_regex != 0) { + if((iRetLocal = objUse(regexp, LM_REGEXP_FILENAME)) == RS_RET_OK) { + regexp.regfree(&(pTpeDel->data.field.re)); + } + } /*dbgprintf("(FIELD), value: '%s'", pTpeDel->data.field.pPropRepl);*/ free(pTpeDel->data.field.pPropRepl); break; @@ -854,15 +959,20 @@ void tplDeleteAll(void) free(pTplDel->pszName); free(pTplDel); } + ENDfunc } + /* Destroy all templates obtained from conf file - * preserving hadcoded ones. This is called from init(). + * preserving hardcoded ones. This is called from init(). */ void tplDeleteNew(void) { struct template *pTpl, *pTplDel; struct templateEntry *pTpe, *pTpeDel; + rsRetVal iRetLocal; + + BEGINfunc if(tplRoot == NULL || tplLastStatic == NULL) return; @@ -887,6 +997,12 @@ void tplDeleteNew(void) free(pTpeDel->data.constant.pConstant); break; case FIELD: + /* check if we have a regexp and, if so, delete it */ + if(pTpeDel->data.field.has_regex != 0) { + if((iRetLocal = objUse(regexp, LM_REGEXP_FILENAME)) == RS_RET_OK) { + regexp.regfree(&(pTpeDel->data.field.re)); + } + } /*dbgprintf("(FIELD), value: '%s'", pTpeDel->data.field.pPropRepl);*/ free(pTpeDel->data.field.pPropRepl); break; @@ -900,6 +1016,7 @@ void tplDeleteNew(void) free(pTplDel->pszName); free(pTplDel); } + ENDfunc } /* Store the pointer to the last hardcoded teplate */ @@ -974,6 +1091,15 @@ void tplPrintList(void) if(pTpe->data.field.options.bSpaceCC) { dbgprintf("[replace control-characters with space] "); } + if(pTpe->data.field.options.bSecPathDrop) { + dbgprintf("[slashes are dropped] "); + } + if(pTpe->data.field.options.bSecPathReplace) { + dbgprintf("[slashes are replaced by '_'] "); + } + if(pTpe->data.field.options.bSPIffNo1stSP) { + dbgprintf("[SP iff no first SP] "); + } if(pTpe->data.field.options.bDropLastLF) { dbgprintf("[drop last LF in msg] "); } @@ -1000,6 +1126,19 @@ int tplGetEntryCount(struct template *pTpl) assert(pTpl != NULL); return(pTpl->tpenElements); } + +/* our init function. TODO: remove once converted to a class + */ +rsRetVal templateInit() +{ + DEFiRet; + CHKiRet(objGetObjInterface(&obj)); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + +finalize_it: + RETiRet; +} + /* * vi:set ai: */ |