Added m.getvars() and finalised Lua support.

This commit is contained in:
ivanr 2007-12-21 12:50:03 +00:00
parent 8924f605d4
commit 2068357af8
9 changed files with 322 additions and 135 deletions

View File

@ -1,9 +1,14 @@
20 Dec 2007 - 2.5.0-rc1
21 Dec 2007 - 2.5.0-rc1
-----------------------
Changes since 2.5.0-dev2:
* Added support for Lua scripting in the following ways: SecRuleScript
can be used to specify a script to execute as a rule, the exec
action processes Lua scripts internally, and does the @inspectFile
operator. Refer to the documentation for more details.
* Updated included Core Ruleset to version 1.5.1.
* Changed how allow works. Used on its own it now allows phases 1-4. Used

View File

@ -39,8 +39,6 @@ APACHECTL = apachectl
INCLUDES = -I /usr/include/libxml2 -I /usr/include/lua5.1
# INCLUDES = -I /usr/include/libxml2 -I /path/to/httpd-x.y/srclib/pcre
DEFS = -DWITH_LUA
# DEFS = -DWITH_ICONV
# DEFS = -DPERFORMANCE_MEASUREMENT
# DEFS = -DNO_MODSEC_API
# DEFS = -DDEBUG_CONF

View File

@ -1283,14 +1283,12 @@ static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag) {
return NULL;
}
#ifdef WITH_LUA
static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg, const char *p1,
const char *p2)
{
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);
}
#endif
static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, const char *p1) {
directory_config *dcfg = (directory_config *)_dcfg;
@ -1887,7 +1885,6 @@ const command_rec module_directives[] = {
"On or Off"
),
#ifdef WITH_LUA
AP_INIT_TAKE12 (
"SecRuleScript",
cmd_rule_script,
@ -1895,7 +1892,6 @@ const command_rec module_directives[] = {
CMD_SCOPE_ANY,
"" // TODO
),
#endif
AP_INIT_ITERATE (
"SecRuleRemoveById",

View File

@ -1,9 +1,6 @@
#include "msc_lua.h"
#ifdef WITH_LUA
#include "apr_strings.h"
typedef struct {
@ -123,18 +120,60 @@ static int l_log(lua_State *L) {
return 0;
}
/**
*
*/
static apr_array_header_t *resolve_tfns(lua_State *L, int idx, modsec_rec *msr, apr_pool_t *mp) {
apr_array_header_t *tfn_arr = NULL;
msre_tfn_metadata *tfn = NULL;
char *name = NULL;
tfn_arr = apr_array_make(mp, 25, sizeof(msre_tfn_metadata *));
if (tfn_arr == NULL) return NULL;
if (lua_istable(L, idx)) { /* Is the second parameter an array? */
int i, n = lua_objlen(L, idx);
for(i = 1; i <= n; i++) {
lua_rawgeti(L, idx, i);
name = (char *)luaL_checkstring(L, -1);
tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name);
if (tfn == NULL) {
msr_log(msr, 1, "SecRuleScript: Invalid transformation function: %s", name);
} else {
*(msre_tfn_metadata **)apr_array_push(tfn_arr) = tfn;
}
}
} else if (lua_isstring(L, idx)) { /* The second parameter may be a simple string? */
name = (char *)luaL_checkstring(L, idx);
tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name);
if (tfn == NULL) {
msr_log(msr, 1, "SecRuleScript: Invalid transformation function: %s", name);
} else {
*(msre_tfn_metadata **)apr_array_push(tfn_arr) = tfn;
}
} else {
// TODO Error
return NULL;
}
return tfn_arr;
}
/**
*
*/
static int l_getvar(lua_State *L) {
char *varname = NULL;
char *param = NULL;
char *varname = NULL, *param = NULL;
modsec_rec *msr = NULL;
msre_rule *rule = NULL;
char *my_error_msg = NULL;
char *p1 = NULL;
apr_array_header_t *tfn_arr = NULL;
msre_var *vx = NULL;
/* Retrieve parameters. */
varname = (char *)luaL_checkstring(L, 1);
p1 = (char *)luaL_checkstring(L, 1);
/* Retrieve msr. */
lua_getglobal(L, "__msr");
@ -144,100 +183,123 @@ static int l_getvar(lua_State *L) {
lua_getglobal(L, "__rule");
rule = (msre_rule *)lua_topointer(L, -1);
/* Resolve variable $varname. */
/* Extract the variable name and its parameter from the script. */
varname = apr_pstrdup(msr->msc_rule_mptmp, p1);
param = strchr(varname, '.');
if (param != NULL) {
*param = '\0';
param++;
}
/* Resolve variable. */
msre_var *var = msre_create_var_ex(msr->msc_rule_mptmp, msr->modsecurity->msre,
varname, param, msr, &my_error_msg);
if (var == NULL) {
msr_log(msr, 1, "SecRuleScript: Failed to resolve variable: %s", varname);
msr_log(msr, 1, "%s", my_error_msg);
lua_pushnil(L);
return 0;
} else {
msre_var *vx = NULL;
vx = generate_single_var(msr, var, rule, msr->msc_rule_mptmp);
if (vx != NULL) {
char *rval = NULL;
long int rval_len = -1;
/* Transform the variable if a list of transformation
* functions has been supplied.
*/
if (lua_istable(L, 2)) { /* Is the second parameter an array? */
int i, n = lua_objlen(L, 2);
/* Make a copy so that we don't ruin the original value. */
vx->value = apr_pstrmemdup(msr->msc_rule_mptmp, vx->value, vx->value_len);
for(i = 1; i <= n; i++) {
msre_tfn_metadata *tfn = NULL;
char *name = NULL;
int rc = 0;
lua_rawgeti(L, 2, i);
name = (char *)luaL_checkstring(L, -1);
tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name);
if (tfn == NULL) {
msr_log(msr, 1, "SecRuleScript: Invalid transformation function in getvar() call: %s", name);
return 0;
}
rc = tfn->execute(msr->msc_rule_mptmp, (unsigned char*)vx->value,
vx->value_len, &rval, &rval_len);
vx->value = rval;
vx->value_len = rval_len;
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name,
log_escape_nq_ex(msr->msc_rule_mptmp, vx->value, vx->value_len));
}
}
}
else if (lua_isstring(L, 2)) { /* The second parameter may be a simple string? */
msre_tfn_metadata *tfn = NULL;
char *name = NULL;
int rc = 0;
/* Make a copy so that we don't ruin the original value. */
vx->value = apr_pstrmemdup(msr->msc_rule_mptmp, vx->value, vx->value_len);
name = (char *)luaL_checkstring(L, 2);
tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name);
if (tfn == NULL) {
msr_log(msr, 1, "SecRuleScript: Invalid transformation function in getvar() call: %s", name);
return 0;
}
rc = tfn->execute(msr->msc_rule_mptmp, (unsigned char *)vx->value,
vx->value_len, &rval, &rval_len);
vx->value = rval;
vx->value_len = rval_len;
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name,
log_escape_nq_ex(msr->msc_rule_mptmp, vx->value, vx->value_len));
}
}
lua_pushlstring(L, vx->value, vx->value_len);
return 1;
}
}
return 0;
/* Resolve transformation functions. */
tfn_arr = resolve_tfns(L, 2, msr, msr->msc_rule_mptmp);
/* Generate variable. */
vx = generate_single_var(msr, var, tfn_arr, rule, msr->msc_rule_mptmp);
if (vx == NULL) {
lua_pushnil(L);
return 0;
}
/* Return variable value. */
lua_pushlstring(L, vx->value, vx->value_len);
return 1;
}
/**
*
*/
static int l_getvars(lua_State *L) {
const apr_array_header_t *tarr;
const apr_table_entry_t *telts;
apr_table_t *vartable = NULL;
apr_array_header_t *tfn_arr = NULL;
char *varname = NULL, *param = NULL;
modsec_rec *msr = NULL;
msre_rule *rule = NULL;
msre_var *vartemplate = NULL;
char *my_error_msg = NULL;
char *p1 = NULL;
int i;
/* Retrieve parameters. */
p1 = (char *)luaL_checkstring(L, 1);
/* Retrieve msr. */
lua_getglobal(L, "__msr");
msr = (modsec_rec *)lua_topointer(L, -1);
/* Retrieve rule. */
lua_getglobal(L, "__rule");
rule = (msre_rule *)lua_topointer(L, -1);
/* Extract the variable name and its parameter from the script. */
varname = apr_pstrdup(msr->msc_rule_mptmp, p1);
param = strchr(varname, '.');
if (param != NULL) {
*param = '\0';
param++;
}
/* Resolve transformation functions. */
tfn_arr = resolve_tfns(L, 2, msr, msr->msc_rule_mptmp);
lua_newtable(L);
/* Resolve variable. */
vartemplate = msre_create_var_ex(msr->msc_rule_mptmp, msr->modsecurity->msre,
varname, param, msr, &my_error_msg);
if (vartemplate == NULL) {
msr_log(msr, 1, "%s", my_error_msg);
/* Returning empty table. */
return 1;
}
vartable = generate_multi_var(msr, vartemplate, tfn_arr, rule, msr->msc_rule_mptmp);
tarr = apr_table_elts(vartable);
telts = (const apr_table_entry_t*)tarr->elts;
for (i = 0; i < tarr->nelts; i++) {
msre_var *var = (msre_var *)telts[i].val;
lua_pushnumber(L, i + 1); /* Index is not zero-based. */
lua_newtable(L); /* Per-parameter table. */
lua_pushstring(L, "name");
lua_pushlstring(L, var->name, strlen(var->name));
lua_settable(L, -3);
lua_pushstring(L, "value");
lua_pushlstring(L, var->value, var->value_len);
lua_settable(L, -3);
lua_settable(L, -3); /* Push one parameter into the results table. */
}
return 1;
}
static const struct luaL_Reg mylib[] = {
{ "log", l_log },
{ "getvar", l_getvar },
{ "getvars", l_getvars },
{ NULL, NULL }
};
@ -317,4 +379,3 @@ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rul
return ((*error_msg != NULL) ? RULE_MATCH : RULE_NO_MATCH);
}
#endif

