diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/modulemanager.lua | 42 | ||||
-rw-r--r-- | core/servermanager.lua | 14 | ||||
-rw-r--r-- | core/sessionmanager.lua | 73 | ||||
-rw-r--r-- | core/usermanager.lua | 2 | ||||
-rw-r--r-- | core/xmlhandlers.lua | 32 |
5 files changed, 130 insertions, 33 deletions
diff --git a/core/modulemanager.lua b/core/modulemanager.lua index ad92b41b..6d803a26 100644 --- a/core/modulemanager.lua +++ b/core/modulemanager.lua @@ -4,6 +4,7 @@ local log = require "util.logger".init("modulemanager") local loadfile, pcall = loadfile, pcall; local setmetatable, setfenv, getfenv = setmetatable, setfenv, getfenv; local pairs, ipairs = pairs, ipairs; +local t_insert = table.insert; local type = type; local tostring, print = tostring, print; @@ -18,6 +19,7 @@ local handlers = {}; local modulehelpers = setmetatable({}, { __index = _G }); function modulehelpers.add_iq_handler(origin_type, xmlns, handler) + if not (origin_type and handler and xmlns) then return false; end handlers[origin_type] = handlers[origin_type] or {}; handlers[origin_type].iq = handlers[origin_type].iq or {}; if not handlers[origin_type].iq[xmlns] then @@ -29,17 +31,19 @@ function modulehelpers.add_iq_handler(origin_type, xmlns, handler) end end -function modulehelpers.add_handler(origin_type, tag, handler) +function modulehelpers.add_handler(origin_type, tag, xmlns, handler) + if not (origin_type and tag and xmlns and handler) then return false; end handlers[origin_type] = handlers[origin_type] or {}; if not handlers[origin_type][tag] then - handlers[origin_type][tag]= handler; + handlers[origin_type][tag] = handlers[origin_type][tag] or {}; + handlers[origin_type][tag][xmlns]= handler; handler_info[handler] = getfenv(2).module; log("debug", "mod_%s now handles tag '%s'", getfenv(2).module.name, tag); elseif handler_info[handlers[origin_type][tag]] then log("warning", "mod_%s wants to handle tag '%s' but mod_%s already handles that", getfenv(2).module.name, tag, handler_info[handlers[origin_type][tag]].module.name); end end - + function loadall() load("saslauth"); load("legacyauth"); @@ -79,14 +83,38 @@ function handle_stanza(origin, stanza) end end - --FIXME: All iq's must be replied to, here we should return service-unavailable I think elseif handlers[origin_type] then local handler = handlers[origin_type][name]; if handler then - log("debug", "Passing stanza to mod_%s", handler_info[handler].name); - return handler(origin, stanza) or true; + handler = handler[xmlns]; + if handler then + log("debug", "Passing stanza to mod_%s", handler_info[handler].name); + return handler(origin, stanza) or true; + end end end - log("debug", "Stanza unhandled by any modules"); + log("debug", "Stanza unhandled by any modules, xmlns: %s", stanza.attr.xmlns); return false; -- we didn't handle it end + +do + local event_handlers = {}; + + function modulehelpers.add_event_hook(name, handler) + if not event_handlers[name] then + event_handlers[name] = {}; + end + t_insert(event_handlers[name] , handler); + end + + function fire_event(name, ...) + local event_handlers = event_handlers[name]; + if event_handlers then + for name, handler in ipairs(event_handlers) do + handler(...); + end + end + end +end + +return _M; diff --git a/core/servermanager.lua b/core/servermanager.lua index 02ccab53..c1e075db 100644 --- a/core/servermanager.lua +++ b/core/servermanager.lua @@ -1,8 +1,20 @@ +local st = require "util.stanza"; +local send = require "core.sessionmanager".send_to_session; +local xmlns_stanzas ='urn:ietf:params:xml:ns:xmpp-stanzas'; + require "modulemanager" -- Handle stanzas that were addressed to the server (whether they came from c2s, s2s, etc.) function handle_stanza(origin, stanza) -- Use plugins - return modulemanager.handle_stanza(origin, stanza); + if not modulemanager.handle_stanza(origin, stanza) then + if stanza.name == "iq" then + local reply = st.reply(stanza); + reply.attr.type = "error"; + reply:tag("error", { type = "cancel" }) + :tag("service-unavailable", { xmlns = xmlns_stanzas }); + send(origin, reply); + end + end end diff --git a/core/sessionmanager.lua b/core/sessionmanager.lua index e89de262..a7a9ff10 100644 --- a/core/sessionmanager.lua +++ b/core/sessionmanager.lua @@ -1,22 +1,62 @@ -local tostring = tostring; - -local print = print; +local tonumber, tostring = tonumber, tostring; +local ipairs, pairs, print= ipairs, pairs, print; +local collectgarbage = collectgarbage; +local m_random = import("math", "random"); +local format = import("string", "format"); local hosts = hosts; +local sessions = sessions; +local modulemanager = require "core.modulemanager"; local log = require "util.logger".init("sessionmanager"); +local error = error; +local uuid_generate = require "util.uuid".uuid_generate; + +local newproxy = newproxy; +local getmetatable = getmetatable; module "sessionmanager" function new_session(conn) local session = { conn = conn, notopen = true, priority = 0, type = "c2s_unauthed" }; + if true then + session.trace = newproxy(true); + getmetatable(session.trace).__gc = function () print("Session got collected") end; + end local w = conn.write; session.send = function (t) w(tostring(t)); end return session; end function destroy_session(session) + if not (session and session.disconnect) then return; end + log("debug", "Destroying session..."); + session.disconnect(); + if session.username then + if session.resource then + hosts[session.host].sessions[session.username].sessions[session.resource] = nil; + end + local nomore = true; + for res, ssn in pairs(hosts[session.host].sessions[session.username]) do + nomore = false; + end + if nomore then + hosts[session.host].sessions[session.username] = nil; + end + end + session.conn = nil; + session.disconnect = nil; + for k in pairs(session) do + if k ~= "trace" then + session[k] = nil; + end + end + collectgarbage("collect"); + collectgarbage("collect"); + collectgarbage("collect"); + collectgarbage("collect"); + collectgarbage("collect"); end function send_to_session(session, data) @@ -26,16 +66,16 @@ end function make_authenticated(session, username) session.username = username; - session.resource = resource; if session.type == "c2s_unauthed" then session.type = "c2s"; end + return true; end function bind_resource(session, resource) if not session.username then return false, "auth"; end if session.resource then return false, "constraint"; end -- We don't support binding multiple resources - resource = resource or math.random(100000, 99999999); -- FIXME: Clearly we have issues :) + resource = resource or uuid_generate(); --FIXME: Randomly-generated resources must be unique per-user, and never conflict with existing if not hosts[session.host].sessions[session.username] then @@ -54,4 +94,27 @@ function bind_resource(session, resource) return true; end +function streamopened(session, attr) + local send = session.send; + session.host = attr.to or error("Client failed to specify destination hostname"); + session.version = tonumber(attr.version) or 0; + session.streamid = m_random(1000000, 99999999); + print(session, session.host, "Client opened stream"); + send("<?xml version='1.0'?>"); + send(format("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='%s' from='%s' version='1.0'>", session.streamid, session.host)); + + local features = {}; + modulemanager.fire_event("stream-features", session, features); + + send("<stream:features>"); + + for _, feature in ipairs(features) do + send_to_session(session, tostring(feature)); + end + + send("</stream:features>"); + log("info", "Stream opened successfully"); + session.notopen = nil; +end + return _M;
\ No newline at end of file diff --git a/core/usermanager.lua b/core/usermanager.lua index a67ad368..0f303b24 100644 --- a/core/usermanager.lua +++ b/core/usermanager.lua @@ -1,10 +1,12 @@ require "util.datamanager" local datamanager = datamanager; +local log = require "util.logger".init("usermanager"); module "usermanager" function validate_credentials(host, username, password) + log("debug", "User '%s' is being validated", username); local credentials = datamanager.load(username, host, "accounts") or {}; if password == credentials.password then return true; end return false; diff --git a/core/xmlhandlers.lua b/core/xmlhandlers.lua index b6050c5a..ebc8f91d 100644 --- a/core/xmlhandlers.lua +++ b/core/xmlhandlers.lua @@ -1,4 +1,5 @@ +local sessionmanager_streamopened = require "core.sessionmanager".streamopened; require "util.stanza" local st = stanza; @@ -9,6 +10,7 @@ local t_insert = table.insert; local t_remove = table.remove; local t_concat = table.concat; local t_concatall = function (t, sep) local tt = {}; for _, s in ipairs(t) do t_insert(tt, tostring(s)); end return t_concat(tt, sep); end +local sm_destroy_session = import("core.sessionmanager", "destroy_session"); local error = error; @@ -27,7 +29,6 @@ function init_xmlhandlers(session) local stanza function xml_handlers:StartElement(name, attr) - log("info", "xmlhandlers", "Start element: " .. name); if stanza and #chardata > 0 then -- We have some character data in the buffer stanza:text(t_concat(chardata)); @@ -37,24 +38,7 @@ function init_xmlhandlers(session) if not stanza then if session.notopen then if name == "stream" then - session.host = attr.to or error("Client failed to specify destination hostname"); - session.version = attr.version or 0; - session.streamid = m_random(1000000, 99999999); - print(session, session.host, "Client opened stream"); - send("<?xml version='1.0'?>"); - send(format("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='%s' from='%s' version='1.0'>", session.streamid, session.host)); - send("<stream:features>"); - if not session.username then - send("<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"); - send("<mechanism>PLAIN</mechanism>"); - send("</mechanisms>"); - else - send("<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><required/></bind>"); - end - --send [[<register xmlns="http://jabber.org/features/iq-register"/> ]] - send("</stream:features>"); - log("info", "core", "Stream opened successfully"); - session.notopen = nil; + sessionmanager_streamopened(session, attr); return; end error("Client failed to open stream successfully"); @@ -77,7 +61,15 @@ function init_xmlhandlers(session) end function xml_handlers:EndElement(name) curr_ns,name = name:match("^(.+):(%w+)$"); - if (not stanza) or #stanza.last_add < 0 or (#stanza.last_add > 0 and name ~= stanza.last_add[#stanza.last_add].name) then error("XML parse error in client stream"); end + if (not stanza) or #stanza.last_add < 0 or (#stanza.last_add > 0 and name ~= stanza.last_add[#stanza.last_add].name) then + if name == "stream" then + log("debug", "Stream closed"); + sm_destroy_session(session); + return; + else + error("XML parse error in client stream"); + end + end if stanza and #chardata > 0 then -- We have some character data in the buffer stanza:text(t_concat(chardata)); |