aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/certmanager.lua90
-rw-r--r--core/hostmanager.lua1
-rw-r--r--core/portmanager.lua37
-rw-r--r--plugins/adhoc/adhoc.lib.lua7
-rw-r--r--plugins/mod_dialback.lua25
-rw-r--r--plugins/mod_lastactivity.lua3
-rw-r--r--plugins/mod_legacyauth.lua7
-rw-r--r--plugins/mod_presence.lua8
-rw-r--r--plugins/mod_s2s/mod_s2s.lua2
-rw-r--r--plugins/mod_saslauth.lua2
-rw-r--r--plugins/mod_tls.lua34
-rw-r--r--util/sslconfig.lua87
12 files changed, 170 insertions, 133 deletions
diff --git a/core/certmanager.lua b/core/certmanager.lua
index d6a59b9f..837fe231 100644
--- a/core/certmanager.lua
+++ b/core/certmanager.lua
@@ -10,13 +10,13 @@ local configmanager = require "core.configmanager";
local log = require "util.logger".init("certmanager");
local ssl = ssl;
local ssl_newcontext = ssl and ssl.newcontext;
+local new_config = require"util.sslconfig".new;
local tostring = tostring;
local pairs = pairs;
local type = type;
local io_open = io.open;
-local t_concat = table.concat;
-local t_insert = table.insert;
+local select = select;
local prosody = prosody;
local resolve_path = require"util.paths".resolve_relative_path;
@@ -55,9 +55,6 @@ local core_defaults = {
local path_options = { -- These we pass through resolve_path()
key = true, certificate = true, cafile = true, capath = true, dhparam = true
}
-local set_options = {
- options = true, verify = true, verifyext = true
-}
if ssl and not luasec_has_verifyext and ssl.x509 then
-- COMPAT mw/luasec-hg
@@ -66,85 +63,34 @@ if ssl and not luasec_has_verifyext and ssl.x509 then
end
end
-local function merge_set(t, o)
- if type(t) ~= "table" then t = { t } end
- for k,v in pairs(t) do
- if v == true or v == false then
- o[k] = v;
- else
- o[v] = true;
- end
- end
- return o;
-end
-
-local protocols = { "sslv2", "sslv3", "tlsv1", "tlsv1_1", "tlsv1_2" };
-for i = 1, #protocols do protocols[protocols[i] .. "+"] = i - 1; end
-
-function create_context(host, mode, user_ssl_config)
- user_ssl_config = user_ssl_config or {}
- user_ssl_config.mode = mode;
-
+function create_context(host, mode, ...)
if not ssl then return nil, "LuaSec (required for encryption) was not found"; end
- if global_ssl_config then
- for option,default_value in pairs(global_ssl_config) do
- if user_ssl_config[option] == nil then
- user_ssl_config[option] = default_value;
- end
- end
- end
-
- for option,default_value in pairs(core_defaults) do
- if user_ssl_config[option] == nil then
- user_ssl_config[option] = default_value;
- end
- end
-
- for option in pairs(set_options) do
- local merged = {};
- merge_set(core_defaults[option], merged);
- if global_ssl_config then
- merge_set(global_ssl_config[option], merged);
- end
- merge_set(user_ssl_config[option], merged);
- local final_array = {};
- for opt, enable in pairs(merged) do
- if enable then
- final_array[#final_array+1] = opt;
- end
- end
- user_ssl_config[option] = final_array;
+ local cfg = new_config();
+ cfg:apply(core_defaults);
+ cfg:apply(global_ssl_config);
+ cfg:apply({
+ mode = mode,
+ -- We can't read the password interactively when daemonized
+ password = function() log("error", "Encrypted certificate for %s requires 'ssl' 'password' to be set in config", host); end;
+ });
+
+ for i = select('#', ...), 1, -1 do
+ cfg:apply(select(i, ...));
end
+ local user_ssl_config = cfg:final();
- local min_protocol = protocols[user_ssl_config.protocol];
- if min_protocol then
- user_ssl_config.protocol = "sslv23";
- for i = 1, min_protocol do
- t_insert(user_ssl_config.options, "no_"..protocols[i]);
- end
+ if mode == "server" then
+ if not user_ssl_config.key then return nil, "No key present in SSL/TLS configuration for "..host; end
+ if not user_ssl_config.certificate then return nil, "No certificate present in SSL/TLS configuration for "..host; end
end
- -- We can't read the password interactively when daemonized
- user_ssl_config.password = user_ssl_config.password or
- function() log("error", "Encrypted certificate for %s requires 'ssl' 'password' to be set in config", host); end;
-
for option in pairs(path_options) do
if type(user_ssl_config[option]) == "string" then
user_ssl_config[option] = resolve_path(config_path, user_ssl_config[option]);
end
end
- -- Allow the cipher list to be a table
- if type(user_ssl_config.ciphers) == "table" then
- user_ssl_config.ciphers = t_concat(user_ssl_config.ciphers, ":")
- end
-
- if mode == "server" then
- if not user_ssl_config.key then return nil, "No key present in SSL/TLS configuration for "..host; end
- if not user_ssl_config.certificate then return nil, "No certificate present in SSL/TLS configuration for "..host; end
- end
-
-- LuaSec expects dhparam to be a callback that takes two arguments.
-- We ignore those because it is mostly used for having a separate
-- set of params for EXPORT ciphers, which we don't have by default.
diff --git a/core/hostmanager.lua b/core/hostmanager.lua
index 91b052d1..d10ecd30 100644
--- a/core/hostmanager.lua
+++ b/core/hostmanager.lua
@@ -74,7 +74,6 @@ function activate(host, host_config)
host = host;
s2sout = {};
events = events_new();
- dialback_secret = configmanager.get(host, "dialback_secret") or uuid_gen();
send = host_send;
modules = {};
};
diff --git a/core/portmanager.lua b/core/portmanager.lua
index 4cbf3eb3..bc2d4264 100644
--- a/core/portmanager.lua
+++ b/core/portmanager.lua
@@ -72,16 +72,6 @@ prosody.events.add_handler("item-removed/net-provider", function (event)
unregister_service(item.name, item);
end);
-local function duplicate_ssl_config(ssl_config)
- local ssl_config = type(ssl_config) == "table" and ssl_config or {};
-
- local _config = {};
- for k, v in pairs(ssl_config) do
- _config[k] = v;
- end
- return _config;
-end
-
--- Public API
function activate(service_name)
@@ -127,24 +117,15 @@ function activate(service_name)
local err;
-- Create SSL context for this service/port
if service_info.encryption == "ssl" then
- local ssl_config = duplicate_ssl_config((config.get("*", config_prefix.."ssl") and config.get("*", config_prefix.."ssl")[interface])
- or (config.get("*", config_prefix.."ssl") and config.get("*", config_prefix.."ssl")[port])
- or config.get("*", config_prefix.."ssl")
- or (config.get("*", "ssl") and config.get("*", "ssl")[interface])
- or (config.get("*", "ssl") and config.get("*", "ssl")[port])
- or config.get("*", "ssl"));
- -- add default entries for, or override ssl configuration
- if ssl_config and service_info.ssl_config then
- for key, value in pairs(service_info.ssl_config) do
- if not service_info.ssl_config_override and not ssl_config[key] then
- ssl_config[key] = value;
- elseif service_info.ssl_config_override then
- ssl_config[key] = value;
- end
- end
- end
-
- ssl, err = certmanager.create_context(service_info.name.." port "..port, "server", ssl_config);
+ local global_ssl_config = config.get("*", "ssl") or {};
+ local prefix_ssl_config = config.get("*", config_prefix.."ssl") or global_ssl_config;
+ ssl, err = certmanager.create_context(service_info.name.." port "..port, "server",
+ service_info.ssl_config or {},
+ prefix_ssl_config[interface],
+ prefix_ssl_config[port],
+ prefix_ssl_config,
+ global_ssl_config[interface],
+ global_ssl_config[port]);
if not ssl then
log("error", "Error binding encrypted port for %s: %s", service_info.name, error_to_friendly_message(service_name, port_number, err) or "unknown error");
end
diff --git a/plugins/adhoc/adhoc.lib.lua b/plugins/adhoc/adhoc.lib.lua
index b544ddc8..5c90c91b 100644
--- a/plugins/adhoc/adhoc.lib.lua
+++ b/plugins/adhoc/adhoc.lib.lua
@@ -25,12 +25,13 @@ function _M.new(name, node, handler, permission)
end
function _M.handle_cmd(command, origin, stanza)
- local sessionid = stanza.tags[1].attr.sessionid or uuid.generate();
+ local cmdtag = stanza.tags[1]
+ local sessionid = cmdtag.attr.sessionid or uuid.generate();
local dataIn = {};
dataIn.to = stanza.attr.to;
dataIn.from = stanza.attr.from;
- dataIn.action = stanza.tags[1].attr.action or "execute";
- dataIn.form = stanza.tags[1]:child_with_ns("jabber:x:data");
+ dataIn.action = cmdtag.attr.action or "execute";
+ dataIn.form = cmdtag:get_child("x", "jabber:x:data");
local data, state = command:handler(dataIn, states[sessionid]);
states[sessionid] = state;
diff --git a/plugins/mod_dialback.lua b/plugins/mod_dialback.lua
index 8d2bbd8f..15e24281 100644
--- a/plugins/mod_dialback.lua
+++ b/plugins/mod_dialback.lua
@@ -13,13 +13,26 @@ local log = module._log;
local st = require "util.stanza";
local sha256_hash = require "util.hashes".sha256;
local nameprep = require "util.encodings".stringprep.nameprep;
+local check_cert_status = module:depends"s2s".check_cert_status;
+local uuid_gen = require"util.uuid".generate;
local xmlns_stream = "http://etherx.jabber.org/streams";
local dialback_requests = setmetatable({}, { __mode = 'v' });
+local dialback_secret = module.host .. module:get_option_string("dialback_secret", uuid_gen());
+local dwd = module:get_option_boolean("dialback_without_dialback", false);
+
+function module.save()
+ return { dialback_secret = dialback_secret };
+end
+
+function module.restore(state)
+ dialback_secret = state.dialback_secret;
+end
+
function generate_dialback(id, to, from)
- return sha256_hash(id..to..from..hosts[from].dialback_secret, true);
+ return sha256_hash(id..to..dialback_secret, true);
end
function initiate_dialback(session)
@@ -69,6 +82,16 @@ module:hook("stanza/jabber:server:dialback:result", function(event)
local attr = stanza.attr;
local to, from = nameprep(attr.to), nameprep(attr.from);
+ if 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 });
+ return true;
+ end
+ end
+
if not hosts[to] then
-- Not a host that we serve
origin.log("warn", "%s tried to connect to %s, which we don't serve", from, to);
diff --git a/plugins/mod_lastactivity.lua b/plugins/mod_lastactivity.lua
index fabf07b4..2dd61699 100644
--- a/plugins/mod_lastactivity.lua
+++ b/plugins/mod_lastactivity.lua
@@ -19,8 +19,7 @@ module:hook("pre-presence/bare", function(event)
local stanza = event.stanza;
if not(stanza.attr.to) and stanza.attr.type == "unavailable" then
local t = os.time();
- local s = stanza:child_with_name("status");
- s = s and #s.tags == 0 and s[1] or "";
+ local s = stanza:get_child_text("status");
map[event.origin.username] = {s = s, t = t};
end
end, 10);
diff --git a/plugins/mod_legacyauth.lua b/plugins/mod_legacyauth.lua
index cb5ce0d3..54cbec24 100644
--- a/plugins/mod_legacyauth.lua
+++ b/plugins/mod_legacyauth.lua
@@ -44,9 +44,10 @@ module:hook("stanza/iq/jabber:iq:auth:query", function(event)
return true;
end
- local username = stanza.tags[1]:child_with_name("username");
- local password = stanza.tags[1]:child_with_name("password");
- local resource = stanza.tags[1]:child_with_name("resource");
+ local query = stanza.tags[1];
+ local username = query:get_child("username");
+ local password = query:get_child("password");
+ local resource = query:get_child("resource");
if not (username and password and resource) then
local reply = st.reply(stanza);
session.send(reply:query("jabber:iq:auth")
diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua
index 32a25b59..9e8f37db 100644
--- a/plugins/mod_presence.lua
+++ b/plugins/mod_presence.lua
@@ -55,14 +55,14 @@ local ignore_presence_priority = module:get_option("ignore_presence_priority");
function handle_normal_presence(origin, stanza)
if ignore_presence_priority then
- local priority = stanza:child_with_name("priority");
+ local priority = stanza:get_child("priority");
if priority and priority[1] ~= "0" then
for i=#priority.tags,1,-1 do priority.tags[i] = nil; end
for i=#priority,1,-1 do priority[i] = nil; end
priority[1] = "0";
end
end
- local priority = stanza:child_with_name("priority");
+ local priority = stanza:get_child("priority");
if priority and #priority > 0 then
priority = t_concat(priority);
if s_find(priority, "^[+-]?[0-9]+$") then
@@ -90,6 +90,7 @@ function handle_normal_presence(origin, stanza)
end
end
if stanza.attr.type == nil and not origin.presence then -- initial presence
+ module:fire_event("presence/initial", { origin = origin, stanza = stanza } );
origin.presence = stanza; -- FIXME repeated later
local probe = st.presence({from = origin.full_jid, type = "probe"});
for jid, item in pairs(roster) do -- probe all contacts we are subscribed to
@@ -137,9 +138,6 @@ function handle_normal_presence(origin, stanza)
origin.directed = nil;
end
else
- if not origin.presence then
- module:fire_event("presence/initial", { origin = origin, stanza = stanza } );
- end
origin.presence = stanza;
stanza:tag("delay", { xmlns = "urn:xmpp:delay", from = host, stamp = datetime.datetime() }):up();
if origin.priority ~= priority then
diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua
index 3de59d35..e704c25a 100644
--- a/plugins/mod_s2s/mod_s2s.lua
+++ b/plugins/mod_s2s/mod_s2s.lua
@@ -235,7 +235,7 @@ function make_authenticated(event)
end
--- Helper to check that a session peer's certificate is valid
-local function check_cert_status(session)
+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_saslauth.lua b/plugins/mod_saslauth.lua
index df60aefa..a07c5fd2 100644
--- a/plugins/mod_saslauth.lua
+++ b/plugins/mod_saslauth.lua
@@ -284,7 +284,7 @@ module:hook("iq/self/urn:ietf:params:xml:ns:xmpp-bind:bind", function(event)
local resource;
if stanza.attr.type == "set" then
local bind = stanza.tags[1];
- resource = bind:child_with_name("resource");
+ resource = bind:get_child("resource");
resource = resource and #resource.tags == 0 and resource[1] or nil;
end
local success, err_type, err, err_msg = sm_bind_resource(origin, resource);
diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua
index 7c3d79be..351aaffc 100644
--- a/plugins/mod_tls.lua
+++ b/plugins/mod_tls.lua
@@ -6,7 +6,6 @@
-- COPYING file in the source package for more information.
--
-local config = require "core.configmanager";
local create_context = require "core.certmanager".create_context;
local st = require "util.stanza";
@@ -34,23 +33,26 @@ local host = hosts[module.host];
local ssl_ctx_c2s, ssl_ctx_s2sout, ssl_ctx_s2sin;
do
- local function get_ssl_cfg(typ)
- local cfg_key = (typ and typ.."_" or "").."ssl";
- local ssl_config = config.rawget(module.host, cfg_key);
- if not ssl_config then
- local base_host = module.host:match("%.(.*)");
- ssl_config = config.get(base_host, cfg_key);
- end
- return ssl_config or typ and get_ssl_cfg();
- end
+ local NULL, err = {};
+ local global = module:context("*");
+ local parent = module:context(module.host:match("%.(.*)$"));
+
+ local parent_ssl = parent:get_option("ssl");
+ local host_ssl = module:get_option("ssl", parent_ssl);
+
+ local global_c2s = global:get_option("c2s_ssl", NULL);
+ local parent_c2s = parent:get_option("c2s_ssl", NULL);
+ local host_c2s = module:get_option("c2s_ssl", parent_c2s);
+
+ local global_s2s = global:get_option("s2s_ssl", NULL);
+ local parent_s2s = parent:get_option("s2s_ssl", NULL);
+ local host_s2s = module:get_option("s2s_ssl", parent_s2s);
- local ssl_config, err = get_ssl_cfg("c2s");
- ssl_ctx_c2s, err = create_context(host.host, "server", ssl_config); -- for incoming client connections
+ ssl_ctx_c2s, err = create_context(host.host, "server", host_c2s, host_ssl, global_c2s); -- for incoming client connections
if err then module:log("error", "Error creating context for c2s: %s", err); end
- ssl_config = get_ssl_cfg("s2s");
- ssl_ctx_s2sin, err = create_context(host.host, "server", ssl_config); -- for incoming server connections
- ssl_ctx_s2sout = create_context(host.host, "client", ssl_config); -- for outgoing server connections
+ ssl_ctx_s2sin, err = create_context(host.host, "server", host_s2s, host_ssl, global_s2s); -- for incoming server connections
+ ssl_ctx_s2sout = create_context(host.host, "client", host_s2s, host_ssl, global_s2s); -- for outgoing server connections
if err then module:log("error", "Error creating context for s2s: %s", err); end -- Both would have the same issue
end
@@ -106,7 +108,7 @@ end);
-- For s2sout connections, start TLS if we can
module:hook_stanza("http://etherx.jabber.org/streams", "features", function (session, stanza)
module:log("debug", "Received features element");
- if can_do_tls(session) and stanza:child_with_ns(xmlns_starttls) then
+ if can_do_tls(session) and stanza:get_child("starttls", xmlns_starttls) then
module:log("debug", "%s is offering TLS, taking up the offer...", session.to_host);
session.sends2s("<starttls xmlns='"..xmlns_starttls.."'/>");
return true;
diff --git a/util/sslconfig.lua b/util/sslconfig.lua
new file mode 100644
index 00000000..98e61341
--- /dev/null
+++ b/util/sslconfig.lua
@@ -0,0 +1,87 @@
+
+local handlers = { };
+local finalisers = { };
+local id = function (v) return v end
+
+function handlers.options(a, k, b)
+ local o = a[k] or { };
+ if type(b) ~= "table" then b = { b } end
+ for k,v in pairs(b) do
+ if v == true or v == false then
+ o[k] = v;
+ else
+ o[v] = true;
+ end
+ end
+ a[k] = o;
+end
+
+handlers.verify = handlers.options;
+handlers.verifyext = handlers.options;
+
+function finalisers.options(a)
+ local o = {};
+ for opt, enable in pairs(a) do
+ if enable then
+ o[#o+1] = opt;
+ end
+ end
+ return o;
+end
+
+finalisers.verify = finalisers.options;
+finalisers.verifyext = finalisers.options;
+
+function finalisers.ciphers(a)
+ if type(a) == "table" then
+ return table.concat(a, ":");
+ end
+ return a;
+end
+
+local protocols = { "sslv2", "sslv3", "tlsv1", "tlsv1_1", "tlsv1_2" };
+for i = 1, #protocols do protocols[protocols[i] .. "+"] = i - 1; end
+
+local function protocol(a)
+ local min_protocol = protocols[a.protocol];
+ if min_protocol then
+ a.protocol = "sslv23";
+ for i = 1, min_protocol do
+ table.insert(a.options, "no_"..protocols[i]);
+ end
+ end
+end
+
+local function apply(a, b)
+ if type(b) == "table" then
+ for k,v in pairs(b) do
+ (handlers[k] or rawset)(a, k, v);
+ end
+ end
+end
+
+local function final(a)
+ local f = { };
+ for k,v in pairs(a) do
+ f[k] = (finalisers[k] or id)(v);
+ end
+ protocol(f);
+ return f;
+end
+
+local sslopts_mt = {
+ __index = {
+ apply = apply;
+ final = final;
+ };
+};
+
+local function new()
+ return setmetatable({options={}}, sslopts_mt);
+end
+
+return {
+ apply = apply;
+ final = final;
+ new = new;
+};