View File

@ -11,8 +11,6 @@
#ifndef _MSC_LUA_H_
#define _MSC_LUA_H_
#if defined(WITH_LUA)
typedef struct msc_script msc_script;
typedef struct msc_script_part msc_script_part;
@ -39,4 +37,3 @@ char DSOLOCAL *lua_compile(msc_script **script, const char *filename, apr_pool_t
int DSOLOCAL lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rule, char **error_msg);
#endif
#endif

View File

@ -1314,7 +1314,6 @@ msre_rule *msre_rule_create(msre_ruleset *ruleset,
return rule;
}
#ifdef WITH_LUA
/**
*
*/
@ -1362,7 +1361,6 @@ msre_rule *msre_rule_lua_create(msre_ruleset *ruleset,
return rule;
}
#endif
/**
* Perform non-disruptive actions associated with the provided actionset.
@ -2001,11 +1999,9 @@ apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
apr_pool_clear(msr->msc_rule_mptmp);
}
#if defined(WITH_LUA)
if (rule->type == RULE_TYPE_LUA) {
return msre_rule_process_lua(rule, msr);
}
#endif
return msre_rule_process_normal(rule, msr);
}

View File

@ -65,9 +65,11 @@ int DSOLOCAL msre_parse_generic(apr_pool_t *pool, const char *text, apr_table_t
int DSOLOCAL rule_id_in_range(int ruleid, const char *range);
msre_var DSOLOCAL *generate_single_var(modsec_rec *msr, msre_var *var, msre_rule *rule,
apr_pool_t *mptmp);
msre_var DSOLOCAL *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr,
msre_rule *rule, apr_pool_t *mptmp);
apr_table_t DSOLOCAL *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr,
msre_rule *rule, apr_pool_t *mptmp);
/* Structures with the corresponding functions */
@ -143,9 +145,8 @@ struct msre_rule {
unsigned int execution_time;
#endif
#if defined(WITH_LUA)
/* Compiled Lua script. */
msc_script *script;
#endif
};
msre_rule DSOLOCAL *msre_rule_create(msre_ruleset *ruleset,

View File

@ -39,21 +39,118 @@ static void msre_engine_action_register(msre_engine *engine, const char *name, u
/**
* Generates a single variable (from the supplied metadata).
*/
msre_var *generate_single_var(modsec_rec *msr, msre_var *var, msre_rule *rule,
apr_pool_t *mptmp)
msre_var *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr,
msre_rule *rule, apr_pool_t *mptmp)
{
apr_table_t *vartab = NULL;
const apr_table_entry_t *te = NULL;
const apr_array_header_t *arr = NULL;
msre_var *rvar = NULL;
int i;
/* Sanity check. */
if ((var == NULL)||(var->metadata == NULL)||(var->metadata->generate == NULL)) return NULL;
if (var->metadata->generate == NULL) return NULL;
vartab = apr_table_make(mptmp, 16);
var->metadata->generate(msr, var, rule, vartab, mptmp);
arr = apr_table_elts(vartab);
if (arr->nelts == 0) return NULL;
te = (apr_table_entry_t *)arr->elts;
te = (apr_table_entry_t *)arr->elts;
return (msre_var *)te[0].val;
rvar = (msre_var *)te[0].val;
/* Return straight away if there were no
* transformation functions supplied.
*/
if ((tfn_arr == NULL)||(tfn_arr->nelts == 0)) {
return rvar;
}
/* Copy the value so that we can transform it in piece. */
rvar->value = apr_pstrndup(mptmp, rvar->value, rvar->value_len);
/* Transform rvar in a loop. */
for (i = 0; i < tfn_arr->nelts; i++) {
msre_tfn_metadata *tfn = ((msre_tfn_metadata **)tfn_arr->elts)[i];
char *rval;
int rc;
long int rval_len;
rc = tfn->execute(mptmp, (unsigned char *)rvar->value,
rvar->value_len, &rval, &rval_len);
rvar->value = rval;
rvar->value_len = rval_len;
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name,
log_escape_nq_ex(mptmp, rvar->value, rvar->value_len));
}
}
return rvar;
}
/**
*
*/
apr_table_t *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr,
msre_rule *rule, apr_pool_t *mptmp)
{
const apr_array_header_t *tarr;
const apr_table_entry_t *telts;
apr_table_t *vartab = NULL, *tvartab = NULL;
msre_var *rvar = NULL;
int i, j;
/* Sanity check. */
if ((var == NULL)||(var->metadata == NULL)||(var->metadata->generate == NULL)) return NULL;
/* Generate variables. */
vartab = apr_table_make(mptmp, 16);
var->metadata->generate(msr, var, rule, vartab, mptmp);
/* Return straight away if there were no
* transformation functions supplied.
*/
if ((tfn_arr == NULL)||(tfn_arr->nelts == 0)) {
return vartab;
}
tvartab = apr_table_make(mptmp, 16);
tarr = apr_table_elts(vartab);
telts = (const apr_table_entry_t*)tarr->elts;
for (j = 0; j < tarr->nelts; j++) {
rvar = (msre_var *)telts[j].val;
/* Copy the value so that we can transform it in piece. */
rvar->value = apr_pstrndup(mptmp, rvar->value, rvar->value_len);
/* Transform rvar in a loop. */
for (i = 0; i < tfn_arr->nelts; i++) {
msre_tfn_metadata *tfn = ((msre_tfn_metadata **)tfn_arr->elts)[i];
char *rval;
int rc;
long int rval_len;
rc = tfn->execute(mptmp, (unsigned char *)rvar->value,
rvar->value_len, &rval, &rval_len);
rvar->value = rval;
rvar->value_len = rval_len;
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name,
log_escape_nq_ex(mptmp, rvar->value, rvar->value_len));
}
}
apr_table_addn(tvartab, rvar->name, (void *)rvar);
}
return tvartab;
}
/**
@ -137,7 +234,7 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t
var_resolved = msre_create_var_ex(mptmp, msr->modsecurity->msre, var_name, var_value,
msr, &my_error_msg);
if (var_resolved != NULL) {
var_generated = generate_single_var(msr, var_resolved, rule, mptmp);
var_generated = generate_single_var(msr, var_resolved, NULL, rule, mptmp);
if (var_generated != NULL) {
part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string));
if (part == NULL) return -1;
@ -1457,7 +1554,6 @@ static char *msre_action_exec_validate(msre_engine *engine, msre_action *action)
/* TODO Support relative filenames. */
#ifdef WITH_LUA
/* Process Lua scripts internally. */
if (strlen(filename) > 4) {
char *p = filename + strlen(filename) - 4;
@ -1472,7 +1568,6 @@ static char *msre_action_exec_validate(msre_engine *engine, msre_action *action)
action->param_data = script;
}
}
#endif
return NULL;
}

