Changeset

5364:61cf6b84ae81

Merge 0.9->trunk
author Matthew Wild <mwild1@gmail.com>
date Fri, 22 Mar 2013 14:22:46 +0000
parents 5356:97197ca60cb2 (current diff) 5363:f29c26da7ecc (diff)
children 5369:a344c1120e2b
files
diffstat 8 files changed, 156 insertions(+), 141 deletions(-) [+]
line wrap: on
line diff
--- a/core/configmanager.lua	Wed Mar 20 20:35:59 2013 +0000
+++ b/core/configmanager.lua	Fri Mar 22 14:22:46 2013 +0000
@@ -22,62 +22,48 @@
 local parsers = {};
 
 local config_mt = { __index = function (t, k) return rawget(t, "*"); end};
-local config = setmetatable({ ["*"] = { core = {} } }, config_mt);
+local config = setmetatable({ ["*"] = { } }, config_mt);
 
 -- When host not found, use global
 local host_mt = { };
 
--- When key not found in section, check key in global's section
-function section_mt(section_name)
-	return { __index = 	function (t, k)
-					local section = rawget(config["*"], section_name);
-					if not section then return nil; end
-					return section[k];
-				end
-	};
-end
-
 function getconfig()
 	return config;
 end
 
-function get(host, section, key)
-	if not key then
-		section, key = "core", section;
+function get(host, key, _oldkey)
+	if key == "core" then
+		key = _oldkey; -- COMPAT with code that still uses "core"
 	end
-	local sec = config[host][section];
-	if sec then
-		return sec[key];
+	return config[host][key];
+end
+function _M.rawget(host, key, _oldkey)
+	if key == "core" then
+		key = _oldkey; -- COMPAT with code that still uses "core"
 	end
-	return nil;
-end
-function _M.rawget(host, section, key)
 	local hostconfig = rawget(config, host);
 	if hostconfig then
-		local sectionconfig = rawget(hostconfig, section);
-		if sectionconfig then
-			return rawget(sectionconfig, key);
-		end
+		return rawget(hostconfig, key);
 	end
 end
 
-local function set(config, host, section, key, value)
-	if host and section and key then
+local function set(config, host, key, value)
+	if host and key then
 		local hostconfig = rawget(config, host);
 		if not hostconfig then
 			hostconfig = rawset(config, host, setmetatable({}, host_mt))[host];
 		end
-		if not rawget(hostconfig, section) then
-			hostconfig[section] = setmetatable({}, section_mt(section));
-		end
-		hostconfig[section][key] = value;
+		hostconfig[key] = value;
 		return true;
 	end
 	return false;
 end
 
-function _M.set(host, section, key, value)
-	return set(config, host, section, key, value);
+function _M.set(host, key, value, _oldvalue)
+	if key == "core" then
+		key, value = value, _oldvalue; --COMPAT with code that still uses "core"
+	end
+	return set(config, host, key, value);
 end
 
 -- Helper function to resolve relative paths (needed by config)
@@ -122,7 +108,7 @@
 	if parsers[format] and parsers[format].load then
 		local f, err = io.open(filename);
 		if f then
-			local new_config = setmetatable({ ["*"] = { core = {} } }, config_mt);
+			local new_config = setmetatable({ ["*"] = { } }, config_mt);
 			local ok, err = parsers[format].load(f:read("*a"), filename, new_config);
 			f:close();
 			if ok then
@@ -176,53 +162,50 @@
 			Component = true, component = true,
 			Include = true, include = true, RunScript = true }, {
 				__index = function (t, k)
-					return rawget(_G, k) or
-						function (settings_table)
-							config[__currenthost or "*"][k] = settings_table;
-						end;
+					return rawget(_G, k);
 				end,
 				__newindex = function (t, k, v)
-					set(config, env.__currenthost or "*", "core", k, v);
+					set(config, env.__currenthost or "*", k, v);
 				end
 		});
 		
 		rawset(env, "__currenthost", "*") -- Default is global
 		function env.VirtualHost(name)
-			if rawget(config, name) and rawget(config[name].core, "component_module") then
+			if rawget(config, name) and rawget(config[name], "component_module") then
 				error(format("Host %q clashes with previously defined %s Component %q, for services use a sub-domain like conference.%s",
-					name, config[name].core.component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0);
+					name, config[name].component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0);
 			end
 			rawset(env, "__currenthost", name);
 			-- Needs at least one setting to logically exist :)
