Merge 0.10->trunk
[prosody.git] / plugins / mod_admin_telnet.lua
index 71dfa300b85aece8dfd8f2a6bbc19fc10c348a9f..9185ac1ba41586c19cdc3f077315cc5e96488824 100644 (file)
@@ -27,6 +27,7 @@ local set, array = require "util.set", require "util.array";
 local cert_verify_identity = require "util.x509".verify_identity;
 local envload = require "util.envload".envload;
 local envloadfile = require "util.envload".envloadfile;
+local has_pposix, pposix = pcall(require, "util.pposix");
 
 local commands = module:shared("commands")
 local def_env = module:shared("env");
@@ -154,6 +155,14 @@ function console_listener.onincoming(conn, data)
        session.partial_data = data:match("[^\n]+$");
 end
 
+function console_listener.onreadtimeout(conn)
+       local session = sessions[conn];
+       if session then
+               session.send("\0");
+               return true;
+       end
+end
+
 function console_listener.ondisconnect(conn, err)
        local session = sessions[conn];
        if session then
@@ -162,6 +171,10 @@ function console_listener.ondisconnect(conn, err)
        end
 end
 
+function console_listener.ondetach(conn)
+       sessions[conn] = nil;
+end
+
 -- Console commands --
 -- These are simple commands, not valid standalone in Lua
 
@@ -212,9 +225,11 @@ function commands.help(session, data)
                print [[c2s:show(jid) - Show all client sessions with the specified JID (or all if no JID given)]]
                print [[c2s:show_insecure() - Show all unencrypted client connections]]
                print [[c2s:show_secure() - Show all encrypted client connections]]
+               print [[c2s:show_tls() - Show TLS cipher info for encrypted sessions]]
                print [[c2s:close(jid) - Close all sessions for the specified JID]]
        elseif section == "s2s" then
                print [[s2s:show(domain) - Show all s2s connections for the given domain (or all if no domain given)]]
+               print [[s2s:show_tls(domain) - Show TLS cipher info for encrypted sessions]]
                print [[s2s:close(from, to) - Close a connection from one domain to another]]
                print [[s2s:closeall(host) - Close all the incoming/outgoing s2s sessions to specified host]]
        elseif section == "module" then
@@ -308,7 +323,7 @@ local function human(kb)
 end
 
 function def_env.server:memory()
-       if not pposix.meminfo then
+       if not has_pposix or not pposix.meminfo then
                return true, "Lua is using "..collectgarbage("count");
        end
        local mem, lua_mem = pposix.meminfo(), collectgarbage("count");
@@ -471,22 +486,28 @@ function def_env.config:reload()
        return ok, (ok and "Config reloaded (you may need to reload modules to take effect)") or tostring(err);
 end
 
