diff options
Diffstat (limited to 'src/cfg_xml.c')
-rw-r--r-- | src/cfg_xml.c | 461 |
1 files changed, 427 insertions, 34 deletions
diff --git a/src/cfg_xml.c b/src/cfg_xml.c index 872bd7a00..46ccd1e2e 100644 --- a/src/cfg_xml.c +++ b/src/cfg_xml.c @@ -34,6 +34,9 @@ #include "classifiers/classifiers.h" #include "tokenizers/tokenizers.h" #include "lua/lua_common.h" +#include "view.h" +#include "expressions.h" +#include "settings.h" /* Maximum attributes for param */ #define MAX_PARAM 64 @@ -52,11 +55,11 @@ enum xml_config_section { XML_SECTION_WORKER, XML_SECTION_METRIC, XML_SECTION_CLASSIFIER, + XML_SECTION_STATFILE, XML_SECTION_FACTORS, XML_SECTION_MODULE, XML_SECTION_MODULES, - XML_SECTION_VIEW, - XML_SECTION_SETTINGS + XML_SECTION_VIEW }; struct xml_config_param { @@ -117,6 +120,30 @@ static struct xml_parser_rule grammar[] = { G_STRUCT_OFFSET (struct config_file, filters_str), NULL }, + { + "variable", + handle_variable, + 0, + NULL + }, + { + "composite", + handle_composite, + 0, + NULL + }, + { + "user_settings", + handle_user_settings, + 0, + NULL + }, + { + "domain_settings", + handle_domain_settings, + 0, + NULL + }, NULL_ATTR }, NULL_ATTR @@ -226,6 +253,71 @@ static struct xml_parser_rule grammar[] = { NULL_ATTR }, { XML_SECTION_CLASSIFIER, { + { + "metric", + xml_handle_string, + G_STRUCT_OFFSET (struct classifier_config, metric), + NULL + }, + { + "tokenizer", + handle_classifier_tokenizer, + 0, + NULL + }, + { + "option", + handle_classifier_opt, + 0, + NULL + }, + NULL_ATTR + }, + NULL_ATTR + }, + { XML_SECTION_STATFILE, { + { + "symbol", + xml_handle_string, + G_STRUCT_OFFSET (struct statfile, symbol), + NULL + }, + { + "path", + xml_handle_string, + G_STRUCT_OFFSET (struct statfile, path), + NULL + }, + { + "size", + xml_handle_size, + G_STRUCT_OFFSET (struct statfile, size), + NULL + }, + { + "normalizer", + handle_statfile_normalizer, + 0, + NULL + }, + { + "binlog", + handle_statfile_binlog, + 0, + NULL + }, + { + "binlog_rotate", + handle_statfile_binlog_rotate, + 0, + NULL + }, + { + "binlog_master", + handle_statfile_binlog_master, + 0, + NULL + }, NULL_ATTR }, NULL_ATTR @@ -257,20 +349,51 @@ static struct xml_parser_rule grammar[] = { } }, { XML_SECTION_MODULES, { + { + "path", + handle_module_path, + 0, + NULL + }, NULL_ATTR }, NULL_ATTR }, { XML_SECTION_VIEW, { + { + "skip_check", + xml_handle_boolean, + G_STRUCT_OFFSET (struct rspamd_view, skip_check), + NULL + }, + { + "ip", + handle_view_ip, + 0, + NULL + }, + { + "client_ip", + handle_view_client_ip, + 0, + NULL + }, + { + "from", + handle_view_from, + 0, + NULL + }, + { + "symbols", + handle_view_symbols, + 0, + NULL + }, NULL_ATTR }, NULL_ATTR }, - { XML_SECTION_SETTINGS, { - NULL_ATTR - }, - NULL_ATTR - } }; GQuark @@ -373,6 +496,7 @@ call_param_handler (struct rspamd_xml_userdata *ctx, const gchar *name, gchar *v /* Handlers */ /* Specific handlers */ +/* Logging section */ gboolean handle_log_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) { @@ -471,10 +595,11 @@ handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHas return TRUE; } +/* Worker section */ gboolean worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) { - struct worker_conf *wrk = ctx->other_data; + struct worker_conf *wrk = ctx->section_pointer; char *name; if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { @@ -489,7 +614,7 @@ worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, G gboolean worker_handle_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) { - struct worker_conf *wrk = ctx->other_data; + struct worker_conf *wrk = ctx->section_pointer; if (g_ascii_strcasecmp (data, "normal") == 0) { @@ -519,7 +644,7 @@ worker_handle_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GH gboolean worker_handle_bind (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) { - struct worker_conf *wrk = ctx->other_data; + struct worker_conf *wrk = ctx->section_pointer; if (!parse_bind_line (cfg, wrk, data)) { msg_err ("cannot parse bind_socket: %s", data); @@ -529,6 +654,7 @@ worker_handle_bind (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GH return TRUE; } +/* Factors section */ gboolean handle_factor (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) { @@ -554,6 +680,7 @@ handle_factor (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTa return TRUE; } +/* Modules section */ gboolean handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) { @@ -641,6 +768,243 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable return TRUE; } +/* Modules section */ +gboolean +handle_module_path (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct stat st; + struct script_module *cur; + glob_t globbuf; + char *pattern; + size_t len; + int i; + + if (stat (data, &st) == -1) { + msg_err ("cannot stat path %s, %s", data, strerror (errno)); + return FALSE; + } + + globbuf.gl_offs = 0; + len = strlen (data) + sizeof ("*.lua"); + pattern = g_malloc (len); + snprintf (pattern, len, "%s%s", data, "*.lua"); + + if (glob (pattern, GLOB_DOOFFS, NULL, &globbuf) == 0) { + for (i = 0; i < globbuf.gl_pathc; i ++) { + cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct script_module)); + cur->path = memory_pool_strdup (cfg->cfg_pool, globbuf.gl_pathv[i]); + cfg->script_modules = g_list_prepend (cfg->script_modules, cur); + } + globfree (&globbuf); + } + else { + msg_err ("glob failed: %s", strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/* Variables and composites */ +gboolean +handle_variable (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + gchar *val; + + if ((val = g_hash_table_lookup (attrs, "name")) == NULL) { + msg_err ("'name' attribute is required for tag 'variable'"); + return FALSE; + } + + g_hash_table_insert (cfg->variables, val, memory_pool_strdup (cfg->cfg_pool, data)); + return TRUE; +} + +gboolean +handle_composite (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + gchar *val; + struct expression *expr; + + if ((val = g_hash_table_lookup (attrs, "name")) == NULL) { + msg_err ("'name' attribute is required for tag 'composite'"); + return FALSE; + } + + if ((expr = parse_expression (cfg->cfg_pool, data)) == NULL) { + msg_err ("cannot parse composite expression: %s", data); + return FALSE; + } + g_hash_table_insert (cfg->composite_symbols, val, expr); + + return TRUE; +} + +/* View section */ +gboolean +handle_view_ip (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct rspamd_view *view = ctx->section_pointer; + + if (!add_view_ip (view, data)) { + msg_err ("invalid ip line in view definition: ip = '%s'", data); + return FALSE; + } + + return TRUE; +} +gboolean +handle_view_client_ip (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct rspamd_view *view = ctx->section_pointer; + + if (!add_view_client_ip (view, data)) { + msg_err ("invalid ip line in view definition: ip = '%s'", data); + return FALSE; + } + + return TRUE; +} +gboolean +handle_view_from (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct rspamd_view *view = ctx->section_pointer; + + if (!add_view_from (view, data)) { + msg_err ("invalid from line in view definition: ip = '%s'", data); + return FALSE; + } + + return TRUE; +} +gboolean +handle_view_symbols (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct rspamd_view *view = ctx->section_pointer; + + if (!add_view_symbols (view, data)) { + msg_err ("invalid symbols line in view definition: ip = '%s'", data); + return FALSE; + } + + return TRUE; +} + +/* Settings */ +gboolean +handle_user_settings (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + if (!read_settings (data, cfg, cfg->user_settings)) { + msg_err ("cannot read settings %s", data); + return FALSE; + } + + return TRUE; +} +gboolean +handle_domain_settings (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + if (!read_settings (data, cfg, cfg->domain_settings)) { + msg_err ("cannot read settings %s", data); + return FALSE; + } + + return TRUE; +} + +/* Classifier */ +gboolean +handle_classifier_tokenizer (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct classifier_config *ccf = ctx->section_pointer; + + if ((ccf->tokenizer = get_tokenizer (data)) == NULL) { + msg_err ("unknown tokenizer %s", data); + return FALSE; + } + + return TRUE; +} + +gboolean +handle_classifier_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct classifier_config *ccf = ctx->section_pointer; + gchar *val; + + if ((val = g_hash_table_lookup (attrs, "name")) == NULL) { + msg_err ("'name' attribute is required for tag 'option'"); + return FALSE; + } + + g_hash_table_insert (ccf->opts, val, memory_pool_strdup (cfg->cfg_pool, data)); + return TRUE; +} + +/* Statfile */ +gboolean +handle_statfile_normalizer (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct statfile *st = ctx->section_pointer; + + if (!parse_normalizer (cfg, st, data)) { + msg_err ("cannot parse normalizer string: %s", data); + return FALSE; + } + + return TRUE; +} + +gboolean +handle_statfile_binlog (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct statfile *st = ctx->section_pointer; + + if (st->binlog == NULL) { + st->binlog = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct statfile_binlog_params)); + } + if (g_ascii_strcasecmp (data, "master") == 0) { + st->binlog->affinity = AFFINITY_MASTER; + } + else if (g_ascii_strcasecmp (data, "slave") == 0) { + st->binlog->affinity = AFFINITY_SLAVE; + } + else { + st->binlog->affinity = AFFINITY_NONE; + } + + return TRUE; +} + +gboolean +handle_statfile_binlog_rotate (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct statfile *st = ctx->section_pointer; + + if (st->binlog == NULL) { + st->binlog = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct statfile_binlog_params)); + } + st->binlog->rotate_time = parse_seconds (data); + + return TRUE; +} + +gboolean +handle_statfile_binlog_master (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) +{ + struct statfile *st = ctx->section_pointer; + if (st->binlog == NULL) { + st->binlog = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct statfile_binlog_params)); + } + + if (!parse_host_port (data, &st->binlog->master_addr, &st->binlog->master_port)) { + msg_err ("cannot parse master address: %s", data); + return FALSE; + } + + return TRUE; +} + /* Common handlers */ gboolean xml_handle_string (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset) @@ -807,7 +1171,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam g_strlcpy (ud->section_name, res, sizeof (ud->section_name)); ud->state = XML_READ_METRIC; /* Create object */ - ud->other_data = memory_pool_alloc0 (ud->cfg->cfg_pool, sizeof (struct metric)); + ud->section_pointer = memory_pool_alloc0 (ud->cfg->cfg_pool, sizeof (struct metric)); } else { *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'metric'"); @@ -819,7 +1183,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam g_strlcpy (ud->section_name, res, sizeof (ud->section_name)); ud->state = XML_READ_CLASSIFIER; /* Create object */ - ud->other_data = check_classifier_cfg (ud->cfg, NULL); + ud->section_pointer = check_classifier_cfg (ud->cfg, NULL); } else { *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'type' is required for tag 'classifier'"); @@ -829,28 +1193,30 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam else if (g_ascii_strcasecmp (element_name, "worker") == 0) { ud->state = XML_READ_WORKER; /* Create object */ - ud->other_data = check_worker_conf (ud->cfg, NULL); + ud->section_pointer = check_worker_conf (ud->cfg, NULL); + } + else if (g_ascii_strcasecmp (element_name, "view") == 0) { + ud->state = XML_READ_VIEW; + /* Create object */ + ud->section_pointer = init_view (ud->cfg->cfg_pool); } - else if (g_ascii_strcasecmp (element_name, "variable") == 0) { - if (extract_attr ("name", attribute_names, attribute_values, &res)) { - g_strlcpy (ud->section_name, res, sizeof (ud->section_name)); - ud->state = XML_READ_VARIABLE; - } - else { - *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'variable'"); - ud->state = XML_ERROR; - } - - } else { /* Extract other tags */ g_strlcpy (ud->section_name, element_name, sizeof (ud->section_name)); ud->state = XML_READ_VALUE; } break; + case XML_READ_CLASSIFIER: + if (g_ascii_strcasecmp (element_name, "statfile") == 0) { + ud->state = XML_READ_STATFILE; + + /* Now section pointer is statfile and parent pointer is classifier */ + ud->parent_pointer = ud->section_pointer; + ud->section_pointer = memory_pool_alloc0 (ud->cfg->cfg_pool, sizeof (struct statfile)); + } + break; case XML_READ_MODULE: case XML_READ_FACTORS: - case XML_READ_CLASSIFIER: case XML_READ_STATFILE: case XML_READ_WORKER: case XML_READ_LOGGING: @@ -882,6 +1248,9 @@ void rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error) { struct rspamd_xml_userdata *ud = user_data; + struct metric *m; + struct classifier_config *ccf; + struct statfile *st; gboolean res; switch (ud->state) { @@ -893,6 +1262,21 @@ rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name, break; case XML_READ_STATFILE: CHECK_TAG ("statfile", FALSE); + if (res) { + ccf = ud->parent_pointer; + st = ud->section_pointer; + /* Check statfile and insert it into classifier */ + if (st->path == NULL || st->size == 0 || st->symbol == NULL) { + *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "not enough arguments in statfile definition"); + ud->state = XML_ERROR; + } + ccf->statfiles = g_list_prepend (ccf->statfiles, st); + ud->cfg->statfiles = g_list_prepend (ud->cfg->statfiles, st); + g_hash_table_insert (ud->cfg->classifiers_symbols, st->symbol, ccf); + ud->section_pointer = ccf; + ud->parent_pointer = NULL; + ud->state = XML_READ_CLASSIFIER; + } break; case XML_READ_FACTORS: CHECK_TAG ("factors", FALSE); @@ -900,7 +1284,7 @@ rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name, case XML_READ_METRIC: CHECK_TAG ("metric", FALSE); if (res) { - struct metric *m = ud->other_data; + m = ud->section_pointer; if (m->name == NULL) { *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "metric attribute \"name\" is required but missing"); ud->state = XML_ERROR; @@ -917,11 +1301,15 @@ rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name, CHECK_TAG ("worker", FALSE); if (res) { /* Insert object to list */ - ud->cfg->workers = g_list_prepend (ud->cfg->workers, ud->other_data); + ud->cfg->workers = g_list_prepend (ud->cfg->workers, ud->section_pointer); } break; - case XML_READ_VARIABLE: - CHECK_TAG ("variable", TRUE); + case XML_READ_VIEW: + CHECK_TAG ("view", FALSE); + if (res) { + /* Insert object to list */ + ud->cfg->views = g_list_prepend (ud->cfg->views, ud->section_pointer); + } break; case XML_READ_VALUE: /* Check tags parity */ @@ -959,13 +1347,13 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len switch (ud->state) { case XML_READ_MODULE: - if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_MODULE)) { + if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_MODULE)) { *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); ud->state = XML_ERROR; } break; case XML_READ_CLASSIFIER: - if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_CLASSIFIER)) { + if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_CLASSIFIER)) { *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); ud->state = XML_ERROR; } @@ -979,18 +1367,23 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len } break; case XML_READ_METRIC: - if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_METRIC)) { + if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_METRIC)) { *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); ud->state = XML_ERROR; } break; case XML_READ_WORKER: - if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_WORKER)) { + if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_WORKER)) { + *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); + ud->state = XML_ERROR; + } + break; + case XML_READ_VIEW: + if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_VIEW)) { *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); ud->state = XML_ERROR; } break; - case XML_READ_VARIABLE: case XML_READ_VALUE: if (!call_param_handler (ud, ud->section_name, val, cfg, XML_SECTION_MAIN)) { *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); |