util.sql: Get character set info from the correct database.
[prosody.git] / prosodyctl
index 41f3b8dcf622161d186d4bcf4ddd482f42bb9797..cf2ab74df253f1c850d9597acebc82ead6f82945 100755 (executable)
@@ -274,11 +274,12 @@ 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;
        end
-       local user, host = arg[1]:match("([^@]+)@(.+)");
+       local user, host = jid_split(arg[1]);
        if not user and host then
                show_message [[Failed to understand JID, please supply the JID you want to create]]
                show_usage [[adduser user@host]]
@@ -313,11 +314,12 @@ 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;
        end
-       local user, host = arg[1]:match("([^@]+)@(.+)");
+       local user, host = jid_split(arg[1]);
        if not user and host then
                show_message [[Failed to understand JID, please supply the JID you want to set the password for]]
                show_usage [[passwd user@host]]
@@ -352,11 +354,12 @@ 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;
        end
-       local user, host = arg[1]:match("([^@]+)@(.+)");
+       local user, host = jid_split(arg[1]);
        if not user and host then
                show_message [[Failed to understand JID, please supply the JID you want to set the password for]]
                show_usage [[passwd user@host]]
@@ -777,6 +780,10 @@ function commands.cert(arg)
 end
 
 function commands.check(arg)
+       if arg[1] == "--help" then
+               show_usage([[check]], [[Perform basic checks on your Prosody installation]]);
+               return 1;
+       end
        local what = table.remove(arg, 1);
        local array, set = require "util.array", require "util.set";
        local it = require "util.iterators";
