aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/mod_bosh.lua14
-rw-r--r--plugins/mod_compression.lua62
-rw-r--r--plugins/mod_groups.lua10
-rw-r--r--plugins/mod_iq.lua11
-rw-r--r--plugins/mod_pep.lua44
-rw-r--r--plugins/mod_presence.lua60
-rw-r--r--plugins/mod_privacy.lua60
-rw-r--r--plugins/mod_private.lua6
-rw-r--r--plugins/mod_saslauth.lua32
9 files changed, 145 insertions, 154 deletions
diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua
index b11de6c6..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 = {} };
@@ -174,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)-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 = 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);
diff --git a/plugins/mod_compression.lua b/plugins/mod_compression.lua
index c2e84f2b..0e1aab8c 100644
--- a/plugins/mod_compression.lua
+++ b/plugins/mod_compression.lua
@@ -14,6 +14,7 @@ local xmlns_compression_feature = "http://jabber.org/features/compress"
local xmlns_compression_protocol = "http://jabber.org/protocol/compress"
local xmlns_stream = "http://etherx.jabber.org/streams";
local compression_stream_feature = st.stanza("compression", {xmlns=xmlns_compression_feature}):tag("method"):text("zlib"):up();
+local add_filter = require "util.filters".add_filter;
local compression_level = module:get_option("compression_level");
-- if not defined assume admin wants best compression
@@ -94,44 +95,37 @@ end
-- setup compression for a stream
local function setup_compression(session, deflate_stream)
- local old_send = (session.sends2s or session.send);
-
- 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({
- condition = "undefined-condition";
- text = compressed;
- extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
- });
- module:log("warn", "%s", tostring(compressed));
- return;
- end
- session.conn:write(compressed);
- end;
-
- if session.sends2s then session.sends2s = new_send
- elseif session.send then session.send = new_send end
+ add_filter(session, "bytes/out", function(t)
+ session.log(t)
+ local status, compressed, eof = pcall(deflate_stream, tostring(t), 'sync');
+ if status == false then
+ session:close({
+ condition = "undefined-condition";
+ text = compressed;
+ extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
+ });
+ module:log("warn", "%s", tostring(compressed));
+ return;
+ end
+ return compressed;
+ end);
end
-- setup decompression for a stream
local function setup_decompression(session, inflate_stream)
- local old_data = session.data
- session.data = function(conn, data)
- local status, decompressed, eof = pcall(inflate_stream, data);
- if status == false then
- session:close({
- condition = "undefined-condition";
- text = decompressed;
- extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
- });
- module:log("warn", "%s", tostring(decompressed));
- return;
- end
- old_data(conn, decompressed);
- end;
+ add_filter(session, "bytes/in", function(data)
+ local status, decompressed, eof = pcall(inflate_stream, data);
+ if status == false then
+ session:close({
+ condition = "undefined-condition";
+ text = decompressed;
+ extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
+ });
+ module:log("warn", "%s", tostring(decompressed));
+ return;
+ end
+ return decompressed;
+ end);
end
module:add_handler({"s2sout_unauthed", "s2sout"}, "compressed", xmlns_compression_protocol,
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_iq.lua b/plugins/mod_iq.lua
index b3001fe5..e90af781 100644
--- a/plugins/mod_iq.lua
+++ b/plugins/mod_iq.lua
@@ -9,7 +9,6 @@
local st = require "util.stanza";
local jid_split = require "util.jid".split;
-local user_exists = require "core.usermanager".user_exists;
local full_sessions = full_sessions;
local bare_sessions = bare_sessions;
@@ -34,16 +33,6 @@ module:hook("iq/bare", function(data)
-- IQ to bare JID recieved
local origin, stanza = data.origin, data.stanza;
- local to = stanza.attr.to;
- if to and not bare_sessions[to] then -- quick check for account existance
- local node, host = jid_split(to);
- if not user_exists(node, host) then -- full check for account existance
- if stanza.attr.type == "get" or stanza.attr.type == "set" then
- origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
- end
- return true;
- end
- end
-- TODO fire post processing events
if stanza.attr.type == "get" or stanza.attr.type == "set" then
return module:fire_event("iq/bare/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data);
diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua
index aa46d2d3..31546dff 100644
--- a/plugins/mod_pep.lua
+++ b/plugins/mod_pep.lua
@@ -16,7 +16,6 @@ local is_contact_subscribed = require "core.rostermanager".is_contact_subscribed
local pairs, ipairs = pairs, ipairs;
local next = next;
local type = type;
-local load_roster = require "core.rostermanager".load_roster;
local sha1 = require "util.hashes".sha1;
local base64 = require "util.encodings".base64.encode;
@@ -40,8 +39,8 @@ module:add_feature("http://jabber.org/protocol/pubsub#publish");
local function subscription_presence(user_bare, recipient)
local recipient_bare = jid_bare(recipient);
if (recipient_bare == user_bare) then return true end
- local item = load_roster(jid_split(user_bare))[recipient_bare];
- return item and (item.subscription == 'from' or item.subscription == 'both');
+ local username, host = jid_split(user_bare);
+ return is_contact_subscribed(username, host, recipient_bare);
end
local function publish(session, node, id, item)
@@ -118,27 +117,32 @@ module:hook("presence/bare", function(event)
-- inbound presence to bare JID recieved
local origin, stanza = event.origin, event.stanza;
local user = stanza.attr.to or (origin.username..'@'..origin.host);
+ local t = stanza.attr.type;
- if not stanza.attr.to or subscription_presence(user, stanza.attr.from) then
- local recipient = stanza.attr.from;
- local current = recipients[user] and recipients[user][recipient];
- local hash = get_caps_hash_from_presence(stanza, current);
- if current == hash then return; end
- if not hash then
- if recipients[user] then recipients[user][recipient] = nil; end
- else
- recipients[user] = recipients[user] or {};
- if hash_map[hash] then
- recipients[user][recipient] = hash_map[hash];
- publish_all(user, recipient, origin);
+ if not t then -- available presence
+ if not stanza.attr.to or subscription_presence(user, stanza.attr.from) then
+ local recipient = stanza.attr.from;
+ local current = recipients[user] and recipients[user][recipient];
+ local hash = get_caps_hash_from_presence(stanza, current);
+ if current == hash then return; end
+ if not hash then
+ if recipients[user] then recipients[user][recipient] = nil; end
else
- recipients[user][recipient] = hash;
- origin.send(
- st.stanza("iq", {from=stanza.attr.to, to=stanza.attr.from, id="disco", type="get"})
- :query("http://jabber.org/protocol/disco#info")
- );
+ recipients[user] = recipients[user] or {};
+ if hash_map[hash] then
+ recipients[user][recipient] = hash_map[hash];
+ publish_all(user, recipient, origin);
+ else
+ recipients[user][recipient] = hash;
+ origin.send(
+ st.stanza("iq", {from=stanza.attr.to, to=stanza.attr.from, id="disco", type="get"})
+ :query("http://jabber.org/protocol/disco#info")
+ );
+ end
end
end
+ elseif t == "unavailable" then
+ if recipients[user] then recipients[user][stanza.attr.from] = nil; end
end
end, 10);
diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua
index 5ad3bfdf..9071ae4c 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
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..ca5d51fa 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
@@ -326,7 +307,7 @@ function checkIfNeedToBeBlocked(e, session)
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_saslauth.lua b/plugins/mod_saslauth.lua
index c0360553..9f940c37 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,7 +104,7 @@ 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
@@ -103,12 +113,20 @@ local function handle_status(session, status)
module:log("warn", "SASL succeeded but we didn't get a username!");
session.sasl_handler = nil;
session:reset_stream();
- return;
+ return status, ret, err_msg;
+ end
+
+ if not(require_provisioning) or usermanager_user_exists(username, session.host) then
+ sm_make_authenticated(session, session.sasl_handler.username);
+ session.sasl_handler = nil;
+ session:reset_stream();
+ 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);