Пример #1
0
struct rspamd_content_disposition *
rspamd_content_disposition_parse (const gchar *in,
		gsize len, rspamd_mempool_t *pool)
{
	struct rspamd_content_disposition *res = NULL, val;

	val.lc_data = rspamd_mempool_alloc (pool, len);
	memcpy (val.lc_data, in, len);
	rspamd_str_lc (val.lc_data, len);

	if (rspamd_content_disposition_parser (in, len, &val, pool)) {
		res = rspamd_mempool_alloc (pool, sizeof (val));
		memcpy (res, &val, sizeof (val));

		if (res->attrs) {
			rspamd_mempool_add_destructor (pool,
					(rspamd_mempool_destruct_t)g_hash_table_unref, res->attrs);
		}
	}
	else {
		msg_warn_pool ("cannot parse content disposition: %*s",
				(gint)len, val.lc_data);
	}

	return res;
}
Пример #2
0
static GList *
parse_mime_types (const gchar *str)
{
	gchar **strvec, *p;
	gint num, i;
	struct fuzzy_mime_type *type;
	GList *res = NULL;

	strvec = g_strsplit_set (str, ",", 0);
	num = g_strv_length (strvec);
	for (i = 0; i < num; i++) {
		g_strstrip (strvec[i]);
		if ((p = strchr (strvec[i], '/')) != NULL) {
			*p = 0;
			type = rspamd_mempool_alloc (fuzzy_module_ctx->fuzzy_pool,
					sizeof (struct fuzzy_mime_type));
			type->type = g_pattern_spec_new (strvec[i]);
			type->subtype = g_pattern_spec_new (p + 1);
			*p = '/';
			res = g_list_prepend (res, type);
		}
		else {
			type = rspamd_mempool_alloc (fuzzy_module_ctx->fuzzy_pool,
							sizeof (struct fuzzy_mime_type));
			type->type = g_pattern_spec_new (strvec[i]);
			type->subtype = NULL;
			res = g_list_prepend (res, type);
		}
	}

	g_strfreev (strvec);

	return res;
}
Пример #3
0
static gint
lua_config_add_kv_map (lua_State *L)
{
	struct rspamd_config *cfg = lua_check_config (L);
	const gchar *map_line, *description;
	GHashTable **r, ***ud;

	if (cfg) {
		map_line = luaL_checkstring (L, 2);
		description = lua_tostring (L, 3);
		r = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (GHashTable *));
		*r = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
		if (!add_map (cfg, map_line, description, read_kv_list, fin_kv_list,
			(void **)r)) {
			msg_warn ("invalid hash map %s", map_line);
			g_hash_table_destroy (*r);
			lua_pushnil (L);
			return 1;
		}
		rspamd_mempool_add_destructor (cfg->cfg_pool,
			(rspamd_mempool_destruct_t)g_hash_table_destroy,
			*r);
		ud = lua_newuserdata (L, sizeof (GHashTable *));
		*ud = r;
		rspamd_lua_setclass (L, "rspamd{hash_table}", -1);

		return 1;
	}

	lua_pushnil (L);
	return 1;

}
Пример #4
0
static gint
lua_config_add_radix_map (lua_State *L)
{
	struct rspamd_config *cfg = lua_check_config (L);
	const gchar *map_line, *description;
	radix_compressed_t **r, ***ud;

	if (cfg) {
		map_line = luaL_checkstring (L, 2);
		description = lua_tostring (L, 3);
		r = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (radix_compressed_t *));
		*r = radix_create_compressed ();
		if (!add_map (cfg, map_line, description, read_radix_list,
			fin_radix_list, (void **)r)) {
			msg_warn ("invalid radix map %s", map_line);
			radix_destroy_compressed (*r);
			lua_pushnil (L);
			return 1;
		}
		ud = lua_newuserdata (L, sizeof (radix_compressed_t *));
		*ud = r;
		rspamd_lua_setclass (L, "rspamd{radix}", -1);

		return 1;
	}

	lua_pushnil (L);
	return 1;

}
Пример #5
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;
}
Пример #6
0
static gboolean
lua_tcp_arg_toiovec (lua_State *L, gint pos, rspamd_mempool_t *pool,
		struct iovec *vec)
{
	struct rspamd_lua_text *t;
	gsize len;
	const gchar *str;

	if (lua_type (L, pos) == LUA_TUSERDATA) {
		t = lua_check_text (L, pos);

		if (t) {
			vec->iov_base = (void *)t->start;
			vec->iov_len = t->len;
		}
		else {
			return FALSE;
		}
	}
	else if (lua_type (L, pos) == LUA_TSTRING) {
		str = luaL_checklstring (L, pos, &len);
		vec->iov_base = rspamd_mempool_alloc (pool, len + 1);
		rspamd_strlcpy (vec->iov_base, str, len + 1);
		vec->iov_len = len;
	}
	else {
		return FALSE;
	}

