Exemple #1
0
gboolean
rspamd_task_add_result_option (struct rspamd_task *task,
		struct rspamd_symbol_result *s, const gchar *opt)
{
	char *opt_cpy;
	gboolean ret = FALSE;

	if (s && opt) {
		if (s->options && !(s->sym &&
				(s->sym->flags & RSPAMD_SYMBOL_FLAG_ONEPARAM))) {
			/* Append new options */
			if (!g_hash_table_lookup (s->options, opt)) {
				opt_cpy = rspamd_mempool_strdup (task->task_pool, opt);
				g_hash_table_insert (s->options, opt_cpy, opt_cpy);
				ret = TRUE;
			}
		}
		else {
			s->options = g_hash_table_new (rspamd_strcase_hash,
					rspamd_strcase_equal);
			rspamd_mempool_add_destructor (task->task_pool,
					(rspamd_mempool_destruct_t)g_hash_table_unref,
					s->options);
			opt_cpy = rspamd_mempool_strdup (task->task_pool, opt);
			g_hash_table_insert (s->options, opt_cpy, opt_cpy);
			ret = TRUE;
		}
	}
	else if (!opt) {
		ret = TRUE;
	}

	return ret;
}
Exemple #2
0
static rspamd_expression_atom_t *
lua_atom_parse (const gchar *line, gsize len,
                rspamd_mempool_t *pool, gpointer ud, GError **err)
{
    struct lua_expression *e = (struct lua_expression *)ud;
    rspamd_expression_atom_t *atom;
    gsize rlen;
    const gchar *tok;

    lua_rawgeti (e->L, LUA_REGISTRYINDEX, e->parse_idx);
    lua_pushlstring (e->L, line, len);

    if (lua_pcall (e->L, 1, 1, 0) != 0) {
        msg_info ("callback call failed: %s", lua_tostring (e->L, -1));
    }

    if (lua_type (e->L, -1) != LUA_TSTRING) {
        g_set_error (err, lua_expr_quark(), 500, "cannot parse lua atom");
        lua_pop (e->L, 1);
        return NULL;
    }

    tok = lua_tolstring (e->L, -1, &rlen);
    atom = rspamd_mempool_alloc0 (e->pool, sizeof (*atom));
    atom->str = rspamd_mempool_strdup (e->pool, tok);
    atom->len = rlen;
    atom->data = ud;

    lua_pop (e->L, 1);

    return atom;
}
Exemple #3
0
static void
dkim_module_key_handler (rspamd_dkim_key_t *key,
	gsize keylen,
	rspamd_dkim_context_t *ctx,
	gpointer ud,
	GError *err)
{
	struct rspamd_task *task = ud;


	if (key != NULL) {
		/* Add new key to the lru cache */
		rspamd_lru_hash_insert (dkim_module_ctx->dkim_hash,
			g_strdup (ctx->dns_key),
			key, task->tv.tv_sec, key->ttl);
		dkim_module_check (task, ctx, key);
	}
	else {
		/* Insert tempfail symbol */
		msg_info ("cannot get key for domain %s", ctx->dns_key);
		if (err != NULL) {
			rspamd_task_insert_result (task, dkim_module_ctx->symbol_tempfail, 1,
				g_list_prepend (NULL,
				rspamd_mempool_strdup (task->task_pool, err->message)));

		}
		else {
			rspamd_task_insert_result (task, dkim_module_ctx->symbol_tempfail, 1, NULL);
		}
	}

	if (err) {
		g_error_free (err);
	}
}
Exemple #4
0
static gint
lua_config_register_symbol (lua_State * L)
{
	struct rspamd_config *cfg = lua_check_config (L);
	gchar *name;
	double weight;

	if (cfg) {
		name = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2));
		weight = luaL_checknumber (L, 3);

		if (lua_type (L, 4) == LUA_TSTRING) {
			lua_getglobal (L, luaL_checkstring (L, 4));
		}
		else {
			lua_pushvalue (L, 4);
		}
		if (name) {
			rspamd_register_symbol_fromlua (L,
					cfg,
					name,
					luaL_ref (L, LUA_REGISTRYINDEX),
					weight,
					0,
					SYMBOL_TYPE_NORMAL);
		}
	}

	return 0;
}
Exemple #5
0
static void
rspamd_register_symbol_fromlua (lua_State *L,
		struct rspamd_config *cfg,
		const gchar *name,
		gint ref,
		gdouble weight,
		gint priority,
		enum rspamd_symbol_type type)
{
	struct lua_callback_data *cd;

	cd = rspamd_mempool_alloc0 (cfg->cfg_pool,
		sizeof (struct lua_callback_data));
	cd->cb_is_ref = TRUE;
	cd->callback.ref = ref;
	cd->L = L;
	if (name) {
		cd->symbol = rspamd_mempool_strdup (cfg->cfg_pool, name);
	}

