예제 #1
0
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);
	}
}
예제 #2
0
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);
	}
}
예제 #3
0
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);
	}
}