aboutsummaryrefslogtreecommitdiffstats
path: root/src/settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings.c')
-rw-r--r--src/settings.c657
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
- */