mod_posix: Move everything to util.startup
This allows greater control over the order of events.
Notably, the internal ordering between daemonization, initialization of
libunbound and setup of signal handling is sensitive.
libunbound starts a separate thread for processing DNS requests.
If this thread is started before signal handling has been set up, it
will not inherit the signal handlers and instead behave as it would have
before signal handlers were set up, i.e. cause the whole process to
immediately exit.
libunbound is usually initialized on the first DNS request, usually
triggered by an outgoing s2s connection attempt.
If daemonization happens before signals have been set up, signals may
not be processed at all.
-- Prosody IM
-- Copyright (C) 2012 Florian Zeitz
-- Copyright (C) 2019 Kim Alvefur
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
local encodings = require "prosody.util.encodings";
assert(encodings.confusable, "This module requires that Prosody be built with ICU");
local skeleton = encodings.confusable.skeleton;
local usage = require "prosody.util.prosodyctl".show_usage;
local usermanager = require "prosody.core.usermanager";
local storagemanager = require "prosody.core.storagemanager";
local skeletons
function module.load()
if module.host ~= "*" then
skeletons = module:open_store("skeletons");
end
end
module:hook("user-registered", function(user)
local skel = skeleton(user.username);
local ok, err = skeletons:set(skel, { username = user.username });
if not ok then
module:log("error", "Unable to store mimicry data (%q => %q): %s", user.username, skel, err);
end
end);
module:hook_global("user-deleted", function(user)
if user.host ~= module.host then return end
local skel = skeleton(user.username);
local ok, err = skeletons:set(skel, nil);
if not ok and err then
module:log("error", "Unable to clear mimicry data (%q): %s", skel, err);
end
end);
module:hook("user-registering", function(user)
local existing, err = skeletons:get(skeleton(user.username));
if existing then
module:log("debug", "Attempt to register username '%s' which could be confused with '%s'", user.username, existing.username);
user.allowed = false;
elseif err then
module:log("error", "Unable to check if new username '%s' can be confused with any existing user: %s", err);
end
end);
function module.command(arg)
if (arg[1] ~= "bootstrap" or not arg[2]) then
usage("mod_mimicking bootstrap <host>", "Initialize username mimicry database");
return;
end
local host = arg[2];
local host_session = prosody.hosts[host];
if not host_session then
return "No such host";
end
storagemanager.initialize_host(host);
usermanager.initialize_host(host);
skeletons = storagemanager.open(host, "skeletons");
local count = 0;
for user in usermanager.users(host) do
local skel = skeleton(user);
local existing, err = skeletons:get(skel);
if existing and existing.username ~= user then
module:log("warn", "Existing usernames '%s' and '%s' are confusable", existing.username, user);
elseif err then
module:log("error", "Error checking for existing mimicry data (%q = %q): %s", user, skel, err);
end
local ok, err = skeletons:set(skel, { username = user });
if ok then
count = count + 1;
elseif err then
module:log("error", "Unable to store mimicry data (%q => %q): %s", user, skel, err);
end
end
module:log("info", "%d usernames indexed", count);
end