	register_symbol_common (&cfg->cache,
					name,
					weight,
					priority,
					lua_metric_symbol_callback,
					cd,
					type);
	rspamd_mempool_add_destructor (cfg->cfg_pool,
		(rspamd_mempool_destruct_t)lua_destroy_cfg_symbol,
		cd);
}
Exemple #6
0
static gint
lua_config_register_pre_filter (lua_State *L)
{
	struct rspamd_config *cfg = lua_check_config (L);
	struct lua_callback_data *cd;

	if (cfg) {
		cd =
			rspamd_mempool_alloc (cfg->cfg_pool,
				sizeof (struct lua_callback_data));
		if (lua_type (L, 2) == LUA_TSTRING) {
			cd->callback.name = rspamd_mempool_strdup (cfg->cfg_pool,
					luaL_checkstring (L, 2));
			cd->cb_is_ref = FALSE;
		}
		else {
			lua_pushvalue (L, 2);
			/* Get a reference */
			cd->callback.ref = luaL_ref (L, LUA_REGISTRYINDEX);
			cd->cb_is_ref = TRUE;
		}
		cd->L = L;
		cfg->pre_filters = g_list_prepend (cfg->pre_filters, cd);
		rspamd_mempool_add_destructor (cfg->cfg_pool,
			(rspamd_mempool_destruct_t)lua_destroy_cfg_symbol,
			cd);
	}
	return 1;
}
Exemple #7
0
static gint
lua_config_register_symbols (lua_State *L)
{
	struct rspamd_config *cfg = lua_check_config (L);
	gint i, top, idx;
	gchar *sym;
	gdouble weight = 1.0;

	if (lua_gettop (L) < 3) {
		msg_err ("not enough arguments to register a function");
		return 0;
	}
	if (cfg) {
		if (lua_type (L, 2) == LUA_TSTRING) {
			lua_getglobal (L, luaL_checkstring (L, 2));
		}
		else {
			lua_pushvalue (L, 2);
		}
		idx = luaL_ref (L, LUA_REGISTRYINDEX);

		if (lua_type (L, 3) == LUA_TNUMBER) {
			weight = lua_tonumber (L, 3);
			top = 4;
		}
		else {
			top = 3;
		}
		sym = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, top));
		rspamd_register_symbol_fromlua (L,
				cfg,
				sym,
				idx,
				weight,
				0,
				SYMBOL_TYPE_NORMAL);
		for (i = top; i < lua_gettop (L); i++) {
			sym =
				rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L,
					i + 1));
			register_virtual_symbol (&cfg->cache, sym, weight);
		}
	}

	return 0;
}
Exemple #8
0
static void
lua_metric_symbol_callback (struct rspamd_task *task, gpointer ud)
{
	struct lua_callback_data *cd = ud;
	struct rspamd_task **ptask;
	gint level = lua_gettop (cd->L), nresults;

	if (cd->cb_is_ref) {
		lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
	}
	else {
		lua_getglobal (cd->L, cd->callback.name);
	}
	ptask = lua_newuserdata (cd->L, sizeof (struct rspamd_task *));
	rspamd_lua_setclass (cd->L, "rspamd{task}", -1);
	*ptask = task;

	if (lua_pcall (cd->L, 1, LUA_MULTRET, 0) != 0) {
		msg_info ("call to (%s)%s failed: %s", cd->symbol,
			cd->cb_is_ref ? "local function" : cd->callback.name,
			lua_tostring (cd->L, -1));
	}

	nresults = lua_gettop (cd->L) - level;
	if (nresults >= 1) {
		/* Function returned boolean, so maybe we need to insert result? */
		gboolean res;
		GList *opts = NULL;
		gint i;
		gdouble flag = 1.0;

		if (lua_type (cd->L, level + 1) == LUA_TBOOLEAN) {
			res = lua_toboolean (cd->L, level + 1);
			if (res) {
				gint first_opt = 2;

				if (lua_type (cd->L, level + 2) == LUA_TNUMBER) {
					flag = lua_tonumber (cd->L, level + 2);
					/* Shift opt index */
					first_opt = 3;
				}

				for (i = lua_gettop (cd->L); i >= level + first_opt; i --) {
					if (lua_type (cd->L, i) == LUA_TSTRING) {
						const char *opt = lua_tostring (cd->L, i);

						opts = g_list_prepend (opts,
							rspamd_mempool_strdup (task->task_pool, opt));
					}
				}
				rspamd_task_insert_result (task, cd->symbol, flag, opts);
			}
		}
		lua_pop (cd->L, nresults);
	}
}
Exemple #9
0
static gint
lua_config_register_function (lua_State *L)
{
	struct rspamd_config *cfg = lua_check_config (L);
	gchar *name;
	struct lua_callback_data *cd;

	if (cfg) {
		name = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2));
		cd =
			rspamd_mempool_alloc (cfg->cfg_pool,
				sizeof (struct lua_callback_data));

		if (lua_type (L, 3) == LUA_TSTRING) {
			cd->callback.name = rspamd_mempool_strdup (cfg->cfg_pool,
					luaL_checkstring (L, 3));
			cd->cb_is_ref = FALSE;
		}
		else {
			lua_pushvalue (L, 3);
			/* Get a reference */
			cd->callback.ref = luaL_ref (L, LUA_REGISTRYINDEX);
			cd->cb_is_ref = TRUE;
		}
		if (name) {
			cd->L = L;
			cd->symbol = name;
			register_expression_function (name, lua_config_function_callback,
				cd);
		}
		rspamd_mempool_add_destructor (cfg->cfg_pool,
			(rspamd_mempool_destruct_t)lua_destroy_cfg_symbol,
			cd);
	}
	return 1;
}
Exemple #10
0
static gint
lua_config_register_virtual_symbol (lua_State * L)
{
	struct rspamd_config *cfg = lua_check_config (L);
	gchar *name;
	double weight;

	if (cfg) {
		name = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2));
		weight = luaL_checknumber (L, 3);
		if (name) {
			register_virtual_symbol (&cfg->cache, name, weight);
		}
	}
	return 0;
}
Exemple #11
0
void
rspamd_symbols_cache_add_dependency (struct symbols_cache *cache,
		gint id_from, const gchar *to)
{
	struct cache_item *source;
	struct cache_dependency *dep;

	g_assert (id_from < (gint)cache->items_by_id->len);

	source = g_ptr_array_index (cache->items_by_id, id_from);
	dep = rspamd_mempool_alloc (cache->static_pool, sizeof (*dep));
	dep->id = id_from;
	dep->sym = rspamd_mempool_strdup (cache->static_pool, to);
	/* Will be filled later */
	dep->item = NULL;
	g_ptr_array_add (source->deps, dep);
}
Exemple #12
0
struct rspamd_symbols_group *
rspamd_config_new_group (struct rspamd_config *cfg, struct metric *metric,
		const gchar *name)
{
	struct rspamd_symbols_group *gr;

	gr = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*gr));
	gr->symbols = g_hash_table_new (rspamd_strcase_hash,
			rspamd_strcase_equal);
	rspamd_mempool_add_destructor (cfg->cfg_pool,
			(rspamd_mempool_destruct_t)g_hash_table_unref, gr->symbols);
	gr->name = rspamd_mempool_strdup (cfg->cfg_pool, name);

	g_hash_table_insert (metric->groups, gr->name, gr);

	return gr;
}
Exemple #13
0
struct metric *
rspamd_config_new_metric (struct rspamd_config *cfg, struct metric *c,
		const gchar *name)
{
	int i;

	if (c == NULL) {
		c = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (struct metric));
		c->grow_factor = 1.0;
		c->symbols = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
		c->groups = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);

		for (i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i++) {
			c->actions[i].score = -1.0;
			c->actions[i].action = i;
		}

		c->subject = SPAM_SUBJECT;
		c->name = rspamd_mempool_strdup (cfg->cfg_pool, name);
		rspamd_mempool_add_destructor (cfg->cfg_pool,
			(rspamd_mempool_destruct_t) g_hash_table_unref,
			c->symbols);
		rspamd_mempool_add_destructor (cfg->cfg_pool,
			(rspamd_mempool_destruct_t) g_hash_table_unref,
			c->groups);

		g_hash_table_insert (cfg->metrics, (void *)c->name, c);
		cfg->metrics_list = g_list_prepend (cfg->metrics_list, c);

		if (strcmp (c->name, DEFAULT_METRIC) == 0) {
			cfg->default_metric = c;
		}
	}

	return c;
}
Exemple #14
0
gint
rspamd_symbols_cache_add_symbol (struct symbols_cache *cache,
	const gchar *name,
	double weight,
	gint priority,
	symbol_func_t func,
	gpointer user_data,
	enum rspamd_symbol_type type,
	gint parent)
{
	struct cache_item *item = NULL;

	g_assert (cache != NULL);

	if (name == NULL && type != SYMBOL_TYPE_CALLBACK) {
		msg_warn ("no name for non-callback symbol!");
	}
	else if (type == SYMBOL_TYPE_VIRTUAL && parent == -1) {
		msg_warn ("no parent symbol is associated with virtual symbol %s",
			name);
	}

	if (name != NULL) {
		if (g_hash_table_lookup (cache->items_by_symbol, name) != NULL) {
			msg_err ("skip duplicate symbol registration for %s", name);
			return -1;
		}
	}

	item = rspamd_mempool_alloc0_shared (cache->static_pool,
			sizeof (struct cache_item));
	/*
	 * We do not share cd to skip locking, instead we'll just calculate it on
	 * save or accumulate
	 */
	item->cd = rspamd_mempool_alloc0 (cache->static_pool,
			sizeof (struct counter_data));

	if (name != NULL) {
		item->symbol = rspamd_mempool_strdup (cache->static_pool, name);
	}

	item->func = func;
	item->user_data = user_data;
	item->priority = priority;
	item->type = type;
	item->weight = weight;

	if (item->weight < 0 && item->priority == 0) {
		/* Make priority for negative weighted symbols */
		item->priority = 1;
	}

	item->id = cache->used_items;
	item->parent = parent;
	cache->used_items ++;
	msg_debug ("used items: %d, added symbol: %s", cache->used_items, name);
	rspamd_set_counter (item, 0);
	g_ptr_array_add (cache->items_by_id, item);
	g_ptr_array_add (cache->items_by_order, item);
	item->deps = g_ptr_array_new ();
	item->rdeps = g_ptr_array_new ();
	rspamd_mempool_add_destructor (cache->static_pool,
			rspamd_ptr_array_free_hard, item->deps);
	rspamd_mempool_add_destructor (cache->static_pool,
			rspamd_ptr_array_free_hard, item->rdeps);

	if (name != NULL) {
		g_hash_table_insert (cache->items_by_symbol, item->symbol, item);
	}

	return item->id;
}
Exemple #15
0
gboolean
rspamd_config_add_metric_symbol (struct rspamd_config *cfg,
		const gchar *metric_name, const gchar *symbol,
		gdouble score, const gchar *description, const gchar *group,
		gboolean one_shot, gboolean rewrite_existing)
{
	struct rspamd_symbols_group *sym_group;
	struct rspamd_symbol_def *sym_def;
	GList *metric_list;
	struct metric *metric;
	gdouble *score_ptr;

	g_assert (cfg != NULL);
	g_assert (symbol != NULL);

	if (metric_name == NULL) {
		metric_name = DEFAULT_METRIC;
	}

	metric = g_hash_table_lookup (cfg->metrics, metric_name);

	if (metric == NULL) {
		msg_err_config ("metric %s has not been found", metric_name);
		return FALSE;
	}

	if (g_hash_table_lookup (cfg->metrics_symbols, symbol) != NULL &&
			!rewrite_existing) {
		msg_debug_config ("symbol %s has been already registered, do not override");
		return FALSE;
	}

	sym_def =
		rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_symbol_def));
	score_ptr = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (gdouble));

	*score_ptr = score;
	sym_def->score = score;
	sym_def->weight_ptr = score_ptr;
	sym_def->name = rspamd_mempool_strdup (cfg->cfg_pool, symbol);
	sym_def->one_shot = one_shot;

	if (description) {
		sym_def->description = rspamd_mempool_strdup (cfg->cfg_pool, description);
	}

	msg_debug_config ("registered symbol %s with weight %.2f in metric %s and group %s",
			sym_def->name, score, metric->name, group);

	g_hash_table_insert (metric->symbols, sym_def->name, sym_def);

	if ((metric_list =
		g_hash_table_lookup (cfg->metrics_symbols, sym_def->name)) == NULL) {
		metric_list = g_list_prepend (NULL, metric);
		rspamd_mempool_add_destructor (cfg->cfg_pool,
			(rspamd_mempool_destruct_t)g_list_free,
			metric_list);
		g_hash_table_insert (cfg->metrics_symbols, sym_def->name, metric_list);
	}
	else {
		/* Slow but keep start element of list in safe */
		if (!g_list_find (metric_list, metric)) {
			metric_list = g_list_append (metric_list, metric);
		}
	}

	/* Search for symbol group */
	if (group == NULL) {
		group = "ungrouped";
	}

	sym_group = g_hash_table_lookup (metric->groups, group);
	if (sym_group == NULL) {
		/* Create new group */
		sym_group = rspamd_config_new_group (cfg, metric, group);
	}

	sym_def->gr = sym_group;
	g_hash_table_insert (sym_group->symbols, sym_def->name, sym_def);

	return TRUE;
}
Exemple #16
0
gboolean
rspamd_parse_bind_line (struct rspamd_config *cfg,
	struct rspamd_worker_conf *cf,
	const gchar *str)
{
	struct rspamd_worker_bind_conf *cnf;
	gchar **tokens, *err;
	gboolean ret = TRUE;

	if (str == NULL) {
		return FALSE;
	}

	if (str[0] == '[') {
		/* This is an ipv6 address */
		gsize len, ntok;
		const gchar *start, *ip_pos;

		start = str + 1;

		len = strcspn (start, "]");
		if (start[len] != ']') {
			return FALSE;
		}

		ip_pos = start;
		start += len + 1;
		ntok = 1;

		if (*start == ':') {
			ntok = 2;
			start ++;
		}

		tokens = g_malloc_n (ntok + 1, sizeof (gchar *));
		tokens[ntok] = NULL;
		tokens[0] = g_malloc (len + 1);
		rspamd_strlcpy (tokens[0], ip_pos, len + 1);

		if (ntok > 1) {
			tokens[1] = g_strdup (start);
		}
	}
	else {
		tokens = g_strsplit_set (str, ":", 0);
	}
	if (!tokens || !tokens[0]) {
		return FALSE;
	}

	cnf =
		rspamd_mempool_alloc0 (cfg->cfg_pool,
			sizeof (struct rspamd_worker_bind_conf));

	cnf->cnt = 1024;
	if (strcmp (tokens[0], "systemd") == 0) {
		/* The actual socket will be passed by systemd environment */
		cnf->is_systemd = TRUE;
		cnf->cnt = strtoul (tokens[1], &err, 10);
		cnf->addrs = NULL;

		if (err == NULL || *err == '\0') {
			cnf->name = rspamd_mempool_strdup (cfg->cfg_pool, str);
			LL_PREPEND (cf->bind_conf, cnf);
		}
		else {
			msg_err_config ("cannot parse bind line: %s", str);
			ret = FALSE;
		}
	}
	else {
		if (!rspamd_parse_host_port_priority_strv (tokens, &cnf->addrs,
				NULL, &cnf->name, DEFAULT_BIND_PORT, cfg->cfg_pool)) {
			msg_err_config ("cannot parse bind line: %s", str);
			ret = FALSE;
		}
		else {
			cnf->cnt = cnf->addrs->len;
			LL_PREPEND (cf->bind_conf, cnf);
		}
	}

	g_strfreev (tokens);

	return ret;
}
Exemple #17
0
/*
 * Perform post load actions
 */
