]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Feature] Add new configwizard command to rspamadm
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sat, 2 Dec 2017 15:50:47 +0000 (15:50 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sat, 2 Dec 2017 15:50:47 +0000 (15:50 +0000)
lualib/rspamadm/configwizard.lua [new file with mode: 0644]
src/rspamadm/CMakeLists.txt
src/rspamadm/commands.c
src/rspamadm/configwizard.c [new file with mode: 0644]

diff --git a/lualib/rspamadm/configwizard.lua b/lualib/rspamadm/configwizard.lua
new file mode 100644 (file)
index 0000000..164d291
--- /dev/null
@@ -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
+
index 83c91f8a9878e010b2577c57fd58e17bbdb766fe..7dfaad69167c6c0ac9346d52392791a16d82d076 100644 (file)
@@ -9,6 +9,7 @@ SET(RSPAMADMSRC rspamadm.c
         configdump.c
         control.c
         confighelp.c
+        configwizard.c
         stat_convert.c
         signtool.c
         lua_repl.c
index d344dce3c9734d45c6082d88be83668a297a5306..1eaa45c81ecee06a434b831c71653ac085eee467 100644 (file)
@@ -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 (file)
index 0000000..6ff5d25
--- /dev/null
@@ -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);
+}