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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
/* 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); } } } }
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"); } }
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; } }
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; }
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; }
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); }
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; }
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; } }
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; }
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; }
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); }
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; }
/** * 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; }
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; }
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; }
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; }
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); }
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; }