Adds XML variable, xml body request processor and @validateSchema

This commit is contained in:
Felipe Zimmerle
2016-05-11 21:40:06 -03:00
parent 35636674e3
commit 6a40752500
19 changed files with 1296 additions and 33 deletions

View File

@@ -56,7 +56,8 @@ VARIABLES = \
variables/tx.cc \
variables/variable.cc \
variables/variations/count.cc \
variables/variations/exclusion.cc
variables/variations/exclusion.cc \
variables/xml.cc
ACTIONS = \
@@ -179,6 +180,12 @@ COLLECTION = \
collection/backend/in_memory-per_process.cc
BODY_PROCESSORS = \
request_body_processor/multipart.cc \
request_body_processor/multipart_blob.cc \
request_body_processor/xml.cc
libmodsecurity_la_SOURCES = \
parser/seclang-parser.yy \
parser/seclang-scanner.ll \
@@ -196,10 +203,9 @@ libmodsecurity_la_SOURCES = \
debug_log_writer.cc \
debug_log_writer_agent.cc \
macro_expansion.cc \
request_body_processor/multipart.cc \
request_body_processor/multipart_blob.cc \
rule.cc \
unique_id.cc \
${BODY_PROCESSORS} \
${ACTIONS} \
${COLLECTION} \
${OPERATORS} \
@@ -221,16 +227,18 @@ libmodsecurity_la_CPPFLAGS = \
$(GLOBAL_CPPFLAGS) \
$(MODSEC_NO_LOGS) \
$(YAJL_CFLAGS) \
$(PCRE_CFLAGS)
$(PCRE_CFLAGS) \
$(LIBXML2_CFLAGS)
libmodsecurity_la_LIBADD = \
$(GLOBAL_LDADD) \
$(CURL_LDADD) \
$(GEOIP_LDFLAGS) $(GEOIP_LDADD) \
@LEXLIB@ \
$(PCRE_LDADD) \
$(YAJL_LDADD) \
../others/libinjection.la
$(GLOBAL_LDADD) \
$(CURL_LDADD) \
$(GEOIP_LDFLAGS) $(GEOIP_LDADD) \
@LEXLIB@ \
$(PCRE_LDADD) \
$(YAJL_LDADD) \
$(LIBXML2_LDADD) \
../others/libinjection.la
libmodsecurity_la_LDFLAGS = \

View File