	return TRUE;
}
Пример #7
0
GList *
rspamd_config_parse_comma_list (rspamd_mempool_t * pool, const gchar *line)
{
	GList *res = NULL;
	const gchar *c, *p;
	gchar *str;

	c = line;
	p = c;

	while (*p) {
		if (*p == ',' && *c != *p) {
			str = rspamd_mempool_alloc (pool, p - c + 1);
			rspamd_strlcpy (str, c, p - c + 1);
			res = g_list_prepend (res, str);
			/* Skip spaces */
			while (g_ascii_isspace (*(++p))) ;
			c = p;
			continue;
		}
		p++;
	}
	if (res != NULL) {
		rspamd_mempool_add_destructor (pool,
			(rspamd_mempool_destruct_t) g_list_free,
			res);
	}

	return res;
}
Пример #8
0
gboolean
make_smtp_tempfile (struct smtp_session *session)
{
	gsize r;

	r = strlen (session->cfg->temp_dir) + sizeof ("/rspamd-XXXXXX");
	session->temp_name = rspamd_mempool_alloc (session->pool, r);
	rspamd_snprintf (session->temp_name,
		r,
		"%s%crspamd-XXXXXX",
		session->cfg->temp_dir,
		G_DIR_SEPARATOR);
#ifdef HAVE_MKSTEMP
	/* Umask is set before */
	session->temp_fd = mkstemp (session->temp_name);
#else
	session->temp_fd = g_mkstemp_full (session->temp_name,
			O_RDWR,
			S_IWUSR | S_IRUSR);
#endif
	if (session->temp_fd == -1) {
		msg_err ("mkstemp error: %s", strerror (errno));

		return FALSE;
	}

	return TRUE;
}
Пример #9
0
static gchar*
strip_map_elt (rspamd_mempool_t *pool, const gchar *start,
               size_t len)
{
    gchar *res = NULL;
    const gchar *c = start, *p = start + len - 1;

    /* Strip starting spaces */
    while (g_ascii_isspace (*c)) {
        c ++;
    }

    /* Strip ending spaces */
    while (g_ascii_isspace (*p) && p >= c) {
        p --;
    }

    /* One symbol up */
    p ++;

    if (p - c > 0) {
        res = rspamd_mempool_alloc (pool, p - c + 1);
        rspamd_strlcpy (res, c, p - c + 1);
    }

    return res;
}
Пример #10
0
gboolean
parse_smtp_helo (struct smtp_session *session, struct smtp_command *cmd)
{
	rspamd_ftok_t *arg;

	if (cmd->args == NULL) {
		session->error = SMTP_ERROR_BAD_ARGUMENTS;
		return FALSE;
	}
	arg = cmd->args->data;
	session->helo = rspamd_mempool_alloc (session->pool, arg->len + 1);
	rspamd_strlcpy (session->helo, arg->begin, arg->len + 1);
	/* Now try to write reply */
	if (cmd->command == SMTP_COMMAND_HELO) {
		/* No ESMTP */
		session->error = SMTP_ERROR_OK;
		session->esmtp = FALSE;
		return TRUE;
	}
	else {
		/* Try to write all capabilities */
		session->esmtp = TRUE;
		if (session->ctx->smtp_capabilities == NULL) {
			session->error = SMTP_ERROR_OK;
			return TRUE;
		}
		else {
			session->error = session->ctx->smtp_capabilities;
			return TRUE;
		}
	}

	return FALSE;
}
Пример #11
0
gpointer
rspamd_tokenizer_osb_get_config (rspamd_mempool_t *pool,
		struct rspamd_tokenizer_config *cf,
		gsize *len)
{
	struct rspamd_osb_tokenizer_config *osb_cf, *def;

	if (cf != NULL && cf->opts != NULL) {
		osb_cf = rspamd_tokenizer_osb_config_from_ucl (pool, cf->opts);
	}
	else {
		def = rspamd_tokenizer_osb_default_config ();
		osb_cf = rspamd_mempool_alloc (pool, sizeof (*osb_cf));
		memcpy (osb_cf, def, sizeof (*osb_cf));
		/* Do not write sipkey to statfile */
	}

	if (osb_cf->ht == RSPAMD_OSB_HASH_SIPHASH) {
		msg_info_pool ("siphash key is not stored into statfiles, so you'd "
				"need to keep it inside the configuration");
	}

	memset (osb_cf->sk, 0, sizeof (osb_cf->sk));

	if (len != NULL) {
		*len = sizeof (*osb_cf);
	}

	return osb_cf;
}
Пример #12
0
static gint
lua_util_process_message (lua_State *L)
{
	struct rspamd_config *cfg = lua_check_config (L, 1);
	const gchar *message;
	gsize mlen;
	struct rspamd_task *task;
	struct event_base *base;
	ucl_object_t *res = NULL;

	message = luaL_checklstring (L, 2, &mlen);

	if (cfg != NULL && message != NULL) {
		base = event_init ();
		rspamd_init_filters (cfg, FALSE);
		task = rspamd_task_new (NULL);
		task->cfg = cfg;
		task->ev_base = base;
		task->msg.start = rspamd_mempool_alloc (task->task_pool, mlen + 1);
		rspamd_strlcpy ((gpointer)task->msg.start, message, mlen + 1);
		task->msg.len = mlen;
		task->fin_callback = lua_util_task_fin;
		task->fin_arg = &res;
		task->resolver = dns_resolver_init (NULL, base, cfg);
		task->s = rspamd_session_create (task->task_pool, rspamd_task_fin,
					rspamd_task_restore, rspamd_task_free_hard, task);

		if (!rspamd_task_load_message (task, NULL, message, mlen)) {
			lua_pushnil (L);
		}
		else {
			if (rspamd_task_process (task, RSPAMD_TASK_PROCESS_ALL)) {
				event_base_loop (base, 0);

				if (res != NULL) {
					ucl_object_push_lua (L, res, true);

					ucl_object_unref (res);
				}
				else {
					ucl_object_push_lua (L, rspamd_protocol_write_ucl (task, NULL),
							true);
					rdns_resolver_release (task->resolver->r);
					rspamd_task_free_hard (task);
				}
			}
			else {
				lua_pushnil (L);
			}
		}

		event_base_free (base);
	}
	else {
		lua_pushnil (L);
	}

	return 1;
}
Пример #13
0
/* Sort items in logical order */
static void
post_cache_init (struct symbols_cache *cache)
{
	struct cache_item *it, *dit;
	struct cache_dependency *dep, *rdep;
	struct delayed_cache_dependency *ddep;
	GList *cur;
	guint i, j;

	g_ptr_array_sort_with_data (cache->items_by_order, cache_logic_cmp, cache);

	cur = cache->delayed_deps;
	while (cur) {
		ddep = cur->data;

		it = g_hash_table_lookup (cache->items_by_symbol, ddep->from);

		if (it == NULL) {
			msg_err ("cannot register delayed dependency between %s and %s, "
					"%s is missing", ddep->from, ddep->to, ddep->from);
		}
		else {
			rspamd_symbols_cache_add_dependency (cache, it->id, ddep->to);
		}

		cur = g_list_next (cur);
	}

	for (i = 0; i < cache->items_by_id->len; i ++) {
		it = g_ptr_array_index (cache->items_by_id, i);

		for (j = 0; j < it->deps->len; j ++) {
			dep = g_ptr_array_index (it->deps, j);
			dit = g_hash_table_lookup (cache->items_by_symbol, dep->sym);

			if (dit != NULL) {
				if (dit->parent != -1) {
					dit = g_ptr_array_index (cache->items_by_id, dit->parent);
				}

				rdep = rspamd_mempool_alloc (cache->static_pool, sizeof (*rdep));
				rdep->sym = dep->sym;
				rdep->item = it;
				rdep->id = i;
				g_ptr_array_add (dit->rdeps, rdep);
				dep->item = dit;
				dep->id = dit->id;

				msg_debug ("add dependency from %d on %d", it->id, dit->id);
			}
			else {
				msg_err ("cannot find dependency on symbol %s", dep->sym);
			}
		}
	}
}
Пример #14
0
static void
parse_flags (struct fuzzy_rule *rule,
	struct rspamd_config *cfg,
	const ucl_object_t *val,
	gint cb_id)
{
	const ucl_object_t *elt;
	struct fuzzy_mapping *map;
	const gchar *sym = NULL;

	if (val->type == UCL_STRING) {
		msg_err_config (
			"string mappings are deprecated and no longer supported, use new style configuration");
	}
	else if (val->type == UCL_OBJECT) {
		elt = ucl_object_find_key (val, "symbol");
		if (elt == NULL || !ucl_object_tostring_safe (elt, &sym)) {
			sym = ucl_object_key (val);
		}
		if (sym != NULL) {
			map =
				rspamd_mempool_alloc (fuzzy_module_ctx->fuzzy_pool,
					sizeof (struct fuzzy_mapping));
			map->symbol = sym;
			elt = ucl_object_find_key (val, "flag");
			if (elt != NULL && ucl_obj_toint_safe (elt, &map->fuzzy_flag)) {
				elt = ucl_object_find_key (val, "max_score");
				if (elt != NULL) {
					map->weight = ucl_obj_todouble (elt);
				}
				else {
					map->weight = rule->max_score;
				}
				/* Add flag to hash table */
				g_hash_table_insert (rule->mappings,
					GINT_TO_POINTER (map->fuzzy_flag), map);
				rspamd_symbols_cache_add_symbol (cfg->cache,
						map->symbol, 0,
						NULL, NULL,
						SYMBOL_TYPE_VIRTUAL|SYMBOL_TYPE_FINE,
						cb_id);
			}
			else {
				msg_err_config ("fuzzy_map parameter has no flag definition");
			}
		}
		else {
			msg_err_config ("fuzzy_map parameter has no symbol definition");
		}
	}
	else {
		msg_err_config ("fuzzy_map parameter is of an unsupported type");
	}
}
Пример #15
0
void
rspamd_content_type_add_param (rspamd_mempool_t *pool,
		struct rspamd_content_type *ct,
		const gchar *name_start, const gchar *name_end,
		const gchar *value_start, const gchar *value_end)
{
	rspamd_ftok_t srch;
	struct rspamd_content_type_param *found = NULL, *nparam;

	g_assert (ct != NULL);

	srch.begin = name_start;
	srch.len = name_end - name_start;

	if (ct->attrs) {
		found = g_hash_table_lookup (ct->attrs, &srch);
	}
	else {
		ct->attrs = g_hash_table_new (rspamd_ftok_icase_hash,
				rspamd_ftok_icase_equal);
	}

	nparam = rspamd_mempool_alloc (pool, sizeof (*nparam));
	nparam->name.begin = name_start;
	nparam->name.len = name_end - name_start;
	nparam->value.begin = value_start;
	nparam->value.len = value_end - value_start;

	if (!found) {
		DL_APPEND (found, nparam);
		g_hash_table_insert (ct->attrs, &nparam->name, nparam);
	}
	else {
		DL_APPEND (found, nparam);
	}

	RSPAMD_FTOK_ASSIGN (&srch, "charset");

	if (rspamd_ftok_cmp (&nparam->name, &srch) == 0) {
		/* Adjust charset */
		ct->charset.begin = nparam->value.begin;
		ct->charset.len = nparam->value.len;
	}

	RSPAMD_FTOK_ASSIGN (&srch, "boundary");

	if (rspamd_ftok_cmp (&nparam->name, &srch) == 0) {
		/* Adjust boundary */
		ct->boundary.begin = nparam->value.begin;
		ct->boundary.len = nparam->value.len;
	}
}
Пример #16
0
static gboolean
add_statfile_watch (statfile_pool_t *pool,
	struct rspamd_statfile_config *st,
	struct rspamd_config *cfg,
	struct event_base *ev_base)
{
	struct rspamd_sync_ctx *ctx;
	guint32 jittered_interval;

