mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-14 05:45:59 +03:00
Merge branch 'experimental_python_support' of https://github.com/SpiderLabs/ModSecurity into experimental_python_support
This commit is contained in:
commit
11756d0dcf
@ -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
|
||||
|
149
build/find_python.m4
Normal file
149
build/find_python.m4
Normal file
@ -0,0 +1,149 @@
|
||||
dnl Check for PYTHON Libraries
|
||||
dnl Sets:
|
||||
|
||||
|
||||
AC_DEFUN([CHECK_PYTHON],
|
||||
[dnl
|
||||
|
||||
AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
|
||||
PYTHON_CONFIG=""
|
||||
PYTHON_VERSION=""
|
||||
PYTHON_CFLAGS=""
|
||||
PYTHON_CPPFLAGS=""
|
||||
PYTHON_LDADD=""
|
||||
PYTHON_LDFLAGS=""
|
||||
PYTHON_CONFIG=${PKG_CONFIG}
|
||||
PYTHON_PKGNAMES="python3"
|
||||
PYTHON_SONAMES="so la sl dll dylib"
|
||||
|
||||
AC_ARG_WITH(
|
||||
python,
|
||||
[AC_HELP_STRING([--with-python=PATH],[Path to Python prefix or config script])]
|
||||
,, with_python=yes)
|
||||
|
||||
AS_CASE(["${with_pythonl}"],
|
||||
[no], [test_paths=],
|
||||
[yes], [test_paths="/usr/local/libpython /usr/local/python /usr/local /opt/libpython /opt/python /opt /usr"],
|
||||
[test_paths="${with_python}"])
|
||||
|
||||
AS_IF([test "x${test_paths}" != "x"], [
|
||||
AC_MSG_CHECKING([for Python config script])
|
||||
for x in ${test_paths}; do
|
||||
dnl # Determine if the script was specified and use it directly
|
||||
if test ! -d "$x" -a -e "$x"; then
|
||||
PYTHON_CONFIG=$x
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Try known config script names/locations
|
||||
for y in $PYTHON_CONFIG; do
|
||||
if test -e "${x}/bin/${y}"; then
|
||||
PYTHON_CONFIG="${x}/bin/${y}"
|
||||
python_config="${PYTHON_CONFIG}"
|
||||
break
|
||||
elif test -e "${x}/${y}"; then
|
||||
PYTHON_CONFIG="${x}/${y}"
|
||||
python_config="${PYTHON_CONFIG}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -n "${python_config}"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
dnl # Try known package names
|
||||
if test -n "${PYTHON_CONFIG}"; then
|
||||
PYTHON_PKGNAME=""
|
||||
for x in ${PYTHON_PKGNAMES}; do
|
||||
if ${PYTHON_CONFIG} --exists ${x}; then
|
||||
PYTHON_PKGNAME="$x"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if test -n "${PYTHON_PKGNAME}"; then
|
||||
AC_MSG_RESULT([${PYTHON_CONFIG}])
|
||||
PYTHON_VERSION="`${PYTHON_CONFIG} ${PYTHON_PKGNAME} --modversion`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(python VERSION: $PYTHON_VERSION); fi
|
||||
PYTHON_CFLAGS="`${PYTHON_CONFIG} ${PYTHON_PKGNAME} --cflags`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(python CFLAGS: $PYTHON_CFLAGS); fi
|
||||
PYTHON_LDADD="`${PYTHON_CONFIG} ${PYTHON_PKGNAME} --libs-only-l`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(python LDADD: $PYTHON_LDADD); fi
|
||||
PYTHON_LDFLAGS="`${PYTHON_CONFIG} ${PYTHON_PKGNAME} --libs-only-L --libs-only-other`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(python LDFLAGS: $PYTHON_LDFLAGS); fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
|
||||
dnl Hack to just try to find the lib and include
|
||||
AC_MSG_CHECKING([for python install])
|
||||
for x in ${test_paths}; do
|
||||
for y in ${PYTHON_SONAMES}; do
|
||||
if test -e "${x}/libpython.${y}"; then
|
||||
python_lib_path="${x}/"
|
||||
python_lib_name="python"
|
||||
break
|
||||
else
|
||||
python_lib_path=""
|
||||
python_lib_name=""
|
||||
fi
|
||||
done
|
||||
if test -n "$python_lib_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
for x in ${test_paths}; do
|
||||
if test -e "${x}/include/Python.h"; then
|
||||
python_inc_path="${x}/include"
|
||||
break
|
||||
elif test -e "${x}/Python.h"; then
|
||||
python_inc_path="${x}"
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Check some sub-paths as well
|
||||
for python_pkg_name in ${python_lib_name} ${PYTHON_PKGNAMES}; do
|
||||
if test -e "${x}/include/${python_pkg_name}/Python.h"; then
|
||||
python_inc_path="${x}/include"
|
||||
break
|
||||
elif test -e "${x}/${python_pkg_name}/Python.h"; then
|
||||
python_inc_path="${x}"
|
||||
break
|
||||
else
|
||||
python_inc_path=""
|
||||
fi
|
||||
done
|
||||
if test -n "$python_inc_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -n "${python_lib_path}" -a -n "${python_inc_path}"; then
|
||||
PYTHON_CONFIG=""
|
||||
AC_MSG_RESULT([${python_lib_path} ${python_inc_path}])
|
||||
PYTHON_VERSION="2"
|
||||
PYTHON_CFLAGS="-I${python_inc_path}"
|
||||
PYTHON_LDADD="-l${python_lib_name}"
|
||||
PYTHON_LDFLAGS="-L${python_lib_path}"
|
||||
else
|
||||
PYTHON_VERSION=""
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
PYTHON_LIBS=${PYTHON_LDADD}
|
||||
AC_SUBST(PYTHON_CFLAGS)
|
||||
AC_SUBST(PYTHON_LDADD)
|
||||
AC_SUBST(PYTHON_LIBS)
|
||||
AC_SUBST(PYTHON_LDFLAGS)
|
||||
if test -z "${PYTHON_VERSION}"; then
|
||||
ifelse([$2], , AC_MSG_NOTICE([optional python library not found]), $2)
|
||||
else
|
||||
AC_MSG_NOTICE([using python v${PYTHON_VERSION}])
|
||||
PYTHON_CFLAGS="-DWITH_PYTHON ${PYTHON_CFLAGS}"
|
||||
ifelse([$1], , , $1)
|
||||
fi
|
||||
])
|
@ -701,6 +701,7 @@ fi
|
||||
# Check for YAJL libs (for JSON body processor)
|
||||
CHECK_YAJL()
|
||||
#AC_SEARCH_LIBS([yajl_alloc], [yajl])
|
||||
CHECK_PYTHON()
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_CONFIG_FILES([tools/Makefile])
|
||||
|
56
scripts/python/modsecurity.py
Executable file
56
scripts/python/modsecurity.py
Executable file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
|
||||
# Needs to be singlenton ?
|
||||
class Singleton(object):
|
||||
_instances = {}
|
||||
"""
|
||||
def __new__(class_, *args, **kwargs):
|
||||
if class_ not in class_._instances:
|
||||
class_._instances[class_] = super(Singleton, class_).__new__(class_, *args, **kwargs)
|
||||
return class_._instances[class_]
|
||||
"""
|
||||
|
||||
class ModSecurity():
|
||||
def __init__(self):
|
||||
self.default_attr = ["default_attr", "name", "modsecCore"]
|
||||
self.name = None
|
||||
self.modsecCore = None
|
||||
|
||||
def setModSecurityCore(self, cb):
|
||||
self.modsecCore = cb
|
||||
self.log(8, "Log attached");
|
||||
return True
|
||||
|
||||
def log(self, level, msg):
|
||||
if self.modsecCore == None:
|
||||
print("ModSecurity Python: ", str(level) + " " + str(msg), file=sys.stderr)
|
||||
else:
|
||||
self.modsecCore.log(level, msg)
|
||||
return True
|
||||
|
||||
def __getattribute__(self, key):
|
||||
v = None
|
||||
try:
|
||||
v = object.__getattribute__(self, key)
|
||||
if hasattr(v, '__get__'):
|
||||
return v.__get__(None, self)
|
||||
except:
|
||||
if self.modsecCore != None:
|
||||
v = self.modsecCore.getVariable(key)
|
||||
|
||||
return v
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
self.__dict__[name] = value
|
||||
|
||||
if name not in self.default_attr:
|
||||
if self.modsecCore != None:
|
||||
self.modsecCore.setVariable("tx." + name, value)
|
||||
|
||||
|
||||
"""
|
||||
TODO: transformation
|
||||
"""
|
15
scripts/python/setup.py
Normal file
15
scripts/python/setup.py
Normal file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
setup(name="ModSecurity Python extension",
|
||||
version="0.1",
|
||||
description="ModSecurity python externsion",
|
||||
author="Felipe Zimmerle",
|
||||
author_email="felipe@zimmerle.org",
|
||||
url="http://www.modsecurity.org",
|
||||
py_modules=['modsecurity'],
|
||||
keywords="ModSecurity WAF Security",
|
||||
|
||||
)
|
||||
|
50
scripts/python/skell.py
Executable file
50
scripts/python/skell.py
Executable file
@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ModSecurity core binding.
|
||||
from modsecurity import ModSecurity
|
||||
|
||||
class ModSecurityExtension(ModSecurity):
|
||||
"""
|
||||
Class ModSecurityExtension should represents your custom module.
|
||||
Nocite that this class should derivate from ModSecurity and should
|
||||
implement the method process.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
ModSecurity.__init__(self)
|
||||
|
||||
def process(self):
|
||||
"""
|
||||
The method is called by ModSecurity core whenever a request is
|
||||
needed to be evaluated.
|
||||
"""
|
||||
|
||||
# self.log can be utilised to produce content inside the SecDebugLog
|
||||
# (https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#secdebuglog)
|
||||
self.log(8, "This is our custom Python script, it seems that I am working"
|
||||
"like a charm.")
|
||||
|
||||
|
||||
self.log(8, "Hum... Do we have something at FILES_TMPNAMES? %s" %
|
||||
self.FILES_TMPNAMES)
|
||||
|
||||
# Returns True whenever you want to send a "match" to ModSecurity core.
|
||||
return True
|
||||
|
||||
# Should be used to test your custom extension, deattached from ModSecurity core.
|
||||
if __name__ == "__main__":
|
||||
myExtension = ModSecurityExtension()
|
||||
|
||||
# Setting FILES_TMPNAMES property.
|
||||
# https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#files_tmpnames
|
||||
myExtension.FILES_TMPNAMES = [ "/etc/issue", "/etc/resolv.conf" ]
|
||||
|
||||
# Process the content.
|
||||
ret = myExtension.process()
|
||||
|
||||
if ret == True:
|
||||
print("Matched!")
|
||||
else:
|
||||
print("_not_ matched")
|
||||
|
@ -21,6 +21,7 @@ standalone_la_SOURCES = ../apache2/acmp.c \
|
||||
../apache2/msc_multipart.c \
|
||||
../apache2/msc_parsers.c \
|
||||
../apache2/msc_pcre.c \
|
||||
../apache2/msc_python.c \
|
||||
../apache2/msc_release.c \
|
||||
../apache2/msc_reqbody.c \
|
||||
../apache2/msc_tree.c \
|
||||
@ -51,6 +52,7 @@ standalone_la_CFLAGS = -DVERSION_NGINX \
|
||||
@LUA_CFLAGS@ \
|
||||
@MODSEC_EXTRA_CFLAGS@ \
|
||||
@PCRE_CFLAGS@ \
|
||||
@PYTHON_CFLAGS@ \
|
||||
@YAJL_CFLAGS@
|
||||
|
||||
standalone_la_CPPFLAGS = @APR_CPPFLAGS@ \
|
||||
@ -62,6 +64,7 @@ standalone_la_LIBADD = @APR_LDADD@ \
|
||||
@LIBXML2_LDADD@ \
|
||||
@LUA_LDADD@ \
|
||||
@PCRE_LDADD@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDADD@
|
||||
|
||||
if AIX
|
||||
@ -72,6 +75,7 @@ standalone_la_LDFLAGS = -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@ -83,6 +87,7 @@ standalone_la_LDFLAGS = -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@ -94,6 +99,7 @@ standalone_la_LDFLAGS = -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@ -105,6 +111,7 @@ standalone_la_LDFLAGS = -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@ -116,6 +123,7 @@ standalone_la_LDFLAGS = -no-undefined -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@ -127,6 +135,7 @@ standalone_la_LDFLAGS = -no-undefined -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@ -138,6 +147,7 @@ standalone_la_LDFLAGS = -no-undefined -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
||||
@ -149,5 +159,6 @@ standalone_la_LDFLAGS = -no-undefined -module -avoid-version \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
endif
|
||||
|
@ -14,6 +14,7 @@ msc_test_SOURCES = msc_test.c \
|
||||
$(top_srcdir)/apache2/msc_multipart.c \
|
||||
$(top_srcdir)/apache2/msc_parsers.c \
|
||||
$(top_srcdir)/apache2/msc_pcre.c \
|
||||
$(top_srcdir)/apache2/msc_python.c \
|
||||
$(top_srcdir)/apache2/msc_release.c \
|
||||
$(top_srcdir)/apache2/msc_reqbody.c \
|
||||
$(top_srcdir)/apache2/msc_tree.c \
|
||||
@ -36,6 +37,7 @@ msc_test_CFLAGS = @APR_CFLAGS@ \
|
||||
@LUA_CFLAGS@ \
|
||||
@MODSEC_EXTRA_CFLAGS@ \
|
||||
@PCRE_CFLAGS@ \
|
||||
@PYTHON_CFLAGS@ \
|
||||
@YAJL_CFLAGS@
|
||||
|
||||
msc_test_CPPFLAGS = -I$(top_srcdir)/apache2 \
|
||||
@ -48,6 +50,7 @@ msc_test_LDADD = @APR_LDADD@ \
|
||||
@LIBXML2_LDADD@ \
|
||||
@LUA_LDADD@ \
|
||||
@PCRE_LDADD@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDADD@
|
||||
|
||||
msc_test_LDFLAGS = @APR_LDFLAGS@ \
|
||||
@ -56,6 +59,7 @@ msc_test_LDFLAGS = @APR_LDFLAGS@ \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@PCRE_LDFLAGS@ \
|
||||
@PYTHON_LDFLAGS@ \
|
||||
@YAJL_LDFLAGS@
|
||||
|
||||
check_SCRIPTS = run-unit-tests.pl
|
||||
|
21
tests/regression/nginx/conf/script.py
Executable file
21
tests/regression/nginx/conf/script.py
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from modsecurity import ModSecurity
|
||||
|
||||
class ModSecurityExtension(ModSecurity):
|
||||
def process(self):
|
||||
self.log(8, "Python test message.")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
myExtension = ModSecurityExtension()
|
||||
|
||||
# Process the content.
|
||||
ret = myExtension.process()
|
||||
|
||||
if ret == True:
|
||||
print("Matched!")
|
||||
else:
|
||||
print("_not_ matched")
|
||||
|
24
tests/regression/rule/01-python-script.t
Normal file
24
tests/regression/rule/01-python-script.t
Normal file
@ -0,0 +1,24 @@
|
||||
### Test for SecRuleScript
|
||||
|
||||
# Python
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleScript (Python match)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRuleScript "script.py" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Python script matched\./, 1 ],
|
||||
debug => [ qr/Python test message\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?foo=bar&foo2=bar2",
|
||||
),
|
||||
}
|
||||
|
21
tests/regression/server_root/conf/script.py
Executable file
21
tests/regression/server_root/conf/script.py
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from modsecurity import ModSecurity
|
||||
|
||||
class ModSecurityExtension(ModSecurity):
|
||||
def process(self):
|
||||
self.log(8, "Python test message.")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
myExtension = ModSecurityExtension()
|
||||
|
||||
# Process the content.
|
||||
ret = myExtension.process()
|
||||
|
||||
if ret == True:
|
||||
print("Matched!")
|
||||
else:
|
||||
print("_not_ matched")
|
||||
|
Loading…
x
Reference in New Issue
Block a user