From 4c4e764e23cd7d103868a73a0cdb5a7bdcaa4bea Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 7 May 2021 17:03:49 +0100 Subject: mod_c2s, mod_s2s, mod_component, mod_bosh, mod_websockets: Set default stanza size limits c2s/bosh/ws streams will default to 256KB, s2s and components to 512KB. These values are aligned with ejabberd's default settings, which should reduce issues related to inconsistent size limits between servers on the XMPP network. The previous default (10MB) is excessive for any production server, and allows significant memory usage by even unauthenticated sessions. --- plugins/mod_bosh.lua | 3 ++- plugins/mod_c2s.lua | 2 +- plugins/mod_component.lua | 3 ++- plugins/mod_s2s/mod_s2s.lua | 2 +- plugins/mod_websocket.lua | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) (limited to 'plugins') diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 52168670..db7ae03e 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -45,6 +45,7 @@ local bosh_max_wait = module:get_option_number("bosh_max_wait", 120); local consider_bosh_secure = module:get_option_boolean("consider_bosh_secure"); local cross_domain = module:get_option("cross_domain_bosh", false); +local stanza_size_limit = module:get_option_number("c2s_stanza_size_limit", 1024*256); if cross_domain == true then cross_domain = "*"; end if type(cross_domain) == "table" then cross_domain = table.concat(cross_domain, ", "); end @@ -115,7 +116,7 @@ function handle_POST(event) local body = request.body; local context = { request = request, response = response, notopen = true }; - local stream = new_xmpp_stream(context, stream_callbacks); + local stream = new_xmpp_stream(context, stream_callbacks, stanza_size_limit); response.context = context; local headers = response.headers; diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 8d4dcfb8..f19f9df5 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -26,7 +26,7 @@ local log = module._log; local c2s_timeout = module:get_option_number("c2s_timeout", 300); local stream_close_timeout = module:get_option_number("c2s_close_timeout", 5); local opt_keepalives = module:get_option_boolean("c2s_tcp_keepalives", module:get_option_boolean("tcp_keepalives", true)); -local stanza_size_limit = module:get_option_number("c2s_stanza_size_limit"); -- TODO come up with a sensible default (util.xmppstream defaults to 10M) +local stanza_size_limit = module:get_option_number("c2s_stanza_size_limit", 1024*256); local measure_connections = module:measure("connections", "amount"); local measure_ipv6 = module:measure("ipv6", "amount"); diff --git a/plugins/mod_component.lua b/plugins/mod_component.lua index b41204a2..51d731c7 100644 --- a/plugins/mod_component.lua +++ b/plugins/mod_component.lua @@ -27,6 +27,7 @@ local hosts = prosody.hosts; local log = module._log; local opt_keepalives = module:get_option_boolean("component_tcp_keepalives", module:get_option_boolean("tcp_keepalives", true)); +local stanza_size_limit = module:get_option_number("component_stanza_size_limit", module:get_option_number("s2s_stanza_size_limit", 1024*512)); local sessions = module:shared("sessions"); @@ -297,7 +298,7 @@ function listener.onconnect(conn) session.log("info", "Incoming Jabber component connection"); - local stream = new_xmpp_stream(session, stream_callbacks); + local stream = new_xmpp_stream(session, stream_callbacks, stanza_size_limit); session.stream = stream; session.notopen = true; diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index 8e398f56..b2376b97 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -37,7 +37,7 @@ local secure_auth = module:get_option_boolean("s2s_secure_auth", false); -- One local secure_domains, insecure_domains = module:get_option_set("s2s_secure_domains", {})._items, module:get_option_set("s2s_insecure_domains", {})._items; local require_encryption = module:get_option_boolean("s2s_require_encryption", false); -local stanza_size_limit = module:get_option_number("s2s_stanza_size_limit"); -- TODO come up with a sensible default (util.xmppstream defaults to 10M) +local stanza_size_limit = module:get_option_number("s2s_stanza_size_limit", 1024*512); local measure_connections = module:measure("connections", "amount"); local measure_ipv6 = module:measure("ipv6", "amount"); diff --git a/plugins/mod_websocket.lua b/plugins/mod_websocket.lua index a613672b..60c76605 100644 --- a/plugins/mod_websocket.lua +++ b/plugins/mod_websocket.lua @@ -28,7 +28,7 @@ local parse_close = websocket_frames.parse_close; local t_concat = table.concat; -local stanza_size_limit = module:get_option_number("c2s_stanza_size_limit", 10 * 1024 * 1024); +local stanza_size_limit = module:get_option_number("c2s_stanza_size_limit", 1024 * 256); local frame_buffer_limit = module:get_option_number("websocket_frame_buffer_limit", 2 * stanza_size_limit); local frame_fragment_limit = module:get_option_number("websocket_frame_fragment_limit", 8); local stream_close_timeout = module:get_option_number("c2s_close_timeout", 5); -- cgit v1.2.3 From 6a54d2d2c483de3824f57fffc3ab3375fde4e21e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 10 May 2021 16:50:24 +0100 Subject: mod_auth_internal_{plain,hashed}: Use constant-time string comparison for secrets --- plugins/mod_auth_internal_hashed.lua | 5 +++-- plugins/mod_auth_internal_plain.lua | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'plugins') diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 15058098..b29a9ee8 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -16,6 +16,7 @@ local new_sasl = require "util.sasl".new; local hex = require"util.hex"; local to_hex, from_hex = hex.to, hex.from; local saslprep = require "util.encodings".stringprep.saslprep; +local secure_equals = require "util.hashes".equals; local log = module._log; local host = module.host; @@ -39,7 +40,7 @@ function provider.test_password(username, password) end if credentials.password ~= nil and string.len(credentials.password) ~= 0 then - if saslprep(credentials.password) ~= password then + if not secure_equals(saslprep(credentials.password), password) then return nil, "Auth failed. Provided password is incorrect."; end @@ -59,7 +60,7 @@ function provider.test_password(username, password) local stored_key_hex = to_hex(stored_key); local server_key_hex = to_hex(server_key); - if valid and stored_key_hex == credentials.stored_key and server_key_hex == credentials.server_key then + if valid and secure_equals(stored_key_hex, credentials.stored_key) and secure_equals(server_key_hex, credentials.server_key) then return true; else return nil, "Auth failed. Invalid username, password, or password hash information."; diff --git a/plugins/mod_auth_internal_plain.lua b/plugins/mod_auth_internal_plain.lua index 56ef52d5..8a50e820 100644 --- a/plugins/mod_auth_internal_plain.lua +++ b/plugins/mod_auth_internal_plain.lua @@ -9,6 +9,7 @@ local usermanager = require "core.usermanager"; local new_sasl = require "util.sasl".new; local saslprep = require "util.encodings".stringprep.saslprep; +local secure_equals = require "util.hashes".equals; local log = module._log; local host = module.host; @@ -26,7 +27,7 @@ function provider.test_password(username, password) return nil, "Password fails SASLprep."; end - if password == saslprep(credentials.password) then + if secure_equals(password, saslprep(credentials.password)) then return true; else return nil, "Auth failed. Invalid username or password."; -- cgit v1.2.3 From 1e42cdef094e3c34d0c3791d5d2b55d1726d8313 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 10 May 2021 17:01:38 +0100 Subject: MUC: Add support for advertising muc#roomconfig_allowinvites in room disco#info The de-facto interpretation of this (undocumented) option is to indicate to the client whether it is allowed to invite other users to the MUC. This is differs from the existing option in our config form, which only controls the behaviour of sending of invites in a members-only MUC (we always allow invites in open rooms). Conversations is one client known to use this disco#info item to determine whether it may send invites. --- plugins/muc/members_only.lib.lua | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'plugins') diff --git a/plugins/muc/members_only.lib.lua b/plugins/muc/members_only.lib.lua index 4194c5c7..3220225f 100644 --- a/plugins/muc/members_only.lib.lua +++ b/plugins/muc/members_only.lib.lua @@ -61,12 +61,20 @@ local function set_allow_member_invites(room, allow_member_invites) end module:hook("muc-disco#info", function(event) - event.reply:tag("feature", {var = get_members_only(event.room) and "muc_membersonly" or "muc_open"}):up(); + local members_only_room = not not get_members_only(event.room); + local members_can_invite = not not get_allow_member_invites(event.room); + event.reply:tag("feature", {var = members_only_room and "muc_membersonly" or "muc_open"}):up(); table.insert(event.form, { name = "{http://prosody.im/protocol/muc}roomconfig_allowmemberinvites"; label = "Allow members to invite new members"; type = "boolean"; - value = not not get_allow_member_invites(event.room); + value = members_can_invite; + }); + table.insert(event.form, { + name = "muc#roomconfig_allowinvites"; + label = "Allow users to invite other users"; + type = "boolean"; + value = not members_only_room or members_can_invite; }); end); -- cgit v1.2.3 From 08f721a07280cf59abd167ad0fcfcb6f9bb8fb19 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 11 May 2021 14:10:26 +0100 Subject: mod_limits: Don't emit error when no burst period is configured --- plugins/mod_limits.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/mod_limits.lua b/plugins/mod_limits.lua index 914d5c44..616dca1b 100644 --- a/plugins/mod_limits.lua +++ b/plugins/mod_limits.lua @@ -31,7 +31,7 @@ local function parse_burst(burst, sess_type) burst = burst:match("^(%d+) ?s$"); end local n_burst = tonumber(burst); - if not n_burst then + if burst and not n_burst then module:log("error", "Unable to parse burst for %s: %q, using default burst interval (%ds)", sess_type, tostring(burst), default_burst); end return n_burst or default_burst; -- cgit v1.2.3 From 6f6c807bdf9eb25f335ace6f73243801019bbb87 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 11 May 2021 14:22:59 +0100 Subject: mod_limits: Use default limits if none configured --- plugins/mod_limits.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/mod_limits.lua b/plugins/mod_limits.lua index 616dca1b..98b52a96 100644 --- a/plugins/mod_limits.lua +++ b/plugins/mod_limits.lua @@ -39,7 +39,16 @@ end -- Process config option into limits table: -- limits = { c2s = { bytes_per_second = X, burst_seconds = Y } } -local limits = {}; +local limits = { + c2s = { + bytes_per_second = 10 * 1024; + burst_seconds = 2; + }; + s2sin = { + bytes_per_second = 30 * 1024; + burst_seconds = 2; + }; +}; for sess_type, sess_limits in pairs(limits_cfg) do limits[sess_type] = { -- cgit v1.2.3 From 0d3dc2e5223f7f63449a2c5c92b97e310377dca9 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 12 May 2021 13:59:49 +0100 Subject: mod_proxy65: Restrict access to local c2s connections by default Previously no 'proxy65_acl' option would allow unrestricted access by local or remote JIDs. --- plugins/mod_proxy65.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'plugins') diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index 00833772..36614810 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -94,6 +94,7 @@ function module.add_host(module) local proxy_address = module:get_option_string("proxy65_address", host); local proxy_acl = module:get_option_array("proxy65_acl"); + local proxy_open_access = module:get_option_boolean("proxy65_open_access", false); -- COMPAT w/pre-0.9 where proxy65_port was specified in the components section of the config local legacy_config = module:get_option_number("proxy65_port"); @@ -110,13 +111,20 @@ function module.add_host(module) -- check ACL -- using 'while' instead of 'if' so we can break out of it - while proxy_acl and #proxy_acl > 0 do --luacheck: ignore 512 + local allow; + if proxy_acl and #proxy_acl > 0 then local jid = stanza.attr.from; - local allow; for _, acl in ipairs(proxy_acl) do - if jid_compare(jid, acl) then allow = true; break; end + if jid_compare(jid, acl) then + allow = true; + break; + end end - if allow then break; end + elseif proxy_open_access or origin.type == "c2s" then + allow = true; + end + + if not allow then module:log("warn", "Denying use of proxy for %s", tostring(stanza.attr.from)); origin.send(st.error_reply(stanza, "auth", "forbidden")); return true; -- cgit v1.2.3 From 0a3d7966232970cb9c8076d693db0a7fef69116d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 12 May 2021 14:00:53 +0100 Subject: mod_dialback: Use constant-time comparison with hmac --- plugins/mod_dialback.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/mod_dialback.lua b/plugins/mod_dialback.lua index eddc3209..38d16b60 100644 --- a/plugins/mod_dialback.lua +++ b/plugins/mod_dialback.lua @@ -13,6 +13,7 @@ local log = module._log; local st = require "util.stanza"; local sha256_hash = require "util.hashes".sha256; local sha256_hmac = require "util.hashes".hmac_sha256; +local secure_equals = require "util.hashes".equals; local nameprep = require "util.encodings".stringprep.nameprep; local uuid_gen = require"util.uuid".generate; @@ -56,7 +57,7 @@ function initiate_dialback(session) end function verify_dialback(id, to, from, key) - return key == generate_dialback(id, to, from); + return secure_equals(key, generate_dialback(id, to, from)); end module:hook("stanza/jabber:server:dialback:verify", function(event) -- cgit v1.2.3 From 1cd5049c778cd54f88eb349411ccebd36af5ab3e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 23 Jun 2019 16:16:26 +0200 Subject: mod_dialback: Use correct host for certificate check (fixes #1381) --- plugins/mod_dialback.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'plugins') diff --git a/plugins/mod_dialback.lua b/plugins/mod_dialback.lua index 38d16b60..c81484a9 100644 --- a/plugins/mod_dialback.lua +++ b/plugins/mod_dialback.lua @@ -25,8 +25,7 @@ local dialback_secret = sha256_hash(module:get_option_string("dialback_secret", local dwd = module:get_option_boolean("dialback_without_dialback", false); --- Helper to check that a session peer's certificate is valid -function check_cert_status(session) - local host = session.direction == "outgoing" and session.to_host or session.from_host +function check_cert_status(session, host) local conn = session.conn:socket() local cert if conn.getpeercertificate then -- cgit v1.2.3 From c2ce30433a9dd12436f532be4dd3b0548c2bbae3 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 12 May 2021 17:22:02 +0200 Subject: mod_dialback: Remove d-w-d feature Backs out 1d0862814bfc and 2fdd71b08126 Largely unused, undocumented and did not have enough tests to provide confidence in its correct operation. --- plugins/mod_dialback.lua | 22 ---------------------- plugins/mod_s2s/mod_s2s.lua | 2 +- 2 files changed, 1 insertion(+), 23 deletions(-) (limited to 'plugins') diff --git a/plugins/mod_dialback.lua b/plugins/mod_dialback.lua index c81484a9..4e9f9458 100644 --- a/plugins/mod_dialback.lua +++ b/plugins/mod_dialback.lua @@ -22,19 +22,6 @@ local xmlns_stream = "http://etherx.jabber.org/streams"; local dialback_requests = setmetatable({}, { __mode = 'v' }); local dialback_secret = sha256_hash(module:get_option_string("dialback_secret", uuid_gen()), true); -local dwd = module:get_option_boolean("dialback_without_dialback", false); - ---- Helper to check that a session peer's certificate is valid -function check_cert_status(session, host) - local conn = session.conn:socket() - local cert - if conn.getpeercertificate then - cert = conn:getpeercertificate() - end - - return module:fire_event("s2s-check-certificate", { host = host, session = session, cert = cert }); -end - function module.save() return { dialback_secret = dialback_secret }; @@ -104,15 +91,6 @@ module:hook("stanza/jabber:server:dialback:result", function(event) origin:close("improper-addressing"); end - if dwd and origin.secure then - if check_cert_status(origin, from) == false then - return - elseif origin.cert_chain_status == "valid" and origin.cert_identity_status == "valid" then - origin.sends2s(st.stanza("db:result", { to = from, from = to, id = attr.id, type = "valid" })); - module:fire_event("s2s-authenticated", { session = origin, host = from }); - return true; - end - end origin.hosts[from] = { dialback_key = stanza[1] }; diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index b2376b97..c3de28db 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -276,7 +276,7 @@ function make_authenticated(event) end --- Helper to check that a session peer's certificate is valid -function check_cert_status(session) +local function check_cert_status(session) local host = session.direction == "outgoing" and session.to_host or session.from_host local conn = session.conn:socket() local cert -- cgit v1.2.3