	if (st->binlog->master_addr != NULL) {
		ctx =
			rspamd_mempool_alloc (pool->pool, sizeof (struct rspamd_sync_ctx));
		ctx->st = st;
		ctx->timeout = cfg->statfile_sync_timeout;
		ctx->sync_interval = cfg->statfile_sync_interval;
		ctx->ev_base = ev_base;
		/* Add some jittering for synchronization */
		jittered_interval = g_random_int_range (ctx->sync_interval,
				ctx->sync_interval * 2);
		msec_to_tv (jittered_interval, &ctx->interval);
		/* Open statfile and attach it to pool */
		if ((ctx->real_statfile =
			statfile_pool_is_open (pool, st->path)) == NULL) {
			if ((ctx->real_statfile =
				statfile_pool_open (pool, st->path, st->size, FALSE)) == NULL) {
				msg_warn ("cannot open %s", st->path);
				if (statfile_pool_create (pool, st->path, st->size) == -1) {
					msg_err ("cannot create statfile %s", st->path);
					return FALSE;
				}
				ctx->real_statfile = statfile_pool_open (pool,
						st->path,
						st->size,
						FALSE);
			}
		}
		/* Now plan event for it's future executing */
		evtimer_set (&ctx->tm_ev, sync_timer_callback, ctx);
		event_base_set (ctx->ev_base, &ctx->tm_ev);
		evtimer_add (&ctx->tm_ev, &ctx->interval);
		log_next_sync (st->symbol, ctx->interval.tv_sec);
	}
	else {
		msg_err ("cannot add statfile watch for statfile %s: no master defined",
			st->symbol);
		return FALSE;
	}

