From 4405a019f681fcb51ce0e53b477ed64d50740138 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 6 Apr 2010 19:55:11 +0400 Subject: [PATCH] * Add lua functions parsing for module options * Add missing sections to XML parser (classifier, statfile, view, settings) * Add missing params to XML parser * Implement new commandline options parser (using glib) * Set version to 0.3.0 as new rspamd would use new config system --- CMakeLists.txt | 4 +- src/cfg_file.h | 18 +- src/cfg_xml.c | 461 ++++++++++++++++++++++++++++++++++++++--- src/cfg_xml.h | 31 ++- src/lua/lua_cfg_file.c | 104 +++++++++- src/lua/lua_common.c | 4 +- src/lua/lua_common.h | 4 +- src/main.c | 103 ++++----- 8 files changed, 619 insertions(+), 110 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 480fe88ce..3b93b49c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,8 @@ PROJECT(rspamd C) SET(RSPAMD_VERSION_MAJOR 0) -SET(RSPAMD_VERSION_MINOR 2) -SET(RSPAMD_VERSION_PATCH 9) +SET(RSPAMD_VERSION_MINOR 3) +SET(RSPAMD_VERSION_PATCH 0) SET(RSPAMD_VERSION "${RSPAMD_VERSION_MAJOR}.${RSPAMD_VERSION_MINOR}.${RSPAMD_VERSION_PATCH}") SET(RSPAMD_MASTER_SITE_URL "http://cebka.pp.ru/hg/rspamd") diff --git a/src/cfg_file.h b/src/cfg_file.h index 225a940ac..17f81b3a6 100644 --- a/src/cfg_file.h +++ b/src/cfg_file.h @@ -102,6 +102,16 @@ struct script_module { gchar *path; /**< path to module */ }; +/** + * Type of lua variable + */ +enum lua_var_type { + LUA_VAR_NUM, + LUA_VAR_BOOLEAN, + LUA_VAR_STRING, + LUA_VAR_FUNCTION, + LUA_VAR_UNKNOWN +}; /** * Module option */ @@ -110,13 +120,7 @@ struct module_opt { gchar *value; /**< paramater value */ gpointer actual_data; /**< parsed data */ gboolean is_lua; /**< actually this is lua variable */ - enum { - LUA_VAR_NUM, - LUA_VAR_BOOLEAN, - LUA_VAR_STRING, - LUA_VAR_FUNCTION, - LUA_VAR_UNKNOWN - } lua_type; /**< type of lua variable */ + enum lua_var_type lua_type; /**< type of lua variable */ }; /** 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); diff --git a/src/cfg_xml.h b/src/cfg_xml.h index ec0547ffe..d27f147ca 100644 --- a/src/cfg_xml.h +++ b/src/cfg_xml.h @@ -20,10 +20,10 @@ enum xml_read_state { XML_READ_FACTORS, XML_READ_METRIC, XML_READ_WORKER, - XML_READ_VARIABLE, + XML_READ_VIEW, XML_READ_LOGGING, - XML_ERROR, XML_READ_VALUE, + XML_ERROR, XML_END }; @@ -31,7 +31,8 @@ struct rspamd_xml_userdata { enum xml_read_state state; struct config_file *cfg; gchar section_name[MAX_NAME]; - gpointer other_data; + gpointer section_pointer; + gpointer parent_pointer; GHashTable *cur_attrs; }; @@ -88,12 +89,36 @@ gboolean xml_handle_boolean (struct config_file *cfg, struct rspamd_xml_userdata 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); 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); 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); + gboolean handle_factor (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset); + 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); + 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); gboolean handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset); + gboolean handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset); +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); + +gboolean handle_variable (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset); +gboolean handle_composite (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset); + +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); +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); +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); +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); + +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); +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); + +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); +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); + +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); +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); +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); +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); /* Dumper functions */ gboolean xml_dump_config (struct config_file *cfg, const char *filename); diff --git a/src/lua/lua_cfg_file.c b/src/lua/lua_cfg_file.c index 1ac334299..8be11b02b 100644 --- a/src/lua/lua_cfg_file.c +++ b/src/lua/lua_cfg_file.c @@ -121,7 +121,7 @@ lua_process_element (struct config_file *cfg, const char *name, struct module_op opt->lua_type = LUA_VAR_STRING; break; case LUA_TFUNCTION: - opt->actual_data = (gpointer)lua_topointer (L, idx); + opt->actual_data = memory_pool_strdup (cfg->cfg_pool, lua_tostring (L, idx)); opt->lua_type = LUA_VAR_FUNCTION; break; case LUA_TNIL: @@ -152,7 +152,7 @@ lua_module_callback (gpointer key, gpointer value, gpointer ud) lua_getglobal (L, "config"); if (lua_istable (L, -1)) { lua_pushstring (L, opt->param); - lua_gettable (L, -2); + lua_gettable (L, -2); if (lua_isnil (L, -1)) { /* Try to get global variable */ lua_getglobal (L, opt->param); @@ -194,3 +194,103 @@ lua_post_load_config (struct config_file *cfg) /* Now parse all lua params */ g_hash_table_foreach (cfg->modules_opts, lua_module_callback, cfg); } + +/* Handle lua dynamic config param */ +gboolean +lua_handle_param (struct worker_task *task, gchar *mname, gchar *optname, enum lua_var_type expected_type, gpointer *res) +{ + lua_State *L = task->cfg->lua_state; + GList *cur; + struct module_opt *opt; + struct worker_task **ptask; + double num_res; + gboolean bool_res; + gchar *str_res; + + if ((cur = g_hash_table_lookup (task->cfg->modules_opts, mname)) == NULL) { + *res = NULL; + return FALSE; + } + + /* Search for specified option */ + while (cur) { + opt = cur->data; + if (opt->is_lua && g_ascii_strcasecmp (opt->param, optname) == 0) { + if (opt->lua_type == expected_type) { + /* Just push pointer to res */ + *res = opt->actual_data; + return TRUE; + } + else if (opt->lua_type == LUA_VAR_FUNCTION) { + /* Call specified function and expect result of given expected_type */ + /* First check function in config table */ + lua_getglobal (L, "config"); + if (lua_istable (L, -1)) { + lua_pushstring (L, opt->actual_data); + lua_gettable (L, -2); + if (lua_isnil (L, -1)) { + /* Try to get global variable */ + lua_getglobal (L, opt->actual_data); + } + } + else { + /* Try to get global variable */ + lua_getglobal (L, opt->actual_data); + } + if (lua_isnil (L, -1)) { + msg_err ("function with name %s is not defined", (gchar *)opt->actual_data); + return FALSE; + } + /* Now we got function in top of stack */ + ptask = lua_newuserdata (L, sizeof (struct worker_task *)); + lua_setclass (L, "rspamd{task}", -1); + *ptask = task; + /* Call function */ + if (lua_pcall (L, 1, 1, 0) != 0) { + msg_info ("call to %s failed: %s", (gchar *)opt->actual_data, lua_tostring (L, -1)); + *res = NULL; + return FALSE; + } + /* Get result of specified type */ + switch (expected_type) { + case LUA_VAR_NUM: + if (!lua_isnumber (L, -1)) { + *res = NULL; + return FALSE; + } + num_res = lua_tonumber (L, -1); + *res = memory_pool_alloc (task->task_pool, sizeof (double)); + **(double **)res = num_res; + return TRUE; + case LUA_VAR_BOOLEAN: + if (!lua_isboolean (L, -1)) { + *res = NULL; + return FALSE; + } + bool_res = lua_toboolean (L, -1); + *res = memory_pool_alloc (task->task_pool, sizeof (gboolean)); + **(gboolean **)res = bool_res; + return TRUE; + case LUA_VAR_STRING: + if (!lua_isstring (L, -1)) { + *res = NULL; + return FALSE; + } + str_res = memory_pool_strdup (task->task_pool, lua_tostring (L, -1)); + *res = str_res; + return TRUE; + case LUA_VAR_FUNCTION: + case LUA_VAR_UNKNOWN: + msg_err ("cannot expect function or unknown types"); + *res = NULL; + return FALSE; + } + } + } + cur = g_list_next (cur); + } + + /* Option not found */ + *res = NULL; + return FALSE; +} diff --git a/src/lua/lua_common.c b/src/lua/lua_common.c index 3d4e29b28..c73b663bb 100644 --- a/src/lua/lua_common.c +++ b/src/lua/lua_common.c @@ -181,7 +181,7 @@ luaopen_logger (lua_State * L) } void -init_lua () +init_lua (struct config_file *cfg) { if (L == NULL) { L = lua_open (); @@ -198,6 +198,7 @@ init_lua () (void)luaopen_message (L); (void)luaopen_classifier (L); (void)luaopen_statfile (L); + cfg->lua_state = L; } } @@ -361,7 +362,6 @@ void add_luabuf (const char *line) { int error; - init_lua (); error = luaL_loadbuffer (L, line, strlen (line), "config") || lua_pcall (L, 0, 0, 0); if (error) { diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h index 5de7bdc71..4c8ff2585 100644 --- a/src/lua/lua_common.h +++ b/src/lua/lua_common.h @@ -30,7 +30,7 @@ int luaopen_hash_table (lua_State *L); int luaopen_textpart (lua_State *L); int luaopen_classifier (lua_State *L); int luaopen_statfile (lua_State * L); -void init_lua (); +void init_lua (struct config_file *cfg); void init_lua_filters (struct config_file *cfg); /* Filters functions */ @@ -48,6 +48,8 @@ double lua_normalizer_func (double score, void *params); /* Config file functions */ void lua_post_load_config (struct config_file *cfg); void lua_process_element (struct config_file *cfg, const char *name, struct module_opt *opt, int idx); +gboolean lua_handle_param (struct worker_task *task, gchar *mname, gchar *optname, + enum lua_var_type expected_type, gpointer *res); #endif /* WITH_LUA */ diff --git a/src/main.c b/src/main.c index 926d0e5c6..022773038 100644 --- a/src/main.c +++ b/src/main.c @@ -28,6 +28,7 @@ #include "util.h" #include "lmtp.h" #include "fuzzy_storage.h" +#include "cfg_xml.h" #ifndef WITHOUT_PERL @@ -65,8 +66,14 @@ GQueue *signals_info; extern int yynerrs; extern FILE *yyin; -static int dump_vars = 0; -static int dump_cache = 0; +static gboolean config_test; +static gboolean no_fork; +static gchar *cfg_name; +static gchar *rspamd_user; +static gchar *rspamd_group; +static gchar *rspamd_pidfile; +static gboolean dump_vars; +static gboolean dump_cache; #ifndef WITHOUT_PERL extern void xs_init (pTHX); @@ -76,6 +83,21 @@ extern PerlInterpreter *perl_interpreter; /* List of workers that are pending to start */ static GList *workers_pending = NULL; +/* Commandline options */ +static GOptionEntry entries[] = +{ + { "config-test", 't', 0, G_OPTION_ARG_NONE, &config_test, "Do config test and exit", NULL }, + { "no-fork", 'f', 0, G_OPTION_ARG_NONE, &no_fork, "Do not daemonize main process", NULL }, + { "config", 'c', 0, G_OPTION_ARG_STRING, &cfg_name, "Specify config file", NULL }, + { "user", 'u', 0, G_OPTION_ARG_STRING, &rspamd_user, "User to run rspamd as", NULL }, + { "group", 'g', 0, G_OPTION_ARG_STRING, &rspamd_group, "Group to run rspamd as", NULL }, + { "pid", 'p', 0, G_OPTION_ARG_STRING, &rspamd_pidfile, "Path to pidfile", NULL }, + { "dump-vars", 'V', 0, G_OPTION_ARG_NONE, &dump_vars, "Print all rspamd variables and exit", NULL }, + { "dump-cache", 'C', 0, G_OPTION_ARG_NONE, &dump_cache, "Dump symbols cache stats and exit", NULL }, + { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL } +}; + + #ifndef HAVE_SA_SIGINFO static void sig_handler (int signo) @@ -156,61 +178,22 @@ print_signals_info () static void read_cmd_line (int argc, char **argv, struct config_file *cfg) { - int ch; - while ((ch = getopt (argc, argv, "tVChfc:u:g:p:")) != -1) { - switch (ch) { - case 'f': - cfg->no_fork = 1; - break; - case 'c': - if (optarg && cfg->cfg_name) { - cfg->cfg_name = memory_pool_strdup (cfg->cfg_pool, optarg); - } - break; - case 't': - cfg->config_test = 1; - break; - case 'V': - dump_vars = 1; - break; - case 'C': - dump_cache = 1; - break; - case 'u': - if (optarg) { - cfg->rspamd_user = memory_pool_strdup (cfg->cfg_pool, optarg); - } - break; - case 'g': - if (optarg) { - cfg->rspamd_group = memory_pool_strdup (cfg->cfg_pool, optarg); - } - break; - case 'p': - if (optarg) { - cfg->pid_file = memory_pool_strdup (cfg->cfg_pool, optarg); - } - break; - case 'h': - case '?': - default: - /* Show help message and exit */ - printf ("Rspamd version " RVERSION "\n" - "Usage: rspamd [-t] [-h] [-n] [-f] [-c config_file]\n" - "-h: This help message\n" - "-t: Do config test and exit\n" - "-C: Dump symbols cache stats and exit\n" - "-V Print all rspamd variables and exit\n" - "-f: Do not daemonize main process\n" - "-c: Specify config file (./rspamd.conf is used by default)\n" - "-u: User to run rspamd as\n" - "-g: Group to run rspamd as\n" - "-p: Path to pidfile\n" - ); - exit (0); - break; - } - } + GError *error = NULL; + GOptionContext *context; + + context = g_option_context_new ("- run rspamd daemon"); + g_option_context_set_summary (context, "Summary:\n Rspamd daemon version " RVERSION); + g_option_context_add_main_entries (context, entries, NULL); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + fprintf (stderr, "option parsing failed: %s\n", error->message); + exit (1); + } + cfg->no_fork = no_fork; + cfg->config_test = config_test; + cfg->rspamd_user = rspamd_user; + cfg->rspamd_group = rspamd_group; + cfg->cfg_name = cfg_name; + cfg->pid_file = rspamd_pidfile; } static void @@ -598,8 +581,10 @@ main (int argc, char **argv, char **env) bzero (&signals, sizeof (struct sigaction)); - rspamd->cfg->cfg_name = memory_pool_strdup (rspamd->cfg->cfg_pool, FIXED_CONFIG_FILE); read_cmd_line (argc, argv, rspamd->cfg); + if (rspamd->cfg->cfg_name == NULL) { + rspamd->cfg->cfg_name = FIXED_CONFIG_FILE; + } if (cfg->config_test) { cfg->log_level = G_LOG_LEVEL_DEBUG; @@ -624,7 +609,7 @@ main (int argc, char **argv, char **env) #ifndef HAVE_SETPROCTITLE init_title (argc, argv, environ); #endif - init_lua (); + init_lua (cfg); f = fopen (rspamd->cfg->cfg_name, "r"); if (f == NULL) { -- 2.39.5