X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=prosodyctl;h=1a487fb5f54dbb5b8b897ee3f226f51eea09ebf0;hb=36c567ebc96fc65b364b348d8603412bd127b856;hp=d9ae9b736ce0cbb1f8724845a536fb7112188e3f;hpb=c49aa28dbba39243deba5502639e801d8ebeb3aa;p=prosody.git diff --git a/prosodyctl b/prosodyctl index d9ae9b73..1a487fb5 100755 --- a/prosodyctl +++ b/prosodyctl @@ -220,6 +220,7 @@ local error_messages = setmetatable({ ["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-such-method"] = "This module has no commands"; ["not-running"] = "Prosody is not running"; @@ -243,13 +244,14 @@ end local modulemanager = require "core.modulemanager" local prosodyctl = require "util.prosodyctl" -require "socket" +local socket = require "socket" ----------------------- -- 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(); @@ -257,7 +259,9 @@ function read_version() prosody.version = "hg:"..prosody.version; end else - prosody.version = "unknown"; + local hg = require"util.mercurial"; + local hgid = hg.check_id(CFG_SOURCEDIR or "."); + if hgid then prosody.version = "hg:" .. hgid; end end end @@ -268,13 +272,14 @@ local show_yesno = prosodyctl.show_yesno; local show_prompt = prosodyctl.show_prompt; 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 commands = {}; local command = arg[1]; function commands.adduser(arg) - local jid_split = require "util.jid".split; if not arg[1] or arg[1] == "--help" then show_usage([[adduser JID]], [[Create the specified user account in Prosody]]); return 1; @@ -314,7 +319,6 @@ function commands.adduser(arg) end function commands.passwd(arg) - local jid_split = require "util.jid".split; if not arg[1] or arg[1] == "--help" then show_usage([[passwd JID]], [[Set the password for the specified user account in Prosody]]); return 1; @@ -354,7 +358,6 @@ function commands.passwd(arg) end function commands.deluser(arg) - local jid_split = require "util.jid".split; if not arg[1] or arg[1] == "--help" then show_usage([[deluser JID]], [[Permanently remove the specified user account from Prosody]]); return 1; @@ -373,7 +376,6 @@ function commands.deluser(arg) if not 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); end @@ -529,16 +531,32 @@ function commands.about(arg) 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; print("Prosody "..(prosody.version or "(unknown version)")); print(""); print("# Prosody directories"); - print("Data directory: ", CFG_DATADIR or "./"); - print("Plugin directory:", CFG_PLUGINDIR or "./"); - print("Config directory:", CFG_CONFIGDIR or "./"); - print("Source directory:", CFG_SOURCEDIR or "./"); + print("Data directory: "..relpath(pwd, data_path)); + print("Config directory: "..relpath(pwd, CFG_CONFIGDIR or ".")); + print("Source directory: "..relpath(pwd, CFG_SOURCEDIR or ".")); + print("Plugin directories:") + print(" "..(prosody.paths.plugins:gsub("([^;]+);?", function(path) + local opath = path; + path = config.resolve_relative_path(pwd, path); + local hgid, hgrepo = hg.check_id(path); + if not hgid and hgrepo then + return path.." - "..hgrepo .."!\n "; + end + -- 010452cfaf53 is the first commit in the prosody-modules repository + hgrepo = hgrepo == "010452cfaf53" and "prosody-modules"; + return path..(hgid and " - "..(hgrepo or "HG").." rev: "..hgid or "") + .."\n "; + end))); print(""); print("# Lua environment"); print("Lua version: ", _G._VERSION); @@ -553,13 +571,15 @@ function commands.about(arg) print(" "..path); end print(""); - local luarocks_status = (pcall(require, "luarocks.loader") and "Installed ("..(luarocks.cfg.program_version or "2.x+")..")") + 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"; 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"; for name, module in pairs(package.loaded) do if type(module) == "table" and rawget(module, "_VERSION") and name ~= "_G" and not name:match("%.") then @@ -655,14 +675,26 @@ local lfs; local cert_commands = {}; -local function ask_overwrite(filename) - return lfs.attributes(filename) and not show_yesno("Overwrite "..filename .. "?"); +-- If a file already exists, ask if the user wants to use it or replace it +-- Backups the old file if replaced +local function use_existing(filename) + local attrs = lfs.attributes(filename); + if attrs then + if show_yesno(filename .. " exists, do you want to replace it? [y/n]") then + local backup = filename..".bkp~"..os.date("%FT%T", attrs.change); + os.rename(filename, backup); + show_message(filename.." backed up to "..backup); + else + -- Use the existing file + return true; + end + end end function cert_commands.config(arg) if #arg >= 1 and arg[1] ~= "--help" then local conf_filename = (CFG_DATADIR or "./certs") .. "/" .. arg[1] .. ".cnf"; - if ask_overwrite(conf_filename) then + if use_existing(conf_filename) then return nil, conf_filename; end local conf = openssl.config.new(); @@ -710,7 +742,7 @@ end function cert_commands.key(arg) if #arg >= 1 and arg[1] ~= "--help" then local key_filename = (CFG_DATADIR or "./certs") .. "/" .. arg[1] .. ".key"; - if ask_overwrite(key_filename) then + if use_existing(key_filename) then return nil, key_filename; end os.remove(key_filename); -- This file, if it exists is unlikely to have write permissions @@ -732,12 +764,12 @@ end function cert_commands.request(arg) if #arg >= 1 and arg[1] ~= "--help" then local req_filename = (CFG_DATADIR or "./certs") .. "/" .. arg[1] .. ".req"; - if ask_overwrite(req_filename) then + if use_existing(req_filename) then return nil, req_filename; end local _, key_filename = cert_commands.key({arg[1]}); local _, conf_filename = cert_commands.config(arg); - if openssl.req{new=true, key=key_filename, utf8=true, config=conf_filename, out=req_filename} then + if openssl.req{new=true, key=key_filename, utf8=true, sha256=true, config=conf_filename, out=req_filename} then show_message("Certificate request written to ".. req_filename); else show_message("There was a problem, see OpenSSL output"); @@ -750,7 +782,7 @@ end function cert_commands.generate(arg) if #arg >= 1 and arg[1] ~= "--help" then local cert_filename = (CFG_DATADIR or "./certs") .. "/" .. arg[1] .. ".crt"; - if ask_overwrite(cert_filename) then + if use_existing(cert_filename) then return nil, cert_filename; end local _, key_filename = cert_commands.key({arg[1]}); @@ -758,8 +790,10 @@ function cert_commands.generate(arg) local ret; if key_filename and conf_filename and cert_filename and openssl.req{new=true, x509=true, nodes=true, key=key_filename, - days=365, sha1=true, utf8=true, config=conf_filename, out=cert_filename} then + days=365, sha256=true, utf8=true, config=conf_filename, out=cert_filename} then show_message("Certificate written to ".. cert_filename); + print(); + show_message(("Example config:\n\nssl = {\n\tcertificate = %q;\n\tkey = %q;\n}"):format(cert_filename, key_filename)); else show_message("There was a problem, see OpenSSL output"); end @@ -817,11 +851,12 @@ function commands.check(arg) if not what or what == "config" then print("Checking config..."); local deprecated = set.new({ - "bosh_ports", "disallow_s2s", "no_daemonize", "anonymous_login", + "bosh_ports", "disallow_s2s", "no_daemonize", "anonymous_login", "require_encryption", }); local known_global_options = set.new({ "pidfile", "log", "plugin_paths", "prosody_user", "prosody_group", "daemonize", - "umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings" + "umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings", + "network_backend", "http_default_host", }); local config = config.getconfig(); -- Check that we have any global options (caused by putting a host at the top) @@ -842,6 +877,20 @@ function commands.check(arg) print(" All hosts are disabled. Remove enabled = false from at least one VirtualHost section") end end + if not config["*"].modules_enabled then + print(" No global modules_enabled is set?"); + local suggested_global_modules; + for host, options in enabled_hosts() do + 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 + end + if not suggested_global_modules:empty() then + print(" Consider moving these modules into modules_enabled in the global section:") + print(" "..tostring(suggested_global_modules / function (x) return ("%q"):format(x) end)); + end + print(); + 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); @@ -857,7 +906,7 @@ function commands.check(arg) for name in pairs(options) do if name:match("^interfaces?") or name:match("_ports?$") or name:match("_interfaces?$") - or name:match("_ssl$") then + or (name:match("_ssl$") and not name:match("^[cs]2s_ssl$")) then misplaced_options:add(name); end end @@ -880,6 +929,66 @@ function commands.check(arg) print(" For more information see: http://prosody.im/doc/dns"); end end + local all_modules = set.new(config["*"].modules_enabled); + local all_options = set.new(it.to_array(it.keys(config["*"]))); + for host in enabled_hosts() do + all_options:include(set.new(it.to_array(it.keys(config[host])))); + all_modules:include(set.new(config[host].modules_enabled)); + end + for mod in all_modules do + if mod:match("^mod_") then + print(""); + print(" Modules in modules_enabled should not have the 'mod_' prefix included."); + print(" Change '"..mod.."' to '"..mod:match("^mod_(.*)").."'."); + elseif mod:match("^auth_") then + print(""); + print(" Authentication modules should not be added to modules_enabled,"); + print(" but be specified in the 'authentication' option."); + print(" Remove '"..mod.."' from modules_enabled and instead add"); + print(" authentication = '"..mod:match("^auth_(.*)").."'"); + print(" For more information see https://prosody.im/doc/authentication"); + elseif mod:match("^storage_") then + print(""); + print(" storage modules should not be added to modules_enabled,"); + print(" but be specified in the 'storage' option."); + print(" Remove '"..mod.."' from modules_enabled and instead add"); + print(" storage = '"..mod:match("^storage_(.*)").."'"); + print(" For more information see https://prosody.im/doc/storage"); + end + end + local ssl = dependencies.softreq"ssl"; + if not ssl then + if not set.intersection(all_options, set.new({"require_encryption", "c2s_require_encryption", "s2s_require_encryption"})):empty() then + print(""); + print(" You require encryption but LuaSec is not available."); + print(" Connections will fail."); + ok = false; + end + elseif not ssl.loadcertificate then + if all_options:contains("s2s_secure_auth") then + print(""); + print(" You have set s2s_secure_auth but your version of LuaSec does "); + print(" not support certificate validation, so all s2s connections will"); + print(" fail."); + ok = false; + elseif all_options:contains("s2s_secure_domains") then + local secure_domains = set.new(); + for host in enabled_hosts() do + if config[host].s2s_secure_auth == true then + secure_domains:add("*"); + else + secure_domains:include(set.new(config[host].s2s_secure_domains)); + end + end + if not secure_domains:empty() then + print(""); + print(" You have set s2s_secure_domains but your version of LuaSec does "); + print(" not support certificate validation, so s2s connections to/from "); + print(" these domains will fail."); + ok = false; + end + end + end print("Done.\n"); end @@ -985,8 +1094,8 @@ function commands.check(arg) target_hosts:remove("localhost"); end - local modules = set.new(it.to_array(it.values(host_options.modules_enabled))) - + set.new(it.to_array(it.values(config.get("*", "modules_enabled")))) + 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") }); if modules:contains("proxy65") then @@ -1076,7 +1185,7 @@ function commands.check(arg) local x509_verify_identity = require"util.x509".verify_identity; local ssl = dependencies.softreq"ssl"; -- local datetime_parse = require"util.datetime".parse_x509; - local load_cert = ssl and ssl.x509 and ssl.x509.load; + local load_cert = ssl and ssl.loadcertificate; -- or ssl.cert_from_pem if not ssl then print("LuaSec not available, can't perform certificate checks") @@ -1128,7 +1237,7 @@ function commands.check(arg) end if (not (config.get(host, "anonymous_login") or config.get(host, "authentication") == "anonymous")) - and not x509_verify_identity(host, "_xmpp-client", cert) then + and not x509_verify_identity(host, "_xmpp-server", cert) then print(" Not vaild for server-to-server connections to "..host..".") cert_ok = false end