aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Wild <mwild1@gmail.com>2021-05-13 11:17:13 +0100
committerMatthew Wild <mwild1@gmail.com>2021-05-13 11:17:13 +0100
commit5bc8b2a379e21901429e4d7f5e10e424ca85e403 (patch)
treedc46f3423a4319e09fe85402fa76f15568ad89d1
parent37ad3b8fb2039684273b3cb63b5b573e879b04d7 (diff)
parenta95576d485eda2a273b4d66c4c2b363f88c5c43a (diff)
downloadprosody-5bc8b2a379e21901429e4d7f5e10e424ca85e403.tar.gz
prosody-5bc8b2a379e21901429e4d7f5e10e424ca85e403.zip
Merge 0.11->trunk
-rw-r--r--core/certmanager.lua21
-rw-r--r--plugins/mod_auth_internal_hashed.lua5
-rw-r--r--plugins/mod_auth_internal_plain.lua3
-rw-r--r--plugins/mod_bosh.lua3
-rw-r--r--plugins/mod_c2s.lua2
-rw-r--r--plugins/mod_component.lua3
-rw-r--r--plugins/mod_dialback.lua26
-rw-r--r--plugins/mod_limits.lua13
-rw-r--r--plugins/mod_proxy65.lua16
-rw-r--r--plugins/mod_s2s.lua4
-rw-r--r--plugins/mod_websocket.lua2
-rw-r--r--plugins/muc/members_only.lib.lua12
-rw-r--r--prosody.cfg.lua.dist13
-rwxr-xr-xprosodyctl4
-rw-r--r--util-src/hashes.c14
-rw-r--r--util/prosodyctl/check.lua2
-rw-r--r--util/set.lua6
-rw-r--r--util/startup.lua8
-rw-r--r--util/xmppstream.lua8
19 files changed, 111 insertions, 54 deletions
diff --git a/core/certmanager.lua b/core/certmanager.lua
index 69c8e32c..4d2649b0 100644
--- a/core/certmanager.lua
+++ b/core/certmanager.lua
@@ -42,12 +42,13 @@ local pathutil = require"util.paths";
local resolve_path = pathutil.resolve_relative_path;
local config_path = prosody.paths.config or ".";
+local function test_option(option)
+ return not not ssl_newcontext({mode="server",protocol="sslv23",options={ option }});
+end
+
local luasec_major, luasec_minor = ssl._VERSION:match("^(%d+)%.(%d+)");
local luasec_version = tonumber(luasec_major) * 100 + tonumber(luasec_minor);
--- TODO Use ssl.config instead of require here once we are sure that the fix
--- in LuaSec has been widely distributed
--- https://github.com/brunoos/luasec/issues/149
-local luasec_has = softreq"ssl.config" or {
+local luasec_has = ssl.config or softreq"ssl.config" or {
algorithms = {
ec = luasec_version >= 5;
};
@@ -55,11 +56,12 @@ local luasec_has = softreq"ssl.config" or {
curves_list = luasec_version >= 7;
};
options = {
- cipher_server_preference = luasec_version >= 2;
- no_ticket = luasec_version >= 4;
- no_compression = luasec_version >= 5;
- single_dh_use = luasec_version >= 2;
- single_ecdh_use = luasec_version >= 2;
+ cipher_server_preference = test_option("cipher_server_preference");
+ no_ticket = test_option("no_ticket");
+ no_compression = test_option("no_compression");
+ single_dh_use = test_option("single_dh_use");
+ single_ecdh_use = test_option("single_ecdh_use");
+ no_renegotiation = test_option("no_renegotiation");
};
};
@@ -219,6 +221,7 @@ local core_defaults = {
no_compression = luasec_has.options.no_compression and configmanager.get("*", "ssl_compression") ~= true;
single_dh_use = luasec_has.options.single_dh_use;
single_ecdh_use = luasec_has.options.single_ecdh_use;
+ no_renegotiation = luasec_has.options.no_renegotiation;
};
verifyext = {
"lsec_continue", -- Continue past certificate verification errors
diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua
index 4fd0bd13..37621d20 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;
@@ -41,7 +42,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
@@ -61,7 +62,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.";
diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua
index 0fbf3037..b050e350 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");
+local stanza_size_limit = module:get_option_number("c2s_stanza_size_limit", 1024*256);
if cross_domain ~= nil then
module:log("info", "The 'cross_domain_bosh' option has been deprecated");
@@ -122,7 +123,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 8687b4df..38a275f5 100644
--- a/plugins/mod_c2s.lua
+++ b/plugins/mod_c2s.lua
@@ -27,7 +27,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:metric("gauge", "connections", "", "Established c2s connections", {"host", "type", "ip_family"});
diff --git a/plugins/mod_component.lua b/plugins/mod_component.lua
index a0bac298..fb5f5ab8 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");
@@ -304,7 +305,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_dialback.lua b/plugins/mod_dialback.lua
index 7396e07e..0df8d36f 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;
@@ -21,20 +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)
- local host = session.direction == "outgoing" and session.to_host or session.from_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 };
@@ -56,7 +43,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)
@@ -110,15 +97,6 @@ module:hook("stanza/jabber:server:dialback:result", function(event)
return true;
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, mechanism = "dialback" });
- return true;
- end
- end
origin.hosts[from] = { dialback_key = stanza[1] };
diff --git a/plugins/mod_limits.lua b/plugins/mod_limits.lua
index 024ab686..9fe62d05 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, burst, default_burst);
end
return n_burst or default_burst;
@@ -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] = {
diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua
index bac36b55..069ce0a9 100644
--- a/plugins/mod_proxy65.lua
+++ b/plugins/mod_proxy65.lua
@@ -93,6 +93,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");
@@ -109,13 +110,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", stanza.attr.from);
origin.send(st.error_reply(stanza, "auth", "forbidden"));
return true;
diff --git a/plugins/mod_s2s.lua b/plugins/mod_s2s.lua
index 679f97e9..9c45fc31 100644
--- a/plugins/mod_s2s.lua
+++ b/plugins/mod_s2s.lua
@@ -39,7 +39,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_inbound = module:metric(
"gauge", "connections_inbound", "",
@@ -343,7 +343,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
diff --git a/plugins/mod_websocket.lua b/plugins/mod_websocket.lua
index 6946894a..80296c5b 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);
diff --git a/plugins/muc/members_only.lib.lua b/plugins/muc/members_only.lib.lua
index 79077153..6a2543e1 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);
diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist
index c6a210e5..32776a2e 100644
--- a/prosody.cfg.lua.dist
+++ b/prosody.cfg.lua.dist
@@ -55,6 +55,7 @@ modules_enabled = {
"blocklist"; -- Allow users to block communications with other users
"vcard4"; -- User profiles (stored in PEP)
"vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard
+ "limits"; -- Enable bandwidth limiting for XMPP connections
-- Nice to have
"version"; -- Replies to server version requests
@@ -75,7 +76,6 @@ modules_enabled = {
--"http_files"; -- Serve static files from a directory over HTTP
-- Other specific functionality
- --"limits"; -- Enable bandwidth limiting for XMPP connections
--"groups"; -- Shared roster support
--"server_contact_info"; -- Publish contact information for this service
--"announce"; -- Send announcement to all online users
@@ -125,6 +125,17 @@ s2s_secure_auth = false
--s2s_secure_domains = { "jabber.org" }
+-- Enable rate limits for incoming client and server connections
+
+limits = {
+ c2s = {
+ rate = "10kb/s";
+ };
+ s2sin = {
+ rate = "30kb/s";
+ };
+}
+
-- Select the authentication backend to use. The 'internal' providers
-- use Prosody's configured data storage to store the authentication data.
diff --git a/prosodyctl b/prosodyctl
index 07df69b6..558d59f4 100755
--- a/prosodyctl
+++ b/prosodyctl
@@ -466,6 +466,7 @@ function commands.about(arg)
ssl = "LuaSec";
};
local lunbound = dependencies.softreq"lunbound";
+ local lxp = dependencies.softreq"lxp";
for name, module in pairs(package.loaded) do
if type(module) == "table" and rawget(module, "_VERSION")
and name ~= "_G" and not name:match("%.") then
@@ -486,6 +487,9 @@ function commands.about(arg)
end
library_versions["libunbound"] = lunbound._LIBVER;
end
+ if lxp then
+ library_versions["libexpat"] = lxp._EXPAT_VERSION;
+ end
for name, version in sorted_pairs(module_versions) do
print(name..":"..string.rep(" ", longest_name-#name), version);
end
diff --git a/util-src/hashes.c b/util-src/hashes.c
index 84a604ef..31b52f40 100644
--- a/util-src/hashes.c
+++ b/util-src/hashes.c
@@ -23,6 +23,7 @@ typedef unsigned __int32 uint32_t;
#include "lua.h"
#include "lauxlib.h"
+#include <openssl/crypto.h>
#include <openssl/sha.h>
#include <openssl/md5.h>
#include <openssl/hmac.h>
@@ -133,6 +134,18 @@ static int Lpbkdf2_sha256(lua_State *L) {
return 1;
}
+static int Lhash_equals(lua_State *L) {
+ size_t len1, len2;
+ const char *s1 = luaL_checklstring(L, 1, &len1);
+ const char *s2 = luaL_checklstring(L, 2, &len2);
+ if(len1 == len2) {
+ lua_pushboolean(L, CRYPTO_memcmp(s1, s2, len1) == 0);
+ } else {
+ lua_pushboolean(L, 0);
+ }
+ return 1;
+}
+
static const luaL_Reg Reg[] = {
{ "sha1", Lsha1 },
{ "sha224", Lsha224 },
@@ -147,6 +160,7 @@ static const luaL_Reg Reg[] = {
{ "scram_Hi_sha1", Lpbkdf2_sha1 }, /* COMPAT */
{ "pbkdf2_hmac_sha1", Lpbkdf2_sha1 },
{ "pbkdf2_hmac_sha256", Lpbkdf2_sha256 },
+ { "equals", Lhash_equals },
{ NULL, NULL }
};
diff --git a/util/prosodyctl/check.lua b/util/prosodyctl/check.lua
index 4822448a..905703d2 100644
--- a/util/prosodyctl/check.lua
+++ b/util/prosodyctl/check.lua
@@ -47,7 +47,7 @@ local function check(arg)
"umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings",
"network_backend", "http_default_host",
"statistics_interval", "statistics", "statistics_config",
- "plugin_server", "installer_plugin_path",
+ "plugin_server", "installer_plugin_path", "gc"
});
local config = configmanager.getconfig();
-- Check that we have any global options (caused by putting a host at the top)
diff --git a/util/set.lua b/util/set.lua
index 827a9158..7e600ebd 100644
--- a/util/set.lua
+++ b/util/set.lua
@@ -32,6 +32,11 @@ function set_mt:__freeze()
return a;
end
+local function is_set(o)
+ local mt = getmetatable(o);
+ return mt == set_mt;
+end
+
local function new(list)
local items = setmetatable({}, items_mt);
local set = { _items = items };
@@ -177,6 +182,7 @@ end
return {
new = new;
+ is_set = is_set;
union = union;
difference = difference;
intersection = intersection;
diff --git a/util/startup.lua b/util/startup.lua
index 11225290..52832988 100644
--- a/util/startup.lua
+++ b/util/startup.lua
@@ -14,7 +14,13 @@ local dependencies = require "util.dependencies";
local original_logging_config;
-local default_gc_params = { mode = "incremental", threshold = 105, speed = 250 };
+local default_gc_params = {
+ mode = "incremental";
+ -- Incremental mode defaults
+ threshold = 105, speed = 500;
+ -- Generational mode defaults
+ minor_threshold = 20, major_threshold = 50;
+};
local short_params = { D = "daemonize", F = "no-daemonize" };
local value_params = { config = true };
diff --git a/util/xmppstream.lua b/util/xmppstream.lua
index 2763b000..be113396 100644
--- a/util/xmppstream.lua
+++ b/util/xmppstream.lua
@@ -22,7 +22,7 @@ local lxp_supports_doctype = pcall(lxp.new, { StartDoctypeDecl = false });
local lxp_supports_xmldecl = pcall(lxp.new, { XmlDecl = false });
local lxp_supports_bytecount = not not lxp.new({}).getcurrentbytecount;
-local default_stanza_size_limit = 1024*1024*10; -- 10MB
+local default_stanza_size_limit = 1024*1024*1; -- 1MB
local _ENV = nil;
-- luacheck: std none
@@ -194,6 +194,9 @@ local function new_sax_handlers(session, stream_callbacks, cb_handleprogress)
stanza = t_remove(stack);
end
else
+ if lxp_supports_bytecount then
+ cb_handleprogress(stanza_size);
+ end
if cb_streamclosed then
cb_streamclosed(session);
end
@@ -295,6 +298,9 @@ local function new(session, stream_callbacks, stanza_size_limit)
return ok, err;
end,
set_session = meta.set_session;
+ set_stanza_size_limit = function (_, new_stanza_size_limit)
+ stanza_size_limit = new_stanza_size_limit;
+ end;
};
end