Comparison

prosodyctl @ 8671:a4899174a894

prosodyctl: Large number of changes to satisfy [luacheck], includes bug fixes
author Matthew Wild <mwild1@gmail.com>
date Thu, 22 Mar 2018 22:33:42 +0000
parent 8668:31c5abd49dfe
child 8701:b7a22baaf55f
comparison
equal deleted inserted replaced
8670:800c648827e3 8671:a4899174a894
43 end 43 end
44 end 44 end
45 45
46 ----------- 46 -----------
47 47
48 require "util.startup".prosodyctl(); 48 local startup = require "util.startup";
49 startup.prosodyctl();
49 50
50 ----------- 51 -----------
51 52
52 local error_messages = setmetatable({ 53 local error_messages = setmetatable({
53 ["invalid-username"] = "The given username is invalid in a Jabber ID"; 54 ["invalid-username"] = "The given username is invalid in a Jabber ID";
59 ["no-pidfile"] = "There is no 'pidfile' option in the configuration file, see https://prosody.im/doc/prosodyctl#pidfile for help"; 60 ["no-pidfile"] = "There is no 'pidfile' option in the configuration file, see https://prosody.im/doc/prosodyctl#pidfile for help";
60 ["invalid-pidfile"] = "The 'pidfile' option in the configuration file is not a string, see https://prosody.im/doc/prosodyctl#pidfile for help"; 61 ["invalid-pidfile"] = "The 'pidfile' option in the configuration file is not a string, see https://prosody.im/doc/prosodyctl#pidfile for help";
61 ["no-posix"] = "The mod_posix module is not enabled in the Prosody config file, see https://prosody.im/doc/prosodyctl for more info"; 62 ["no-posix"] = "The mod_posix module is not enabled in the Prosody config file, see https://prosody.im/doc/prosodyctl for more info";
62 ["no-such-method"] = "This module has no commands"; 63 ["no-such-method"] = "This module has no commands";
63 ["not-running"] = "Prosody is not running"; 64 ["not-running"] = "Prosody is not running";
64 }, { __index = function (t,k) return "Error: "..(tostring(k):gsub("%-", " "):gsub("^.", string.upper)); end }); 65 }, { __index = function (_,k) return "Error: "..(tostring(k):gsub("%-", " "):gsub("^.", string.upper)); end });
65 66
66 local config = require "core.configmanager"; 67 local configmanager = require "core.configmanager";
67 local modulemanager = require "core.modulemanager" 68 local modulemanager = require "core.modulemanager"
68 local prosodyctl = require "util.prosodyctl" 69 local prosodyctl = require "util.prosodyctl"
69 local socket = require "socket" 70 local socket = require "socket"
70 local dependencies = require "util.dependencies"; 71 local dependencies = require "util.dependencies";
71 72
77 local show_prompt = prosodyctl.show_prompt; 78 local show_prompt = prosodyctl.show_prompt;
78 local read_password = prosodyctl.read_password; 79 local read_password = prosodyctl.read_password;
79 80
80 local jid_split = require "util.jid".prepped_split; 81 local jid_split = require "util.jid".prepped_split;
81 82
82 local prosodyctl_timeout = (config.get("*", "prosodyctl_timeout") or 5) * 2; 83 local prosodyctl_timeout = (configmanager.get("*", "prosodyctl_timeout") or 5) * 2;
83 ----------------------- 84 -----------------------
84 local commands = {}; 85 local commands = {};
85 local command = arg[1]; 86 local command = arg[1];
86 87
87 function commands.adduser(arg) 88 function commands.adduser(arg)
102 end 103 end
103 104
104 if not hosts[host] then 105 if not hosts[host] then
105 show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host) 106 show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host)
106 show_warning("The user will not be able to log in until this is changed."); 107 show_warning("The user will not be able to log in until this is changed.");
107 hosts[host] = make_host(host); 108 hosts[host] = startup.make_host(host); --luacheck: ignore 122/hosts
108 end 109 end
109 110
110 if prosodyctl.user_exists{ user = user, host = host } then 111 if prosodyctl.user_exists{ user = user, host = host } then
111 show_message [[That user already exists]]; 112 show_message [[That user already exists]];
112 return 1; 113 return 1;
141 end 142 end
142 143
143 if not hosts[host] then 144 if not hosts[host] then
144 show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host) 145 show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host)
145 show_warning("The user will not be able to log in until this is changed."); 146 show_warning("The user will not be able to log in until this is changed.");
146 hosts[host] = make_host(host); 147 hosts[host] = startup.make_host(host); --luacheck: ignore 122/hosts
147 end 148 end
148 149
149 if not prosodyctl.user_exists { user = user, host = host } then 150 if not prosodyctl.user_exists { user = user, host = host } then
150 show_message [[That user does not exist, use prosodyctl adduser to create a new user]] 151 show_message [[That user does not exist, use prosodyctl adduser to create a new user]]
151 return 1; 152 return 1;
179 return 1; 180 return 1;
180 end 181 end
181 182
182 if not hosts[host] then 183 if not hosts[host] then
183 show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host) 184 show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host)
184 hosts[host] = make_host(host); 185 hosts[host] = startup.make_host(host); --luacheck: ignore 122/hosts
185 end 186 end
186 187
187 if not prosodyctl.user_exists { user = user, host = host } then 188 if not prosodyctl.user_exists { user = user, host = host } then
188 show_message [[That user does not exist on this server]] 189 show_message [[That user does not exist on this server]]
189 return 1; 190 return 1;
207 show_message(error_messages[ret]); 208 show_message(error_messages[ret]);
208 return 1; 209 return 1;
209 end 210 end
210 211
211 if ret then 212 if ret then
213 --luacheck: ignore 421/ret
212 local ok, ret = prosodyctl.getpid(); 214 local ok, ret = prosodyctl.getpid();
213 if not ok then 215 if not ok then
214 show_message("Couldn't get running Prosody's PID"); 216 show_message("Couldn't get running Prosody's PID");
215 show_message(error_messages[ret]); 217 show_message(error_messages[ret]);
216 return 1; 218 return 1;
217 end 219 end
218 show_message("Prosody is already running with PID %s", ret or "(unknown)"); 220 show_message("Prosody is already running with PID %s", ret or "(unknown)");
219 return 1; 221 return 1;
220 end 222 end
221 223
224 --luacheck: ignore 411/ret
222 local ok, ret = prosodyctl.start(prosody.paths.source); 225 local ok, ret = prosodyctl.start(prosody.paths.source);
223 if ok then 226 if ok then
224 local daemonize = config.get("*", "daemonize"); 227 local daemonize = configmanager.get("*", "daemonize");
225 if daemonize == nil then 228 if daemonize == nil then
226 daemonize = prosody.installed; 229 daemonize = prosody.installed;
227 end 230 end
228 if daemonize then 231 if daemonize then
229 local i=1; 232 local i=1;
261 show_message(error_messages[ret]); 264 show_message(error_messages[ret]);
262 return 1; 265 return 1;
263 end 266 end
264 267
265 if ret then 268 if ret then
269 --luacheck: ignore 421/ret
266 local ok, ret = prosodyctl.getpid(); 270 local ok, ret = prosodyctl.getpid();
267 if not ok then 271 if not ok then
268 show_message("Couldn't get running Prosody's PID"); 272 show_message("Couldn't get running Prosody's PID");
269 show_message(error_messages[ret]); 273 show_message(error_messages[ret]);
270 return 1; 274 return 1;
271 end 275 end
272 show_message("Prosody is running with PID %s", ret or "(unknown)"); 276 show_message("Prosody is running with PID %s", ret or "(unknown)");
273 return 0; 277 return 0;
274 else 278 else
275 show_message("Prosody is not running"); 279 show_message("Prosody is not running");
276 if not switched_user and current_uid ~= 0 then 280 if not prosody.switched_user and prosody.current_uid ~= 0 then
277 print("\nNote:") 281 print("\nNote:")
278 print(" You will also see this if prosodyctl is not running under"); 282 print(" You will also see this if prosodyctl is not running under");
279 print(" the same user account as Prosody. Try running as root (e.g. "); 283 print(" the same user account as Prosody. Try running as root (e.g. ");
280 print(" with 'sudo' in front) to gain access to Prosody's real status."); 284 print(" with 'sudo' in front) to gain access to Prosody's real status.");
281 end 285 end
282 return 2 286 return 2
283 end 287 end
284 return 1;
285 end 288 end
286 289
287 function commands.stop(arg) 290 function commands.stop(arg)
288 if arg[1] == "--help" then 291 if arg[1] == "--help" then
289 show_usage([[stop]], [[Stop a running Prosody server]]); 292 show_usage([[stop]], [[Stop a running Prosody server]]);
334 show_usage([[about]], [[Show information about this Prosody installation]]); 337 show_usage([[about]], [[Show information about this Prosody installation]]);
335 return 1; 338 return 1;
336 end 339 end
337 340
338 local pwd = "."; 341 local pwd = ".";
339 local lfs = require "lfs";
340 local array = require "util.array"; 342 local array = require "util.array";
341 local keys = require "util.iterators".keys; 343 local keys = require "util.iterators".keys;
342 local hg = require"util.mercurial"; 344 local hg = require"util.mercurial";
343 local relpath = config.resolve_relative_path; 345 local relpath = configmanager.resolve_relative_path;
344 346
345 print("Prosody "..(prosody.version or "(unknown version)")); 347 print("Prosody "..(prosody.version or "(unknown version)"));
346 print(""); 348 print("");
347 print("# Prosody directories"); 349 print("# Prosody directories");
348 print("Data directory: "..relpath(pwd, prosody.paths.data)); 350 print("Data directory: "..relpath(pwd, prosody.paths.data));
349 print("Config directory: "..relpath(pwd, prosody.paths.config or ".")); 351 print("Config directory: "..relpath(pwd, prosody.paths.config or "."));
350 print("Source directory: "..relpath(pwd, prosody.paths.source or ".")); 352 print("Source directory: "..relpath(pwd, prosody.paths.source or "."));
351 print("Plugin directories:") 353 print("Plugin directories:")
352 print(" "..(prosody.paths.plugins:gsub("([^;]+);?", function(path) 354 print(" "..(prosody.paths.plugins:gsub("([^;]+);?", function(path)
353 path = config.resolve_relative_path(pwd, path); 355 path = configmanager.resolve_relative_path(pwd, path);
354 local hgid, hgrepo = hg.check_id(path); 356 local hgid, hgrepo = hg.check_id(path);
355 if not hgid and hgrepo then 357 if not hgid and hgrepo then
356 return path.." - "..hgrepo .."!\n "; 358 return path.." - "..hgrepo .."!\n ";
357 end 359 end
358 -- 010452cfaf53 is the first commit in the prosody-modules repository 360 -- 010452cfaf53 is the first commit in the prosody-modules repository
380 print("LuaRocks: ", luarocks_status); 382 print("LuaRocks: ", luarocks_status);
381 print(""); 383 print("");
382 print("# Lua module versions"); 384 print("# Lua module versions");
383 local module_versions, longest_name = {}, 8; 385 local module_versions, longest_name = {}, 8;
384 local luaevent =dependencies.softreq"luaevent"; 386 local luaevent =dependencies.softreq"luaevent";
385 local ssl = dependencies.softreq"ssl"; 387 dependencies.softreq"ssl";
386 for name, module in pairs(package.loaded) do 388 for name, module in pairs(package.loaded) do
387 if type(module) == "table" and rawget(module, "_VERSION") 389 if type(module) == "table" and rawget(module, "_VERSION")
388 and name ~= "_G" and not name:match("%.") then 390 and name ~= "_G" and not name:match("%.") then
389 if #name > longest_name then 391 if #name > longest_name then
390 longest_name = #name; 392 longest_name = #name;
501 503
502 local have_pposix, pposix = pcall(require, "util.pposix"); 504 local have_pposix, pposix = pcall(require, "util.pposix");
503 local cert_basedir = prosody.paths.data == "." and "./certs" or prosody.paths.data; 505 local cert_basedir = prosody.paths.data == "." and "./certs" or prosody.paths.data;
504 if have_pposix and pposix.getuid() == 0 then 506 if have_pposix and pposix.getuid() == 0 then
505 -- FIXME should be enough to check if this directory is writable 507 -- FIXME should be enough to check if this directory is writable
506 local cert_dir = config.get("*", "certificates") or "certs"; 508 local cert_dir = configmanager.get("*", "certificates") or "certs";
507 cert_basedir = config.resolve_relative_path(prosody.paths.config, cert_dir); 509 cert_basedir = configmanager.resolve_relative_path(prosody.paths.config, cert_dir);
508 end 510 end
509 511
510 function cert_commands.config(arg) 512 function cert_commands.config(arg)
511 if #arg >= 1 and arg[1] ~= "--help" then 513 if #arg >= 1 and arg[1] ~= "--help" then
512 local conf_filename = cert_basedir .. "/" .. arg[1] .. ".cnf"; 514 local conf_filename = cert_basedir .. "/" .. arg[1] .. ".cnf";
516 local distinguished_name; 518 local distinguished_name;
517 if arg[#arg]:find("^/") then 519 if arg[#arg]:find("^/") then
518 distinguished_name = table.remove(arg); 520 distinguished_name = table.remove(arg);
519 end 521 end
520 local conf = openssl.config.new(); 522 local conf = openssl.config.new();
521 conf:from_prosody(hosts, config, arg); 523 conf:from_prosody(hosts, configmanager, arg);
522 if distinguished_name then 524 if distinguished_name then
523 local dn = {}; 525 local dn = {};
524 for k, v in distinguished_name:gmatch("/([^=/]+)=([^/]+)") do 526 for k, v in distinguished_name:gmatch("/([^=/]+)=([^/]+)") do
525 table.insert(dn, k); 527 table.insert(dn, k);
526 dn[k] = v; 528 dn[k] = v;
530 show_message("Please provide details to include in the certificate config file."); 532 show_message("Please provide details to include in the certificate config file.");
531 show_message("Leave the field empty to use the default value or '.' to exclude the field.") 533 show_message("Leave the field empty to use the default value or '.' to exclude the field.")
532 for _, k in ipairs(openssl._DN_order) do 534 for _, k in ipairs(openssl._DN_order) do
533 local v = conf.distinguished_name[k]; 535 local v = conf.distinguished_name[k];
534 if v then 536 if v then
535 local nv; 537 local nv = nil;
536 if k == "commonName" then 538 if k == "commonName" then
537 v = arg[1] 539 v = arg[1]
538 elseif k == "emailAddress" then 540 elseif k == "emailAddress" then
539 v = "xmpp@" .. arg[1]; 541 v = "xmpp@" .. arg[1];
540 elseif k == "countryName" then 542 elseif k == "countryName" then
669 for host in domains:gmatch("%S+") do 671 for host in domains:gmatch("%S+") do
670 table.insert(hostnames, host); 672 table.insert(hostnames, host);
671 end 673 end
672 else 674 else
673 for host in pairs(prosody.hosts) do 675 for host in pairs(prosody.hosts) do
674 if host ~= "*" and config.get(host, "enabled") ~= false then 676 if host ~= "*" and configmanager.get(host, "enabled") ~= false then
675 table.insert(hostnames, host); 677 table.insert(hostnames, host);
676 end 678 end
677 end 679 end
678 end 680 end
679 end 681 end
682 "Copies certificates to "..cert_basedir); 684 "Copies certificates to "..cert_basedir);
683 return 1; 685 return 1;
684 end 686 end
685 local owner, group; 687 local owner, group;
686 if pposix.getuid() == 0 then -- We need root to change ownership 688 if pposix.getuid() == 0 then -- We need root to change ownership
687 owner = config.get("*", "prosody_user") or "prosody"; 689 owner = configmanager.get("*", "prosody_user") or "prosody";
688 group = config.get("*", "prosody_group") or owner; 690 group = configmanager.get("*", "prosody_group") or owner;
689 end 691 end
690 local cm = require "core.certmanager"; 692 local cm = require "core.certmanager";
691 local imported = {}; 693 local imported = {};
692 for _, host in ipairs(hostnames) do 694 for _, host in ipairs(hostnames) do
693 for _, dir in ipairs(arg) do 695 for _, dir in ipairs(arg) do
764 if arg[1] == "--help" then 766 if arg[1] == "--help" then
765 show_usage([[check]], [[Perform basic checks on your Prosody installation]]); 767 show_usage([[check]], [[Perform basic checks on your Prosody installation]]);
766 return 1; 768 return 1;
767 end 769 end
768 local what = table.remove(arg, 1); 770 local what = table.remove(arg, 1);
769 local array, set = require "util.array", require "util.set"; 771 local set = require "util.set";
770 local it = require "util.iterators"; 772 local it = require "util.iterators";
771 local ok = true; 773 local ok = true;
772 local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end 774 local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end
773 local function enabled_hosts() return it.filter(disabled_hosts, pairs(config.getconfig())); end 775 local function enabled_hosts() return it.filter(disabled_hosts, pairs(configmanager.getconfig())); end
774 if not what or what == "disabled" then 776 if not what or what == "disabled" then
775 local disabled_hosts = set.new(); 777 local disabled_hosts_set = set.new();
776 for host, host_options in it.filter("*", pairs(config.getconfig())) do 778 for host, host_options in it.filter("*", pairs(configmanager.getconfig())) do
777 if host_options.enabled == false then 779 if host_options.enabled == false then
778 disabled_hosts:add(host); 780 disabled_hosts_set:add(host);
779 end 781 end
780 end 782 end
781 if not disabled_hosts:empty() then 783 if not disabled_hosts_set:empty() then
782 local msg = "Checks will be skipped for these disabled hosts: %s"; 784 local msg = "Checks will be skipped for these disabled hosts: %s";
783 if what then msg = "These hosts are disabled: %s"; end 785 if what then msg = "These hosts are disabled: %s"; end
784 show_warning(msg, tostring(disabled_hosts)); 786 show_warning(msg, tostring(disabled_hosts_set));
785 if what then return 0; end 787 if what then return 0; end
786 print"" 788 print""
787 end 789 end
788 end 790 end
789 if not what or what == "config" then 791 if not what or what == "config" then
795 local known_global_options = set.new({ 797 local known_global_options = set.new({
796 "pidfile", "log", "plugin_paths", "prosody_user", "prosody_group", "daemonize", 798 "pidfile", "log", "plugin_paths", "prosody_user", "prosody_group", "daemonize",
797 "umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings", 799 "umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings",
798 "network_backend", "http_default_host", 800 "network_backend", "http_default_host",
799 }); 801 });
800 local config = config.getconfig(); 802 local config = configmanager.getconfig();
801 -- Check that we have any global options (caused by putting a host at the top) 803 -- Check that we have any global options (caused by putting a host at the top)
802 if it.count(it.filter("log", pairs(config["*"]))) == 0 then 804 if it.count(it.filter("log", pairs(config["*"]))) == 0 then
803 ok = false; 805 ok = false;
804 print(""); 806 print("");
805 print(" No global options defined. Perhaps you have put a host definition at the top") 807 print(" No global options defined. Perhaps you have put a host definition at the top")
817 end 819 end
818 end 820 end
819 if not config["*"].modules_enabled then 821 if not config["*"].modules_enabled then
820 print(" No global modules_enabled is set?"); 822 print(" No global modules_enabled is set?");
821 local suggested_global_modules; 823 local suggested_global_modules;
822 for host, options in enabled_hosts() do 824 for host, options in enabled_hosts() do --luacheck: ignore 213/host
823 if not options.component_module and options.modules_enabled then 825 if not options.component_module and options.modules_enabled then
824 suggested_global_modules = set.intersection(suggested_global_modules or set.new(options.modules_enabled), set.new(options.modules_enabled)); 826 suggested_global_modules = set.intersection(suggested_global_modules or set.new(options.modules_enabled), set.new(options.modules_enabled));
825 end 827 end
826 end 828 end
827 if suggested_global_modules and not suggested_global_modules:empty() then 829 if suggested_global_modules and not suggested_global_modules:empty() then
860 print(" You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", ")); 862 print(" You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", "));
861 end 863 end
862 local subdomain = host:match("^[^.]+"); 864 local subdomain = host:match("^[^.]+");
863 if not(host_options:contains("component_module")) and (subdomain == "jabber" or subdomain == "xmpp" 865 if not(host_options:contains("component_module")) and (subdomain == "jabber" or subdomain == "xmpp"
864 or subdomain == "chat" or subdomain == "im") then 866 or subdomain == "chat" or subdomain == "im") then
865 print(""); 867 print("");
866 print(" Suggestion: If "..host.. " is a new host with no real users yet, consider renaming it now to"); 868 print(" Suggestion: If "..host.. " is a new host with no real users yet, consider renaming it now to");
867 print(" "..host:gsub("^[^.]+%.", "")..". You can use SRV records to redirect XMPP clients and servers to "..host.."."); 869 print(" "..host:gsub("^[^.]+%.", "")..". You can use SRV records to redirect XMPP clients and servers to "..host..".");
868 print(" For more information see: https://prosody.im/doc/dns"); 870 print(" For more information see: https://prosody.im/doc/dns");
869 end 871 end
870 end 872 end
871 local all_modules = set.new(config["*"].modules_enabled); 873 local all_modules = set.new(config["*"].modules_enabled);
872 local all_options = set.new(it.to_array(it.keys(config["*"]))); 874 local all_options = set.new(it.to_array(it.keys(config["*"])));
873 for host in enabled_hosts() do 875 for host in enabled_hosts() do
893 print(" Remove '"..mod.."' from modules_enabled and instead add"); 895 print(" Remove '"..mod.."' from modules_enabled and instead add");
894 print(" storage = '"..mod:match("^storage_(.*)").."'"); 896 print(" storage = '"..mod:match("^storage_(.*)").."'");
895 print(" For more information see https://prosody.im/doc/storage"); 897 print(" For more information see https://prosody.im/doc/storage");
896 end 898 end
897 end 899 end
898 for host, config in pairs(config) do 900 for host, host_config in pairs(config) do --luacheck: ignore 213/host
899 if type(rawget(config, "storage")) == "string" and rawget(config, "default_storage") then 901 if type(rawget(host_config, "storage")) == "string" and rawget(host_config, "default_storage") then
900 print(""); 902 print("");
901 print(" The 'default_storage' option is not needed if 'storage' is set to a string."); 903 print(" The 'default_storage' option is not needed if 'storage' is set to a string.");
902 break; 904 break;
903 end 905 end
904 end 906 end
905 local require_encryption = set.intersection(all_options, set.new({"require_encryption", "c2s_require_encryption", "s2s_require_encryption"})):empty(); 907 local require_encryption = set.intersection(all_options, set.new({
908 "require_encryption", "c2s_require_encryption", "s2s_require_encryption"
909 })):empty();
906 local ssl = dependencies.softreq"ssl"; 910 local ssl = dependencies.softreq"ssl";
907 if not ssl then 911 if not ssl then
908 if not require_encryption then 912 if not require_encryption then
909 print(""); 913 print("");
910 print(" You require encryption but LuaSec is not available."); 914 print(" You require encryption but LuaSec is not available.");
946 end 950 end
947 if not what or what == "dns" then 951 if not what or what == "dns" then
948 local dns = require "net.dns"; 952 local dns = require "net.dns";
949 local idna = require "util.encodings".idna; 953 local idna = require "util.encodings".idna;
950 local ip = require "util.ip"; 954 local ip = require "util.ip";
951 local c2s_ports = set.new(config.get("*", "c2s_ports") or {5222}); 955 local c2s_ports = set.new(configmanager.get("*", "c2s_ports") or {5222});
952 local s2s_ports = set.new(config.get("*", "s2s_ports") or {5269}); 956 local s2s_ports = set.new(configmanager.get("*", "s2s_ports") or {5269});
953 957
954 local c2s_srv_required, s2s_srv_required; 958 local c2s_srv_required, s2s_srv_required;
955 if not c2s_ports:contains(5222) then 959 if not c2s_ports:contains(5222) then
956 c2s_srv_required = true; 960 c2s_srv_required = true;
957 end 961 end
963 967
964 local external_addresses, internal_addresses = set.new(), set.new(); 968 local external_addresses, internal_addresses = set.new(), set.new();
965 969
966 local fqdn = socket.dns.tohostname(socket.dns.gethostname()); 970 local fqdn = socket.dns.tohostname(socket.dns.gethostname());
967 if fqdn then 971 if fqdn then
968 local res = dns.lookup(idna.to_ascii(fqdn), "A"); 972 do
969 if res then 973 local res = dns.lookup(idna.to_ascii(fqdn), "A");
970 for _, record in ipairs(res) do 974 if res then
971 external_addresses:add(record.a); 975 for _, record in ipairs(res) do
972 end 976 external_addresses:add(record.a);
973 end 977 end
974 local res = dns.lookup(idna.to_ascii(fqdn), "AAAA"); 978 end
975 if res then 979 end
976 for _, record in ipairs(res) do 980 do
977 external_addresses:add(record.aaaa); 981 local res = dns.lookup(idna.to_ascii(fqdn), "AAAA");
982 if res then
983 for _, record in ipairs(res) do
984 external_addresses:add(record.aaaa);
985 end
978 end 986 end
979 end 987 end
980 end 988 end
981 989
982 local local_addresses = require"util.net".local_addresses() or {}; 990 local local_addresses = require"util.net".local_addresses() or {};
1023 else 1031 else
1024 target_hosts:add(host); 1032 target_hosts:add(host);
1025 end 1033 end
1026 end 1034 end
1027 end 1035 end
1028 local res = dns.lookup("_xmpp-server._tcp."..idna.to_ascii(host)..".", "SRV"); 1036 do
1029 if res then 1037 local res = dns.lookup("_xmpp-server._tcp."..idna.to_ascii(host)..".", "SRV");
1030 for _, record in ipairs(res) do 1038 if res then
1031 target_hosts:add(record.srv.target); 1039 for _, record in ipairs(res) do
1032 if not s2s_ports:contains(record.srv.port) then 1040 target_hosts:add(record.srv.target);
1033 print(" SRV target "..record.srv.target.." contains unknown server port: "..record.srv.port); 1041 if not s2s_ports:contains(record.srv.port) then
1042 print(" SRV target "..record.srv.target.." contains unknown server port: "..record.srv.port);
1043 end
1034 end 1044 end
1035 end
1036 else
1037 if s2s_srv_required then
1038 print(" No _xmpp-server SRV record found for "..host..", but it looks like you need one.");
1039 all_targets_ok = false;
1040 else 1045 else
1041 target_hosts:add(host); 1046 if s2s_srv_required then
1047 print(" No _xmpp-server SRV record found for "..host..", but it looks like you need one.");
1048 all_targets_ok = false;
1049 else
1050 target_hosts:add(host);
1051 end
1042 end 1052 end
1043 end 1053 end
1044 if target_hosts:empty() then 1054 if target_hosts:empty() then
1045 target_hosts:add(host); 1055 target_hosts:add(host);
1046 end 1056 end
1049 print(" Target 'localhost' cannot be accessed from other servers"); 1059 print(" Target 'localhost' cannot be accessed from other servers");
1050 target_hosts:remove("localhost"); 1060 target_hosts:remove("localhost");
1051 end 1061 end
1052 1062
1053 local modules = set.new(it.to_array(it.values(host_options.modules_enabled or {}))) 1063 local modules = set.new(it.to_array(it.values(host_options.modules_enabled or {})))
1054 + set.new(it.to_array(it.values(config.get("*", "modules_enabled") or {}))) 1064 + set.new(it.to_array(it.values(configmanager.get("*", "modules_enabled") or {})))
1055 + set.new({ config.get(host, "component_module") }); 1065 + set.new({ configmanager.get(host, "component_module") });
1056 1066
1057 if modules:contains("proxy65") then 1067 if modules:contains("proxy65") then
1058 local proxy65_target = config.get(host, "proxy65_address") or host; 1068 local proxy65_target = configmanager.get(host, "proxy65_address") or host;
1059 local A, AAAA = dns.lookup(idna.to_ascii(proxy65_target), "A"), dns.lookup(idna.to_ascii(proxy65_target), "AAAA"); 1069 local A, AAAA = dns.lookup(idna.to_ascii(proxy65_target), "A"), dns.lookup(idna.to_ascii(proxy65_target), "AAAA");
1060 local prob = {}; 1070 local prob = {};
1061 if not A then 1071 if not A then
1062 table.insert(prob, "A"); 1072 table.insert(prob, "A");
1063 end 1073 end
1064 if v6_supported and not AAAA then 1074 if v6_supported and not AAAA then
1065 table.insert(prob, "AAAA"); 1075 table.insert(prob, "AAAA");
1066 end 1076 end
1067 if #prob > 0 then 1077 if #prob > 0 then
1068 print(" File transfer proxy "..proxy65_target.." has no "..table.concat(prob, "/").." record. Create one or set 'proxy65_address' to the correct host/IP."); 1078 print(" File transfer proxy "..proxy65_target.." has no "..table.concat(prob, "/")
1069 end 1079 .." record. Create one or set 'proxy65_address' to the correct host/IP.");
1070 end 1080 end
1071 1081 end
1072 for host in target_hosts do 1082
1083 for target_host in target_hosts do
1073 local host_ok_v4, host_ok_v6; 1084 local host_ok_v4, host_ok_v6;
1074 local res = dns.lookup(idna.to_ascii(host), "A"); 1085 do
1075 if res then 1086 local res = dns.lookup(idna.to_ascii(target_host), "A");
1076 for _, record in ipairs(res) do 1087 if res then
1077 if external_addresses:contains(record.a) then 1088 for _, record in ipairs(res) do
1078 some_targets_ok = true; 1089 if external_addresses:contains(record.a) then
1079 host_ok_v4 = true; 1090 some_targets_ok = true;
1080 elseif internal_addresses:contains(record.a) then 1091 host_ok_v4 = true;
1081 host_ok_v4 = true; 1092 elseif internal_addresses:contains(record.a) then
1082 some_targets_ok = true; 1093 host_ok_v4 = true;
1083 print(" "..host.." A record points to internal address, external connections might fail"); 1094 some_targets_ok = true;
1084 else 1095 print(" "..target_host.." A record points to internal address, external connections might fail");
1085 print(" "..host.." A record points to unknown address "..record.a); 1096 else
1086 all_targets_ok = false; 1097 print(" "..target_host.." A record points to unknown address "..record.a);
1098 all_targets_ok = false;
1099 end
1087 end 1100 end
1088 end 1101 end
1089 end 1102 end
1090 local res = dns.lookup(idna.to_ascii(host), "AAAA"); 1103 do
1091 if res then 1104 local res = dns.lookup(idna.to_ascii(target_host), "AAAA");
1092 for _, record in ipairs(res) do 1105 if res then
1093 if external_addresses:contains(record.aaaa) then 1106 for _, record in ipairs(res) do
1094 some_targets_ok = true; 1107 if external_addresses:contains(record.aaaa) then
1095 host_ok_v6 = true; 1108 some_targets_ok = true;
1096 elseif internal_addresses:contains(record.aaaa) then 1109 host_ok_v6 = true;
1097 host_ok_v6 = true; 1110 elseif internal_addresses:contains(record.aaaa) then
1098 some_targets_ok = true; 1111 host_ok_v6 = true;
1099 print(" "..host.." AAAA record points to internal address, external connections might fail"); 1112 some_targets_ok = true;
1100 else 1113 print(" "..target_host.." AAAA record points to internal address, external connections might fail");
1101 print(" "..host.." AAAA record points to unknown address "..record.aaaa); 1114 else
1102 all_targets_ok = false; 1115 print(" "..target_host.." AAAA record points to unknown address "..record.aaaa);
1116 all_targets_ok = false;
1117 end
1103 end 1118 end
1104 end 1119 end
1105 end 1120 end
1106 1121
1107 local bad_protos = {} 1122 local bad_protos = {}
1110 end 1125 end
1111 if not host_ok_v6 then 1126 if not host_ok_v6 then
1112 table.insert(bad_protos, "IPv6"); 1127 table.insert(bad_protos, "IPv6");
1113 end 1128 end
1114 if #bad_protos > 0 then 1129 if #bad_protos > 0 then
1115 print(" Host "..host.." does not seem to resolve to this server ("..table.concat(bad_protos, "/")..")"); 1130 print(" Host "..target_host.." does not seem to resolve to this server ("..table.concat(bad_protos, "/")..")");
1116 end 1131 end
1117 if host_ok_v6 and not v6_supported then 1132 if host_ok_v6 and not v6_supported then
1118 print(" Host "..host.." has AAAA records, but your version of LuaSocket does not support IPv6."); 1133 print(" Host "..target_host.." has AAAA records, but your version of LuaSocket does not support IPv6.");
1119 print(" Please see https://prosody.im/doc/ipv6 for more information."); 1134 print(" Please see https://prosody.im/doc/ipv6 for more information.");
1120 end 1135 end
1121 end 1136 end
1122 if not all_targets_ok then 1137 if not all_targets_ok then
1123 print(" "..(some_targets_ok and "Only some" or "No").." targets for "..host.." appear to resolve to this server."); 1138 print(" "..(some_targets_ok and "Only some" or "No").." targets for "..host.." appear to resolve to this server.");
1159 return true; 1174 return true;
1160 end 1175 end
1161 for host in it.filter(skip_bare_jid_hosts, enabled_hosts()) do 1176 for host in it.filter(skip_bare_jid_hosts, enabled_hosts()) do
1162 print("Checking certificate for "..host); 1177 print("Checking certificate for "..host);
1163 -- First, let's find out what certificate this host uses. 1178 -- First, let's find out what certificate this host uses.
1164 local host_ssl_config = config.rawget(host, "ssl") 1179 local host_ssl_config = configmanager.rawget(host, "ssl")
1165 or config.rawget(host:match("%.(.*)"), "ssl"); 1180 or configmanager.rawget(host:match("%.(.*)"), "ssl");
1166 local global_ssl_config = config.rawget("*", "ssl"); 1181 local global_ssl_config = configmanager.rawget("*", "ssl");
1167 local ok, err, ssl_config = create_context(host, "server", host_ssl_config, global_ssl_config); 1182 local ok, err, ssl_config = create_context(host, "server", host_ssl_config, global_ssl_config);
1168 if not ok then 1183 if not ok then
1169 print(" Error: "..err); 1184 print(" Error: "..err);
1170 cert_ok = false 1185 cert_ok = false
1171 elseif not ssl_config.certificate then 1186 elseif not ssl_config.certificate then
1186 if not cert_fh then 1201 if not cert_fh then
1187 print(" Could not open "..ssl_config.certificate..": "..err); 1202 print(" Could not open "..ssl_config.certificate..": "..err);
1188 cert_ok = false 1203 cert_ok = false
1189 else 1204 else
1190 print(" Certificate: "..ssl_config.certificate) 1205 print(" Certificate: "..ssl_config.certificate)
1191 local cert = load_cert(cert_fh:read"*a"); cert_fh = cert_fh:close(); 1206 local cert = load_cert(cert_fh:read"*a"); cert_fh:close();
1192 if not cert:validat(os.time()) then 1207 if not cert:validat(os.time()) then
1193 print(" Certificate has expired.") 1208 print(" Certificate has expired.")
1194 cert_ok = false 1209 cert_ok = false
1195 elseif not cert:validat(os.time() + 86400) then 1210 elseif not cert:validat(os.time() + 86400) then
1196 print(" Certificate expires within one day.") 1211 print(" Certificate expires within one day.")
1198 elseif not cert:validat(os.time() + 86400*7) then 1213 elseif not cert:validat(os.time() + 86400*7) then
1199 print(" Certificate expires within one week.") 1214 print(" Certificate expires within one week.")
1200 elseif not cert:validat(os.time() + 86400*31) then 1215 elseif not cert:validat(os.time() + 86400*31) then
1201 print(" Certificate expires within one month.") 1216 print(" Certificate expires within one month.")
1202 end 1217 end
1203 if config.get(host, "component_module") == nil 1218 if configmanager.get(host, "component_module") == nil
1204 and not x509_verify_identity(host, "_xmpp-client", cert) then 1219 and not x509_verify_identity(host, "_xmpp-client", cert) then
1205 print(" Not valid for client connections to "..host..".") 1220 print(" Not valid for client connections to "..host..".")
1206 cert_ok = false 1221 cert_ok = false
1207 end 1222 end
1208 if (not (config.get(host, "anonymous_login") 1223 if (not (configmanager.get(host, "anonymous_login")
1209 or config.get(host, "authentication") == "anonymous")) 1224 or configmanager.get(host, "authentication") == "anonymous"))
1210 and not x509_verify_identity(host, "_xmpp-server", cert) then 1225 and not x509_verify_identity(host, "_xmpp-server", cert) then
1211 print(" Not valid for server-to-server connections to "..host..".") 1226 print(" Not valid for server-to-server connections to "..host..".")
1212 cert_ok = false 1227 cert_ok = false
1213 end 1228 end
1214 end 1229 end
1215 end 1230 end
1216 end 1231 end
1217 if cert_ok == false then 1232 end
1218 print("") 1233 if cert_ok == false then
1219 print("For more information about certificates please see https://prosody.im/doc/certificates"); 1234 print("")
1220 ok = false 1235 print("For more information about certificates please see https://prosody.im/doc/certificates");
1221 end 1236 ok = false
1222 end 1237 end
1223 print("") 1238 print("")
1224 end 1239 end
1225 if not ok then 1240 if not ok then
1226 print("Problems found, see above."); 1241 print("Problems found, see above.");
1231 end 1246 end
1232 1247
1233 --------------------- 1248 ---------------------
1234 1249
1235 local async = require "util.async"; 1250 local async = require "util.async";
1251 local server = require "net.server";
1236 local watchers = { 1252 local watchers = {
1237 error = function (_, err) 1253 error = function (_, err)
1238 error(err); 1254 error(err);
1239 end; 1255 end;
1240 waiting = function () 1256 waiting = function ()
1242 end; 1258 end;
1243 }; 1259 };
1244 local command_runner = async.runner(function () 1260 local command_runner = async.runner(function ()
1245 if command and command:match("^mod_") then -- Is a command in a module 1261 if command and command:match("^mod_") then -- Is a command in a module
1246 local module_name = command:match("^mod_(.+)"); 1262 local module_name = command:match("^mod_(.+)");
1247 local ret, err = modulemanager.load("*", module_name); 1263 do
1248 if not ret then 1264 local ret, err = modulemanager.load("*", module_name);
1249 show_message("Failed to load module '"..module_name.."': "..err); 1265 if not ret then
1250 os.exit(1); 1266 show_message("Failed to load module '"..module_name.."': "..err);
1267 os.exit(1);
1268 end
1251 end 1269 end
1252 1270
1253 table.remove(arg, 1); 1271 table.remove(arg, 1);
1254 1272
1255 local module = modulemanager.get_module("*", module_name); 1273 local module = modulemanager.get_module("*", module_name);
1293 local commands_order = { "adduser", "passwd", "deluser", "start", "stop", "restart", "reload", "about" }; 1311 local commands_order = { "adduser", "passwd", "deluser", "start", "stop", "restart", "reload", "about" };
1294 1312
1295 local done = {}; 1313 local done = {};
1296 1314
1297 for _, command_name in ipairs(commands_order) do 1315 for _, command_name in ipairs(commands_order) do
1298 local command = commands[command_name]; 1316 local command_func = commands[command_name];
1299 if command then 1317 if command_func then
1300 command{ "--help" }; 1318 command_func{ "--help" };
1301 print"" 1319 print""
1302 done[command_name] = true; 1320 done[command_name] = true;
1303 end 1321 end
1304 end 1322 end
1305 1323
1306 for command_name, command in pairs(commands) do 1324 for command_name, command_func in pairs(commands) do
1307 if not done[command_name] and not hidden_commands:contains(command_name) then 1325 if not done[command_name] and not hidden_commands:contains(command_name) then
1308 command{ "--help" }; 1326 command_func{ "--help" };
1309 print"" 1327 print""
1310 done[command_name] = true; 1328 done[command_name] = true;
1311 end 1329 end
1312 end 1330 end
1313 1331