@@ -18,26 +18,116 @@
#include <string>
#include "operators/operator.h"
#include "request_body_processor/xml.h"
#include "src/utils.h"
namespace modsecurity {
namespace operators {
bool ValidateSchema::evaluate(Transaction *transaction,
const std::string &str) {
/**
* @todo Implement the operator ValidateSchema.
* Reference: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#validateSchema
*/
bool ValidateSchema::init(const std::string &file, const char **error) {
m_resource = find_resource(param, file);
if (m_resource == "") {
std::string f("XML: File not found: " + param + ".");
*error = strdup(f.c_str());
return false;
}
m_parserCtx = xmlSchemaNewParserCtxt(m_resource.c_str());
if (m_parserCtx == NULL) {
std::stringstream err;
err << "XML: Failed to load Schema from file: ";
err << m_resource;
err << ". ";
if (m_err.empty() == false) {
err << m_err;
}
*error = strdup(err.str().c_str());
return false;
}
xmlSchemaSetParserErrors(m_parserCtx,
(xmlSchemaValidityErrorFunc)error_load,
(xmlSchemaValidityWarningFunc)warn_load, &m_err);
xmlThrDefSetGenericErrorFunc(m_parserCtx,
null_error);
xmlSetGenericErrorFunc(m_parserCtx,
null_error);
m_schema = xmlSchemaParse(m_parserCtx);
if (m_schema == NULL) {
std::stringstream err;
err << "XML: Failed to load Schema: ";
err << m_resource;
err << ".";
if (m_err.empty() == false) {
err << " " << m_err;
}
*error = strdup(err.str().c_str());
xmlSchemaFreeParserCtxt(m_parserCtx);
return false;
}
m_validCtx = xmlSchemaNewValidCtxt(m_schema);
if (m_validCtx == NULL) {
std::stringstream err("XML: Failed to create validation context.");
if (m_err.empty() == false) {
err << " " << m_err;
}
*error = strdup(err.str().c_str());
return false;
}
return true;
}
ValidateSchema::ValidateSchema(std::string op, std::string param,
bool negation)
: Operator() {
this->op = op;
this->param = param;
bool ValidateSchema::evaluate(Transaction *t,
const std::string &str) {
int rc;
/* Send validator errors/warnings to msr_log */
xmlSchemaSetValidErrors(m_validCtx,
(xmlSchemaValidityErrorFunc)error_runtime,
(xmlSchemaValidityWarningFunc)warn_runtime, t);
if (t->m_xml->m_data.doc == NULL) {
t->debug(4, "XML document tree could not be found for " \
"schema validation.");
return true;
}
if (t->m_xml->m_data.well_formed != 1) {
t->debug(4, "XML: Schema validation failed because " \
"content is not well formed.");
return true;
}
/* Make sure there were no other generic processing errors */
/*
if (msr->msc_reqbody_error) {
t->debug(4, "XML: Schema validation could not proceed due to previous"
" processing errors.");
return true;
}
*/
rc = xmlSchemaValidateDoc(m_validCtx, t->m_xml->m_data.doc);
if (rc != 0) {
t->debug(4, "XML: Schema validation failed.");
xmlSchemaFree(m_schema);
xmlSchemaFreeParserCtxt(m_parserCtx);
return true; /* No match. */
}
t->debug(4, "XML: Successfully validated payload against " \
"Schema: " + m_resource);
return false;
}
} // namespace operators
} // namespace modsecurity

View File

@@ -16,6 +16,12 @@
#ifndef SRC_OPERATORS_VALIDATE_SCHEMA_H_
#define SRC_OPERATORS_VALIDATE_SCHEMA_H_
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <libxml/xmlschemas.h>
#include <libxml/xpath.h>
#include <string>
#include "operators/operator.h"
@@ -27,8 +33,100 @@ namespace operators {
class ValidateSchema : public Operator {
public:
/** @ingroup ModSecurity_Operator */
ValidateSchema(std::string o, std::string p, bool i);
ValidateSchema(std::string o, std::string p, bool i)
: Operator(o, p, i),
m_schema(NULL),
m_validCtx(NULL),
m_parserCtx(NULL) { }
~ValidateSchema() {
/*
if (m_schema != NULL) {
xmlSchemaFree(m_schema);
m_schema = NULL;
}
*/
if (m_validCtx != NULL) {
xmlSchemaFreeValidCtxt(m_validCtx);
m_validCtx = NULL;
}
}
bool evaluate(Transaction *transaction, const std::string &str) override;
bool init(const std::string &file, const char **error) override;
static void error_load(void *ctx, const char *msg, ...) {
std::string *t = reinterpret_cast<std::string *>(ctx);
char buf[1024];
va_list args;
va_start(args, msg);
int len = vsnprintf(buf, sizeof(buf), msg, args);
va_end(args);
if (len > 0) {
t->append("XML Error: " + std::string(buf));
}
}
static void warn_load(void *ctx, const char *msg, ...) {
std::string *t = reinterpret_cast<std::string *>(ctx);
char buf[1024];
va_list args;
va_start(args, msg);
int len = vsnprintf(buf, sizeof(buf), msg, args);
va_end(args);
if (len > 0) {
t->append("XML Warning: " + std::string(buf));
}
}
static void error_runtime(void *ctx, const char *msg, ...) {
Transaction *t = reinterpret_cast<Transaction *>(ctx);
char buf[1024];
std::string s;
va_list args;
va_start(args, msg);
int len = vsnprintf(buf, sizeof(buf), msg, args);
va_end(args);
if (len > 0) {
s = "XML Error: " + std::string(buf);
}
t->debug(4, s);
}
static void warn_runtime(void *ctx, const char *msg, ...) {
Transaction *t = reinterpret_cast<Transaction *>(ctx);
char buf[1024];
std::string s;
va_list args;
va_start(args, msg);
int len = vsnprintf(buf, sizeof(buf), msg, args);
va_end(args);
if (len > 0) {
s = "XML Warning: " + std::string(buf);
}
t->debug(4, s);
}
static void null_error(void *ctx, const char *msg, ...) {
}
private:
xmlSchemaParserCtxtPtr m_parserCtx;
xmlSchemaValidCtxtPtr m_validCtx;
xmlSchemaPtr m_schema;
std::string m_resource;
std::string m_err;
};
} // namespace operators

View File

@@ -61,6 +61,7 @@ class Driver;
#include "variables/time_wday.h"
#include "variables/time_year.h"
#include "variables/tx.h"
#include "variables/xml.h"
using modsecurity::ModSecurity;
@@ -103,6 +104,7 @@ using modsecurity::Variables::TimeWDay;
using modsecurity::Variables::TimeYear;
using modsecurity::Variables::Variable;
using modsecurity::Variables::Tx;
using modsecurity::Variables::XML;
#define CHECK_VARIATION_DECL \
@@ -229,6 +231,7 @@ using modsecurity::Variables::Tx;
%token <std::string> RUN_TIME_VAR_TIME_SEC
%token <std::string> RUN_TIME_VAR_TIME_WDAY
%token <std::string> RUN_TIME_VAR_TIME_YEAR
%token <std::string> RUN_TIME_VAR_XML
%token <std::string> CONFIG_SEC_REMOTE_RULES_FAIL_ACTION
@@ -816,6 +819,15 @@ var:
if (!var) { var = new TimeYear(name); }
$$ = var;
}
| RUN_TIME_VAR_XML
{
std::string name($1);
CHECK_VARIATION_DECL
CHECK_VARIATION(&) { var = new Count(new XML(name)); }
CHECK_VARIATION(!) { var = new Exclusion(new XML(name)); }
if (!var) { var = new XML(name); }
$$ = var;
}
;
act:

View File

@@ -117,7 +117,7 @@ TRANSFORMATION t:(?i:(cmdLine|sha1|hexEncode|lowercase|urlDecodeUni|urlDecode|n
VARIABLE (?i:(RESOURCE|ARGS_COMBINED_SIZE|ARGS_GET_NAMES|ARGS_POST_NAMES|FILES_COMBINED_SIZE|FULL_REQUEST_LENGTH|REQUEST_BODY_LENGTH|REQUEST_URI_RAW|UNIQUE_ID|SERVER_PORT|SERVER_ADDR|REMOTE_PORT|REMOTE_HOST|MULTIPART_STRICT_ERROR|PATH_INFO|MULTIPART_CRLF_LF_LINES|MATCHED_VAR_NAME|MATCHED_VAR|INBOUND_DATA_ERROR|OUTBOUND_DATA_ERROR|FULL_REQUEST|AUTH_TYPE|ARGS_NAMES|REMOTE_ADDR|REQUEST_BASENAME|REQUEST_BODY|REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_METHOD|REQUEST_PROTOCOL|REQUEST_URI|RESPONSE_BODY|RESPONSE_CONTENT_LENGTH|RESPONSE_CONTENT_TYPE|RESPONSE_HEADERS_NAMES|RESPONSE_PROTOCOL|RESPONSE_STATUS|REQBODY_PROCESSOR|USERID|SESSIONID))
VARIABLE_COL (?i:(SESSION|GLOBAL|ARGS_POST|ARGS_GET|ARGS|FILES_SIZES|FILES_NAMES|FILES_TMP_CONTENT|MULTIPART_FILENAME|MULTIPART_NAME|MATCHED_VARS_NAMES|MATCHED_VARS|FILES|QUERY_STRING|REQUEST_COOKIES|REQUEST_HEADERS|RESPONSE_HEADERS|GEO|IP|XML|REQUEST_COOKIES_NAMES))
VARIABLE_COL (?i:(SESSION|GLOBAL|ARGS_POST|ARGS_GET|ARGS|FILES_SIZES|FILES_NAMES|FILES_TMP_CONTENT|MULTIPART_FILENAME|MULTIPART_NAME|MATCHED_VARS_NAMES|MATCHED_VARS|FILES|QUERY_STRING|REQUEST_COOKIES|REQUEST_HEADERS|RESPONSE_HEADERS|GEO|IP|REQUEST_COOKIES_NAMES))
VARIABLE_TX (?i:TX)
VARIABLE_WEBSERVER_ERROR_LOG (?:WEBSERVER_ERROR_LOG)
@@ -136,6 +136,7 @@ RUN_TIME_VAR_TIME_MON (?i:TIME_MON)
RUN_TIME_VAR_TIME_SEC (?i:TIME_SEC)
RUN_TIME_VAR_TIME_WDAY (?i:TIME_WDAY)
RUN_TIME_VAR_TIME_YEAR (?i:TIME_YEAR)
RUN_TIME_VAR_XML (?i:XML)
VARIABLENOCOLON (?i:REQBODY_ERROR|MULTIPART_STRICT_ERROR|MULTIPART_UNMATCHED_BOUNDARY|REMOTE_ADDR|REQUEST_LINE)
@@ -227,6 +228,8 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
[!&]?{VARIABLE}(\:[\']{FREE_TEXT_QUOTE}[\'])? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE(yytext, *driver.loc.back()); }
[!&]?{VARIABLE_COL}(\:{DICT_ELEMENT})? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_COL(yytext, *driver.loc.back()); }
[!&]?{VARIABLE_COL}(\:[\']{FREE_TEXT_QUOTE}[\'])? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_COL(yytext, *driver.loc.back()); }
[!&]?{RUN_TIME_VAR_XML}(\:{DICT_ELEMENT})? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_XML(yytext, *driver.loc.back()); }
[!&]?{RUN_TIME_VAR_XML}(\:[\']{FREE_TEXT_QUOTE}[\'])? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_XML(yytext, *driver.loc.back()); }
[!&]?{VARIABLE_TX}(\:{DICT_ELEMENT})? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_TX(yytext, *driver.loc.back()); }
[!&]?{VARIABLE_TX}(\:[\']{FREE_TEXT_QUOTE}[\'])? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_TX(yytext, *driver.loc.back()); }
[!&]?{RUN_TIME_VAR_DUR} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_DUR(yytext, *driver.loc.back()); }
@@ -243,6 +246,8 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
["][!&]?{VARIABLE_TX}(\:[\']{FREE_TEXT_QUOTE}[\'])?["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_TX(yytext, *driver.loc.back()); }
["][!&]?{VARIABLE_COL}(\:{DICT_ELEMENT})? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_COL(yytext, *driver.loc.back()); }
["][!&]?{VARIABLE_COL}(\:[\']{FREE_TEXT_QUOTE}[\'])?["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_COL(yytext, *driver.loc.back()); }
["][!&]?{RUN_TIME_VAR_XML}(\:{DICT_ELEMENT})? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_XML(yytext, *driver.loc.back()); }
["][!&]?{RUN_TIME_VAR_XML}(\:[\']{FREE_TEXT_QUOTE}[\'])?["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_XML(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()); }

View File

@@ -0,0 +1,122 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include "request_body_processor/xml.h"
#include <list>
#include <iostream>
#include <string>
namespace modsecurity {
namespace RequestBodyProcessor {
XML::XML(Transaction *transaction)
: m_transaction(transaction) {
m_data.doc = NULL;
m_data.parsing_ctx = NULL;
m_data.sax_handler = NULL;
}
XML::~XML() {
if (m_data.doc != NULL) {
xmlFreeDoc(m_data.doc);
m_data.doc = NULL;
}
}
bool XML::init() {
// xmlParserInputBufferCreateFilenameFunc entity;
// entity = xmlParserInputBufferCreateFilenameDefault(
// this->unloadExternalEntity);
return true;
}
bool XML::processChunk(const char *buf, unsigned int size) {
/* We want to initialise our parsing context here, to
* enable us to pass it the first chunk of data so that
* it can attempt to auto-detect the encoding.
*/
if (m_data.parsing_ctx == NULL) {
/* First invocation. */
debug(4, "XML: Initialising parser.");
/* NOTE When Sax interface is used libxml will not
* create the document object, but we need it.
msr->xml->sax_handler = (xmlSAXHandler *)apr_pcalloc(msr->mp,
sizeof(xmlSAXHandler));
if (msr->xml->sax_handler == NULL) return -1;
msr->xml->sax_handler->error = xml_receive_sax_error;
msr->xml->sax_handler->warning = xml_receive_sax_error;
msr->xml->parsing_ctx = xmlCreatePushParserCtxt(msr->xml->sax_handler,
msr, buf, size, "body.xml");
*/
m_data.parsing_ctx = xmlCreatePushParserCtxt(NULL, NULL,
buf, size, "body.xml");
if (m_data.parsing_ctx == NULL) {
debug(4, "XML: Failed to create parsing context.");
return false;
}
return true;
}
/* Not a first invocation. */
xmlParseChunk(m_data.parsing_ctx, buf, size, 0);
if (m_data.parsing_ctx->wellFormed != 1) {
debug(4, "XML: Failed parsing document.");
return false;
}
return true;
}
bool XML::complete() {
/* Only if we have a context, meaning we've done some work. */
if (m_data.parsing_ctx != NULL) {
/* This is how we signalise the end of parsing to libxml. */
xmlParseChunk(m_data.parsing_ctx, NULL, 0, 1);
/* Preserve the results for our reference. */
m_data.well_formed = m_data.parsing_ctx->wellFormed;
m_data.doc = m_data.parsing_ctx->myDoc;
/* Clean up everything else. */
xmlFreeParserCtxt(m_data.parsing_ctx);
m_data.parsing_ctx = NULL;
debug(4, "XML: Parsing complete (well_formed " \
+ std::to_string(m_data.well_formed) + ").");
if (m_data.well_formed != 1) {
debug(4, "XML: Failed parsing document.");
return false;
}
}
return true;
}
} // namespace RequestBodyProcessor
} // namespace modsecurity

View File

@@ -0,0 +1,68 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <libxml/xmlschemas.h>
#include <libxml/xpath.h>
#include <string>
#include <iostream>
#include "modsecurity/transaction.h"
#ifndef SRC_REQUEST_BODY_PROCESSOR_XML_H_
#define SRC_REQUEST_BODY_PROCESSOR_XML_H_
namespace modsecurity {
namespace RequestBodyProcessor {
struct xml_data {
xmlSAXHandler *sax_handler;
xmlParserCtxtPtr parsing_ctx;
xmlDocPtr doc;
unsigned int well_formed;
};
typedef struct xml_data xml_data;
class XML {
public:
explicit XML(Transaction *transaction);
~XML();
bool init();
bool processChunk(const char *buf, unsigned int size);
bool complete();
static xmlParserInputBufferPtr unloadExternalEntity(const char *URI,
xmlCharEncoding enc) { return NULL; }
#ifndef NO_LOGS
void debug(int a, std::string str) {
m_transaction->debug(a, str);
}
#endif
xml_data m_data;
private:
Transaction *m_transaction;
std::string m_header;
};
} // namespace RequestBodyProcessor
} // namespace modsecurity
#endif // SRC_REQUEST_BODY_PROCESSOR_XML_H_

View File

@@ -37,6 +37,7 @@
#include "modsecurity/intervention.h"
#include "modsecurity/modsecurity.h"
#include "request_body_processor/multipart.h"
#include "request_body_processor/xml.h"
#include "audit_log/audit_log.h"
#include "src/unique_id.h"
#include "src/utils.h"
@@ -44,6 +45,7 @@
using modsecurity::actions::Action;
using modsecurity::RequestBodyProcessor::Multipart;
using modsecurity::RequestBodyProcessor::XML;
namespace modsecurity {
@@ -113,7 +115,8 @@ Transaction::Transaction(ModSecurity *ms, Rules *rules, void *logCbData)
m_logCbData(logCbData),
m_ms(ms),
m_collections(ms->m_global_collection, ms->m_ip_collection,
ms->m_session_collection, ms->m_user_collection) {
ms->m_session_collection, ms->m_user_collection),
m_xml(new RequestBodyProcessor::XML(this)) {
m_id = std::to_string(this->m_timeStamp) + \
std::to_string(generate_transaction_unique_id());
m_rules->incrementReferenceCount();
@@ -156,6 +159,8 @@ Transaction::~Transaction() {
m_rulesMessages.clear();
m_rules->decrementReferenceCount();
delete m_xml;
}
@@ -478,6 +483,10 @@ int Transaction::addRequestHeader(const std::string& key,
if (l == "application/x-www-form-urlencoded") {
this->m_requestBodyType = WWWFormUrlEncoded;
}
if (l == "text/xml") {
this->m_requestBodyType = XMLRequestBody;
}
}
return 1;
}
@@ -581,6 +590,18 @@ int Transaction::processRequestBody() {
*
*/
if (m_requestBodyType == XMLRequestBody) {
std::string *a = m_collections.resolveFirst(
"REQUEST_HEADERS:Content-Type");
if (a != NULL) {
if (m_xml->init() == true) {
m_xml->processChunk(m_requestBody.str().c_str(),
m_requestBody.str().size());
m_xml->complete();
}
}
}
if (m_requestBodyType == MultiPartRequestBody) {
std::string *a = m_collections.resolveFirst(
"REQUEST_HEADERS:Content-Type");

138
src/variables/xml.cc Normal file
View File

@@ -0,0 +1,138 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include "variables/xml.h"
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libxml/xmlschemas.h>
#include <libxml/xpath.h>
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <utility>
#include "modsecurity/transaction.h"
#include "src/request_body_processor/xml.h"
namespace modsecurity {
namespace Variables {
void XML::evaluateInternal(Transaction *t,
std::vector<const collection::Variable *> *l) {
xmlXPathContextPtr xpathCtx;
xmlXPathObjectPtr xpathObj;
xmlNodeSetPtr nodes;
std::string key;
std::string param;
const xmlChar* xpathExpr = NULL;
int i;
size_t pos;
pos = m_name.find_first_of(":");
if (pos == std::string::npos) {
key = std::string(m_name, 0);
param = "";
} else {
key = std::string(m_name, 0, pos);
param = std::string(m_name, pos+1, m_name.length() - (pos + 1));
}
/* Is there an XML document tree at all? */
if (t->m_xml->m_data.doc == NULL) {
/* Sorry, we've got nothing to give! */
return;
}
if (param.empty() == true) {
/* Invocation without an XPath expression makes sense
* with functions that manipulate the document tree.
*/
l->push_back(new collection::Variable("XML",
std::string("[XML document tree]" + param)));
return;
}
/* Process the XPath expression. */
xpathExpr = (const xmlChar*)param.c_str();
xpathCtx = xmlXPathNewContext(t->m_xml->m_data.doc);
if (xpathCtx == NULL) {
t->debug(1, "XML: Unable to create new XPath context.");
return;
}
#if 0
/* Look through the actionset of the associated rule
* for the namespace information. Register them if any are found.
*/
tarr = apr_table_elts(rule->actionset->actions);
telts = (const apr_table_entry_t*)tarr->elts;
for (i = 0; i < tarr->nelts; i++) {
msre_action *action = (msre_action *)telts[i].val;
if (strcasecmp(action->metadata->name, "xmlns") == 0) {
char *prefix, *href;
if (parse_name_eq_value(mptmp, action->param, &prefix, &href) < 0) return -1;
if ((prefix == NULL)||(href == NULL)) return -1;
if(xmlXPathRegisterNs(xpathCtx, (const xmlChar*)prefix, (const xmlChar*)href) != 0) {
msr_log(msr, 1, "Failed to register XML namespace href \"%s\" prefix \"%s\".",
log_escape(mptmp, prefix), log_escape(mptmp, href));
return -1;
}
msr_log(msr, 4, "Registered XML namespace href \"%s\" prefix \"%s\".",
log_escape(mptmp, prefix), log_escape(mptmp, href));
}
}
#endif
/* Initialise XPath expression. */
xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
if (xpathObj == NULL) {
t->debug(1, "XML: Unable to evaluate xpath expression.");
xmlXPathFreeContext(xpathCtx);
return;
}
/* Evaluate XPath expression. */
nodes = xpathObj->nodesetval;
if (nodes == NULL) {
xmlXPathFreeObject(xpathObj);
xmlXPathFreeContext(xpathCtx);
return;
}
/* Create one variable for each node in the result. */
for (i = 0; i < nodes->nodeNr; i++) {
char *content = NULL;
content = reinterpret_cast<char *>(
xmlNodeGetContent(nodes->nodeTab[i]));
if (content != NULL) {
l->push_back(new collection::Variable(m_name,
std::string(content)));
xmlFree(content);
}
}
xmlXPathFreeObject(xpathObj);
xmlXPathFreeContext(xpathCtx);
}
} // namespace Variables
} // namespace modsecurity

45
src/variables/xml.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <utility>
#ifndef SRC_VARIABLES_XML_H_
#define SRC_VARIABLES_XML_H_
#include "variables/variable.h"
#include "src/variables/xml.h"
namespace modsecurity {
class Transaction;
namespace Variables {
class XML : public Variable {
public:
explicit XML(std::string _name)
: Variable(_name) { }
void evaluateInternal(Transaction *transaction,
std::vector<const collection::Variable *> *l) override;
};
} // namespace Variables
} // namespace modsecurity
#endif // SRC_VARIABLES_XML_H_