Comparison

prosodyctl @ 5720:449399a7e136

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