diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/mod_component.lua | 158 |
1 files changed, 6 insertions, 152 deletions
diff --git a/plugins/mod_component.lua b/plugins/mod_component.lua index e5ea47a2..fa2c166f 100644 --- a/plugins/mod_component.lua +++ b/plugins/mod_component.lua @@ -33,74 +33,18 @@ local component_listener = { default_port = 5347; default_mode = "*a"; default_i local xmlns_component = 'jabber:component:accept'; ---- Callbacks/data for xmlhandlers to handle streams for us --- - -local stream_callbacks = { stream_tag = "http://etherx.jabber.org/streams|stream", default_ns = xmlns_component }; - -function stream_callbacks.error(session, error, data, data2) - log("warn", "Error processing component stream: "..tostring(error)); - if error == "no-stream" then - session:close("invalid-namespace"); - elseif error == "xml-parse-error" and data == "unexpected-element-close" then - session.log("debug", "Unexpected close of '%s' tag", data2); - session:close("xml-not-well-formed"); - else - session.log("debug", "External component %s XML parse error: %s", tostring(session.host), tostring(error)); - print(data, debug.traceback()) - session:close("xml-not-well-formed"); - end -end - -function stream_callbacks.streamopened(session, attr) - if config.get(attr.to, "core", "component_module") ~= "component" then - -- Trying to act as a component domain which - -- hasn't been configured - session:close{ condition = "host-unknown", text = tostring(attr.to).." does not match any configured external components" }; - return; - end - - -- Store the original host (this is used for config, etc.) - session.user = attr.to; - -- Set the host for future reference - session.host = config.get(attr.to, "core", "component_address") or attr.to; - -- Note that we don't create the internal component - -- until after the external component auths successfully - - session.streamid = uuid_gen(); - session.notopen = nil; - - session.send(st.stanza("stream:stream", { xmlns=xmlns_component, - ["xmlns:stream"]='http://etherx.jabber.org/streams', id=session.streamid, from=session.host }):top_tag()); - -end - -function stream_callbacks.streamclosed(session) - session.send("</stream:stream>"); - session.notopen = true; -end - -local core_process_stanza = core_process_stanza; - -function stream_callbacks.handlestanza(session, stanza) - -- Namespaces are icky. - log("warn", "Handing stanza with name %s", stanza.name); - if stanza.name ~= "handshake" then - return core_process_stanza(session, stanza); - else - handle_component_auth(session, stanza); - end -end - --- Handle authentication attempts by components function handle_component_auth(session, stanza) + log("info", "Handling component auth"); if (not session.host) or #stanza.tags > 0 then + (session.log or log)("warn", "Component handshake invalid"); session:close("not-authorized"); return; end local secret = config.get(session.user, "core", "component_secret"); if not secret then - log("warn", "Component attempted to identify as %s, but component_password is not set", session.user); + (session.log or log)("warn", "Component attempted to identify as %s, but component_password is not set", session.user); session:close("not-authorized"); return; end @@ -108,18 +52,21 @@ function handle_component_auth(session, stanza) local supplied_token = t_concat(stanza); local calculated_token = sha1(session.streamid..secret, true); if supplied_token:lower() ~= calculated_token:lower() then + log("info", "Component for %s authentication failed", session.host); session:close{ condition = "not-authorized", text = "Given token does not match calculated token" }; return; end -- Authenticated now + log("info", "Component authenticated: %s", session.host); -- If component not already created for this host, create one now if not hosts[session.host].connected then local send = session.send; session.component_session = cm_register_component(session.host, function (_, data) return send(data); end); hosts[session.host].connected = true; + log("info", "Component successfully registered"); else log("error", "Multiple components bound to the same address, first one wins (TODO: Implement stanza distribution)"); end @@ -129,96 +76,3 @@ function handle_component_auth(session, stanza) end module:add_handler("component", "handshake", xmlns_component, handle_component_auth); - ---- Closing a component connection -local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; -local function session_close(session, reason) - local log = session.log or log; - if session.conn then - if reason then - if type(reason) == "string" then -- assume stream error - log("info", "Disconnecting component, <stream:error> is: %s", reason); - session.send(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' })); - elseif type(reason) == "table" then - if reason.condition then - local stanza = st.stanza("stream:error"):tag(reason.condition, stream_xmlns_attr):up(); - if reason.text then - stanza:tag("text", stream_xmlns_attr):text(reason.text):up(); - end - if reason.extra then - stanza:add_child(reason.extra); - end - log("info", "Disconnecting component, <stream:error> is: %s", tostring(stanza)); - session.send(stanza); - elseif reason.name then -- a stanza - log("info", "Disconnecting component, <stream:error> is: %s", tostring(reason)); - session.send(reason); - end - end - end - session.send("</stream:stream>"); - session.conn.close(); - component_listener.disconnect(session.conn, "stream error"); - end -end - ---- Component connlistener -function component_listener.listener(conn, data) - local session = sessions[conn]; - if not session then - local _send = conn.write; - session = { type = "component", conn = conn, send = function (data) return _send(tostring(data)); end }; - sessions[conn] = session; - - -- Logging functions -- - - local conn_name = "xep114-"..tostring(conn):match("[a-f0-9]+$"); - session.log = logger.init(conn_name); - session.close = session_close; - - session.log("info", "Incoming XEP-0114 connection"); - - local parser = lxp.new(init_xmlhandlers(session, stream_callbacks), "|"); - session.parser = parser; - - session.notopen = true; - - function session.data(conn, data) - local ok, err = parser:parse(data); - if ok then return; end - session:close("xml-not-well-formed"); - end - - session.dispatch_stanza = stream_callbacks.handlestanza; - - end - if data then - session.data(conn, data); - end -end - -function component_listener.disconnect(conn, err) - local session = sessions[conn]; - if session then - (session.log or log)("info", "component disconnected: %s (%s)", tostring(session.host), tostring(err)); - if session.host then - log("debug", "deregistering component"); - cm_deregister_component(session.host); - hosts[session.host].connected = nil; - end - sessions[conn] = nil; - session = nil; - collectgarbage("collect"); - end -end - -connlisteners.register('component', component_listener); - -module:add_event_hook("server-started", - function () - if _G.net_activate_ports then - _G.net_activate_ports("component", "component", {5437}, "tcp"); - else - error("No net_activate_ports: Using an incompatible version of Prosody?"); - end - end); |