Comparison

prosodyctl @ 6054:7a5ddbaf758d

Merge 0.9->0.10
author Matthew Wild <mwild1@gmail.com>
date Wed, 02 Apr 2014 17:41:38 +0100
parent 6038:b3ceb7627e27
child 6062:6cc6b4d407df
comparison
equal deleted inserted replaced
6053:2f93a04564b2 6054:7a5ddbaf758d
272 ----------------------- 272 -----------------------
273 local commands = {}; 273 local commands = {};
274 local command = arg[1]; 274 local command = arg[1];
275 275
276 function commands.adduser(arg) 276 function commands.adduser(arg)
277 local jid_split = require "util.jid".split;
277 if not arg[1] or arg[1] == "--help" then 278 if not arg[1] or arg[1] == "--help" then
278 show_usage([[adduser JID]], [[Create the specified user account in Prosody]]); 279 show_usage([[adduser JID]], [[Create the specified user account in Prosody]]);
279 return 1; 280 return 1;
280 end 281 end
281 local user, host = arg[1]:match("([^@]+)@(.+)"); 282 local user, host = jid_split(arg[1]);
282 if not user and host then 283 if not user and host then
283 show_message [[Failed to understand JID, please supply the JID you want to create]] 284 show_message [[Failed to understand JID, please supply the JID you want to create]]
284 show_usage [[adduser user@host]] 285 show_usage [[adduser user@host]]
285 return 1; 286 return 1;
286 end 287 end
311 show_message(msg) 312 show_message(msg)
312 return 1; 313 return 1;
313 end 314 end
314 315
315 function commands.passwd(arg) 316 function commands.passwd(arg)
317 local jid_split = require "util.jid".split;
316 if not arg[1] or arg[1] == "--help" then 318 if not arg[1] or arg[1] == "--help" then
317 show_usage([[passwd JID]], [[Set the password for the specified user account in Prosody]]); 319 show_usage([[passwd JID]], [[Set the password for the specified user account in Prosody]]);
318 return 1; 320 return 1;
319 end 321 end
320 local user, host = arg[1]:match("([^@]+)@(.+)"); 322 local user, host = jid_split(arg[1]);
321 if not user and host then 323 if not user and host then
322 show_message [[Failed to understand JID, please supply the JID you want to set the password for]] 324 show_message [[Failed to understand JID, please supply the JID you want to set the password for]]
323 show_usage [[passwd user@host]] 325 show_usage [[passwd user@host]]
324 return 1; 326 return 1;
325 end 327 end
350 show_message(error_messages[msg]) 352 show_message(error_messages[msg])
351 return 1; 353 return 1;
352 end 354 end
353 355
354 function commands.deluser(arg) 356 function commands.deluser(arg)
357 local jid_split = require "util.jid".split;
355 if not arg[1] or arg[1] == "--help" then 358 if not arg[1] or arg[1] == "--help" then
356 show_usage([[deluser JID]], [[Permanently remove the specified user account from Prosody]]); 359 show_usage([[deluser JID]], [[Permanently remove the specified user account from Prosody]]);
357 return 1; 360 return 1;
358 end 361 end
359 local user, host = arg[1]:match("([^@]+)@(.+)"); 362 local user, host = jid_split(arg[1]);
360 if not user and host then 363 if not user and host then
361 show_message [[Failed to understand JID, please supply the JID you want to set the password for]] 364 show_message [[Failed to understand JID, please supply the JID you want to set the password for]]
362 show_usage [[passwd user@host]] 365 show_usage [[passwd user@host]]
363 return 1; 366 return 1;
364 end 367 end
779 end 782 end
780 end 783 end
781 show_usage("cert config|request|generate|key", "Helpers for generating X.509 certificates and keys.") 784 show_usage("cert config|request|generate|key", "Helpers for generating X.509 certificates and keys.")
782 end 785 end
783 786
787 function commands.check(arg)
788 if arg[1] == "--help" then
789 show_usage([[check]], [[Perform basic checks on your Prosody installation]]);
790 return 1;
791 end
792 local what = table.remove(arg, 1);
793 local array, set = require "util.array", require "util.set";
794 local it = require "util.iterators";
795 local ok = true;
796 if not what or what == "config" then
797 print("Checking config...");
798 local known_global_options = set.new({
799 "pidfile", "log", "plugin_paths", "prosody_user", "prosody_group", "daemonize",
800 "umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings"
801 });
802 local config = config.getconfig();
803 -- Check that we have any global options (caused by putting a host at the top)
804 if it.count(it.filter("log", pairs(config["*"]))) == 0 then
805 ok = false;
806 print("");
807 print(" No global options defined. Perhaps you have put a host definition at the top")
808 print(" of the config file? They should be at the bottom, see http://prosody.im/doc/configure#overview");
809 end
810 -- Check for global options under hosts
811 local global_options = set.new(it.to_array(it.keys(config["*"])));
812 for host, options in it.filter("*", pairs(config)) do
813 local host_options = set.new(it.to_array(it.keys(options)));
814 local misplaced_options = set.intersection(host_options, known_global_options);
815 for name in pairs(options) do
816 if name:match("^interfaces?")
817 or name:match("_ports?$") or name:match("_interfaces?$")
818 or name:match("_ssl$") then
819 misplaced_options:add(name);
820 end
821 end
822 if not misplaced_options:empty() then
823 ok = false;
824 print("");
825 local n = it.count(misplaced_options);
826 print(" You have "..n.." option"..(n>1 and "s " or " ").."set under "..host.." that should be");
827 print(" in the global section of the config file, above any VirtualHost or Component definitions,")
828 print(" see http://prosody.im/doc/configure#overview for more information.")
829 print("");
830 print(" You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", "));
831 end
832 local subdomain = host:match("^[^.]+");
833 if not(host_options:contains("component_module")) and (subdomain == "jabber" or subdomain == "xmpp"
834 or subdomain == "chat" or subdomain == "im") then
835 print("");
836 print(" Suggestion: If "..host.. " is a new host with no real users yet, consider renaming it now to");
837 print(" "..host:gsub("^[^.]+%.", "")..". You can use SRV records to redirect XMPP clients and servers to "..host..".");
838 print(" For more information see: http://prosody.im/doc/dns");
839 end
840 end
841
842 print("Done.\n");
843 end
844 if not what or what == "dns" then
845 local dns = require "net.dns";
846 local idna = require "util.encodings".idna;
847 local ip = require "util.ip";
848 local c2s_ports = set.new(config.get("*", "c2s_ports") or {5222});
849 local s2s_ports = set.new(config.get("*", "s2s_ports") or {5269});
850
851 local c2s_srv_required, s2s_srv_required;
852 if not c2s_ports:contains(5222) then
853 c2s_srv_required = true;
854 end
855 if not s2s_ports:contains(5269) then
856 s2s_srv_required = true;
857 end
858
859 local problem_hosts = set.new();
860
861 local external_addresses, internal_addresses = set.new(), set.new();
862
863 local fqdn = socket.dns.tohostname(socket.dns.gethostname());
864 if fqdn then
865 local res = dns.lookup(idna.to_ascii(fqdn), "A");
866 if res then
867 for _, record in ipairs(res) do
868 external_addresses:add(record.a);
869 end
870 end
871 local res = dns.lookup(idna.to_ascii(fqdn), "AAAA");
872 if res then
873 for _, record in ipairs(res) do
874 external_addresses:add(record.aaaa);
875 end
876 end
877 end
878
879 local local_addresses = require"util.net".local_addresses() or {};
880
881 for addr in it.values(local_addresses) do
882 if not ip.new_ip(addr).private then
883 external_addresses:add(addr);
884 else
885 internal_addresses:add(addr);
886 end
887 end
888
889 if external_addresses:empty() then
890 print("");
891 print(" Failed to determine the external addresses of this server. Checks may be inaccurate.");
892 c2s_srv_required, s2s_srv_required = true, true;
893 end
894
895 local v6_supported = not not socket.tcp6;
896
897 for host, host_options in it.filter("*", pairs(config.getconfig())) do
898 local all_targets_ok, some_targets_ok = true, false;
899
900 local is_component = not not host_options.component_module;
901 print("Checking DNS for "..(is_component and "component" or "host").." "..host.."...");
902 local target_hosts = set.new();
903 if not is_component then
904 local res = dns.lookup("_xmpp-client._tcp."..idna.to_ascii(host)..".", "SRV");
905 if res then
906 for _, record in ipairs(res) do
907 target_hosts:add(record.srv.target);
908 if not c2s_ports:contains(record.srv.port) then
909 print(" SRV target "..record.srv.target.." contains unknown client port: "..record.srv.port);
910 end
911 end
912 else
913 if c2s_srv_required then
914 print(" No _xmpp-client SRV record found for "..host..", but it looks like you need one.");
915 all_targst_ok = false;
916 else
917 target_hosts:add(host);
918 end
919 end
920 end
921 local res = dns.lookup("_xmpp-server._tcp."..idna.to_ascii(host)..".", "SRV");
922 if res then
923 for _, record in ipairs(res) do
924 target_hosts:add(record.srv.target);
925 if not s2s_ports:contains(record.srv.port) then
926 print(" SRV target "..record.srv.target.." contains unknown server port: "..record.srv.port);
927 end
928 end
929 else
930 if s2s_srv_required then
931 print(" No _xmpp-server SRV record found for "..host..", but it looks like you need one.");
932 all_targets_ok = false;
933 else
934 target_hosts:add(host);
935 end
936 end
937 if target_hosts:empty() then
938 target_hosts:add(host);
939 end
940
941 if target_hosts:contains("localhost") then
942 print(" Target 'localhost' cannot be accessed from other servers");
943 target_hosts:remove("localhost");
944 end
945
946 local modules = set.new(it.to_array(it.values(host_options.modules_enabled)))
947 + set.new(it.to_array(it.values(config.get("*", "modules_enabled"))))
948 + set.new({ config.get(host, "component_module") });
949
950 if modules:contains("proxy65") then
951 local proxy65_target = config.get(host, "proxy65_address") or host;
952 local A, AAAA = dns.lookup(idna.to_ascii(proxy65_target), "A"), dns.lookup(idna.to_ascii(proxy65_target), "AAAA");
953 local prob = {};
954 if not A then
955 table.insert(prob, "A");
956 end
957 if v6_supported and not AAAA then
958 table.insert(prob, "AAAA");
959 end
960 if #prob > 0 then
961 print(" File transfer proxy "..proxy65_target.." has no "..table.concat(prob, "/").." record. Create one or set 'proxy65_address' to the correct host/IP.");
962 end
963 end
964
965 for host in target_hosts do
966 local host_ok_v4, host_ok_v6;
967 local res = dns.lookup(idna.to_ascii(host), "A");
968 if res then
969 for _, record in ipairs(res) do
970 if external_addresses:contains(record.a) then
971 some_targets_ok = true;
972 host_ok_v4 = true;
973 elseif internal_addresses:contains(record.a) then
974 host_ok_v4 = true;
975 some_targets_ok = true;
976 print(" "..host.." A record points to internal address, external connections might fail");
977 else
978 print(" "..host.." A record points to unknown address "..record.a);
979 all_targets_ok = false;
980 end
981 end
982 end
983 local res = dns.lookup(idna.to_ascii(host), "AAAA");
984 if res then
985 for _, record in ipairs(res) do
986 if external_addresses:contains(record.aaaa) then
987 some_targets_ok = true;
988 host_ok_v6 = true;
989 elseif internal_addresses:contains(record.aaaa) then
990 host_ok_v6 = true;
991 some_targets_ok = true;
992 print(" "..host.." AAAA record points to internal address, external connections might fail");
993 else
994 print(" "..host.." AAAA record points to unknown address "..record.aaaa);
995 all_targets_ok = false;
996 end
997 end
998 end
999
1000 local bad_protos = {}
1001 if not host_ok_v4 then
1002 table.insert(bad_protos, "IPv4");
1003 end
1004 if not host_ok_v6 then
1005 table.insert(bad_protos, "IPv6");
1006 end
1007 if #bad_protos > 0 then
1008 print(" Host "..host.." does not seem to resolve to this server ("..table.concat(bad_protos, "/")..")");
1009 end
1010 if host_ok_v6 and not v6_supported then
1011 print(" Host "..host.." has AAAA records, but your version of LuaSocket does not support IPv6.");
1012 print(" Please see http://prosody.im/doc/ipv6 for more information.");
1013 end
1014 end
1015 if not all_targets_ok then
1016 print(" "..(some_targets_ok and "Only some" or "No").." targets for "..host.." appear to resolve to this server.");
1017 if is_component then
1018 print(" DNS records are necessary if you want users on other servers to access this component.");
1019 end
1020 problem_hosts:add(host);
1021 end
1022 print("");
1023 end
1024 if not problem_hosts:empty() then
1025 print("");
1026 print("For more information about DNS configuration please see http://prosody.im/doc/dns");
1027 print("");
1028 ok = false;
1029 end
1030 end
1031 if not what or what == "certs" then
1032 local cert_ok;
1033 print"Checking certificates..."
1034 local x509_verify_identity = require"util.x509".verify_identity;
1035 local ssl = dependencies.softreq"ssl";
1036 -- local datetime_parse = require"util.datetime".parse_x509;
1037 local load_cert = ssl and ssl.x509 and ssl.x509.load;
1038 -- or ssl.cert_from_pem
1039 if not ssl then
1040 print("LuaSec not available, can't perform certificate checks")
1041 if what == "certs" then cert_ok = false end
1042 elseif not load_cert then
1043 print("This version of LuaSec (" .. ssl._VERSION .. ") does not support certificate checking");
1044 cert_ok = false
1045 else
1046 for host in pairs(hosts) do
1047 if host ~= "*" then -- Should check global certs too.
1048 print("Checking certificate for "..host);
1049 -- First, let's find out what certificate this host uses.
1050 local ssl_config = config.rawget(host, "ssl");
1051 if not ssl_config then
1052 local base_host = host:match("%.(.*)");
1053 ssl_config = config.get(base_host, "ssl");
1054 end
1055 if not ssl_config then
1056 print(" No 'ssl' option defined for "..host)
1057 cert_ok = false
1058 elseif not ssl_config.certificate then
1059 print(" No 'certificate' set in ssl option for "..host)
1060 cert_ok = false
1061 elseif not ssl_config.key then
1062 print(" No 'key' set in ssl option for "..host)
1063 cert_ok = false
1064 else
1065 local key, err = io.open(ssl_config.key); -- Permissions check only
1066 if not key then
1067 print(" Could not open "..ssl_config.key..": "..err);
1068 cert_ok = false
1069 else
1070 key:close();
1071 end
1072 local cert_fh, err = io.open(ssl_config.certificate); -- Load the file.
1073 if not cert_fh then
1074 print(" Could not open "..ssl_config.certificate..": "..err);
1075 cert_ok = false
1076 else
1077 print(" Certificate: "..ssl_config.certificate)
1078 local cert = load_cert(cert_fh:read"*a"); cert_fh = cert_fh:close();
1079 if not cert:validat(os.time()) then
1080 print(" Certificate has expired.")
1081 cert_ok = false
1082 end
1083 if config.get(host, "component_module") == nil
1084 and not x509_verify_identity(host, "_xmpp-client", cert) then
1085 print(" Not vaild for client connections to "..host..".")
1086 cert_ok = false
1087 end
1088 if (not (config.get(name, "anonymous_login")
1089 or config.get(name, "authentication") == "anonymous"))
1090 and not x509_verify_identity(host, "_xmpp-client", cert) then
1091 print(" Not vaild for server-to-server connections to "..host..".")
1092 cert_ok = false
1093 end
1094 end
1095 end
1096 end
1097 end
1098 if cert_ok == false then
1099 print("")
1100 print("For more information about certificates please see http://prosody.im/doc/certificates");
1101 ok = false
1102 end
1103 end
1104 print("")
1105 end
1106 if not ok then
1107 print("Problems found, see above.");
1108 else
1109 print("All checks passed, congratulations!");
1110 end
1111 return ok and 0 or 2;
1112 end
1113
784 --------------------- 1114 ---------------------
785 1115
786 if command and command:match("^mod_") then -- Is a command in a module 1116 if command and command:match("^mod_") then -- Is a command in a module
787 local module_name = command:match("^mod_(.+)"); 1117 local module_name = command:match("^mod_(.+)");
788 local ret, err = modulemanager.load("*", module_name); 1118 local ret, err = modulemanager.load("*", module_name);