changeset 1188:5eaecb7f680d

mod_watchuntrusted: New module that will warn admins about s2s connections that fail due to lack of encryption or invalid certificates.
author Thijs Alkemade <me@thijsalkema.de>
date Fri, 06 Sep 2013 13:07:57 +0200
parents d677d1807bb0
children 1630c6ed3814
files mod_watchuntrusted/mod_watchuntrusted.lua
diffstat 1 files changed, 56 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_watchuntrusted/mod_watchuntrusted.lua	Fri Sep 06 13:07:57 2013 +0200
@@ -0,0 +1,56 @@
+local jid_prep = require "util.jid".prep;
+
+local secure_auth = module:get_option_boolean("s2s_secure_auth", false);
+local secure_domains, insecure_domains =
+	module:get_option_set("s2s_secure_domains", {})._items, module:get_option_set("s2s_insecure_domains", {})._items;
+
+local untrusted_fail_watchers = module:get_option_set("untrusted_fail_watchers", module:get_option("admins", {})) / jid_prep;
+local untrusted_fail_notification = module:get_option("untrusted_fail_notification", "Establishing a secure connection from $from_host to $to_host failed. Certificate hash: $sha1. $errors");
+
+local st = require "util.stanza";
+
+module:hook_global("s2s-check-certificate", function (event)
+    local session, host = event.session, event.host;
+    local conn = session.conn:socket();
+    local local_host = session.direction == "outgoing" and session.from_host or session.to_host;
+
+    if not (local_host == module:get_host()) then return end
+
+    module:log("debug", "Checking certificate...");
+    local must_secure = secure_auth;
+
+    if not must_secure and secure_domains[host] then
+            must_secure = true;
+    elseif must_secure and insecure_domains[host] then
+            must_secure = false;
+    end
+
+    if must_secure and (session.cert_chain_status ~= "valid" or session.cert_identity_status ~= "valid") then
+		local _, errors = conn:getpeerverification();
+		local error_message = "";
+
+		for depth, t in pairs(errors or {}) do
+			if #t > 0 then
+				error_message = error_message .. "Error with certificate " .. (depth - 1) .. ": " .. table.concat(t, ", ") .. ". ";
+			end
+		end
+
+		if session.cert_identity_status then
+			error_message = error_message .. "This certificate is " .. session.cert_identity_status .. " for " .. host .. ".";
+		end
+
+		local replacements = { sha1 = event.cert and event.cert:digest("sha1"), errors = error_message };
+
+		local message = st.message{ type = "chat", from = local_host }
+			:tag("body")
+				:text(untrusted_fail_notification:gsub("%$([%w_]+)", function (v)
+					return event[v] or session and session[v] or replacements and replacements[v] or nil;
+				end));
+		for jid in untrusted_fail_watchers do
+			module:log("debug", "Notifying %s", jid);
+			message.attr.to = jid;
+			module:send(message);
+		end
+	end
+end, -0.5);
+