aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lualib/rspamadm/configwizard.lua190
-rw-r--r--src/rspamadm/CMakeLists.txt1
-rw-r--r--src/rspamadm/commands.c2
-rw-r--r--src/rspamadm/configwizard.c164
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);
+}