diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/mod_bosh.lua | 2 | ||||
-rw-r--r-- | plugins/mod_compression.lua | 31 | ||||
-rw-r--r-- | plugins/mod_legacyauth.lua | 7 | ||||
-rw-r--r-- | plugins/mod_presence.lua | 19 | ||||
-rw-r--r-- | plugins/mod_privacy.lua | 146 | ||||
-rw-r--r-- | plugins/mod_roster.lua | 12 | ||||
-rw-r--r-- | plugins/mod_saslauth.lua | 17 | ||||
-rw-r--r-- | plugins/mod_tls.lua | 139 |
8 files changed, 152 insertions, 221 deletions
diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index f25e7670..2cb3100e 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -206,6 +206,7 @@ function stream_callbacks.streamopened(request, attr) -- Send creation response local features = st.stanza("stream:features"); + hosts[session.host].events.fire_event("stream-features", { origin = session, features = features }); fire_event("stream-features", session, features); --xmpp:version='1.0' xmlns:xmpp='urn:xmpp:xbosh' local response = st.stanza("body", { xmlns = xmlns_bosh, @@ -257,6 +258,7 @@ function stream_callbacks.streamopened(request, attr) if session.notopen then local features = st.stanza("stream:features"); + hosts[session.host].events.fire_event("stream-features", { origin = session, features = features }); fire_event("stream-features", session, features); session.send(features); session.notopen = nil; diff --git a/plugins/mod_compression.lua b/plugins/mod_compression.lua index 638b8e13..4b1fa79f 100644 --- a/plugins/mod_compression.lua +++ b/plugins/mod_compression.lua @@ -25,24 +25,21 @@ if not compression_level or compression_level < 1 or compression_level > 9 then return; end -module:add_event_hook("stream-features", - function (session, features) - if not session.compressed then - -- FIXME only advertise compression support when TLS layer has no compression enabled - features:add_child(compression_stream_feature); - end - end -); +module:hook("stream-features", function(event) + local origin, features = event.origin, event.features; + if not origin.compressed then + -- FIXME only advertise compression support when TLS layer has no compression enabled + features:add_child(compression_stream_feature); + end +end); -module:hook("s2s-stream-features", - function (data) - local session, features = data.session, data.features; - -- FIXME only advertise compression support when TLS layer has no compression enabled - if not session.compressed then - features:add_child(compression_stream_feature); - end - end -); +module:hook("s2s-stream-features", function(event) + local origin, features = event.origin, event.features; + -- FIXME only advertise compression support when TLS layer has no compression enabled + if not origin.compressed then + features:add_child(compression_stream_feature); + end +end); -- Hook to activate compression if remote server supports it. module:hook_stanza(xmlns_stream, "features", diff --git a/plugins/mod_legacyauth.lua b/plugins/mod_legacyauth.lua index c678dce1..9837920b 100644 --- a/plugins/mod_legacyauth.lua +++ b/plugins/mod_legacyauth.lua @@ -19,11 +19,12 @@ local nodeprep = require "util.encodings".stringprep.nodeprep; local resourceprep = require "util.encodings".stringprep.resourceprep; module:add_feature("jabber:iq:auth"); -module:add_event_hook("stream-features", function (session, features) - if secure_auth_only and not session.secure then +module:hook("stream-features", function(event) + local origin, features = event.origin, event.features; + if secure_auth_only and not origin.secure then -- Sorry, not offering to insecure streams! return; - elseif not session.username then + elseif not origin.username then features:tag("auth", {xmlns='http://jabber.org/features/iq-auth'}):up(); end end); diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua index c28dd338..f6ea9e6b 100644 --- a/plugins/mod_presence.lua +++ b/plugins/mod_presence.lua @@ -18,6 +18,7 @@ local st = require "util.stanza"; local jid_split = require "util.jid".split; local jid_bare = require "util.jid".bare; local hosts = hosts; +local NULL = {}; local rostermanager = require "core.rostermanager"; local sessionmanager = require "core.sessionmanager"; @@ -54,16 +55,18 @@ local function select_top_resources(user) end return recipients; end -local function recalc_resource_map(origin) - local user = hosts[origin.host].sessions[origin.username]; - user.top_resources = select_top_resources(user); - if #user.top_resources == 0 then user.top_resources = nil; end +local function recalc_resource_map(user) + if user then + user.top_resources = select_top_resources(user); + if #user.top_resources == 0 then user.top_resources = nil; end + end end function handle_normal_presence(origin, stanza, core_route_stanza) local roster = origin.roster; local node, host = origin.username, origin.host; - for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast to all resources + local user = bare_sessions[node.."@"..host]; + for _, res in pairs(user and user.sessions or NULL) do -- broadcast to all resources if res ~= origin and res.presence then -- to resource stanza.attr.to = res.full_jid; core_route_stanza(origin, stanza); @@ -84,7 +87,7 @@ function handle_normal_presence(origin, stanza, core_route_stanza) core_route_stanza(origin, probe); end end - for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast from all available resources + for _, res in pairs(user and user.sessions or NULL) do -- broadcast from all available resources if res ~= origin and res.presence then res.presence.attr.to = origin.full_jid; core_route_stanza(res, res.presence); @@ -115,7 +118,7 @@ function handle_normal_presence(origin, stanza, core_route_stanza) origin.presence = nil; if origin.priority then origin.priority = nil; - recalc_resource_map(origin); + recalc_resource_map(user); end if origin.directed then for jid in pairs(origin.directed) do @@ -137,7 +140,7 @@ function handle_normal_presence(origin, stanza, core_route_stanza) else priority = 0; end if origin.priority ~= priority then origin.priority = priority; - recalc_resource_map(origin); + recalc_resource_map(user); end end stanza.attr.to = nil; -- reset it diff --git a/plugins/mod_privacy.lua b/plugins/mod_privacy.lua index 05ca01d6..d3043d69 100644 --- a/plugins/mod_privacy.lua +++ b/plugins/mod_privacy.lua @@ -17,16 +17,6 @@ local jid_split = util_Jid.split; local load_roster = require "core.rostermanager".load_roster; local to_number = tonumber; -function findNamedList(privacy_lists, name) - if privacy_lists.lists then - for i=1,#privacy_lists.lists do - if privacy_lists.lists[i].name == name then - return i; - end - end - end -end - function isListUsed(origin, name, privacy_lists) local user = bare_sessions[origin.username.."@"..origin.host]; if user then @@ -75,40 +65,6 @@ function sendUnavailable(origin, to, from) end end -function sendNeededUnavailablePersences(origin, listnameOrItem) -- TODO implement it correctly! - if type(listnameOrItem) == "string" then - local listname = listnameOrItem; - for _,list in ipairs(privacy_lists.lists) do - if list.name == listname then - for _,item in ipairs(list.items) do - sendNeededUnavailablePersences(origin, item); - end - end - end - elseif type(listnameOrItem) == "table" then - module:log("debug", "got an item, check whether to send unavailable presence stanza or not"); - local item = listnameOrItem; - - if item["presence-out"] == true then - if item.type == "jid" then - sendUnavailable(origin, item.value, origin.full_jid); - elseif item.type == "group" then - elseif item.type == "subscription" then - elseif item.type == nil then - end - elseif item["presence-in"] == true then - if item.type == "jid" then - sendUnavailable(origin, origin.full_jid, item.value); - elseif item.type == "group" then - elseif item.type == "subscription" then - elseif item.type == nil then - end - end - else - module:log("debug", "got unknown type: %s", type(listnameOrItem)); - end -end - function declineList(privacy_lists, origin, stanza, which) if which == "default" then if isAnotherSessionUsingDefaultList(origin) then @@ -126,30 +82,17 @@ function declineList(privacy_lists, origin, stanza, which) end function activateList(privacy_lists, origin, stanza, which, name) - local idx = findNamedList(privacy_lists, name); + local list = privacy_lists.lists[name]; - if privacy_lists.default == nil then - privacy_lists.default = ""; - end - if origin.activePrivacyList == nil then - origin.activePrivacyList = ""; - end - - if which == "default" and idx ~= nil then + if which == "default" and list then if isAnotherSessionUsingDefaultList(origin) then return {"cancel", "conflict", "Another session is online and using the default list."}; end privacy_lists.default = name; origin.send(st.reply(stanza)); ---[[ - if origin.activePrivacyList == nil then - sendNeededUnavailablePersences(origin, name); - end -]]-- - elseif which == "active" and idx ~= nil then + elseif which == "active" and list then origin.activePrivacyList = name; origin.send(st.reply(stanza)); - -- sendNeededUnavailablePersences(origin, name); else return {"modify", "bad-request", "Either not active or default given or unknown list name specified."}; end @@ -157,19 +100,19 @@ function activateList(privacy_lists, origin, stanza, which, name) end function deleteList(privacy_lists, origin, stanza, name) - local idx = findNamedList(privacy_lists, name); + local list = privacy_lists.lists[name]; - if idx ~= nil then + if list then if isListUsed(origin, name, privacy_lists) then return {"cancel", "conflict", "Another session is online and using the list which should be deleted."}; end if privacy_lists.default == name then - privacy_lists.default = ""; + privacy_lists.default = nil; end if origin.activePrivacyList == name then - origin.activePrivacyList = ""; + origin.activePrivacyList = nil; end - table.remove(privacy_lists.lists, idx); + privacy_lists.lists[name] = nil; origin.send(st.reply(stanza)); return true; end @@ -177,19 +120,16 @@ function deleteList(privacy_lists, origin, stanza, name) end function createOrReplaceList (privacy_lists, origin, stanza, name, entries, roster) - local idx = findNamedList(privacy_lists, name); local bare_jid = origin.username.."@"..origin.host; if privacy_lists.lists == nil then privacy_lists.lists = {}; end - if idx == nil then - idx = #privacy_lists.lists + 1; - end + local list = {}; + privacy_lists.lists[name] = list; local orderCheck = {}; - local list = {}; list.name = name; list.items = {}; @@ -251,20 +191,11 @@ function createOrReplaceList (privacy_lists, origin, stanza, name, entries, rost if tmp.action ~= "deny" and tmp.action ~= "allow" then return {"cancel", "bad-request", "Action must be either deny or allow."}; end - ---[[ - if (privacy_lists.default == name and origin.activePrivacyList == nil) or origin.activePrivacyList == name then - module:log("debug", "calling sendNeededUnavailablePresences!"); - -- item is valid and list is active, so send needed unavailable stanzas - sendNeededUnavailablePersences(origin, tmp); - end -]]-- list.items[#list.items + 1] = tmp; end table.sort(list, function(a, b) return a.order < b.order; end); - privacy_lists.lists[idx] = list; origin.send(st.reply(stanza)); if bare_sessions[bare_jid] ~= nil then local iq = st.iq ( { type = "set", id="push1" } ); @@ -286,17 +217,20 @@ function getList(privacy_lists, origin, stanza, name) reply:tag("query", {xmlns="jabber:iq:privacy"}); if name == nil then - reply:tag("active", {name=origin.activePrivacyList or ""}):up(); - reply:tag("default", {name=privacy_lists.default or ""}):up(); if privacy_lists.lists then - for _,list in ipairs(privacy_lists.lists) do - reply:tag("list", {name=list.name}):up(); + if origin.ActivePrivacyList then + reply:tag("active", {name=origin.activePrivacyList}):up(); + end + if privacy_lists.default then + reply:tag("default", {name=privacy_lists.default}):up(); + end + for name,list in pairs(privacy_lists.lists) do + reply:tag("list", {name=name}):up(); end end else - local idx = findNamedList(privacy_lists, name); - if idx ~= nil then - local list = privacy_lists.lists[idx]; + local list = privacy_lists.lists[name]; + if list then reply = reply:tag("list", {name=list.name}); for _,item in ipairs(list.items) do reply:tag("item", {type=item.type, value=item.value, action=item.action, order=item.order}); @@ -321,7 +255,16 @@ module:hook("iq/bare/jabber:iq:privacy:query", function(data) if stanza.attr.to == nil then -- only service requests to own bare JID local query = stanza.tags[1]; -- the query element local valid = false; - local privacy_lists = datamanager.load(origin.username, origin.host, "privacy") or {}; + local privacy_lists = datamanager.load(origin.username, origin.host, "privacy") or { lists = {} }; + + if privacy_lists.lists[1] then -- Code to migrate from old privacy lists format, remove in 0.8 + module:log("info", "Upgrading format of stored privacy lists for %s@%s", origin.username, origin.host); + local lists = privacy_lists.lists; + for idx, list in ipairs(lists) do + lists[list.name] = list; + lists[idx] = nil; + end + end if stanza.attr.type == "set" then if #query.tags == 1 then -- the <query/> element MUST NOT include more than one child element @@ -358,13 +301,14 @@ module:hook("iq/bare/jabber:iq:privacy:query", function(data) end if valid ~= true then - if valid[0] == nil then - valid[0] = "cancel"; - end + valid = valid or { "cancel", "bad-request", "Couldn't understand request" }; if valid[1] == nil then - valid[1] = "bad-request"; + valid[1] = "cancel"; + end + if valid[2] == nil then + valid[2] = "bad-request"; end - origin.send(st.error_reply(stanza, valid[0], valid[1], valid[2])); + origin.send(st.error_reply(stanza, valid[1], valid[2], valid[3])); else datamanager.store(origin.username, origin.host, "privacy", privacy_lists); end @@ -385,8 +329,7 @@ function checkIfNeedToBeBlocked(e, session) module:log("debug", "stanza: %s, to: %s, from: %s", tostring(stanza.name), tostring(to), tostring(from)); if privacy_lists.lists == nil or - (session.activePrivacyList == nil or session.activePrivacyList == "") and - (privacy_lists.default == nil or privacy_lists.default == "") + not (session.activePrivacyList or privacy_lists.default) then return; -- Nothing to block, default is Allow all end @@ -395,21 +338,14 @@ function checkIfNeedToBeBlocked(e, session) return; -- from one of a user's resource to another => HANDS OFF! end - local idx; - local list; local item; local listname = session.activePrivacyList; - if listname == nil or listname == "" then + if listname == nil then listname = privacy_lists.default; -- no active list selected, use default list end - idx = findNamedList(privacy_lists, listname); - if idx == nil then - module:log("debug", "given privacy listname not found. name: %s", listname); - return; - end - list = privacy_lists.lists[idx]; - if list == nil then - module:log("debug", "privacy list index wrong. index: %d", idx); + local list = privacy_lists.lists[listname]; + if not list then + module:log("debug", "given privacy list not found. name: %s", listname); return; end for _,item in ipairs(list.items) do diff --git a/plugins/mod_roster.lua b/plugins/mod_roster.lua index 52c61a26..4362dca2 100644 --- a/plugins/mod_roster.lua +++ b/plugins/mod_roster.lua @@ -23,12 +23,12 @@ local core_post_stanza = core_post_stanza; module:add_feature("jabber:iq:roster"); local rosterver_stream_feature = st.stanza("ver", {xmlns="urn:xmpp:features:rosterver"}):tag("optional"):up(); -module:add_event_hook("stream-features", - function (session, features) - if session.username then - features:add_child(rosterver_stream_feature); - end - end); +module:hook("stream-features", function(event) + local origin, features = event.origin, event.features; + if origin.username then + features:add_child(rosterver_stream_feature); + end +end); module:add_iq_handler("c2s", "jabber:iq:roster", function (session, stanza) diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 75ee9f04..beb59dd2 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -144,21 +144,22 @@ module: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' }; -module:add_event_hook("stream-features", function(session, features) - if not session.username then - if secure_auth_only and not session.secure then +module:hook("stream-features", function(event) + local origin, features = event.origin, event.features; + if not origin.username then + if secure_auth_only and not origin.secure then return; end if module:get_option("anonymous_login") then - session.sasl_handler = new_sasl(session.host, anonymous_authentication_profile); + origin.sasl_handler = new_sasl(origin.host, anonymous_authentication_profile); else - session.sasl_handler = new_sasl(session.host, default_authentication_profile); - if not (module:get_option("allow_unencrypted_plain_auth")) and not session.secure then - session.sasl_handler:forbidden({"PLAIN"}); + origin.sasl_handler = new_sasl(origin.host, default_authentication_profile); + if not (module:get_option("allow_unencrypted_plain_auth")) and not origin.secure then + origin.sasl_handler:forbidden({"PLAIN"}); end end features:tag("mechanisms", mechanisms_attr); - for k, v in pairs(session.sasl_handler:mechanisms()) do + for k, v in pairs(origin.sasl_handler:mechanisms()) do features:tag("mechanism"):text(v):up(); end features:up(); diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua index 7153e48a..8f688d61 100644 --- a/plugins/mod_tls.lua +++ b/plugins/mod_tls.lua @@ -8,88 +8,79 @@ local st = require "util.stanza"; -local xmlns_stream = 'http://etherx.jabber.org/streams'; -local xmlns_starttls = 'urn:ietf:params:xml:ns:xmpp-tls'; - local secure_auth_only = module:get_option("c2s_require_encryption") or module:get_option("require_encryption"); local secure_s2s_only = module:get_option("s2s_require_encryption"); +local xmlns_starttls = 'urn:ietf:params:xml:ns:xmpp-tls'; +local starttls_attr = { xmlns = xmlns_starttls }; +local starttls_proceed = st.stanza("proceed", starttls_attr); +local starttls_failure = st.stanza("failure", starttls_attr); +local c2s_feature = st.stanza("starttls", starttls_attr); +local s2s_feature = st.stanza("starttls", starttls_attr); +if secure_auth_only then c2s_feature:tag("required"):up(); end +if secure_s2s_only then s2s_feature:tag("required"):up(); end + local global_ssl_ctx = prosody.global_ssl_ctx; -module:add_handler("c2s_unauthed", "starttls", xmlns_starttls, - function (session, stanza) - if session.conn.starttls then - session.send(st.stanza("proceed", { xmlns = xmlns_starttls })); - session:reset_stream(); - local ssl_ctx = session.host and hosts[session.host].ssl_ctx_in or global_ssl_ctx; - session.conn:starttls(ssl_ctx); - session.log("info", "TLS negotiation started..."); - session.secure = false; - else - -- FIXME: What reply? - session.log("warn", "Attempt to start TLS, but TLS is not available on this connection"); - end - end); - -module:add_handler("s2sin_unauthed", "starttls", xmlns_starttls, - function (session, stanza) - if session.conn.starttls then - session.sends2s(st.stanza("proceed", { xmlns = xmlns_starttls })); - session:reset_stream(); - local ssl_ctx = session.to_host and hosts[session.to_host].ssl_ctx_in or global_ssl_ctx; - session.conn:starttls(ssl_ctx); - session.log("info", "TLS negotiation started for incoming s2s..."); - session.secure = false; - else - -- FIXME: What reply? - session.log("warn", "Attempt to start TLS, but TLS is not available on this s2s connection"); - end - end); +local host = hosts[module.host]; +local function can_do_tls(session) + if session.type == "c2s_unauthed" then + return session.username and session.conn.starttls and host.ssl_ctx_in; + elseif session.type == "s2sin_unauthed" then + return origin.to_host and origin.conn.starttls and host.ssl_ctx_in; + end + return false; +end -local starttls_attr = { xmlns = xmlns_starttls }; -module:add_event_hook("stream-features", - function (session, features) - if not session.username and session.conn.starttls then - features:tag("starttls", starttls_attr); - if secure_auth_only then - features:tag("required"):up():up(); - else - features:up(); - end - end - end); +-- Hook <starttls/> +module:hook("stanza/urn:ietf:params:xml:ns:xmpp-tls:starttls", function(event) + local origin = event.origin; + if can_do_tls(origin) then + (origin.sends2s or origin.send)(starttls_proceed); + origin:reset_stream(); + local host = origin.to_host or origin.host; + local ssl_ctx = host and hosts[host].ssl_ctx_in or global_ssl_ctx; + origin.conn:starttls(ssl_ctx); + origin.log("info", "TLS negotiation started for %s...", origin.type); + origin.secure = false; + else + origin.log("warn", "Attempt to start TLS, but TLS is not available on this %s connection", origin.type); + (origin.sends2s or origin.send)(starttls_failure); + origin:close(); + end + return true; +end); -module:hook("s2s-stream-features", - function (data) - local session, features = data.session, data.features; - if session.to_host and session.type ~= "s2sin" and session.conn.starttls then - features:tag("starttls", starttls_attr):up(); - if secure_s2s_only then - features:tag("required"):up():up(); - else - features:up(); - end - end - end); +-- Advertize stream feature +module:hook("stream-features", function(event) + local origin, features = event.origin, event.features; + if can_do_tls(origin) then + features:add_child(c2s_feature); + end +end); +module:hook("s2s-stream-features", function(event) + local origin, features = event.origin, event.features; + if can_do_tls(origin) then + features:add_child(s2s_feature); + end +end); -- For s2sout connections, start TLS if we can -module:hook_stanza(xmlns_stream, "features", - function (session, stanza) - module:log("debug", "Received features element"); - if session.conn.starttls and stanza:child_with_ns(xmlns_starttls) then - module:log("%s is offering TLS, taking up the offer...", session.to_host); - session.sends2s("<starttls xmlns='"..xmlns_starttls.."'/>"); - return true; - end - end, 500); +module:hook_stanza("http://etherx.jabber.org/streams", "features", function (session, stanza) + module:log("debug", "Received features element"); + if session.conn.starttls and stanza:child_with_ns(xmlns_starttls) then + module:log("%s is offering TLS, taking up the offer...", session.to_host); + session.sends2s("<starttls xmlns='"..xmlns_starttls.."'/>"); + return true; + end +end, 500); -module:hook_stanza(xmlns_starttls, "proceed", - function (session, stanza) - module:log("debug", "Proceeding with TLS on s2sout..."); - session:reset_stream(); - local ssl_ctx = session.from_host and hosts[session.from_host].ssl_ctx or global_ssl_ctx; - session.conn:starttls(ssl_ctx, true); - session.secure = false; - return true; - end); +module:hook_stanza(xmlns_starttls, "proceed", function (session, stanza) + module:log("debug", "Proceeding with TLS on s2sout..."); + session:reset_stream(); + local ssl_ctx = session.from_host and hosts[session.from_host].ssl_ctx or global_ssl_ctx; + session.conn:starttls(ssl_ctx, true); + session.secure = false; + return true; +end); |