diff options
Diffstat (limited to 'prosodyctl')
-rwxr-xr-x | prosodyctl | 640 |
1 files changed, 237 insertions, 403 deletions
@@ -20,8 +20,8 @@ CFG_DATADIR=CFG_DATADIR or os.getenv("PROSODY_DATADIR"); local function is_relative(path) local path_sep = package.config:sub(1,1); - return ((path_sep == "/" and path:sub(1,1) ~= "/") - or (path_sep == "\\" and (path:sub(1,1) ~= "/" and path:sub(2,3) ~= ":\\"))) + return ((path_sep == "/" and path:sub(1,1) ~= "/") + or (path_sep == "\\" and (path:sub(1,1) ~= "/" and path:sub(2,3) ~= ":\\"))) end -- Tell Lua where to find our libraries @@ -43,190 +43,12 @@ if CFG_DATADIR then end end --- Global 'prosody' object -local prosody = { - hosts = {}; - events = require "util.events".new(); - platform = "posix"; - lock_globals = function () end; - unlock_globals = function () end; - installed = CFG_SOURCEDIR ~= nil; - core_post_stanza = function () end; -- TODO: mod_router! -}; -_G.prosody = prosody; - -local dependencies = require "util.dependencies"; -if not dependencies.check_dependencies() then - os.exit(1); -end - -config = require "core.configmanager" - -local ENV_CONFIG; -do - local filenames = {}; - - local filename; - if arg[1] == "--config" and arg[2] then - table.insert(filenames, arg[2]); - if CFG_CONFIGDIR then - table.insert(filenames, CFG_CONFIGDIR.."/"..arg[2]); - end - table.remove(arg, 1); table.remove(arg, 1); - else - for _, format in ipairs(config.parsers()) do - table.insert(filenames, (CFG_CONFIGDIR or ".").."/prosody.cfg."..format); - end - end - for _,_filename in ipairs(filenames) do - filename = _filename; - local file = io.open(filename); - if file then - file:close(); - ENV_CONFIG = filename; - CFG_CONFIGDIR = filename:match("^(.*)[\\/][^\\/]*$"); - break; - end - end - local ok, level, err = config.load(filename); - if not ok then - print("\n"); - print("**************************"); - if level == "parser" then - print("A problem occured while reading the config file "..filename); - local err_line, err_message = tostring(err):match("%[string .-%]:(%d*): (.*)"); - print("Error"..(err_line and (" on line "..err_line) or "")..": "..(err_message or tostring(err))); - print(""); - elseif level == "file" then - print("Prosody was unable to find the configuration file."); - print("We looked for: "..filename); - print("A sample config file is included in the Prosody download called prosody.cfg.lua.dist"); - print("Copy or rename it to prosody.cfg.lua and edit as necessary."); - end - print("More help on configuring Prosody can be found at http://prosody.im/doc/configure"); - print("Good luck!"); - print("**************************"); - print(""); - os.exit(1); - end -end -local original_logging_config = config.get("*", "log"); -config.set("*", "log", { { levels = { min = os.getenv("PROSODYCTL_LOG_LEVEL") or "info" }, to = "console" } }); - -local data_path = config.get("*", "data_path") or CFG_DATADIR or "data"; -local custom_plugin_paths = config.get("*", "plugin_paths"); -if custom_plugin_paths then - local path_sep = package.config:sub(3,3); - -- path1;path2;path3;defaultpath... - CFG_PLUGINDIR = table.concat(custom_plugin_paths, path_sep)..path_sep..(CFG_PLUGINDIR or "plugins"); -end -prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR, - plugins = CFG_PLUGINDIR or "plugins", data = data_path }; - -if prosody.installed then - -- Change working directory to data path. - require "lfs".chdir(data_path); -end +----------- -require "core.loggingmanager" - -dependencies.log_warnings(); - --- Switch away from root and into the prosody user -- -local switched_user, current_uid; - -local want_pposix_version = "0.4.0"; -local have_pposix, pposix = pcall(require, "util.pposix"); - -if have_pposix and pposix then - if pposix._VERSION ~= want_pposix_version then - print(string.format("Unknown version (%s) of binary pposix module, expected %s", - tostring(pposix._VERSION), want_pposix_version)); return; - end - current_uid = pposix.getuid(); - local arg_root = arg[1] == "--root"; - if arg_root then table.remove(arg, 1); end - if current_uid == 0 and config.get("*", "run_as_root") ~= true and not arg_root then - -- We haz root! - local desired_user = config.get("*", "prosody_user") or "prosody"; - local desired_group = config.get("*", "prosody_group") or desired_user; - local ok, err = pposix.setgid(desired_group); - if ok then - ok, err = pposix.initgroups(desired_user); - end - if ok then - ok, err = pposix.setuid(desired_user); - if ok then - -- Yay! - switched_user = true; - end - end - if not switched_user then - -- Boo! - print("Warning: Couldn't switch to Prosody user/group '"..tostring(desired_user).."'/'"..tostring(desired_group).."': "..tostring(err)); - else - -- Make sure the Prosody user can read the config - local conf, err, errno = io.open(ENV_CONFIG); - if conf then - conf:close(); - else - print("The config file is not readable by the '"..desired_user.."' user."); - print("Prosody will not be able to read it."); - print("Error was "..err); - os.exit(1); - end - end - end - - -- Set our umask to protect data files - pposix.umask(config.get("*", "umask") or "027"); - pposix.setenv("HOME", data_path); - pposix.setenv("PROSODY_CONFIG", ENV_CONFIG); -else - print("Error: Unable to load pposix module. Check that Prosody is installed correctly.") - print("For more help send the below error to us through http://prosody.im/discuss"); - print(tostring(pposix)) - os.exit(1); -end - -local function test_writeable(filename) - local f, err = io.open(filename, "a"); - if not f then - return false, err; - end - f:close(); - return true; -end - -local unwriteable_files = {}; -if type(original_logging_config) == "string" and original_logging_config:sub(1,1) ~= "*" then - local ok, err = test_writeable(original_logging_config); - if not ok then - table.insert(unwriteable_files, err); - end -elseif type(original_logging_config) == "table" then - for _, rule in ipairs(original_logging_config) do - if rule.filename then - local ok, err = test_writeable(rule.filename); - if not ok then - table.insert(unwriteable_files, err); - end - end - end -end - -if #unwriteable_files > 0 then - print("One of more of the Prosody log files are not"); - print("writeable, please correct the errors and try"); - print("starting prosodyctl again."); - print(""); - for _, err in ipairs(unwriteable_files) do - print(err); - end - print(""); - os.exit(1); -end +local startup = require "util.startup"; +startup.prosodyctl(); +----------- local error_messages = setmetatable({ ["invalid-username"] = "The given username is invalid in a Jabber ID"; @@ -235,60 +57,21 @@ local error_messages = setmetatable({ ["no-such-user"] = "The given user does not exist on the server"; ["no-such-host"] = "The given hostname does not exist in the config"; ["unable-to-save-data"] = "Unable to store, perhaps you don't have permission?"; - ["no-pidfile"] = "There is no 'pidfile' option in the configuration file, see http://prosody.im/doc/prosodyctl#pidfile for help"; - ["invalid-pidfile"] = "The 'pidfile' option in the configuration file is not a string, see http://prosody.im/doc/prosodyctl#pidfile for help"; - ["no-posix"] = "The mod_posix module is not enabled in the Prosody config file, see http://prosody.im/doc/prosodyctl for more info"; + ["no-pidfile"] = "There is no 'pidfile' option in the configuration file, see https://prosody.im/doc/prosodyctl#pidfile for help"; + ["invalid-pidfile"] = "The 'pidfile' option in the configuration file is not a string, see https://prosody.im/doc/prosodyctl#pidfile for help"; + ["no-posix"] = "The mod_posix module is not enabled in the Prosody config file, see https://prosody.im/doc/prosodyctl for more info"; ["no-such-method"] = "This module has no commands"; ["not-running"] = "Prosody is not running"; - }, { __index = function (t,k) return "Error: "..(tostring(k):gsub("%-", " "):gsub("^.", string.upper)); end }); - -hosts = prosody.hosts; - -local function make_host(hostname) - return { - type = "local", - events = prosody.events, - modules = {}, - sessions = {}, - users = require "core.usermanager".new_null_provider(hostname) - }; -end - -for hostname, config in pairs(config.getconfig()) do - hosts[hostname] = make_host(hostname); -end + }, { __index = function (_,k) return "Error: "..(tostring(k):gsub("%-", " "):gsub("^.", string.upper)); end }); +local configmanager = require "core.configmanager"; local modulemanager = require "core.modulemanager" - local prosodyctl = require "util.prosodyctl" local socket = require "socket" - -local http = require "net.http" -local config_ssl = config.get("*", "ssl") or {} -local https_client = config.get("*", "client_https_ssl") -http.default.options.sslctx = require "core.certmanager".create_context("client_https port 0", "client", - { capath = config_ssl.capath, cafile = config_ssl.cafile, verify = "peer", }, https_client); +local dependencies = require "util.dependencies"; ----------------------- --- FIXME: Duplicate code waiting for util.startup -function read_version() - -- Try to determine version - local version_file = io.open((CFG_SOURCEDIR or ".").."/prosody.version"); - prosody.version = "unknown"; - if version_file then - prosody.version = version_file:read("*a"):gsub("%s*$", ""); - version_file:close(); - if #prosody.version == 12 and prosody.version:match("^[a-f0-9]+$") then - prosody.version = "hg:"..prosody.version; - end - else - local hg = require"util.mercurial"; - local hgid = hg.check_id(CFG_SOURCEDIR or "."); - if hgid then prosody.version = "hg:" .. hgid; end - end -end - local show_message, show_warning = prosodyctl.show_message, prosodyctl.show_warning; local show_usage = prosodyctl.show_usage; local show_yesno = prosodyctl.show_yesno; @@ -297,7 +80,7 @@ local read_password = prosodyctl.read_password; local jid_split = require "util.jid".prepped_split; -local prosodyctl_timeout = (config.get("*", "prosodyctl_timeout") or 5) * 2; +local prosodyctl_timeout = (configmanager.get("*", "prosodyctl_timeout") or 5) * 2; ----------------------- local commands = {}; local command = arg[1]; @@ -319,10 +102,10 @@ function commands.adduser(arg) return 1; end - if not hosts[host] then + if not prosody.hosts[host] then show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host) show_warning("The user will not be able to log in until this is changed."); - hosts[host] = make_host(host); + prosody.hosts[host] = startup.make_host(host); --luacheck: ignore 122 end if prosodyctl.user_exists{ user = user, host = host } then @@ -358,10 +141,10 @@ function commands.passwd(arg) return 1; end - if not hosts[host] then + if not prosody.hosts[host] then show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host) show_warning("The user will not be able to log in until this is changed."); - hosts[host] = make_host(host); + prosody.hosts[host] = startup.make_host(host); --luacheck: ignore 122 end if not prosodyctl.user_exists { user = user, host = host } then @@ -397,9 +180,9 @@ function commands.deluser(arg) return 1; end - if not hosts[host] then + if not prosody.hosts[host] then show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host) - hosts[host] = make_host(host); + prosody.hosts[host] = startup.make_host(host); --luacheck: ignore 122 end if not prosodyctl.user_exists { user = user, host = host } then @@ -427,6 +210,7 @@ function commands.start(arg) end if ret then + --luacheck: ignore 421/ret local ok, ret = prosodyctl.getpid(); if not ok then show_message("Couldn't get running Prosody's PID"); @@ -437,9 +221,10 @@ function commands.start(arg) return 1; end - local ok, ret = prosodyctl.start(); + --luacheck: ignore 411/ret + local ok, ret = prosodyctl.start(prosody.paths.source); if ok then - local daemonize = config.get("*", "daemonize"); + local daemonize = configmanager.get("*", "daemonize"); if daemonize == nil then daemonize = prosody.installed; end @@ -481,6 +266,7 @@ function commands.status(arg) end if ret then + --luacheck: ignore 421/ret local ok, ret = prosodyctl.getpid(); if not ok then show_message("Couldn't get running Prosody's PID"); @@ -491,7 +277,7 @@ function commands.status(arg) return 0; else show_message("Prosody is not running"); - if not switched_user and current_uid ~= 0 then + if not prosody.switched_user and prosody.current_uid ~= 0 then print("\nNote:") print(" You will also see this if prosodyctl is not running under"); print(" the same user account as Prosody. Try running as root (e.g. "); @@ -499,7 +285,6 @@ function commands.status(arg) end return 2 end - return 1; end function commands.stop(arg) @@ -548,28 +333,26 @@ function commands.restart(arg) end function commands.about(arg) - read_version(); if arg[1] == "--help" then show_usage([[about]], [[Show information about this Prosody installation]]); return 1; end local pwd = "."; - local lfs = require "lfs"; local array = require "util.array"; local keys = require "util.iterators".keys; local hg = require"util.mercurial"; - local relpath = config.resolve_relative_path; + local relpath = configmanager.resolve_relative_path; print("Prosody "..(prosody.version or "(unknown version)")); print(""); print("# Prosody directories"); - print("Data directory: "..relpath(pwd, data_path)); - print("Config directory: "..relpath(pwd, CFG_CONFIGDIR or ".")); - print("Source directory: "..relpath(pwd, CFG_SOURCEDIR or ".")); + print("Data directory: "..relpath(pwd, prosody.paths.data)); + print("Config directory: "..relpath(pwd, prosody.paths.config or ".")); + print("Source directory: "..relpath(pwd, prosody.paths.source or ".")); print("Plugin directories:") print(" "..(prosody.paths.plugins:gsub("([^;]+);?", function(path) - path = config.resolve_relative_path(pwd, path); + path = configmanager.resolve_relative_path(pwd, path); local hgid, hgrepo = hg.check_id(path); if not hgid and hgrepo then return path.." - "..hgrepo .."!\n "; @@ -593,15 +376,21 @@ function commands.about(arg) print(" "..path); end print(""); - local luarocks_status = (pcall(require, "luarocks.loader") and "Installed ("..(package.loaded["luarocks.cfg"].program_version or "2.x+")..")") - or (pcall(require, "luarocks.require") and "Installed (1.x)") - or "Not installed"; + local luarocks_status = "Not installed" + if pcall(require, "luarocks.loader") then + luarocks_status = "Installed (2.x+)"; + if package.loaded["luarocks.cfg"] then + luarocks_status = "Installed ("..(package.loaded["luarocks.cfg"].program_version or "2.x+")..")"; + end + elseif pcall(require, "luarocks.require") then + luarocks_status = "Installed (1.x)"; + end print("LuaRocks: ", luarocks_status); print(""); print("# Lua module versions"); local module_versions, longest_name = {}, 8; local luaevent =dependencies.softreq"luaevent"; - local ssl = dependencies.softreq"ssl"; + dependencies.softreq"ssl"; for name, module in pairs(package.loaded) do if type(module) == "table" and rawget(module, "_VERSION") and name ~= "_G" and not name:match("%.") then @@ -718,11 +507,12 @@ local function use_existing(filename) end end -local cert_basedir = CFG_DATADIR or "./certs"; +local have_pposix, pposix = pcall(require, "util.pposix"); +local cert_basedir = prosody.paths.data == "." and "./certs" or prosody.paths.data; if have_pposix and pposix.getuid() == 0 then -- FIXME should be enough to check if this directory is writable - local cert_dir = config.get("*", "certificates") or "certs"; - cert_basedir = config.resolve_relative_path(prosody.paths.config, cert_dir); + local cert_dir = configmanager.get("*", "certificates") or "certs"; + cert_basedir = configmanager.resolve_relative_path(prosody.paths.config, cert_dir); end function cert_commands.config(arg) @@ -736,7 +526,7 @@ function cert_commands.config(arg) distinguished_name = table.remove(arg); end local conf = openssl.config.new(); - conf:from_prosody(hosts, config, arg); + conf:from_prosody(prosody.hosts, configmanager, arg); if distinguished_name then local dn = {}; for k, v in distinguished_name:gmatch("/([^=/]+)=([^/]+)") do @@ -750,7 +540,7 @@ function cert_commands.config(arg) for _, k in ipairs(openssl._DN_order) do local v = conf.distinguished_name[k]; if v then - local nv; + local nv = nil; if k == "commonName" then v = arg[1] elseif k == "emailAddress" then @@ -889,7 +679,7 @@ function cert_commands.import(arg) end else for host in pairs(prosody.hosts) do - if host ~= "*" and config.get(host, "enabled") ~= false then + if host ~= "*" and configmanager.get(host, "enabled") ~= false then table.insert(hostnames, host); end end @@ -902,8 +692,8 @@ function cert_commands.import(arg) end local owner, group; if pposix.getuid() == 0 then -- We need root to change ownership - owner = config.get("*", "prosody_user") or "prosody"; - group = config.get("*", "prosody_group") or owner; + owner = configmanager.get("*", "prosody_user") or "prosody"; + group = configmanager.get("*", "prosody_group") or owner; end local cm = require "core.certmanager"; local imported = {}; @@ -961,7 +751,7 @@ function commands.cert(arg) show_message"You need to supply at least one hostname" arg = { "--help" }; end - if arg[1] ~= "--help" and not hosts[arg[1]] then + if arg[1] ~= "--help" and not prosody.hosts[arg[1]] then show_message(error_messages["no-such-host"]); return 1; end @@ -984,22 +774,22 @@ function commands.check(arg) return 1; end local what = table.remove(arg, 1); - local array, set = require "util.array", require "util.set"; + local set = require "util.set"; local it = require "util.iterators"; local ok = true; local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end - local function enabled_hosts() return it.filter(disabled_hosts, pairs(config.getconfig())); end + local function enabled_hosts() return it.filter(disabled_hosts, pairs(configmanager.getconfig())); end if not what or what == "disabled" then - local disabled_hosts = set.new(); - for host, host_options in it.filter("*", pairs(config.getconfig())) do + local disabled_hosts_set = set.new(); + for host, host_options in it.filter("*", pairs(configmanager.getconfig())) do if host_options.enabled == false then - disabled_hosts:add(host); + disabled_hosts_set:add(host); end end - if not disabled_hosts:empty() then + if not disabled_hosts_set:empty() then local msg = "Checks will be skipped for these disabled hosts: %s"; if what then msg = "These hosts are disabled: %s"; end - show_warning(msg, tostring(disabled_hosts)); + show_warning(msg, tostring(disabled_hosts_set)); if what then return 0; end print"" end @@ -1015,13 +805,13 @@ function commands.check(arg) "umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings", "network_backend", "http_default_host", }); - local config = config.getconfig(); + local config = configmanager.getconfig(); -- Check that we have any global options (caused by putting a host at the top) if it.count(it.filter("log", pairs(config["*"]))) == 0 then ok = false; print(""); print(" No global options defined. Perhaps you have put a host definition at the top") - print(" of the config file? They should be at the bottom, see http://prosody.im/doc/configure#overview"); + print(" of the config file? They should be at the bottom, see https://prosody.im/doc/configure#overview"); end if it.count(enabled_hosts()) == 0 then ok = false; @@ -1037,7 +827,7 @@ function commands.check(arg) if not config["*"].modules_enabled then print(" No global modules_enabled is set?"); local suggested_global_modules; - for host, options in enabled_hosts() do + for host, options in enabled_hosts() do --luacheck: ignore 213/host if not options.component_module and options.modules_enabled then suggested_global_modules = set.intersection(suggested_global_modules or set.new(options.modules_enabled), set.new(options.modules_enabled)); end @@ -1048,6 +838,19 @@ function commands.check(arg) end print(); end + + do -- Check for modules enabled both normally and as components + local modules = set.new(config["*"]["modules_enabled"]); + for host, options in enabled_hosts() do + local component_module = options.component_module; + if component_module and modules:contains(component_module) then + print((" mod_%s is enabled both in modules_enabled and as Component %q %q"):format(component_module, host, component_module)); + print(" This means the service is enabled on all VirtualHosts as well as the Component."); + print(" Are you sure this what you want? It may cause unexpected behaviour."); + end + end + end + -- Check for global options under hosts local global_options = set.new(it.to_array(it.keys(config["*"]))); local deprecated_global_options = set.intersection(global_options, deprecated); @@ -1073,17 +876,17 @@ function commands.check(arg) local n = it.count(misplaced_options); print(" You have "..n.." option"..(n>1 and "s " or " ").."set under "..host.." that should be"); print(" in the global section of the config file, above any VirtualHost or Component definitions,") - print(" see http://prosody.im/doc/configure#overview for more information.") + print(" see https://prosody.im/doc/configure#overview for more information.") print(""); print(" You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", ")); end local subdomain = host:match("^[^.]+"); if not(host_options:contains("component_module")) and (subdomain == "jabber" or subdomain == "xmpp" - or subdomain == "chat" or subdomain == "im") then + or subdomain == "chat" or subdomain == "im") then print(""); print(" Suggestion: If "..host.. " is a new host with no real users yet, consider renaming it now to"); print(" "..host:gsub("^[^.]+%.", "")..". You can use SRV records to redirect XMPP clients and servers to "..host.."."); - print(" For more information see: http://prosody.im/doc/dns"); + print(" For more information see: https://prosody.im/doc/dns"); end end local all_modules = set.new(config["*"].modules_enabled); @@ -1113,14 +916,16 @@ function commands.check(arg) print(" For more information see https://prosody.im/doc/storage"); end end - for host, config in pairs(config) do - if type(rawget(config, "storage")) == "string" and rawget(config, "default_storage") then + for host, host_config in pairs(config) do --luacheck: ignore 213/host + if type(rawget(host_config, "storage")) == "string" and rawget(host_config, "default_storage") then print(""); print(" The 'default_storage' option is not needed if 'storage' is set to a string."); break; end end - local require_encryption = set.intersection(all_options, set.new({"require_encryption", "c2s_require_encryption", "s2s_require_encryption"})):empty(); + local require_encryption = set.intersection(all_options, set.new({ + "require_encryption", "c2s_require_encryption", "s2s_require_encryption" + })):empty(); local ssl = dependencies.softreq"ssl"; if not ssl then if not require_encryption then @@ -1166,8 +971,8 @@ function commands.check(arg) local dns = require "net.dns"; local idna = require "util.encodings".idna; local ip = require "util.ip"; - local c2s_ports = set.new(config.get("*", "c2s_ports") or {5222}); - local s2s_ports = set.new(config.get("*", "s2s_ports") or {5269}); + local c2s_ports = set.new(configmanager.get("*", "c2s_ports") or {5222}); + local s2s_ports = set.new(configmanager.get("*", "s2s_ports") or {5269}); local c2s_srv_required, s2s_srv_required; if not c2s_ports:contains(5222) then @@ -1183,16 +988,20 @@ function commands.check(arg) local fqdn = socket.dns.tohostname(socket.dns.gethostname()); if fqdn then - local res = dns.lookup(idna.to_ascii(fqdn), "A"); - if res then - for _, record in ipairs(res) do - external_addresses:add(record.a); + do + local res = dns.lookup(idna.to_ascii(fqdn), "A"); + if res then + for _, record in ipairs(res) do + external_addresses:add(record.a); + end end end - local res = dns.lookup(idna.to_ascii(fqdn), "AAAA"); - if res then - for _, record in ipairs(res) do - external_addresses:add(record.aaaa); + do + local res = dns.lookup(idna.to_ascii(fqdn), "AAAA"); + if res then + for _, record in ipairs(res) do + external_addresses:add(record.aaaa); + end end end end @@ -1243,20 +1052,22 @@ function commands.check(arg) end end end - local res = dns.lookup("_xmpp-server._tcp."..idna.to_ascii(host)..".", "SRV"); - if res then - for _, record in ipairs(res) do - target_hosts:add(record.srv.target); - if not s2s_ports:contains(record.srv.port) then - print(" SRV target "..record.srv.target.." contains unknown server port: "..record.srv.port); + do + local res = dns.lookup("_xmpp-server._tcp."..idna.to_ascii(host)..".", "SRV"); + if res then + for _, record in ipairs(res) do + target_hosts:add(record.srv.target); + if not s2s_ports:contains(record.srv.port) then + print(" SRV target "..record.srv.target.." contains unknown server port: "..record.srv.port); + end end - end - else - if s2s_srv_required then - print(" No _xmpp-server SRV record found for "..host..", but it looks like you need one."); - all_targets_ok = false; else - target_hosts:add(host); + if s2s_srv_required then + print(" No _xmpp-server SRV record found for "..host..", but it looks like you need one."); + all_targets_ok = false; + else + target_hosts:add(host); + end end end if target_hosts:empty() then @@ -1268,12 +1079,14 @@ function commands.check(arg) target_hosts:remove("localhost"); end - local modules = set.new(it.to_array(it.values(host_options.modules_enabled or {}))) - + set.new(it.to_array(it.values(config.get("*", "modules_enabled") or {}))) - + set.new({ config.get(host, "component_module") }); + local modules, component_module = modulemanager.get_modules_for_host(host); + + if component_module then + modules:add(component_module); + end if modules:contains("proxy65") then - local proxy65_target = config.get(host, "proxy65_address") or host; + local proxy65_target = configmanager.get(host, "proxy65_address") or host; local A, AAAA = dns.lookup(idna.to_ascii(proxy65_target), "A"), dns.lookup(idna.to_ascii(proxy65_target), "AAAA"); local prob = {}; if not A then @@ -1283,41 +1096,46 @@ function commands.check(arg) table.insert(prob, "AAAA"); end if #prob > 0 then - print(" File transfer proxy "..proxy65_target.." has no "..table.concat(prob, "/").." record. Create one or set 'proxy65_address' to the correct host/IP."); + print(" File transfer proxy "..proxy65_target.." has no "..table.concat(prob, "/") + .." record. Create one or set 'proxy65_address' to the correct host/IP."); end end - for host in target_hosts do + for target_host in target_hosts do local host_ok_v4, host_ok_v6; - local res = dns.lookup(idna.to_ascii(host), "A"); - if res then - for _, record in ipairs(res) do - if external_addresses:contains(record.a) then - some_targets_ok = true; - host_ok_v4 = true; - elseif internal_addresses:contains(record.a) then - host_ok_v4 = true; - some_targets_ok = true; - print(" "..host.." A record points to internal address, external connections might fail"); - else - print(" "..host.." A record points to unknown address "..record.a); - all_targets_ok = false; + do + local res = dns.lookup(idna.to_ascii(target_host), "A"); + if res then + for _, record in ipairs(res) do + if external_addresses:contains(record.a) then + some_targets_ok = true; + host_ok_v4 = true; + elseif internal_addresses:contains(record.a) then + host_ok_v4 = true; + some_targets_ok = true; + print(" "..target_host.." A record points to internal address, external connections might fail"); + else + print(" "..target_host.." A record points to unknown address "..record.a); + all_targets_ok = false; + end end end end - local res = dns.lookup(idna.to_ascii(host), "AAAA"); - if res then - for _, record in ipairs(res) do - if external_addresses:contains(record.aaaa) then - some_targets_ok = true; - host_ok_v6 = true; - elseif internal_addresses:contains(record.aaaa) then - host_ok_v6 = true; - some_targets_ok = true; - print(" "..host.." AAAA record points to internal address, external connections might fail"); - else - print(" "..host.." AAAA record points to unknown address "..record.aaaa); - all_targets_ok = false; + do + local res = dns.lookup(idna.to_ascii(target_host), "AAAA"); + if res then + for _, record in ipairs(res) do + if external_addresses:contains(record.aaaa) then + some_targets_ok = true; + host_ok_v6 = true; + elseif internal_addresses:contains(record.aaaa) then + host_ok_v6 = true; + some_targets_ok = true; + print(" "..target_host.." AAAA record points to internal address, external connections might fail"); + else + print(" "..target_host.." AAAA record points to unknown address "..record.aaaa); + all_targets_ok = false; + end end end end @@ -1330,11 +1148,11 @@ function commands.check(arg) table.insert(bad_protos, "IPv6"); end if #bad_protos > 0 then - print(" Host "..host.." does not seem to resolve to this server ("..table.concat(bad_protos, "/")..")"); + print(" Host "..target_host.." does not seem to resolve to this server ("..table.concat(bad_protos, "/")..")"); end if host_ok_v6 and not v6_supported then - print(" Host "..host.." has AAAA records, but your version of LuaSocket does not support IPv6."); - print(" Please see http://prosody.im/doc/ipv6 for more information."); + print(" Host "..target_host.." has AAAA records, but your version of LuaSocket does not support IPv6."); + print(" Please see https://prosody.im/doc/ipv6 for more information."); end end if not all_targets_ok then @@ -1348,7 +1166,7 @@ function commands.check(arg) end if not problem_hosts:empty() then print(""); - print("For more information about DNS configuration please see http://prosody.im/doc/dns"); + print("For more information about DNS configuration please see https://prosody.im/doc/dns"); print(""); ok = false; end @@ -1379,9 +1197,9 @@ function commands.check(arg) for host in it.filter(skip_bare_jid_hosts, enabled_hosts()) do print("Checking certificate for "..host); -- First, let's find out what certificate this host uses. - local host_ssl_config = config.rawget(host, "ssl") - or config.rawget(host:match("%.(.*)"), "ssl"); - local global_ssl_config = config.rawget("*", "ssl"); + local host_ssl_config = configmanager.rawget(host, "ssl") + or configmanager.rawget(host:match("%.(.*)"), "ssl"); + local global_ssl_config = configmanager.rawget("*", "ssl"); local ok, err, ssl_config = create_context(host, "server", host_ssl_config, global_ssl_config); if not ok then print(" Error: "..err); @@ -1406,7 +1224,7 @@ function commands.check(arg) cert_ok = false else print(" Certificate: "..ssl_config.certificate) - local cert = load_cert(cert_fh:read"*a"); cert_fh = cert_fh:close(); + local cert = load_cert(cert_fh:read"*a"); cert_fh:close(); if not cert:validat(os.time()) then print(" Certificate has expired.") cert_ok = false @@ -1418,13 +1236,13 @@ function commands.check(arg) elseif not cert:validat(os.time() + 86400*31) then print(" Certificate expires within one month.") end - if config.get(host, "component_module") == nil + if configmanager.get(host, "component_module") == nil and not x509_verify_identity(host, "_xmpp-client", cert) then print(" Not valid for client connections to "..host..".") cert_ok = false end - if (not (config.get(host, "anonymous_login") - or config.get(host, "authentication") == "anonymous")) + if (not (configmanager.get(host, "anonymous_login") + or configmanager.get(host, "authentication") == "anonymous")) and not x509_verify_identity(host, "_xmpp-server", cert) then print(" Not valid for server-to-server connections to "..host..".") cert_ok = false @@ -1432,11 +1250,11 @@ function commands.check(arg) end end end - if cert_ok == false then - print("") - print("For more information about certificates please see http://prosody.im/doc/certificates"); - ok = false - end + end + if cert_ok == false then + print("") + print("For more information about certificates please see https://prosody.im/doc/certificates"); + ok = false end print("") end @@ -1450,77 +1268,93 @@ end --------------------- -if command and command:match("^mod_") then -- Is a command in a module - local module_name = command:match("^mod_(.+)"); - local ret, err = modulemanager.load("*", module_name); - if not ret then - show_message("Failed to load module '"..module_name.."': "..err); - os.exit(1); - end +local async = require "util.async"; +local server = require "net.server"; +local watchers = { + error = function (_, err) + error(err); + end; + waiting = function () + server.loop(); + end; +}; +local command_runner = async.runner(function () + if command and command:match("^mod_") then -- Is a command in a module + local module_name = command:match("^mod_(.+)"); + do + local ret, err = modulemanager.load("*", module_name); + if not ret then + show_message("Failed to load module '"..module_name.."': "..err); + os.exit(1); + end + end - table.remove(arg, 1); + table.remove(arg, 1); - local module = modulemanager.get_module("*", module_name); - if not module then - show_message("Failed to load module '"..module_name.."': Unknown error"); - os.exit(1); - end + local module = modulemanager.get_module("*", module_name); + if not module then + show_message("Failed to load module '"..module_name.."': Unknown error"); + os.exit(1); + end - if not modulemanager.module_has_method(module, "command") then - show_message("Fail: mod_"..module_name.." does not support any commands"); - os.exit(1); - end + if not modulemanager.module_has_method(module, "command") then + show_message("Fail: mod_"..module_name.." does not support any commands"); + os.exit(1); + end - local ok, ret = modulemanager.call_module_method(module, "command", arg); - if ok then - if type(ret) == "number" then - os.exit(ret); - elseif type(ret) == "string" then - show_message(ret); + local ok, ret = modulemanager.call_module_method(module, "command", arg); + if ok then + if type(ret) == "number" then + os.exit(ret); + elseif type(ret) == "string" then + show_message(ret); + end + os.exit(0); -- :) + else + show_message("Failed to execute command: "..error_messages[ret]); + os.exit(1); -- :( end - os.exit(0); -- :) - else - show_message("Failed to execute command: "..error_messages[ret]); - os.exit(1); -- :( end -end -if not commands[command] then -- Show help for all commands - function show_usage(usage, desc) - print(" "..usage); - print(" "..desc); - end + if not commands[command] then -- Show help for all commands + function show_usage(usage, desc) + print(" "..usage); + print(" "..desc); + end - print("prosodyctl - Manage a Prosody server"); - print(""); - print("Usage: "..arg[0].." COMMAND [OPTIONS]"); - print(""); - print("Where COMMAND may be one of:\n"); + print("prosodyctl - Manage a Prosody server"); + print(""); + print("Usage: "..arg[0].." COMMAND [OPTIONS]"); + print(""); + print("Where COMMAND may be one of:\n"); - local hidden_commands = require "util.set".new{ "register", "unregister", "addplugin" }; - local commands_order = { "adduser", "passwd", "deluser", "start", "stop", "restart", "reload", "about" }; + local hidden_commands = require "util.set".new{ "register", "unregister", "addplugin" }; + local commands_order = { "adduser", "passwd", "deluser", "start", "stop", "restart", "reload", "about" }; - local done = {}; + local done = {}; - for _, command_name in ipairs(commands_order) do - local command = commands[command_name]; - if command then - command{ "--help" }; - print"" - done[command_name] = true; + for _, command_name in ipairs(commands_order) do + local command_func = commands[command_name]; + if command_func then + command_func{ "--help" }; + print"" + done[command_name] = true; + end end - end - for command_name, command in pairs(commands) do - if not done[command_name] and not hidden_commands:contains(command_name) then - command{ "--help" }; - print"" - done[command_name] = true; + for command_name, command_func in pairs(commands) do + if not done[command_name] and not hidden_commands:contains(command_name) then + command_func{ "--help" }; + print"" + done[command_name] = true; + end end - end - os.exit(0); -end + os.exit(0); + end + + os.exit(commands[command]({ select(2, unpack(arg)) })); +end, watchers); -os.exit(commands[command]({ select(2, unpack(arg)) })); +command_runner:run(true); |