mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-22 17:28:25 +01:00
CVE-2016-1232: Add Dialback Key Generation and Validation support (XEP-0185)
This commit is contained in:
parent
15245e9ec4
commit
c7931b4a4f
@ -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] -> ok;
|
||||
[fromto, pid, key] ->
|
||||
mnesia:transform_table(s2s, ignore, [fromto, pid]),
|
||||
mnesia:clear_table(s2s);
|
||||
[fromto, pid] -> ok;
|
||||
{'EXIT', _} -> ok
|
||||
end,
|
||||
case lists:member(local_s2s, mnesia:system_info(tables)) of
|
||||
|
@ -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">>,
|
||||
|
@ -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 =
|
||||
|
Loading…
Reference in New Issue
Block a user