static void dkim_sign_callback (struct rspamd_task *task, void *unused) { lua_State *L; struct rspamd_task **ptask; gboolean sign = FALSE; gint err_idx; GString *tb, *hdr; GError *err = NULL; const gchar *selector = NULL, *domain = NULL, *key = NULL; rspamd_dkim_sign_context_t *ctx; rspamd_dkim_sign_key_t *dkim_key; if (dkim_module_ctx->sign_condition_ref != -1) { sign = FALSE; L = task->cfg->lua_state; lua_pushcfunction (L, &rspamd_lua_traceback); err_idx = lua_gettop (L); lua_rawgeti (L, LUA_REGISTRYINDEX, dkim_module_ctx->sign_condition_ref); ptask = lua_newuserdata (L, sizeof (struct rspamd_task *)); *ptask = task; rspamd_lua_setclass (L, "rspamd{task}", -1); if (lua_pcall (L, 1, 1, err_idx) != 0) { tb = lua_touserdata (L, -1); msg_err_task ("call to user extraction script failed: %v", tb); g_string_free (tb, TRUE); } else { if (lua_istable (L, -1)) { /* * Get the following elements: * - selector * - domain * - key */ if (!rspamd_lua_parse_table_arguments (L, -1, &err, "*key=S;*domain=S;*selector=S", &key, &domain, &selector)) { msg_err_task ("invalid return value from sign condition: %e", err); g_error_free (err); return; } dkim_key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_sign_hash, key, time (NULL)); if (dkim_key == NULL) { dkim_key = rspamd_dkim_sign_key_load (key, &err); if (dkim_key == NULL) { msg_err_task ("cannot load dkim key %s: %e", key, err); g_error_free (err); return; } rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash, g_strdup (key), dkim_key, time (NULL), 0); } ctx = rspamd_create_dkim_sign_context (task, dkim_key, DKIM_CANON_RELAXED, DKIM_CANON_RELAXED, dkim_module_ctx->sign_headers, &err); if (ctx == NULL) { msg_err_task ("cannot create sign context: %e", key, err); g_error_free (err); return; } hdr = rspamd_dkim_sign (task, selector, domain, 0, 0, ctx); if (hdr) { rspamd_mempool_set_variable (task->task_pool, "dkim-signature", hdr, rspamd_gstring_free_hard); } sign = TRUE; } else { sign = FALSE; } } /* Result + error function */ lua_settop (L, 0); if (!sign) { msg_debug_task ("skip signing as dkim condition callback returned" " false"); return; } } }
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); } }
gint lua_dkim_sign_handler (lua_State *L) { struct rspamd_task *task = lua_check_task (L, 1); luaL_argcheck (L, lua_type (L, 2) == LUA_TTABLE, 2, "'table' expected"); GError *err = NULL; GString *hdr; const gchar *selector = NULL, *domain = NULL, *key = NULL; rspamd_dkim_sign_context_t *ctx; rspamd_dkim_sign_key_t *dkim_key; /* * Get the following elements: * - selector * - domain * - key */ if (!rspamd_lua_parse_table_arguments (L, 2, &err, "*key=S;*domain=S;*selector=S", &key, &domain, &selector)) { msg_err_task ("invalid return value from sign condition: %e", err); g_error_free (err); lua_pushboolean (L, FALSE); return 1; } if (dkim_module_ctx->dkim_sign_hash == NULL) { dkim_module_ctx->dkim_sign_hash = rspamd_lru_hash_new ( 128, g_free, /* Keys are just C-strings */ (GDestroyNotify)rspamd_dkim_sign_key_unref); } dkim_key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_sign_hash, key, time (NULL)); if (dkim_key == NULL) { dkim_key = rspamd_dkim_sign_key_load (key, &err); if (dkim_key == NULL) { msg_err_task ("cannot load dkim key %s: %e", key, err); g_error_free (err); lua_pushboolean (L, FALSE); return 1; } rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash, g_strdup (key), dkim_key, time (NULL), 0); } ctx = rspamd_create_dkim_sign_context (task, dkim_key, DKIM_CANON_RELAXED, DKIM_CANON_RELAXED, dkim_module_ctx->sign_headers, &err); if (ctx == NULL) { msg_err_task ("cannot create sign context: %e", err); g_error_free (err); lua_pushboolean (L, FALSE); return 1; } hdr = rspamd_dkim_sign (task, selector, domain, 0, 0, ctx); if (hdr) { rspamd_mempool_set_variable (task->task_pool, "dkim-signature", hdr, rspamd_gstring_free_hard); lua_pushboolean (L, TRUE); return 1; } lua_pushboolean (L, FALSE); return 1; }
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; /* First check if a message has its signature */ hlist = 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"); /* * Check only last signature as there is no way to check embeded signatures after * resend or something like this */ if (dkim_module_ctx->skip_multi) { if (hlist->next != NULL) { msg_info ( "<%s> skip dkim check as it has several dkim signatures", task->message_id); return; } } hlist = g_list_last (hlist); rh = (struct raw_header *)hlist->data; ctx = rspamd_create_dkim_context (rh->decoded, task->task_pool, dkim_module_ctx->time_jitter, &err); if (ctx == NULL) { msg_info ("cannot parse DKIM context: %s", err->message); g_error_free (err); } else { /* Get key */ 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); return; } 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); dkim_module_check (task, ctx, key); } else { debug_task ("request key for %s from DNS", ctx->dns_key); task->dns_requests++; rspamd_get_dkim_key (ctx, task->resolver, task->s, dkim_module_key_handler, task); } } } } }