Comparison

plugins/mod_s2s/mod_s2s.lua @ 5364:61cf6b84ae81

Merge 0.9->trunk
author Matthew Wild <mwild1@gmail.com>
date Fri, 22 Mar 2013 14:22:46 +0000
parent 5363:f29c26da7ecc
child 5365:cd480ea490f1
comparison
equal deleted inserted replaced
5356:97197ca60cb2 5364:61cf6b84ae81
22 local nameprep = require "util.encodings".stringprep.nameprep; 22 local nameprep = require "util.encodings".stringprep.nameprep;
23 local new_xmpp_stream = require "util.xmppstream".new; 23 local new_xmpp_stream = require "util.xmppstream".new;
24 local s2s_new_incoming = require "core.s2smanager".new_incoming; 24 local s2s_new_incoming = require "core.s2smanager".new_incoming;
25 local s2s_new_outgoing = require "core.s2smanager".new_outgoing; 25 local s2s_new_outgoing = require "core.s2smanager".new_outgoing;
26 local s2s_destroy_session = require "core.s2smanager".destroy_session; 26 local s2s_destroy_session = require "core.s2smanager".destroy_session;
27 local s2s_mark_connected = require "core.s2smanager".mark_connected;
28 local uuid_gen = require "util.uuid".generate; 27 local uuid_gen = require "util.uuid".generate;
29 local cert_verify_identity = require "util.x509".verify_identity; 28 local cert_verify_identity = require "util.x509".verify_identity;
29 local fire_global_event = prosody.events.fire_event;
30 30
31 local s2sout = module:require("s2sout"); 31 local s2sout = module:require("s2sout");
32 32
33 local connect_timeout = module:get_option_number("s2s_timeout", 90); 33 local connect_timeout = module:get_option_number("s2s_timeout", 90);
34 local stream_close_timeout = module:get_option_number("s2s_close_timeout", 5); 34 local stream_close_timeout = module:get_option_number("s2s_close_timeout", 5);
35
36 local secure_auth = module:get_option_boolean("s2s_secure_auth", false); -- One day...
37 local secure_domains, insecure_domains =
38 module:get_option_set("s2s_secure_domains", {})._items, module:get_option_set("s2s_insecure_domains", {})._items;
39 local require_encryption = module:get_option_boolean("s2s_require_encryption", secure_auth);
35 40
36 local sessions = module:shared("sessions"); 41 local sessions = module:shared("sessions");
37 42
38 local log = module._log; 43 local log = module._log;
39 44
130 module:log("warn", "The 'disallow_s2s' config option is deprecated, please see http://prosody.im/doc/s2s#disabling"); 135 module:log("warn", "The 'disallow_s2s' config option is deprecated, please see http://prosody.im/doc/s2s#disabling");
131 return nil, "This host has disallow_s2s set"; 136 return nil, "This host has disallow_s2s set";
132 end 137 end
133 module:hook("route/remote", route_to_existing_session, 200); 138 module:hook("route/remote", route_to_existing_session, 200);
134 module:hook("route/remote", route_to_new_session, 100); 139 module:hook("route/remote", route_to_new_session, 100);
140 module:hook("s2s-authenticated", make_authenticated, -1);
141 end
142
143 -- Stream is authorised, and ready for normal stanzas
144 function mark_connected(session)
145 local sendq, send = session.sendq, session.sends2s;
146
147 local from, to = session.from_host, session.to_host;
148
149 session.log("info", "%s s2s connection %s->%s complete", session.direction, from, to);
150
151 local event_data = { session = session };
152 if session.type == "s2sout" then
153 fire_global_event("s2sout-established", event_data);
154 hosts[from].events.fire_event("s2sout-established", event_data);
155 else
156 local host_session = hosts[to];
157 session.send = function(stanza)
158 return host_session.events.fire_event("route/remote", { from_host = to, to_host = from, stanza = stanza });
159 end;
160
161 fire_global_event("s2sin-established", event_data);
162 hosts[to].events.fire_event("s2sin-established", event_data);
163 end
164
165 if session.direction == "outgoing" then
166 if sendq then
167 session.log("debug", "sending %d queued stanzas across new outgoing connection to %s", #sendq, session.to_host);
168 for i, data in ipairs(sendq) do
169 send(data[1]);
170 sendq[i] = nil;
171 end
172 session.sendq = nil;
173 end
174
175 session.ip_hosts = nil;
176 session.srv_hosts = nil;
177 end
178 end
179
180 function make_authenticated(event)
181 local session, host = event.session, event.host;
182 if not session.secure then
183 if require_encryption or secure_auth or secure_domains[host] then
184 session:close({
185 condition = "policy-violation",
186 text = "Encrypted server-to-server communication is required but was not "
187 ..((session.direction == "outgoing" and "offered") or "used")
188 });
189 end
190 end
191 if session.type == "s2sout_unauthed" then
192 session.type = "s2sout";
193 elseif session.type == "s2sin_unauthed" then
194 session.type = "s2sin";
195 if host then
196 if not session.hosts[host] then session.hosts[host] = {}; end
197 session.hosts[host].authed = true;
198 end
199 elseif session.type == "s2sin" and host then
200 if not session.hosts[host] then session.hosts[host] = {}; end
201 session.hosts[host].authed = true;
202 else
203 return false;
204 end
205 session.log("debug", "connection %s->%s is now authenticated for %s", session.from_host, session.to_host, host);
206
207 mark_connected(session);
208
209 return true;
135 end 210 end
136 211
137 --- Helper to check that a session peer's certificate is valid 212 --- Helper to check that a session peer's certificate is valid
138 local function check_cert_status(session) 213 local function check_cert_status(session)
139 local host = session.direction == "incoming" and session.from_host or session.to_host 214 local host = session.direction == "incoming" and session.from_host or session.to_host
165 session.cert_identity_status = "invalid" 240 session.cert_identity_status = "invalid"
166 end 241 end
167 end 242 end
168 end 243 end
169 end 244 end
170 module:fire_event("s2s-check-certificate", { host = host, session = session, cert = cert }); 245 return module:fire_event("s2s-check-certificate", { host = host, session = session, cert = cert });
171 end 246 end
172 247
173 --- XMPP stream event handlers 248 --- XMPP stream event handlers
174 249
175 local stream_callbacks = { default_ns = "jabber:server", handlestanza = core_process_stanza }; 250 local stream_callbacks = { default_ns = "jabber:server", handlestanza = core_process_stanza };
244 }); 319 });
245 return; 320 return;
246 end 321 end
247 end 322 end
248 323
249 if session.secure and not session.cert_chain_status then check_cert_status(session); end 324 if session.secure and not session.cert_chain_status then
325 if check_cert_status(session) == false then
326 return;
327 end
328 end
250 329
251 session:open_stream() 330 session:open_stream()
252 if session.version >= 1.0 then 331 if session.version >= 1.0 then
253 local features = st.stanza("stream:features"); 332 local features = st.stanza("stream:features");
254 333
264 elseif session.direction == "outgoing" then 343 elseif session.direction == "outgoing" then
265 -- If we are just using the connection for verifying dialback keys, we won't try and auth it 344 -- If we are just using the connection for verifying dialback keys, we won't try and auth it
266 if not attr.id then error("stream response did not give us a streamid!!!"); end 345 if not attr.id then error("stream response did not give us a streamid!!!"); end
267 session.streamid = attr.id; 346 session.streamid = attr.id;
268 347
269 if session.secure and not session.cert_chain_status then check_cert_status(session); end 348 if session.secure and not session.cert_chain_status then
349 if check_cert_status(session) == false then
350 return;
351 end
352 end
270 353
271 -- Send unauthed buffer 354 -- Send unauthed buffer
272 -- (stanzas which are fine to send before dialback) 355 -- (stanzas which are fine to send before dialback)
273 -- Note that this is *not* the stanza queue (which 356 -- Note that this is *not* the stanza queue (which
274 -- we can only send if auth succeeds) :) 357 -- we can only send if auth succeeds) :)
285 -- If server is pre-1.0, don't wait for features, just do dialback 368 -- If server is pre-1.0, don't wait for features, just do dialback
286 if session.version < 1.0 then 369 if session.version < 1.0 then
287 if not session.dialback_verifying then 370 if not session.dialback_verifying then
288 hosts[session.from_host].events.fire_event("s2sout-authenticate-legacy", { origin = session }); 371 hosts[session.from_host].events.fire_event("s2sout-authenticate-legacy", { origin = session });
289 else 372 else
290 s2s_mark_connected(session); 373 mark_connected(session);
291 end 374 end
292 end 375 end
293 end 376 end
294 session.notopen = nil; 377 session.notopen = nil;
295 end 378 end
524 session.direction = "outgoing"; 607 session.direction = "outgoing";
525 sessions[conn] = session; 608 sessions[conn] = session;
526 initialize_session(session); 609 initialize_session(session);
527 end 610 end
528 611
612 function check_auth_policy(event)
613 local host, session = event.host, event.session;
614
615 if not secure_auth and secure_domains[host] then
616 secure_auth = true;
617 elseif secure_auth and insecure_domains[host] then
618 secure_auth = false;
619 end
620
621 if secure_auth and not session.cert_identity_status then
622 module:log("warn", "Forbidding insecure connection to/from %s", host);
623 session:close(false);
624 return false;
625 end
626 end
627
628 module:hook("s2s-check-certificate", check_auth_policy, -1);
629
529 s2sout.set_listener(listener); 630 s2sout.set_listener(listener);
530 631
531 module:hook("server-stopping", function(event) 632 module:hook("server-stopping", function(event)
532 local reason = event.reason; 633 local reason = event.reason;
533 for _, session in pairs(sessions) do 634 for _, session in pairs(sessions) do