View File

@ -3,7 +3,7 @@
<title>ModSecurity Reference Manual</title>
<articleinfo>
<releaseinfo>Version 2.5.0-rc1/ (December 19, 2007)</releaseinfo>
<releaseinfo>Version 2.5.0-rc1/ (December 21, 2007)</releaseinfo>
<copyright>
<year>2004-2007</year>
@ -300,6 +300,11 @@
installed on the server.</para>
</listitem>
<listitem>
<para>Install the latest version of Lua in the 5.1.x branch, if it
isn't already installed on the server.</para>
</listitem>
<listitem>
<para>Unpack the ModSecurity archive</para>
</listitem>
@ -315,14 +320,13 @@
<listitem>
<para>Edit Makefile to configure the correct include path for libxml
(for example: <filename
moreinfo="none">INCLUDES=-I/usr/include/libxml2</filename>)</para>
(for example <filename moreinfo="none">-I
/usr/include/libxml2</filename>)</para>
</listitem>
<listitem>
<para>(Optional) If you want to use Lua scripting add
<literal>-DWITH_LUA</literal> and configure the path to Lua include
files (for example <literal>-I /usr/include/lua5.1</literal>).</para>
<para>Edit Makefile to configure the correct incpude path for Lua (for
example <literal>-I /usr/include/lua5.1</literal>).</para>
</listitem>
<listitem>
@ -339,19 +343,18 @@
</listitem>
<listitem>
<para>Add one line to your configuration to load libxml2: <filename
<para>Load libxml2 before ModSecurity: <filename
moreinfo="none">LoadFile /usr/lib/libxml2.so</filename></para>
</listitem>
<listitem>
<para>(Optional) Add one line to load Lua before ModSecurity:
<literal>LoadFile /usr/lib/liblua5.1.so</literal>.</para>
<para>Load Lua before ModSecurity: <literal>LoadFile
/usr/lib/liblua5.1.so</literal>.</para>
</listitem>
<listitem>
<para>Add one line to your configuration to load ModSecurity: <literal
moreinfo="none">LoadModule security2_module
modules/mod_security2.so</literal></para>
<para>Load ModSecurity itself: <literal moreinfo="none">LoadModule
security2_module modules/mod_security2.so</literal></para>
</listitem>
<listitem>
@ -1805,6 +1808,12 @@ ServerAlias www.app2.com
<literal>SecRuleScript</literal> resides. This allows you to place your
script in the same folder as the configuration files using them.</para>
<note>
<para>All Lua scripts are compiled at configuration time and cached in
memory. To reload scripts you must reload the entire ModSecurity
configuration by restarting Apache.</para>
</note>
<para>Example script:</para>
<programlisting>-- Your script must define the <emphasis>main</emphasis> entry
@ -1816,33 +1825,65 @@ function main()
m.log(1, "Hello world!");
-- Retrieve one variable.
var1 = m.getvar("REMOTE_ADDR");
local var1 = m.getvar("REMOTE_ADDR");
-- Retrieve one variable, applying one transformation function.
-- The second parameter is a string.
var2 = m.getvar("REQUEST_URI", "normalisePath");
local var2 = m.getvar("REQUEST_URI", "normalisePath");
-- Retrieve one variable, applying several transformation functions.
-- The second parameter is now a list. You should note that m.getvar()
-- requires the use of comma to separate collection names from
-- variable names. This is because only one variable is returned.
var3 = m.getvar("ARGS.p", { "lowercase", "compressWhitespace" } );
local var3 = m.getvar("ARGS.p", { "lowercase", "compressWhitespace" } );
-- If you want this rule to match return a string
-- containing the error message. It is a good idea to mention
-- where the problem is located.
-- containing the error message. The message <emphasis>must</emphasis> contain the name
-- of the variable where the problem is located.
-- return "Variable ARGS:p looks suspicious!"
-- Otherwise, simply return null.
return null;
end</programlisting>
<para>In this first example we were only retrieving one variable at the
time. In this case the name of the variable is known to you. In many
cases, however, you will want to examine variables whose names you won't
know in advance, for example script parameters.</para>
<para>Example showing use of <literal>m.getvars()</literal> to retrieve
many variables at once:</para>
<programlisting>function main()
-- Retrieve script parameters.
local d = m.getvars("ARGS", { "lowercase", "htmlEntityDecode" } );
-- Loop through the paramters.
for i = 1, #d do
-- Examine parameter value.
if (string.find(d[i].value, "&lt;script")) then
-- Always specify the name of the variable where the
-- problem is located in the error message.
return ("Suspected XSS in variable " .. d[i].name .. ".");
end
end
-- Nothing wrong found.
return null;
end</programlisting>
<note>
<para>Go to <ulink url="http://www.lua.org">http://www.lua.org</ulink>
to find more about the Lua programming language. The reference manual
too is available online, at <ulink
url="http://www.lua.org/manual/5.1/">http://www.lua.org/manual/5.1/</ulink>.</para>
</note>
<note>
<para>Lua support is marked as <emphasis>experimental</emphasis>
because the way the scripts are written and function names may still
change while we are working for the best implementation style.</para>
</note>
</section>
<section>
@ -3926,9 +3967,8 @@ SecRule IP:AUTH_ATTEMPT "@gt 25" \
<title><literal>exec</literal></title>
<para><emphasis>Description:</emphasis> Executes an external
script/binary supplied as parameter. As of v2.5, when the support for
Lua scripting is enabled, and the parameter supplied to
<literal>exec</literal> is a Lua script (detected by the
script/binary supplied as parameter. As of v2.5, if tge parameter
supplied to <literal>exec</literal> is a Lua script (detected by the
<filename>.lua</filename> extension) the script will be processed
<emphasis>internally</emphasis>. This means you will get direct access
to the internal request context from the script. Please read the
@ -3945,8 +3985,7 @@ SecRule REQUEST_URI "^/cgi-bin/script\.pl" \
"log,<emphasis>exec:/usr/local/apache/bin/test.sh</emphasis>"
# The following is going to process /usr/local/apache/conf/exec.lua
# internally as a Lua script on rule match, provided ModSecurity was
# compiled with Lua support enabled.
# internally as a Lua script on rule match.
SecRule ARGS:p attack log,<emphasis>exec:/usr/local/apache/conf/exec.lua</emphasis></programlisting>
<note>
@ -4878,10 +4917,9 @@ SecRule ARGS:route "!<emphasis>@endsWith %{REQUEST_ADDR}</emphasis>" t:none,deny
extracted from the request. As of v2.5, if the supplied filename is not
absolute it is treated as relative to the directory in which the
configuration file resides. Also as of v2.5 if the filename is
determined to be a Lua script (based on its extension) and the Lua
support is compiled in, the script will be processed by the internal
engine. As such it will have full access to the ModSecurity
context.</para>
determined to be a Lua script (based on its extension) the script will
be processed by the internal engine. As such it will have full access to
the ModSecurity context.</para>
<para>Example of using an external binary/script:</para>