commit a8fb3a3: [Feature] Regexp: Allow local lua functions in Rspamd regexp module
Vsevolod Stakhov
vsevolod at highsecure.ru
Tue Jan 15 12:56:05 UTC 2019
Author: Vsevolod Stakhov
Date: 2019-01-15 12:27:14 +0000
URL: https://github.com/rspamd/rspamd/commit/a8fb3a3f5f2bc1847f583ffc969b82708bfccc98
[Feature] Regexp: Allow local lua functions in Rspamd regexp module
---
src/libmime/mime_expressions.c | 118 +++++++++++++++++++++++++++++++++++++----
src/libmime/mime_expressions.h | 7 +++
src/plugins/regexp.c | 18 +++++--
3 files changed, 129 insertions(+), 14 deletions(-)
diff --git a/src/libmime/mime_expressions.c b/src/libmime/mime_expressions.c
index 17a42a128..6657570e7 100644
--- a/src/libmime/mime_expressions.c
+++ b/src/libmime/mime_expressions.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <contrib/libucl/ucl.h>
#include "config.h"
#include "util.h"
#include "cfg_file.h"
@@ -117,7 +118,8 @@ struct rspamd_function_atom {
enum rspamd_mime_atom_type {
MIME_ATOM_REGEXP = 0,
MIME_ATOM_INTERNAL_FUNCTION,
- MIME_ATOM_LUA_FUNCTION
+ MIME_ATOM_LUA_FUNCTION,
+ MIME_ATOM_LOCAL_LUA_FUNCTION, /* New style */
};
struct rspamd_mime_atom {
@@ -126,6 +128,7 @@ struct rspamd_mime_atom {
struct rspamd_regexp_atom *re;
struct rspamd_function_atom *func;
const gchar *lua_function;
+ gint lua_cbref;
} d;
enum rspamd_mime_atom_type type;
};
@@ -638,7 +641,8 @@ rspamd_mime_expr_parse (const gchar *line, gsize len,
rspamd_expression_atom_t *a = NULL;
struct rspamd_mime_atom *mime_atom = NULL;
const gchar *p, *end;
- struct rspamd_config *cfg = ud;
+ struct rspamd_mime_expr_ud *real_ud = (struct rspamd_mime_expr_ud *)ud;
+ struct rspamd_config *cfg;
rspamd_regexp_t *own_re;
gchar t;
gint type = MIME_ATOM_REGEXP, obraces = 0, ebraces = 0;
@@ -659,6 +663,7 @@ rspamd_mime_expr_parse (const gchar *line, gsize len,
p = line;
end = p + len;
+ cfg = real_ud->cfg;
while (p < end) {
t = *p;
@@ -674,11 +679,21 @@ rspamd_mime_expr_parse (const gchar *line, gsize len,
state = got_obrace;
}
else if (!g_ascii_isalnum (t) && t != '_' && t != '-' && t != '=') {
- /* Likely lua function, identified by just a string */
- type = MIME_ATOM_LUA_FUNCTION;
- state = end_atom;
- /* Do not increase p */
- continue;
+ if (t == ':') {
+ if (p - line == 3 && memcmp (line, "lua", 3) == 0) {
+ type = MIME_ATOM_LOCAL_LUA_FUNCTION;
+ state = end_atom;
+ p ++;
+ continue;
+ }
+ }
+ else {
+ /* Likely lua function, identified by just a string */
+ type = MIME_ATOM_LUA_FUNCTION;
+ state = end_atom;
+ /* Do not increase p */
+ continue;
+ }
}
else if (g_ascii_isspace (t)) {
state = bad_atom;
@@ -768,8 +783,15 @@ set:
mime_atom = rspamd_mempool_alloc (pool, sizeof (*mime_atom));
mime_atom->type = type;
- mime_atom->str = rspamd_mempool_alloc (pool, p - line + 1);
- rspamd_strlcpy (mime_atom->str, line, p - line + 1);
+
+ if (type != MIME_ATOM_LOCAL_LUA_FUNCTION) {
+ mime_atom->str = rspamd_mempool_alloc (pool, p - line + 1);
+ rspamd_strlcpy (mime_atom->str, line, p - line + 1);
+ }
+ else {
+ mime_atom->str = rspamd_mempool_alloc (pool, end - p + 1);
+ rspamd_strlcpy (mime_atom->str, p, end - p + 1);
+ }
if (type == MIME_ATOM_REGEXP) {
mime_atom->d.re = rspamd_mime_expr_parse_regexp_atom (pool,
@@ -851,8 +873,59 @@ set:
goto err;
}
+
lua_pop (cfg->lua_state, 1);
}
+ else if (type == MIME_ATOM_LOCAL_LUA_FUNCTION) {
+ /* p pointer is set to the start of Lua function name */
+
+ if (real_ud->conf_obj == NULL) {
+ g_set_error (err, rspamd_mime_expr_quark(), 300,
+ "no config object for '%s'",
+ mime_atom->str);
+ goto err;
+ }
+
+ const ucl_object_t *functions = ucl_object_lookup (real_ud->conf_obj,
+ "functions");
+
+ if (functions == NULL) {
+ g_set_error (err, rspamd_mime_expr_quark(), 310,
+ "no functions defined for '%s'",
+ mime_atom->str);
+ goto err;
+ }
+
+ if (ucl_object_type (functions) != UCL_OBJECT) {
+ g_set_error (err, rspamd_mime_expr_quark(), 320,
+ "functions is not a table for '%s'",
+ mime_atom->str);
+ goto err;
+ }
+
+ const ucl_object_t *function_obj;
+
+ function_obj = ucl_object_lookup_len (functions, p,
+ end - p);
+
+ if (function_obj == NULL) {
+ g_set_error (err, rspamd_mime_expr_quark(), 320,
+ "function %*.s is not found for '%s'",
+ (int)(end - p), p, mime_atom->str);
+ goto err;
+ }
+
+ if (ucl_object_type (function_obj) != UCL_USERDATA) {
+ g_set_error (err, rspamd_mime_expr_quark(), 320,
+ "function %*.s has invalid type for '%s'",
+ (int)(end - p), p, mime_atom->str);
+ goto err;
+ }
+
+ struct ucl_lua_funcdata *fd = function_obj->value.ud;
+
+ mime_atom->d.lua_cbref = fd->idx;
+ }
else {
mime_atom->d.func = rspamd_mime_expr_parse_function_atom (pool,
mime_atom->str);
@@ -933,6 +1006,7 @@ rspamd_mime_expr_priority (rspamd_expression_atom_t *atom)
ret = 50;
break;
case MIME_ATOM_LUA_FUNCTION:
+ case MIME_ATOM_LOCAL_LUA_FUNCTION:
ret = 50;
break;
case MIME_ATOM_REGEXP:
@@ -1036,6 +1110,32 @@ rspamd_mime_expr_process (struct rspamd_expr_process_data *process_data, rspamd_
lua_pop (L, 1);
}
}
+ else if (mime_atom->type == MIME_ATOM_LOCAL_LUA_FUNCTION) {
+ L = task->cfg->lua_state;
+ lua_rawgeti (L, LUA_REGISTRYINDEX, mime_atom->d.lua_cbref);
+ rspamd_lua_task_push (L, task);
+
+ if (lua_pcall (L, 1, 1, 0) != 0) {
+ msg_info_task ("lua call to local function for atom '%s' failed: %s",
+ mime_atom->str,
+ lua_tostring (L, -1));
+ lua_pop (L, 1);
+ }
+ else {
+ if (lua_type (L, -1) == LUA_TBOOLEAN) {
+ ret = lua_toboolean (L, -1);
+ }
+ else if (lua_type (L, -1) == LUA_TNUMBER) {
+ ret = lua_tonumber (L, 1);
+ }
+ else {
+ msg_err_task ("%s returned wrong return type: %s",
+ mime_atom->str, lua_typename (L, lua_type (L, -1)));
+ }
+ /* Remove result */
+ lua_pop (L, 1);
+ }
+ }
else {
ret = rspamd_mime_expr_process_function (mime_atom->d.func, task,
task->cfg->lua_state);
diff --git a/src/libmime/mime_expressions.h b/src/libmime/mime_expressions.h
index 834f1983f..2677b9968 100644
--- a/src/libmime/mime_expressions.h
+++ b/src/libmime/mime_expressions.h
@@ -8,8 +8,15 @@
#include "config.h"
#include "expression.h"
+#include "contrib/libucl/ucl.h"
struct rspamd_task;
+struct rspamd_config;
+
+struct rspamd_mime_expr_ud {
+ struct rspamd_config *cfg;
+ const ucl_object_t *conf_obj;
+};
extern const struct rspamd_atom_subr mime_expr_subr;
diff --git a/src/plugins/regexp.c b/src/plugins/regexp.c
index 01c086169..87ab1f9c0 100644
--- a/src/plugins/regexp.c
+++ b/src/plugins/regexp.c
@@ -73,12 +73,12 @@ read_regexp_expression (rspamd_mempool_t * pool,
struct regexp_module_item *chain,
const gchar *symbol,
const gchar *line,
- struct rspamd_config *cfg)
+ struct rspamd_mime_expr_ud *ud)
{
struct rspamd_expression *e = NULL;
GError *err = NULL;
- if (!rspamd_parse_expression (line, 0, &mime_expr_subr, cfg, pool, &err,
+ if (!rspamd_parse_expression (line, 0, &mime_expr_subr, ud, pool, &err,
&e)) {
msg_warn_pool ("%s = \"%s\" is invalid regexp expression: %e", symbol,
line,
@@ -161,14 +161,19 @@ regexp_module_config (struct rspamd_config *cfg)
msg_warn_config ("regexp module is now single threaded, max_threads is ignored");
}
else if (value->type == UCL_STRING) {
+ struct rspamd_mime_expr_ud ud;
+
cur_item = rspamd_mempool_alloc0 (cfg->cfg_pool,
sizeof (struct regexp_module_item));
cur_item->symbol = ucl_object_key (value);
cur_item->magic = rspamd_regexp_cb_magic;
+ ud.conf_obj = NULL;
+ ud.cfg = cfg;
+
if (!read_regexp_expression (cfg->cfg_pool,
- cur_item, ucl_object_key (value),
- ucl_obj_tostring (value), cfg)) {
+ cur_item, ucl_object_key (value),
+ ucl_obj_tostring (value), &ud)) {
res = FALSE;
}
else {
@@ -202,6 +207,7 @@ regexp_module_config (struct rspamd_config *cfg)
gdouble score = 0.0;
guint flags = 0, priority = 0;
gboolean is_lua = FALSE, valid_expression = TRUE;
+ struct rspamd_mime_expr_ud ud;
/* We have some lua table, extract its arguments */
elt = ucl_object_lookup (value, "callback");
@@ -216,10 +222,12 @@ regexp_module_config (struct rspamd_config *cfg)
sizeof (struct regexp_module_item));
cur_item->symbol = ucl_object_key (value);
cur_item->magic = rspamd_regexp_cb_magic;
+ ud.cfg = cfg;
+ ud.conf_obj = elt;
if (!read_regexp_expression (cfg->cfg_pool,
cur_item, ucl_object_key (value),
- ucl_obj_tostring (elt), cfg)) {
+ ucl_obj_tostring (elt), &ud)) {
res = FALSE;
}
else {
More information about the Commits
mailing list