-def_env.hosts = {};
-function def_env.hosts:list()
-       for host, host_session in pairs(hosts) do
-               self.session.print(host);
+local function common_info(session, line)
+       if session.id then
+               line[#line+1] = "["..session.id.."]"
+       else
+               line[#line+1] = "["..session.type..(tostring(session):match("%x*$")).."]"
        end
-       return true, "Done";
-end
-
-function def_env.hosts:add(name)
 end
 
 local function session_flags(session, line)
        line = line or {};
+       common_info(session, line);
+       if session.type == "c2s" then
+               local status, priority = "unavailable", tostring(session.priority or "-");
+               if session.presence then
+                       status = session.presence:get_child_text("show") or "available";
+               end
+               line[#line+1] = status.."("..priority..")";
+       end
        if session.cert_identity_status == "valid" then
-               line[#line+1] = "(secure)";
-       elseif session.secure then
+               line[#line+1] = "(authenticated)";
+       end
+       if session.secure then
                line[#line+1] = "(encrypted)";
        end
        if session.compressed then
@@ -501,6 +522,23 @@ local function session_flags(session, line)
        return table.concat(line, " ");
 end
 
+local function tls_info(session, line)
+       line = line or {};
+       common_info(session, line);
+       if session.secure then
+               local sock = session.conn and session.conn.socket and session.conn:socket();
+               if sock and sock.info then
+                       local info = sock:info();
+                       line[#line+1] = ("(%s with %s)"):format(info.protocol, info.cipher);
+               else
+                       line[#line+1] = "(cipher info unavailable)";
+               end
+       else
+               line[#line+1] = "(insecure)";
+       end
+       return table.concat(line, " ");
+end
+
 def_env.c2s = {};
 
 local function show_c2s(callback)
@@ -524,8 +562,9 @@ function def_env.c2s:count(match_jid)
        return true, "Total: "..count.." clients";
 end
 
-function def_env.c2s:show(match_jid)
+function def_env.c2s:show(match_jid, annotate)
        local print, count = self.session.print, 0;
+       annotate = annotate or session_flags;
        local curr_host;
        show_c2s(function (jid, session)
                if curr_host ~= session.host then
@@ -534,11 +573,7 @@ function def_env.c2s:show(match_jid)
                end
                if (not match_jid) or jid:match(match_jid) then
                        count = count + 1;
-                       local status, priority = "unavailable", tostring(session.priority or "-");
-                       if session.presence then
-                               status = session.presence:get_child_text("show") or "available";
-                       end
-                       print(session_flags(session, { "   "..jid.." - "..status.."("..priority..")" }));
+                       print(annotate(session, { "  ", jid }));
                end
        end);
        return true, "Total: "..count.." clients";
@@ -566,6 +601,10 @@ function def_env.c2s:show_secure(match_jid)
        return true, "Total: "..count.." secure client connections";
 end
 
+function def_env.c2s:show_tls(match_jid)
+       return self:show(match_jid, tls_info);
+end
+
 function def_env.c2s:close(match_jid)
        local count = 0;
        show_c2s(function (jid, session)
@@ -579,8 +618,9 @@ end
 
 
 def_env.s2s = {};
-function def_env.s2s:show(match_jid)
+function def_env.s2s:show(match_jid, annotate)
        local print = self.session.print;
+       annotate = annotate or session_flags;
 
        local count_in, count_out = 0,0;
        local s2s_list = { };
@@ -598,8 +638,7 @@ function def_env.s2s:show(match_jid)
                        remotehost, localhost = session.from_host or "?", session.to_host or "?";
                end
                local sess_lines = { l = localhost, r = remotehost,
-                       session_flags(session, { "", direction, remotehost or "?",
-                               "["..session.type..tostring(session):match("[a-f0-9]*$").."]" })};
+                       annotate(session, { "", direction, remotehost or "?" })};
 
                if (not match_jid) or remotehost:match(match_jid) or localhost:match(match_jid) then
                        table.insert(s2s_list, sess_lines);
@@ -654,6 +693,10 @@ function def_env.s2s:show(match_jid)
        return true, "Total: "..count_out.." outgoing, "..count_in.." incoming connections";
 end
 
+function def_env.s2s:show_tls(match_jid)
+       return self:show(match_jid, tls_info);
+end
+
 local function print_subject(print, subject)
        for _, entry in ipairs(subject) do
                print(
@@ -823,9 +866,19 @@ end
 function def_env.host:list()
        local print = self.session.print;
        local i = 0;
+       local type;
        for host in values(array.collect(keys(prosody.hosts)):sort()) do
                i = i + 1;
-               print(host);
+               type = hosts[host].type;
+               if type == "local" then
+                       print(host);
+               else
+                       type = module:context(host):get_option_string("component_module", type);
+                       if type ~= "component" then
+                               type = type .. " component";
+                       end
+                       print(("%s (%s)"):format(host, type));
+               end
        end
        return true, i.." hosts";
 end
@@ -909,13 +962,26 @@ function def_env.muc:room(room_jid)
        if not room_name then
                return room_name, host;
        end
-       local room_obj = hosts[host].modules.muc.rooms[room_jid];
+       local room_obj = hosts[host].modules.muc.get_room_from_jid(room_jid);
        if not room_obj then
                return nil, "No such room: "..room_jid;
        end
        return setmetatable({ room = room_obj }, console_room_mt);
 end
 
+function def_env.muc:list(host)
+       local host_session = hosts[host];
+       if not host_session or not host_session.modules.muc then
+               return nil, "Please supply the address of a local MUC component";
+       end
+       local c = 0;
+       for room in host_session.modules.muc.each_room() do
+               print(room.jid);
+               c = c + 1;
+       end
+       return true, c.." rooms";
+end
+
 local um = require"core.usermanager";
 
 def_env.user = {};
@@ -1012,12 +1078,12 @@ function def_env.dns:lookup(name, typ, class)
 end
 
 function def_env.dns:addnameserver(...)
-       dns.addnameserver(...)
+       dns._resolver:addnameserver(...)
        return true
 end
 
 function def_env.dns:setnameserver(...)
-       dns.setnameserver(...)
+       dns._resolver:setnameserver(...)
        return true
 end