	return TRUE;
}
Пример #17
0
static gint
lua_config_add_map (lua_State *L)
{
	struct rspamd_config *cfg = lua_check_config (L);
	const gchar *map_line, *description;
	struct lua_map_callback_data *cbdata, **pcbdata;
	int cbidx;

	if (cfg) {
		map_line = luaL_checkstring (L, 2);

		if (lua_gettop (L) == 4) {
			description = lua_tostring (L, 3);
			cbidx = 4;
		}
		else {
			description = NULL;
			cbidx = 3;
		}

		if (lua_type (L, cbidx) == LUA_TFUNCTION) {
			cbdata = g_slice_alloc (sizeof (*cbdata));
			cbdata->L = L;
			cbdata->data = NULL;
			lua_pushvalue (L, cbidx);
			/* Get a reference */
			cbdata->ref = luaL_ref (L, LUA_REGISTRYINDEX);
			pcbdata = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (cbdata));
			*pcbdata = cbdata;
			if (!add_map (cfg, map_line, description, lua_map_read, lua_map_fin,
				(void **)pcbdata)) {
				msg_warn ("invalid hash map %s", map_line);
				lua_pushboolean (L, false);
			}
			else {
				lua_pushboolean (L, true);
			}
		}
		else {
			msg_warn ("invalid callback argument for map %s", map_line);
			lua_pushboolean (L, false);
		}
	}
	else {
		lua_pushboolean (L, false);
	}

	return 1;
}
Пример #18
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);
}
Пример #19
0
struct metric_result *
rspamd_create_metric_result (struct rspamd_task *task, const gchar *name)
{
	struct metric_result *metric_res;
	struct metric *metric;
	guint i;

	metric_res = g_hash_table_lookup (task->results, name);

	if (metric_res != NULL) {
		return metric_res;
	}

	metric = g_hash_table_lookup (task->cfg->metrics, name);
	if (metric == NULL) {
		return NULL;
	}

	metric_res =
			rspamd_mempool_alloc (task->task_pool,
					sizeof (struct metric_result));
	metric_res->symbols = g_hash_table_new (rspamd_str_hash,
			rspamd_str_equal);
	rspamd_mempool_add_destructor (task->task_pool,
			(rspamd_mempool_destruct_t) g_hash_table_unref,
			metric_res->symbols);
	metric_res->sym_groups = g_hash_table_new (g_direct_hash, g_direct_equal);
	rspamd_mempool_add_destructor (task->task_pool,
			(rspamd_mempool_destruct_t) g_hash_table_unref,
			metric_res->sym_groups);
	metric_res->metric = metric;
	metric_res->grow_factor = 0;
	metric_res->score = 0;
	g_hash_table_insert (task->results, (gpointer) metric->name,
			metric_res);

	for (i = 0; i < METRIC_ACTION_MAX; i++) {
		metric_res->actions_limits[i] = metric->actions[i].score;
	}

	metric_res->action = METRIC_ACTION_MAX;

	return metric_res;
}
Пример #20
0
void
rspamd_content_disposition_add_param (rspamd_mempool_t *pool,
		struct rspamd_content_disposition *cd,
		const gchar *name_start, const gchar *name_end,
		const gchar *value_start, const gchar *value_end)
{
	rspamd_ftok_t srch;
	gchar *decoded;
	struct rspamd_content_type_param *found = NULL, *nparam;

	g_assert (cd != NULL);

	srch.begin = name_start;
	srch.len = name_end - name_start;

	if (cd->attrs) {
		found = g_hash_table_lookup (cd->attrs, &srch);
	}
	else {
		cd->attrs = g_hash_table_new (rspamd_ftok_icase_hash,
				rspamd_ftok_icase_equal);
	}

	nparam = rspamd_mempool_alloc (pool, sizeof (*nparam));
	nparam->name.begin = name_start;
	nparam->name.len = name_end - name_start;
	decoded = rspamd_mime_header_decode (pool, value_start, value_end - value_start);
	RSPAMD_FTOK_FROM_STR (&nparam->value, decoded);

	if (!found) {
		g_hash_table_insert (cd->attrs, &nparam->name, nparam);
	}

	DL_APPEND (found, nparam);

	srch.begin = "filename";
	srch.len = 8;

	if (rspamd_ftok_cmp (&nparam->name, &srch) == 0) {
		/* Adjust filename */
		cd->filename.begin = nparam->value.begin;
		cd->filename.len = nparam->value.len;
	}
}
Пример #21
0
gchar *
make_smtp_error (rspamd_mempool_t *pool,
	gint error_code,
	const gchar *format,
	...)
{
	va_list vp;
	gchar *result = NULL, *p;
	size_t len;

	va_start (vp, format);
	len = g_printf_string_upper_bound (format, vp);
	va_end (vp);
	va_start (vp, format);
	len += sizeof ("65535 ") + sizeof (CRLF) - 1;
	result = rspamd_mempool_alloc (pool, len);
	p = result + rspamd_snprintf (result, len, "%d ", error_code);
	p = rspamd_vsnprintf (p, len - (p - result), format, vp);
	*p++ = CR; *p++ = LF; *p = '\0';
	va_end (vp);

	return result;
}
Пример #22
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;
}
Пример #23
0
static bool
rspamd_include_map_handler (const guchar *data, gsize len,
		const ucl_object_t *args, void * ud)
{
	struct rspamd_config *cfg = (struct rspamd_config *)ud;
	struct rspamd_ucl_map_cbdata *cbdata, **pcbdata;
	gchar *map_line;

	map_line = rspamd_mempool_alloc (cfg->cfg_pool, len + 1);
	rspamd_strlcpy (map_line, data, len + 1);

	cbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata));
	pcbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata *));
	cbdata->buf = NULL;
	cbdata->cfg = cfg;
	*pcbdata = cbdata;

	return rspamd_map_add (cfg,
			   map_line,
			   "ucl include",
			   rspamd_ucl_read_cb,
			   rspamd_ucl_fin_cb,
			   (void **)pcbdata);
}
Пример #24
0
gboolean
smtp_upstream_read_socket (rspamd_ftok_t * in, void *arg)
{
	struct smtp_session *session = arg;
	gchar outbuf[BUFSIZ];
	gint r;

	msg_debug ("in: %T, state: %d", in, session->upstream_state);
	switch (session->upstream_state) {
	case SMTP_STATE_GREETING:
		r = check_smtp_ustream_reply (in, '2');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else if (r == 1) {
			if (session->ctx->use_xclient) {
				r = rspamd_snprintf (outbuf,
						sizeof (outbuf),
						"XCLIENT NAME=%s ADDR=%s" CRLF,
						session->resolved ? session->hostname : "[UNDEFINED]",
						inet_ntoa (session->client_addr));
				session->upstream_state = SMTP_STATE_HELO;
				return rspamd_dispatcher_write (session->upstream_dispatcher,
						   outbuf,
						   r,
						   FALSE,
						   FALSE);
			}
			else {
				session->upstream_state = SMTP_STATE_FROM;
				if (session->helo) {
					r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s %s" CRLF,
							session->esmtp ? "EHLO" : "HELO",
							session->helo);
				}
				else {
					return smtp_upstream_read_socket (in, arg);
				}
				return rspamd_dispatcher_write (session->upstream_dispatcher,
						   outbuf,
						   r,
						   FALSE,
						   FALSE);
			}
		}
		break;
	case SMTP_STATE_HELO:
		r = check_smtp_ustream_reply (in, '2');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else if (r == 1) {
			session->upstream_state = SMTP_STATE_FROM;
			if (session->helo) {
				r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s %s" CRLF,
						session->esmtp ? "EHLO" : "HELO",
						session->helo);
			}
			else {
				return smtp_upstream_read_socket (in, arg);
			}
			return rspamd_dispatcher_write (session->upstream_dispatcher,
					   outbuf,
					   r,
					   FALSE,
					   FALSE);
		}
		break;
	case SMTP_STATE_FROM:
		r = check_smtp_ustream_reply (in, '2');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else if (r == 1) {
			r = rspamd_snprintf (outbuf, sizeof (outbuf), "MAIL FROM: ");
			r +=
				smtp_upstream_write_list (session->from,
					outbuf + r,
					sizeof (outbuf) - r);
			session->upstream_state = SMTP_STATE_RCPT;
			return rspamd_dispatcher_write (session->upstream_dispatcher,
					   outbuf,
					   r,
					   FALSE,
					   FALSE);
		}
		break;
	case SMTP_STATE_RCPT:
		r = check_smtp_ustream_reply (in, '2');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else if (r == 1) {
			r = rspamd_snprintf (outbuf, sizeof (outbuf), "RCPT TO: ");
			session->cur_rcpt = g_list_first (session->rcpt);
			r += smtp_upstream_write_list (session->cur_rcpt->data,
					outbuf + r,
					sizeof (outbuf) - r);
			session->cur_rcpt = g_list_next (session->cur_rcpt);
			session->upstream_state = SMTP_STATE_BEFORE_DATA;
			return rspamd_dispatcher_write (session->upstream_dispatcher,
					   outbuf,
					   r,
					   FALSE,
					   FALSE);
		}
		break;
	case SMTP_STATE_BEFORE_DATA:
		r = check_smtp_ustream_reply (in, '2');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			if (session->cur_rcpt) {
				session->rcpt = g_list_delete_link (session->rcpt,
						session->cur_rcpt);
			}
			else {
				session->rcpt =
					g_list_delete_link (session->rcpt, session->rcpt);
			}
			session->errors++;
			session->state = SMTP_STATE_RCPT;
			return TRUE;
		}
		else if (r == 1) {
			if (session->cur_rcpt != NULL) {
				r = rspamd_snprintf (outbuf, sizeof (outbuf), "RCPT TO: ");
				r += smtp_upstream_write_list (session->cur_rcpt,
						outbuf + r,
						sizeof (outbuf) - r);
				session->cur_rcpt = g_list_next (session->cur_rcpt);
				if (!rspamd_dispatcher_write (session->upstream_dispatcher,
					outbuf, r, FALSE, FALSE)) {
					goto err;
				}
			}
			else {
				session->upstream_state = SMTP_STATE_DATA;
				rspamd_dispatcher_pause (session->upstream_dispatcher);
			}
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* Write to client */
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			if (session->state == SMTP_STATE_WAIT_UPSTREAM) {
				rspamd_dispatcher_restore (session->dispatcher);
				session->state = SMTP_STATE_RCPT;
			}
		}
		break;
	case SMTP_STATE_DATA:
		r = check_smtp_ustream_reply (in, '3');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				0, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else if (r == 1) {
			if (!make_smtp_tempfile (session)) {
				session->error = SMTP_ERROR_FILE;
				session->state = SMTP_STATE_CRITICAL_ERROR;
				rspamd_dispatcher_restore (session->dispatcher);
				if (!rspamd_dispatcher_write (session->dispatcher,
					session->error, 0, FALSE, TRUE)) {
					goto err;
				}
				rspamd_session_destroy (session->s);
				return FALSE;
			}
			session->state = SMTP_STATE_AFTER_DATA;
			session->error = SMTP_ERROR_DATA_OK;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				0, FALSE, TRUE)) {
				goto err;
			}
			rspamd_dispatcher_pause (session->upstream_dispatcher);
			rspamd_set_dispatcher_policy (session->dispatcher, BUFFER_LINE, 0);
			session->dispatcher->strip_eol = FALSE;
			return TRUE;
		}
		break;
	case SMTP_STATE_AFTER_DATA:
		session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
		rspamd_strlcpy (session->error, in->begin, in->len + 1);
		session->state = SMTP_STATE_DATA;
		rspamd_dispatcher_restore (session->dispatcher);
		if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0,
			FALSE, TRUE)) {
			goto err;
		}
		if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) -
			1, FALSE, TRUE)) {
			goto err;
		}
		if (!rspamd_dispatcher_write (session->upstream_dispatcher, "QUIT" CRLF,
			sizeof ("QUIT" CRLF) - 1, FALSE, TRUE)) {
			goto err;
		}
		session->upstream_state = SMTP_STATE_END;
		return TRUE;
		break;
	case SMTP_STATE_END:
		r = check_smtp_ustream_reply (in, '5');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				0, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else {
			rspamd_session_remove_event (session->s,
				(event_finalizer_t)smtp_upstream_finalize_connection,
				session);
		}
		return FALSE;
		break;
	default:
		msg_err ("got upstream reply at unexpected state: %d, reply: %T",
			session->upstream_state,
			in);
		session->state = SMTP_STATE_CRITICAL_ERROR;
		rspamd_dispatcher_restore (session->dispatcher);
		if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0,
			FALSE, TRUE)) {
			goto err;
		}
		if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) -
			1, FALSE, TRUE)) {
			goto err;
		}
		rspamd_session_destroy (session->s);
		return FALSE;
	}

	return TRUE;
