static void dkim_symbol_callback (struct rspamd_task *task, void *unused) { GList *hlist; rspamd_dkim_context_t *ctx; rspamd_dkim_key_t *key; GError *err = NULL; struct raw_header *rh; struct dkim_check_result *res = NULL, *cur; /* First check if a message has its signature */ hlist = rspamd_message_get_header (task, DKIM_SIGNHEADER, FALSE); if (hlist != NULL) { /* Check whitelist */ msg_debug ("dkim signature found"); if (radix_find_compressed_addr (dkim_module_ctx->whitelist_ip, task->from_addr) == RADIX_NO_VALUE) { /* Parse signature */ msg_debug ("create dkim signature"); while (hlist != NULL) { rh = (struct raw_header *)hlist->data; if (res == NULL) { res = rspamd_mempool_alloc0 (task->task_pool, sizeof (*res)); res->prev = res; res->w = rspamd_session_get_watcher (task->s); cur = res; } else { cur = rspamd_mempool_alloc0 (task->task_pool, sizeof (*res)); } cur->first = res; cur->res = -1; cur->task = task; cur->mult_allow = 1.0; cur->mult_deny = 1.0; ctx = rspamd_create_dkim_context (rh->decoded, task->task_pool, dkim_module_ctx->time_jitter, &err); if (ctx == NULL) { if (err != NULL) { msg_info ("<%s> cannot parse DKIM context: %s", task->message_id, err->message); g_error_free (err); } else { msg_info ("<%s> cannot parse DKIM context: unknown error", task->message_id); } hlist = g_list_next (hlist); continue; } else { /* Get key */ cur->ctx = ctx; if (dkim_module_ctx->trusted_only && (dkim_module_ctx->dkim_domains == NULL || g_hash_table_lookup (dkim_module_ctx->dkim_domains, ctx->domain) == NULL)) { msg_debug ("skip dkim check for %s domain", ctx->domain); hlist = g_list_next (hlist); continue; } key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_hash, ctx->dns_key, task->tv.tv_sec); if (key != NULL) { debug_task ("found key for %s in cache", ctx->dns_key); cur->key = key; } else { debug_task ("request key for %s from DNS", ctx->dns_key); rspamd_get_dkim_key (ctx, task, dkim_module_key_handler, cur); } } if (res != cur) { DL_APPEND (res, cur); } hlist = g_list_next (hlist); } } } if (res != NULL) { rspamd_session_watcher_push (task->s); dkim_module_check (res); } }
static void dkim_symbol_callback (struct rspamd_task *task, void *unused) { GList *hlist; rspamd_dkim_context_t *ctx; rspamd_dkim_key_t *key; GError *err = NULL; struct raw_header *rh; struct dkim_check_result *res = NULL, *cur; guint checked = 0; /* First check if plugin should be enabled */ if (task->user != NULL || rspamd_inet_address_is_local (task->from_addr)) { msg_info_task ("skip DKIM checks for local networks and authorized users"); return; } /* Check whitelist */ if (radix_find_compressed_addr (dkim_module_ctx->whitelist_ip, task->from_addr) != RADIX_NO_VALUE) { msg_info_task ("skip DKIM checks for whitelisted address"); return; } /* Now check if a message has its signature */ hlist = rspamd_message_get_header (task, DKIM_SIGNHEADER, FALSE); if (hlist != NULL) { msg_debug_task ("dkim signature found"); while (hlist != NULL) { rh = (struct raw_header *)hlist->data; if (rh->decoded == NULL || rh->decoded[0] == '\0') { msg_info_task ("<%s> cannot load empty DKIM context", task->message_id); hlist = g_list_next (hlist); continue; } if (res == NULL) { res = rspamd_mempool_alloc0 (task->task_pool, sizeof (*res)); res->prev = res; res->w = rspamd_session_get_watcher (task->s); cur = res; } else { cur = rspamd_mempool_alloc0 (task->task_pool, sizeof (*res)); } cur->first = res; cur->res = -1; cur->task = task; cur->mult_allow = 1.0; cur->mult_deny = 1.0; ctx = rspamd_create_dkim_context (rh->decoded, task->task_pool, dkim_module_ctx->time_jitter, &err); if (ctx == NULL) { if (err != NULL) { msg_info_task ("<%s> cannot parse DKIM context: %e", task->message_id, err); g_error_free (err); err = NULL; } else { msg_info_task ("<%s> cannot parse DKIM context: " "unknown error", task->message_id); } hlist = g_list_next (hlist); continue; } else { /* Get key */ cur->ctx = ctx; if (dkim_module_ctx->trusted_only && (dkim_module_ctx->dkim_domains == NULL || g_hash_table_lookup (dkim_module_ctx->dkim_domains, rspamd_dkim_get_domain (ctx)) == NULL)) { msg_debug_task ("skip dkim check for %s domain", rspamd_dkim_get_domain (ctx)); hlist = g_list_next (hlist); continue; } key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_hash, rspamd_dkim_get_dns_key (ctx), task->tv.tv_sec); if (key != NULL) { cur->key = rspamd_dkim_key_ref (key); /* Release key when task is processed */ rspamd_mempool_add_destructor (task->task_pool, dkim_module_key_dtor, cur->key); } else { rspamd_get_dkim_key (ctx, task, dkim_module_key_handler, cur); } } if (res != cur) { DL_APPEND (res, cur); } if (dkim_module_ctx->skip_multi) { if (hlist->next) { msg_info_task ("message has multiple signatures but we" " check only one as 'skip_multi' is set"); } break; } checked ++; if (checked > dkim_module_ctx->max_sigs) { msg_info_task ("message has multiple signatures but we" " stopped after %d checked signatures as limit" " is reached", checked); break; } hlist = g_list_next (hlist); } } else { rspamd_task_insert_result (task, dkim_module_ctx->symbol_na, 1.0, NULL); } if (res != NULL) { rspamd_session_watcher_push (task->s); dkim_module_check (res); } }
/* * Calculates the specified regexp for the specified class if it's not calculated */ static guint rspamd_re_cache_exec_re (struct rspamd_task *task, struct rspamd_re_runtime *rt, rspamd_regexp_t *re, struct rspamd_re_class *re_class, gboolean is_strong) { guint ret = 0, i, re_id; GList *cur, *headerlist; GHashTableIter it; struct raw_header *rh; const gchar *in; gboolean raw = FALSE; struct mime_text_part *part; struct rspamd_url *url; struct rspamd_re_cache *cache = rt->cache; gpointer k, v; gsize len; msg_debug_re_cache ("get to the slow path for re type: %s: %s", rspamd_re_cache_type_to_string (re_class->type), rspamd_regexp_get_pattern (re)); re_id = rspamd_regexp_get_cache_id (re); switch (re_class->type) { case RSPAMD_RE_HEADER: case RSPAMD_RE_RAWHEADER: /* Get list of specified headers */ headerlist = rspamd_message_get_header (task, re_class->type_data, is_strong); if (headerlist) { cur = headerlist; while (cur) { rh = cur->data; if (re_class->type == RSPAMD_RE_RAWHEADER) { in = rh->value; raw = TRUE; } else { in = rh->decoded; /* Validate input */ if (!in || !g_utf8_validate (in, -1, NULL)) { cur = g_list_next (cur); continue; } } /* Match re */ if (in) { ret = rspamd_re_cache_process_regexp_data (rt, re, task->task_pool, in, strlen (in), raw); debug_task ("checking header %s regexp: %s -> %d", re_class->type_data, rspamd_regexp_get_pattern (re), ret); } cur = g_list_next (cur); } } break; case RSPAMD_RE_ALLHEADER: raw = TRUE; in = task->raw_headers_content.begin; len = task->raw_headers_content.len; ret = rspamd_re_cache_process_regexp_data (rt, re, task->task_pool, in, len, raw); debug_task ("checking allheader regexp: %s -> %d", rspamd_regexp_get_pattern (re), ret); break; case RSPAMD_RE_MIME: case RSPAMD_RE_RAWMIME: /* Iterate throught text parts */ for (i = 0; i < task->text_parts->len; i++) { part = g_ptr_array_index (task->text_parts, i); /* Skip empty parts */ if (IS_PART_EMPTY (part)) { continue; } /* Check raw flags */ if (!IS_PART_UTF (part)) { raw = TRUE; } /* Select data for regexp */ if (re_class->type == RSPAMD_RE_RAWMIME) { in = part->orig->data; len = part->orig->len; raw = TRUE; } else { in = part->content->data; len = part->content->len; } if (len > 0) { ret = rspamd_re_cache_process_regexp_data (rt, re, task->task_pool, in, len, raw); debug_task ("checking mime regexp: %s -> %d", rspamd_regexp_get_pattern (re), ret); } } break; case RSPAMD_RE_URL: g_hash_table_iter_init (&it, task->urls); while (g_hash_table_iter_next (&it, &k, &v)) { url = v; in = url->string; len = url->urllen; raw = FALSE; ret = rspamd_re_cache_process_regexp_data (rt, re, task->task_pool, in, len, raw); } g_hash_table_iter_init (&it, task->emails); while (g_hash_table_iter_next (&it, &k, &v)) { url = v; in = url->string; len = url->urllen; raw = FALSE; ret = rspamd_re_cache_process_regexp_data (rt, re, task->task_pool, in, len, raw); } debug_task ("checking url regexp: %s -> %d", rspamd_regexp_get_pattern (re), ret); break; case RSPAMD_RE_BODY: raw = TRUE; in = task->msg.begin; len = task->msg.len; ret = rspamd_re_cache_process_regexp_data (rt, re, task->task_pool, in, len, raw); debug_task ("checking rawbody regexp: %s -> %d", rspamd_regexp_get_pattern (re), ret); break; case RSPAMD_RE_MAX: msg_err_task ("regexp of class invalid has been called: %s", rspamd_regexp_get_pattern (re)); break; } #if WITH_HYPERSCAN if (!rt->cache->disable_hyperscan) { rspamd_re_cache_finish_class (rt, re_class); } #endif setbit (rt->checked, re_id); return rt->results[re_id]; }