diff options
-rw-r--r-- | core/hostmanager.lua | 9 | ||||
-rw-r--r-- | core/loggingmanager.lua | 12 | ||||
-rw-r--r-- | core/modulemanager.lua | 3 | ||||
-rw-r--r-- | core/s2smanager.lua | 5 | ||||
-rw-r--r-- | core/sessionmanager.lua | 8 | ||||
-rw-r--r-- | core/stanza_router.lua | 4 | ||||
-rw-r--r-- | net/dns.lua | 11 | ||||
-rw-r--r-- | net/server_event.lua | 7 | ||||
-rw-r--r-- | net/server_select.lua | 10 | ||||
-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 | ||||
-rwxr-xr-x | prosody | 65 | ||||
-rwxr-xr-x | prosodyctl | 12 |
19 files changed, 240 insertions, 279 deletions
diff --git a/core/hostmanager.lua b/core/hostmanager.lua index 038085c3..f8d7400d 100644 --- a/core/hostmanager.lua +++ b/core/hostmanager.lua @@ -32,12 +32,19 @@ local hosts_loaded_once; local function load_enabled_hosts(config) local defined_hosts = config or configmanager.getconfig(); + local activated_any_host; for host, host_config in pairs(defined_hosts) do - if host ~= "*" and (host_config.core.enabled == nil or host_config.core.enabled) and not host_config.core.component_module then + if host ~= "*" and host_config.core.enabled ~= false and not host_config.core.component_module then + activated_any_host = true; activate(host, host_config); end end + + if not activated_any_host then + log("error", "No hosts defined in the config file. This may cause unexpected behaviour as no modules will be loaded."); + end + eventmanager.fire_event("hosts-activated", defined_hosts); hosts_loaded_once = true; end diff --git a/core/loggingmanager.lua b/core/loggingmanager.lua index 4154e1a7..1bf90db1 100644 --- a/core/loggingmanager.lua +++ b/core/loggingmanager.lua @@ -94,7 +94,7 @@ function apply_sink_rules(sink_type) end end elseif type(logging_config) == "string" and (not logging_config:match("^%*")) and sink_type == "file" then - -- User specified simply a filename, and the "file" sink type + -- User specified simply a filename, and the "file" sink type -- was just added for _, sink_config in pairs(default_file_logging) do sink_config.filename = logging_config; @@ -128,7 +128,7 @@ function get_levels(criteria, set) return set; elseif in_range then set[level] = true; - end + end end end @@ -161,12 +161,12 @@ function log_sink_types.stdout() if timestamps then io_write(os_date(timestamps), " "); end - if ... then + if ... then io_write(name, rep(" ", sourcewidth-namelen), level, "\t", format(message, ...), "\n"); else io_write(name, rep(" ", sourcewidth-namelen), level, "\t", message, "\n"); end - end + end end do @@ -197,7 +197,7 @@ do if timestamps then io_write(os_date(timestamps), " "); end - if ... then + if ... then io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", format(message, ...), "\n"); else io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", message, "\n"); @@ -237,7 +237,7 @@ function log_sink_types.file(config) if timestamps then write(logfile, os_date(timestamps), " "); end - if ... then + if ... then write(logfile, name, "\t", level, "\t", format(message, ...), "\n"); else write(logfile, name, "\t" , level, "\t", message, "\n"); diff --git a/core/modulemanager.lua b/core/modulemanager.lua index d8418d83..6b2260f5 100644 --- a/core/modulemanager.lua +++ b/core/modulemanager.lua @@ -127,6 +127,7 @@ function load(host, module_name, config) local api_instance = setmetatable({ name = module_name, host = host, config = config, _log = _log, log = function (self, ...) return _log(...); end }, { __index = api }); local pluginenv = setmetatable({ module = api_instance }, { __index = _G }); + api_instance.environment = pluginenv; setfenv(mod, pluginenv); if not hosts[host] then @@ -397,7 +398,7 @@ function api:require(lib) f, n = pluginloader.load_code(lib, lib..".lib.lua"); end if not f then error("Failed to load plugin library '"..lib.."', error: "..n); end -- FIXME better error message - setfenv(f, setmetatable({ module = self }, { __index = _G })); + setfenv(f, self.environment); return f(); end diff --git a/core/s2smanager.lua b/core/s2smanager.lua index d8ceb4ef..602d6837 100644 --- a/core/s2smanager.lua +++ b/core/s2smanager.lua @@ -389,7 +389,7 @@ function streamopened(session, attr) local features = st.stanza("stream:features"); if session.to_host then - hosts[session.to_host].events.fire_event("s2s-stream-features", { session = session, features = features }); + hosts[session.to_host].events.fire_event("s2s-stream-features", { origin = session, features = features }); else (session.log or log)("warn", "No 'to' on stream header from %s means we can't offer any features", session.from_host or "unknown host"); end @@ -508,6 +508,8 @@ function mark_connected(session) end end +local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed s2s session: %s", data); end + function destroy_session(session, reason) (session.log or log)("info", "Destroying "..tostring(session.direction).." session "..tostring(session.from_host).."->"..tostring(session.to_host)); @@ -523,6 +525,7 @@ function destroy_session(session, reason) session[k] = nil; end end + session.data = null_data_handler; end return _M; diff --git a/core/sessionmanager.lua b/core/sessionmanager.lua index 1a7ef175..29adcfbb 100644 --- a/core/sessionmanager.lua +++ b/core/sessionmanager.lua @@ -66,13 +66,13 @@ function new_session(conn) return session; end +local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed c2s session: %s", data); end + function destroy_session(session, err) (session.log or log)("info", "Destroying session for %s (%s@%s)", session.full_jid or "(unknown)", session.username or "(unknown)", session.host or "(unknown)"); -- Remove session/resource from user's session list if session.full_jid then - hosts[session.host].events.fire_event("resource-unbind", {session=session, error=err}); - hosts[session.host].sessions[session.username].sessions[session.resource] = nil; full_sessions[session.full_jid] = nil; @@ -81,6 +81,8 @@ function destroy_session(session, err) hosts[session.host].sessions[session.username] = nil; bare_sessions[session.username..'@'..session.host] = nil; end + + hosts[session.host].events.fire_event("resource-unbind", {session=session, error=err}); end for k in pairs(session) do @@ -88,6 +90,7 @@ function destroy_session(session, err) session[k] = nil; end end + session.data = null_data_handler; end function make_authenticated(session, username) @@ -190,6 +193,7 @@ function streamopened(session, attr) end local features = st.stanza("stream:features"); + hosts[session.host].events.fire_event("stream-features", { origin = session, features = features }); fire_event("stream-features", session, features); send(features); diff --git a/core/stanza_router.lua b/core/stanza_router.lua index 12133a8e..71e40681 100644 --- a/core/stanza_router.lua +++ b/core/stanza_router.lua @@ -124,7 +124,7 @@ function core_post_stanza(origin, stanza, preevents) local node, host, resource = jid_split(to); local to_bare = node and (node.."@"..host) or host; -- bare JID - local to_type; + local to_type, to_self; if node then if resource then to_type = '/full'; @@ -132,6 +132,7 @@ function core_post_stanza(origin, stanza, preevents) to_type = '/bare'; if node == origin.username and host == origin.host then stanza.attr.to = nil; + to_self = true; end end else @@ -149,6 +150,7 @@ function core_post_stanza(origin, stanza, preevents) local h = hosts[to_bare] or hosts[host or origin.host]; if h then if h.events.fire_event(stanza.name..to_type, event_data) then return; end -- do processing + if to_self and h.events.fire_event(stanza.name..'/self', event_data) then return; end -- do processing if h.type == "component" then component_handle_stanza(origin, stanza); diff --git a/net/dns.lua b/net/dns.lua index 10ac50a4..ca5f3c62 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -594,17 +594,18 @@ end function resolver:remember(rr, type) -- - - - - - - - - - - - - - remember --print ('remember', type, rr.class, rr.type, rr.name) + local qname, qtype, qclass = standardize(rr.name, rr.type, rr.class); if type ~= '*' then - type = rr.type; - local all = get(self.cache, rr.class, '*', rr.name); + type = qtype; + local all = get(self.cache, qclass, '*', qname); --print('remember all', all); if all then append(all, rr); end end self.cache = self.cache or setmetatable({}, cache_metatable); - local rrs = get(self.cache, rr.class, type, rr.name) or - set(self.cache, rr.class, type, rr.name, setmetatable({}, rrs_metatable)); + local rrs = get(self.cache, qclass, type, qname) or + set(self.cache, qclass, type, qname, setmetatable({}, rrs_metatable)); append(rrs, rr); if type == 'MX' then self.unsorted[rrs] = true; end @@ -723,7 +724,7 @@ function resolver:receive(rset) -- - - - - - - - - - - - - - - - - receive for i,sock in pairs(rset) do if self.socketset[sock] then - local packet = sock.receive(); + local packet = sock:receive(); if packet then response = self:decode(packet); if response and self.active[response.header.id] diff --git a/net/server_event.lua b/net/server_event.lua index 3afc732b..e79a57d0 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -43,7 +43,7 @@ local tostring = use "tostring" local coroutine = use "coroutine" local setmetatable = use "setmetatable" -local ssl = use "ssl" or require "ssl" +local ssl = use "ssl" local socket = use "socket" or require "socket" local log = require ("util.logger").init("socket") @@ -142,7 +142,7 @@ do self:_close() debug( "new connection failed. id:", self.id, "error:", self.fatalerror ) else - if plainssl then -- start ssl session + if plainssl and ssl then -- start ssl session self:starttls() else -- normal connection self:_start_session( self.listener.onconnect ) @@ -489,6 +489,7 @@ do _sslctx = sslctx; -- parameters _usingssl = false; -- client is using ssl; } + if not ssl then interface.starttls = false; end interface.id = tostring(interface):match("%x+$"); interface.writecallback = function( event ) -- called on write events --vdebug( "new client write event, id/ip/port:", interface, ip, port ) @@ -670,7 +671,7 @@ do interface._connections = interface._connections + 1 -- increase connection count local clientinterface = handleclient( client, ip, port, interface, pattern, listener, nil, sslctx ) --vdebug( "client id:", clientinterface, "startssl:", startssl ) - if sslctx then + if ssl and sslctx then clientinterface:starttls(sslctx) else clientinterface:_start_session( clientinterface.onconnect ) diff --git a/net/server_select.lua b/net/server_select.lua index db4475e2..685cd13e 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -55,8 +55,8 @@ local coroutine_yield = coroutine.yield --// extern libs //-- -local luasec = select( 2, pcall( require, "ssl" ) ) -local luasocket = require "socket" +local luasec = use "ssl" +local luasocket = use "socket" or require "socket" --// extern lib methods //-- @@ -472,7 +472,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist _ = needtls and handler:starttls(nil, true) _writetimes[ handler ] = nil - _ = toclose and handler.close( ) + _ = toclose and handler.close( ) return true elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write buffer = string_sub( buffer, byte + 1, bufferlen ) -- new buffer @@ -601,8 +601,10 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport handler.readbuffer = _readbuffer handler.sendbuffer = _sendbuffer end + else + handler.readbuffer = _readbuffer + handler.sendbuffer = _sendbuffer end - send = socket.send receive = socket.receive shutdown = ( ssl and id ) or socket.shutdown 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); @@ -32,34 +32,6 @@ if CFG_DATADIR then end end --- Initialize logging -require "core.loggingmanager" - --- Check runtime dependencies -if not require "util.dependencies".check_dependencies() then - os.exit(1); -end - --- Replace require() with one that doesn't pollute _G, required --- for neat sandboxing of modules -do - local _realG = _G; - local _real_require = require; - function require(...) - local curr_env = getfenv(2); - local curr_env_mt = getmetatable(getfenv(2)); - local _realG_mt = getmetatable(_realG); - if curr_env_mt and curr_env_mt.__index and not curr_env_mt.__newindex and _realG_mt then - local old_newindex - old_newindex, _realG_mt.__newindex = _realG_mt.__newindex, curr_env; - local ret = _real_require(...); - _realG_mt.__newindex = old_newindex; - return ret; - end - return _real_require(...); - end -end - -- Load the config-parsing module config = require "core.configmanager" @@ -119,6 +91,38 @@ function load_libraries() server = require "net.server" end +function init_logging() + -- Initialize logging + require "core.loggingmanager" +end + +function check_dependencies() + -- Check runtime dependencies + if not require "util.dependencies".check_dependencies() then + os.exit(1); + end +end + +function sandbox_require() + -- Replace require() with one that doesn't pollute _G, required + -- for neat sandboxing of modules + local _realG = _G; + local _real_require = require; + function require(...) + local curr_env = getfenv(2); + local curr_env_mt = getmetatable(getfenv(2)); + local _realG_mt = getmetatable(_realG); + if curr_env_mt and curr_env_mt.__index and not curr_env_mt.__newindex and _realG_mt then + local old_newindex + old_newindex, _realG_mt.__newindex = _realG_mt.__newindex, curr_env; + local ret = _real_require(...); + _realG_mt.__newindex = old_newindex; + return ret; + end + return _real_require(...); + end +end + function init_global_state() bare_sessions = {}; full_sessions = {}; @@ -407,7 +411,12 @@ function cleanup() end -- Are you ready? :) +-- These actions are in a strict order, as many depend on +-- previous steps to have already been performed read_config(); +init_logging(); +check_dependencies(); +sandbox_require(); load_libraries(); init_global_state(); read_version(); @@ -29,12 +29,6 @@ if CFG_DATADIR then end end -require "core.loggingmanager" - -if not require "util.dependencies".check_dependencies() then - os.exit(1); -end - config = require "core.configmanager" do @@ -63,6 +57,12 @@ do end end +require "core.loggingmanager" + +if not require "util.dependencies".check_dependencies() then + os.exit(1); +end + prosody = { hosts = {}, events = events, platform = "posix" }; local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data"; |