diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2012-09-13 12:19:45 +0200 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2012-09-13 12:19:45 +0200 |
commit | 3daaf7c8365e188828a45217b0234a935d1d4a77 (patch) | |
tree | 77ee08991f60393458cbcf4c5c983ac7ec39727d | |
parent | 3fe276fb5b04a47dc7d1116f0b431b430f373143 (diff) | |
parent | 36b9e37896b2ce89494cc354b3d10cb689ec1ee5 (diff) | |
download | rsyslog-3daaf7c8365e188828a45217b0234a935d1d4a77.tar.gz rsyslog-3daaf7c8365e188828a45217b0234a935d1d4a77.tar.bz2 rsyslog-3daaf7c8365e188828a45217b0234a935d1d4a77.zip |
Merge branch 'v6-devel'
Conflicts:
ChangeLog
-rw-r--r-- | ChangeLog | 36 | ||||
-rw-r--r-- | doc/v6compatibility.html | 9 | ||||
-rw-r--r-- | grammar/lexer.l | 10 | ||||
-rw-r--r-- | grammar/rainerscript.c | 138 | ||||
-rw-r--r-- | grammar/rainerscript.h | 1 | ||||
-rw-r--r-- | runtime/rule.c | 161 |
6 files changed, 275 insertions, 80 deletions
@@ -1,4 +1,15 @@ --------------------------------------------------------------------------- +Version 7.1.3 [devel] 2012-09-?? +- bugfix: missing support for escape sequences in RainerScript + only \' was supported. Now the usual set is supported. Note that v5 + used \x as escape where x was any character (e.g. "\n" meant "n" and NOT + LF). This also means there is some incompatibility to v5 for well-know + sequences. Better break it now than later. +- bugfix: invalid property name in property-filter could cause abort + if action chaining (& operator) was used + http://bugzilla.adiscon.com/show_bug.cgi?id=355 + Thanks to pilou@gmx.com for the bug report +--------------------------------------------------------------------------- Version 7.1.2 [devel] 2012-09-12 - bugfix: messages were duplicated, sometimes massively regression from new code in 7.1.1 and reason for early release @@ -28,6 +39,18 @@ Version 7.1.0 [devel] 2012-09-06 - bugfix: imtcp could abort on exit due to invalid free() - imported bugfixes from 6.4.1 --------------------------------------------------------------------------- +Version 6.5.1 [devel] 2012-08-?? +- added pure JSON output plugin parameter passing mode +- ommongodb now supports templates +- bugfix: imtcp could abort on exit due to invalid free() +- bugfix: remove invalid socket option call from imuxsock + Thanks to Cristian Ionescu-Idbohrn and Jonny Törnbom +- bugfix: missing support for escape sequences in RainerScript + only \' was supported. Now the usual set is supported. Note that v5 + used \x as escape where x was any character (e.g. "\n" meant "n" and NOT + LF). This also means there is some incompatibility to v5 for well-know + sequences. Better break it now than later. +--------------------------------------------------------------------------- Version 6.5.0 [devel] 2012-08-28 - imrelp now supports non-cancel thread termination (but now requires at least librelp 1.0.1) @@ -53,6 +76,15 @@ Version 6.5.0 [devel] 2012-08-28 Note: patches were released under ASL 2.0, see http://bugzilla.adiscon.com/show_bug.cgi?id=353 --------------------------------------------------------------------------- +Version 6.4.2 [V6-STABLE] 2012-09-?? +- bugfix: remove invalid socket option call from imuxsock + Thanks to Cristian Ionescu-Idbohrn and Jonny Törnbom +- bugfix: missing support for escape sequences in RainerScript + only \' was supported. Now the usual set is supported. Note that v5 + used \x as escape where x was any character (e.g. "\n" meant "n" and NOT + LF). This also means there is some incompatibility to v5 for well-know + sequences. Better break it now than later. +--------------------------------------------------------------------------- Version 6.4.1 [V6-STABLE] 2012-09-06 - bugfix: multiple main queues with same queue file name were not detected This lead to queue file corruption. While the root cause is a config @@ -607,6 +639,10 @@ expected that interfaces, even new ones, break during the initial [ported from v4] --------------------------------------------------------------------------- Version 5.10.1 [V5-STABLE], 2012-0?-?? +- bugfix: invalid property name in property-filter could cause abort + if action chaining (& operator) was used + http://bugzilla.adiscon.com/show_bug.cgi?id=355 + Thanks to pilou@gmx.com for the bug report - bugfix: remove invalid socket option call from imuxsock Thanks to Cristian Ionescu-Idbohrn and Jonny Törnbom --------------------------------------------------------------------------- diff --git a/doc/v6compatibility.html b/doc/v6compatibility.html index eec0784b..edb6dedf 100644 --- a/doc/v6compatibility.html +++ b/doc/v6compatibility.html @@ -181,6 +181,15 @@ As you see, here you may include spaces between user names. so it is a wise decision to change config files at least to the legacy format (with ":omusrmsg:" in front of the name). +<h2>Escape Sequences in Script-Based Filters<h2> +<p>In v5, escape sequences were very simplistic. Inside a string, "\x" meant +"x" with x being any character. This has been changed so that the usual set of +escapes is supported, must importantly "\n", "\t", "\xhh" (with hh being hex digits) +and "\ooo" with (o being octal digits). So if one of these sequences was used +previously, results are obviously different. However, that should not create any +real problems, because it is hard to envision why someone should have done that +(why write "\n" when you can also write "n"?). +--------------------------------------------------------------------------- <p>[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p> <p><font size="2">This documentation is part of the <a href="http://www.rsyslog.com/">rsyslog</a> project.<br> diff --git a/grammar/lexer.l b/grammar/lexer.l index db875386..8b930713 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -122,9 +122,15 @@ int fileno(FILE *stream); <EXPR>0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ <EXPR>([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } <EXPR>\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } -<EXPR>\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); +<EXPR>\'([^'\\]|\\['"\\$bntr]|\\x[0-9a-f][0-9a-f]|\\[0-7][0-7][0-7])*\' { + yytext[yyleng-1] = '\0'; + unescapeStr((uchar*)yytext+1, yyleng-2); + yylval.estr = es_newStrFromBuf(yytext+1, strlen(yytext)); return STRING; } -<EXPR>\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); +<EXPR>\"([^"\\$]|\\["'\\$bntr]|\\x[0-9a-f][0-9a-f]|\\[0-7][0-7][0-7])*\" { + yytext[yyleng-1] = '\0'; + unescapeStr((uchar*)yytext+1, yyleng-2); + yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); return STRING; } <EXPR>[ \t\n] <EXPR>[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index d588ccc9..b0a79458 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1910,3 +1910,141 @@ initRainerscript(void) finalize_it: RETiRet; } + +/* we need a function to check for octal digits */ +static inline int +isodigit(uchar c) +{ + return(c >= '0' && c <= '7'); +} + +/** + * Get numerical value of a hex digit. This is a helper function. + * @param[in] c a character containing 0..9, A..Z, a..z anything else + * is an (undetected) error. + */ +static inline int +hexDigitVal(char c) +{ + int r; + if(c < 'A') + r = c - '0'; + else if(c < 'a') + r = c - 'A' + 10; + else + r = c - 'a' + 10; + return r; +} + +/* Handle the actual unescaping. + * a helper to unescapeStr(), to help make the function easier to read. + */ +static inline void +doUnescape(unsigned char *c, int len, int *iSrc, int iDst) +{ + if(c[*iSrc] == '\\') { + if(++(*iSrc) == len) { + /* error, incomplete escape, treat as single char */ + c[iDst] = '\\'; + } + /* regular case, unescape */ + switch(c[*iSrc]) { + case 'a': + c[iDst] = '\007'; + break; + case 'b': + c[iDst] = '\b'; + break; + case 'f': + c[iDst] = '\014'; + break; + case 'n': + c[iDst] = '\n'; + break; + case 'r': + c[iDst] = '\r'; + break; + case 't': + c[iDst] = '\t'; + break; + case '\'': + c[iDst] = '\''; + break; + case '"': + c[iDst] = '"'; + break; + case '?': + c[iDst] = '?'; + break; + case '$': + c[iDst] = '$'; + break; + case '\\': + c[iDst] = '\\'; + break; + case 'x': + if( (*iSrc)+2 >= len + || !isxdigit(c[(*iSrc)+1]) + || !isxdigit(c[(*iSrc)+2])) { + /* error, incomplete escape, use as is */ + c[iDst] = '\\'; + --(*iSrc); + } + c[iDst] = (hexDigitVal(c[(*iSrc)+1]) << 4) + + hexDigitVal(c[(*iSrc)+2]); + *iSrc += 2; + break; + case '0': /* octal escape */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + if( (*iSrc)+2 >= len + || !isodigit(c[(*iSrc)+1]) + || !isodigit(c[(*iSrc)+2])) { + /* error, incomplete escape, use as is */ + c[iDst] = '\\'; + --(*iSrc); + } + c[iDst] = ((c[(*iSrc) ] - '0') << 6) + + ((c[(*iSrc)+1] - '0') << 3) + + ( c[(*iSrc)+2] - '0'); + *iSrc += 2; + break; + default: + /* error, incomplete escape, indicate by '?' */ + c[iDst] = '?'; + break; + } + } else { + /* regular character */ + c[iDst] = c[*iSrc]; + } +} + +void +unescapeStr(uchar *s, int len) +{ + int iSrc, iDst; + assert(s != NULL); + + /* scan for first escape sequence (if we are luky, there is none!) */ + iSrc = 0; + while(iSrc < len && s[iSrc] != '\\') + ++iSrc; + /* now we have a sequence or end of string. In any case, we process + * all remaining characters (maybe 0!) and unescape. + */ + if(iSrc != len) { + iDst = iSrc; + while(iSrc < len) { + doUnescape(s, len, &iSrc, iDst); + ++iSrc; + ++iDst; + } + s[iDst] = '\0'; + } +} diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 5306188d..7637ae48 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -291,6 +291,7 @@ struct cnfstmt * cnfstmtNewLegaAct(char *actline); void cnfstmtDestruct(struct cnfstmt *root); char* getFIOPName(unsigned iFIOP); rsRetVal initRainerscript(void); +void unescapeStr(uchar *s, int len); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); diff --git a/runtime/rule.c b/runtime/rule.c index 67ecd077..f6160bdc 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -184,78 +184,83 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) DBGPRINTF("result of rainerscript filter evaluation: %d\n", bRet); } else { assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */ - pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, - pRule->f_filterData.prop.propName, &propLen, &pbMustBeFreed); - - /* Now do the compares (short list currently ;)) */ - switch(pRule->f_filterData.prop.operation ) { - case FIOP_CONTAINS: - if(rsCStrLocateInSzStr(pRule->f_filterData.prop.pCSCompValue, (uchar*) pszPropVal) != -1) - bRet = 1; - break; - case FIOP_ISEMPTY: - if(propLen == 0) - bRet = 1; /* process message! */ - break; - case FIOP_ISEQUAL: - if(rsCStrSzStrCmp(pRule->f_filterData.prop.pCSCompValue, - pszPropVal, ustrlen(pszPropVal)) == 0) - bRet = 1; /* process message! */ - break; - case FIOP_STARTSWITH: - if(rsCStrSzStrStartsWithCStr(pRule->f_filterData.prop.pCSCompValue, - pszPropVal, ustrlen(pszPropVal)) == 0) - bRet = 1; /* process message! */ - break; - case FIOP_REGEX: - if(rsCStrSzStrMatchRegex(pRule->f_filterData.prop.pCSCompValue, - (unsigned char*) pszPropVal, 0, &pRule->f_filterData.prop.regex_cache) == RS_RET_OK) - bRet = 1; - break; - case FIOP_EREREGEX: - if(rsCStrSzStrMatchRegex(pRule->f_filterData.prop.pCSCompValue, - (unsigned char*) pszPropVal, 1, &pRule->f_filterData.prop.regex_cache) == RS_RET_OK) - bRet = 1; - break; - default: - /* here, it handles NOP (for performance reasons) */ - assert(pRule->f_filterData.prop.operation == FIOP_NOP); - bRet = 1; /* as good as any other default ;) */ - break; - } - - /* now check if the value must be negated */ - if(pRule->f_filterData.prop.isNegated) - bRet = (bRet == 1) ? 0 : 1; - - if(Debug) { - char *cstr; - if(pRule->f_filterData.prop.propID == PROP_CEE) { - cstr = es_str2cstr(pRule->f_filterData.prop.propName, NULL); - DBGPRINTF("Filter: check for CEE property '%s' (value '%s') ", - cstr, pszPropVal); - free(cstr); - } else { - DBGPRINTF("Filter: check for property '%s' (value '%s') ", - propIDToName(pRule->f_filterData.prop.propID), pszPropVal); + if(pRule->f_filterData.prop.propID == PROP_INVALID) { + DBGPRINTF("invalid property ID, filter always returns 0\n"); + bRet = 0; + } else { + pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, + pRule->f_filterData.prop.propName, &propLen, &pbMustBeFreed); + + /* Now do the compares (short list currently ;)) */ + switch(pRule->f_filterData.prop.operation ) { + case FIOP_CONTAINS: + if(rsCStrLocateInSzStr(pRule->f_filterData.prop.pCSCompValue, (uchar*) pszPropVal) != -1) + bRet = 1; + break; + case FIOP_ISEMPTY: + if(propLen == 0) + bRet = 1; /* process message! */ + break; + case FIOP_ISEQUAL: + if(rsCStrSzStrCmp(pRule->f_filterData.prop.pCSCompValue, + pszPropVal, ustrlen(pszPropVal)) == 0) + bRet = 1; /* process message! */ + break; + case FIOP_STARTSWITH: + if(rsCStrSzStrStartsWithCStr(pRule->f_filterData.prop.pCSCompValue, + pszPropVal, ustrlen(pszPropVal)) == 0) + bRet = 1; /* process message! */ + break; + case FIOP_REGEX: + if(rsCStrSzStrMatchRegex(pRule->f_filterData.prop.pCSCompValue, + (unsigned char*) pszPropVal, 0, &pRule->f_filterData.prop.regex_cache) == RS_RET_OK) + bRet = 1; + break; + case FIOP_EREREGEX: + if(rsCStrSzStrMatchRegex(pRule->f_filterData.prop.pCSCompValue, + (unsigned char*) pszPropVal, 1, &pRule->f_filterData.prop.regex_cache) == RS_RET_OK) + bRet = 1; + break; + default: + /* here, it handles NOP (for performance reasons) */ + assert(pRule->f_filterData.prop.operation == FIOP_NOP); + bRet = 1; /* as good as any other default ;) */ + break; } + + /* now check if the value must be negated */ if(pRule->f_filterData.prop.isNegated) - DBGPRINTF("NOT "); - if(pRule->f_filterData.prop.operation == FIOP_ISEMPTY) { - DBGPRINTF("%s : %s\n", - getFIOPName(pRule->f_filterData.prop.operation), - bRet ? "TRUE" : "FALSE"); - } else { - DBGPRINTF("%s '%s': %s\n", - getFIOPName(pRule->f_filterData.prop.operation), - rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue), - bRet ? "TRUE" : "FALSE"); + bRet = (bRet == 1) ? 0 : 1; + + if(Debug) { + char *cstr; + if(pRule->f_filterData.prop.propID == PROP_CEE) { + cstr = es_str2cstr(pRule->f_filterData.prop.propName, NULL); + dbgprintf("Filter: check for CEE property '%s' (value '%s') ", + cstr, pszPropVal); + free(cstr); + } else { + dbgprintf("Filter: check for property '%s' (value '%s') ", + propIDToName(pRule->f_filterData.prop.propID), pszPropVal); + } + if(pRule->f_filterData.prop.isNegated) + dbgprintf("NOT "); + if(pRule->f_filterData.prop.operation == FIOP_ISEMPTY) { + dbgprintf("%s : %s\n", + getFIOPName(pRule->f_filterData.prop.operation), + bRet ? "TRUE" : "FALSE"); + } else { + dbgprintf("%s '%s': %s\n", + getFIOPName(pRule->f_filterData.prop.operation), + rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue), + bRet ? "TRUE" : "FALSE"); + } } - } - /* cleanup */ - if(pbMustBeFreed) - free(pszPropVal); + /* cleanup */ + if(pbMustBeFreed) + free(pszPropVal); + } } finalize_it: @@ -401,16 +406,16 @@ CODESTARTobjDebugPrint(rule) } else { dbgprintf("PROPERTY-BASED Filter:\n"); dbgprintf("\tProperty.: '%s'\n", propIDToName(pThis->f_filterData.prop.propID)); - if(pThis->f_filterData.prop.propName != NULL) { - cstr = es_str2cstr(pThis->f_filterData.prop.propName, NULL); - dbgprintf("\tCEE-Prop.: '%s'\n", cstr); - free(cstr); - } - dbgprintf("\tOperation: "); - if(pThis->f_filterData.prop.isNegated) - dbgprintf("NOT "); - dbgprintf("'%s'\n", getFIOPName(pThis->f_filterData.prop.operation)); - if(pThis->f_filterData.prop.pCSCompValue != NULL) { + if(pThis->f_filterData.prop.propID != PROP_INVALID) { + if(pThis->f_filterData.prop.propName != NULL) { + cstr = es_str2cstr(pThis->f_filterData.prop.propName, NULL); + dbgprintf("\tCEE-Prop.: '%s'\n", cstr); + free(cstr); + } + dbgprintf("\tOperation: "); + if(pThis->f_filterData.prop.isNegated) + dbgprintf("NOT "); + dbgprintf("'%s'\n", getFIOPName(pThis->f_filterData.prop.operation)); dbgprintf("\tValue....: '%s'\n", rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSCompValue)); } |