err:
	msg_warn ("write error occured");
	return FALSE;
}
Пример #25
0
/**
 * FSM for parsing lists
 */
gchar *
abstract_parse_kv_list (rspamd_mempool_t * pool,
                        gchar * chunk,
                        gint len,
                        struct map_cb_data *data,
                        insert_func func)
{
    gchar *c, *p, *key = NULL, *value = NULL, *end;

    p = chunk;
    c = p;
    end = p + len;

    while (p < end) {
        switch (data->state) {
        case 0:
            /* read key */
            /* Check here comments, eol and end of buffer */
            if (*p == '#') {
                if (key != NULL && p - c  >= 0) {
                    value = rspamd_mempool_alloc (pool, p - c + 1);
                    memcpy (value, c, p - c);
                    value[p - c] = '\0';
                    value = g_strstrip (value);
                    func (data->cur_data, key, value);
                    msg_debug_pool ("insert kv pair: %s -> %s", key, value);
                }
                data->state = 99;
            }
            else if (*p == '\r' || *p == '\n') {
                if (key != NULL && p - c >= 0) {
                    value = rspamd_mempool_alloc (pool, p - c + 1);
                    memcpy (value, c, p - c);
                    value[p - c] = '\0';

                    value = g_strstrip (value);
                    func (data->cur_data, key, value);
                    msg_debug_pool ("insert kv pair: %s -> %s", key, value);
                }
                else if (key == NULL && p - c > 0) {
                    /* Key only line */
                    key = rspamd_mempool_alloc (pool, p - c + 1);
                    memcpy (key, c, p - c);
                    key[p - c] = '\0';
                    value = rspamd_mempool_alloc (pool, 1);
                    *value = '\0';
                    func (data->cur_data, key, value);
                    msg_debug_pool ("insert kv pair: %s -> %s", key, value);
                }
                data->state = 100;
                key = NULL;
            }
            else if (g_ascii_isspace (*p)) {
                if (p - c > 0) {
                    key = rspamd_mempool_alloc (pool, p - c + 1);
                    memcpy (key, c, p - c);
                    key[p - c] = '\0';
                    data->state = 2;
                }
                else {
                    key = NULL;
                }
            }
            else {
                p++;
            }
            break;
        case 2:
            /* Skip spaces before value */
            if (!g_ascii_isspace (*p)) {
                c = p;
                data->state = 0;
            }
            else {
                p++;
            }
            break;
        case 99:
            /* SKIP_COMMENT */
            /* Skip comment till end of line */
            if (*p == '\r' || *p == '\n') {
                while ((*p == '\r' || *p == '\n') && p < end) {
                    p++;
                }
                c = p;
                key = NULL;
                data->state = 0;
            }
            else {
                p++;
            }
            break;
        case 100:
            /* Skip \r\n and whitespaces */
            if (*p == '\r' || *p == '\n' || g_ascii_isspace (*p)) {
                p++;
            }
            else {
                c = p;
                key = NULL;
                data->state = 0;
            }
            break;
        }
    }

    return c;
}
Пример #26
0
gboolean
write_smtp_reply (struct smtp_session *session)
{
	gchar logbuf[1024], *new_subject;
	const gchar *old_subject;
	struct smtp_metric_callback_data cd;
	GMimeStream *stream;
	gint old_fd, sublen;

	/* Check metrics */
	cd.session = session;
	cd.action = METRIC_ACTION_NOACTION;
	cd.res = NULL;
	cd.log_buf = logbuf;
	cd.log_offset = rspamd_snprintf (logbuf,
			sizeof (logbuf),
			"id: <%s>, qid: <%s>, ",
			session->task->message_id,
			session->task->queue_id);
	cd.log_size = sizeof (logbuf);
	if (session->task->user) {
		cd.log_offset += rspamd_snprintf (logbuf + cd.log_offset,
				sizeof (logbuf) - cd.log_offset,
				"user: %s, ",
				session->task->user);
	}

	g_hash_table_foreach (session->task->results, smtp_metric_callback, &cd);

	msg_info ("%s", logbuf);

	if (cd.action <= METRIC_ACTION_REJECT) {
		if (!rspamd_dispatcher_write (session->dispatcher,
			session->ctx->reject_message, 0, FALSE, TRUE)) {
			return FALSE;
		}
		if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) -
			1, FALSE, TRUE)) {
			return FALSE;
		}
		destroy_session (session->s);
		return FALSE;
	}
	else if (cd.action <= METRIC_ACTION_ADD_HEADER || cd.action <=
		METRIC_ACTION_REWRITE_SUBJECT) {
		old_fd = session->temp_fd;
		if (!make_smtp_tempfile (session)) {
			session->error = SMTP_ERROR_FILE;
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				0, FALSE, TRUE)) {
				goto err;
			}
			destroy_session (session->s);
			return FALSE;
		}

		if (cd.action <= METRIC_ACTION_REWRITE_SUBJECT) {
			/* XXX: add this action */
			old_subject = g_mime_message_get_subject (session->task->message);
			if (old_subject != NULL) {
				sublen = strlen (old_subject) + sizeof (SPAM_SUBJECT);
				new_subject = rspamd_mempool_alloc (session->pool, sublen);
				rspamd_snprintf (new_subject,
					sublen,
					"%s%s",
					SPAM_SUBJECT,
					old_subject);
			}
			else {
				new_subject = SPAM_SUBJECT;
			}
			g_mime_message_set_subject (session->task->message, new_subject);
		}
		else if (cd.action <= METRIC_ACTION_ADD_HEADER) {
#ifndef GMIME24
			g_mime_message_add_header (session->task->message, "X-Spam",
				"true");
#else
			g_mime_object_append_header (GMIME_OBJECT (
					session->task->message), "X-Spam", "true");
#endif
		}
		stream = g_mime_stream_fs_new (session->temp_fd);
		g_mime_stream_fs_set_owner (GMIME_STREAM_FS (stream), FALSE);
		close (old_fd);

		if (g_mime_object_write_to_stream (GMIME_OBJECT (session->task->message),
			stream) == -1) {
			msg_err ("cannot write MIME object to stream: %s",
				strerror (errno));
			session->error = SMTP_ERROR_FILE;
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				0, FALSE, TRUE)) {
				goto err;
			}
			destroy_session (session->s);
			return FALSE;
		}
		g_object_unref (stream);
	}
	/* XXX: Add other actions */
	return smtp_send_upstream_message (session);