-			set(config, name or "*", "core", "defined", true);
+			set(config, name or "*", "defined", true);
 			return function (config_options)
 				rawset(env, "__currenthost", "*"); -- Return to global scope
 				for option_name, option_value in pairs(config_options) do
-					set(config, name or "*", "core", option_name, option_value);
+					set(config, name or "*", option_name, option_value);
 				end
 			end;
 		end
 		env.Host, env.host = env.VirtualHost, env.VirtualHost;
 		
 		function env.Component(name)
-			if rawget(config, name) and rawget(config[name].core, "defined") and not rawget(config[name].core, "component_module") then
+			if rawget(config, name) and rawget(config[name], "defined") and not rawget(config[name], "component_module") then
 				error(format("Component %q clashes with previously defined Host %q, for services use a sub-domain like conference.%s",
 					name, name, name), 0);
 			end
-			set(config, name, "core", "component_module", "component");
+			set(config, name, "component_module", "component");
 			-- Don't load the global modules by default
-			set(config, name, "core", "load_global_modules", false);
+			set(config, name, "load_global_modules", false);
 			rawset(env, "__currenthost", name);
 			local function handle_config_options(config_options)
 				rawset(env, "__currenthost", "*"); -- Return to global scope
 				for option_name, option_value in pairs(config_options) do
-					set(config, name or "*", "core", option_name, option_value);
+					set(config, name or "*", option_name, option_value);
 				end
 			end
 	
 			return function (module)
 					if type(module) == "string" then
-						set(config, name, "core", "component_module", module);
+						set(config, name, "component_module", module);
 						return handle_config_options;
 					end
 					return handle_config_options(module);
--- a/core/hostmanager.lua	Wed Mar 20 20:35:59 2013 +0000
+++ b/core/hostmanager.lua	Fri Mar 22 14:22:46 2013 +0000
@@ -17,7 +17,7 @@
 
 local log = require "util.logger".init("hostmanager");
 
-local hosts = hosts;
+local hosts = prosody.hosts;
 local prosody_events = prosody.events;
 if not _G.prosody.incoming_s2s then
 	require "core.s2smanager";
@@ -25,7 +25,7 @@
 local incoming_s2s = _G.prosody.incoming_s2s;
 local core_route_stanza = _G.prosody.core_route_stanza;
 
-local pairs, select = pairs, select;
+local pairs, select, rawget = pairs, select, rawget;
 local tostring, type = tostring, type;
 
 module "hostmanager"
@@ -37,8 +37,8 @@
 	local activated_any_host;
 	
 	for host, host_config in pairs(defined_hosts) do
-		if host ~= "*" and host_config.core.enabled ~= false then
-			if not host_config.core.component_module then
+		if host ~= "*" and host_config.enabled ~= false then
+			if not host_config.component_module then
 				activated_any_host = true;
 			end
 			activate(host, host_config);
@@ -67,7 +67,7 @@
 end
 
 function activate(host, host_config)
-	if hosts[host] then return nil, "The host "..host.." is already activated"; end
+	if rawget(hosts, host) then return nil, "The host "..host.." is already activated"; end
 	host_config = host_config or configmanager.getconfig()[host];
 	if not host_config then return nil, "Couldn't find the host "..tostring(host).." defined in the current config"; end
 	local host_session = {
@@ -78,7 +78,7 @@
 		send = host_send;
 		modules = {};
 	};
-	if not host_config.core.component_module then -- host
+	if not host_config.component_module then -- host
 		host_session.type = "local";
 		host_session.sessions = {};
 	else -- component
@@ -86,9 +86,9 @@
 	end
 	hosts[host] = host_session;
 	if not host:match("[@/]") then
-		disco_items:set(host:match("%.(.*)") or "*", host, host_config.core.name or true);
+		disco_items:set(host:match("%.(.*)") or "*", host, host_config.name or true);
 	end
-	for option_name in pairs(host_config.core) do
+	for option_name in pairs(host_config) do
 		if option_name:match("_ports$") or option_name:match("_interface$") then
 			log("warn", "%s: Option '%s' has no effect for virtual hosts - put it in the server-wide section instead", host, option_name);
 		end
