Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/processone/ejabberd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>2016-01-11 14:22:17 +0300
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>2016-01-11 14:22:17 +0300
commitc7931b4a4f35022325feaa58bb555bb688c90bd2 (patch)
treec4b29992a96a6861bb3ff42841a8352060d25567 /src
parent15245e9ec42989ea8689080993add3b9d661c076 (diff)
CVE-2016-1232: Add Dialback Key Generation and Validation support (XEP-0185)
Diffstat (limited to 'src')
-rw-r--r--src/ejabberd_s2s.erl61
-rw-r--r--src/ejabberd_s2s_in.erl6
-rw-r--r--src/ejabberd_s2s_out.erl32
3 files changed, 44 insertions, 55 deletions
diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl
index 0e51ec044..24694f3f0 100644
--- a/src/ejabberd_s2s.erl
+++ b/src/ejabberd_s2s.erl
@@ -35,8 +35,8 @@
%% API
-export([start_link/0, route/3, have_connection/1,
- has_key/2, get_connections_pids/1, try_register/1,
- remove_connection/3, find_connection/2,
+ make_key/2, get_connections_pids/1, try_register/1,
+ remove_connection/2, find_connection/2,
dirty_get_connections/0, allow_host/2,
incoming_s2s_number/0, outgoing_s2s_number/0,
clean_temporarily_blocked_table/0,
@@ -75,8 +75,7 @@
%% once a server is temporarly blocked, it stay blocked for 60 seconds
-record(s2s, {fromto = {<<"">>, <<"">>} :: {binary(), binary()} | '_',
- pid = self() :: pid() | '_' | '$1',
- key = <<"">> :: binary() | '_'}).
+ pid = self() :: pid() | '_' | '$1'}).
-record(state, {}).
@@ -134,19 +133,15 @@ is_temporarly_blocked(Host) ->
end.
-spec remove_connection({binary(), binary()},
- pid(), binary()) -> {atomic, ok} |
- ok |
- {aborted, any()}.
+ pid()) -> {atomic, ok} | ok | {aborted, any()}.
-remove_connection(FromTo, Pid, Key) ->
+remove_connection(FromTo, Pid) ->
case catch mnesia:dirty_match_object(s2s,
- #s2s{fromto = FromTo, pid = Pid,
- _ = '_'})
+ #s2s{fromto = FromTo, pid = Pid})
of
- [#s2s{pid = Pid, key = Key}] ->
+ [#s2s{pid = Pid}] ->
F = fun () ->
- mnesia:delete_object(#s2s{fromto = FromTo, pid = Pid,
- key = Key})
+ mnesia:delete_object(#s2s{fromto = FromTo, pid = Pid})
end,
mnesia:transaction(F);
_ -> ok
@@ -162,19 +157,6 @@ have_connection(FromTo) ->
false
end.
--spec has_key({binary(), binary()}, binary()) -> boolean().
-
-has_key(FromTo, Key) ->
- case mnesia:dirty_select(s2s,
- [{#s2s{fromto = FromTo, key = Key, _ = '_'},
- [],
- ['$_']}]) of
- [] ->
- false;
- _ ->
- true
- end.
-
-spec get_connections_pids({binary(), binary()}) -> [pid()].
get_connections_pids(FromTo) ->
@@ -185,10 +167,9 @@ get_connections_pids(FromTo) ->
[]
end.
--spec try_register({binary(), binary()}) -> {key, binary()} | false.
+-spec try_register({binary(), binary()}) -> boolean().
try_register(FromTo) ->
- Key = randoms:get_string(),
MaxS2SConnectionsNumber = max_s2s_connections_number(FromTo),
MaxS2SConnectionsNumberPerNode =
max_s2s_connections_number_per_node(FromTo),
@@ -198,9 +179,8 @@ try_register(FromTo) ->
MaxS2SConnectionsNumber,
MaxS2SConnectionsNumberPerNode),
if NeededConnections > 0 ->
- mnesia:write(#s2s{fromto = FromTo, pid = self(),
- key = Key}),
- {key, Key};
+ mnesia:write(#s2s{fromto = FromTo, pid = self()}),
+ true;
true -> false
end
end,
@@ -241,6 +221,12 @@ check_peer_certificate(SockMod, Sock, Peer) ->
{error, <<"Cannot get peer certificate">>}
end.
+make_key({From, To}, StreamID) ->
+ Secret = ejabberd_config:get_option(shared_key, fun(V) -> V end),
+ p1_sha:to_hexlist(
+ crypto:hmac(sha256, p1_sha:to_hexlist(crypto:hash(sha256, Secret)),
+ [To, " ", From, " ", StreamID])).
+
%%====================================================================
%% gen_server callbacks
%%====================================================================
@@ -407,17 +393,15 @@ open_several_connections(N, MyServer, Server, From,
new_connection(MyServer, Server, From, FromTo,
MaxS2SConnectionsNumber, MaxS2SConnectionsNumberPerNode) ->
- Key = randoms:get_string(),
{ok, Pid} = ejabberd_s2s_out:start(
- MyServer, Server, {new, Key}),
+ MyServer, Server, new),
F = fun() ->
L = mnesia:read({s2s, FromTo}),
NeededConnections = needed_connections_number(L,
MaxS2SConnectionsNumber,
MaxS2SConnectionsNumberPerNode),
if NeededConnections > 0 ->
- mnesia:write(#s2s{fromto = FromTo, pid = Pid,
- key = Key}),
+ mnesia:write(#s2s{fromto = FromTo, pid = Pid}),
?INFO_MSG("New s2s connection started ~p", [Pid]),
Pid;
true -> choose_connection(From, L)
@@ -520,9 +504,12 @@ update_tables() ->
end,
case catch mnesia:table_info(s2s, attributes) of
[fromto, node, key] ->
- mnesia:transform_table(s2s, ignore, [fromto, pid, key]),
+ mnesia:transform_table(s2s, ignore, [fromto, pid]),
+ mnesia:clear_table(s2s);
+ [fromto, pid, key] ->
+ mnesia:transform_table(s2s, ignore, [fromto, pid]),
mnesia:clear_table(s2s);
- [fromto, pid, key] -> ok;
+ [fromto, pid] -> ok;
{'EXIT', _} -> ok
end,
case lists:member(local_s2s, mnesia:system_info(tables)) of
diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl
index 1b184a274..4159dee4a 100644
--- a/src/ejabberd_s2s_in.erl
+++ b/src/ejabberd_s2s_in.erl
@@ -432,9 +432,9 @@ stream_established({xmlstreamelement, El}, StateData) ->
?DEBUG("VERIFY KEY: ~p", [{To, From, Id, Key}]),
LTo = jid:nameprep(To),
LFrom = jid:nameprep(From),
- Type = case ejabberd_s2s:has_key({LTo, LFrom}, Key) of
- true -> <<"valid">>;
- _ -> <<"invalid">>
+ Type = case ejabberd_s2s:make_key({LTo, LFrom}, Id) of
+ Key -> <<"valid">>;
+ _ -> <<"invalid">>
end,
send_element(StateData,
#xmlel{name = <<"db:verify">>,
diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl
index a5f728055..331f54436 100644
--- a/src/ejabberd_s2s_out.erl
+++ b/src/ejabberd_s2s_out.erl
@@ -56,6 +56,7 @@
-record(state,
{socket :: ejabberd_socket:socket_state(),
streamid = <<"">> :: binary(),
+ remote_streamid = <<"">> :: binary(),
use_v10 = true :: boolean(),
tls = false :: boolean(),
tls_required = false :: boolean(),
@@ -69,7 +70,7 @@
server = <<"">> :: binary(),
queue = queue:new() :: ?TQUEUE,
delay_to_retry = undefined_delay :: undefined_delay | non_neg_integer(),
- new = false :: false | binary(),
+ new = false :: boolean(),
verify = false :: false | {pid(), binary(), binary()},
bridge :: {atom(), atom()},
timer = make_ref() :: reference()}).
@@ -196,7 +197,7 @@ init([From, Server, Type]) ->
true -> TLSOpts4
end,
{New, Verify} = case Type of
- {new, Key} -> {Key, false};
+ new -> {true, false};
{verify, Pid, Key, SID} ->
start_connection(self()), {false, {Pid, Key, SID}}
end,
@@ -310,7 +311,7 @@ open_socket2(Type, Addr, Port) ->
wait_for_stream({xmlstreamstart, _Name, Attrs},
StateData) ->
- {CertCheckRes, CertCheckMsg, NewStateData} =
+ {CertCheckRes, CertCheckMsg, StateData0} =
if StateData#state.tls_certverify, StateData#state.tls_enabled ->
{Res, Msg} =
ejabberd_s2s:check_peer_certificate(ejabberd_socket,
@@ -322,6 +323,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs},
true ->
{no_verify, <<"Not verified">>, StateData}
end,
+ RemoteStreamID = xml:get_attr_s(<<"id">>, Attrs),
+ NewStateData = StateData0#state{remote_streamid = RemoteStreamID},
case {xml:get_attr_s(<<"xmlns">>, Attrs),
xml:get_attr_s(<<"xmlns:db">>, Attrs),
xml:get_attr_s(<<"version">>, Attrs) == <<"1.0">>}
@@ -958,10 +961,10 @@ terminate(Reason, StateName, StateData) ->
?DEBUG("terminated: ~p", [{Reason, StateName}]),
case StateData#state.new of
false -> ok;
- Key ->
+ true ->
ejabberd_s2s:remove_connection({StateData#state.myname,
StateData#state.server},
- self(), Key)
+ self())
end,
bounce_queue(StateData#state.queue,
?ERR_REMOTE_SERVER_NOT_FOUND),
@@ -1029,19 +1032,18 @@ bounce_messages(Error) ->
send_db_request(StateData) ->
Server = StateData#state.server,
New = case StateData#state.new of
- false ->
- case ejabberd_s2s:try_register({StateData#state.myname,
- Server})
- of
- {key, Key} -> Key;
- false -> false
- end;
- Key -> Key
+ false ->
+ ejabberd_s2s:try_register({StateData#state.myname, Server});
+ true ->
+ true
end,
NewStateData = StateData#state{new = New},
try case New of
- false -> ok;
- Key1 ->
+ false -> ok;
+ true ->
+ Key1 = ejabberd_s2s:make_key(
+ {StateData#state.myname, Server},
+ StateData#state.remote_streamid),
send_element(StateData,
#xmlel{name = <<"db:result">>,
attrs =