mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-11-15 17:12:14 +03:00
Merge branch 'experimental_python_support' of https://github.com/SpiderLabs/ModSecurity into experimental_python_support
This commit is contained in:
@@ -20,6 +20,7 @@ mod_security2_la_SOURCES = acmp.c \
|
||||
msc_multipart.c \
|
||||
msc_parsers.c \
|
||||
msc_pcre.c \
|
||||
msc_python.c \
|
||||
msc_release.c \
|
||||
msc_reqbody.c \
|
||||
msc_tree.c \
|
||||
@@ -41,6 +42,7 @@ mod_security2_la_CFLAGS = @APR_CFLAGS@ \
|
||||
@LUA_CFLAGS@ \
|
||||
@MODSEC_EXTRA_CFLAGS@ \
|
||||
@PCRE_CFLAGS@ \
|
||||
@PYTHON_CFLAGS@ \
|
||||
@YAJL_CFLAGS@
|
||||
|
||||
|
||||
@@ -53,6 +55,7 @@ mod_security2_la_LIBADD = @APR_LDADD@ \
|
||||
@LIBXML2_LDADD@ \
|
||||
@LUA_LDADD@ \
|
||||
@PCRE_LDADD@ \
|
||||
@PYTHON_LDADD@ \
|
||||
@YAJL_LDADD@
|
||||
|
||||
if AIX
|
||||
@@ -63,7 +66,9 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
|
||||
endif
|
||||
|
||||
if HPUX
|
||||
@@ -74,6 +79,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@@ -85,6 +91,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@@ -96,6 +103,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@@ -107,6 +115,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version -R @PCRE_LD_PATH
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@@ -118,6 +127,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@@ -129,6 +139,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@@ -140,6 +151,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include "msc_lua.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
#include "msc_python.h"
|
||||
#endif
|
||||
|
||||
/* -- Directory context creation and initialisation -- */
|
||||
|
||||
@@ -771,11 +774,19 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
|
||||
/* Create the rule now. */
|
||||
switch(type) {
|
||||
#if defined(WITH_LUA)
|
||||
case RULE_TYPE_LUA :
|
||||
case RULE_TYPE_LUA:
|
||||
rule = msre_rule_lua_create(dcfg->ruleset, cmd->directive->filename,
|
||||
cmd->directive->line_num, p1, p2, &my_error_msg);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
case RULE_TYPE_PYTHON:
|
||||
rule = msre_rule_python_create(dcfg->ruleset, cmd->directive->filename,
|
||||
cmd->directive->line_num, p1, p2, &my_error_msg);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default :
|
||||
rule = msre_rule_create(dcfg->ruleset, type, cmd->directive->filename,
|
||||
cmd->directive->line_num, p1, p2, p3, &my_error_msg);
|
||||
@@ -790,6 +801,9 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
|
||||
if (
|
||||
#if defined(WITH_LUA)
|
||||
type != RULE_TYPE_LUA &&
|
||||
#endif
|
||||
#ifdef WITH_PYTHON
|
||||
type != RULE_TYPE_PYTHON &&
|
||||
#endif
|
||||
(dcfg->tmp_chain_starter == NULL))
|
||||
if(rule->actionset == NULL)
|
||||
@@ -799,23 +813,32 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
|
||||
if(rule->actionset->id == NOT_SET_P
|
||||
#if defined(WITH_LUA)
|
||||
&& (type != RULE_TYPE_LUA)
|
||||
#endif
|
||||
#ifdef WITH_PYTHON
|
||||
&& (type != RULE_TYPE_PYTHON)
|
||||
#endif
|
||||
)
|
||||
return "ModSecurity: No action id present within the rule";
|
||||
#if defined(WITH_LUA)
|
||||
if(type != RULE_TYPE_LUA)
|
||||
|
||||
#ifdef WITH_LUA
|
||||
if (type != RULE_TYPE_LUA)
|
||||
#endif
|
||||
{
|
||||
rid = apr_hash_get(dcfg->rule_id_htab, rule->actionset->id, APR_HASH_KEY_STRING);
|
||||
if(rid != NULL) {
|
||||
return "ModSecurity: Found another rule with the same id";
|
||||
} else {
|
||||
apr_hash_set(dcfg->rule_id_htab, apr_pstrdup(dcfg->mp, rule->actionset->id), APR_HASH_KEY_STRING, apr_pstrdup(dcfg->mp, "1"));
|
||||
}
|
||||
#ifdef WITH_PYTHON
|
||||
if (type != RULE_TYPE_PYTHON)
|
||||
#endif
|
||||
{
|
||||
rid = apr_hash_get(dcfg->rule_id_htab, rule->actionset->id, APR_HASH_KEY_STRING);
|
||||
if(rid != NULL) {
|
||||
return "ModSecurity: Found another rule with the same id";
|
||||
} else {
|
||||
apr_hash_set(dcfg->rule_id_htab, apr_pstrdup(dcfg->mp, rule->actionset->id), APR_HASH_KEY_STRING, apr_pstrdup(dcfg->mp, "1"));
|
||||
}
|
||||
|
||||
//tmp_rule = msre_ruleset_fetch_rule(dcfg->ruleset, rule->actionset->id, offset);
|
||||
//if(tmp_rule != NULL)
|
||||
// return "ModSecurity: Found another rule with the same id";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2246,13 +2269,30 @@ static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag)
|
||||
static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg,
|
||||
const char *p1, const char *p2)
|
||||
{
|
||||
#if defined(WITH_LUA)
|
||||
const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
|
||||
return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL);
|
||||
#else
|
||||
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Ignoring SecRuleScript \"%s\" directive (%s:%d): No Lua scripting support.", p1, cmd->directive->filename, cmd->directive->line_num);
|
||||
|
||||
if (strlen(filename) > 3) {
|
||||
const char *p = filename + strlen(filename) - 3;
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
if ((p[0] == '.')&&(p[1] == 'p')&&(p[2] == 'y'))
|
||||
{
|
||||
return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_PYTHON, filename, p2, NULL);
|
||||
}
|
||||
#endif
|
||||
#ifdef WITH_LUA
|
||||
if ((p[0] == 'l')&&(p[1] == 'u')&&(p[2] == 'a'))
|
||||
{
|
||||
return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(WITH_PYTHON) || !defined(WITH_LUA)
|
||||
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Ignoring SecRuleScript \"%s\" directive (%s:%d): No Lua scripting or Python support.", p1, cmd->directive->filename, cmd->directive->line_num);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg,
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
#include "msc_lua.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
#include "msc_python.h"
|
||||
#endif
|
||||
|
||||
#include "msc_status_engine.h"
|
||||
|
||||
|
||||
|
||||
@@ -60,6 +60,10 @@ typedef struct msc_parm msc_parm;
|
||||
#include "msc_lua.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
#include "msc_python.h"
|
||||
#endif
|
||||
|
||||
#define PHASE_REQUEST_HEADERS 1
|
||||
#define PHASE_REQUEST_BODY 2
|
||||
#define PHASE_RESPONSE_HEADERS 3
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
||||
re re_operators re_actions re_tfns re_variables msc_json \
|
||||
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
||||
persist_dbm msc_reqbody pdf_protect msc_geo msc_gsb msc_crypt msc_tree msc_unicode acmp msc_lua
|
||||
persist_dbm msc_reqbody pdf_protect msc_geo msc_gsb msc_crypt msc_tree msc_unicode acmp msc_lua \
|
||||
msc_python
|
||||
|
||||
H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h msc_json.h \
|
||||
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
|
||||
msc_geo.h msc_gsb.h msc_crypt.h msc_tree.h msc_unicode.h acmp.h utf8tables.h msc_lua.h
|
||||
msc_geo.h msc_gsb.h msc_crypt.h msc_tree.h msc_unicode.h acmp.h utf8tables.h msc_lua.h \
|
||||
msc_python.h
|
||||
|
||||
${MOD_SECURITY2:=.slo}: ${H}
|
||||
${MOD_SECURITY2:=.lo}: ${H}
|
||||
|
||||
442
apache2/msc_python.c
Normal file
442
apache2/msc_python.c
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 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.
|
||||
*/
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
|
||||
#include "msc_python.h"
|
||||
|
||||
#include "apr_lib.h"
|
||||
#include "apr_strmatch.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apache2.h"
|
||||
#include <Python.h>
|
||||
|
||||
#define PY_STR_DBG(arg, msr, z) { if (arg == NULL) { msr_log(msr, 8, "Python -%s-:", z); } else { PyObject *e = PyObject_Repr(arg); PyObject *a = PyUnicode_AsEncodedString(e, "utf-8", NULL); char *s = PyBytes_AsString(a); msr_log(msr, 8, "Python -%s-: %s", z, s); } }
|
||||
|
||||
/* ModSecurityI */
|
||||
|
||||
static PyObject *pyModSecurityI_log(PyObject *self, PyObject *args, PyObject *kwds) {
|
||||
char *str = NULL;
|
||||
int level = 0;
|
||||
PyObject *capsuleModSecurity = NULL;
|
||||
modsec_rec *msr = NULL;
|
||||
|
||||
if (PyArg_ParseTuple(args, "is", &level, &str) == 0)
|
||||
{
|
||||
/* PyArg already set this.
|
||||
* PyErr_SetString(PyExc_TypeError, "log() takes exactly 2 arguments.");
|
||||
*/
|
||||
goto end;
|
||||
}
|
||||
|
||||
capsuleModSecurity = PyObject_GetAttrString(self, "capsuleModSecurity");
|
||||
if (capsuleModSecurity == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error paramenter.
|
||||
PyErr_SetString(PyExc_TypeError, "log() needs ModSecurity core to be attached.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
msr = PyCapsule_GetPointer(capsuleModSecurity, "modsecurity");
|
||||
if (msr == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error paramenter.
|
||||
PyErr_SetString(PyExc_TypeError, "log() needs ModSecurity core to be attached.");
|
||||
goto end_no_msr;
|
||||
}
|
||||
|
||||
msr_log(msr, level, str);
|
||||
|
||||
end_no_msr:
|
||||
Py_DECREF(capsuleModSecurity);
|
||||
end:
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *pyModSecurityI_setCapsuleModSecurity(PyObject *self, PyObject *args, PyObject *kwds) {
|
||||
PyObject *capsule = NULL;
|
||||
|
||||
if (PyArg_ParseTuple(args, "O", &capsule) == 0)
|
||||
{
|
||||
/* PyArg already set this.
|
||||
* PyErr_SetString(PyExc_TypeError, "setCapsuleModSecurity() takes exactly 1 argument.");
|
||||
*/
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (capsule == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "setCapsuleModSecurity() Capsule cannot be NULL.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (PyModule_AddObject(self, "capsuleModSecurity", capsule) == -1)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "setCapsuleModSecurity() Failed to save capsule.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *pyModSecurityI_setCapsuleRule(PyObject *self, PyObject *args, PyObject *kwds) {
|
||||
PyObject *capsule = NULL;
|
||||
|
||||
if (PyArg_ParseTuple(args, "O", &capsule) == 0)
|
||||
{
|
||||
/* PyArg already set this.
|
||||
* PyErr_SetString(PyExc_TypeError, "setCapsuleRule() takes exactly 1 argument.");
|
||||
*/
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (capsule == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "setCapsuleRule() Capsule cannot be NULL.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (PyModule_AddObject(self, "capsuleRule", capsule) == -1)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "setCapsuleRule() Failed to save capsule.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *pyModSecurityI_getVariable(PyObject *self, PyObject *args, PyObject *kwds) {
|
||||
char *my_error_msg = NULL;
|
||||
const char *var_name = NULL;
|
||||
const apr_array_header_t *arr = NULL;
|
||||
PyObject *ret = Py_None;
|
||||
PyObject *capsuleRule = NULL;
|
||||
PyObject *capsuleModSecurity = NULL;
|
||||
msre_rule *rule = NULL;
|
||||
msre_var *var = NULL;
|
||||
modsec_rec *msr = NULL;
|
||||
apr_table_t *vartab = NULL;
|
||||
|
||||
if (PyArg_ParseTuple(args, "s", &var_name) == 0)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
capsuleRule = PyObject_GetAttrString(self, "capsuleRule");
|
||||
if (capsuleRule == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "getVariable() needs ModSecurity core to be attached.");
|
||||
goto end_no_rule;
|
||||
}
|
||||
|
||||
capsuleModSecurity = PyObject_GetAttrString(self, "capsuleModSecurity");
|
||||
if (capsuleModSecurity == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "getVariable() needs ModSecurity core to be attached.");
|
||||
goto end_no_msr;
|
||||
}
|
||||
|
||||
rule = PyCapsule_GetPointer(capsuleRule, "rule");
|
||||
msr = PyCapsule_GetPointer(capsuleModSecurity, "modsecurity");
|
||||
if (rule == NULL || msr == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "getVariable() needs ModSecurity core to be attached.");
|
||||
goto end_no_rule_or_msr;
|
||||
}
|
||||
|
||||
var = msre_create_var_ex(msr->msc_rule_mptmp, msr->modsecurity->msre,
|
||||
var_name, '\0', msr, &my_error_msg);
|
||||
|
||||
if (var == NULL)
|
||||
{
|
||||
goto end_no_var;
|
||||
}
|
||||
|
||||
vartab = apr_table_make(msr->msc_rule_mptmp, 16);
|
||||
if (vartab == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "getVariable() Internal error, failed to create var table.");
|
||||
goto end_no_vartab;
|
||||
}
|
||||
|
||||
var->metadata->generate(msr, var, rule, vartab, msr->msc_rule_mptmp);
|
||||
arr = apr_table_elts(vartab);
|
||||
|
||||
if (arr->nelts == 1)
|
||||
{
|
||||
msre_var *vx = generate_single_var(msr, var, NULL, rule, msr->msc_rule_mptmp);
|
||||
if (vx != NULL)
|
||||
{
|
||||
ret = Py_BuildValue("s", vx->value);
|
||||
}
|
||||
}
|
||||
else if (arr->nelts > 1)
|
||||
{
|
||||
// FIXME: We should have an object to encapsulate this dictionary, in order to auto-save the changes.
|
||||
int i = 0;
|
||||
const apr_table_entry_t *te = NULL;
|
||||
PyObject *pDict = PyDict_New();
|
||||
|
||||
te = (apr_table_entry_t *)arr->elts;
|
||||
|
||||
for (i = 0; i < arr->nelts; i++)
|
||||
{
|
||||
msre_var *str = (msre_var *) te[i].val;
|
||||
PyDict_SetItemString(pDict, str->name + strlen(var->name) + 1, Py_BuildValue("s", str->value));
|
||||
}
|
||||
|
||||
ret = pDict;
|
||||
}
|
||||
|
||||
end_no_vartab:
|
||||
end_no_var:
|
||||
end_no_rule_or_msr:
|
||||
Py_DECREF(capsuleModSecurity);
|
||||
end_no_msr:
|
||||
Py_DECREF(capsuleRule);
|
||||
end_no_rule:
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *pyModSecurityI_applyTransformation(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
|
||||
// TODO: Implement.
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "applyTransformation() is not ready yet.");
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *pyModSecurityI_setVariable(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
char *name = NULL;
|
||||
char *value = NULL;
|
||||
PyObject *ret = Py_None;
|
||||
PyObject *capsuleRule = NULL;
|
||||
PyObject *capsuleModSecurity = NULL;
|
||||
msre_rule *rule = NULL;
|
||||
modsec_rec *msr = NULL;
|
||||
|
||||
if (PyArg_ParseTuple(args, "ss", &name, &value) == 0)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
capsuleRule = PyObject_GetAttrString(self, "capsuleRule");
|
||||
if (capsuleRule == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "setVariable() needs ModSecurity core to be attached.");
|
||||
goto end_no_rule;
|
||||
}
|
||||
|
||||
capsuleModSecurity = PyObject_GetAttrString(self, "capsuleModSecurity");
|
||||
if (capsuleModSecurity == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "setVariable() needs ModSecurity core to be attached.");
|
||||
goto end_no_msr;
|
||||
}
|
||||
|
||||
rule = PyCapsule_GetPointer(capsuleRule, "rule");
|
||||
msr = PyCapsule_GetPointer(capsuleModSecurity, "modsecurity");
|
||||
if (rule == NULL || msr == NULL)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "setVariable() needs ModSecurity core to be attached.");
|
||||
goto end_no_rule_or_msr;
|
||||
}
|
||||
|
||||
|
||||
if (msre_action_setvar_execute(msr, msr->msc_rule_mptmp, rule, name, value) != 1)
|
||||
{
|
||||
// FIXME: Use the correct error object.
|
||||
PyErr_SetString(PyExc_TypeError, "setVariable() Internal error. Failed to save variable.");
|
||||
goto end_failed_to_set;
|
||||
}
|
||||
|
||||
end_failed_to_set:
|
||||
end_no_rule_or_msr:
|
||||
Py_DECREF(capsuleModSecurity);
|
||||
end_no_msr:
|
||||
Py_DECREF(capsuleRule);
|
||||
end_no_rule:
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef pyModSecurityI_functions[] = {
|
||||
{ "log", (PyCFunction)pyModSecurityI_log, METH_VARARGS, NULL },
|
||||
{ "setCapsuleModSecurity", (PyCFunction)pyModSecurityI_setCapsuleModSecurity, METH_VARARGS, NULL },
|
||||
{ "setCapsuleRule", (PyCFunction)pyModSecurityI_setCapsuleRule, METH_VARARGS, NULL },
|
||||
{ "getVariable", (PyCFunction)pyModSecurityI_getVariable, METH_VARARGS, NULL },
|
||||
{ "setVariable", (PyCFunction)pyModSecurityI_setVariable, METH_VARARGS, NULL },
|
||||
{ "applyTransformation", (PyCFunction)pyModSecurityI_applyTransformation, METH_VARARGS, NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
static struct PyModuleDef pyModSecurityI_def = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"ModSecurityI",
|
||||
NULL,
|
||||
0,
|
||||
pyModSecurityI_functions,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
// FIXME: Split files.
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
char *python_load(msc_python_script **script, const char *filename, apr_pool_t *pool)
|
||||
{
|
||||
PyObject *pName, *pModule;
|
||||
const char *path = NULL;
|
||||
const char *file = NULL;
|
||||
const char *module = NULL;
|
||||
|
||||
/*
|
||||
* Script path?
|
||||
* FIXME: Avoid to use apr_ functions
|
||||
*/
|
||||
file = apr_filepath_name_get(filename);
|
||||
path = apr_pstrndup(pool, filename, strlen(filename) - strlen(file));
|
||||
|
||||
Py_Initialize();
|
||||
|
||||
PyObject* sysPath = PySys_GetObject((char*)"path");
|
||||
PyList_Append(sysPath, PyUnicode_FromFormat("."));
|
||||
PyList_Append(sysPath, PyUnicode_FromFormat(path));
|
||||
|
||||
module = apr_pstrndup(pool, file, strlen(file) - strlen(".py"));
|
||||
Py_SetProgramName((wchar_t *)module); /* FIXME */
|
||||
|
||||
pName = PyUnicode_FromString(module);
|
||||
pModule = PyImport_Import(pName);
|
||||
|
||||
if (pModule == NULL) {
|
||||
const char *s = NULL;
|
||||
PyObject *err = NULL;
|
||||
PyObject *exc_type = NULL, *exc_value = NULL, *exc_tb = NULL;
|
||||
|
||||
PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
|
||||
err = PyObject_Repr(exc_value); //Now a unicode object
|
||||
PyObject* pyStr = PyUnicode_AsEncodedString(err, "utf-8", NULL);
|
||||
s = PyBytes_AS_STRING(pyStr);
|
||||
|
||||
return apr_psprintf(pool, "ModSecurity: Failed to load script: %s - %s",
|
||||
filename, s);
|
||||
}
|
||||
|
||||
(*script) = apr_pcalloc(pool, sizeof(msc_python_script));
|
||||
(*script)->name = strdup(filename);
|
||||
(*script)->pName = pName;
|
||||
(*script)->pModule = pModule;
|
||||
(*script)->extInstance = NULL;
|
||||
|
||||
Py_DECREF(pName);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Error handling
|
||||
int python_execute(msc_python_script *script, char *param, modsec_rec *msr, msre_rule *rule, char **error_msg) {
|
||||
apr_time_t time_before;
|
||||
int ret = RULE_NO_MATCH;
|
||||
PyObject* methodRes = NULL;
|
||||
PyObject *extObject = NULL;
|
||||
|
||||
if (error_msg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
// if (script->extInstance == NULL) // FIXME: without cache this will draing the performance.
|
||||
// {
|
||||
extObject = PyObject_GetAttrString(script->pModule, "ModSecurityExtension");
|
||||
script->extInstance = PyObject_CallObject(extObject, NULL);
|
||||
|
||||
PyObject *logMod = PyModule_Create(&pyModSecurityI_def);
|
||||
PyObject *capsule_msr = PyCapsule_New(msr, "modsecurity", NULL);
|
||||
PyObject *capsule_rule = PyCapsule_New(rule, "rule", NULL);
|
||||
PyObject* setCapsule1 = PyObject_CallMethod(logMod, "setCapsuleModSecurity", "(O)", capsule_msr);
|
||||
PyObject* setCapsule2 = PyObject_CallMethod(logMod, "setCapsuleRule", "(O)", capsule_rule);
|
||||
|
||||
|
||||
PyObject* setLog = PyObject_CallMethod(script->extInstance, "setModSecurityCore", "(O)", logMod);
|
||||
if (setLog == NULL)
|
||||
{
|
||||
const char *s = NULL;
|
||||
PyObject *exc_type = NULL, *exc_value = NULL, *exc_tb = NULL, *err = NULL;
|
||||
|
||||
PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
|
||||
err = PyObject_Repr(exc_value); //Now a unicode object
|
||||
|
||||
PyObject* pyStr = PyUnicode_AsEncodedString(err, "utf-8", NULL);
|
||||
s = PyBytes_AS_STRING(pyStr);
|
||||
msr_log(msr, 8, "Python problem: %s", s);
|
||||
}
|
||||
// }
|
||||
methodRes = PyObject_CallMethod(script->extInstance, "process", NULL);
|
||||
|
||||
if (methodRes == NULL)
|
||||
{
|
||||
const char *s = NULL;
|
||||
PyObject *exc_type = NULL, *exc_value = NULL, *exc_tb = NULL, *err = NULL;
|
||||
|
||||
PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
|
||||
err = PyObject_Repr(exc_value); //Now a unicode object
|
||||
|
||||
PyObject* pyStr = PyUnicode_AsEncodedString(err, "utf-8", NULL);
|
||||
s = PyBytes_AS_STRING(pyStr);
|
||||
|
||||
*error_msg = apr_psprintf(msr->mp, "Python script failed: '%s'.", s);
|
||||
goto end;
|
||||
}
|
||||
if (methodRes == Py_True)
|
||||
{
|
||||
*error_msg = apr_psprintf(msr->mp, "Python script matched");
|
||||
ret = RULE_MATCH;
|
||||
}
|
||||
|
||||
Py_DECREF(methodRes);
|
||||
end:
|
||||
// Py_DECREF(extInstance);
|
||||
// Py_DECREF(extObject);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* WITH_PYTHON */
|
||||
38
apache2/msc_python.h
Normal file
38
apache2/msc_python.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 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.
|
||||
*/
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
|
||||
#ifndef _MSC_PYTHON_H_
|
||||
#define _MSC_PYTHON_H_
|
||||
|
||||
typedef struct msc_python_script msc_python_script;
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "apr_general.h"
|
||||
#include "apr_tables.h"
|
||||
#include "modsecurity.h"
|
||||
|
||||
struct msc_python_script {
|
||||
const char *name;
|
||||
PyObject *pName;
|
||||
PyObject *pModule;
|
||||
PyObject *extInstance;
|
||||
};
|
||||
|
||||
char DSOLOCAL *python_load(msc_python_script **script, const char *filename, apr_pool_t *pool);
|
||||
|
||||
#endif /* _MSC_PYTHON_H_ */
|
||||
#endif /* WITH_PYTHON */
|
||||
107
apache2/re.c
107
apache2/re.c
@@ -20,6 +20,10 @@
|
||||
#include "msc_lua.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
#include "msc_python.h"
|
||||
#endif
|
||||
|
||||
static const char *const severities[] = {
|
||||
"EMERGENCY",
|
||||
"ALERT",
|
||||
@@ -2327,6 +2331,19 @@ char * msre_rule_generate_unparsed(apr_pool_t *pool, const msre_rule *rule, con
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef WITH_PYTHON
|
||||
case RULE_TYPE_PYTHON:
|
||||
/* SecRuleScript */
|
||||
if (r_actions == NULL) {
|
||||
unparsed = apr_psprintf(pool, "SecRuleScript \"%s\"", r_args);
|
||||
}
|
||||
else {
|
||||
unparsed = apr_psprintf(pool, "SecRuleScript \"%s\" \"%s\"",
|
||||
r_args, log_escape(pool, r_actions));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return unparsed;
|
||||
@@ -2466,6 +2483,54 @@ msre_rule *msre_rule_lua_create(msre_ruleset *ruleset,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
/**
|
||||
* Allocate and initialize the main structure needed for Python
|
||||
* script execution.
|
||||
*
|
||||
*/
|
||||
msre_rule *msre_rule_python_create(msre_ruleset *ruleset,
|
||||
const char *fn, int line, const char *script_filename,
|
||||
const char *actions, char **error_msg)
|
||||
{
|
||||
msre_rule *rule;
|
||||
char *my_error_msg;
|
||||
char *filename = (char *)rule->op_param;
|
||||
|
||||
if (error_msg == NULL) return NULL;
|
||||
*error_msg = NULL;
|
||||
|
||||
rule = (msre_rule *)apr_pcalloc(ruleset->mp, sizeof(msre_rule));
|
||||
if (rule == NULL) return NULL;
|
||||
|
||||
rule->type = RULE_TYPE_PYTHON;
|
||||
rule->ruleset = ruleset;
|
||||
rule->filename = apr_pstrdup(ruleset->mp, fn);
|
||||
rule->line_num = line;
|
||||
|
||||
/* Load the script */
|
||||
*error_msg = python_load(&rule->python_script, script_filename, ruleset->mp);
|
||||
if (*error_msg != NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Parse actions */
|
||||
if (actions != NULL) {
|
||||
/* Create per-rule actionset */
|
||||
rule->actionset = msre_actionset_create(ruleset->engine, ruleset->mp, actions, &my_error_msg);
|
||||
if (rule->actionset == NULL) {
|
||||
*error_msg = apr_psprintf(ruleset->mp, "Error parsing actions: %s", my_error_msg);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the unparsed rule */
|
||||
rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, NULL, script_filename, NULL);
|
||||
|
||||
return rule;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Perform non-disruptive actions associated with the provided actionset.
|
||||
*/
|
||||
@@ -3331,6 +3396,41 @@ static apr_status_t msre_rule_process_lua(msre_rule *rule, modsec_rec *msr) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
static apr_status_t msre_rule_process_python(msre_rule *rule, modsec_rec *msr) {
|
||||
msre_actionset *acting_actionset = NULL;
|
||||
char *my_error_msg = NULL;
|
||||
int rc = 0;
|
||||
/* Choose the correct metadata/disruptive action actionset. */
|
||||
acting_actionset = rule->actionset;
|
||||
if (rule->chain_starter != NULL) {
|
||||
acting_actionset = rule->chain_starter->actionset;
|
||||
}
|
||||
|
||||
rc = python_execute(rule->python_script, NULL, msr, rule, &my_error_msg);
|
||||
if (rc < 0) {
|
||||
msr_log(msr, 1, "%s", my_error_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* A non-NULL error message means the rule matched. */
|
||||
if (my_error_msg != NULL) {
|
||||
/* Perform non-disruptive actions. */
|
||||
msre_perform_nondisruptive_actions(msr, rule, rule->actionset, msr->msc_rule_mptmp);
|
||||
|
||||
/* Perform disruptive actions, but only if
|
||||
* this rule is not part of a chain.
|
||||
*/
|
||||
if (rule->actionset->is_chained == 0) {
|
||||
msre_perform_disruptive_actions(msr, rule, acting_actionset, msr->msc_rule_mptmp, my_error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -3350,6 +3450,13 @@ static apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
if (rule->type == RULE_TYPE_PYTHON) {
|
||||
return msre_rule_process_python(rule, msr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return msre_rule_process_normal(rule, msr);
|
||||
}
|
||||
|
||||
|
||||
19
apache2/re.h
19
apache2/re.h
@@ -46,6 +46,10 @@ typedef struct msre_cache_rec msre_cache_rec;
|
||||
#include "msc_lua.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
#include "msc_python.h"
|
||||
#endif
|
||||
|
||||
/* Actions, variables, functions and operator functions */
|
||||
char DSOLOCAL *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *rule, const char *p2,
|
||||
const char *p3);
|
||||
@@ -136,7 +140,10 @@ int DSOLOCAL msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset
|
||||
#define RULE_TYPE_ACTION 1 /* SecAction */
|
||||
#define RULE_TYPE_MARKER 2 /* SecMarker */
|
||||
#if defined(WITH_LUA)
|
||||
#define RULE_TYPE_LUA 3 /* SecRuleScript */
|
||||
#define RULE_TYPE_LUA 3 /* SecRuleScript - lua */
|
||||
#endif
|
||||
#ifdef WITH_PYTHON
|
||||
#define RULE_TYPE_PYTHON 4 /* SecRuleScript - python */
|
||||
#endif
|
||||
|
||||
struct msre_rule {
|
||||
@@ -167,6 +174,10 @@ struct msre_rule {
|
||||
msc_script *script;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
msc_python_script *python_script;
|
||||
#endif
|
||||
|
||||
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 0
|
||||
ap_regex_t *sub_regex;
|
||||
#else
|
||||
@@ -192,6 +203,12 @@ msre_rule DSOLOCAL *msre_rule_lua_create(msre_ruleset *ruleset,
|
||||
const char *actions, char **error_msg);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
msre_rule DSOLOCAL *msre_rule_python_create(msre_ruleset *ruleset,
|
||||
const char *fn, int line, const char *script_filename,
|
||||
const char *actions, char **error_msg);
|
||||
#endif
|
||||
|
||||
#define VAR_SIMPLE 0 /* REQUEST_URI */
|
||||
#define VAR_LIST 1
|
||||
|
||||
|
||||
@@ -3733,6 +3733,23 @@ static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) {
|
||||
|
||||
filename = resolve_relative_path(rule->ruleset->mp, rule->filename, filename);
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
/* ENH Write & use string_ends(s, e). */
|
||||
if (strlen(rule->op_param) > 3) {
|
||||
char *p = filename + strlen(filename) - 3;
|
||||
if ((p[0] == '.')&&(p[1] == 'p')&&(p[2] == 'y'))
|
||||
{
|
||||
msc_python_script *script = NULL;
|
||||
|
||||
/* Compile script. */
|
||||
*error_msg = python_load(&script, filename, rule->ruleset->mp);
|
||||
if (*error_msg != NULL) return -1;
|
||||
|
||||
rule->op_param_data = script;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_LUA)
|
||||
/* ENH Write & use string_ends(s, e). */
|
||||
if (strlen(rule->op_param) > 4) {
|
||||
@@ -3748,7 +3765,7 @@ static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) {
|
||||
rule->op_param_data = script;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (rule->op_param_data == NULL) {
|
||||
/* ENH Verify the script exists and that we have
|
||||
|
||||
Reference in New Issue
Block a user