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