]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Regexp: Allow local lua functions in Rspamd regexp module
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 15 Jan 2019 12:27:14 +0000 (12:27 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 15 Jan 2019 12:27:14 +0000 (12:27 +0000)
src/libmime/mime_expressions.c
src/libmime/mime_expressions.h
src/plugins/regexp.c

index 17a42a128b413f64f2aacd4325c457b420f7c679..6657570e7982bdbbc805369abe962809537558e9 100644 (file)
@@ -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);
index 834f1983f667a69c79c542d198227ee964091e27..2677b99685ccc7006f1bc84417ce3bb3a160e1fb 100644 (file)
@@ -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;
 
index 01c086169318e79a8f2f1aaf9e328f1918a5655e..87ab1f9c00bdef8789135823a12e20136e5eb432 100644 (file)
@@ -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 {