diff --git a/headers/modsecurity/rules.h b/headers/modsecurity/rules.h index 7cc5e04b..b059f9d3 100644 --- a/headers/modsecurity/rules.h +++ b/headers/modsecurity/rules.h @@ -69,10 +69,10 @@ class Rules : public RulesProperties { void incrementReferenceCount(void); void decrementReferenceCount(void); - bool loadFromUri(const char *uri); - bool loadRemote(const char *key, const char *uri); - bool load(const char *rules); - bool load(const char *rules, const std::string &ref); + int loadFromUri(const char *uri); + int loadRemote(const char *key, const char *uri); + int load(const char *rules); + int load(const char *rules, const std::string &ref); void dump(); diff --git a/src/Makefile.am b/src/Makefile.am index b83665e0..9bf1b5a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -56,6 +56,7 @@ ACTIONS = \ actions/block.cc \ actions/capture.cc \ actions/chain.cc \ + actions/log_data.cc \ actions/msg.cc \ actions/no_audit_log.cc \ actions/phase.cc \ diff --git a/src/actions/action.cc b/src/actions/action.cc index e089c9c4..3579f55e 100644 --- a/src/actions/action.cc +++ b/src/actions/action.cc @@ -76,9 +76,6 @@ Action *Action::instantiate(const std::string& name) { if (name.compare(0, rule_id.length(), rule_id) == 0) { return new RuleId(name); } - if (name.compare(0, severity.length(), severity) == 0) { - return new Severity(name); - } if (name == "chain") { return new Chain(name); } diff --git a/src/actions/severity.cc b/src/actions/severity.cc index 3895bdec..2c2bc6f9 100644 --- a/src/actions/severity.cc +++ b/src/actions/severity.cc @@ -28,7 +28,6 @@ namespace actions { Severity::Severity(std::string action) : Action(action, RunTimeOnlyIfMatchKind) { std::string a = action; - a.erase(0, 9); if (tolower(a) == "emergency") { this->m_severity = 0; } else if (tolower(a) == "alert") { diff --git a/src/debug_log.cc b/src/debug_log.cc index 97730cb3..e8b0647e 100644 --- a/src/debug_log.cc +++ b/src/debug_log.cc @@ -75,6 +75,7 @@ bool DebugLog::setOutputFile(const std::string& file_path) { * */ bool DebugLog::write_log(int debug_level, const std::string &text) { + std::cout << "?" << std::to_string(is_open()) << ":" << std::to_string(m_debug_level) <<" [" << debug_level << "] " << text << std::endl; if (!is_open()) { return false; } diff --git a/src/operators/pm.cc b/src/operators/pm.cc index e4f19d11..220dd463 100644 --- a/src/operators/pm.cc +++ b/src/operators/pm.cc @@ -59,6 +59,14 @@ void Pm::postOrderTraversal(acmp_btree_node_t *node) { node = NULL; } +void Pm::replaceAll(std::string& str, const std::string& from, const std::string& to) { + size_t start_pos = 0; + while((start_pos = str.find(from, start_pos)) != std::string::npos) { + size_t end_pos = start_pos + from.length(); + str.replace(start_pos, end_pos, to); + start_pos += to.length(); + } +} bool Pm::evaluate(Assay *assay, const std::string &input) { int rc = 0; @@ -79,6 +87,8 @@ bool Pm::evaluate(Assay *assay, const std::string &input) { bool Pm::init(const char **error) { std::vector vec; + replaceAll(param, "\\", "\\\\"); + char *content = parse_pm_content(param.c_str(), param.length(), error); if (content == NULL) { return false; diff --git a/src/operators/pm.h b/src/operators/pm.h index f09bb7f9..ef7eaf6f 100644 --- a/src/operators/pm.h +++ b/src/operators/pm.h @@ -35,7 +35,7 @@ class Pm : public Operator { m_p = acmp_create(0); } ~Pm(); - + void replaceAll(std::string& str, const std::string& from, const std::string& to); bool evaluate(Assay *assay, const std::string &input); virtual bool init(const char **error); diff --git a/src/operators/rx.cc b/src/operators/rx.cc index a968d6c5..1f2b3a46 100644 --- a/src/operators/rx.cc +++ b/src/operators/rx.cc @@ -24,10 +24,12 @@ namespace ModSecurity { namespace operators { + bool Rx::evaluate(Assay *assay, const std::string& input) { SMatch match; - if (regex_search(input, &match, m_re) && match.size() >= 1) { + std::string i = input; + if (regex_search(i, &match, m_re) && match.size() >= 1) { this->matched.push_back(match.match); return true; } diff --git a/src/parser/driver.cc b/src/parser/driver.cc index 91c235c0..77add967 100644 --- a/src/parser/driver.cc +++ b/src/parser/driver.cc @@ -25,8 +25,8 @@ namespace ModSecurity { namespace Parser { Driver::Driver() - : trace_scanning(true), - trace_parsing(true) { + : trace_scanning(false), + trace_parsing(false) { audit_log = new AuditLog(); } @@ -46,11 +46,13 @@ int Driver::addSecRule(Rule *rule) { if (size == 0) { this->rules[rule->phase].push_back(rule); + lastRule = rule; return true; } - Rule *lastRule = this->rules[rule->phase][size-1]; + if (lastRule->chained && lastRule->chainedRule == NULL) { + rule->phase = lastRule->phase; lastRule->chainedRule = rule; return true; } @@ -64,7 +66,7 @@ int Driver::addSecRule(Rule *rule) { return true; } } - + lastRule = rule; rules[rule->phase].push_back(rule); return true; } diff --git a/src/parser/driver.h b/src/parser/driver.h index 99346283..2cf69d5a 100644 --- a/src/parser/driver.h +++ b/src/parser/driver.h @@ -79,6 +79,7 @@ class Driver : public RulesProperties { std::list ref; std::string buffer; + Rule *lastRule; }; diff --git a/src/parser/seclang-parser.yy b/src/parser/seclang-parser.yy index a745d032..5274629c 100644 --- a/src/parser/seclang-parser.yy +++ b/src/parser/seclang-parser.yy @@ -18,7 +18,9 @@ class Driver; #include "actions/action.h" #include "actions/set_var.h" +#include "actions/severity.h" #include "actions/msg.h" +#include "actions/log_data.h" #include "actions/rev.h" #include "actions/tag.h" #include "actions/transformations/transformation.h" @@ -45,9 +47,11 @@ class Driver; using ModSecurity::actions::Action; using ModSecurity::actions::SetVar; +using ModSecurity::actions::Severity; using ModSecurity::actions::Tag; using ModSecurity::actions::Rev; using ModSecurity::actions::Msg; +using ModSecurity::actions::LogData; using ModSecurity::actions::transformations::Transformation; using ModSecurity::operators::Operator; using ModSecurity::Rule; @@ -125,7 +129,7 @@ using ModSecurity::Variables::Variable; PIPE ; -%left CONFIG_VALUE_RELEVANT_ONLY CONFIG_VALUE_ON CONFIG_VALUE_OFF +%left SPACE CONFIG_VALUE_RELEVANT_ONLY CONFIG_VALUE_ON CONFIG_VALUE_OFF %token QUOTATION_MARK %token DIRECTIVE %token CONFIG_DIR_REQ_BODY_LIMIT @@ -202,9 +206,11 @@ using ModSecurity::Variables::Variable; %token ACTION_MSG %token ACTION_TAG %token ACTION_REV +%token LOG_DATA %token TRANSFORMATION %token ACTION_CTL_BDY_XML %token ACTION_CTL_BDY_JSON +%token ACTION_CTL_AUDIT_LOG_PARTS %type *> actions %type *> variables @@ -223,6 +229,8 @@ input: line: expression | SPACE expression + | SPACE expression SPACE + | expression SPACE ; audit_log: @@ -298,6 +306,7 @@ audit_log: expression: audit_log + | DIRECTIVE SPACE variables SPACE OPERATOR SPACE QUOTATION_MARK actions SPACE QUOTATION_MARK | DIRECTIVE SPACE variables SPACE OPERATOR SPACE QUOTATION_MARK actions QUOTATION_MARK { Operator *op = Operator::instantiate($5); @@ -313,6 +322,7 @@ expression: ); driver.addSecRule(rule); } + | DIRECTIVE SPACE variables SPACE FREE_TEXT SPACE QUOTATION_MARK actions SPACE QUOTATION_MARK | DIRECTIVE SPACE variables SPACE FREE_TEXT SPACE QUOTATION_MARK actions QUOTATION_MARK { Operator *op = Operator::instantiate("@pm " + $5); @@ -577,14 +587,14 @@ act: { $$ = Action::instantiate($1); } - | ACTION_SEVERITY - { - $$ = Action::instantiate($1); - } | TRANSFORMATION { $$ = Transformation::instantiate($1); } + | ACTION_SEVERITY + { + $$ = new Severity($1); + } | ACTION_SETVAR { std::string error; @@ -597,6 +607,10 @@ act: $$ = setVar; } + | LOG_DATA + { + $$ = new LogData($1); + } | ACTION_MSG { $$ = new Msg($1); @@ -619,6 +633,11 @@ act: /* not ready yet. */ $$ = Action::instantiate($1); } + | ACTION_CTL_AUDIT_LOG_PARTS + { + /* not ready yet. */ + $$ = Action::instantiate($1); + } ; actions: diff --git a/src/parser/seclang-scanner.ll b/src/parser/seclang-scanner.ll index 51afde5e..378b1185 100755 --- a/src/parser/seclang-scanner.ll +++ b/src/parser/seclang-scanner.ll @@ -23,16 +23,18 @@ using ModSecurity::split; %} %option noyywrap nounput batch debug noinput -ACTION (?i:accuracy|allow|append|auditlog|block|capture|chain|deny|deprecatevar|drop|exec|expirevar|id:[0-9]+|id:'[0-9]+'|initcol|log|logdata|maturity|multiMatch|noauditlog|nolog|pass|pause|phase:[0-9]+|prepend|proxy|redirect:[A-Z0-9_\|\&\:\/\/\.]+|sanitiseArg|sanitiseMatched|sanitiseMatchedBytes|sanitiseRequestHeader|sanitiseResponseHeader|setuid|setrsc|setsid|setenv|skip|skipAfter|status:[0-9]+|ver|xmlns) -ACTION_SEVERITY (?i:severity:[0-9]+|severity:'[0-9]+'|severity:(EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG)|severity:'(EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG)') +ACTION (?i:accuracy|allow|append|auditlog|block|capture|chain|deny|deprecatevar|drop|exec|expirevar|id:[0-9]+|id:'[0-9]+'|initcol|log|maturity|multiMatch|noauditlog|nolog|pass|pause|phase:[0-9]+|prepend|proxy|redirect:[A-Z0-9_\|\&\:\/\/\.]+|sanitiseArg|sanitiseMatched|sanitiseMatchedBytes|sanitiseRequestHeader|sanitiseResponseHeader|setuid|setrsc|setsid|setenv|skip|skipAfter|status:[0-9]+|ver|xmlns) +ACTION_SEVERITY (?i:severity) +ACTION_SEVERITY_VALUE (?i:(EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG)|[0-9]+) ACTION_SETVAR (?i:setvar) ACTION_MSG (?i:msg) ACTION_TAG (?i:tag) ACTION_REV (?i:rev) ACTION_CTL_BDY_XML ctl:requestBodyProcessor=XML ACTION_CTL_BDY_JSON ctl:requestBodyProcessor=JSON +ACTION_CTL_AUDIT_LOG_PARTS (?i:ctl:auditLogParts) DIRECTIVE SecRule - +LOG_DATA (?i:logdata) CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION (?i:SecPcreMatchLimitRecursion) CONFIG_DIR_PCRE_MATCH_LIMIT (?i:SecPcreMatchLimit) @@ -78,7 +80,7 @@ CONFIG_SEC_REMOTE_RULES (?i:SecRemoteRules) CONFIG_SEC_REMOTE_RULES_FAIL_ACTION (?i:SecRemoteRulesFailAction) -DICT_ELEMENT [A-Za-z_0-9-]+ +DICT_ELEMENT [^ \|\t]+ OPERATOR (?i:(?:@inspectFile|@fuzzyHash|@validateByteRange|@validateDTD|@validateHash|@validateSchema|@verifyCC|@verifyCPF|@verifySSN|@gsbLookup|@rsub)|(?:\!{0,1})(?:@within|@containsWord|@contains|@endsWith|@eq|@ge|@gt|@ipMatchF|@ipMatch|@ipMatchFromFile|@le|@lt|@pmf|@pm|@pmFromFile|@rbl|@rx|@streq|@strmatch|@beginsWith)) @@ -86,7 +88,7 @@ OPERATOR (?i:(?:@inspectFile|@fuzzyHash|@validateByteRange|@validateDTD|@ OPERATORNOARG (?i:@detectSQLi|@detectXSS|@geoLookup|@validateUrlEncoding|@validateUtf8Encoding) -TRANSFORMATION t:(lowercase|urlDecodeUni|urlDecode|none|compressWhitespace|removeWhitespace|replaceNulls|removeNulls|htmlEntityDecode|jsDecode|cssDecode|trim) +TRANSFORMATION t:(lowercase|urlDecodeUni|urlDecode|none|compressWhitespace|removeWhitespace|replaceNulls|removeNulls|htmlEntityDecode|jsDecode|cssDecode|trim|normalizePathWin|length) VARIABLE (?i:UNIQUE_ID|SERVER_PORT|SERVER_ADDR|REMOTE_PORT|REMOTE_HOST|MULTIPART_STRICT_ERROR|PATH_INFO|MULTIPART_NAME|MULTIPART_FILENAME|MULTIPART_CRLF_LF_LINES|MATCHED_VAR_NAME|MATCHED_VARS_NAMES|MATCHED_VAR|MATCHED_VARS|INBOUND_DATA_ERROR|OUTBOUND_DATA_ERROR|FULL_REQUEST|FILES|AUTH_TYPE|ARGS_NAMES|ARGS|QUERY_STRING|REMOTE_ADDR|REQUEST_BASENAME|REQUEST_BODY|REQUEST_COOKIES_NAMES|REQUEST_COOKIES|REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_HEADERS|REQUEST_METHOD|REQUEST_PROTOCOL|REQUEST_URI|RESPONSE_BODY|RESPONSE_CONTENT_LENGTH|RESPONSE_CONTENT_TYPE|RESPONSE_HEADERS_NAMES|RESPONSE_HEADERS|RESPONSE_PROTOCOL|RESPONSE_STATUS|TX|GEO) RUN_TIME_VAR_DUR (?i:DURATION) @@ -123,8 +125,16 @@ CONFIG_VALUE_PATH [0-9A-Za-z_/\.\-]+ AUDIT_PARTS [ABCDEFHJKIZ]+ CONFIG_VALUE_NUMBER [0-9]+ -FREE_TEXT [^\"]+ +FREE_TEXT ([^\"]|([^\\]\\\"))+ + FREE_TEXT_NEW_LINE [^\"|\n]+ +FREE_TEXT_QUOTE ([^\']|([^\\]\\\'))+ +FREE_TEXT_SPACE [^ \t]+ +FREE_TEXT_SPACE_COMMA [^, \t]+ + +VAR_FREE_TEXT_QUOTE ([^\']|([^\\]\\\'))+ +VAR_FREE_TEXT_SPACE_COMMA [^, \t\"]+ +VAR_FREE_TEXT_SPACE [^ \t\"]+ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile) @@ -158,6 +168,7 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile) {CONFIG_DIR_AUDIT_LOG_P}[ ]{AUDIT_PARTS} { return yy::seclang_parser::make_CONFIG_DIR_AUDIT_LOG_P(strchr(yytext, ' ') + 1, *driver.loc.back()); } {CONFIG_DIR_AUDIT_STS}[ ]["]{FREE_TEXT}["] { return yy::seclang_parser::make_CONFIG_DIR_AUDIT_STS(strchr(yytext, ' ') + 1, *driver.loc.back()); } {CONFIG_DIR_AUDIT_TPE} { return yy::seclang_parser::make_CONFIG_DIR_AUDIT_TPE(yytext, *driver.loc.back()); } +{ACTION_CTL_AUDIT_LOG_PARTS}=[+|-]{AUDIT_PARTS} { return yy::seclang_parser::make_ACTION_CTL_AUDIT_LOG_PARTS(yytext, *driver.loc.back()); } %{ /* Debug log entries */ %} {CONFIG_DIR_DEBUG_LOG}[ ]{CONFIG_VALUE_PATH} { return yy::seclang_parser::make_CONFIG_DIR_DEBUG_LOG(strchr(yytext, ' ') + 1, *driver.loc.back()); } @@ -165,23 +176,30 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile) { %{ /* Variables */ %} -[!|&]?{VARIABLE}:?{DICT_ELEMENT}? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_DUR} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_DUR(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_ENV}:?{DICT_ELEMENT}? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_ENV(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_BLD} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_BLD(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_HSV} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_HSV(yytext, *driver.loc.back()); } -[!|&]?{VARIABLENOCOLON} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE(yytext, *driver.loc.back()); } +[!&]?{VARIABLE}:?{DICT_ELEMENT}? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_DUR} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_DUR(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_ENV}:?{DICT_ELEMENT}? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_ENV(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_BLD} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_BLD(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_HSV} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_HSV(yytext, *driver.loc.back()); } +[!&]?{VARIABLENOCOLON} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE(yytext, *driver.loc.back()); } + +["][!&]?{VARIABLE}:?{DICT_ELEMENT}?["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE(yytext, *driver.loc.back()); } +["][!&]?{RUN_TIME_VAR_DUR}["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_DUR(yytext, *driver.loc.back()); } +["][!&]?{RUN_TIME_VAR_ENV}:?{DICT_ELEMENT}?["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_ENV(yytext, *driver.loc.back()); } +["][!&]?{RUN_TIME_VAR_BLD}["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_BLD(yytext, *driver.loc.back()); } +["][!&]?{RUN_TIME_VAR_HSV}["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_HSV(yytext, *driver.loc.back()); } +["][!&]?{VARIABLENOCOLON}["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE(yytext, *driver.loc.back()); } %{ /* Variables: TIME */ %} -[!|&]?{RUN_TIME_VAR_TIME} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_TIME_DAY} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_DAY(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_TIME_EPOCH} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_EPOCH(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_TIME_HOUR} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_HOUR(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_TIME_MIN} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_MIN(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_TIME_MON} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_MON(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_TIME_SEC} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_SEC(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_TIME_WDAY} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_WDAY(yytext, *driver.loc.back()); } -[!|&]?{RUN_TIME_VAR_TIME_YEAR} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_YEAR(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_TIME} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_TIME_DAY} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_DAY(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_TIME_EPOCH} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_EPOCH(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_TIME_HOUR} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_HOUR(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_TIME_MIN} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_MIN(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_TIME_MON} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_MON(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_TIME_SEC} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_SEC(yytext, *driver.loc.back()); } +[&]?{RUN_TIME_VAR_TIME_WDAY} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_WDAY(yytext, *driver.loc.back()); } +[!&]?{RUN_TIME_VAR_TIME_YEAR} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_TIME_YEAR(yytext, *driver.loc.back()); } } @@ -225,20 +243,32 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile) { ["][^@]{FREE_TEXT}["] { BEGIN(INITIAL); return yy::seclang_parser::make_FREE_TEXT(yytext, *driver.loc.back()); } ["]{OPERATOR}[ ]{FREE_TEXT}["] { BEGIN(INITIAL); return yy::seclang_parser::make_OPERATOR(yytext, *driver.loc.back()); } -["]{OPERATORNOARG}["] { BEGIN(INITIAL); return yy::seclang_parser::make_OPERATOR(yytext, *driver.loc.back()); } +["]{OPERATORNOARG}[\t ]*["] { BEGIN(INITIAL); return yy::seclang_parser::make_OPERATOR(yytext, *driver.loc.back()); } } {ACTION} { return yy::seclang_parser::make_ACTION(yytext, *driver.loc.back()); } -{ACTION_SEVERITY} { return yy::seclang_parser::make_ACTION_SEVERITY(yytext, *driver.loc.back()); } -{ACTION_SETVAR}:{FREE_TEXT}={FREE_TEXT} { + +{ACTION_SEVERITY}:{ACTION_SEVERITY_VALUE} { return yy::seclang_parser::make_ACTION_SEVERITY(yytext + 9, *driver.loc.back()); } +{ACTION_SEVERITY}:'{ACTION_SEVERITY_VALUE}' { return yy::seclang_parser::make_ACTION_SEVERITY(std::string(yytext, 10, yyleng - 11), *driver.loc.back()); } + + +{ACTION_SETVAR}:'{VAR_FREE_TEXT_QUOTE}={VAR_FREE_TEXT_QUOTE}' { return yy::seclang_parser::make_ACTION_SETVAR(strchr(yytext, ':') + 1, *driver.loc.back()); } -{ACTION_SETVAR}:{FREE_TEXT} { +{ACTION_SETVAR}:'{VAR_FREE_TEXT_QUOTE}' { return yy::seclang_parser::make_ACTION_SETVAR(strchr(yytext, ':') + 1, *driver.loc.back()); } -{ACTION_MSG}:'{FREE_TEXT}' { return yy::seclang_parser::make_ACTION_MSG(strchr(yytext, ':') + 1, *driver.loc.back()); } -{ACTION_TAG}:'{FREE_TEXT}' { return yy::seclang_parser::make_ACTION_TAG(strchr(yytext, ':') + 1, *driver.loc.back()); } -{ACTION_REV}:'{FREE_TEXT}' { return yy::seclang_parser::make_ACTION_REV(strchr(yytext, ':') + 1, *driver.loc.back()); } +{ACTION_SETVAR}:{VAR_FREE_TEXT_SPACE}={VAR_FREE_TEXT_SPACE_COMMA} { + return yy::seclang_parser::make_ACTION_SETVAR(strchr(yytext, ':') + 1, *driver.loc.back()); + } +{ACTION_SETVAR}:{VAR_FREE_TEXT_SPACE_COMMA} { + return yy::seclang_parser::make_ACTION_SETVAR(strchr(yytext, ':') + 1, *driver.loc.back()); + } + +{LOG_DATA}:'{FREE_TEXT_QUOTE}' { return yy::seclang_parser::make_LOG_DATA(strchr(yytext, ':') + 1, *driver.loc.back()); } +{ACTION_MSG}:'{FREE_TEXT_QUOTE}' { return yy::seclang_parser::make_ACTION_MSG(strchr(yytext, ':') + 1, *driver.loc.back()); } +{ACTION_TAG}:'{FREE_TEXT_QUOTE}' { return yy::seclang_parser::make_ACTION_TAG(strchr(yytext, ':') + 1, *driver.loc.back()); } +{ACTION_REV}:'{CONFIG_VALUE_NUMBER}' { return yy::seclang_parser::make_ACTION_REV(strchr(yytext, ':') + 1, *driver.loc.back()); } {ACTION_CTL_BDY_XML} { return yy::seclang_parser::make_ACTION_CTL_BDY_XML(yytext, *driver.loc.back()); } {ACTION_CTL_BDY_JSON} { return yy::seclang_parser::make_ACTION_CTL_BDY_JSON(yytext, *driver.loc.back()); } diff --git a/src/rules.cc b/src/rules.cc index 4f840cf5..f41bec1d 100644 --- a/src/rules.cc +++ b/src/rules.cc @@ -104,52 +104,53 @@ Rules::~Rules() { * * @param uri Full path to the rules file. * - * @return If rules were loaded successfully or not. + * @return Number of rules loaded, -1 if failed. * @retval true Rules where loaded successfully. * @retval false Problem loading the rules. * */ -bool Rules::loadFromUri(const char *uri) { +int Rules::loadFromUri(const char *uri) { Driver *driver = new Driver(); if (driver->parseFile(uri) == false) { parserError << driver->parserError.str(); - return false; + return -1; } - this->merge(driver); + int rules = this->merge(driver); delete driver; - return true; + return rules; } -bool Rules::load(const char *file, const std::string &ref) { +int Rules::load(const char *file, const std::string &ref) { Driver *driver = new Driver(); if (driver->parse(file, ref) == false) { parserError << driver->parserError.str(); - return false; + return -1; } - this->merge(driver); + int rules = this->merge(driver); delete driver; - return true; + return rules; } -bool Rules::loadRemote(const char *key, const char *uri) { +int Rules::loadRemote(const char *key, const char *uri) { HttpsClient client; + client.setKey(key); bool ret = client.download(uri); if (ret) { return this->load(client.content.c_str(), uri); } - return false; + return -1; } -bool Rules::load(const char *plainRules) { +int Rules::load(const char *plainRules) { return this->load(plainRules, ""); } @@ -178,9 +179,11 @@ int Rules::evaluate(int phase, Assay *assay) { int Rules::merge(Driver *from) { + int amount_of_rules = 0; for (int i = 0; i < ModSecurity::Phases::NUMBER_OF_PHASES; i++) { std::vector rules = from->rules[i]; for (int j = 0; j < rules.size(); j++) { + amount_of_rules++; Rule *rule = rules[j]; this->rules[i].push_back(rule); rule->refCountIncrease(); @@ -208,17 +211,19 @@ int Rules::merge(Driver *from) { this->audit_log = from->audit_log; this->audit_log->refCountIncrease(); - this->debugLog->setDebugLevel(this->debugLevel); - this->debugLog->setOutputFile(this->debug_log_path); + this->debugLog->setDebugLevel(from->debugLevel); + this->debugLog->setOutputFile(from->debug_log_path); - return 0; + return amount_of_rules; } int Rules::merge(Rules *from) { + int amount_of_rules = 0; for (int i = 0; i < ModSecurity::Phases::NUMBER_OF_PHASES; i++) { std::vector rules = from->rules[i]; for (int j = 0; j < rules.size(); j++) { + amount_of_rules++; Rule *rule = rules[j]; this->rules[i].push_back(rule); rule->refCountIncrease(); @@ -244,10 +249,10 @@ int Rules::merge(Rules *from) { this->audit_log = from->audit_log; this->audit_log->refCountIncrease(); - this->debugLog->setDebugLevel(this->debugLevel); - this->debugLog->setOutputFile(this->debug_log_path); + this->debugLog->setDebugLevel(from->debugLevel); + this->debugLog->setOutputFile(from->debug_log_path); - return 0; + return amount_of_rules; } @@ -267,7 +272,7 @@ void Rules::dump() { std::cout << " rules)" << std::endl; for (int j = 0; j < rules.size(); j++) { std::cout << " Rule ID: " << std::to_string(rules[j]->rule_id); - std::cout << std::endl; + std::cout << "--" << rules[j] << std::endl; } } } @@ -297,7 +302,7 @@ extern "C" int msc_rules_add_remote(Rules *rules, const char *key, const char *uri, const char **error) { int ret = rules->loadRemote(key, uri); if (ret == 0) { - *error = rules->getParserError().c_str(); + *error = strdup(rules->getParserError().c_str()); } return ret; } @@ -307,7 +312,7 @@ extern "C" int msc_rules_add_file(Rules *rules, const char *file, const char **error) { int ret = rules->loadFromUri(file); if (ret == 0) { - *error = rules->getParserError().c_str(); + *error = strdup(rules->getParserError().c_str()); } return ret; } @@ -317,7 +322,7 @@ extern "C" int msc_rules_add(Rules *rules, const char *plain_rules, const char **error) { int ret = rules->load(plain_rules); if (ret == 0) { - *error = rules->getParserError().c_str(); + *error = strdup(rules->getParserError().c_str()); } return ret; } diff --git a/src/utils/https_client.cc b/src/utils/https_client.cc index 2fb48905..32ee523d 100644 --- a/src/utils/https_client.cc +++ b/src/utils/https_client.cc @@ -29,6 +29,7 @@ #include #include +#include "modsecurity/modsecurity.h" #include "src/unique_id.h" namespace ModSecurity { @@ -45,12 +46,16 @@ size_t HttpsClient::handle_impl(char* data, size_t size, size_t nmemb) { return size * nmemb; } +void HttpsClient::setKey(const std::string& key) { + m_key = "ModSec-key: " + key; +} #ifdef MSC_WITH_CURL bool HttpsClient::download(const std::string &uri) { CURL *curl; CURLcode res; std::string uniqueId = "ModSec-unique-id: " + UniqueId::uniqueId(); + std::string status = "ModSec-status: " MODSECURITY_VERSION_NUM; curl = curl_easy_init(); if (!curl) { @@ -62,6 +67,10 @@ bool HttpsClient::download(const std::string &uri) { curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); headers_chunk = curl_slist_append(headers_chunk, uniqueId.c_str()); + headers_chunk = curl_slist_append(headers_chunk, status.c_str()); + if (m_key.empty() == false) { + headers_chunk = curl_slist_append(headers_chunk, m_key.c_str()); + } /* Make it TLS 1.x only. */ curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); diff --git a/src/utils/https_client.h b/src/utils/https_client.h index bb43d562..383e31ff 100644 --- a/src/utils/https_client.h +++ b/src/utils/https_client.h @@ -37,15 +37,19 @@ class HttpsClient { public: HttpsClient() : content(""), - error("") { } + error(""), + m_key("") { } bool download(const std::string &uri); std::string content; static size_t handle(char * data, size_t size, size_t nmemb, void * p); size_t handle_impl(char * data, size_t size, size_t nmemb); + void setKey(const std::string& key); std::string error; + private: + std::string m_key; };