diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/mod_console.lua | 140 | ||||
-rw-r--r-- | plugins/mod_dialback.lua | 8 | ||||
-rw-r--r-- | plugins/mod_disco.lua | 9 | ||||
-rw-r--r-- | plugins/mod_register.lua | 29 | ||||
-rw-r--r-- | plugins/mod_roster.lua | 15 | ||||
-rw-r--r-- | plugins/mod_saslauth.lua | 16 | ||||
-rw-r--r-- | plugins/mod_selftests.lua | 53 | ||||
-rw-r--r-- | plugins/mod_tls.lua | 3 | ||||
-rw-r--r-- | plugins/mod_vcard.lua | 3 |
9 files changed, 262 insertions, 14 deletions
diff --git a/plugins/mod_console.lua b/plugins/mod_console.lua new file mode 100644 index 00000000..5787ad25 --- /dev/null +++ b/plugins/mod_console.lua @@ -0,0 +1,140 @@ +
+local connlisteners_register = require "net.connlisteners".register;
+
+local console_listener = { default_port = 5582; default_mode = "*l"; };
+
+local commands = {};
+local default_env = {};
+local default_env_mt = { __index = default_env };
+
+console = {};
+
+function console:new_session(conn)
+ local w = conn.write;
+ return { conn = conn;
+ send = function (t) w(tostring(t)); end;
+ print = function (t) w("| "..tostring(t).."\n"); end;
+ disconnect = function () conn.close(); end;
+ env = setmetatable({}, default_env_mt);
+ };
+end
+
+local sessions = {};
+
+function console_listener.listener(conn, data)
+ local session = sessions[conn];
+
+ if not session then
+ -- Handle new connection
+ session = console:new_session(conn);
+ sessions[conn] = session;
+ session.print("Welcome to the lxmppd admin console!");
+ end
+ if data then
+ -- Handle data
+
+ if data:match("[!.]$") then
+ local command = data:lower();
+ command = data:match("^%w+") or data:match("%p");
+ if commands[command] then
+ commands[command](session, data);
+ return;
+ end
+ end
+
+ session.env._ = data;
+
+ local chunk, err = loadstring("return "..data);
+ if not chunk then
+ chunk, err = loadstring(data);
+ if not chunk then
+ err = err:gsub("^%[string .-%]:%d+: ", "");
+ err = err:gsub("^:%d+: ", "");
+ err = err:gsub("'<eof>'", "the end of the line");
+ session.print("Sorry, I couldn't understand that... "..err);
+ return;
+ end
+ end
+
+ setfenv(chunk, session.env);
+ local ranok, taskok, message = pcall(chunk);
+
+ if not ranok then
+ session.print("Fatal error while running command, it did not complete");
+ session.print("Error: "..taskok);
+ return;
+ end
+
+ if not message then
+ session.print("Result: "..tostring(taskok));
+ return;
+ elseif (not taskok) and message then
+ session.print("Command completed with a problem");
+ session.print("Message: "..tostring(message));
+ return;
+ end
+
+ session.print("OK: "..tostring(message));
+ end
+end
+
+function console_listener.disconnect(conn, err)
+
+end
+
+connlisteners_register('console', console_listener);
+
+-- Console commands --
+-- These are simple commands, not valid standalone in Lua
+
+function commands.bye(session)
+ session.print("See you! :)");
+ session.disconnect();
+end
+
+commands["!"] = function (session, data)
+ if data:match("^!!") then
+ session.print("!> "..session.env._);
+ return console_listener.listener(session.conn, session.env._);
+ end
+ local old, new = data:match("^!(.-[^\\])!(.-)!$");
+ if old and new then
+ local ok, res = pcall(string.gsub, session.env._, old, new);
+ if not ok then
+ session.print(res)
+ return;
+ end
+ session.print("!> "..res);
+ return console_listener.listener(session.conn, res);
+ end
+ session.print("Sorry, not sure what you want");
+end
+
+-- Session environment --
+-- Anything in default_env will be accessible within the session as a global variable
+
+default_env.server = {};
+function default_env.server.reload()
+ dofile "main.lua"
+ return true, "Server reloaded";
+end
+
+default_env.module = {};
+function default_env.module.load(name)
+ local mm = require "modulemanager";
+ local ok, err = mm.load(name);
+ if not ok then
+ return false, err or "Unknown error loading module";
+ end
+ return true, "Module loaded";
+end
+
+default_env.config = {};
+function default_env.config.load(filename, format)
+ local cfgm_load = require "core.configmanager".load;
+ local ok, err = cfgm_load(filename, format);
+ if not ok then
+ return false, err or "Unknown error loading config";
+ end
+ return true, "Config loaded";
+end
diff --git a/plugins/mod_dialback.lua b/plugins/mod_dialback.lua index c17cbcaf..87ac303b 100644 --- a/plugins/mod_dialback.lua +++ b/plugins/mod_dialback.lua @@ -55,8 +55,12 @@ add_handler({ "s2sout_unauthed", "s2sout" }, "verify", xmlns_dialback, log("warn", "dialback for "..(origin.dialback_verifying.from_host or "(unknown)").." failed"); valid = "invalid"; end - origin.dialback_verifying.sends2s(format("<db:result from='%s' to='%s' id='%s' type='%s'>%s</db:result>", - attr.from, attr.to, attr.id, valid, origin.dialback_verifying.dialback_key)); + if not origin.dialback_verifying.sends2s then + log("warn", "Incoming s2s session %s was closed in the meantime, so we can't notify it of the db result", tostring(origin.dialback_verifying):match("%w+$")); + else + origin.dialback_verifying.sends2s(format("<db:result from='%s' to='%s' id='%s' type='%s'>%s</db:result>", + attr.to, attr.from, attr.id, valid, origin.dialback_verifying.dialback_key)); + end end end); diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua new file mode 100644 index 00000000..261650ce --- /dev/null +++ b/plugins/mod_disco.lua @@ -0,0 +1,9 @@ +
+local discomanager_handle = require "core.discomanager".handle;
+
+add_iq_handler({"c2s", "s2sin"}, "http://jabber.org/protocol/disco#info", function (session, stanza)
+ session.send(discomanager_handle(stanza));
+end);
+add_iq_handler({"c2s", "s2sin"}, "http://jabber.org/protocol/disco#items", function (session, stanza)
+ session.send(discomanager_handle(stanza));
+end);
diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index fb001392..c2b85bae 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -2,6 +2,7 @@ local st = require "util.stanza"; local usermanager_user_exists = require "core.usermanager".user_exists; local usermanager_create_user = require "core.usermanager".create_user; +local datamanager_store = require "util.datamanager".store; add_iq_handler("c2s", "jabber:iq:register", function (session, stanza) if stanza.tags[1].name == "query" then @@ -16,7 +17,33 @@ add_iq_handler("c2s", "jabber:iq:register", function (session, stanza) elseif stanza.attr.type == "set" then if query.tags[1] and query.tags[1].name == "remove" then -- TODO delete user auth data, send iq response, kick all user resources with a <not-authorized/>, delete all user data - session.send(st.error_reply(stanza, "cancel", "not-allowed")); + --session.send(st.error_reply(stanza, "cancel", "not-allowed")); + --return; + usermanager_create_user(session.username, nil, session.host); -- Disable account + -- FIXME the disabling currently allows a different user to recreate the account + -- we should add an in-memory account block mode when we have threading + session.send(st.reply(stanza)); + local roster = session.roster; + for _, session in pairs(hosts[session.host].sessions[session.username].sessions) do -- disconnect all resources + session:disconnect({condition = "not-authorized", text = "Account deleted"}); + end + -- TODO datamanager should be able to delete all user data itself + datamanager.store(session.username, session.host, "roster", nil); + datamanager.store(session.username, session.host, "vCard", nil); + datamanager.store(session.username, session.host, "private", nil); + datamanager.store(session.username, session.host, "offline", nil); + local bare = session.username.."@"..session.host; + for jid, item in pairs(roster) do + if jid ~= "pending" then + if item.subscription == "both" or item.subscription == "to" then + -- TODO unsubscribe + end + if item.subscription == "both" or item.subscription == "from" then + -- TODO unsubscribe + end + end + end + datamanager.store(session.username, session.host, "accounts", nil); -- delete accounts datastore at the end else local username = query:child_with_name("username"); local password = query:child_with_name("password"); diff --git a/plugins/mod_roster.lua b/plugins/mod_roster.lua index 23a19828..24d858e7 100644 --- a/plugins/mod_roster.lua +++ b/plugins/mod_roster.lua @@ -4,6 +4,7 @@ local st = require "util.stanza" local jid_split = require "util.jid".split; local t_concat = table.concat; +local handle_outbound_presence_subscriptions_and_probes = require "core.presencemanager".handle_outbound_presence_subscriptions_and_probes; local rm_remove_from_roster = require "core.rostermanager".remove_from_roster; local rm_add_to_roster = require "core.rostermanager".add_to_roster; local rm_roster_push = require "core.rostermanager".roster_push; @@ -38,15 +39,25 @@ add_iq_handler("c2s", "jabber:iq:roster", and query.tags[1].attr.jid ~= "pending" then local item = query.tags[1]; local from_node, from_host = jid_split(stanza.attr.from); + local from_bare = from_node and (from_node.."@"..from_host) or from_host; -- bare JID local node, host, resource = jid_split(item.attr.jid); - if not resource then + local to_bare = node and (node.."@"..host) or host; -- bare JID + if not resource and host then if item.attr.jid ~= from_node.."@"..from_host then if item.attr.subscription == "remove" then - if session.roster[item.attr.jid] then + local r_item = session.roster[item.attr.jid]; + if r_item then local success, err_type, err_cond, err_msg = rm_remove_from_roster(session, item.attr.jid); if success then session.send(st.reply(stanza)); rm_roster_push(from_node, from_host, item.attr.jid); + if r_item.subscription == "both" or r_item.subscription == "from" then + handle_outbound_presence_subscriptions_and_probes(session, + st.presence({type="unsubscribed"}), from_bare, to_bare); + elseif r_item.subscription == "both" or r_item.subscription == "to" then + handle_outbound_presence_subscriptions_and_probes(session, + st.presence({type="unsubscribe"}), from_bare, to_bare); + end else session.send(st.error_reply(stanza, err_type, err_cond, err_msg)); end diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 6ceb0be3..7ca4308b 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -83,19 +83,21 @@ add_handler("c2s_unauthed", "auth", xmlns_sasl, sasl_handler); add_handler("c2s_unauthed", "abort", xmlns_sasl, sasl_handler); add_handler("c2s_unauthed", "response", xmlns_sasl, sasl_handler); +local mechanisms_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-sasl' }; +local bind_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-bind' }; +local xmpp_session_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-session' }; add_event_hook("stream-features", function (session, features) if not session.username then - t_insert(features, "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"); + features:tag("mechanisms", mechanisms_attr); -- TODO: Provide PLAIN only if TLS is active, this is a SHOULD from the introduction of RFC 4616. This behavior could be overridden via configuration but will issuing a warning or so. - t_insert(features, "<mechanism>PLAIN</mechanism>"); - t_insert(features, "<mechanism>DIGEST-MD5</mechanism>"); - t_insert(features, "</mechanisms>"); + features:tag("mechanism"):text("PLAIN"):up(); + features:tag("mechanism"):text("DIGEST-MD5"):up(); + features:up(); else - t_insert(features, "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><required/></bind>"); - t_insert(features, "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"); + features:tag("bind", bind_attr):tag("required"):up():up(); + features:tag("session", xmpp_session_attr):up(); end - --send [[<register xmlns="http://jabber.org/features/iq-register"/> ]] end); add_iq_handler("c2s", "urn:ietf:params:xml:ns:xmpp-bind", diff --git a/plugins/mod_selftests.lua b/plugins/mod_selftests.lua new file mode 100644 index 00000000..4f128504 --- /dev/null +++ b/plugins/mod_selftests.lua @@ -0,0 +1,53 @@ + +local st = require "util.stanza"; +local register_component = require "core.componentmanager".register_component; +local core_route_stanza = core_route_stanza; +local socket = require "socket"; +local config = require "core.configmanager"; +local ping_hosts = config.get("*", "mod_selftests", "ping_hosts") or { "jabber.org" }; + +local open_pings = {}; + +local t_insert = table.insert; + +local log = require "util.logger".init("mod_selftests"); + +local tests_jid = "self_tests@getjabber.ath.cx"; +local host = "getjabber.ath.cx"; + +if not (tests_jid and host) then + for currhost in pairs(host) do + if currhost ~= "localhost" then + tests_jid, host = "self_tests@"..currhost, currhost; + end + end +end + +if tests_jid and host then + local bot = register_component(tests_jid, function(origin, stanza, ourhost) + local time = open_pings[stanza.attr.id]; + + if time then + log("info", "Ping reply from %s in %fs", tostring(stanza.attr.from), socket.gettime() - time); + else + log("info", "Unexpected reply: %s", stanza:pretty_print()); + end + end); + + + local our_origin = hosts[host]; + add_event_hook("server-started", + function () + local id = st.new_id(); + local ping_attr = { xmlns = 'urn:xmpp:ping' }; + local function send_ping(to) + log("info", "Sending ping to %s", to); + core_route_stanza(our_origin, st.iq{ to = to, from = tests_jid, id = id, type = "get" }:tag("ping", ping_attr)); + open_pings[id] = socket.gettime(); + end + + for _, host in ipairs(ping_hosts) do + send_ping(host); + end + end); +end diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua index b5ca5015..cc46d556 100644 --- a/plugins/mod_tls.lua +++ b/plugins/mod_tls.lua @@ -24,9 +24,10 @@ add_handler("c2s_unauthed", "starttls", xmlns_starttls, end end); +local starttls_attr = { xmlns = xmlns_starttls }; add_event_hook("stream-features", function (session, features) if session.conn.starttls then - t_insert(features, "<starttls xmlns='"..xmlns_starttls.."'/>"); + features:tag("starttls", starttls_attr):up(); end end); diff --git a/plugins/mod_vcard.lua b/plugins/mod_vcard.lua index fb7382c2..d2f2c7ba 100644 --- a/plugins/mod_vcard.lua +++ b/plugins/mod_vcard.lua @@ -43,9 +43,10 @@ add_iq_handler({"c2s", "s2sin"}, "vcard-temp", end end); +local feature_vcard_attr = { var='vcard-temp' }; add_event_hook("stream-features", function (session, features) if session.type == "c2s" then - t_insert(features, "<feature var='vcard-temp'/>"); + features:tag("feature", feature_vcard_attr):up(); end end); |