void
rspamd_config_post_load (struct rspamd_config *cfg)
{
#ifdef HAVE_CLOCK_GETTIME
	struct timespec ts;
#endif
	struct metric *def_metric;

#ifdef HAVE_CLOCK_GETTIME
#ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
	clock_getres (CLOCK_PROCESS_CPUTIME_ID, &ts);
# elif defined(HAVE_CLOCK_VIRTUAL)
	clock_getres (CLOCK_VIRTUAL,			&ts);
# else
	clock_getres (CLOCK_REALTIME,			&ts);
# endif

	cfg->clock_res = log10 (1000000. / ts.tv_nsec);
	if (cfg->clock_res < 0) {
		cfg->clock_res = 0;
	}
	if (cfg->clock_res > 3) {
		cfg->clock_res = 3;
	}
#else
	/* For gettimeofday */
	cfg->clock_res = 1;
#endif

	rspamd_regexp_library_init ();

	if ((def_metric =
		g_hash_table_lookup (cfg->metrics, DEFAULT_METRIC)) == NULL) {
		def_metric = rspamd_config_new_metric (cfg, NULL, DEFAULT_METRIC);
		def_metric->actions[METRIC_ACTION_REJECT].score = DEFAULT_SCORE;
	}

	if (cfg->tld_file == NULL) {
		/* Try to guess tld file */
		GString *fpath = g_string_new (NULL);

		rspamd_printf_gstring (fpath, "%s%c%s", RSPAMD_PLUGINSDIR,
				G_DIR_SEPARATOR, "effective_tld_names.dat");

		if (access (fpath->str, R_OK)) {
			msg_warn_config ("url_tld option is not specified but %s is available,"
					" therefore this file is assumed as TLD file for URL"
					" extraction", fpath->str);
			cfg->tld_file = rspamd_mempool_strdup (cfg->cfg_pool, fpath->str);
		}
		else {
			msg_err_config ("no url_tld option has been specified, URL's detection "
					"will be awfully broken");
		}

		g_string_free (fpath, TRUE);
	}

	/* Lua options */
	(void)rspamd_lua_post_load_config (cfg);
	init_dynamic_config (cfg);

	rspamd_url_init (cfg->tld_file);

	/* Insert classifiers symbols */
	(void)rspamd_config_insert_classify_symbols (cfg);
}
Exemple #18
0
/***
 * @function rspamd_tcp.request({params})
 * This function creates and sends TCP request to the specified host and port,
 * resolves hostname (if needed) and invokes continuation callback upon data received
 * from the remote peer. This function accepts table of arguments with the following
 * attributes
 *
 * - `task`: rspamd task objects (implies `pool`, `session`, `ev_base` and `resolver` arguments)
 * - `ev_base`: event base (if no task specified)
 * - `resolver`: DNS resolver (no task)
 * - `session`: events session (no task)
 * - `pool`: memory pool (no task)
 * - `host`: IP or name of the peer (required)
 * - `port`: remote port to use (required)
 * - `data`: a table of strings or `rspamd_text` objects that contains data pieces
 * - `callback`: continuation function (required)
 * - `timeout`: floating point value that specifies timeout for IO operations in seconds
 * - `partial`: boolean flag that specifies that callback should be called on any data portion received
 * - `stop_pattern`: stop reading on finding a certain pattern (e.g. \r\n.\r\n for smtp)
 * @return {boolean} true if request has been sent
 */
