diff options
Diffstat (limited to 'src/settings.c')
-rw-r--r-- | src/settings.c | 657 |
1 files changed, 0 insertions, 657 deletions
diff --git a/src/settings.c b/src/settings.c deleted file mode 100644 index c3292c8ab..000000000 --- a/src/settings.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * Copyright (c) 2009-2012, Vsevolod Stakhov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "cfg_file.h" -#include "map.h" -#include "main.h" -#include "settings.h" -#include "filter.h" -#include "json/jansson.h" - -struct json_buf { - GHashTable *table; - gchar *buf; - gchar *pos; - size_t buflen; -}; - -static void -settings_actions_free (gpointer data) -{ - GList *cur = data; - - while (cur) { - g_free (cur->data); - cur = g_list_next (cur); - } - - g_list_free ((GList *)data); -} - -static void -settings_free (gpointer data) -{ - struct rspamd_settings *s = data; - - if (s->statfile_alias) { - g_free (s->statfile_alias); - } - if (s->factors) { - g_hash_table_destroy (s->factors); - } - if (s->metric_scores) { - g_hash_table_destroy (s->metric_scores); - } - if (s->reject_scores) { - g_hash_table_destroy (s->reject_scores); - } - if (s->whitelist) { - g_hash_table_destroy (s->whitelist); - } - if (s->blacklist) { - g_hash_table_destroy (s->blacklist); - } - if (s->metric_actions) { - g_hash_table_destroy (s->metric_actions); - } - - g_slice_free1 (sizeof (struct rspamd_settings), s); -} - -static struct rspamd_settings * -settings_ref (struct rspamd_settings *s) -{ - if (s == NULL) { - s = g_slice_alloc (sizeof (struct rspamd_settings)); - s->metric_scores = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal, g_free, g_free); - s->reject_scores = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal, g_free, g_free); - s->metric_actions = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal, g_free, settings_actions_free); - s->factors = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal, g_free, g_free); - s->whitelist = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal, g_free, g_free); - s->blacklist = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal, g_free, g_free); - s->statfile_alias = NULL; - s->want_spam = FALSE; - s->ref_count = 1; - } - else { - s->ref_count ++; - } - - return s; -} - -static void -settings_unref (struct rspamd_settings *s) -{ - if (s != NULL) { - s->ref_count --; - if (s->ref_count <= 0) { - settings_free (s); - } - } -} - - -gchar * -json_read_cb (rspamd_mempool_t * pool, gchar * chunk, gint len, struct map_cb_data *data) -{ - struct json_buf *jb; - size_t free, off; - - if (data->cur_data == NULL) { - jb = g_malloc (sizeof (struct json_buf)); - jb->table = g_hash_table_ref (((struct json_buf *)data->prev_data)->table); - jb->buf = NULL; - jb->pos = NULL; - data->cur_data = jb; - } - else { - jb = data->cur_data; - } - - if (jb->buf == NULL) { - /* Allocate memory for buffer */ - jb->buflen = len * 2; - jb->buf = g_malloc (jb->buflen); - jb->pos = jb->buf; - } - - off = jb->pos - jb->buf; - free = jb->buflen - off; - - if ((gint)free < len) { - jb->buflen = MAX (jb->buflen * 2, jb->buflen + len * 2); - jb->buf = g_realloc (jb->buf, jb->buflen); - jb->pos = jb->buf + off; - } - - memcpy (jb->pos, chunk, len); - jb->pos += len; - - /* Say not to copy any part of this buffer */ - return NULL; -} - -void -json_fin_cb (rspamd_mempool_t * pool, struct map_cb_data *data) -{ - struct json_buf *jb; - gint nelts, i, n, j; - json_t *js, *cur_elt, *cur_nm, *it_val, *act_it, *act_value; - json_error_t je; - struct metric_action *new_act; - struct rspamd_settings *cur_settings; - GList *cur_act; - gchar *cur_name; - void *json_it; - double *score; - - if (data->prev_data) { - jb = data->prev_data; - /* Clean prev data */ - if (jb->table) { - g_hash_table_unref (jb->table); - } - if (jb->buf) { - g_free (jb->buf); - } - g_free (jb); - } - - /* Now parse json */ - if (data->cur_data) { - jb = data->cur_data; - } - else { - msg_err ("no data read"); - return; - } - if (jb->buf == NULL) { - msg_err ("no data read"); - return; - } - /* NULL terminate current buf */ - *jb->pos = '\0'; - - js = json_loads (jb->buf, &je); - if (!js) { - msg_err ("cannot load json data: parse error %s, on line %d", je.text, je.line); - return; - } - - if (!json_is_array (js)) { - json_decref (js); - msg_err ("loaded json is not an array"); - return; - } - - nelts = json_array_size (js); - for (i = 0; i < nelts; i++) { - cur_settings = settings_ref (NULL); - - cur_elt = json_array_get (js, i); - if (!cur_elt || !json_is_object (cur_elt)) { - json_decref (js); - msg_err ("loaded json is not an object"); - settings_unref (cur_settings); - return; - } - cur_nm = json_object_get (cur_elt, "name"); - if (cur_nm == NULL || !json_is_string (cur_nm)) { - json_decref (js); - msg_err ("name is not a string or not exists"); - settings_unref (cur_settings); - return; - } - cur_name = g_strdup (json_string_value (cur_nm)); - /* Now check other settings */ - /* Statfile */ - cur_nm = json_object_get (cur_elt, "statfile"); - if (cur_nm != NULL && json_is_string (cur_nm)) { - cur_settings->statfile_alias = g_strdup (json_string_value (cur_nm)); - } - /* Factors object */ - cur_nm = json_object_get (cur_elt, "factors"); - if (cur_nm != NULL && json_is_object (cur_nm)) { - json_it = json_object_iter (cur_nm); - while (json_it) { - it_val = json_object_iter_value (json_it); - if (it_val && json_is_string (it_val)) { - g_hash_table_insert (cur_settings->factors, g_strdup (json_object_iter_key (json_it)), g_strdup (json_string_value (it_val))); - } - json_it = json_object_iter_next (cur_nm, json_it); - } - } - /* Metrics object */ - cur_nm = json_object_get (cur_elt, "metrics"); - if (cur_nm != NULL && json_is_object (cur_nm)) { - json_it = json_object_iter (cur_nm); - while (json_it) { - it_val = json_object_iter_value (json_it); - if (it_val && json_is_number (it_val)) { - score = g_malloc (sizeof (double)); - *score = json_number_value (it_val); - g_hash_table_insert (cur_settings->metric_scores, - g_strdup (json_object_iter_key (json_it)), score); - } - else if (it_val && json_is_object (it_val)) { - /* Assume this as actions hash */ - cur_act = NULL; - act_it = json_object_iter (it_val); - while (act_it) { - act_value = json_object_iter_value (act_it); - - if (act_value && json_is_number (act_value)) { - /* Special cases */ - if (g_ascii_strcasecmp (json_object_iter_key (act_it), "spam_score") == 0) { - score = g_malloc (sizeof (double)); - *score = json_number_value (act_value); - g_hash_table_insert (cur_settings->metric_scores, - g_strdup (json_object_iter_key (json_it)), score); - } - else if (g_ascii_strcasecmp (json_object_iter_key (act_it), "reject_score") == 0) { - score = g_malloc (sizeof (double)); - *score = json_number_value (act_value); - g_hash_table_insert (cur_settings->reject_scores, - g_strdup (json_object_iter_key (json_it)), score); - } - else if (check_action_str (json_object_iter_key (act_it), &j)) { - new_act = g_malloc (sizeof (struct metric_action)); - new_act->action = j; - new_act->score = json_number_value (act_value); - cur_act = g_list_prepend (cur_act, new_act); - } - } - act_it = json_object_iter_next (it_val, act_it); - } - if (cur_act != NULL) { - g_hash_table_insert (cur_settings->metric_actions, - g_strdup (json_object_iter_key (json_it)), cur_act); - cur_act = NULL; - } - } - json_it = json_object_iter_next (cur_nm, json_it); - } - } - /* Rejects object */ - cur_nm = json_object_get (cur_elt, "rejects"); - if (cur_nm != NULL && json_is_object (cur_nm)) { - json_it = json_object_iter (cur_nm); - while (json_it) { - it_val = json_object_iter_value (json_it); - if (it_val && json_is_number (it_val)) { - score = g_malloc (sizeof (double)); - *score = json_number_value (it_val); - g_hash_table_insert (cur_settings->reject_scores, g_strdup (json_object_iter_key (json_it)), - score); - } - json_it = json_object_iter_next(cur_nm, json_it); - } - } - /* Whitelist object */ - cur_nm = json_object_get (cur_elt, "whitelist"); - if (cur_nm != NULL && json_is_array (cur_nm)) { - n = json_array_size(cur_nm); - for(j = 0; j < n; j++) { - it_val = json_array_get(cur_nm, j); - if (it_val && json_is_string (it_val)) { - if (strlen (json_string_value (it_val)) > 0) { - g_hash_table_insert (cur_settings->whitelist, - g_strdup (json_string_value (it_val)), g_strdup (json_string_value (it_val))); - } - } - - } - } - /* Blacklist object */ - cur_nm = json_object_get (cur_elt, "blacklist"); - if (cur_nm != NULL && json_is_array (cur_nm)) { - n = json_array_size(cur_nm); - for(j = 0; j < n; j++) { - it_val = json_array_get(cur_nm, j); - if (it_val && json_is_string (it_val)) { - if (strlen (json_string_value (it_val)) > 0) { - g_hash_table_insert (cur_settings->blacklist, - g_strdup (json_string_value (it_val)), g_strdup (json_string_value (it_val))); - } - } - - } - } - /* Want spam */ - cur_nm = json_object_get (cur_elt, "want_spam"); - if (cur_nm != NULL) { - if (json_is_true (cur_nm)) { - cur_settings->want_spam = TRUE; - } - } - g_hash_table_replace (((struct json_buf *)data->cur_data)->table, cur_name, cur_settings); - } - json_decref (js); -} - -gboolean -read_settings (const gchar *path, const gchar *description, struct config_file *cfg, GHashTable * table) -{ - struct json_buf *jb = g_malloc (sizeof (struct json_buf)), **pjb; - - pjb = g_malloc (sizeof (struct json_buf *)); - - jb->table = table; - jb->buf = NULL; - *pjb = jb; - - if (!add_map (cfg, path, description, json_read_cb, json_fin_cb, (void **)pjb)) { - msg_err ("cannot add map %s", path); - return FALSE; - } - - return TRUE; -} - -void -init_settings (struct config_file *cfg) -{ - cfg->domain_settings = g_hash_table_new_full (rspamd_strcase_hash, rspamd_strcase_equal, - g_free, (GDestroyNotify)settings_unref); - cfg->user_settings = g_hash_table_new_full (rspamd_strcase_hash, rspamd_strcase_equal, - g_free, (GDestroyNotify)settings_unref); -} - -static gboolean -check_setting (struct rspamd_task *task, struct rspamd_settings **user_settings, struct rspamd_settings **domain_settings) -{ - gchar *field = NULL, *domain = NULL; - gchar cmp_buf[1024]; - gint len; - - if (task->deliver_to != NULL) { - /* First try to use deliver-to field */ - field = task->deliver_to; - } - else if (task->user != NULL) { - /* Then user field */ - field = task->user; - } - else if (task->rcpt != NULL) { - /* Then first recipient */ - field = task->rcpt->data; - } - else { - return FALSE; - } - - domain = strchr (field, '@'); - if (domain == NULL) { - /* First try to search in first recipient */ - if (task->rcpt) { - domain = strchr (task->rcpt->data, '@'); - } - } - if (domain != NULL) { - domain++; - } - - /* First try to search per-user settings */ - if (field != NULL) { - if (*field == '<') { - field ++; - } - len = strcspn (field, ">"); - rspamd_strlcpy (cmp_buf, field, MIN ((gint)sizeof (cmp_buf), len + 1)); - *user_settings = g_hash_table_lookup (task->cfg->user_settings, cmp_buf); - } - if (domain != NULL) { - len = strcspn (domain, ">"); - rspamd_strlcpy (cmp_buf, domain, MIN ((gint)sizeof (cmp_buf), len + 1)); - *domain_settings = g_hash_table_lookup (task->cfg->domain_settings, cmp_buf); - } - - if (*domain_settings != NULL || *user_settings != NULL) { - return TRUE; - } - - return FALSE; -} - -static gboolean -check_bwhitelist (struct rspamd_task *task, struct rspamd_settings *s, gboolean *is_black) -{ - gchar *src_email = NULL, *src_domain = NULL, *data; - - if (task->from != NULL && *task->from != '\0') { - src_email = task->from; - } else { - return FALSE; - } - - src_domain = strchr (src_email, '@'); - if(src_domain != NULL) { - src_domain++; - } - - if ((((data = g_hash_table_lookup (s->blacklist, src_email)) != NULL) || - ( (src_domain != NULL) && ((data = g_hash_table_lookup (s->blacklist, src_domain)) != NULL)) )) { - *is_black = TRUE; - msg_info ("<%s> blacklisted as domain %s is in settings blacklist", task->message_id, data); - return TRUE; - } - if ((((data = g_hash_table_lookup (s->whitelist, src_email)) != NULL) || - ( (src_domain != NULL) && ((data = g_hash_table_lookup (s->whitelist, src_domain)) != NULL)) )) { - *is_black = FALSE; - msg_info ("<%s> whitelisted as domain %s is in settings blacklist", task->message_id, data); - return TRUE; - } - return FALSE; -} - -gboolean -check_metric_settings (struct metric_result *res, double *score, double *rscore) -{ - struct rspamd_settings *us = res->user_settings, *ds = res->domain_settings; - double *sc, *rs; - struct metric *metric = res->metric; - - /* XXX: what the fuck is that? */ - *rscore = 10.0; - - if (us != NULL) { - if ((rs = g_hash_table_lookup (us->reject_scores, metric->name)) != NULL) { - *rscore = *rs; - } - if ((sc = g_hash_table_lookup (us->metric_scores, metric->name)) != NULL) { - *score = *sc; - return TRUE; - } - /* Now check in domain settings */ - if (ds && ((rs = g_hash_table_lookup (ds->reject_scores, metric->name)) != NULL)) { - *rscore = *rs; - } - if (ds && (sc = g_hash_table_lookup (ds->metric_scores, metric->name)) != NULL) { - *score = *sc; - return TRUE; - } - } - else if (ds != NULL) { - if ((rs = g_hash_table_lookup (ds->reject_scores, metric->name)) != NULL) { - *rscore = *rs; - } - if ((sc = g_hash_table_lookup (ds->metric_scores, metric->name)) != NULL) { - *score = *sc; - return TRUE; - } - } - - return FALSE; -} - -gboolean -check_metric_action_settings (struct rspamd_task *task, struct metric_result *res, - double score, enum rspamd_metric_action *result) -{ - struct rspamd_settings *us = res->user_settings, *ds = res->domain_settings; - struct metric_action *act, *sel = NULL; - GList *cur; - enum rspamd_metric_action r = METRIC_ACTION_NOACTION; - gboolean black; - - if (us != NULL) { - /* Check whitelist and set appropriate action for whitelisted users */ - if (check_bwhitelist(task, us, &black)) { - if (black) { - *result = METRIC_ACTION_REJECT; - } - else { - *result = METRIC_ACTION_NOACTION; - } - return TRUE; - } - if ((cur = g_hash_table_lookup (us->metric_actions, res->metric->name)) != NULL) { - while (cur) { - act = cur->data; - if (score >= act->score) { - r = act->action; - sel = act; - } - cur = g_list_next (cur); - } - } - } - else if (ds != NULL) { - /* Check whitelist and set appropriate action for whitelisted users */ - if (check_bwhitelist(task, ds, &black)) { - if (black) { - *result = METRIC_ACTION_REJECT; - } - else { - *result = METRIC_ACTION_NOACTION; - } - return TRUE; - } - if ((cur = g_hash_table_lookup (ds->metric_actions, res->metric->name)) != NULL) { - while (cur) { - act = cur->data; - if (score >= act->score) { - r = act->action; - sel = act; - } - cur = g_list_next (cur); - } - } - } - - if (sel != NULL && result != NULL) { - *result = r; - return TRUE; - } - - return FALSE; -} - -gboolean -apply_metric_settings (struct rspamd_task *task, struct metric *metric, struct metric_result *res) -{ - struct rspamd_settings *us = NULL, *ds = NULL; - - if (check_setting (task, &us, &ds)) { - if (us != NULL || ds != NULL) { - if (us != NULL) { - res->user_settings = settings_ref (us); - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t)settings_unref, - us); - } - if (ds != NULL) { - /* Need to ref hash table to avoid occasional data corruption */ - res->domain_settings = settings_ref (ds); - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t)settings_unref, - ds); - } - } - else { - return FALSE; - } - } - - return TRUE; -} - -gboolean -check_factor_settings (struct metric_result *res, const gchar *symbol, double *factor) -{ - double *fc; - - if (res->user_settings != NULL) { - /* First search in user's settings */ - if ((fc = g_hash_table_lookup (res->user_settings->factors, symbol)) != NULL) { - *factor = *fc; - return TRUE; - } - /* Now check in domain settings */ - if (res->domain_settings && (fc = g_hash_table_lookup (res->domain_settings->factors, symbol)) != NULL) { - *factor = *fc; - return TRUE; - } - } - else if (res->domain_settings != NULL) { - if ((fc = g_hash_table_lookup (res->domain_settings->factors, symbol)) != NULL) { - *factor = *fc; - return TRUE; - } - } - - return FALSE; - -} - - -gboolean -check_want_spam (struct rspamd_task *task) -{ - struct rspamd_settings *us = NULL, *ds = NULL; - - if (check_setting (task, &us, &ds)) { - if (us != NULL) { - /* First search in user's settings */ - if (us->want_spam) { - return TRUE; - } - /* Now check in domain settings */ - if (ds && ds->want_spam) { - return TRUE; - } - } - else if (ds != NULL) { - if (ds->want_spam) { - return TRUE; - } - } - } - - return FALSE; -} - -/* - * vi:ts=4 - */ |