b1bc3ae300ab04e5e86c8758a922b0731ce9a1d1
[prosody.git] / plugins / mod_dialback.lua
1 -- Prosody IM v0.4
2 -- Copyright (C) 2008-2009 Matthew Wild
3 -- Copyright (C) 2008-2009 Waqas Hussain
4 -- 
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8
9
10 local hosts = _G.hosts;
11 local send_s2s = require "core.s2smanager".send_to_host;
12 local s2s_make_authenticated = require "core.s2smanager".make_authenticated;
13 local s2s_verify_dialback = require "core.s2smanager".verify_dialback;
14 local s2s_destroy_session = require "core.s2smanager".destroy_session;
15
16 local log = module._log;
17
18 local st = require "util.stanza";
19
20 local xmlns_dialback = "jabber:server:dialback";
21
22 local dialback_requests = setmetatable({}, { __mode = 'v' });
23
24 module:add_handler({"s2sin_unauthed", "s2sin"}, "verify", xmlns_dialback,
25         function (origin, stanza)
26                 -- We are being asked to verify the key, to ensure it was generated by us
27                 origin.log("debug", "verifying that dialback key is ours...");
28                 local attr = stanza.attr;
29                 -- FIXME: Grr, ejabberd breaks this one too?? it is black and white in XEP-220 example 34
30                 --if attr.from ~= origin.to_host then error("invalid-from"); end
31                 local type;
32                 if s2s_verify_dialback(attr.id, attr.from, attr.to, stanza[1]) then
33                         type = "valid"
34                 else
35                         type = "invalid"
36                         origin.log("warn", "Asked to verify a dialback key that was incorrect. An imposter is claiming to be %s?", attr.to);
37                 end
38                 origin.log("debug", "verified dialback key... it is %s", type);
39                 origin.sends2s(st.stanza("db:verify", { from = attr.to, to = attr.from, id = attr.id, type = type }):text(stanza[1]));
40         end);
41
42 module:add_handler({ "s2sin_unauthed", "s2sin" }, "result", xmlns_dialback,
43         function (origin, stanza)
44                 -- he wants to be identified through dialback
45                 -- We need to check the key with the Authoritative server
46                 local attr = stanza.attr;
47                 origin.hosts[attr.from] = { dialback_key = stanza[1] };
48                 
49                 if not hosts[attr.to] then
50                         -- Not a host that we serve
51                         origin.log("info", "%s tried to connect to %s, which we don't serve", attr.from, attr.to);
52                         origin:close("host-unknown");
53                         return;
54                 end
55                 
56                 dialback_requests[attr.from] = origin;
57                 
58                 if not origin.from_host then
59                         -- Just used for friendlier logging
60                         origin.from_host = attr.from;
61                 end
62                 if not origin.to_host then
63                         -- Just used for friendlier logging
64                         origin.to_host = attr.to;
65                 end
66                 
67                 origin.log("debug", "asking %s if key %s belongs to them", attr.from, stanza[1]);
68                 send_s2s(attr.to, attr.from,
69                         st.stanza("db:verify", { from = attr.to, to = attr.from, id = origin.streamid }):text(stanza[1]));
70         end);
71
72 module:add_handler({ "s2sout_unauthed", "s2sout" }, "verify", xmlns_dialback,
73         function (origin, stanza)
74                 local attr = stanza.attr;
75                 local dialback_verifying = dialback_requests[attr.from];
76                 if dialback_verifying then
77                         local valid;
78                         if attr.type == "valid" then
79                                 s2s_make_authenticated(dialback_verifying, attr.from);
80                                 valid = "valid";
81                         else
82                                 -- Warn the original connection that is was not verified successfully
83                                 log("warn", "authoritative server for "..(attr.from or "(unknown)").." denied the key");
84                                 valid = "invalid";
85                         end
86                         if not dialback_verifying.sends2s then
87                                 log("warn", "Incoming s2s session %s was closed in the meantime, so we can't notify it of the db result", tostring(dialback_verifying):match("%w+$"));
88                         else
89                                 dialback_verifying.sends2s(
90                                                 st.stanza("db:result", { from = attr.to, to = attr.from, id = attr.id, type = valid })
91                                                                 :text(dialback_verifying.hosts[attr.from].dialback_key));
92                         end
93                         dialback_requests[attr.from] = nil;
94                 end
95         end);
96
97 module:add_handler({ "s2sout_unauthed", "s2sout" }, "result", xmlns_dialback,
98         function (origin, stanza)
99                 -- Remote server is telling us whether we passed dialback
100                 
101                 local attr = stanza.attr;
102                 if not hosts[attr.to] then
103                         origin:close("host-unknown");
104                         return;
105                 elseif hosts[attr.to].s2sout[attr.from] ~= origin then
106                         -- This isn't right
107                         origin:close("invalid-id");
108                         return;
109                 end
110                 if stanza.attr.type == "valid" then
111                         s2s_make_authenticated(origin, attr.from);
112                 else
113                         s2s_destroy_session(origin)
114                 end
115         end);