err:
	session->error = SMTP_ERROR_FILE;
	session->state = SMTP_STATE_CRITICAL_ERROR;
	if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE,
		TRUE)) {
		return FALSE;
	}
	destroy_session (session->s);
	return FALSE;
}
Пример #27
0
static gint
lua_expr_create (lua_State *L)
{
    struct lua_expression *e, **pe;
    const char *line;
    gsize len;
    GError *err = NULL;
    rspamd_mempool_t *pool;

    /* Check sanity of the arguments */
    if (lua_type (L, 1) != LUA_TSTRING || lua_type (L, 2) != LUA_TTABLE ||
            rspamd_lua_check_mempool (L, 3) == NULL) {
        msg_info ("bad arguments to lua_expr_create");
        lua_pushnil (L);
        lua_pushstring (L, "bad arguments");
    }
    else {
        line = lua_tolstring (L, 1, &len);
        pool = rspamd_lua_check_mempool (L, 3);

        /* Check callbacks */
        lua_pushvalue (L, 2);
        lua_pushnumber (L, 1);
        lua_gettable (L, -2);

        if (lua_type (L, -1) != LUA_TFUNCTION) {
            lua_pop (L, 2);
            lua_pushnil (L);
            lua_pushstring (L, "bad parse callback");

            return 2;
        }

        lua_pop (L, 1);

        lua_pushnumber (L, 2);
        lua_gettable (L, -2);

        if (lua_type (L, -1) != LUA_TFUNCTION) {
            lua_pop (L, 2);
            lua_pushnil (L);
            lua_pushstring (L, "bad process callback");

            return 2;
        }

        lua_pop (L, 1);

        /* Table is still on the top of stack */

        e = rspamd_mempool_alloc (pool, sizeof (*e));
        e->L = L;
        e->pool = pool;

        lua_pushnumber (L, 1);
        lua_gettable (L, -2);
        e->parse_idx = luaL_ref (L, LUA_REGISTRYINDEX);

        lua_pushnumber (L, 2);
        lua_gettable (L, -2);
        e->process_idx = luaL_ref (L, LUA_REGISTRYINDEX);
        lua_pop (L, 1); /* Table */

        if (!rspamd_parse_expression (line, len, &lua_atom_subr, e, pool, &err,
                                      &e->expr)) {
            lua_pushnil (L);
            lua_pushstring (L, err->message);
            g_error_free (err);

            return 2;
        }

        pe = lua_newuserdata (L, sizeof (struct lua_expression *));
        rspamd_lua_setclass (L, "rspamd{expr}", -1);
        *pe = e;
        lua_pushnil (L);
    }

    return 2;
}
Пример #28
0
gboolean
parse_smtp_command (struct smtp_session *session,
	rspamd_ftok_t *line,
	struct smtp_command **cmd)
{
	enum {
		SMTP_PARSE_START = 0,
		SMTP_PARSE_SPACES,
		SMTP_PARSE_ARGUMENT,
		SMTP_PARSE_DONE
	}                              state;
	const gchar *p, *c;
	gchar ch, cmd_buf[4];
	guint i;
	rspamd_ftok_t *arg = NULL;
	struct smtp_command *pcmd;

