Merge branch 'experimental_python_support' of https://github.com/SpiderLabs/ModSecurity into experimental_python_support

This commit is contained in:
root
2014-10-24 17:54:34 -04:00
20 changed files with 1053 additions and 18 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -37,6 +37,10 @@
#include "msc_lua.h"
#endif
#ifdef WITH_PYTHON
#include "msc_python.h"
#endif
#include "msc_status_engine.h"

View File

@@ -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

View File

@@ -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
View 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
View 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 */

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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