--- a/core/s2smanager.lua	Wed Mar 20 20:35:59 2013 +0000
+++ b/core/s2smanager.lua	Fri Mar 22 14:22:46 2013 +0000
@@ -9,15 +9,13 @@
 
 
 local hosts = hosts;
-local tostring, pairs, ipairs, getmetatable, newproxy, setmetatable
-    = tostring, pairs, ipairs, getmetatable, newproxy, setmetatable;
+local tostring, pairs, getmetatable, newproxy, setmetatable
+    = tostring, pairs, getmetatable, newproxy, setmetatable;
 
 local logger_init = require "util.logger".init;
 
 local log = logger_init("s2smanager");
 
-local config = require "core.configmanager";
-
 local prosody = _G.prosody;
 incoming_s2s = {};
 prosody.incoming_s2s = incoming_s2s;
@@ -49,75 +47,6 @@
 	return host_session;
 end
 
-function make_authenticated(session, host)
-	if not session.secure then
-		local local_host = session.direction == "incoming" and session.to_host or session.from_host;
-		if config.get(local_host, "core", "s2s_require_encryption") then
-			session:close({
-				condition = "policy-violation",
-				text = "Encrypted server-to-server communication is required but was not "
-				       ..((session.direction == "outgoing" and "offered") or "used")
-			});
-		end
-	end
-	if session.type == "s2sout_unauthed" then
-		session.type = "s2sout";
-	elseif session.type == "s2sin_unauthed" then
-		session.type = "s2sin";
-		if host then
-			if not session.hosts[host] then session.hosts[host] = {}; end
-			session.hosts[host].authed = true;
-		end
-	elseif session.type == "s2sin" and host then
-		if not session.hosts[host] then session.hosts[host] = {}; end
-		session.hosts[host].authed = true;
-	else
-		return false;
-	end
-	session.log("debug", "connection %s->%s is now authenticated for %s", session.from_host, session.to_host, host);
-	
-	mark_connected(session);
-	
-	return true;
-end
-
--- Stream is authorised, and ready for normal stanzas
-function mark_connected(session)
-	local sendq, send = session.sendq, session.sends2s;
-	
-	local from, to = session.from_host, session.to_host;
-	
-	session.log("info", "%s s2s connection %s->%s complete", session.direction, from, to);
-
-	local event_data = { session = session };
-	if session.type == "s2sout" then
-		fire_event("s2sout-established", event_data);
-		hosts[from].events.fire_event("s2sout-established", event_data);
-	else
-		local host_session = hosts[to];
-		session.send = function(stanza)
-			return host_session.events.fire_event("route/remote", { from_host = to, to_host = from, stanza = stanza });
-		end;
-
-		fire_event("s2sin-established", event_data);
-		hosts[to].events.fire_event("s2sin-established", event_data);
-	end
-	
-	if session.direction == "outgoing" then
-		if sendq then
-			session.log("debug", "sending %d queued stanzas across new outgoing connection to %s", #sendq, session.to_host);
-			for i, data in ipairs(sendq) do
-				send(data[1]);
-				sendq[i] = nil;
-			end
-			session.sendq = nil;
-		end
-		
-		session.ip_hosts = nil;
-		session.srv_hosts = nil;
-	end
-end
-
 local resting_session = { -- Resting, not dead
 		destroyed = true;
 		type = "s2s_destroyed";
--- a/plugins/mod_dialback.lua	Wed Mar 20 20:35:59 2013 +0000
+++ b/plugins/mod_dialback.lua	Fri Mar 22 14:22:46 2013 +0000
@@ -7,7 +7,6 @@
 --
 
 local hosts = _G.hosts;
-local s2s_make_authenticated = require "core.s2smanager".make_authenticated;
 
 local log = module._log;
 
@@ -110,7 +109,7 @@
 		if dialback_verifying and attr.from == origin.to_host then
 			local valid;
 			if attr.type == "valid" then
-				s2s_make_authenticated(dialback_verifying, attr.from);
+				module:fire_event("s2s-authenticated", { session = dialback_verifying, host = attr.from });
 				valid = "valid";
 			else
 				-- Warn the original connection that is was not verified successfully
@@ -146,7 +145,7 @@
 			return true;
 		end
 		if stanza.attr.type == "valid" then
-			s2s_make_authenticated(origin, attr.from);
+			module:fire_event("s2s-authenticated", { session = origin, host = attr.from });
 		else
 			origin:close("not-authorized", "dialback authentication failed");
 		end
--- a/plugins/mod_s2s/mod_s2s.lua	Wed Mar 20 20:35:59 2013 +0000
+++ b/plugins/mod_s2s/mod_s2s.lua	Fri Mar 22 14:22:46 2013 +0000
@@ -24,15 +24,20 @@
 local s2s_new_incoming = require "core.s2smanager".new_incoming;
 local s2s_new_outgoing = require "core.s2smanager".new_outgoing;
 local s2s_destroy_session = require "core.s2smanager".destroy_session;
-local s2s_mark_connected = require "core.s2smanager".mark_connected;
 local uuid_gen = require "util.uuid".generate;
 local cert_verify_identity = require "util.x509".verify_identity;
+local fire_global_event = prosody.events.fire_event;
 
 local s2sout = module:require("s2sout");
 
 local connect_timeout = module:get_option_number("s2s_timeout", 90);
 local stream_close_timeout = module:get_option_number("s2s_close_timeout", 5);
 
+local secure_auth = module:get_option_boolean("s2s_secure_auth", false); -- One day...
+local secure_domains, insecure_domains =
+	module:get_option_set("s2s_secure_domains", {})._items, module:get_option_set("s2s_insecure_domains", {})._items;
+local require_encryption = module:get_option_boolean("s2s_require_encryption", secure_auth);
+
 local sessions = module:shared("sessions");
 
 local log = module._log;
@@ -132,6 +137,76 @@
 	end
 	module:hook("route/remote", route_to_existing_session, 200);
 	module:hook("route/remote", route_to_new_session, 100);
+	module:hook("s2s-authenticated", make_authenticated, -1);
+end
+
+-- Stream is authorised, and ready for normal stanzas
+function mark_connected(session)
+	local sendq, send = session.sendq, session.sends2s;
+	
+	local from, to = session.from_host, session.to_host;
+	
+	session.log("info", "%s s2s connection %s->%s complete", session.direction, from, to);
+
+	local event_data = { session = session };
+	if session.type == "s2sout" then
+		fire_global_event("s2sout-established", event_data);
+		hosts[from].events.fire_event("s2sout-established", event_data);
+	else
+		local host_session = hosts[to];
+		session.send = function(stanza)
+			return host_session.events.fire_event("route/remote", { from_host = to, to_host = from, stanza = stanza });
+		end;
+
+		fire_global_event("s2sin-established", event_data);
+		hosts[to].events.fire_event("s2sin-established", event_data);
+	end
+	
+	if session.direction == "outgoing" then
+		if sendq then
+			session.log("debug", "sending %d queued stanzas across new outgoing connection to %s", #sendq, session.to_host);
+			for i, data in ipairs(sendq) do
+				send(data[1]);
+				sendq[i] = nil;
+			end
+			session.sendq = nil;
+		end
+		
+		session.ip_hosts = nil;
+		session.srv_hosts = nil;
+	end
+end
+
+function make_authenticated(event)
+	local session, host = event.session, event.host;
+	if not session.secure then
+		if require_encryption or secure_auth or secure_domains[host] then
+			session:close({
+				condition = "policy-violation",
+				text = "Encrypted server-to-server communication is required but was not "
+				       ..((session.direction == "outgoing" and "offered") or "used")
+			});
+		end
+	end
+	if session.type == "s2sout_unauthed" then
+		session.type = "s2sout";
+	elseif session.type == "s2sin_unauthed" then
+		session.type = "s2sin";
+		if host then
+			if not session.hosts[host] then session.hosts[host] = {}; end
+			session.hosts[host].authed = true;
+		end
+	elseif session.type == "s2sin" and host then
+		if not session.hosts[host] then session.hosts[host] = {}; end
+		session.hosts[host].authed = true;
+	else
+		return false;
+	end
+	session.log("debug", "connection %s->%s is now authenticated for %s", session.from_host, session.to_host, host);
+	
+	mark_connected(session);
+	
+	return true;
 end
 
 --- Helper to check that a session peer's certificate is valid
@@ -167,7 +242,7 @@
 			end
 		end
 	end
-	module:fire_event("s2s-check-certificate", { host = host, session = session, cert = cert });
+	return module:fire_event("s2s-check-certificate", { host = host, session = session, cert = cert });
 end
 
 --- XMPP stream event handlers
@@ -246,7 +321,11 @@
 			end
 		end
 
-		if session.secure and not session.cert_chain_status then check_cert_status(session); end
+		if session.secure and not session.cert_chain_status then
+			if check_cert_status(session) == false then
+				return;
+			end
+		end
 
 		session:open_stream()
 		if session.version >= 1.0 then
@@ -266,7 +345,11 @@
 		if not attr.id then error("stream response did not give us a streamid!!!"); end
 		session.streamid = attr.id;
 
-		if session.secure and not session.cert_chain_status then check_cert_status(session); end
+		if session.secure and not session.cert_chain_status then
+			if check_cert_status(session) == false then
+				return;
+			end
+		end
 
 		-- Send unauthed buffer
 		-- (stanzas which are fine to send before dialback)
@@ -287,7 +370,7 @@
 			if not session.dialback_verifying then
 				hosts[session.from_host].events.fire_event("s2sout-authenticate-legacy", { origin = session });
 			else
-				s2s_mark_connected(session);
+				mark_connected(session);
 			end
 		end
 	end
@@ -526,6 +609,24 @@
 	initialize_session(session);
 end
 
+function check_auth_policy(event)
+	local host, session = event.host, event.session;
+	
+	if not secure_auth and secure_domains[host] then
+		secure_auth = true;
+	elseif secure_auth and insecure_domains[host] then
+		secure_auth = false;
+	end
+	
+	if secure_auth and not session.cert_identity_status then
+		module:log("warn", "Forbidding insecure connection to/from %s", host);
+		session:close(false);
+		return false;
+	end
+end
+
+module:hook("s2s-check-certificate", check_auth_policy, -1);
+
 s2sout.set_listener(listener);
 
 module:hook("server-stopping", function(event)
--- a/plugins/mod_saslauth.lua	Wed Mar 20 20:35:59 2013 +0000
+++ b/plugins/mod_saslauth.lua	Fri Mar 22 14:22:46 2013 +0000
@@ -11,7 +11,6 @@
 local st = require "util.stanza";
 local sm_bind_resource = require "core.sessionmanager".bind_resource;
 local sm_make_authenticated = require "core.sessionmanager".make_authenticated;
-local s2s_make_authenticated = require "core.s2smanager".make_authenticated;
 local base64 = require "util.encodings".base64;
 
 local cert_verify_identity = require "util.x509".verify_identity;
@@ -90,7 +89,7 @@
 	session:reset_stream();
 	session:open_stream();
 
-	s2s_make_authenticated(session, session.to_host);
+	module:fire_event("s2s-authenticated", { session = session, host = session.to_host });
 	return true;
 end)
 
@@ -187,7 +186,7 @@
 
 	local domain = text ~= "" and text or session.from_host;
 	module:log("info", "Accepting SASL EXTERNAL identity from %s", domain);
-	s2s_make_authenticated(session, domain);
+	module:fire_event("s2s-authenticated", { session = session, host = domain });
 	session:reset_stream();
 	return true
 end
--- a/prosody	Wed Mar 20 20:35:59 2013 +0000
+++ b/prosody	Fri Mar 22 14:22:46 2013 +0000
@@ -132,8 +132,8 @@
 function sanity_check()
 	for host, host_config in pairs(config.getconfig()) do
 		if host ~= "*"
-		and host_config.core.enabled ~= false
-		and not host_config.core.component_module then
+		and host_config.enabled ~= false
+		and not host_config.component_module then
 			return;
 		end
 	end
@@ -198,6 +198,7 @@
 end
 
 function init_global_state()
+	-- COMPAT: These globals are deprecated
 	bare_sessions = {};
 	full_sessions = {};
 	hosts = {};
--- a/util-src/pposix.c	Wed Mar 20 20:35:59 2013 +0000
+++ b/util-src/pposix.c	Fri Mar 22 14:22:46 2013 +0000
@@ -484,6 +484,9 @@
 	if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
 	if (!strcmp(s, "RSS")) return RLIMIT_RSS;
 #endif
+#ifdef RLIMIT_NICE
+	if (!strcmp(s, "NICE")) return RLIMIT_NICE;
+#endif
 	return -1;
 }