diff options
-rw-r--r-- | lualib/rspamadm/configwizard.lua | 190 | ||||
-rw-r--r-- | src/rspamadm/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/rspamadm/commands.c | 2 | ||||
-rw-r--r-- | src/rspamadm/configwizard.c | 164 |
4 files changed, 357 insertions, 0 deletions
diff --git a/lualib/rspamadm/configwizard.lua b/lualib/rspamadm/configwizard.lua new file mode 100644 index 000000000..164d29117 --- /dev/null +++ b/lualib/rspamadm/configwizard.lua @@ -0,0 +1,190 @@ +--[[ +Copyright (c) 2017, Vsevolod Stakhov <vsevolod@highsecure.ru> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +]]-- + +local ansicolors = require "rspamadm/ansicolors" +local local_conf = rspamd_paths['CONFDIR'] +local rspamd_util = require "rspamd_util" +local rspamd_logger = require "rspamd_logger" + +local function is_implicit(t) + local mt = getmetatable(t) + + return mt and mt.class and mt.class == 'ucl.type.impl_array' +end + +local function printf(fmt, ...) + print(string.format(fmt, ...)) +end + +local function highlight(str) + return ansicolors.white .. str .. ansicolors.reset +end + +local function ask_yes_no(greet, default) + local def_str + if default then + greet = greet .. "[Y/n]: " + def_str = "yes" + else + greet = greet .. "[y/N]: " + def_str = "no" + end + + local reply = rspamd_util.readline(greet) + + if not reply or #reply == 0 then reply = def_str end + reply = reply:lower() + if reply == 'y' or reply == 'yes' then return true end + + return false +end + +local function print_changes(changes) + local function print_change(k, c, where) + printf('File: %s, changes list:', highlight(local_conf .. '/' + .. where .. '/'.. k)) + + for ek,ev in pairs(c) do + printf("%s => %s", highlight(ek), rspamd_logger.slog("%s", ev)) + end + end + for k, v in pairs(changes.l) do + print_change(k, v, 'local.d') + if changes.o[k] then + v = changes.o[k] + print_change(k, v, 'override.d') + end + print() + end +end + +local function apply_changes(changes) + local function dirname(fname) + if fname:match(".-/.-") then + return string.gsub(fname, "(.*/)(.*)", "%1") + else + return nil + end + end + + local function apply_change(k, c, where) + local fname = local_conf .. '/' .. where .. '/'.. k + + if not rspamd_util.file_exists(fname) then + printf("Create file %s", highlight(fname)) + + local dname = dirname(fname) + + if dname then + local ret, err = rspamd_util.mkdir(dname, true) + + if not ret then + printf("Cannot make directory %s: %s", dname, highlight(err)) + os.exit(1) + end + end + end + + local f = io.open(fname, "a+") + + if not f then + printf("Cannot open file %s, aborting", highlight(fname)) + os.exit(1) + end + + for ek,ev in pairs(c) do + f:write(rspamd_logger.slog("%s = %s; # Set from configwizard\n", ek, ev)) + end + + f:close() + end + for k, v in pairs(changes.l) do + apply_change(k, v, 'local.d') + if changes.o[k] then + v = changes.o[k] + apply_change(k, v, 'override.d') + end + end +end + + +local function setup_controller(controller, changes) + printf("Setup %s and controller worker:", highlight("WebUI")) + + if not controller.password or controller.password == 'q1' then + if ask_yes_no("Controller password is not set, do you want to set one?", true) then + local pw_encrypted = rspamadm.pw_encrypt() + if pw_encrypted then + printf("Set encrypted password to: %s", highlight(pw_encrypted)) + changes.l['worker-controller.inc'] = { + password = pw_encrypted + } + end + end + end +end + +local function find_worker(cfg, wtype) + if cfg.worker then + for k,s in pairs(cfg.worker) do + if type(k) == 'number' and type(s) == 'table' then + if s[wtype] then return s[wtype] end + end + if type(s) == 'table' and s.type and s.type == wtype then + return s + end + if type(k) == 'string' and k == wtype then return s end + end + end + + return nil +end + +return function(args, cfg) + local changes = { + l = {}, -- local changes + o = {}, -- override changes + } + + rspamd_util.umask('022') + printf("Welcome to %s configuration tool", highlight("Rspamd")) + printf("We use %s configuration file, writing results to %s", + highlight(cfg.config_path), highlight(local_conf)) + if ask_yes_no("Do you wish to continue?", true) then + + local controller = find_worker(cfg, 'controller') + if controller then + setup_controller(controller, changes) + end + end + + local nchanges = 0 + for _,_ in pairs(changes.l) do nchanges = nchanges + 1 end + for _,_ in pairs(changes.o) do nchanges = nchanges + 1 end + + if nchanges > 0 then + print_changes(changes) + if ask_yes_no("Apply changes?", true) then + apply_changes(changes) + printf("%d changes applied, the wizard is finished now", nchanges) + else + printf("No changes applied, the wizard is finished now") + end + else + printf("No changes found, the wizard is finished now") + end +end + diff --git a/src/rspamadm/CMakeLists.txt b/src/rspamadm/CMakeLists.txt index 83c91f8a9..7dfaad691 100644 --- a/src/rspamadm/CMakeLists.txt +++ b/src/rspamadm/CMakeLists.txt @@ -9,6 +9,7 @@ SET(RSPAMADMSRC rspamadm.c configdump.c control.c confighelp.c + configwizard.c stat_convert.c signtool.c lua_repl.c diff --git a/src/rspamadm/commands.c b/src/rspamadm/commands.c index d344dce3c..1eaa45c81 100644 --- a/src/rspamadm/commands.c +++ b/src/rspamadm/commands.c @@ -28,6 +28,7 @@ extern struct rspamadm_command grep_command; extern struct rspamadm_command signtool_command; extern struct rspamadm_command lua_command; extern struct rspamadm_command dkim_keygen_command; +extern struct rspamadm_command configwizard_command; const struct rspamadm_command *commands[] = { &help_command, @@ -44,6 +45,7 @@ const struct rspamadm_command *commands[] = { &signtool_command, &lua_command, &dkim_keygen_command, + &configwizard_command, NULL }; diff --git a/src/rspamadm/configwizard.c b/src/rspamadm/configwizard.c new file mode 100644 index 000000000..6ff5d256e --- /dev/null +++ b/src/rspamadm/configwizard.c @@ -0,0 +1,164 @@ +/*- + * Copyright 2017 Vsevolod Stakhov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "config.h" +#include "rspamadm.h" +#include "cfg_file.h" +#include "cfg_rcl.h" +#include "utlist.h" +#include "rspamd.h" +#include "lua/lua_common.h" +#include "utlist.h" + +static gchar *config = NULL; +extern struct rspamd_main *rspamd_main; +/* Defined in modules.c */ +extern module_t *modules[]; +extern worker_t *workers[]; + +static void rspamadm_configwizard (gint argc, gchar **argv); +static const char *rspamadm_configwizard_help (gboolean full_help); + +struct rspamadm_command configwizard_command = { + .name = "configwizard", + .flags = 0, + .help = rspamadm_configwizard_help, + .run = rspamadm_configwizard, + .lua_subrs = NULL, +}; + +static GOptionEntry entries[] = { + {"config", 'c', 0, G_OPTION_ARG_STRING, &config, + "Config file to use", NULL}, + {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL} +}; + +static const char * +rspamadm_configwizard_help (gboolean full_help) +{ + const char *help_str; + + if (full_help) { + help_str = "Perform initial configuration for Rspamd daemon\n\n" + "Usage: rspamadm configwizard [-c <config_name>]\n" + "Where options are:\n\n" + "--help: shows available options and commands"; + } + else { + help_str = "Perform initial configuration for Rspamd daemon"; + } + + return help_str; +} + +static void +config_logger (rspamd_mempool_t *pool, gpointer ud) +{ + struct rspamd_main *rm = ud; + + rm->cfg->log_type = RSPAMD_LOG_CONSOLE; + rm->cfg->log_level = G_LOG_LEVEL_CRITICAL; + + rspamd_set_logger (rm->cfg, g_quark_try_string ("main"), &rm->logger, + rm->server_pool); + + if (rspamd_log_open_priv (rm->logger, rm->workers_uid, rm->workers_gid) == + -1) { + fprintf (stderr, "Fatal error, cannot open logfile, exiting\n"); + exit (EXIT_FAILURE); + } +} + +static void +rspamadm_configwizard (gint argc, gchar **argv) +{ + GOptionContext *context; + GError *error = NULL; + const gchar *confdir; + struct rspamd_config *cfg = rspamd_main->cfg; + gboolean ret = TRUE; + worker_t **pworker; + lua_State *L; + gint i; + + context = g_option_context_new ( + "keypair - create encryption keys"); + g_option_context_set_summary (context, + "Summary:\n Rspamd administration utility version " + RVERSION + "\n Release id: " + RID); + 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); + g_error_free (error); + exit (1); + } + + if (config == NULL) { + if ((confdir = g_hash_table_lookup (ucl_vars, "CONFDIR")) == NULL) { + confdir = RSPAMD_CONFDIR; + } + + config = g_strdup_printf ("%s%c%s", confdir, G_DIR_SEPARATOR, + "rspamd.conf"); + } + + pworker = &workers[0]; + while (*pworker) { + /* Init string quarks */ + (void) g_quark_from_static_string ((*pworker)->name); + pworker++; + } + + cfg->cache = rspamd_symbols_cache_new (cfg); + cfg->compiled_modules = modules; + cfg->compiled_workers = workers; + cfg->cfg_name = config; + + if (!rspamd_config_read (cfg, cfg->cfg_name, NULL, + config_logger, rspamd_main, ucl_vars)) { + ret = FALSE; + } + else { + /* Do post-load actions */ + rspamd_lua_post_load_config (cfg); + + if (!rspamd_init_filters (rspamd_main->cfg, FALSE)) { + ret = FALSE; + } + + if (ret) { + ret = rspamd_config_post_load (cfg, RSPAMD_CONFIG_INIT_SYMCACHE); + } + } + + if (ret) { + L = cfg->lua_state; + ucl_object_insert_key (cfg->rcl_obj, ucl_object_fromstring (cfg->cfg_name), + "config_path", 0, false); + + rspamadm_execute_lua_ucl_subr (L, + argc, + argv, + cfg->rcl_obj, + "configwizard"); + + lua_close (L); + } + + exit (ret ? EXIT_SUCCESS : EXIT_FAILURE); +} |