Software /
code /
prosody
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); |