static gint
lua_tcp_request (lua_State *L)
{
	const gchar *host;
	gchar *stop_pattern = NULL;
	guint port;
	gint cbref, tp;
	struct event_base *ev_base;
	struct lua_tcp_cbdata *cbd;
	struct rspamd_dns_resolver *resolver;
	struct rspamd_async_session *session;
	struct rspamd_task *task = NULL;
	rspamd_mempool_t *pool;
	struct iovec *iov = NULL;
	guint niov = 0, total_out;
	gdouble timeout = default_tcp_timeout;
	gboolean partial = FALSE;

	if (lua_type (L, 1) == LUA_TTABLE) {
		lua_pushstring (L, "host");
		lua_gettable (L, -2);
		host = luaL_checkstring (L, -1);
		lua_pop (L, 1);

		lua_pushstring (L, "port");
		lua_gettable (L, -2);
		port = luaL_checknumber (L, -1);
		lua_pop (L, 1);

		lua_pushstring (L, "callback");
		lua_gettable (L, -2);
		if (host == NULL || lua_type (L, -1) != LUA_TFUNCTION) {
			lua_pop (L, 1);
			msg_err ("tcp request has bad params");
			lua_pushboolean (L, FALSE);
			return 1;
		}
		cbref = luaL_ref (L, LUA_REGISTRYINDEX);

		lua_pushstring (L, "task");
		lua_gettable (L, -2);
		if (lua_type (L, -1) == LUA_TUSERDATA) {
			task = lua_check_task (L, -1);
			ev_base = task->ev_base;
			resolver = task->resolver;
			session = task->s;
			pool = task->task_pool;
		}
		lua_pop (L, 1);

		if (task == NULL) {
			lua_pushstring (L, "ev_base");
			lua_gettable (L, -2);
			if (luaL_checkudata (L, -1, "rspamd{ev_base}")) {
				ev_base = *(struct event_base **)lua_touserdata (L, -1);
			}
			else {
				ev_base = NULL;
			}
			lua_pop (L, 1);

			lua_pushstring (L, "pool");
			lua_gettable (L, -2);
			if (luaL_checkudata (L, -1, "rspamd{mempool}")) {
				pool = *(rspamd_mempool_t **)lua_touserdata (L, -1);
			}
			else {
				pool = NULL;
			}
			lua_pop (L, 1);

			lua_pushstring (L, "resolver");
			lua_gettable (L, -2);
			if (luaL_checkudata (L, -1, "rspamd{resolver}")) {
				resolver = *(struct rspamd_dns_resolver **)lua_touserdata (L, -1);
			}
			else {
				resolver = lua_tcp_global_resolver (ev_base);
			}
			lua_pop (L, 1);

			lua_pushstring (L, "session");
			lua_gettable (L, -2);
			if (luaL_checkudata (L, -1, "rspamd{session}")) {
				session = *(struct rspamd_async_session **)lua_touserdata (L, -1);
			}
			else {
				session = NULL;
			}
			lua_pop (L, 1);
		}

		lua_pushstring (L, "timeout");
		lua_gettable (L, -2);
		if (lua_type (L, -1) == LUA_TNUMBER) {
			timeout = lua_tonumber (L, -1) * 1000.;
		}
		lua_pop (L, 1);

		lua_pushstring (L, "stop_pattern");
		lua_gettable (L, -2);
		if (lua_type (L, -1) == LUA_TSTRING) {
			stop_pattern = rspamd_mempool_strdup (pool, lua_tostring (L, -1));
		}
		lua_pop (L, 1);

		lua_pushstring (L, "partial");
		lua_gettable (L, -2);
		if (lua_type (L, -1) == LUA_TBOOLEAN) {
			partial = lua_toboolean (L, -1);
		}
		lua_pop (L, 1);

		if (pool == NULL) {
			lua_pop (L, 1);
			msg_err ("tcp request has no memory pool associated");
			lua_pushboolean (L, FALSE);
			return 1;
		}

		lua_pushstring (L, "data");
		lua_gettable (L, -2);
		total_out = 0;

		tp = lua_type (L, -1);
		if (tp == LUA_TSTRING || tp == LUA_TUSERDATA) {
			iov = rspamd_mempool_alloc (pool, sizeof (*iov));
			niov = 1;

			if (!lua_tcp_arg_toiovec (L, -1, pool, iov)) {
				lua_pop (L, 1);
				msg_err ("tcp request has bad data argument");
				lua_pushboolean (L, FALSE);
				return 1;
			}

			total_out = iov[0].iov_len;
		}
		else if (tp == LUA_TTABLE) {
			/* Count parts */
			lua_pushnil (L);
			while (lua_next (L, -2) != 0) {
				niov ++;
				lua_pop (L, 1);
			}

			iov = rspamd_mempool_alloc (pool, sizeof (*iov) * niov);
			lua_pushnil (L);
			niov = 0;

			while (lua_next (L, -2) != 0) {
				if (!lua_tcp_arg_toiovec (L, -1, pool, &iov[niov])) {
					lua_pop (L, 2);
					msg_err ("tcp request has bad data argument at pos %d", niov);
					lua_pushboolean (L, FALSE);
					return 1;
				}

				total_out += iov[niov].iov_len;
				niov ++;

				lua_pop (L, 1);
			}
		}

		lua_pop (L, 1);
	}
	else {
		msg_err ("tcp request has bad params");
		lua_pushboolean (L, FALSE);

		return 1;
	}

	cbd = g_slice_alloc0 (sizeof (*cbd));
	cbd->L = L;
	cbd->cbref = cbref;
	cbd->ev_base = ev_base;
	msec_to_tv (timeout, &cbd->tv);
	cbd->fd = -1;
	cbd->pool = pool;
	cbd->partial = partial;
	cbd->iov = iov;
	cbd->iovlen = niov;
	cbd->total = total_out;
	cbd->pos = 0;
	cbd->port = port;
	cbd->stop_pattern = stop_pattern;

	if (session) {
		cbd->session = session;
		rspamd_session_add_event (session,
				(event_finalizer_t)lua_tcp_fin,
				cbd,
				g_quark_from_static_string ("lua tcp"));
	}

	if (rspamd_parse_inet_address (&cbd->addr, host)) {
		rspamd_inet_address_set_port (cbd->addr, port);
		/* Host is numeric IP, no need to resolve */
		if (!lua_tcp_make_connection (cbd)) {
			lua_tcp_maybe_free (cbd);
			lua_pushboolean (L, FALSE);

			return 1;
		}
	}
	else {
		if (task == NULL) {
			if (!make_dns_request (resolver, session, NULL, lua_tcp_dns_handler, cbd,
					RDNS_REQUEST_A, host)) {
				lua_tcp_push_error (cbd, "cannot resolve host");
				lua_tcp_maybe_free (cbd);
			}
		}
		else {
			if (!make_dns_request_task (task, lua_tcp_dns_handler, cbd,
					RDNS_REQUEST_A, host)) {
				lua_tcp_push_error (cbd, "cannot resolve host");
				lua_tcp_maybe_free (cbd);
			}
		}
	}

	lua_pushboolean (L, TRUE);
	return 1;
}
Exemple #19
0
/* Process a single item in 'metrics' table */
static void
lua_process_metric (lua_State *L, const gchar *name, struct rspamd_config *cfg)
{
	GList *metric_list;
	gchar *symbol;
	const gchar *desc;
	struct metric *metric;
	gdouble *score;
	struct rspamd_symbol_def *s;

	/* Get module opt structure */
	if ((metric = g_hash_table_lookup (cfg->metrics, name)) == NULL) {
		metric = rspamd_config_new_metric (cfg, metric, name);
	}

	/* Now iterate throught module table */
	for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
		/* key - -2, value - -1 */
		symbol =
			rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, -2));
		if (symbol != NULL) {
			if (lua_istable (L, -1)) {
				/* We got a table, so extract individual attributes */
				lua_pushstring (L, "weight");
				lua_gettable (L, -2);
				if (lua_isnumber (L, -1)) {
					score =
						rspamd_mempool_alloc (cfg->cfg_pool, sizeof (double));
					*score = lua_tonumber (L, -1);
				}
				else {
					msg_warn_config("cannot get weight of symbol: %s", symbol);
					continue;
				}
				lua_pop (L, 1);
				lua_pushstring (L, "description");
				lua_gettable (L, -2);
				if (lua_isstring (L, -1)) {
					desc = lua_tostring (L, -1);
					s->description = rspamd_mempool_strdup (cfg->cfg_pool, desc);
				}
				lua_pop (L, 1);
			}
			else if (lua_isnumber (L, -1)) {
				/* Just got weight */
				score = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (double));
				*score = lua_tonumber (L, -1);
			}
			else {
				msg_warn_config("cannot get weight of symbol: %s", symbol);
				continue;
			}
			/* Insert symbol */
			if ((s =
				g_hash_table_lookup (metric->symbols, symbol)) != NULL) {
				msg_info_config("replacing weight for symbol %s: %.2f -> %.2f",
					symbol,
					*s->weight_ptr,
					*score);
				s->weight_ptr = score;
			}
			else {
				s = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (*s));
				s->name = symbol;
				s->weight_ptr = score;
				g_hash_table_insert (metric->symbols, symbol, s);
			}

			if ((metric_list =
				g_hash_table_lookup (cfg->metrics_symbols, symbol)) == NULL) {
				metric_list = g_list_prepend (NULL, metric);
				rspamd_mempool_add_destructor (cfg->cfg_pool,
					(rspamd_mempool_destruct_t)g_list_free, metric_list);
				g_hash_table_insert (cfg->metrics_symbols, symbol, metric_list);
			}
			else {
				/* Slow but keep start element of list in safe */
				if (!g_list_find (metric_list, metric)) {
					metric_list = g_list_append (metric_list, metric);
				}
			}
		}
	}
}
Exemple #20
0
gboolean
rspamd_map_add (struct rspamd_config *cfg,
                const gchar *map_line,
                const gchar *description,
                map_cb_t read_callback,
                map_fin_cb_t fin_callback,
                void **user_data)
{
    struct rspamd_map *new_map;
    enum fetch_proto proto;
    const gchar *def, *p, *hostend;
    struct file_map_data *fdata;
    struct http_map_data *hdata;
    gchar portbuf[6], *cksum_encoded, cksum[BLAKE2B_OUTBYTES];
    gint i, s, r;
    struct addrinfo hints, *res;
    rspamd_mempool_t *pool;

    /* First of all detect protocol line */
    if (!rspamd_map_check_proto (map_line, (int *)&proto, &def)) {
        return FALSE;
    }
    /* Constant pool */
    if (cfg->map_pool == NULL) {
        cfg->map_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (),
                                            "map");
        memcpy (cfg->map_pool->tag.uid, cfg->cfg_pool->tag.uid,
                sizeof (cfg->map_pool->tag.uid));
    }

    new_map = rspamd_mempool_alloc0 (cfg->map_pool, sizeof (struct rspamd_map));
    new_map->read_callback = read_callback;
    new_map->fin_callback = fin_callback;
    new_map->user_data = user_data;
    new_map->protocol = proto;
    new_map->cfg = cfg;
    new_map->id = g_random_int ();
    new_map->locked =
        rspamd_mempool_alloc0_shared (cfg->cfg_pool, sizeof (gint));

    if (proto == MAP_PROTO_FILE) {
        new_map->uri = rspamd_mempool_strdup (cfg->cfg_pool, def);
        def = new_map->uri;
    }
    else {
        new_map->uri = rspamd_mempool_strdup (cfg->cfg_pool, map_line);
    }
    if (description != NULL) {
        new_map->description =
            rspamd_mempool_strdup (cfg->cfg_pool, description);
    }

    /* Now check for each proto separately */
    if (proto == MAP_PROTO_FILE) {
        fdata =
            rspamd_mempool_alloc0 (cfg->map_pool,
                                   sizeof (struct file_map_data));
        if (access (def, R_OK) == -1) {
            if (errno != ENOENT) {
                msg_err_config ("cannot open file '%s': %s", def, strerror
                                (errno));
                return FALSE;

            }
            msg_info_config (
                "map '%s' is not found, but it can be loaded automatically later",
                def);
            /* We still can add this file */
            fdata->st.st_mtime = -1;
        }
        else {
            stat (def, &fdata->st);
        }
        fdata->filename = rspamd_mempool_strdup (cfg->map_pool, def);
        new_map->map_data = fdata;
    }
    else if (proto == MAP_PROTO_HTTP) {
        hdata =
            rspamd_mempool_alloc0 (cfg->map_pool,
                                   sizeof (struct http_map_data));
        /* Try to search port */
        if ((p = strchr (def, ':')) != NULL) {
            hostend = p;
            i = 0;
            p++;
            while (g_ascii_isdigit (*p) && i < (gint)sizeof (portbuf) - 1) {
                portbuf[i++] = *p++;
            }
            if (*p != '/') {
                msg_info_config ("bad http map definition: %s", def);
                return FALSE;
            }
            portbuf[i] = '\0';
            hdata->port = atoi (portbuf);
        }
        else {
            /* Default http port */
            rspamd_snprintf (portbuf, sizeof (portbuf), "80");
            hdata->port = 80;
            /* Now separate host from path */
            if ((p = strchr (def, '/')) == NULL) {
                msg_info_config ("bad http map definition: %s", def);
                return FALSE;
            }
            hostend = p;
        }
        hdata->host = rspamd_mempool_alloc (cfg->map_pool, hostend - def + 1);
        rspamd_strlcpy (hdata->host, def, hostend - def + 1);
        hdata->path = rspamd_mempool_strdup (cfg->map_pool, p);
        /* Now try to resolve */
        memset (&hints, 0, sizeof (hints));
        hints.ai_family = AF_UNSPEC;     /* Allow IPv4 or IPv6 */
        hints.ai_socktype = SOCK_STREAM; /* Stream socket */
        hints.ai_flags = 0;
        hints.ai_protocol = 0;           /* Any protocol */
        hints.ai_canonname = NULL;
        hints.ai_addr = NULL;
        hints.ai_next = NULL;

        if ((r = getaddrinfo (hdata->host, portbuf, &hints, &res)) == 0) {
            hdata->addr = res;
            rspamd_mempool_add_destructor (cfg->cfg_pool,
                                           (rspamd_mempool_destruct_t)freeaddrinfo, hdata->addr);
        }
        else {
            msg_err_config ("address resolution for %s failed: %s",
                            hdata->host,
                            gai_strerror (r));
            return FALSE;
        }
        /* Now try to connect */
        if ((s = rspamd_socket_tcp (hdata->addr, FALSE, FALSE)) == -1) {
            msg_info_config ("cannot connect to http server %s: %d, %s",
                             hdata->host,
                             errno,
                             strerror (errno));
            return FALSE;
        }
        close (s);
        hdata->conn = rspamd_http_connection_new (http_map_read, http_map_error,
                      http_map_finish,
                      RSPAMD_HTTP_BODY_PARTIAL | RSPAMD_HTTP_CLIENT_SIMPLE,
                      RSPAMD_HTTP_CLIENT, NULL);
        new_map->map_data = hdata;
    }
    /* Temp pool */
    blake2b (cksum, new_map->uri, NULL, sizeof (cksum), strlen (new_map->uri), 0);
    cksum_encoded = rspamd_encode_base32 (cksum, sizeof (cksum));
    new_map->pool = rspamd_mempool_new (rspamd_mempool_suggest_size (), "map");
    memcpy (new_map->pool->tag.uid, cksum_encoded,
            sizeof (new_map->pool->tag.uid));
    g_free (cksum_encoded);
    pool = new_map->pool;
    msg_info_pool ("added map %s", new_map->uri);


    cfg->maps = g_list_prepend (cfg->maps, new_map);

    return TRUE;
}
Exemple #21
0
struct rspamd_map *
rspamd_map_add (struct rspamd_config *cfg,
	const gchar *map_line,
	const gchar *description,
	map_cb_t read_callback,
	map_fin_cb_t fin_callback,
	void **user_data)
{
	struct rspamd_map *new_map;
	const gchar *def;
	struct file_map_data *fdata;
	struct http_map_data *hdata;
	gchar *cksum_encoded, cksum[rspamd_cryptobox_HASHBYTES];
	rspamd_mempool_t *pool;
	struct http_parser_url up;
	rspamd_ftok_t tok;

	if (cfg->map_pool == NULL) {
		cfg->map_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (),
				"map");
		memcpy (cfg->map_pool->tag.uid, cfg->cfg_pool->tag.uid,
				sizeof (cfg->map_pool->tag.uid));
	}

	new_map = rspamd_mempool_alloc0 (cfg->map_pool, sizeof (struct rspamd_map));

	/* First of all detect protocol line */
	if (rspamd_map_check_proto (cfg, map_line, new_map) == NULL) {
		return NULL;
	}

	new_map->read_callback = read_callback;
	new_map->fin_callback = fin_callback;
	new_map->user_data = user_data;
	new_map->cfg = cfg;
	new_map->id = g_random_int ();
	new_map->locked =
		rspamd_mempool_alloc0_shared (cfg->cfg_pool, sizeof (gint));
	def = new_map->uri;

	if (description != NULL) {
		new_map->description =
			rspamd_mempool_strdup (cfg->cfg_pool, description);
	}

	/* Now check for each proto separately */
	if (new_map->protocol == MAP_PROTO_FILE) {
		fdata =
			rspamd_mempool_alloc0 (cfg->map_pool,
				sizeof (struct file_map_data));
		if (access (def, R_OK) == -1) {
			if (errno != ENOENT) {
				msg_err_config ("cannot open file '%s': %s", def, strerror
						(errno));
				return NULL;

			}
			msg_info_config (
				"map '%s' is not found, but it can be loaded automatically later",
				def);
			/* We still can add this file */
			fdata->st.st_mtime = -1;
		}
		else {
			stat (def, &fdata->st);
		}
		fdata->filename = rspamd_mempool_strdup (cfg->map_pool, def);
		new_map->map_data = fdata;
	}
	else if (new_map->protocol == MAP_PROTO_HTTP) {
		hdata =
			rspamd_mempool_alloc0 (cfg->map_pool,
				sizeof (struct http_map_data));

		memset (&up, 0, sizeof (up));
		if (http_parser_parse_url (new_map->uri, strlen (new_map->uri), FALSE,
				&up) != 0) {
			msg_err_config ("cannot parse HTTP url: %s", new_map->uri);
			return NULL;
		}
		else {
			if (!(up.field_set & 1 << UF_HOST)) {
				msg_err_config ("cannot parse HTTP url: %s: no host", new_map->uri);
				return NULL;
			}

			tok.begin = new_map->uri + up.field_data[UF_HOST].off;
			tok.len = up.field_data[UF_HOST].len;
			hdata->host = rspamd_mempool_ftokdup (cfg->map_pool, &tok);

			if (up.field_set & 1 << UF_PORT) {
				hdata->port = up.port;
			}
			else {
				hdata->port = 80;
			}

			if (up.field_set & 1 << UF_PATH) {
				tok.begin = new_map->uri + up.field_data[UF_PATH].off;
				tok.len = strlen (tok.begin);

				hdata->path = rspamd_mempool_ftokdup (cfg->map_pool, &tok);
			}
		}

		new_map->map_data = hdata;

	}

	/* Temp pool */
	rspamd_cryptobox_hash (cksum, new_map->uri, strlen (new_map->uri), NULL, 0);
	cksum_encoded = rspamd_encode_base32 (cksum, sizeof (cksum));
	new_map->pool = rspamd_mempool_new (rspamd_mempool_suggest_size (), "map");
	rspamd_strlcpy (new_map->pool->tag.uid, cksum_encoded,
			sizeof (new_map->pool->tag.uid));
	g_free (cksum_encoded);
	pool = new_map->pool;
	msg_info_pool ("added map %s", new_map->uri);


	cfg->maps = g_list_prepend (cfg->maps, new_map);

	return new_map;
}
Exemple #22
0
static const gchar *
rspamd_map_check_proto (struct rspamd_config *cfg,
		const gchar *map_line, struct rspamd_map *map)
{
	const gchar *pos = map_line, *end, *end_key;

	g_assert (map != NULL);
	g_assert (pos != NULL);

	end = pos + strlen (pos);

	if (g_ascii_strncasecmp (pos, "sign+", sizeof ("sign+") - 1) == 0) {
		map->is_signed = TRUE;
		pos += sizeof ("sign+") - 1;
	}

	if (g_ascii_strncasecmp (pos, "key=", sizeof ("key=") - 1) == 0) {
		pos += sizeof ("key=") - 1;
		end_key = memchr (pos, '+', end - pos);

		if (end_key != NULL) {
			map->trusted_pubkey = rspamd_pubkey_from_base32 (pos, end_key - pos,
					RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519);

			if (map->trusted_pubkey == NULL) {
				msg_err_config ("cannot read pubkey from map: %s",
						map_line);
				return NULL;
			}
			pos = end_key + 1;
		}
		else if (end - pos > 64) {
			/* Try hex encoding */
			map->trusted_pubkey = rspamd_pubkey_from_hex (pos, 64,
					RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519);

			if (map->trusted_pubkey == NULL) {
				msg_err_config ("cannot read pubkey from map: %s",
						map_line);
				return NULL;
			}
			pos += 64;
		}
		else {
			msg_err_config ("cannot read pubkey from map: %s",
					map_line);
			return NULL;
		}

		if (*pos == '+' || *pos == ':') {
			pos ++;
		}
	}

	map->protocol = MAP_PROTO_FILE;

	if (g_ascii_strncasecmp (pos, "http://",
			sizeof ("http://") - 1) == 0) {
		map->protocol = MAP_PROTO_HTTP;
		/* Include http:// */
		map->uri = rspamd_mempool_strdup (cfg->cfg_pool, pos);
		pos += sizeof ("http://") - 1;
	}
	else if (g_ascii_strncasecmp (pos, "file://", sizeof ("file://") -
			1) == 0) {
		pos += sizeof ("file://") - 1;
		/* Exclude file:// */
		map->uri = rspamd_mempool_strdup (cfg->cfg_pool, pos);
	}
	else if (*pos == '/') {
		/* Trivial file case */
		map->uri = rspamd_mempool_strdup (cfg->cfg_pool, pos);
	}
	else {
		msg_err_config ("invalid map fetching protocol: %s", map_line);

		return NULL;
	}


	return pos;
}
Exemple #23
0
/*
 * Non-static for lua unit testing
 */
