static void dkim_module_check (struct dkim_check_result *res) { gboolean all_done = TRUE, got_allow = FALSE; const gchar *strict_value; struct dkim_check_result *first, *cur, *sel = NULL; first = res->first; DL_FOREACH (first, cur) { if (cur->ctx == NULL) { continue; } if (cur->key != NULL && cur->res == -1) { cur->res = rspamd_dkim_check (cur->ctx, cur->key, cur->task); if (dkim_module_ctx->dkim_domains != NULL) { /* Perform strict check */ if ((strict_value = g_hash_table_lookup (dkim_module_ctx->dkim_domains, rspamd_dkim_get_domain (cur->ctx))) != NULL) { if (!dkim_module_parse_strict (strict_value, &cur->mult_allow, &cur->mult_deny)) { cur->mult_allow = dkim_module_ctx->strict_multiplier; cur->mult_deny = dkim_module_ctx->strict_multiplier; } } } } if (cur->res == -1 || cur->key == NULL) { /* Still need a key */ all_done = FALSE; } } if (all_done) { DL_FOREACH (first, cur) { if (cur->ctx == NULL) { continue; } if (cur->res == DKIM_CONTINUE) { rspamd_task_insert_result (cur->task, dkim_module_ctx->symbol_allow, cur->mult_allow * 1.0, g_list_prepend (NULL, rspamd_mempool_strdup (cur->task->task_pool, rspamd_dkim_get_domain (cur->ctx)))); got_allow = TRUE; sel = NULL; } else if (!got_allow) { if (sel == NULL) { sel = cur; } else if (sel->res == DKIM_TRYAGAIN && cur->res != DKIM_TRYAGAIN) { sel = cur; } } } } if (sel != NULL) { if (sel->res == DKIM_REJECT) { rspamd_task_insert_result (sel->task, dkim_module_ctx->symbol_reject, sel->mult_deny * 1.0, g_list_prepend (NULL, rspamd_mempool_strdup (sel->task->task_pool, rspamd_dkim_get_domain (sel->ctx)))); } else { rspamd_task_insert_result (sel->task, dkim_module_ctx->symbol_tempfail, 1.0, g_list_prepend (NULL, rspamd_mempool_strdup (sel->task->task_pool, rspamd_dkim_get_domain (sel->ctx)))); } } if (all_done) { rspamd_session_watcher_pop (res->task->s, res->w); } }
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); } }
static void dkim_module_check (struct dkim_check_result *res) { gboolean all_done = TRUE; const gchar *strict_value; struct dkim_check_result *first, *cur = NULL; first = res->first; DL_FOREACH (first, cur) { if (cur->ctx == NULL) { continue; } if (cur->key != NULL && cur->res == -1) { cur->res = rspamd_dkim_check (cur->ctx, cur->key, cur->task); if (dkim_module_ctx->dkim_domains != NULL) { /* Perform strict check */ if ((strict_value = g_hash_table_lookup (dkim_module_ctx->dkim_domains, rspamd_dkim_get_domain (cur->ctx))) != NULL) { if (!dkim_module_parse_strict (strict_value, &cur->mult_allow, &cur->mult_deny)) { cur->mult_allow = dkim_module_ctx->strict_multiplier; cur->mult_deny = dkim_module_ctx->strict_multiplier; } } } } } DL_FOREACH (first, cur) { if (cur->ctx == NULL) { continue; } if (cur->res == -1) { /* Still need a key */ all_done = FALSE; } } if (all_done) { DL_FOREACH (first, cur) { const gchar *symbol = NULL; int symbol_weight = 1; if (cur->ctx == NULL) { continue; } if (cur->res == DKIM_REJECT) { symbol = dkim_module_ctx->symbol_reject; symbol_weight = cur->mult_deny * 1.0; } else if (cur->res == DKIM_CONTINUE) { symbol = dkim_module_ctx->symbol_allow; symbol_weight = cur->mult_allow * 1.0; } else if (cur->res == DKIM_PERM_ERROR) { symbol = dkim_module_ctx->symbol_permfail; } else if (cur->res == DKIM_TRYAGAIN) { symbol = dkim_module_ctx->symbol_tempfail; } if (symbol != NULL) { rspamd_task_insert_result (cur->task, symbol, symbol_weight, rspamd_dkim_get_domain (cur->ctx)); } } rspamd_session_watcher_pop (res->task->s, res->w); } }