	if (line->len == 0) {
		return FALSE;
	}

	state = SMTP_PARSE_START;
	c = line->begin;
	p = c;
	*cmd = rspamd_mempool_alloc0 (session->pool, sizeof (struct smtp_command));
	pcmd = *cmd;

	for (i = 0; i < line->len; i++, p++) {
		ch = *p;
		switch (state) {
		case SMTP_PARSE_START:
			if (ch == ' ' || ch == ':' || ch == CR || ch == LF || i ==
				line->len - 1) {
				if (i == line->len - 1) {
					p++;
				}
				if (p - c == 4) {
					cmd_buf[0] = g_ascii_toupper (c[0]);
					cmd_buf[1] = g_ascii_toupper (c[1]);
					cmd_buf[2] = g_ascii_toupper (c[2]);
					cmd_buf[3] = g_ascii_toupper (c[3]);

					if (memcmp (cmd_buf, "HELO", 4) == 0) {
						pcmd->command = SMTP_COMMAND_HELO;
					}
					else if (memcmp (cmd_buf, "EHLO", 4) == 0) {
						pcmd->command = SMTP_COMMAND_EHLO;
					}
					else if (memcmp (cmd_buf, "MAIL", 4) == 0) {
						pcmd->command = SMTP_COMMAND_MAIL;
					}
					else if (memcmp (cmd_buf, "RCPT", 4) == 0) {
						pcmd->command = SMTP_COMMAND_RCPT;
					}
					else if (memcmp (cmd_buf, "DATA", 4) == 0) {
						pcmd->command = SMTP_COMMAND_DATA;
					}
					else if (memcmp (cmd_buf, "QUIT", 4) == 0) {
						pcmd->command = SMTP_COMMAND_QUIT;
					}
					else if (memcmp (cmd_buf, "NOOP", 4) == 0) {
						pcmd->command = SMTP_COMMAND_NOOP;
					}
					else if (memcmp (cmd_buf, "EXPN", 4) == 0) {
						pcmd->command = SMTP_COMMAND_EXPN;
					}
					else if (memcmp (cmd_buf, "RSET", 4) == 0) {
						pcmd->command = SMTP_COMMAND_RSET;
					}
					else if (memcmp (cmd_buf, "HELP", 4) == 0) {
						pcmd->command = SMTP_COMMAND_HELP;
					}
					else if (memcmp (cmd_buf, "VRFY", 4) == 0) {
						pcmd->command = SMTP_COMMAND_VRFY;
					}
					else {
						msg_info ("invalid command: %*s", 4, cmd_buf);
						return FALSE;
					}
				}
				else {
					/* Invalid command */
					msg_info ("invalid command: %*s", 4, c);
					return FALSE;
				}
				/* Now check what we have */
				if (ch == ' ' || ch == ':') {
					state = SMTP_PARSE_SPACES;
				}
				else if (ch == CR) {
					state = SMTP_PARSE_DONE;
				}
				else if (ch == LF) {
					return TRUE;
				}
			}
			else if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
				msg_info ("invalid letter code in SMTP command: %d", (gint)ch);
				return FALSE;
			}
			break;
		case SMTP_PARSE_SPACES:
			if (ch == CR) {
				state = SMTP_PARSE_DONE;
			}
			else if (ch == LF) {
				goto end;
			}
			else if (ch != ' ' && ch != ':') {
				state = SMTP_PARSE_ARGUMENT;
				arg = rspamd_mempool_alloc (session->pool, sizeof (rspamd_fstring_t));
				c = p;
			}
			break;
		case SMTP_PARSE_ARGUMENT:
			if (ch == ' ' || ch == ':' || ch == CR || ch == LF || i ==
				line->len - 1) {
				if (i == line->len - 1 && (ch != ' ' && ch != CR && ch != LF)) {
					p++;
				}
				arg->len = p - c;
				arg->begin = rspamd_mempool_alloc (session->pool, arg->len);
				memcpy ((gchar *)arg->begin, c, arg->len);
				pcmd->args = g_list_prepend (pcmd->args, arg);

				if (ch == ' ' || ch == ':') {
					state = SMTP_PARSE_SPACES;
				}
				else if (ch == CR) {
					state = SMTP_PARSE_DONE;
				}
				else {
					goto end;
				}
			}
			break;
		case SMTP_PARSE_DONE:
			if (ch == LF) {
				goto end;
			}
			msg_info ("CR without LF in SMTP command");
			return FALSE;
		}
	}