gsize
rspamd_redis_expand_object (const gchar *pattern,
		struct redis_stat_ctx *ctx,
		struct rspamd_task *task,
		gchar **target)
{
	gsize tlen = 0;
	const gchar *p = pattern, *elt;
	gchar *d, *end;
	enum  {
		just_char,
		percent_char,
		mod_char
	} state = just_char;
	struct rspamd_statfile_config *stcf;
	lua_State *L = NULL;
	struct rspamd_task **ptask;
	GString *tb;
	const gchar *rcpt = NULL;
	gint err_idx;

	g_assert (ctx != NULL);
	stcf = ctx->stcf;

	if (task) {
		L = task->cfg->lua_state;
	}

	if (ctx->enable_users) {
		if (ctx->cbref_user == -1) {
			rcpt = rspamd_task_get_principal_recipient (task);
		}
		else if (L) {
			/* Execute lua function to get userdata */
			lua_pushcfunction (L, &rspamd_lua_traceback);
			err_idx = lua_gettop (L);

			lua_rawgeti (L, LUA_REGISTRYINDEX, ctx->cbref_user);
			ptask = lua_newuserdata (L, sizeof (struct rspamd_task *));
			*ptask = task;
			rspamd_lua_setclass (L, "rspamd{task}", -1);

			if (lua_pcall (L, 1, 1, err_idx) != 0) {
				tb = lua_touserdata (L, -1);
				msg_err_task ("call to user extraction script failed: %v", tb);
				g_string_free (tb, TRUE);
			}
			else {
				rcpt = rspamd_mempool_strdup (task->task_pool, lua_tostring (L, -1));
			}

			/* Result + error function */
			lua_pop (L, 2);
		}

		if (rcpt) {
			rspamd_mempool_set_variable (task->task_pool, "stat_user",
					(gpointer)rcpt, NULL);
		}
	}



	/* Length calculation */
	while (*p) {
		switch (state) {
		case just_char:
			if (*p == '%') {
				state = percent_char;
			}
			else {
				tlen ++;
			}
			p ++;
			break;
		case percent_char:
			switch (*p) {
			case '%':
				tlen ++;
				state = just_char;
				break;
			case 'u':
				elt = GET_TASK_ELT (task, user);
				if (elt) {
					tlen += strlen (elt);
				}
				break;
			case 'r':

				if (rcpt == NULL) {
					elt = rspamd_task_get_principal_recipient (task);
				}
				else {
					elt = rcpt;
				}

				if (elt) {
					tlen += strlen (elt);
				}
				break;
			case 'l':
				if (stcf->label) {
					tlen += strlen (stcf->label);
				}
				break;
			case 's':
				if (stcf->symbol) {
					tlen += strlen (stcf->symbol);
				}
				break;
			default:
				state = just_char;
				tlen ++;
				break;
			}

			if (state == percent_char) {
				state = mod_char;
			}
			p ++;
			break;

		case mod_char:
			switch (*p) {
			case 'd':
				p ++;
				state = just_char;
				break;
			default:
				state = just_char;
				break;
			}
			break;
		}
	}

	if (target == NULL || task == NULL) {
		return tlen;
	}

	*target = rspamd_mempool_alloc (task->task_pool, tlen + 1);
	d = *target;
	end = d + tlen + 1;
	d[tlen] = '\0';
	p = pattern;
	state = just_char;

	/* Expand string */
	while (*p && d < end) {
		switch (state) {
		case just_char:
			if (*p == '%') {
				state = percent_char;
			}
			else {
				*d++ = *p;
			}
			p ++;
			break;
		case percent_char:
			switch (*p) {
			case '%':
				*d++ = *p;
				state = just_char;
				break;
			case 'u':
				elt = GET_TASK_ELT (task, user);
				if (elt) {
					d += rspamd_strlcpy (d, elt, end - d);
				}
				break;
			case 'r':
				if (rcpt == NULL) {
					elt = rspamd_task_get_principal_recipient (task);
				}
				else {
					elt = rcpt;
				}

				if (elt) {
					d += rspamd_strlcpy (d, elt, end - d);
				}
				break;
			case 'l':
				if (stcf->label) {
					d += rspamd_strlcpy (d, stcf->label, end - d);
				}
				break;
			case 's':
				if (stcf->symbol) {
					d += rspamd_strlcpy (d, stcf->symbol, end - d);
				}
				break;
			default:
				state = just_char;
				*d++ = *p;
				break;
			}

			if (state == percent_char) {
				state = mod_char;
			}
			p ++;
			break;

		case mod_char:
			switch (*p) {
			case 'd':
				/* TODO: not supported yet */
				p ++;
				state = just_char;
				break;
			default:
				state = just_char;
				break;
			}
			break;
		}
	}

	return tlen;
}
Exemple #24
0
static void
dkim_module_check (struct dkim_check_result *res)
{
	gboolean all_done = TRUE, got_allow = FALSE;
	const gchar *strict_value;
	struct dkim_check_result *first, *cur, *sel = NULL;

	first = res->first;

	DL_FOREACH (first, cur) {
		if (cur->ctx == NULL) {
			continue;
		}

		if (cur->key != NULL && cur->res == -1) {
			cur->res = rspamd_dkim_check (cur->ctx, cur->key, cur->task);

			if (dkim_module_ctx->dkim_domains != NULL) {
				/* Perform strict check */
				if ((strict_value =
						g_hash_table_lookup (dkim_module_ctx->dkim_domains,
								rspamd_dkim_get_domain (cur->ctx))) != NULL) {
					if (!dkim_module_parse_strict (strict_value, &cur->mult_allow,
							&cur->mult_deny)) {
						cur->mult_allow = dkim_module_ctx->strict_multiplier;
						cur->mult_deny = dkim_module_ctx->strict_multiplier;
					}
				}
			}
		}

		if (cur->res == -1 || cur->key == NULL) {
			/* Still need a key */
			all_done = FALSE;
		}
	}

	if (all_done) {
		DL_FOREACH (first, cur) {
			if (cur->ctx == NULL) {
				continue;
			}

			if (cur->res == DKIM_CONTINUE) {
				rspamd_task_insert_result (cur->task,
						dkim_module_ctx->symbol_allow,
						cur->mult_allow * 1.0,
						g_list_prepend (NULL,
								rspamd_mempool_strdup (cur->task->task_pool,
										rspamd_dkim_get_domain (cur->ctx))));
				got_allow = TRUE;
				sel = NULL;
			}
			else if (!got_allow) {
				if (sel == NULL) {
					sel = cur;
				}
				else if (sel->res == DKIM_TRYAGAIN && cur->res != DKIM_TRYAGAIN) {
					sel = cur;
				}
			}
		}
	}

	if (sel != NULL) {
		if (sel->res == DKIM_REJECT) {
			rspamd_task_insert_result (sel->task,
					dkim_module_ctx->symbol_reject,
					sel->mult_deny * 1.0,
					g_list_prepend (NULL,
							rspamd_mempool_strdup (sel->task->task_pool,
									rspamd_dkim_get_domain (sel->ctx))));
		}
		else {
			rspamd_task_insert_result (sel->task,
					dkim_module_ctx->symbol_tempfail,
					1.0,
					g_list_prepend (NULL,
							rspamd_mempool_strdup (sel->task->task_pool,
									rspamd_dkim_get_domain (sel->ctx))));
		}
	}

	if (all_done) {
		rspamd_session_watcher_pop (res->task->s, res->w);
	}
}
Exemple #25
0
/* Do post load initialization based on lua */
void
rspamd_lua_post_load_config (struct rspamd_config *cfg)
{
	lua_State *L = cfg->lua_state;
	const gchar *name, *val;
	gchar *sym;
	struct rspamd_expression *expr, *old_expr;
	ucl_object_t *obj;
	gsize keylen;
	GError *err = NULL;

	/* First check all module options that may be overriden in 'config' global */
	lua_getglobal (L, "config");

	if (lua_istable (L, -1)) {
		/* Iterate */
		for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
			/* 'key' is at index -2 and 'value' is at index -1 */
			/* Key must be a string and value must be a table */
			name = luaL_checklstring (L, -2, &keylen);
			if (name != NULL && lua_istable (L, -1)) {
				obj = ucl_object_lua_import (L, lua_gettop (L));
				if (obj != NULL) {
					ucl_object_insert_key_merged (cfg->rcl_obj,
						obj,
						name,
						keylen,
						true);
				}
			}
		}
	}

	/* Check metrics settings */
	lua_getglobal (L, "metrics");

	if (lua_istable (L, -1)) {
		/* Iterate */
		for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
			/* 'key' is at index -2 and 'value' is at index -1 */
			/* Key must be a string and value must be a table */
			name = luaL_checkstring (L, -2);
			if (name != NULL && lua_istable (L, -1)) {
				lua_process_metric (L, name, cfg);
			}
		}
	}

	/* Check composites */
	lua_getglobal (L, "composites");

	if (lua_istable (L, -1)) {
		/* Iterate */
		for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
			/* 'key' is at index -2 and 'value' is at index -1 */
			/* Key must be a string and value must be a table */
			name = luaL_checkstring (L, -2);
			if (name != NULL && lua_isstring (L, -1)) {
				val = lua_tostring (L, -1);
				sym = rspamd_mempool_strdup (cfg->cfg_pool, name);
				if (!rspamd_parse_expression (val, 0, &composite_expr_subr, NULL,
							cfg->cfg_pool, &err, &expr)) {
					msg_err_config("cannot parse composite expression '%s': %s", val,
							err->message);
					g_error_free (err);
					err = NULL;
					continue;
				}
				/* Now check hash table for this composite */
				if ((old_expr =
					g_hash_table_lookup (cfg->composite_symbols,
					name)) != NULL) {
					msg_info_config("replacing composite symbol %s", name);
					g_hash_table_replace (cfg->composite_symbols, sym, expr);
				}
				else {
					g_hash_table_insert (cfg->composite_symbols, sym, expr);
					rspamd_symbols_cache_add_symbol (cfg->cache, sym,
							0, NULL, NULL, SYMBOL_TYPE_COMPOSITE, -1);
				}
			}
		}
	}
}