From c5af3aee3e651187a3a582045dbe269e1b61fe4d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 4 Aug 2017 18:52:15 +0100 Subject: util.sql: Greedily read all rows so we can close queries early (fixes #391) --- util/sql.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util/sql.lua b/util/sql.lua index 15749911..61d6af41 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -175,7 +175,11 @@ function engine:execute_query(sql, ...) sql = self:prepquery(sql); local stmt = assert(self.conn:prepare(sql)); assert(stmt:execute(...)); - return stmt:rows(); + local result = {}; + for row in stmt:rows() do result[#result + 1] = row; end + stmt:close(); + local i = 0; + return function() i=i+1; return result[i]; end; end function engine:execute_update(sql, ...) sql = self:prepquery(sql); -- cgit v1.2.3 From b433940c1ea9200498017fdf529f395a2a92de1d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 21 Jul 2017 00:07:34 +0200 Subject: MUC: Reject whitespace-only nicknames (fixes #337) --- plugins/muc/muc.lib.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 8c486b87..e16a43f6 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -435,6 +435,13 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc self._occupants[current_nick].sessions[from] = pr; self:broadcast_presence(pr, from); else -- change nick + -- a MUC service MUST NOT allow empty or invisible Room Nicknames + -- (i.e., Room Nicknames that consist only of one or more space characters). + if not select(3, jid_split(nick)):find("[^ ]") then -- resourceprep turns all whitespace into 0x20 + module:log("debug", "Rejecting invisible nickname"); + origin.send(st.error_reply(stanza, "cancel", "not-allowed")); + return; + end local occupant = self._occupants[current_nick]; local is_multisession = next(occupant.sessions, next(occupant.sessions)); if self._occupants[to] or is_multisession then @@ -467,6 +474,13 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc -- self:handle_to_occupant(origin, stanza); -- resend available --end else -- enter room + -- a MUC service MUST NOT allow empty or invisible Room Nicknames + -- (i.e., Room Nicknames that consist only of one or more space characters). + if not select(3, jid_split(nick)):find("[^ ]") then -- resourceprep turns all whitespace into 0x20 + module:log("debug", "Rejecting invisible nickname"); + origin.send(st.error_reply(stanza, "cancel", "not-allowed")); + return; + end local new_nick = to; local is_merge; if self._occupants[to] then -- cgit v1.2.3 From 46863c65b32369fc20ba920d46a5f4fd27293ad8 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 27 Jul 2017 14:10:18 +0200 Subject: mod_disco: Advertise in stream-features after auth (probably what was meant in 200f1f6306a7) (fixes #957) --- plugins/mod_disco.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua index 10eb632d..cd07934f 100644 --- a/plugins/mod_disco.lua +++ b/plugins/mod_disco.lua @@ -148,7 +148,7 @@ end); -- Handle caps stream feature module:hook("stream-features", function (event) - if event.origin.type == "c2s" or event.origin.type == "c2s_unauthed" then + if event.origin.type == "c2s" or event.origin.type == "c2s_unbound" then event.features:add_child(get_server_caps_feature()); end end); -- cgit v1.2.3 From 627b87ac7c1d4e67d317b88365df07bcd621f48e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 30 Jul 2017 18:47:43 +0200 Subject: net.websocket: Remove stray module api reference, shouldn't be used in here --- net/websocket.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/websocket.lua b/net/websocket.lua index 373210d6..777b894c 100644 --- a/net/websocket.lua +++ b/net/websocket.lua @@ -38,7 +38,7 @@ function websocket_listeners.ondetach(handler) end local function fail(s, code, reason) - module:log("warn", "WebSocket connection failed, closing. %d %s", code, reason); + log("warn", "WebSocket connection failed, closing. %d %s", code, reason); s:close(code, reason); s.handler:close(); return false -- cgit v1.2.3 From ef1f75a9dd0ebd0f116508b89abbcd790482eb07 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 4 Aug 2017 20:27:43 +0200 Subject: prosodyctl: Skip certificate checks for hosts of the form node@host (fixes #779) --- prosodyctl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/prosodyctl b/prosodyctl index 8997f31c..800dddbf 100755 --- a/prosodyctl +++ b/prosodyctl @@ -1336,7 +1336,14 @@ function commands.check(arg) print("This version of LuaSec (" .. ssl._VERSION .. ") does not support certificate checking"); cert_ok = false else - for host in enabled_hosts() do + local function skip_bare_jid_hosts(host) + if jid_split(host) then + -- See issue #779 + return false; + end + return true; + end + for host in it.filter(skip_bare_jid_hosts, enabled_hosts()) do print("Checking certificate for "..host); -- First, let's find out what certificate this host uses. local host_ssl_config = config.rawget(host, "ssl") -- cgit v1.2.3 From cc8653d31c87dcdf4d140697e87b57ca5130d9d5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 6 Aug 2017 13:27:47 +0200 Subject: MUC: Use variable that actually exists (thanks Martin) --- plugins/muc/muc.lib.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index e16a43f6..53b4f682 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -437,7 +437,7 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc else -- change nick -- a MUC service MUST NOT allow empty or invisible Room Nicknames -- (i.e., Room Nicknames that consist only of one or more space characters). - if not select(3, jid_split(nick)):find("[^ ]") then -- resourceprep turns all whitespace into 0x20 + if not select(3, jid_split(to)):find("[^ ]") then -- resourceprep turns all whitespace into 0x20 module:log("debug", "Rejecting invisible nickname"); origin.send(st.error_reply(stanza, "cancel", "not-allowed")); return; @@ -476,7 +476,7 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc else -- enter room -- a MUC service MUST NOT allow empty or invisible Room Nicknames -- (i.e., Room Nicknames that consist only of one or more space characters). - if not select(3, jid_split(nick)):find("[^ ]") then -- resourceprep turns all whitespace into 0x20 + if not select(3, jid_split(to)):find("[^ ]") then -- resourceprep turns all whitespace into 0x20 module:log("debug", "Rejecting invisible nickname"); origin.send(st.error_reply(stanza, "cancel", "not-allowed")); return; -- cgit v1.2.3 From 73b75571e6546448dac8a67c6c231c14851ccac1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 28 Jul 2017 13:15:29 +0200 Subject: core.usermanager, various modules: Disconnect other resources on password change (thanks waqas) (fixes #512) --- core/usermanager.lua | 8 ++++++-- plugins/mod_admin_adhoc.lua | 2 +- plugins/mod_admin_telnet.lua | 2 +- plugins/mod_auth_internal_hashed.lua | 4 +++- plugins/mod_c2s.lua | 12 ++++++++++++ plugins/mod_register.lua | 2 +- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/core/usermanager.lua b/core/usermanager.lua index d5132662..f795e8ae 100644 --- a/core/usermanager.lua +++ b/core/usermanager.lua @@ -76,8 +76,12 @@ local function get_password(username, host) return hosts[host].users.get_password(username); end -local function set_password(username, password, host) - return hosts[host].users.set_password(username, password); +local function set_password(username, password, host, resource) + local ok, err = hosts[host].users.set_password(username, password); + if ok then + prosody.events.fire_event("user-password-changed", { username = username, host = host, resource = resource }); + end + return ok, err; end local function user_exists(username, host) diff --git a/plugins/mod_admin_adhoc.lua b/plugins/mod_admin_adhoc.lua index 392e715e..f3de6793 100644 --- a/plugins/mod_admin_adhoc.lua +++ b/plugins/mod_admin_adhoc.lua @@ -97,7 +97,7 @@ local change_user_password_command_handler = adhoc_simple(change_user_password_l if module_host ~= host then return { status = "completed", error = { message = "Trying to change the password of a user on " .. host .. " but command was sent to " .. module_host}}; end - if usermanager_user_exists(username, host) and usermanager_set_password(username, fields.password, host) then + if usermanager_user_exists(username, host) and usermanager_set_password(username, fields.password, host, nil) then return { status = "completed", info = "Password successfully changed" }; else return { status = "completed", error = { message = "User does not exist" } }; diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index 293f6320..5c01f8b8 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -1030,7 +1030,7 @@ function def_env.user:password(jid, password) elseif not um.user_exists(username, host) then return nil, "No such user"; end - local ok, err = um.set_password(username, password, host); + local ok, err = um.set_password(username, password, host, nil); if ok then return true, "User password changed"; else diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 53e345e5..35764afb 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -120,7 +120,9 @@ function provider.get_sasl_handler() local credentials = accounts:get(username); if not credentials then return; end if credentials.password then - usermanager.set_password(username, credentials.password, host); + if provider.set_password(username, credentials.password) == nil then + return nil, "Auth failed. Could not set hashed password from plaintext."; + end credentials = accounts:get(username); if not credentials then return; end end diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index cfeb0f0e..fbc22be6 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -203,6 +203,18 @@ module:hook_global("user-deleted", function(event) end end, 200); +module:hook_global("user-password-changed", function(event) + local username, host, resource = event.username, event.host, event.resource; + local user = hosts[host].sessions[username]; + if user and user.sessions then + for r, session in pairs(user.sessions) do + if r ~= resource then + session:close{ condition = "reset", text = "Password changed" }; + end + end + end +end, 200); + --- Port listener function listener.onconnect(conn) local session = sm_new_session(conn); diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index fd5339d9..832dd991 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -130,7 +130,7 @@ local function handle_registration_stanza(event) local password = query:get_child_text("password"); if username and password then if username == session.username then - if usermanager_set_password(username, password, session.host) then + if usermanager_set_password(username, password, session.host, session.resource) then session.send(st.reply(stanza)); else -- TODO unable to write file, file may be locked, etc, what's the correct error? -- cgit v1.2.3 From 88bd13d98b8220f5136890f69becf8a929ad1e0c Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 25 Jul 2017 22:01:16 +0200 Subject: mod_mam: Clone stanzas before mutating (thanks waqas) (fixes #961) --- plugins/mod_mam/mod_mam.lua | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/plugins/mod_mam/mod_mam.lua b/plugins/mod_mam/mod_mam.lua index 1dcce4e4..a86697e8 100644 --- a/plugins/mod_mam/mod_mam.lua +++ b/plugins/mod_mam/mod_mam.lua @@ -243,15 +243,19 @@ local function message_handler(event, c2s) local with = jid_bare(c2s and orig_to or orig_from); -- Filter out that claim to be from us - stanza:maptags(function (tag) - if tag.name == "stanza-id" and tag.attr.xmlns == xmlns_st_id then - local by_user, by_host, res = jid_prepped_split(tag.attr.by); - if not res and by_host == module.host and by_user == store_user then - return nil; + if stanza:get_child("stanza-id", xmlns_st_id) then + stanza = st.clone(stanza); + stanza:maptags(function (tag) + if tag.name == "stanza-id" and tag.attr.xmlns == xmlns_st_id then + local by_user, by_host, res = jid_prepped_split(tag.attr.by); + if not res and by_host == module.host and by_user == store_user then + return nil; + end end - end - return tag; - end); + return tag; + end); + event.stanza = stanza; + end -- We store chat messages or normal messages that have a body if not(orig_type == "chat" or (orig_type == "normal" and stanza:get_child("body")) ) then @@ -268,18 +272,21 @@ local function message_handler(event, c2s) end end + local clone_for_storage; if not strip_tags:empty() then - stanza = st.clone(stanza); - stanza:maptags(function (tag) + clone_for_storage = st.clone(stanza); + clone_for_storage:maptags(function (tag) if strip_tags:contains(tag.attr.xmlns) then return nil; else return tag; end end); - if #stanza.tags == 0 then + if #clone_for_storage.tags == 0 then return; end + else + clone_for_storage = stanza; end -- Check with the users preferences @@ -287,12 +294,14 @@ local function message_handler(event, c2s) log("debug", "Archiving stanza: %s", stanza:top_tag()); -- And stash it - local ok = archive:append(store_user, nil, stanza, time_now(), with); + local ok = archive:append(store_user, nil, clone_for_storage, time_now(), with); if ok then + local clone_for_other_handlers = st.clone(stanza); local id = ok; - event.stanza:tag("stanza-id", { xmlns = xmlns_st_id, by = store_user.."@"..host, id = id }):up(); + clone_for_other_handlers:tag("stanza-id", { xmlns = xmlns_st_id, by = store_user.."@"..host, id = id }):up(); + event.stanza = clone_for_other_handlers; if cleanup then cleanup[store_user] = true; end - module:fire_event("archive-message-added", { origin = origin, stanza = stanza, for_user = store_user, id = id }); + module:fire_event("archive-message-added", { origin = origin, stanza = clone_for_storage, for_user = store_user, id = id }); end else log("debug", "Not archiving stanza: %s (prefs)", stanza:top_tag()); -- cgit v1.2.3 From a15830f3784e1314848f6cea9d2302edb89b4d7b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 24 Aug 2017 21:51:11 +0200 Subject: mod_register: Add comments saying which section handles password change, account deletion and which is in-band registration --- plugins/mod_register.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index 832dd991..b39ce090 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -91,6 +91,7 @@ module:hook("stream-features", function(event) features:add_child(register_stream_feature); end); +-- Password change and account deletion handler local function handle_registration_stanza(event) local session, stanza = event.origin, event.stanza; local log = session.log or module._log; @@ -207,6 +208,7 @@ local function check_throttle(ip) return throttle:poll(1); end +-- In-band registration module:hook("stanza/iq/jabber:iq:register:query", function(event) local session, stanza = event.origin, event.stanza; local log = session.log or module._log; -- cgit v1.2.3 From 10d48f1bad15b74de952aa8ce51d04ad60861c64 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 7 Jul 2017 20:16:00 +0200 Subject: net.http: Remove duplicate 'request' entry --- net/http.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/net/http.lua b/net/http.lua index d820e471..cce363ae 100644 --- a/net/http.lua +++ b/net/http.lua @@ -235,7 +235,6 @@ local function new(options) return new(setmetatable(new_options, { __index = options })); end or new; events = events.new(); - request = request; }; return http; end -- cgit v1.2.3 From 450544aad0a236e7ebcf3307e8fe8dbda683d775 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 7 Jul 2017 20:30:52 +0200 Subject: net.http: Expose defaults --- net/http.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/net/http.lua b/net/http.lua index cce363ae..0d14e526 100644 --- a/net/http.lua +++ b/net/http.lua @@ -245,6 +245,7 @@ return { request = function (u, ex, callback) return default_http:request(u, ex, callback); end; + default = default_http; new = new; events = default_http.events; -- COMPAT -- cgit v1.2.3 From 708ce26bc81ce86b5f0a23f4beb3119210ab6d8f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 7 Jul 2017 20:31:52 +0200 Subject: net.http: Move default SSL/TLS settings into options, allowing them to be overriden in new() --- net/http.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/http.lua b/net/http.lua index 0d14e526..756deaf4 100644 --- a/net/http.lua +++ b/net/http.lua @@ -196,7 +196,7 @@ local function request(self, u, ex, callback) local sslctx = false; if using_https then - sslctx = ex and ex.sslctx or { mode = "client", protocol = "sslv23", options = { "no_sslv2", "no_sslv3" } }; + sslctx = ex and ex.sslctx or self.options and self.options.sslctx; end local handler, conn = server.addclient(host, port_number, listener, "*a", sslctx) @@ -239,7 +239,9 @@ local function new(options) return http; end -local default_http = new(); +local default_http = new({ + sslctx = { mode = "client", protocol = "sslv23", options = { "no_sslv2", "no_sslv3" } }; +}); return { request = function (u, ex, callback) -- cgit v1.2.3 From cb0a2ffe81725c4457a999af5c03b91493629df5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 7 Jul 2017 20:42:35 +0200 Subject: prosody, prosodyctl: Set up TLS settings for HTTPS requests in net.http (part of fix for #659) --- prosody | 6 +++++- prosodyctl | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/prosody b/prosody index 0a48eba4..7d9e76b8 100755 --- a/prosody +++ b/prosody @@ -323,7 +323,11 @@ function load_secondary_libraries() return function() end end}); - require "net.http" + local http = require "net.http" + local config_ssl = config.get("*", "ssl") + local https_client = config.get("*", "client_https_ssl") + http.default.options.sslctx = require "core.certmanager".create_context("client_https port 0", "client", + { capath = config_ssl.capath, cafile = config_ssl.cafile, verify = "peer", }, https_client); require "util.array" require "util.datetime" diff --git a/prosodyctl b/prosodyctl index 800dddbf..cd58212e 100755 --- a/prosodyctl +++ b/prosodyctl @@ -251,6 +251,13 @@ local modulemanager = require "core.modulemanager" local prosodyctl = require "util.prosodyctl" local socket = require "socket" + +local http = require "net.http" +local config_ssl = config.get("*", "ssl") +local https_client = config.get("*", "client_https_ssl") +http.default.options.sslctx = require "core.certmanager".create_context("client_https port 0", "client", + { capath = config_ssl.capath, cafile = config_ssl.cafile, verify = "peer", }, https_client); + ----------------------- -- FIXME: Duplicate code waiting for util.startup -- cgit v1.2.3 From e605ac0987662ef14c3f0b642079a815961102e1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 7 Jul 2017 21:04:30 +0200 Subject: net.http: Validate HTTPS certificates (fixes #659) --- net/http.lua | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/net/http.lua b/net/http.lua index 756deaf4..eba050cd 100644 --- a/net/http.lua +++ b/net/http.lua @@ -11,6 +11,7 @@ local url = require "socket.url" local httpstream_new = require "net.http.parser".new; local util_http = require "util.http"; local events = require "util.events"; +local verify_identity = require"util.x509".verify_identity; local ssl_available = pcall(require, "ssl"); @@ -34,6 +35,26 @@ local listener = { default_port = 80, default_mode = "*a" }; function listener.onconnect(conn) local req = requests[conn]; + + -- Validate certificate + if conn:ssl() then + local sock = conn:socket(); + local chain_valid = sock.getpeerverification and sock:getpeerverification(); + if not chain_valid then + req.callback("certificate-chain-invalid", 0, req); + req.callback = nil; + conn:close(); + return; + end + local cert = sock.getpeercertificate and sock:getpeercertificate(); + if not cert or not verify_identity(req.host, false, cert) then + req.callback("certificate-verify-failed", 0, req); + req.callback = nil; + conn:close(); + return; + end + end + -- Send the request local request_line = { req.method or "GET", " ", req.path, " HTTP/1.1\r\n" }; if req.query then -- cgit v1.2.3 From 7e28119b3d3fe91b2f8541da2af90b232ab38412 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 7 Jul 2017 21:04:46 +0200 Subject: net.http: Add option for disabling TLS certifictate validation --- net/http.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/http.lua b/net/http.lua index eba050cd..8364a104 100644 --- a/net/http.lua +++ b/net/http.lua @@ -37,7 +37,7 @@ function listener.onconnect(conn) local req = requests[conn]; -- Validate certificate - if conn:ssl() then + if not req.insecure and conn:ssl() then local sock = conn:socket(); local chain_valid = sock.getpeerverification and sock:getpeerverification(); if not chain_valid then @@ -202,6 +202,7 @@ local function request(self, u, ex, callback) headers[k] = v; end end + req.insecure = ex.insecure; end log("debug", "Making %s %s request '%s' to %s", req.scheme:upper(), method or "GET", req.id, (ex and ex.suppress_url and host_header) or u); -- cgit v1.2.3