@@ -817,11 +824,21 @@ function commands.check(arg)
                                print("");
                                print("    You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", "));
                        end
+                       local subdomain = host:match("^[^.]+");
+                       if not(host_options:contains("component_module")) and (subdomain == "jabber" or subdomain == "xmpp"
+                          or subdomain == "chat" or subdomain == "im") then
+                               print("");
+                               print("    Suggestion: If "..host.. " is a new host with no real users yet, consider renaming it now to");
+                               print("     "..host:gsub("^[^.]+%.", "")..". You can use SRV records to redirect XMPP clients and servers to "..host..".");
+                               print("     For more information see: http://prosody.im/doc/dns");
+                       end
                end
+               
                print("Done.\n");
        end
        if not what or what == "dns" then
                local dns = require "net.dns";
+               local idna = require "util.encodings".idna;
                local ip = require "util.ip";
                local c2s_ports = set.new(config.get("*", "c2s_ports") or {5222});
                local s2s_ports = set.new(config.get("*", "s2s_ports") or {5269});
@@ -840,13 +857,13 @@ function commands.check(arg)
                
                local fqdn = socket.dns.tohostname(socket.dns.gethostname());
                if fqdn then
-                       local res = dns.lookup(fqdn, "A");
+                       local res = dns.lookup(idna.to_ascii(fqdn), "A");
                        if res then
                                for _, record in ipairs(res) do
                                        external_addresses:add(record.a);
                                end
                        end
-                       local res = dns.lookup(fqdn, "AAAA");
+                       local res = dns.lookup(idna.to_ascii(fqdn), "AAAA");
                        if res then
                                for _, record in ipairs(res) do
                                        external_addresses:add(record.aaaa);
@@ -854,7 +871,7 @@ function commands.check(arg)
                        end
                end
                
-               local local_addresses = socket.local_addresses and socket.local_addresses() or {};
+               local local_addresses = require"util.net".local_addresses() or {};
                
                for addr in it.values(local_addresses) do
                        if not ip.new_ip(addr).private then
@@ -879,7 +896,7 @@ function commands.check(arg)
                        print("Checking DNS for "..(is_component and "component" or "host").." "..host.."...");
                        local target_hosts = set.new();
                        if not is_component then
-                               local res = dns.lookup("_xmpp-client._tcp."..host..".", "SRV");
+                               local res = dns.lookup("_xmpp-client._tcp."..idna.to_ascii(host)..".", "SRV");
                                if res then
                                        for _, record in ipairs(res) do
                                                target_hosts:add(record.srv.target);
@@ -896,7 +913,7 @@ function commands.check(arg)
                                        end
                                end
                        end
-                       local res = dns.lookup("_xmpp-server._tcp."..host..".", "SRV");
+                       local res = dns.lookup("_xmpp-server._tcp."..idna.to_ascii(host)..".", "SRV");
                        if res then
                                for _, record in ipairs(res) do
                                        target_hosts:add(record.srv.target);
@@ -921,9 +938,28 @@ 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"))))
+                                       + set.new({ config.get(host, "component_module") });
+
+                       if modules:contains("proxy65") then
+                               local proxy65_target = config.get(host, "proxy65_address") or host;
+                               local A, AAAA = dns.lookup(idna.to_ascii(proxy65_target), "A"), dns.lookup(idna.to_ascii(proxy65_target), "AAAA");
+                               local prob = {};
+                               if not A then
+                                       table.insert(prob, "A");
+                               end
+                               if v6_supported and not AAAA then
+                                       table.insert(prob, "AAAA");
+                               end
+                               if #prob > 0 then
+                                       print("    File transfer proxy "..proxy65_target.." has no "..table.concat(prob, "/").." record. Create one or set 'proxy65_address' to the correct host/IP.");
+                               end
+                       end
+                       
                        for host in target_hosts do
                                local host_ok_v4, host_ok_v6;
-                               local res = dns.lookup(host, "A");
+                               local res = dns.lookup(idna.to_ascii(host), "A");
                                if res then
                                        for _, record in ipairs(res) do
                                                if external_addresses:contains(record.a) then
@@ -939,7 +975,7 @@ function commands.check(arg)
                                                end
                                        end
                                end
-                               local res = dns.lookup(host, "AAAA");
+                               local res = dns.lookup(idna.to_ascii(host), "AAAA");
                                if res then
                                        for _, record in ipairs(res) do
                                                if external_addresses:contains(record.aaaa) then
@@ -987,6 +1023,81 @@ function commands.check(arg)
                        ok = false;
                end
        end
+       if not what or what == "certs" then
+               local cert_ok;
+               print"Checking certificates..."
+               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;
+               -- or ssl.cert_from_pem
+               if not ssl then
+                       print("LuaSec not available, can't perform certificate checks")
+                       if what == "certs" then cert_ok = false end
+               elseif not load_cert then
+                       print("This version of LuaSec (" .. ssl._VERSION .. ") does not support certificate checking");
+                       cert_ok = false
+               else
+                       for host in pairs(hosts) do
+                               if host ~= "*" then -- Should check global certs too.
+                                       print("Checking certificate for "..host);
+                                       -- First, let's find out what certificate this host uses.
+                                       local ssl_config = config.rawget(host, "ssl");
+                                       if not ssl_config then
+                                               local base_host = host:match("%.(.*)");
+                                               ssl_config = config.get(base_host, "ssl");
+                                       end
+                                       if not ssl_config then
+                                               print("  No 'ssl' option defined for "..host)
+                                               cert_ok = false
+                                       elseif not ssl_config.certificate then
+                                               print("  No 'certificate' set in ssl option for "..host)
+                                               cert_ok = false
+                                       elseif not ssl_config.key then
+                                               print("  No 'key' set in ssl option for "..host)
+                                               cert_ok = false
+                                       else
+                                               local key, err = io.open(ssl_config.key); -- Permissions check only
+                                               if not key then
+                                                       print("    Could not open "..ssl_config.key..": "..err);
+                                                       cert_ok = false
+                                               else
+                                                       key:close();
+                                               end
+                                               local cert_fh, err = io.open(ssl_config.certificate); -- Load the file.
+                                               if not cert_fh then
+                                                       print("    Could not open "..ssl_config.certificate..": "..err);
+                                                       cert_ok = false
+                                               else
+                                                       print("  Certificate: "..ssl_config.certificate)
+                                                       local cert = load_cert(cert_fh:read"*a"); cert_fh = cert_fh:close();
+                                                       if not cert:validat(os.time()) then
+                                                               print("    Certificate has expired.")
+                                                               cert_ok = false
+                                                       end
+                                                       if config.get(host, "component_module") == nil
+                                                       and not x509_verify_identity(host, "_xmpp-client", cert) then
+                                                               print("    Not vaild for client connections to "..host..".")
+                                                               cert_ok = false
+                                                       end
+                                                       if (not (config.get(name, "anonymous_login")
+                                                               or config.get(name, "authentication") == "anonymous"))
+                                                       and not x509_verify_identity(host, "_xmpp-client", cert) then
+                                                               print("    Not vaild for server-to-server connections to "..host..".")
+                                                               cert_ok = false
+                                                       end
+                                               end
+                                       end
+                               end
+                       end
+                       if cert_ok == false then
+                               print("")
+                               print("For more information about certificates please see http://prosody.im/doc/certificates");
+                               ok = false
+                       end
+               end
+               print("")
+       end
        if not ok then
                print("Problems found, see above.");
        else