diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/mod_announce.lua | 1 | ||||
-rw-r--r-- | plugins/mod_bosh.lua | 57 | ||||
-rw-r--r-- | plugins/mod_compression.lua | 3 | ||||
-rw-r--r-- | plugins/mod_console.lua | 6 | ||||
-rw-r--r-- | plugins/mod_groups.lua | 10 | ||||
-rw-r--r-- | plugins/mod_posix.lua | 1 | ||||
-rw-r--r-- | plugins/mod_presence.lua | 62 | ||||
-rw-r--r-- | plugins/mod_privacy.lua | 62 | ||||
-rw-r--r-- | plugins/mod_private.lua | 6 | ||||
-rw-r--r-- | plugins/mod_register.lua | 5 | ||||
-rw-r--r-- | plugins/mod_saslauth.lua | 40 |
11 files changed, 130 insertions, 123 deletions
diff --git a/plugins/mod_announce.lua b/plugins/mod_announce.lua index 7f08a6e0..d3017f6c 100644 --- a/plugins/mod_announce.lua +++ b/plugins/mod_announce.lua @@ -22,7 +22,6 @@ function handle_announcement(data) if not is_admin(stanza.attr.from) then -- Not an admin? Not allowed! module:log("warn", "Non-admin %s tried to send server announcement", tostring(jid.bare(stanza.attr.from))); - origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); return; end diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 02f3ce38..66a79785 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -31,6 +31,8 @@ local BOSH_DEFAULT_POLLING = tonumber(module:get_option("bosh_max_polling")) or local BOSH_DEFAULT_REQUESTS = tonumber(module:get_option("bosh_max_requests")) or 2; local BOSH_DEFAULT_MAXPAUSE = tonumber(module:get_option("bosh_max_pause")) or 300; +local consider_bosh_secure = module:get_option_boolean("consider_bosh_secure"); + local default_headers = { ["Content-Type"] = "text/xml; charset=utf-8" }; local session_close_reply = { headers = default_headers, body = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate" }), attr = {} }; @@ -63,8 +65,11 @@ function on_destroy_request(request) local session = sessions[request.sid]; if session then local requests = session.requests; - for i,r in pairs(requests) do - if r == request then requests[i] = nil; break; end + for i,r in ipairs(requests) do + if r == request then + t_remove(requests, i); + break; + end end -- If this session now has no requests open, mark it as inactive @@ -90,6 +95,8 @@ function handle_request(method, body, request) --log("debug", "Handling new request %s: %s\n----------", request.id, tostring(body)); request.notopen = true; request.log = log; + request.on_destroy = on_destroy_request; + local parser = lxp.new(init_xmlhandlers(request, stream_callbacks), "\1"); parser:parse(body); @@ -118,14 +125,21 @@ function handle_request(method, body, request) session.send(resp); end - if not request.destroyed and session.bosh_wait then - request.reply_before = os_time() + session.bosh_wait; - request.on_destroy = on_destroy_request; - waiting_requests[request] = true; + if not request.destroyed then + -- We're keeping this request open, to respond later + log("debug", "Have nothing to say, so leaving request unanswered for now"); + if session.bosh_wait then + request.reply_before = os_time() + session.bosh_wait; + waiting_requests[request] = true; + end + if inactive_sessions[session] then + -- Session was marked as inactive, since we have + -- a request open now, unmark it + inactive_sessions[session] = nil; + end end - log("debug", "Have nothing to say, so leaving request unanswered for now"); - return true; + return true; -- Inform httpserver we shall reply later end end @@ -162,10 +176,14 @@ function stream_callbacks.streamopened(request, attr) -- New session sid = new_uuid(); - local session = { type = "c2s_unauthed", conn = {}, sid = sid, rid = tonumber(attr.rid), host = attr.to, bosh_version = attr.ver, bosh_wait = attr.wait, streamid = sid, - bosh_hold = BOSH_DEFAULT_HOLD, bosh_max_inactive = BOSH_DEFAULT_INACTIVITY, - requests = { }, send_buffer = {}, reset_stream = bosh_reset_stream, close = bosh_close_stream, - dispatch_stanza = core_process_stanza, log = logger.init("bosh"..sid), secure = request.secure }; + local session = { + type = "c2s_unauthed", conn = {}, sid = sid, rid = tonumber(attr.rid)-1, host = attr.to, + bosh_version = attr.ver, bosh_wait = attr.wait, streamid = sid, + bosh_hold = BOSH_DEFAULT_HOLD, bosh_max_inactive = BOSH_DEFAULT_INACTIVITY, + requests = { }, send_buffer = {}, reset_stream = bosh_reset_stream, + close = bosh_close_stream, dispatch_stanza = core_process_stanza, + log = logger.init("bosh"..sid), secure = consider_bosh_secure or request.secure + }; sessions[sid] = session; log("info", "New BOSH session, assigned it sid '%s'", sid); @@ -174,11 +192,6 @@ function stream_callbacks.streamopened(request, attr) function session.send(s) --log("debug", "Sending BOSH data: %s", tostring(s)); local oldest_request = r[1]; - while oldest_request and oldest_request.destroyed do - t_remove(r, 1); - waiting_requests[oldest_request] = nil; - oldest_request = r[1]; - end if oldest_request then log("debug", "We have an open request, so sending on that"); response.body = t_concat{"<body xmlns='http://jabber.org/protocol/httpbind' sid='", sid, "' xmlns:stream = 'http://etherx.jabber.org/streams'>", tostring(s), "</body>" }; @@ -193,7 +206,6 @@ function stream_callbacks.streamopened(request, attr) else log("debug", "Destroying the request now..."); oldest_request:destroy(); - t_remove(r, 1); end elseif s ~= "" then log("debug", "Saved to send buffer because there are %d open requests", #r); @@ -235,8 +247,9 @@ function stream_callbacks.streamopened(request, attr) session.log("warn", "rid too large (means a request was lost). Last rid: %d New rid: %s", session.rid, attr.rid); elseif diff <= 0 then -- Repeated, ignore - session.log("debug", "rid repeated (on request %s), ignoring: %d", request.id, session.rid); + session.log("debug", "rid repeated (on request %s), ignoring: %s (diff %d)", request.id, session.rid, diff); request.notopen = nil; + request.sid = sid; t_insert(session.requests, request); return; end @@ -250,12 +263,6 @@ function stream_callbacks.streamopened(request, attr) return; end - -- If session was inactive, make sure it is now marked as not - if #session.requests == 0 then - (session.log or log)("debug", "BOSH client now active again at %d", os_time()); - inactive_sessions[session] = nil; - end - if session.notopen then local features = st.stanza("stream:features"); hosts[session.host].events.fire_event("stream-features", { origin = session, features = features }); diff --git a/plugins/mod_compression.lua b/plugins/mod_compression.lua index c2e84f2b..53341492 100644 --- a/plugins/mod_compression.lua +++ b/plugins/mod_compression.lua @@ -55,7 +55,7 @@ module:hook_stanza(xmlns_stream, "features", local algorithm = a[1] if algorithm == "zlib" then session.sends2s(st.stanza("compress", {xmlns=xmlns_compression_protocol}):tag("method"):text("zlib")) - session.log("info", "Enabled compression using zlib.") + session.log("debug", "Enabled compression using zlib.") return true; end end @@ -98,7 +98,6 @@ local function setup_compression(session, deflate_stream) local new_send = function(t) --TODO: Better code injection in the sending process - session.log(t) local status, compressed, eof = pcall(deflate_stream, tostring(t), 'sync'); if status == false then session:close({ diff --git a/plugins/mod_console.lua b/plugins/mod_console.lua index 4457a2f3..e87ef536 100644 --- a/plugins/mod_console.lua +++ b/plugins/mod_console.lua @@ -58,6 +58,7 @@ function console_listener.onconnect(conn) local session = console:new_session(conn); sessions[conn] = session; printbanner(session); + session.send(string.char(0)); end function console_listener.onincoming(conn, data) @@ -84,9 +85,10 @@ function console_listener.onincoming(conn, data) session.env._ = data; - local chunk, err = loadstring("return "..data); + local chunkname = "=console"; + local chunk, err = loadstring("return "..data, chunkname); if not chunk then - chunk, err = loadstring(data); + chunk, err = loadstring(data, chunkname); if not chunk then err = err:gsub("^%[string .-%]:%d+: ", ""); err = err:gsub("^:%d+: ", ""); diff --git a/plugins/mod_groups.lua b/plugins/mod_groups.lua index d4604b1e..5f821cbc 100644 --- a/plugins/mod_groups.lua +++ b/plugins/mod_groups.lua @@ -18,7 +18,7 @@ local jid_bare, jid_prep = jid.bare, jid.prep; local module_host = module:get_host(); function inject_roster_contacts(username, host, roster) - module:log("warn", "Injecting group members to roster"); + --module:log("debug", "Injecting group members to roster"); local bare_jid = username.."@"..host; if not members[bare_jid] and not members[false] then return; end -- Not a member of any groups @@ -41,7 +41,7 @@ function inject_roster_contacts(username, host, roster) -- Find groups this JID is a member of if members[bare_jid] then for _, group_name in ipairs(members[bare_jid]) do - module:log("debug", "Importing group %s", group_name); + --module:log("debug", "Importing group %s", group_name); import_jids_to_roster(group_name); end end @@ -49,7 +49,7 @@ function inject_roster_contacts(username, host, roster) -- Import public groups if members[false] then for _, group_name in ipairs(members[false]) do - module:log("debug", "Importing group %s", group_name); + --module:log("debug", "Importing group %s", group_name); import_jids_to_roster(group_name); end end @@ -67,7 +67,9 @@ function remove_virtual_contacts(username, host, datastore, data) new_roster[jid] = contact; end end - new_roster[false].version = nil; -- Version is void + if new_roster[false] then + new_roster[false].version = nil; -- Version is void + end return username, host, datastore, new_roster; end diff --git a/plugins/mod_posix.lua b/plugins/mod_posix.lua index 5888ae10..c38f7eba 100644 --- a/plugins/mod_posix.lua +++ b/plugins/mod_posix.lua @@ -82,6 +82,7 @@ local function write_pidfile() end pidfile = module:get_option("pidfile"); if pidfile then + local err; local mode = stat(pidfile) and "r+" or "w+"; pidfile_handle, err = io.open(pidfile, mode); if not pidfile_handle then diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua index 5ad3bfdf..4fb8c3e4 100644 --- a/plugins/mod_presence.lua +++ b/plugins/mod_presence.lua @@ -38,42 +38,23 @@ function core_route_stanza(origin, stanza) _core_route_stanza(origin, stanza); end -local select_top_resources; -local bare_message_delivery_policy = module:get_option("bare_message_delivery_policy") or "priority"; -if bare_message_delivery_policy == "broadcast" then - function select_top_resources(user) - local recipients = {}; - for _, session in pairs(user.sessions) do -- find resources with non-negative priority +local function select_top_resources(user) + local priority = 0; + local recipients = {}; + for _, session in pairs(user.sessions) do -- find resource with greatest priority + if session.presence then + -- TODO check active privacy list for session local p = session.priority; - if p and p >= 0 then + if p > priority then + priority = p; + recipients = {session}; + elseif p == priority then t_insert(recipients, session); end end - return recipients; - end -else - if bare_message_delivery_policy ~= "priority" then - module:log("warn", "Invalid value for config option bare_message_delivery_policy"); - end - function select_top_resources(user) - local priority = 0; - local recipients = {}; - for _, session in pairs(user.sessions) do -- find resource with greatest priority - if session.presence then - -- TODO check active privacy list for session - local p = session.priority; - if p > priority then - priority = p; - recipients = {session}; - elseif p == priority then - t_insert(recipients, session); - end - end - end - return recipients; end + return recipients; end - local function recalc_resource_map(user) if user then user.top_resources = select_top_resources(user); @@ -81,7 +62,17 @@ local function recalc_resource_map(user) end end +local ignore_presence_priority = module:get_option("ignore_presence_priority"); + function handle_normal_presence(origin, stanza, core_route_stanza) + if ignore_presence_priority then + local priority = stanza:child_with_name("priority"); + if priority and priority[1] ~= "0" then + for i=#priority.tags,1,-1 do priority.tags[i] = nil; end + for i=#priority,1,-1 do priority[i] = nil; end + priority[1] = "0"; + end + end if full_sessions[origin.full_jid] then -- if user is still connected origin.send(stanza); -- reflect their presence back to them end @@ -236,16 +227,13 @@ function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_b stanza.attr.from, stanza.attr.to = from_bare, to_bare; log("debug", "inbound presence "..stanza.attr.type.." from "..from_bare.." for "..to_bare); - if not node then - log("debug", "dropping presence sent to host or invalid address '%s'", tostring(to_bare)); - end - if stanza.attr.type == "probe" then - if rostermanager.is_contact_subscribed(node, host, from_bare) then + local result, err = rostermanager.is_contact_subscribed(node, host, from_bare); + if result then if 0 == send_presence_of_available_resources(node, host, st_from, origin, core_route_stanza) then - core_route_stanza(hosts[host], st.presence({from=to_bare, to=from_bare, type="unavailable"})); -- TODO send last activity + core_route_stanza(hosts[host], st.presence({from=to_bare, to=st_from, type="unavailable"})); -- TODO send last activity end - else + elseif not err then core_route_stanza(hosts[host], st.presence({from=to_bare, to=from_bare, type="unsubscribed"})); end elseif stanza.attr.type == "subscribe" then diff --git a/plugins/mod_privacy.lua b/plugins/mod_privacy.lua index 77b4dd12..57538ccd 100644 --- a/plugins/mod_privacy.lua +++ b/plugins/mod_privacy.lua @@ -13,7 +13,7 @@ local datamanager = require "util.datamanager"; local bare_sessions, full_sessions = bare_sessions, full_sessions; local util_Jid = require "util.jid"; local jid_bare = util_Jid.bare; -local jid_split = util_Jid.split; +local jid_split, jid_join = util_Jid.split, util_Jid.join; local load_roster = require "core.rostermanager".load_roster; local to_number = tonumber; @@ -160,26 +160,7 @@ function createOrReplaceList (privacy_lists, origin, stanza, name, entries, rost end end - if tmp.type == "group" then - local found = false; - local roster = load_roster(origin.username, origin.host); - for jid,item in pairs(roster) do - if item.groups ~= nil then - for group in pairs(item.groups) do - if group == tmp.value then - found = true; - break; - end - end - if found == true then - break; - end - end - end - if found == false then - return {"cancel", "item-not-found", "Specifed roster group not existing."}; - end - elseif tmp.type == "subscription" then + if tmp.type == "subscription" then if tmp.value ~= "both" and tmp.value ~= "to" and tmp.value ~= "from" and @@ -320,13 +301,13 @@ function checkIfNeedToBeBlocked(e, session) local origin, stanza = e.origin, e.stanza; local privacy_lists = datamanager.load(session.username, session.host, "privacy") or {}; local bare_jid = session.username.."@"..session.host; - local to = stanza.attr.to; + local to = stanza.attr.to or bare_jid; local from = stanza.attr.from; local is_to_user = bare_jid == jid_bare(to); local is_from_user = bare_jid == jid_bare(from); - module:log("debug", "stanza: %s, to: %s, from: %s", tostring(stanza.name), tostring(to), tostring(from)); + --module:log("debug", "stanza: %s, to: %s, from: %s", tostring(stanza.name), tostring(to), tostring(from)); if privacy_lists.lists == nil or not (session.activePrivacyList or privacy_lists.default) @@ -334,7 +315,7 @@ function checkIfNeedToBeBlocked(e, session) return; -- Nothing to block, default is Allow all end if is_from_user and is_to_user then - module:log("debug", "Not blocking communications between user's resources"); + --module:log("debug", "Not blocking communications between user's resources"); return; -- from one of a user's resource to another => HANDS OFF! end @@ -344,8 +325,8 @@ function checkIfNeedToBeBlocked(e, session) listname = privacy_lists.default; -- no active list selected, use default list end local list = privacy_lists.lists[listname]; - if not list then - module:log("debug", "given privacy list not found. name: %s", listname); + if not list then -- should never happen + module:log("warn", "given privacy list not found. name: %s for user %s", listname, bare_jid); return; end for _,item in ipairs(list.items) do @@ -364,10 +345,10 @@ function checkIfNeedToBeBlocked(e, session) local evilJid = {}; apply = false; if is_to_user then - module:log("debug", "evil jid is (from): %s", from); + --module:log("debug", "evil jid is (from): %s", from); evilJid.node, evilJid.host, evilJid.resource = jid_split(from); else - module:log("debug", "evil jid is (to): %s", to); + --module:log("debug", "evil jid is (to): %s", to); evilJid.node, evilJid.host, evilJid.resource = jid_split(to); end if item.type == "jid" and @@ -379,17 +360,22 @@ function checkIfNeedToBeBlocked(e, session) block = (item.action == "deny"); elseif item.type == "group" then local roster = load_roster(session.username, session.host); - local groups = roster[evilJid.node .. "@" .. evilJid.host].groups; - for group in pairs(groups) do - if group == item.value then - apply = true; - block = (item.action == "deny"); - break; + local roster_entry = roster[jid_join(evilJid.node, evilJid.host)]; + if roster_entry then + local groups = roster_entry.groups; + for group in pairs(groups) do + if group == item.value then + apply = true; + block = (item.action == "deny"); + break; + end end end - elseif item.type == "subscription" and evilJid.node ~= nil and evilJid.host ~= nil then -- we need a valid bare evil jid + elseif item.type == "subscription" then -- we need a valid bare evil jid local roster = load_roster(session.username, session.host); - if roster[evilJid.node .. "@" .. evilJid.host].subscription == item.value then + local roster_entry = roster[jid_join(evilJid.node, evilJid.host)]; + if (not(roster_entry) and item.value == "none") + or (roster_entry and roster_entry.subscription == item.value) then apply = true; block = (item.action == "deny"); end @@ -408,7 +394,7 @@ function checkIfNeedToBeBlocked(e, session) end return true; -- stanza blocked ! else - module:log("debug", "stanza explicitly allowed!") + --module:log("debug", "stanza explicitly allowed!") return; end end @@ -439,7 +425,7 @@ function preCheckIncoming(e) if session ~= nil then return checkIfNeedToBeBlocked(e, session); else - module:log("debug", "preCheckIncoming: Couldn't get session for jid: %s@%s/%s", tostring(node), tostring(host), tostring(resource)); + --module:log("debug", "preCheckIncoming: Couldn't get session for jid: %s@%s/%s", tostring(node), tostring(host), tostring(resource)); end end end diff --git a/plugins/mod_private.lua b/plugins/mod_private.lua index 859bf45a..abf1ec03 100644 --- a/plugins/mod_private.lua +++ b/plugins/mod_private.lua @@ -26,7 +26,11 @@ module:add_iq_handler("c2s", "jabber:iq:private", if #query.tags == 1 then local tag = query.tags[1]; local key = tag.name..":"..tag.attr.xmlns; - local data = datamanager.load(node, host, "private"); + local data, err = datamanager.load(node, host, "private"); + if err then + session.send(st.error_reply(stanza, "wait", "internal-server-error")); + return true; + end if stanza.attr.type == "get" then if data and data[key] then session.send(st.reply(stanza):tag("query", {xmlns = "jabber:iq:private"}):add_child(st.deserialize(data[key]))); diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index b8d142f7..2818e336 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -35,7 +35,7 @@ module:add_iq_handler("c2s", "jabber:iq:register", function (session, stanza) local username, host = session.username, session.host; --session.send(st.error_reply(stanza, "cancel", "not-allowed")); --return; - usermanager_set_password(username, host, nil); -- Disable account + --usermanager_set_password(username, host, nil); -- 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)); @@ -46,7 +46,7 @@ module:add_iq_handler("c2s", "jabber:iq:register", function (session, stanza) -- TODO datamanager should be able to delete all user data itself datamanager.store(username, host, "vcard", nil); datamanager.store(username, host, "private", nil); - datamanager.store(username, host, "offline", nil); + datamanager.list_store(username, host, "offline", nil); local bare = username.."@"..host; for jid, item in pairs(roster) do if jid and jid ~= "pending" then @@ -59,6 +59,7 @@ module:add_iq_handler("c2s", "jabber:iq:register", function (session, stanza) end end datamanager.store(username, host, "roster", nil); + datamanager.store(username, host, "privacy", nil); datamanager.store(username, host, "accounts", nil); -- delete accounts datastore at the end module:log("info", "User removed their account: %s@%s", username, host); module:fire_event("user-deregistered", { username = username, host = host, source = "mod_register", session = session }); diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index c0360553..d407e5da 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -28,6 +28,12 @@ local config = require "core.configmanager"; local secure_auth_only = module:get_option("c2s_require_encryption") or module:get_option("require_encryption"); local sasl_backend = module:get_option("sasl_backend") or "builtin"; +-- Cyrus config options +local require_provisioning = module:get_option("cyrus_require_provisioning") or false; +local cyrus_service_realm = module:get_option("cyrus_service_realm"); +local cyrus_service_name = module:get_option("cyrus_service_name"); +local cyrus_application_name = module:get_option("cyrus_application_name"); + local log = module._log; local xmlns_sasl ='urn:ietf:params:xml:ns:xmpp-sasl'; @@ -45,7 +51,11 @@ elseif sasl_backend == "cyrus" then if ok then local cyrus_new = cyrus.new; new_sasl = function(realm) - return cyrus_new(realm, module:get_option("cyrus_service_name") or "xmpp"); + return cyrus_new( + cyrus_service_realm or realm, + cyrus_service_name or "xmpp", + cyrus_application_name or "prosody" + ); end else module:log("error", "Failed to load Cyrus SASL because: %s", cyrus); @@ -94,21 +104,29 @@ local function build_reply(status, ret, err_msg) return reply; end -local function handle_status(session, status) +local function handle_status(session, status, ret, err_msg) if status == "failure" then session.sasl_handler = session.sasl_handler:clean_clone(); elseif status == "success" then local username = nodeprep(session.sasl_handler.username); - if not username then -- TODO move this to sessionmanager - module:log("warn", "SASL succeeded but we didn't get a username!"); - session.sasl_handler = nil; - session:reset_stream(); - return; + + if not(require_provisioning) or usermanager_user_exists(username, session.host) then + local aret, err = sm_make_authenticated(session, session.sasl_handler.username); + if aret then + session.sasl_handler = nil; + session:reset_stream(); + else + module:log("warn", "SASL succeeded but username was invalid"); + session.sasl_handler = session.sasl_handler:clean_clone(); + return "failure", "not-authorized", "User authenticated successfully, but username was invalid"; + end + else + module:log("warn", "SASL succeeded but we don't have an account provisioned for %s", username); + session.sasl_handler = session.sasl_handler:clean_clone(); + return "failure", "not-authorized", "User authenticated successfully, but not provisioned for XMPP"; end - sm_make_authenticated(session, session.sasl_handler.username); - session.sasl_handler = nil; - session:reset_stream(); end + return status, ret, err_msg; end local function sasl_handler(session, stanza) @@ -142,7 +160,7 @@ local function sasl_handler(session, stanza) end end local status, ret, err_msg = session.sasl_handler:process(text); - handle_status(session, status); + status, ret, err_msg = handle_status(session, status, ret, err_msg); local s = build_reply(status, ret, err_msg); log("debug", "sasl reply: %s", tostring(s)); session.send(s); |