end:
	if (pcmd->args) {
		pcmd->args = g_list_reverse (pcmd->args);
		rspamd_mempool_add_destructor (session->pool,
			(rspamd_mempool_destruct_t)g_list_free,
			pcmd->args);
	}
	return TRUE;
}
Пример #29
0
static void
insert_metric_result (struct rspamd_task *task,
	struct metric *metric,
	const gchar *symbol,
	double flag,
	GList * opts,
	gboolean single)
{
	struct metric_result *metric_res;
	struct symbol *s;
	gdouble w, *gr_score = NULL;
	struct rspamd_symbol_def *sdef;
	struct rspamd_symbols_group *gr = NULL;
	const ucl_object_t *mobj, *sobj;

	metric_res = rspamd_create_metric_result (task, metric->name);

	sdef = g_hash_table_lookup (metric->symbols, symbol);
	if (sdef == NULL) {
		w = 0.0;
	}
	else {
		w = (*sdef->weight_ptr) * flag;
		gr = sdef->gr;

		if (gr != NULL) {
			gr_score = g_hash_table_lookup (metric_res->sym_groups, gr);

			if (gr_score == NULL) {
				gr_score = rspamd_mempool_alloc (task->task_pool, sizeof (gdouble));
				*gr_score = 0;
				g_hash_table_insert (metric_res->sym_groups, gr, gr_score);
			}
		}
	}

	if (task->settings) {
		mobj = ucl_object_find_key (task->settings, metric->name);
		if (mobj) {
			gdouble corr;

			sobj = ucl_object_find_key (mobj, symbol);
			if (sobj != NULL && ucl_object_todouble_safe (sobj, &corr)) {
				msg_debug ("settings: changed weight of symbol %s from %.2f to %.2f",
						symbol, w, corr);
				w = corr * flag;
			}
		}
	}

	/* XXX: does not take grow factor into account */
	if (gr != NULL && gr_score != NULL && gr->max_score > 0.0) {
		if (*gr_score >= gr->max_score) {
			msg_info ("maximum group score %.2f for group %s has been reached,"
					" ignoring symbol %s with weight %.2f", gr->max_score,
					gr->name, symbol, w);
			return;
		}
		else if (*gr_score + w > gr->max_score) {
			w = gr->max_score - *gr_score;
		}

		*gr_score += w;
	}

	/* Add metric score */
	if ((s = g_hash_table_lookup (metric_res->symbols, symbol)) != NULL) {
		if (sdef && sdef->one_shot) {
			/*
			 * For one shot symbols we do not need to add them again, so
			 * we just force single behaviour here
			 */
			single = TRUE;
		}
		if (s->options && opts && opts != s->options) {
			/* Append new options */
			s->options = g_list_concat (s->options, g_list_copy (opts));
			/*
			 * Note that there is no need to add new destructor of GList as elements of appended
			 * GList are used directly, so just free initial GList
			 */
		}
		else if (opts) {
			s->options = g_list_copy (opts);
			rspamd_mempool_add_destructor (task->task_pool,
				(rspamd_mempool_destruct_t) g_list_free, s->options);
		}
		if (!single) {
			/* Handle grow factor */
			if (metric_res->grow_factor && w > 0) {
				w *= metric_res->grow_factor;
				metric_res->grow_factor *= metric->grow_factor;
			}
			s->score += w;
			metric_res->score += w;
		}
		else {
			if (fabs (s->score) < fabs (w)) {
				/* Replace less weight with a bigger one */
				metric_res->score = metric_res->score - s->score + w;
				s->score = w;
			}
		}
	}
	else {
		s = rspamd_mempool_alloc (task->task_pool, sizeof (struct symbol));

		/* Handle grow factor */
		if (metric_res->grow_factor && w > 0) {
			w *= metric_res->grow_factor;
			metric_res->grow_factor *= metric->grow_factor;
		}
		else if (w > 0) {
			metric_res->grow_factor = metric->grow_factor;
		}

		s->score = w;
		s->name = symbol;
		s->def = sdef;
		metric_res->score += w;

		if (opts) {
			s->options = g_list_copy (opts);
			rspamd_mempool_add_destructor (task->task_pool,
				(rspamd_mempool_destruct_t) g_list_free, s->options);
		}
		else {
			s->options = NULL;
		}

		g_hash_table_insert (metric_res->symbols, (gpointer) symbol, s);
	}
	debug_task ("symbol %s, score %.2f, metric %s, factor: %f",
		symbol,
		s->score,
		metric->name,
		w);
}
Пример #30
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;
}