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.
local array = require "prosody.util.array";
local it = require "prosody.util.iterators";
local new_short_id = require "prosody.util.id".short;
local role_methods = {};
local role_mt = {
__index = role_methods;
__name = "role";
__add = nil;
};
local function is_role(o)
local mt = getmetatable(o);
return mt == role_mt;
end
local function _new_may(permissions, inherited_mays)
local n_inherited = inherited_mays and #inherited_mays;
return function (role, action, context)
-- Note: 'role' may be a descendent role, not only the one we're attached to
local policy = permissions[action];
if policy ~= nil then
return policy;
end
if n_inherited then
for i = 1, n_inherited do
policy = inherited_mays[i](role, action, context);
if policy ~= nil then
return policy;
end
end
end
return nil;
end
end
local permissions_key = {};
-- {
-- Required:
-- name = "My fancy role";
--
-- Optional:
-- inherits = { role_obj... }
-- default = true
-- priority = 100
-- permissions = {
-- ["foo"] = true; -- allow
-- ["bar"] = false; -- deny
-- }
-- }
local function new(base_config, overrides)
local config = setmetatable(overrides or {}, { __index = base_config });
local permissions = {};
local inherited_mays;
if config.inherits then
inherited_mays = array.pluck(config.inherits, "may");
end
local new_role = {
id = new_short_id();
name = config.name;
description = config.description;
default = config.default;
priority = config.priority;
may = _new_may(permissions, inherited_mays);
inherits = config.inherits;
[permissions_key] = permissions;
};
local desired_permissions = config.permissions or config[permissions_key];
for k, v in pairs(desired_permissions or {}) do
permissions[k] = v;
end
return setmetatable(new_role, role_mt);
end
function role_mt:__freeze()
local t = {
id = self.id;
name = self.name;
description = self.description;
default = self.default;
priority = self.priority;
inherits = self.inherits;
permissions = self[permissions_key];
};
return t;
end
function role_methods:clone(overrides)
return new(self, overrides);
end
function role_methods:set_permission(permission_name, policy, overwrite)
local permissions = self[permissions_key];
if overwrite ~= true and permissions[permission_name] ~= nil and permissions[permission_name] ~= policy then
return false, "policy-already-exists";
end
permissions[permission_name] = policy;
return true;
end
function role_methods:policies()
local policy_iterator, s, v = it.join(pairs(self[permissions_key]));
if self.inherits then
for _, inherited_role in ipairs(self.inherits) do
policy_iterator:append(inherited_role:policies());
end
end
return policy_iterator, s, v;
end
function role_mt.__tostring(self)
return ("role<[%s] %s>"):format(self.id or "nil", self.name or "[no name]");
end
function role_mt.__pairs(self)
return it.filter(permissions_key, next, self);
end
return {
is_role = is_role;
new = new;
};