25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-28 16:34:13 +01:00

Add tests for s2s code

This commit is contained in:
Evgeniy Khramtsov 2016-09-23 12:30:33 +03:00
parent ceda073766
commit 53209b9ab1
19 changed files with 917 additions and 236 deletions

View File

@ -158,7 +158,7 @@
-record(stream_start, {from :: jid:jid(), -record(stream_start, {from :: jid:jid(),
to :: jid:jid(), to :: jid:jid(),
id = <<>> :: binary(), id = <<>> :: binary(),
version = <<>> :: binary(), version :: {non_neg_integer(),non_neg_integer()},
xmlns = <<>> :: binary(), xmlns = <<>> :: binary(),
stream_xmlns = <<>> :: binary(), stream_xmlns = <<>> :: binary(),
db_xmlns = <<>> :: binary(), db_xmlns = <<>> :: binary(),

View File

@ -352,16 +352,16 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
S -> S S -> S
end, end,
StreamVersion = case Version of StreamVersion = case Version of
<<"1.0">> -> <<"1.0">>; {1,0} -> {1,0};
_ -> <<"">> _ -> undefined
end, end,
IsBlacklistedIP = is_ip_blacklisted(StateData#state.ip, Lang), IsBlacklistedIP = is_ip_blacklisted(StateData#state.ip, Lang),
case lists:member(Server, ?MYHOSTS) of case lists:member(Server, ?MYHOSTS) of
true when IsBlacklistedIP == false -> true when IsBlacklistedIP == false ->
change_shaper(StateData, jid:make(<<"">>, Server, <<"">>)), change_shaper(StateData, jid:make(<<"">>, Server, <<"">>)),
case StreamVersion of case StreamVersion of
<<"1.0">> -> {1,0} ->
send_header(StateData, Server, <<"1.0">>, ?MYLANG), send_header(StateData, Server, {1,0}, ?MYLANG),
case StateData#state.authenticated of case StateData#state.authenticated of
false -> false ->
TLS = StateData#state.tls, TLS = StateData#state.tls,
@ -490,10 +490,14 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
send_header(StateData, ?MYNAME, StreamVersion, ?MYLANG), send_header(StateData, ?MYNAME, StreamVersion, ?MYLANG),
send_element(StateData, xmpp:serr_host_unknown()), send_element(StateData, xmpp:serr_host_unknown()),
{stop, normal, StateData} {stop, normal, StateData}
end end;
_ ->
send_header(StateData, ?MYNAME, {1,0}, ?MYLANG),
send_element(StateData, xmpp:serr_invalid_xml()),
{stop, normal, StateData}
catch _:{xmpp_codec, Why} -> catch _:{xmpp_codec, Why} ->
Txt = xmpp:format_error(Why), Txt = xmpp:format_error(Why),
send_header(StateData, ?MYNAME, <<"1.0">>, ?MYLANG), send_header(StateData, ?MYNAME, {1,0}, ?MYLANG),
send_element(StateData, xmpp:serr_invalid_xml(Txt, ?MYLANG)), send_element(StateData, xmpp:serr_invalid_xml(Txt, ?MYLANG)),
{stop, normal, StateData} {stop, normal, StateData}
end; end;
@ -506,7 +510,7 @@ wait_for_stream({xmlstreamend, _}, StateData) ->
send_element(StateData, xmpp:serr_not_well_formed()), send_element(StateData, xmpp:serr_not_well_formed()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_stream({xmlstreamerror, _}, StateData) -> wait_for_stream({xmlstreamerror, _}, StateData) ->
send_header(StateData, ?MYNAME, <<"1.0">>, <<"">>), send_header(StateData, ?MYNAME, {1,0}, <<"">>),
send_element(StateData, xmpp:serr_not_well_formed()), send_element(StateData, xmpp:serr_not_well_formed()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_stream(closed, StateData) -> wait_for_stream(closed, StateData) ->
@ -1374,7 +1378,7 @@ handle_info({'DOWN', Monitor, _Type, _Object, _Info},
handle_info(system_shutdown, StateName, StateData) -> handle_info(system_shutdown, StateName, StateData) ->
case StateName of case StateName of
wait_for_stream -> wait_for_stream ->
send_header(StateData, ?MYNAME, <<"1.0">>, <<"en">>), send_header(StateData, ?MYNAME, {1,0}, <<"en">>),
send_element(StateData, xmpp:serr_system_shutdown()), send_element(StateData, xmpp:serr_system_shutdown()),
ok; ok;
_ -> _ ->
@ -1597,39 +1601,20 @@ send_packet(StateData, Packet) ->
end. end.
-spec send_header(state(), binary(), binary(), binary()) -> ok | {error, any()}. -spec send_header(state(), binary(), binary(), binary()) -> ok | {error, any()}.
send_header(StateData, Server, Version, Lang)
when StateData#state.xml_socket ->
VersionAttr = case Version of
<<"">> -> [];
_ -> [{<<"version">>, Version}]
end,
LangAttr = case Lang of
<<"">> -> [];
_ -> [{<<"xml:lang">>, Lang}]
end,
Header = {xmlstreamstart, <<"stream:stream">>,
VersionAttr ++
LangAttr ++
[{<<"xmlns">>, <<"jabber:client">>},
{<<"xmlns:stream">>,
<<"http://etherx.jabber.org/streams">>},
{<<"id">>, StateData#state.streamid},
{<<"from">>, Server}]},
(StateData#state.sockmod):send_xml(StateData#state.socket,
Header);
send_header(StateData, Server, Version, Lang) -> send_header(StateData, Server, Version, Lang) ->
VersionStr = case Version of Header = #xmlel{name = Name, attrs = Attrs} =
<<"">> -> <<"">>; xmpp:encode(#stream_start{version = Version,
_ -> [<<" version='">>, Version, <<"'">>] lang = Lang,
end, xmlns = ?NS_CLIENT,
LangStr = case Lang of stream_xmlns = ?NS_STREAM,
<<"">> -> <<"">>; id = StateData#state.streamid,
_ -> [<<" xml:lang='">>, Lang, <<"'">>] from = jid:make(Server)}),
end, if StateData#state.xml_socket ->
Header = io_lib:format(?STREAM_HEADER, (StateData#state.sockmod):send_xml(StateData#state.socket,
[StateData#state.streamid, Server, VersionStr, {xmlstreamstart, Name, Attrs});
LangStr]), true ->
send_text(StateData, iolist_to_binary(Header)). send_text(StateData, fxml:element_to_header(Header))
end.
-spec send_trailer(state()) -> ok | {error, any()}. -spec send_trailer(state()) -> ok | {error, any()}.
send_trailer(StateData) send_trailer(StateData)

View File

@ -39,6 +39,7 @@
remove_connection/2, find_connection/2, remove_connection/2, find_connection/2,
dirty_get_connections/0, allow_host/2, dirty_get_connections/0, allow_host/2,
incoming_s2s_number/0, outgoing_s2s_number/0, incoming_s2s_number/0, outgoing_s2s_number/0,
stop_all_connections/0,
clean_temporarily_blocked_table/0, clean_temporarily_blocked_table/0,
list_temporarily_blocked_hosts/0, list_temporarily_blocked_hosts/0,
external_host_overloaded/1, is_temporarly_blocked/1, external_host_overloaded/1, is_temporarly_blocked/1,
@ -480,7 +481,13 @@ get_commands_spec() ->
"the node", "the node",
policy = admin, policy = admin,
module = ?MODULE, function = outgoing_s2s_number, module = ?MODULE, function = outgoing_s2s_number,
args = [], result = {s2s_outgoing, integer}}]. args = [], result = {s2s_outgoing, integer}},
#ejabberd_commands{name = stop_all_connections,
tags = [s2s],
desc = "Stop all outgoing and incoming connections",
policy = admin,
module = ?MODULE, function = stop_all_connections,
args = [], result = {res, rescode}}].
incoming_s2s_number() -> incoming_s2s_number() ->
length(supervisor:which_children(ejabberd_s2s_in_sup)). length(supervisor:which_children(ejabberd_s2s_in_sup)).
@ -488,6 +495,15 @@ incoming_s2s_number() ->
outgoing_s2s_number() -> outgoing_s2s_number() ->
length(supervisor:which_children(ejabberd_s2s_out_sup)). length(supervisor:which_children(ejabberd_s2s_out_sup)).
stop_all_connections() ->
lists:foreach(
fun({_Id, Pid, _Type, _Module}) ->
exit(Pid, kill)
end,
supervisor:which_children(ejabberd_s2s_in_sup) ++
supervisor:which_children(ejabberd_s2s_out_sup)),
mnesia:clear_table(s2s).
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% Update Mnesia tables %%% Update Mnesia tables

View File

@ -168,21 +168,26 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of
#stream_start{xmlns = NS_SERVER, stream_xmlns = NS_STREAM} #stream_start{xmlns = NS_SERVER, stream_xmlns = NS_STREAM}
when NS_SERVER /= ?NS_SERVER; NS_STREAM /= ?NS_STREAM -> when NS_SERVER /= ?NS_SERVER; NS_STREAM /= ?NS_STREAM ->
send_header(StateData, <<" version='1.0'">>), send_header(StateData, {1,0}),
send_element(StateData, xmpp:serr_invalid_namespace()), send_element(StateData, xmpp:serr_invalid_namespace()),
{stop, normal, StateData}; {stop, normal, StateData};
#stream_start{to = #jid{lserver = Server}, #stream_start{to = #jid{lserver = Server},
from = #jid{lserver = From}, from = From, version = {1,0}}
version = <<"1.0">>}
when StateData#state.tls and not StateData#state.authenticated -> when StateData#state.tls and not StateData#state.authenticated ->
send_header(StateData, <<" version='1.0'">>), send_header(StateData, {1,0}),
Auth = if StateData#state.tls_enabled -> Auth = if StateData#state.tls_enabled ->
{Result, Message} = case From of
ejabberd_s2s:check_peer_certificate( #jid{} ->
StateData#state.sockmod, {Result, Message} =
StateData#state.socket, ejabberd_s2s:check_peer_certificate(
From), StateData#state.sockmod,
{Result, From, Message}; StateData#state.socket,
From#jid.lserver),
{Result, From#jid.lserver, Message};
undefined ->
{error, <<"(unknown)">>,
<<"Got no valid 'from' attribute">>}
end;
true -> true ->
{no_verify, <<"(unknown)">>, <<"TLS not (yet) enabled">>} {no_verify, <<"(unknown)">>, <<"TLS not (yet) enabled">>}
end, end,
@ -225,8 +230,8 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
NewStateData#state{server = Server}} NewStateData#state{server = Server}}
end; end;
#stream_start{to = #jid{lserver = Server}, #stream_start{to = #jid{lserver = Server},
version = <<"1.0">>} when StateData#state.authenticated -> version = {1,0}} when StateData#state.authenticated ->
send_header(StateData, <<" version='1.0'">>), send_header(StateData, {1,0}),
send_element(StateData, send_element(StateData,
#stream_features{ #stream_features{
sub_els = ejabberd_hooks:run_fold( sub_els = ejabberd_hooks:run_fold(
@ -236,24 +241,28 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
#stream_start{db_xmlns = ?NS_SERVER_DIALBACK} #stream_start{db_xmlns = ?NS_SERVER_DIALBACK}
when (StateData#state.tls_required and StateData#state.tls_enabled) when (StateData#state.tls_required and StateData#state.tls_enabled)
or (not StateData#state.tls_required) -> or (not StateData#state.tls_required) ->
send_header(StateData, <<"">>), send_header(StateData, undefined),
{next_state, stream_established, StateData}; {next_state, stream_established, StateData};
#stream_start{} -> #stream_start{} ->
send_header(StateData, <<" version='1.0'">>), send_header(StateData, {1,0}),
send_element(StateData, xmpp:serr_undefined_condition()), send_element(StateData, xmpp:serr_undefined_condition()),
{stop, normal, StateData} {stop, normal, StateData};
_ ->
send_header(StateData, {1,0}),
send_element(StateData, xmpp:serr_invalid_xml()),
{stop, normal, StateData}
catch _:{xmpp_codec, Why} -> catch _:{xmpp_codec, Why} ->
Txt = xmpp:format_error(Why), Txt = xmpp:format_error(Why),
send_header(StateData, <<" version='1.0'">>), send_header(StateData, {1,0}),
send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)), send_element(StateData, xmpp:serr_invalid_xml(Txt, ?MYLANG)),
{stop, normal, StateData} {stop, normal, StateData}
end; end;
wait_for_stream({xmlstreamerror, _}, StateData) -> wait_for_stream({xmlstreamerror, _}, StateData) ->
send_header(StateData, <<"">>), send_header(StateData, {1,0}),
send_element(StateData, xmpp:serr_not_well_formed()), send_element(StateData, xmpp:serr_not_well_formed()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_stream(timeout, StateData) -> wait_for_stream(timeout, StateData) ->
send_header(StateData, <<"">>), send_header(StateData, {1,0}),
send_element(StateData, xmpp:serr_connection_timeout()), send_element(StateData, xmpp:serr_connection_timeout()),
{stop, normal, StateData}; {stop, normal, StateData};
wait_for_stream(closed, StateData) -> wait_for_stream(closed, StateData) ->
@ -277,13 +286,21 @@ wait_for_feature_request(#starttls{},
StateData#state.tls_options, StateData#state.tls_options,
{certfile, CertFile}) {certfile, CertFile})
end, end,
TLSOpts2 = case ejabberd_config:get_option(
{s2s_cafile, StateData#state.server},
fun iolist_to_binary/1) of
undefined -> TLSOpts1;
CAFile ->
lists:keystore(cafile, 1, TLSOpts1,
{cafile, CAFile})
end,
TLSOpts = case ejabberd_config:get_option( TLSOpts = case ejabberd_config:get_option(
{s2s_tls_compression, StateData#state.server}, {s2s_tls_compression, StateData#state.server},
fun(true) -> true; fun(true) -> true;
(false) -> false (false) -> false
end, false) of end, false) of
true -> lists:delete(compression_none, TLSOpts1); true -> lists:delete(compression_none, TLSOpts2);
false -> [compression_none | TLSOpts1] false -> [compression_none | TLSOpts2]
end, end,
TLSSocket = (StateData#state.sockmod):starttls( TLSSocket = (StateData#state.sockmod):starttls(
Socket, TLSOpts, Socket, TLSOpts,
@ -293,8 +310,7 @@ wait_for_feature_request(#starttls{},
StateData#state{socket = TLSSocket, streamid = new_id(), StateData#state{socket = TLSSocket, streamid = new_id(),
tls_enabled = true, tls_options = TLSOpts}}; tls_enabled = true, tls_options = TLSOpts}};
_ -> _ ->
Txt = <<"Unsupported TLS transport">>, send_element(StateData, #starttls_failure{}),
send_element(StateData, xmpp:serr_policy_violation(Txt, ?MYLANG)),
{stop, normal, StateData} {stop, normal, StateData}
end; end;
wait_for_feature_request(#sasl_auth{mechanism = Mech}, wait_for_feature_request(#sasl_auth{mechanism = Mech},
@ -313,7 +329,10 @@ wait_for_feature_request(#sasl_auth{mechanism = Mech},
StateData#state{streamid = new_id(), StateData#state{streamid = new_id(),
authenticated = true}}; authenticated = true}};
true -> true ->
send_element(StateData, #sasl_failure{}), Txt = xmpp:mk_text(<<"Denied by ACL">>, ?MYLANG),
send_element(StateData,
#sasl_failure{reason = 'not-authorized',
text = Txt}),
{stop, normal, StateData} {stop, normal, StateData}
end; end;
_ -> _ ->
@ -495,7 +514,7 @@ handle_info({send_text, Text}, StateName, StateData) ->
handle_info({timeout, Timer, _}, StateName, handle_info({timeout, Timer, _}, StateName,
#state{timer = Timer} = StateData) -> #state{timer = Timer} = StateData) ->
if StateName == wait_for_stream -> if StateName == wait_for_stream ->
send_header(StateData, <<"">>); send_header(StateData, undefined);
true -> true ->
ok ok
end, end,
@ -555,15 +574,15 @@ send_error(StateData, Stanza, Error) ->
send_trailer(StateData) -> send_trailer(StateData) ->
send_text(StateData, <<"</stream:stream>">>). send_text(StateData, <<"</stream:stream>">>).
-spec send_header(state(), binary()) -> ok. -spec send_header(state(), undefined | {integer(), integer()}) -> ok.
send_header(StateData, Version) -> send_header(StateData, Version) ->
send_text(StateData, Header = xmpp:encode(
<<"<?xml version='1.0'?><stream:stream " #stream_start{xmlns = ?NS_SERVER,
"xmlns:stream='http://etherx.jabber.org/stream" stream_xmlns = ?NS_STREAM,
"s' xmlns='jabber:server' xmlns:db='jabber:ser" db_xmlns = ?NS_SERVER_DIALBACK,
"ver:dialback' id='", id = StateData#state.streamid,
(StateData#state.streamid)/binary, "'", Version/binary, version = Version}),
">">>). send_text(StateData, fxml:element_to_header(Header)).
-spec change_shaper(state(), binary(), jid()) -> ok. -spec change_shaper(state(), binary(), jid()) -> ok.
change_shaper(StateData, Host, JID) -> change_shaper(StateData, Host, JID) ->
@ -606,9 +625,14 @@ fsm_limit_opts(Opts) ->
end end
end. end.
-spec decode_element(xmlel(), state_name(), state()) -> fsm_transition(). -spec decode_element(xmlel() | xmpp_element(), state_name(), state()) -> fsm_transition().
decode_element(#xmlel{} = El, StateName, StateData) -> decode_element(#xmlel{} = El, StateName, StateData) ->
try xmpp:decode(El) of Opts = if StateName == stream_established ->
[ignore_els];
true ->
[]
end,
try xmpp:decode(El, Opts) of
Pkt -> ?MODULE:StateName(Pkt, StateData) Pkt -> ?MODULE:StateName(Pkt, StateData)
catch error:{xmpp_codec, Why} -> catch error:{xmpp_codec, Why} ->
case xmpp:is_stanza(El) of case xmpp:is_stanza(El) of
@ -620,12 +644,15 @@ decode_element(#xmlel{} = El, StateName, StateData) ->
ok ok
end, end,
{next_state, StateName, StateData} {next_state, StateName, StateData}
end. end;
decode_element(Pkt, StateName, StateData) ->
?MODULE:StateName(Pkt, StateData).
opt_type(domain_certfile) -> fun iolist_to_binary/1; opt_type(domain_certfile) -> fun iolist_to_binary/1;
opt_type(max_fsm_queue) -> opt_type(max_fsm_queue) ->
fun (I) when is_integer(I), I > 0 -> I end; fun (I) when is_integer(I), I > 0 -> I end;
opt_type(s2s_certfile) -> fun iolist_to_binary/1; opt_type(s2s_certfile) -> fun iolist_to_binary/1;
opt_type(s2s_cafile) -> fun iolist_to_binary/1;
opt_type(s2s_ciphers) -> fun iolist_to_binary/1; opt_type(s2s_ciphers) -> fun iolist_to_binary/1;
opt_type(s2s_dhfile) -> fun iolist_to_binary/1; opt_type(s2s_dhfile) -> fun iolist_to_binary/1;
opt_type(s2s_protocol_options) -> opt_type(s2s_protocol_options) ->
@ -647,6 +674,6 @@ opt_type(s2s_use_starttls) ->
(required_trusted) -> required_trusted (required_trusted) -> required_trusted
end; end;
opt_type(_) -> opt_type(_) ->
[domain_certfile, max_fsm_queue, s2s_certfile, [domain_certfile, max_fsm_queue, s2s_certfile, s2s_cafile,
s2s_ciphers, s2s_dhfile, s2s_protocol_options, s2s_ciphers, s2s_dhfile, s2s_protocol_options,
s2s_tls_compression, s2s_use_starttls]. s2s_tls_compression, s2s_use_starttls].

View File

@ -106,12 +106,6 @@
%% Specified in miliseconds. Default value is 5 minutes. %% Specified in miliseconds. Default value is 5 minutes.
-define(MAX_RETRY_DELAY, 300000). -define(MAX_RETRY_DELAY, 300000).
-define(STREAM_HEADER,
<<"<?xml version='1.0'?><stream:stream "
"xmlns:stream='http://etherx.jabber.org/stream"
"s' xmlns='jabber:server' xmlns:db='jabber:ser"
"ver:dialback' from='~s' to='~s'~s>">>).
-define(SOCKET_DEFAULT_RESULT, {error, badarg}). -define(SOCKET_DEFAULT_RESULT, {error, badarg}).
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
@ -228,9 +222,8 @@ open_socket(init, StateData) ->
?SOCKET_DEFAULT_RESULT, AddrList) ?SOCKET_DEFAULT_RESULT, AddrList)
of of
{ok, Socket} -> {ok, Socket} ->
Version = if StateData#state.use_v10 -> Version = if StateData#state.use_v10 -> {1,0};
<<" version='1.0'">>; true -> undefined
true -> <<"">>
end, end,
NewStateData = StateData#state{socket = Socket, NewStateData = StateData#state{socket = Socket,
tls_enabled = false, tls_enabled = false,
@ -318,11 +311,10 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData0) ->
{stop, normal, StateData}; {stop, normal, StateData};
#stream_start{xmlns = NS_SERVER, stream_xmlns = NS_STREAM} #stream_start{xmlns = NS_SERVER, stream_xmlns = NS_STREAM}
when NS_SERVER /= ?NS_SERVER; NS_STREAM /= ?NS_STREAM -> when NS_SERVER /= ?NS_SERVER; NS_STREAM /= ?NS_STREAM ->
send_header(StateData, <<" version='1.0'">>),
send_element(StateData, xmpp:serr_invalid_namespace()), send_element(StateData, xmpp:serr_invalid_namespace()),
{stop, normal, StateData}; {stop, normal, StateData};
#stream_start{db_xmlns = ?NS_SERVER_DIALBACK, id = ID, #stream_start{db_xmlns = ?NS_SERVER_DIALBACK, id = ID,
version = V} when V /= <<"1.0">> -> version = V} when V /= {1,0} ->
send_db_request(StateData#state{remote_streamid = ID}); send_db_request(StateData#state{remote_streamid = ID});
#stream_start{db_xmlns = ?NS_SERVER_DIALBACK, id = ID} #stream_start{db_xmlns = ?NS_SERVER_DIALBACK, id = ID}
when StateData#state.use_v10 -> when StateData#state.use_v10 ->
@ -337,13 +329,14 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData0) ->
StateData#state{db_enabled = false, remote_streamid = ID}, StateData#state{db_enabled = false, remote_streamid = ID},
?FSMTIMEOUT}; ?FSMTIMEOUT};
#stream_start{} -> #stream_start{} ->
send_header(StateData, <<"">>),
send_element(StateData, xmpp:serr_invalid_namespace()), send_element(StateData, xmpp:serr_invalid_namespace()),
{stop, normal, StateData} {stop, normal, StateData};
_ ->
send_element(StateData, xmpp:serr_invalid_xml()),
{stop, normal, StateData}
catch _:{xmpp_codec, Why} -> catch _:{xmpp_codec, Why} ->
Txt = xmpp:format_error(Why), Txt = xmpp:format_error(Why),
send_header(StateData, <<" version='1.0'">>), send_element(StateData, xmpp:serr_invalid_xml(Txt, ?MYLANG)),
send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)),
{stop, normal, StateData} {stop, normal, StateData}
end; end;
wait_for_stream(Event, StateData) -> wait_for_stream(Event, StateData) ->
@ -469,7 +462,7 @@ wait_for_auth_result({xmlstreamelement, El}, StateData) ->
wait_for_auth_result(#sasl_success{}, StateData) -> wait_for_auth_result(#sasl_success{}, StateData) ->
?DEBUG("auth: ~p", [{StateData#state.myname, StateData#state.server}]), ?DEBUG("auth: ~p", [{StateData#state.myname, StateData#state.server}]),
ejabberd_socket:reset_stream(StateData#state.socket), ejabberd_socket:reset_stream(StateData#state.socket),
send_header(StateData, <<" version='1.0'">>), send_header(StateData, {1,0}),
{next_state, wait_for_stream, {next_state, wait_for_stream,
StateData#state{streamid = new_id(), authenticated = true}, StateData#state{streamid = new_id(), authenticated = true},
?FSMTIMEOUT}; ?FSMTIMEOUT};
@ -500,7 +493,7 @@ wait_for_starttls_proceed(#starttls_proceed{}, StateData) ->
streamid = new_id(), streamid = new_id(),
tls_enabled = true, tls_enabled = true,
tls_options = TLSOpts}, tls_options = TLSOpts},
send_header(NewStateData, <<" version='1.0'">>), send_header(NewStateData, {1,0}),
{next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT}; {next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT};
wait_for_starttls_proceed(Event, StateData) -> wait_for_starttls_proceed(Event, StateData) ->
handle_unexpected_event(Event, wait_for_starttls_proceed, StateData). handle_unexpected_event(Event, wait_for_starttls_proceed, StateData).
@ -567,7 +560,8 @@ handle_unexpected_event(Event, StateName, StateData) ->
{xmlstreamend, _} -> {xmlstreamend, _} ->
?INFO_MSG("Closing s2s connection ~s -> ~s in state ~s: " ?INFO_MSG("Closing s2s connection ~s -> ~s in state ~s: "
"XML stream closed by peer", "XML stream closed by peer",
[StateData#state.myname, StateData#state.server]), [StateData#state.myname, StateData#state.server,
StateName]),
{stop, normal, StateData}; {stop, normal, StateData};
timeout -> timeout ->
send_element(StateData, xmpp:serr_connection_timeout()), send_element(StateData, xmpp:serr_connection_timeout()),
@ -741,6 +735,7 @@ print_state(State) -> State.
-spec send_text(state(), iodata()) -> ok. -spec send_text(state(), iodata()) -> ok.
send_text(StateData, Text) -> send_text(StateData, Text) ->
?DEBUG("Send Text on stream = ~s", [Text]),
ejabberd_socket:send(StateData#state.socket, Text). ejabberd_socket:send(StateData#state.socket, Text).
-spec send_element(state(), xmpp_element()) -> ok. -spec send_element(state(), xmpp_element()) -> ok.
@ -748,15 +743,16 @@ send_element(StateData, El) ->
El1 = fix_ns(xmpp:encode(El)), El1 = fix_ns(xmpp:encode(El)),
send_text(StateData, fxml:element_to_binary(El1)). send_text(StateData, fxml:element_to_binary(El1)).
-spec send_header(state(), binary()) -> ok. -spec send_header(state(), undefined | {integer(), integer()}) -> ok.
send_header(StateData, Version) -> send_header(StateData, Version) ->
Txt = io_lib:format( Header = xmpp:encode(
"<?xml version='1.0'?><stream:stream " #stream_start{xmlns = ?NS_SERVER,
"xmlns:stream='http://etherx.jabber.org/stream" stream_xmlns = ?NS_STREAM,
"s' xmlns='jabber:server' xmlns:db='jabber:ser" db_xmlns = ?NS_SERVER_DIALBACK,
"ver:dialback' from='~s' to='~s'~s>", from = jid:make(StateData#state.myname),
[StateData#state.myname, StateData#state.server, Version]), to = jid:make(StateData#state.server),
send_text(StateData, Txt). version = Version}),
send_text(StateData, fxml:element_to_header(Header)).
-spec send_trailer(state()) -> ok. -spec send_trailer(state()) -> ok.
send_trailer(StateData) -> send_trailer(StateData) ->

View File

@ -149,6 +149,10 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
#stream_start{} -> #stream_start{} ->
send_header(StateData, ?MYNAME), send_header(StateData, ?MYNAME),
send_element(StateData, xmpp:serr_improper_addressing()), send_element(StateData, xmpp:serr_improper_addressing()),
{stop, normal, StateData};
_ ->
send_header(StateData, ?MYNAME),
send_element(StateData, xmpp:serr_invalid_xml()),
{stop, normal, StateData} {stop, normal, StateData}
catch _:{xmpp_codec, Why} -> catch _:{xmpp_codec, Why} ->
Txt = xmpp:format_error(Why), Txt = xmpp:format_error(Why),
@ -319,13 +323,12 @@ send_error(StateData, Stanza, Error) ->
-spec send_header(state(), binary()) -> ok. -spec send_header(state(), binary()) -> ok.
send_header(StateData, Host) -> send_header(StateData, Host) ->
send_text(StateData, Header = xmpp:encode(
io_lib:format( #stream_start{xmlns = ?NS_COMPONENT,
<<"<?xml version='1.0'?><stream:stream " stream_xmlns = ?NS_STREAM,
"xmlns:stream='http://etherx.jabber.org/stream" from = jid:make(Host),
"s' xmlns='jabber:component:accept' id='~s' " id = StateData#state.streamid}),
"from='~s'>">>, send_text(StateData, fxml:element_to_header(Header)).
[StateData#state.streamid, fxml:crypt(Host)])).
-spec send_trailer(state()) -> ok. -spec send_trailer(state()) -> ok.
send_trailer(StateData) -> send_trailer(StateData) ->

View File

@ -3955,6 +3955,14 @@ pp(upload_slot, 3) -> [get, put, xmlns];
pp(thumbnail, 4) -> [uri, 'media-type', width, height]; pp(thumbnail, 4) -> [uri, 'media-type', width, height];
pp(_, _) -> no. pp(_, _) -> no.
enc_version({Maj, Min}) ->
<<(integer_to_binary(Maj))/binary, $.,
(integer_to_binary(Min))/binary>>.
dec_version(S) ->
[Major, Minor] = binary:split(S, <<$.>>),
{binary_to_integer(Major), binary_to_integer(Minor)}.
enc_host_port(Host) when is_binary(Host) -> Host; enc_host_port(Host) when is_binary(Host) -> Host;
enc_host_port({{_, _, _, _, _, _, _, _} = IPv6, enc_host_port({{_, _, _, _, _, _, _, _} = IPv6,
Port}) -> Port}) ->
@ -5284,13 +5292,20 @@ encode_stream_start_attr_xmlns(_val, _acc) ->
decode_stream_start_attr_version(__TopXMLNS, decode_stream_start_attr_version(__TopXMLNS,
undefined) -> undefined) ->
<<>>; undefined;
decode_stream_start_attr_version(__TopXMLNS, _val) -> decode_stream_start_attr_version(__TopXMLNS, _val) ->
_val. case catch dec_version(_val) of
{'EXIT', _} ->
erlang:error({xmpp_codec,
{bad_attr_value, <<"version">>, <<"stream:stream">>,
__TopXMLNS}});
_res -> _res
end.
encode_stream_start_attr_version(<<>>, _acc) -> _acc; encode_stream_start_attr_version(undefined, _acc) ->
_acc;
encode_stream_start_attr_version(_val, _acc) -> encode_stream_start_attr_version(_val, _acc) ->
[{<<"version">>, _val} | _acc]. [{<<"version">>, enc_version(_val)} | _acc].
decode_stream_start_attr_id(__TopXMLNS, undefined) -> decode_stream_start_attr_id(__TopXMLNS, undefined) ->
<<>>; <<>>;

View File

@ -20,13 +20,13 @@
make_iq_result/1, start_event_relay/0, make_iq_result/1, start_event_relay/0,
stop_event_relay/1, put_event/2, get_event/1, stop_event_relay/1, put_event/2, get_event/1,
bind/1, auth/1, auth/2, open_session/1, open_session/2, bind/1, auth/1, auth/2, open_session/1, open_session/2,
zlib/1, starttls/1, close_socket/1, init_stream/1, zlib/1, starttls/1, starttls/2, close_socket/1, init_stream/1,
auth_legacy/2, auth_legacy/3]). auth_legacy/2, auth_legacy/3, tcp_connect/1, send_text/2]).
-include("suite.hrl"). -include("suite.hrl").
suite() -> suite() ->
[{timetrap, {seconds,10}}]. [{timetrap, {seconds,30}}].
init_per_suite(Config) -> init_per_suite(Config) ->
NewConfig = init_config(Config), NewConfig = init_config(Config),
@ -36,6 +36,10 @@ init_per_suite(Config) ->
LDIFFile = filename:join([DataDir, "ejabberd.ldif"]), LDIFFile = filename:join([DataDir, "ejabberd.ldif"]),
{ok, _} = file:copy(ExtAuthScript, filename:join([CWD, "extauth.py"])), {ok, _} = file:copy(ExtAuthScript, filename:join([CWD, "extauth.py"])),
{ok, _} = ldap_srv:start(LDIFFile), {ok, _} = ldap_srv:start(LDIFFile),
inet_db:add_host({127,0,0,1}, [binary_to_list(?S2S_VHOST),
binary_to_list(?MNESIA_VHOST)]),
inet_db:set_domain(binary_to_list(randoms:get_string())),
inet_db:set_lookup([file, native]),
start_ejabberd(NewConfig), start_ejabberd(NewConfig),
NewConfig. NewConfig.
@ -125,6 +129,16 @@ do_init_per_group(riak, Config) ->
Err -> Err ->
{skip, {riak_not_available, Err}} {skip, {riak_not_available, Err}}
end; end;
do_init_per_group(s2s, Config) ->
ejabberd_config:add_option(s2s_use_starttls, required_trusted),
ejabberd_config:add_option(domain_certfile, "cert.pem"),
Port = ?config(s2s_port, Config),
set_opt(server, ?COMMON_VHOST,
set_opt(xmlns, ?NS_SERVER,
set_opt(type, server,
set_opt(server_port, Port,
set_opt(stream_from, ?S2S_VHOST,
set_opt(lang, <<"">>, Config))))));
do_init_per_group(component, Config) -> do_init_per_group(component, Config) ->
Server = ?config(server, Config), Server = ?config(server, Config),
Port = ?config(component_port, Config), Port = ?config(component_port, Config),
@ -132,7 +146,7 @@ do_init_per_group(component, Config) ->
set_opt(server, <<"component.", Server/binary>>, set_opt(server, <<"component.", Server/binary>>,
set_opt(type, component, set_opt(type, component,
set_opt(server_port, Port, set_opt(server_port, Port,
set_opt(stream_version, <<"">>, set_opt(stream_version, undefined,
set_opt(lang, <<"">>, Config)))))); set_opt(lang, <<"">>, Config))))));
do_init_per_group(_GroupName, Config) -> do_init_per_group(_GroupName, Config) ->
Pid = start_event_relay(), Pid = start_event_relay(),
@ -158,6 +172,8 @@ end_per_group(riak, _Config) ->
ok; ok;
end_per_group(component, _Config) -> end_per_group(component, _Config) ->
ok; ok;
end_per_group(s2s, _Config) ->
ejabberd_config:add_option(s2s_use_starttls, false);
end_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) ->
stop_event_relay(Config), stop_event_relay(Config),
ok. ok.
@ -215,7 +231,7 @@ init_per_testcase(TestCase, OrigConfig) ->
"test_connect" ++ _ -> "test_connect" ++ _ ->
Config; Config;
"test_legacy_auth" ++ _ -> "test_legacy_auth" ++ _ ->
init_stream(set_opt(stream_version, <<"">>, Config)); init_stream(set_opt(stream_version, undefined, Config));
"test_auth" ++ _ -> "test_auth" ++ _ ->
connect(Config); connect(Config);
"test_starttls" ++ _ -> "test_starttls" ++ _ ->
@ -244,6 +260,8 @@ init_per_testcase(TestCase, OrigConfig) ->
Password = ?config(password, Config), Password = ?config(password, Config),
ejabberd_auth:try_register(User, Server, Password), ejabberd_auth:try_register(User, Server, Password),
open_session(bind(auth(connect(Config)))); open_session(bind(auth(connect(Config))));
_ when TestGroup == s2s_tests ->
auth(connect(starttls(connect(Config))));
_ -> _ ->
open_session(bind(auth(connect(Config)))) open_session(bind(auth(connect(Config))))
end. end.
@ -262,6 +280,7 @@ legacy_auth_tests() ->
no_db_tests() -> no_db_tests() ->
[{generic, [parallel], [{generic, [parallel],
[test_connect_bad_xml, [test_connect_bad_xml,
test_connect_unexpected_xml,
test_connect_unknown_ns, test_connect_unknown_ns,
test_connect_bad_xmlns, test_connect_bad_xmlns,
test_connect_bad_ns_stream, test_connect_bad_ns_stream,
@ -286,7 +305,12 @@ no_db_tests() ->
time, time,
stats, stats,
disco]}, disco]},
{presence, [sequence], [presence]}, {presence_and_s2s, [sequence],
[presence,
s2s_dialback,
s2s_optional,
s2s_required,
s2s_required_trusted]},
{sm, [sequence], {sm, [sequence],
[sm, [sm,
sm_resume, sm_resume,
@ -433,18 +457,39 @@ extauth_tests() ->
test_unregister]}]. test_unregister]}].
component_tests() -> component_tests() ->
[{component_tests, [sequence], [{component_connect, [parallel],
[test_connect_bad_xml, [test_connect_bad_xml,
test_connect_unexpected_xml,
test_connect_unknown_ns, test_connect_unknown_ns,
test_connect_bad_xmlns, test_connect_bad_xmlns,
test_connect_bad_ns_stream, test_connect_bad_ns_stream,
test_connect_missing_to, test_connect_missing_to,
test_connect, test_connect,
test_auth, test_auth,
test_auth_fail, test_auth_fail]},
component_missing_address, {component_tests, [sequence],
component_invalid_from, [test_missing_address,
component_send, test_invalid_from,
test_component_send,
bad_nonza,
codec_failure]}].
s2s_tests() ->
[{s2s_connect, [parallel],
[test_connect_bad_xml,
test_connect_unexpected_xml,
test_connect_unknown_ns,
test_connect_bad_xmlns,
test_connect_bad_ns_stream,
test_connect,
test_connect_s2s_starttls_required,
test_starttls,
test_connect_missing_from,
test_connect_s2s_unauthenticated_iq,
test_auth_starttls]},
{s2s_tests, [sequence],
[test_missing_address,
test_invalid_from,
bad_nonza, bad_nonza,
codec_failure]}]. codec_failure]}].
@ -453,6 +498,7 @@ groups() ->
{extauth, [sequence], extauth_tests()}, {extauth, [sequence], extauth_tests()},
{no_db, [sequence], no_db_tests()}, {no_db, [sequence], no_db_tests()},
{component, [sequence], component_tests()}, {component, [sequence], component_tests()},
{s2s, [sequence], s2s_tests()},
{mnesia, [sequence], db_tests(mnesia)}, {mnesia, [sequence], db_tests(mnesia)},
{redis, [sequence], db_tests(redis)}, {redis, [sequence], db_tests(redis)},
{mysql, [sequence], db_tests(mysql)}, {mysql, [sequence], db_tests(mysql)},
@ -461,16 +507,17 @@ groups() ->
{riak, [sequence], db_tests(riak)}]. {riak, [sequence], db_tests(riak)}].
all() -> all() ->
[{group, component}, [{group, ldap},
%%{group, ldap},
{group, no_db}, {group, no_db},
{group, mnesia}, {group, mnesia},
%%{group, redis}, {group, redis},
%%{group, mysql}, {group, mysql},
%%{group, pgsql}, {group, pgsql},
%%{group, sqlite}, {group, sqlite},
%%{group, extauth}, {group, extauth},
%%{group, riak}, {group, riak},
{group, component},
{group, s2s},
stop_ejabberd]. stop_ejabberd].
stop_ejabberd(Config) -> stop_ejabberd(Config) ->
@ -480,11 +527,23 @@ stop_ejabberd(Config) ->
Config. Config.
test_connect_bad_xml(Config) -> test_connect_bad_xml(Config) ->
Config0 = init_stream(set_opt(xmlns, <<"'">>, Config)), Config0 = tcp_connect(Config),
send_text(Config0, <<"<'/>">>),
Version = ?config(stream_version, Config0),
?recv1(#stream_start{version = Version}),
?recv1(#stream_error{reason = 'not-well-formed'}), ?recv1(#stream_error{reason = 'not-well-formed'}),
?recv1({xmlstreamend, <<"stream:stream">>}), ?recv1({xmlstreamend, <<"stream:stream">>}),
close_socket(Config0). close_socket(Config0).
test_connect_unexpected_xml(Config) ->
Config0 = tcp_connect(Config),
send(Config0, #caps{}),
Version = ?config(stream_version, Config0),
?recv1(#stream_start{version = Version}),
?recv1(#stream_error{reason = 'invalid-xml'}),
?recv1({xmlstreamend, <<"stream:stream">>}),
close_socket(Config0).
test_connect_unknown_ns(Config) -> test_connect_unknown_ns(Config) ->
Config0 = init_stream(set_opt(xmlns, <<"wrong">>, Config)), Config0 = init_stream(set_opt(xmlns, <<"wrong">>, Config)),
?recv1(#stream_error{reason = 'invalid-xml'}), ?recv1(#stream_error{reason = 'invalid-xml'}),
@ -492,7 +551,11 @@ test_connect_unknown_ns(Config) ->
close_socket(Config0). close_socket(Config0).
test_connect_bad_xmlns(Config) -> test_connect_bad_xmlns(Config) ->
Config0 = init_stream(set_opt(xmlns, ?NS_SERVER, Config)), NS = case ?config(type, Config) of
client -> ?NS_SERVER;
_ -> ?NS_CLIENT
end,
Config0 = init_stream(set_opt(xmlns, NS, Config)),
?recv1(#stream_error{reason = 'invalid-namespace'}), ?recv1(#stream_error{reason = 'invalid-namespace'}),
?recv1({xmlstreamend, <<"stream:stream">>}), ?recv1({xmlstreamend, <<"stream:stream">>}),
close_socket(Config0). close_socket(Config0).
@ -521,19 +584,32 @@ test_connect_missing_to(Config) ->
?recv1({xmlstreamend, <<"stream:stream">>}), ?recv1({xmlstreamend, <<"stream:stream">>}),
close_socket(Config0). close_socket(Config0).
test_connect_missing_from(Config) ->
Config1 = starttls(connect(Config)),
Config2 = set_opt(stream_from, <<"">>, Config1),
Config3 = init_stream(Config2),
?recv1(#stream_error{reason = 'policy-violation'}),
?recv1({xmlstreamend, <<"stream:stream">>}),
close_socket(Config3).
test_connect(Config) -> test_connect(Config) ->
disconnect(connect(Config)). disconnect(connect(Config)).
test_component_connect(Config) -> test_connect_s2s_starttls_required(Config) ->
disconnect(component_connect(Config)). Config1 = connect(Config),
send(Config1, #caps{}),
?recv1(#stream_error{reason = 'policy-violation'}),
?recv1({xmlstreamend, <<"stream:stream">>}),
close_socket(Config1).
component_connect(Config) -> test_connect_s2s_unauthenticated_iq(Config) ->
init_stream(Config). Config1 = connect(starttls(connect(Config))),
unauthenticated_iq(Config1).
test_starttls(Config) -> test_starttls(Config) ->
case ?config(starttls, Config) of case ?config(starttls, Config) of
true -> true ->
disconnect(starttls(Config)); disconnect(connect(starttls(Config)));
_ -> _ ->
{skipped, 'starttls_not_available'} {skipped, 'starttls_not_available'}
end. end.
@ -597,8 +673,11 @@ unauthenticated_stanza(Config) ->
disconnect(Config). disconnect(Config).
unauthenticated_iq(Config) -> unauthenticated_iq(Config) ->
From = my_jid(Config),
To = server_jid(Config),
#iq{type = error} = #iq{type = error} =
send_recv(Config, #iq{type = get, sub_els = [#disco_info{}]}), send_recv(Config, #iq{type = get, from = From, to = To,
sub_els = [#disco_info{}]}),
disconnect(Config). disconnect(Config).
bad_nonza(Config) -> bad_nonza(Config) ->
@ -613,23 +692,57 @@ invalid_from(Config) ->
?recv1({xmlstreamend, <<"stream:stream">>}), ?recv1({xmlstreamend, <<"stream:stream">>}),
close_socket(Config). close_socket(Config).
component_missing_address(Config) -> test_missing_address(Config) ->
Server = server_jid(Config), Server = server_jid(Config),
#iq{type = error} = send_recv(Config, #iq{type = get, from = Server}), #iq{type = error} = send_recv(Config, #iq{type = get, from = Server}),
#iq{type = error} = send_recv(Config, #iq{type = get, to = Server}), #iq{type = error} = send_recv(Config, #iq{type = get, to = Server}),
disconnect(Config). disconnect(Config).
component_invalid_from(Config) -> test_invalid_from(Config) ->
From = jid:make(randoms:get_string()), From = jid:make(randoms:get_string()),
To = jid:make(randoms:get_string()), To = jid:make(randoms:get_string()),
#iq{type = error} = #iq{type = error} =
send_recv(Config, #iq{type = get, from = From, to = To}), send_recv(Config, #iq{type = get, from = From, to = To}),
disconnect(Config). disconnect(Config).
component_send(Config) -> test_component_send(Config) ->
JID = my_jid(Config), To = jid:make(?COMMON_VHOST),
send(Config, #message{from = JID, to = JID}), From = server_jid(Config),
#message{from = JID, to = JID} = recv(), #iq{type = result, from = To, to = From} =
send_recv(Config, #iq{type = get, to = To, from = From,
sub_els = [#ping{}]}),
disconnect(Config).
s2s_dialback(Config) ->
ejabberd_s2s:stop_all_connections(),
ejabberd_config:add_option(s2s_use_starttls, false),
ejabberd_config:add_option(domain_certfile, "self-signed-cert.pem"),
s2s_ping(Config).
s2s_optional(Config) ->
ejabberd_s2s:stop_all_connections(),
ejabberd_config:add_option(s2s_use_starttls, optional),
ejabberd_config:add_option(domain_certfile, "self-signed-cert.pem"),
s2s_ping(Config).
s2s_required(Config) ->
ejabberd_s2s:stop_all_connections(),
ejabberd_config:add_option(s2s_use_starttls, required),
ejabberd_config:add_option(domain_certfile, "self-signed-cert.pem"),
s2s_ping(Config).
s2s_required_trusted(Config) ->
ejabberd_s2s:stop_all_connections(),
ejabberd_config:add_option(s2s_use_starttls, required),
ejabberd_config:add_option(domain_certfile, "cert.pem"),
s2s_ping(Config).
s2s_ping(Config) ->
From = my_jid(Config),
To = jid:make(?MNESIA_VHOST),
ID = randoms:get_string(),
ejabberd_s2s:route(From, To, #iq{id = ID, type = get, sub_els = [#ping{}]}),
?recv1(#iq{type = result, id = ID, sub_els = []}),
disconnect(Config). disconnect(Config).
auth_md5(Config) -> auth_md5(Config) ->
@ -674,6 +787,9 @@ test_legacy_auth_fail(Config0) ->
test_auth(Config) -> test_auth(Config) ->
disconnect(auth(Config)). disconnect(auth(Config)).
test_auth_starttls(Config) ->
disconnect(auth(connect(starttls(Config)))).
test_auth_fail(Config0) -> test_auth_fail(Config0) ->
Config = set_opt(user, <<"wrong">>, Config = set_opt(user, <<"wrong">>,
set_opt(password, <<"wrong">>, Config0)), set_opt(password, <<"wrong">>, Config0)),
@ -1895,7 +2011,6 @@ announce_slave(Config) ->
flex_offline_master(Config) -> flex_offline_master(Config) ->
Peer = ?config(slave, Config), Peer = ?config(slave, Config),
ct:log("hooks = ~p", [ets:tab2list(hooks)]),
LPeer = jid:remove_resource(Peer), LPeer = jid:remove_resource(Peer),
lists:foreach( lists:foreach(
fun(I) -> fun(I) ->

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAxGSSFSDTbBTk2GwkORLCXoBdYq5YxwPfen8bK+8WjxRb9Thp
FsHYfImtDQV0qvcZyWnjUFxRh7Dyw7A2X690nplCdzZ9Gl+5yzzlRefHborMSnNY
rnTqx3vs9qiac0A5bzdjMY7XN3VuVwz0XWY6rAiL/7OxunCNUnQz+oswDx7cj1W4
bb9pFzBvW5TjaAiziyzS3IxvTc7kYQYJEa99vIlDZ+Ov9rHtiF/5CZ8kHc457B3s
uc9hHxO2t0EzmBiqg7wpksJjoJeXaJvT9sKSgW6LXkjBCm/7jm1ElPq+7FCph0qp
uIsxMtu15exLKQaSRLcc+tyNkWIZGQ371D2+7wIDAQABAoIBACzcNCozV1fm5ecx
vIx05oUjmTFDVfAPyGp4wkIk2OhR5Dd9bTPPj53S7P5+coni67cAQvZGQDFYj/t3
MtRkhaT8qRwGDEmL+CqefFidewabGdMfye//sOlkO1qUZMNStkvbQQM+95Ypcszb
nq3+/gPx59i+uSg3MXDWLlFand217d8oU4JxmCxHc9ezhkpWsdReiAukWTud+q/5
DzyPetaP09z8Ua/YNXuI6IdsvObYxOSCI1hPPuMSQGM4hQiqkHPqPNBIJDwfM9wk
WzGom5M7nGitrKynJHdS2VRzsZwFL3Hg0yBXnSY1o8er5A6i5//dS2ISSEN9xHjz
9PRRCbECgYEA+yVmv8i5uBLuz/Oeu/iOcX9ZNHfNowuIpInWVyfVhURIc1OwP1Sy
uj5Qst2IY+Hm4IVq0sNg3cZdEk+K6RMyc/Qgd7GoYeJNKH1v0RbA6E1zEzqm8Xv+
jA3dd7RLb5NTwFv11Qh0BDZfw2e8pCmN4oDp+n8fo7RE3NQGaLb77QsCgYEAyDBE
FoYVwXhGaKnhDT1AqM3hkOGBqheJJIxkNUnyMhlU/AxmWtfvTtw7MCP+311bz4Ma
h6yUfaEiHQJs2wkPyIaZ8CbbVyP7bXWMZzA/Rnk4dQWZ/VjRYvEzIvmz9di3w5j6
P1fWX0QODqcY2CvHyMmPLIysbC0cjVDA4ZpDvC0CgYEAlqvrpuevtCV3rL7F3pPS
MXlrdTTi5AyJX91qAEPfr+I1bSsqM/SGfYHhPE34A6SFtPGWEvgwZx0YvWGHPynL
PRGbYPPuxzrTe5U1vkVeWoAMp96qRXpUToYK9kPudfP3bRI+vB4kLFrKvRrBa+Oa
QeeBeE1IGBiQr8NsTOpq3d0CgYB9R+d0iRlYaKL3oUjcdjbe7Wl6uAXjorMLEmks
CEjwHXZX/pKXy4dSPPU1nXFF7DEm3o9d1R1gudSVfw0MztD313TDHC4sjLIuwF/L
vB/9RKOWaJkEOe9gEj7EZqy+8I+gcz45IglguUBq3xvnPQ7ck3dsk+TcFidGMQFk
rpwxSQKBgQDbdzOJagPep0HVJPkOmF1X4idb1rnQUuMi59I3k6lFTXAaypy6nU69
aAUgv7UY4i3XglEhbztk/o51W4/fJ1N8UzbXlBur/pJD8GN2h52ea77CbpOAmDSm
Bjjoj92wmYGfBRf7DwJQDgqxvpa0s1cwtYjNf0RmbDPzBsfzrKLKbQ==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDtTCCAp2gAwIBAgIJAKI8WTrCnPXzMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTUwNDE1MTQxNTI0WhcNNDIwODMxMTQxNTI0WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAxGSSFSDTbBTk2GwkORLCXoBdYq5YxwPfen8bK+8WjxRb9ThpFsHYfImt
DQV0qvcZyWnjUFxRh7Dyw7A2X690nplCdzZ9Gl+5yzzlRefHborMSnNYrnTqx3vs
9qiac0A5bzdjMY7XN3VuVwz0XWY6rAiL/7OxunCNUnQz+oswDx7cj1W4bb9pFzBv
W5TjaAiziyzS3IxvTc7kYQYJEa99vIlDZ+Ov9rHtiF/5CZ8kHc457B3suc9hHxO2
t0EzmBiqg7wpksJjoJeXaJvT9sKSgW6LXkjBCm/7jm1ElPq+7FCph0qpuIsxMtu1
5exLKQaSRLcc+tyNkWIZGQ371D2+7wIDAQABo4GnMIGkMB0GA1UdDgQWBBTQ9mbL
xyIyE3pDyrNMsC36DRHp+TB1BgNVHSMEbjBsgBTQ9mbLxyIyE3pDyrNMsC36DRHp
+aFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAKI8WTrCnPXzMAwGA1UdEwQF
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGyAi//UQaUhy8RLGc33T36Ni6TnRgpz
1xu2aahMe0YfPUZsZwwCP6dK+6fSw7OsRqyXZNZJntlur30yMMDlvjXmV6UDzeS4
/HGd/hr0LqruYpmvOKmvT/y8VkmBqsGlcaRNhSJGDzMHAVEQ0hzAJe3Emw5R753p
iVRbxPqiOVt4U/gjwtrVumSt1v9O4buWo1lTp0jxK1L6K8YWmETLuxyS3IG+i9Ij
DDNyU/UxyocP/mcscUAoV9MJX56exwPC93rPxOlwJT5e5ZMRGnwwUt017dPUrKbA
u+24S8uJCKN2w0OzsrqzC6lvxOf0JRfNxxxGr1KZYyEGT7ps1jhTebA=
-----END CERTIFICATE-----

View File

@ -1,52 +1,54 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIGbDCCBVSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTET MIIEmTCCA4GgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTET
MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
dHkgTHRkMB4XDTE2MDUyNDE3NDIyNVoXDTQzMTAxMDE3NDIyNVowVjELMAkGA1UE dHkgTHRkMB4XDTE2MDkyMzA3MDMyNFoXDTQ0MDIwOTA3MDMyNFowVjELMAkGA1UE
BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp
ZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAxMGYWN0aXZlMIGfMA0GCSqGSIb3DQEBAQUA ZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAxMGYWN0aXZlMIIBIjANBgkqhkiG9w0BAQEF
A4GNADCBiQKBgQC+GTA1D1+yiXgLqUhJXkSj3hj5FiqlBAfJT/8OSXYifY4M4HYv AAOCAQ8AMIIBCgKCAQEAselBnOh089g/VN7gH1m43Vo67kSqh8QRnXZxfjpzt3oP
VQrqER2Fs7jdCaeoGWDvwfK/UOV0b1ROnf+T/2bXFs8EOeqjOz4xG2oexNKVrYj9 Dl5nd04eNey4ezoSBo7o1hKhj/m5KLxmy1kN+xssyutgzto1FZu8GC2jDyLvByNL
ICYAgmSh6Hf2cZJM/YCAISje93Xl2J2w/N7oFC1ZXasPoBIZv3Fgg7hTtQIDAQAB h0Z3XLmzdzBzBjosCtllJtzHlVL08SPuuOId5hToiiT8h3ElgNI4L6w+eLzhZIk5
o4ID2DCCA9QwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5l Rj1WojGa+pnaTEgoOaZPcNrkOj81o1tgnbLXN7HY3hJKnRp78DmPySq82cRhvfNr
cmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFEynWiCoZK4tLDk3KM1wMsbrz9Ug ePCs6BJr3y7yYJk0nG+EOaj5BK95YSJondZ8fOZuCigJPMogEaSw0SGsSUiQrPsd
MB8GA1UdIwQYMBaAFND2ZsvHIjITekPKs0ywLfoNEen5MDMGA1UdHwQsMCowKKAm +3vZQ+3ctOimnhW7cF3fAM79g+zDdv9N9E3D+inhyQIDAQABo4IBgTCCAX0wCQYD
oCSGImh0dHA6Ly9sb2NhbGhvc3Q6NTI4MC9kYXRhL2NybC5kZXIwNgYIKwYBBQUH VR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlm
AQEEKjAoMCYGCCsGAQUFBzABhhpodHRwOi8vbG9jYWxob3N0OjUyODAvb2NzcDAL aWNhdGUwHQYDVR0OBBYEFJgip1fThIyZu9J+YNz3XKDkOcMKMB8GA1UdIwQYMBaA
BgNVHQ8EBAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwkwggLIBgNVHREEggK/MIIC FND2ZsvHIjITekPKs0ywLfoNEen5MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9s
u6A4BggrBgEFBQcIBaAsDCp0ZXN0X3NpbmdsZSEjJCVeKigpYH4rLTtfPVtde318 b2NhbGhvc3Q6NTI4MC9kYXRhL2NybC5kZXIwNgYIKwYBBQUHAQEEKjAoMCYGCCsG
XEBsb2NhbGhvc3SgPwYIKwYBBQUHCAWgMwwxdGVzdF9zaW5nbGUhIyQlXiooKWB+ AQUFBzABhhpodHRwOi8vbG9jYWxob3N0OjUyODAvb2NzcDALBgNVHQ8EBAMCBeAw
Ky07Xz1bXXt9fFxAbW5lc2lhLmxvY2FsaG9zdKA+BggrBgEFBQcIBaAyDDB0ZXN0 JwYDVR0lBCAwHgYIKwYBBQUHAwkGCCsGAQUFBwMBBggrBgEFBQcDAjBfBgNVHREE
X3NpbmdsZSEjJCVeKigpYH4rLTtfPVtde318XEBteXNxbC5sb2NhbGhvc3SgPgYI WDBWoBcGCCsGAQUFBwgFoAsMCWxvY2FsaG9zdKAbBggrBgEFBQcIBaAPDA1zMnMu
KwYBBQUHCAWgMgwwdGVzdF9zaW5nbGUhIyQlXiooKWB+Ky07Xz1bXXt9fFxAcGdz bG9jYWxob3N0oB4GCCsGAQUFBwgFoBIMEG1uZXNpYS5sb2NhbGhvc3QwDQYJKoZI
cWwubG9jYWxob3N0oD8GCCsGAQUFBwgFoDMMMXRlc3Rfc2luZ2xlISMkJV4qKClg hvcNAQEFBQADggEBAEwHeECqeEJIz0VFA0OZ0w9+3rfZPX9K59rbJNNnKVATPhk5
fistO189W117fXxcQHNxbGl0ZS5sb2NhbGhvc3SgQAYIKwYBBQUHCAWgNAwydGVz g5NFpXy1mFTV/3MWjDS1QRbgoXzOYR64S87oez4l3jyDz3YxklyjbbiN3QKaUq5h
dF9zaW5nbGUhIyQlXiooKWB+Ky07Xz1bXXt9fFxAZXh0YXV0aC5sb2NhbGhvc3Sg 284Ze6CiRqxIi6V2bhjjp3voMSP8BQ72bX9uAWjqQl7Z16wYuCzV4QzVZRD5p0c1
PQYIKwYBBQUHCAWgMQwvdGVzdF9zaW5nbGUhIyQlXiooKWB+Ky07Xz1bXXt9fFxA y45WZ6J+sU1GTwEGh0vXZBlDMeTb+53smjEoCxET1ecJmStAvJi+UHiLn63Z3Yzz
bGRhcC5sb2NhbGhvc3SgPQYIKwYBBQUHCAWgMQwvdGVzdF9zaW5nbGUhIyQlXioo CTfdAZ/mj+ytaNLVsgrULXrmZAeo064HVqeyLWL8ZBoM0zLs6u14OQOeDCCB62cj
KWB+Ky07Xz1bXXt9fFxAcDFkYi5sb2NhbGhvc3SgPQYIKwYBBQUHCAWgMQwvdGVz UXb9npKmIdfsWvdii6emCVQqKBQmHnlUMCh56tE=
dF9zaW5nbGUhIyQlXiooKWB+Ky07Xz1bXXt9fFxAcmlhay5sb2NhbGhvc3SgPgYI
KwYBBQUHCAWgMgwwdGVzdF9zaW5nbGUhIyQlXiooKWB+Ky07Xz1bXXt9fFxAcmVk
aXMubG9jYWxob3N0oD4GCCsGAQUFBwgFoDIMMHRlc3Rfc2luZ2xlISMkJV4qKClg
fistO189W117fXxcQG1zc3FsLmxvY2FsaG9zdDANBgkqhkiG9w0BAQUFAAOCAQEA
et4jpmpwlE+2bw+/iqCt7sfU/5nPmQ8YtgMB+32wf7DINNJgkwOdkYJpzhlMXKrh
/bn8+Ybmq6MbK0r2R91Uu858xQf8VKExQm44qaGSyL5Ug3jsAWb3GLZSaWQo37e9
QdDeP8XijCEyr3rum19tRIdiImsRAxJqwfaE4pUSgfCEQMkvb+6//8HSf9RRPToD
o6eAg8QerEtTfxerEdW/0K1ozOrzSrQembWOu+JjvANRl+p59j+1YOWHzS/yQeZl
K3sjFoCvXPvocRnUznvT+TSdy3ORJSjwfEcP5Crim70amZZ6NeMAxfby9wwmmX0x
zkwPCSUXliXke6T88Olj7Q==
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC+GTA1D1+yiXgLqUhJXkSj3hj5FiqlBAfJT/8OSXYifY4M4HYv MIIEpAIBAAKCAQEAselBnOh089g/VN7gH1m43Vo67kSqh8QRnXZxfjpzt3oPDl5n
VQrqER2Fs7jdCaeoGWDvwfK/UOV0b1ROnf+T/2bXFs8EOeqjOz4xG2oexNKVrYj9 d04eNey4ezoSBo7o1hKhj/m5KLxmy1kN+xssyutgzto1FZu8GC2jDyLvByNLh0Z3
ICYAgmSh6Hf2cZJM/YCAISje93Xl2J2w/N7oFC1ZXasPoBIZv3Fgg7hTtQIDAQAB XLmzdzBzBjosCtllJtzHlVL08SPuuOId5hToiiT8h3ElgNI4L6w+eLzhZIk5Rj1W
AoGALddtJJ58eVVlOYqs/+RXsRyR8R9DUV/TcNx1qUBV2KNmafyHA4sCgsd10xQv ojGa+pnaTEgoOaZPcNrkOj81o1tgnbLXN7HY3hJKnRp78DmPySq82cRhvfNrePCs
9D2rzIGyOp8OpswfSSC/t+WqB9+ezSruzMuX6IURdHZbX6aWWX6maICtPKEEkCmI 6BJr3y7yYJk0nG+EOaj5BK95YSJondZ8fOZuCigJPMogEaSw0SGsSUiQrPsd+3vZ
gaLxE/ojuOXnTEBTkVuVWtuFL9PsK/WGi/FIDzJbwqTWJ4ECQQDy9DrBAQM96B6u Q+3ctOimnhW7cF3fAM79g+zDdv9N9E3D+inhyQIDAQABAoIBAQCWIyxVx+36YgGA
G4XpFzBsfgJZoS+NaMdCwK+/jgcEpI6oxobK8tuGB6drp5jNSuQ905W9n8XjA6Xq E927VzIkyqJ0tMncbOAYq/228oj4yy6th4l1Kx1fkHdWtnjDxBJFpc9l+u4ArI1r
x8/GH9I5AkEAyE5g05HhMlxBWCq+P70pBDIamdHJcPQVL8+6NXkT+mTqqZxxkUy4 Cao8wIAadmxp48dshtJC7TBv86EXuvdgH11XiPcknGRVWv4T4cX099gN8cX3QcWR
nMfTh5zE6WfmqYNtrmNBDxXUyaoRSBydXQJACnFnCR7DBekxUGiMc/10LmWoMjQU jHCC3B4phnD9s8RcZAs6X/cQWQU0mxiHodYJefSXDyRIx9wimXmmW83ZqcsFftXS
eC6Vyg/APiqbsJ5mJ2kJKDYSK4uurZjxn3lloCa1HAZ/GgfxHMtj6e86OQJAetq3 MI0+jflmRTf07M4gALVL0LlaBkg2FMoNiaKYPTbubcrEMUgTDsoDsjX3Fi43qLdF
wIwE12KGIZF1xpo6gfxJHHbzWngaVozN5OYyPq2O0CDH9xpbUK2vK8oXbCDx9J5L QTq+lF7HrHQ1EQlngCJupka9JxwZc3Fae6XYlDQvSDPcRxzWJoOuVBPtheGeoU3c
s13lFV+Kd3X7y4LhcQJBAKSFg7ht33l8Sa0TdUkY6Tl1NBMCCLf+np+HYrAbQZux PAry9KihAoGBAN8HCb0k4bMN06WZjSzClKhb6eFw4GMbVpDAOwPDl2N+9+pwrGxE
2NtR6nj2YqeOpEe1ibWZm8tj3dzlTm1FCOIpa+pm114= ztekrM+VdXVScIj23g6wKd6fPqK6EYuEEu3Hre82e9ApqjJ34p1UcOs9Vs4N3VDy
HJnWhEytsc9c03O5nhsK1YAXoGHEPmCYGsg2UA171LDcarnO1WDmpKkNAoGBAMw2
sTCC/LBwgsuPZL5fR10wQ1sr1fIheSL+VK10jSRDwNXT2Y4wdCpQXQ6XNi+n98n5
VvKaE6PxFqjnKCrUUty8X5+fzVcTKpBYVICceEzpVY9FrKbeY1shMnOBRTCkaQwz
8CoEbbQz6SH5s4qW7M8iJdUJ0RulaFDfpmangTStAoGBALMkMxVjZ4rsI0GT2grG
7KNi2LTFducEUX8JeR2n4JUBql78S/LXPhGGa2x9z5ACPPQ23tyLccYowSXyMR+Q
YafuyO4pJEBrBxNsqnDXH7BEX9I43rkjEAgdf70bk4RNOmdtA+sSw7UUxTVibPwn
kPOadKiv+4JoOa2vzkL8X+yNAoGAbU85OUZkC+2tlViEDILjqDYVV8/3DUxtkxWg
LdidVDQQHGTxpvK4u42Ywh6empPGRw54RBPFP5PlFTPmhEZytEUAymi3eUyBFBKz
6MPYgRLFAZPB/vA7LqRuZPVlG8xljmqeu17zeenveIg4Wo6+44Dbz1UZ4TqAxAlz
AK/YsWECgYAPuZnIo9fWJtUAIe5IA2LIqcN0rj3PsZ/tL6eaMXqKZgCYwTvVUGbT
XD4O352t+yLM8v2hJGHrIPuHooN2dCadYuzoBvVFsRTZjGpBlAZ+EJ5WfDYFL0qf
68O2KZNXaSS8ZARlp9g3C8AFiakm/uWhtSfwx09uSBHJgld1V3GAoA==
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----

View File

@ -409,6 +409,7 @@ acl:
user_regexp: "" user_regexp: ""
define_macro: define_macro:
CERTFILE: "cert.pem" CERTFILE: "cert.pem"
CAFILE: "ca.pem"
language: "en" language: "en"
listen: listen:
- -
@ -450,6 +451,10 @@ Welcome to this XMPP server."
mod_time: [] mod_time: []
mod_version: [] mod_version: []
registration_timeout: infinity registration_timeout: infinity
route_subdomains: s2s
domain_certfile: CERTFILE
s2s_use_starttls: false
s2s_cafile: CAFILE
shaper: shaper:
fast: 50000 fast: 50000
normal: 1000 normal: 1000

View File

@ -7,7 +7,10 @@ def read():
cmd = pkt[0] cmd = pkt[0]
args_num = len(pkt) - 1 args_num = len(pkt) - 1
if cmd == 'auth' and args_num >= 3: if cmd == 'auth' and args_num >= 3:
write(True) if pkt[1] == "wrong":
write(False)
else:
write(True)
elif cmd == 'isuser' and args_num == 2: elif cmd == 'isuser' and args_num == 2:
write(True) write(True)
elif cmd == 'setpass' and args_num >= 3: elif cmd == 'setpass' and args_num >= 3:

View File

@ -0,0 +1,18 @@
#!/bin/sh
# Update openssl.cnf if needed (in particular section [alt_names])
rm -rf ssl
mkdir -p ssl/newcerts
touch ssl/index.txt
echo 01 > ssl/serial
echo 1000 > ssl/crlnumber
openssl genrsa -out ssl/client.key
openssl req -new -key ssl/client.key -out ssl/client.csr -config openssl.cnf -batch -subj /C=AU/ST=Some-State/O=Internet\ Widgits\ Pty\ Ltd/CN=active
openssl ca -keyfile ca.key -cert ca.pem -in ssl/client.csr -out ssl/client.crt -config openssl.cnf -days 10000 -batch -notext
openssl req -new -key ssl/client.key -out ssl/self-signed-client.csr -batch -subj /C=AU/ST=Some-State/O=Internet\ Widgits\ Pty\ Ltd/CN=active
openssl x509 -req -in ssl/self-signed-client.csr -signkey ssl/client.key -out ssl/self-signed-client.crt -days 10000
cat ssl/client.crt > cert.pem
cat ssl/self-signed-client.crt > self-signed-cert.pem
cat ssl/client.key >> cert.pem
cat ssl/client.key >> self-signed-cert.pem
rm -rf ssl

View File

@ -0,0 +1,323 @@
#
# OpenSSL example configuration file.
# This is mostly being used for generation of certificate requests.
#
# This definition stops the following lines choking if HOME isn't
# defined.
HOME = .
RANDFILE = $ENV::HOME/.rnd
# Extra OBJECT IDENTIFIER info:
#oid_file = $ENV::HOME/.oid
oid_section = new_oids
# To use this configuration file with the "-extfile" option of the
# "openssl x509" utility, name here the section containing the
# X.509v3 extensions to use:
extensions = v3_req
# (Alternatively, use a configuration file that has only
# X.509v3 extensions in its main [= default] section.)
[ new_oids ]
# We can add new OIDs in here for use by 'ca' and 'req'.
# Add a simple OID like this:
# testoid1=1.2.3.4
# Or use config file substitution like this:
# testoid2=${testoid1}.5.6
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
#dir = ./demoCA # Where everything is kept
dir = ssl
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several ctificates with same subject.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/cacert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
RANDFILE = $dir/private/.rand # private random number file
x509_extensions = usr_cert # The extentions to add to the cert
# Comment out the following two lines for the "traditional"
# (and highly broken) format.
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
# Extension copying option: use with caution.
copy_extensions = copy
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
# so this is commented out by default to leave a V1 CRL.
# crlnumber must also be commented out to leave a V1 CRL.
# crl_extensions = crl_ext
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha1 # which md to use.
preserve = no # keep passed DN ordering
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy = policy_match
# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = optional
emailAddress = optional
# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = optional
emailAddress = optional
####################################################################
[ req ]
default_bits = 1024
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
# Passwords for private keys if not present they will be prompted for
# input_password = secret
# output_password = secret
# This sets a mask for permitted string types. There are several options.
# default: PrintableString, T61String, BMPString.
# pkix : PrintableString, BMPString.
# utf8only: only UTF8Strings.
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
# MASK:XXXX a literal mask value.
# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
# so use this option with caution!
string_mask = nombstr
req_extensions = v3_req # The extensions to add to a certificate request
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = AU
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Some-State
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Internet Widgits Pty Ltd
# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd
organizationalUnitName = Organizational Unit Name (eg, section)
#organizationalUnitName_default =
commonName = Common Name (eg, YOUR name)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
# SET-ex3 = SET extension number 3
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
unstructuredName = An optional company name
[ usr_cert ]
# These extensions are added when 'ca' signs a request.
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints=CA:FALSE
# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
# nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign
# For normal client use this is typical
# nsCertType = client, email
# and for everything including object signing:
# nsCertType = client, email, objsign
# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
# This will be displayed in Netscape's comment listbox.
nsComment = "OpenSSL Generated Certificate"
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move
# Copy subject details
# issuerAltName=issuer:copy
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
#nsBaseUrl
#nsRevocationUrl
#nsRenewalUrl
#nsCaPolicyUrl
#nsSslServerName
crlDistributionPoints = URI:http://localhost:5280/data/crl.der
authorityInfoAccess = OCSP;URI:http://localhost:5280/ocsp
[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = OCSPSigning,serverAuth,clientAuth
subjectAltName = @alt_names
[alt_names]
otherName.1 = 1.3.6.1.5.5.7.8.5;UTF8:"localhost"
otherName.2 = 1.3.6.1.5.5.7.8.5;UTF8:"s2s.localhost"
otherName.3 = 1.3.6.1.5.5.7.8.5;UTF8:"mnesia.localhost"
[ v3_ca ]
crlDistributionPoints = URI:http://localhost:5280/data/crl.der
# Extensions for a typical CA
# PKIX recommendation.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
# This is what PKIX recommends but some broken software chokes on critical
# extensions.
#basicConstraints = critical,CA:true
# So we do this instead.
basicConstraints = CA:true
# Key usage: this is typical for a CA certificate. However since it will
# prevent it being used as an test self-signed certificate it is best
# left out by default.
# keyUsage = cRLSign, keyCertSign
# Some might want this also
# nsCertType = sslCA, emailCA
# Include email address in subject alt name: another PKIX recommendation
# subjectAltName=email:copy
# Copy issuer details
# issuerAltName=issuer:copy
# DER hex encoding of an extension: beware experts only!
# obj=DER:02:03
# Where 'obj' is a standard or added object
# You can even override a supported extension:
# basicConstraints= critical, DER:30:03:01:01:FF
[ crl_ext ]
# CRL extensions.
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
# issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always,issuer:always
[ proxy_cert_ext ]
# These extensions should be added when creating a proxy certificate
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints=CA:FALSE
# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
# nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign
# For normal client use this is typical
# nsCertType = client, email
# and for everything including object signing:
# nsCertType = client, email, objsign
# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
# This will be displayed in Netscape's comment listbox.
nsComment = "OpenSSL Generated Certificate"
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move
# Copy subject details
# issuerAltName=issuer:copy
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
#nsBaseUrl
#nsRevocationUrl
#nsRenewalUrl
#nsCaPolicyUrl
#nsSslServerName
# This really needs to be in place for it to be a proxy certificate.
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo

View File

@ -0,0 +1,46 @@
-----BEGIN CERTIFICATE-----
MIIDKDCCAhACCQCsLYnJDV1wHDANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJB
VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMQ8wDQYDVQQDEwZhY3RpdmUwHhcNMTYwOTIzMDcwMzI0WhcNNDQw
MjA5MDcwMzI0WjBWMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEh
MB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ8wDQYDVQQDEwZhY3Rp
dmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx6UGc6HTz2D9U3uAf
WbjdWjruRKqHxBGddnF+OnO3eg8OXmd3Th417Lh7OhIGjujWEqGP+bkovGbLWQ37
GyzK62DO2jUVm7wYLaMPIu8HI0uHRndcubN3MHMGOiwK2WUm3MeVUvTxI+644h3m
FOiKJPyHcSWA0jgvrD54vOFkiTlGPVaiMZr6mdpMSCg5pk9w2uQ6PzWjW2Cdstc3
sdjeEkqdGnvwOY/JKrzZxGG982t48KzoEmvfLvJgmTScb4Q5qPkEr3lhImid1nx8
5m4KKAk8yiARpLDRIaxJSJCs+x37e9lD7dy06KaeFbtwXd8Azv2D7MN2/030TcP6
KeHJAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAEAIFwHpNCVUiivAcfkxcUPKp0nn
mhGqkMDRrPA7fOCm0ir1Puz4GQ/G4i+tWejzzFoS6kKQl+sUZAUYJdziftJFFoZ7
br3q3Xafc2dWa8SHNcHH6lA1OEk8tXlhkNl+EgSLnRGMhIf0iZL2wGjE8Hlig6cu
3h+OpbUijXUmq0XdH+ui3wNgXb7+Tosg/Od+lr0fNjkopsk3t1oiVXD4OQBZdUyq
V5XValiZjMFDUUBdxBA+l6/Qj3bFmluz+FXI8UwfbinukqADTJzkMeUjEkvmKZWO
tb+EU77NIuvg/k7b1yp4lEmATpdUfcGEuhWNtgeh5AqgMxOhAsJ7zUTA80I=
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAselBnOh089g/VN7gH1m43Vo67kSqh8QRnXZxfjpzt3oPDl5n
d04eNey4ezoSBo7o1hKhj/m5KLxmy1kN+xssyutgzto1FZu8GC2jDyLvByNLh0Z3
XLmzdzBzBjosCtllJtzHlVL08SPuuOId5hToiiT8h3ElgNI4L6w+eLzhZIk5Rj1W
ojGa+pnaTEgoOaZPcNrkOj81o1tgnbLXN7HY3hJKnRp78DmPySq82cRhvfNrePCs
6BJr3y7yYJk0nG+EOaj5BK95YSJondZ8fOZuCigJPMogEaSw0SGsSUiQrPsd+3vZ
Q+3ctOimnhW7cF3fAM79g+zDdv9N9E3D+inhyQIDAQABAoIBAQCWIyxVx+36YgGA
E927VzIkyqJ0tMncbOAYq/228oj4yy6th4l1Kx1fkHdWtnjDxBJFpc9l+u4ArI1r
Cao8wIAadmxp48dshtJC7TBv86EXuvdgH11XiPcknGRVWv4T4cX099gN8cX3QcWR
jHCC3B4phnD9s8RcZAs6X/cQWQU0mxiHodYJefSXDyRIx9wimXmmW83ZqcsFftXS
MI0+jflmRTf07M4gALVL0LlaBkg2FMoNiaKYPTbubcrEMUgTDsoDsjX3Fi43qLdF
QTq+lF7HrHQ1EQlngCJupka9JxwZc3Fae6XYlDQvSDPcRxzWJoOuVBPtheGeoU3c
PAry9KihAoGBAN8HCb0k4bMN06WZjSzClKhb6eFw4GMbVpDAOwPDl2N+9+pwrGxE
ztekrM+VdXVScIj23g6wKd6fPqK6EYuEEu3Hre82e9ApqjJ34p1UcOs9Vs4N3VDy
HJnWhEytsc9c03O5nhsK1YAXoGHEPmCYGsg2UA171LDcarnO1WDmpKkNAoGBAMw2
sTCC/LBwgsuPZL5fR10wQ1sr1fIheSL+VK10jSRDwNXT2Y4wdCpQXQ6XNi+n98n5
VvKaE6PxFqjnKCrUUty8X5+fzVcTKpBYVICceEzpVY9FrKbeY1shMnOBRTCkaQwz
8CoEbbQz6SH5s4qW7M8iJdUJ0RulaFDfpmangTStAoGBALMkMxVjZ4rsI0GT2grG
7KNi2LTFducEUX8JeR2n4JUBql78S/LXPhGGa2x9z5ACPPQ23tyLccYowSXyMR+Q
YafuyO4pJEBrBxNsqnDXH7BEX9I43rkjEAgdf70bk4RNOmdtA+sSw7UUxTVibPwn
kPOadKiv+4JoOa2vzkL8X+yNAoGAbU85OUZkC+2tlViEDILjqDYVV8/3DUxtkxWg
LdidVDQQHGTxpvK4u42Ywh6empPGRw54RBPFP5PlFTPmhEZytEUAymi3eUyBFBKz
6MPYgRLFAZPB/vA7LqRuZPVlG8xljmqeu17zeenveIg4Wo6+44Dbz1UZ4TqAxAlz
AK/YsWECgYAPuZnIo9fWJtUAIe5IA2LIqcN0rj3PsZ/tL6eaMXqKZgCYwTvVUGbT
XD4O352t+yLM8v2hJGHrIPuHooN2dCadYuzoBvVFsRTZjGpBlAZ+EJ5WfDYFL0qf
68O2KZNXaSS8ZARlp9g3C8AFiakm/uWhtSfwx09uSBHJgld1V3GAoA==
-----END RSA PRIVATE KEY-----

View File

@ -27,13 +27,18 @@ init_config(Config) ->
SASLPath = filename:join([PrivDir, "sasl.log"]), SASLPath = filename:join([PrivDir, "sasl.log"]),
MnesiaDir = filename:join([PrivDir, "mnesia"]), MnesiaDir = filename:join([PrivDir, "mnesia"]),
CertFile = filename:join([DataDir, "cert.pem"]), CertFile = filename:join([DataDir, "cert.pem"]),
SelfSignedCertFile = filename:join([DataDir, "self-signed-cert.pem"]),
CAFile = filename:join([DataDir, "ca.pem"]),
{ok, CWD} = file:get_cwd(), {ok, CWD} = file:get_cwd(),
{ok, _} = file:copy(CertFile, filename:join([CWD, "cert.pem"])), {ok, _} = file:copy(CertFile, filename:join([CWD, "cert.pem"])),
{ok, _} = file:copy(SelfSignedCertFile,
filename:join([CWD, "self-signed-cert.pem"])),
{ok, _} = file:copy(CAFile, filename:join([CWD, "ca.pem"])),
{ok, CfgContentTpl} = file:read_file(ConfigPathTpl), {ok, CfgContentTpl} = file:read_file(ConfigPathTpl),
Password = <<"password!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>, Password = <<"password!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>,
CfgContent = process_config_tpl(CfgContentTpl, [ CfgContent = process_config_tpl(CfgContentTpl, [
{c2s_port, 5222}, {c2s_port, 5222},
{loglevel, 5}, {loglevel, 4},
{s2s_port, 5269}, {s2s_port, 5269},
{component_port, 5270}, {component_port, 5270},
{web_port, 5280}, {web_port, 5280},
@ -62,6 +67,7 @@ init_config(Config) ->
[{server_port, ct:get_config(c2s_port, 5222)}, [{server_port, ct:get_config(c2s_port, 5222)},
{server_host, "localhost"}, {server_host, "localhost"},
{component_port, ct:get_config(component_port, 5270)}, {component_port, ct:get_config(component_port, 5270)},
{s2s_port, ct:get_config(s2s_port, 5269)},
{server, ?COMMON_VHOST}, {server, ?COMMON_VHOST},
{user, <<"test_single!#$%^*()`~+-;_=[]{}|\\">>}, {user, <<"test_single!#$%^*()`~+-;_=[]{}|\\">>},
{master_nick, <<"master_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {master_nick, <<"master_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
@ -71,11 +77,14 @@ init_config(Config) ->
{type, client}, {type, client},
{xmlns, ?NS_CLIENT}, {xmlns, ?NS_CLIENT},
{ns_stream, ?NS_STREAM}, {ns_stream, ?NS_STREAM},
{stream_version, <<"1.0">>}, {stream_version, {1, 0}},
{stream_id, <<"">>}, {stream_id, <<"">>},
{stream_from, <<"">>},
{db_xmlns, <<"">>},
{mechs, []}, {mechs, []},
{lang, <<"en">>}, {lang, <<"en">>},
{base_dir, BaseDir}, {base_dir, BaseDir},
{socket, undefined},
{resource, <<"resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {resource, <<"resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
{master_resource, <<"master_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {master_resource, <<"master_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
{slave_resource, <<"slave_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {slave_resource, <<"slave_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
@ -130,42 +139,50 @@ process_config_tpl(Content, [{Name, DefaultValue} | Rest]) ->
process_config_tpl(NewContent, Rest). process_config_tpl(NewContent, Rest).
stream_header(Config) -> stream_header(Config) ->
NSStream = ?config(ns_stream, Config),
XMLNS = ?config(xmlns, Config),
Lang = case ?config(lang, Config) of
<<"">> -> <<"">>;
L -> iolist_to_binary(["xml:lang='", L, "'"])
end,
To = case ?config(server, Config) of To = case ?config(server, Config) of
<<"">> -> <<"">>; <<"">> -> undefined;
Server -> <<"to='", Server/binary, "'">> Server -> jid:make(Server)
end, end,
Version = case ?config(stream_version, Config) of From = case ?config(stream_from, Config) of
<<"">> -> <<"">>; <<"">> -> undefined;
V -> <<"version='", V/binary, "'">> Frm -> jid:make(Frm)
end, end,
io_lib:format("<?xml version='1.0'?><stream:stream " #stream_start{to = To,
"xmlns:stream='~s' xmlns='~s' ~s ~s ~s>", from = From,
[NSStream, XMLNS, To, Version, Lang]). lang = ?config(lang, Config),
version = ?config(stream_version, Config),
xmlns = ?config(xmlns, Config),
db_xmlns = ?config(db_xmlns, Config),
stream_xmlns = ?config(ns_stream, Config)}.
connect(Config) -> connect(Config) ->
NewConfig = init_stream(Config), NewConfig = init_stream(Config),
case ?config(type, NewConfig) of case ?config(type, NewConfig) of
client -> process_stream_features(NewConfig); client -> process_stream_features(NewConfig);
server -> process_stream_features(NewConfig);
component -> NewConfig component -> NewConfig
end. end.
tcp_connect(Config) ->
case ?config(socket, Config) of
undefined ->
{ok, Sock} = ejabberd_socket:connect(
?config(server_host, Config),
?config(server_port, Config),
[binary, {packet, 0}, {active, false}]),
set_opt(socket, Sock, Config);
_ ->
Config
end.
init_stream(Config) -> init_stream(Config) ->
Version = ?config(stream_version, Config), Version = ?config(stream_version, Config),
{ok, Sock} = ejabberd_socket:connect( NewConfig = tcp_connect(Config),
?config(server_host, Config), send(NewConfig, stream_header(NewConfig)),
?config(server_port, Config),
[binary, {packet, 0}, {active, false}]),
NewConfig = set_opt(socket, Sock, Config),
ok = send_text(NewConfig, stream_header(NewConfig)),
XMLNS = case ?config(type, Config) of XMLNS = case ?config(type, Config) of
client -> ?NS_CLIENT; client -> ?NS_CLIENT;
component -> ?NS_COMPONENT component -> ?NS_COMPONENT;
server -> ?NS_SERVER
end, end,
#stream_start{id = ID, xmlns = XMLNS, version = Version} = recv(), #stream_start{id = ID, xmlns = XMLNS, version = Version} = recv(),
set_opt(stream_id, ID, NewConfig). set_opt(stream_id, ID, NewConfig).
@ -206,13 +223,24 @@ close_socket(Config) ->
Config. Config.
starttls(Config) -> starttls(Config) ->
starttls(Config, false).
starttls(Config, ShouldFail) ->
send(Config, #starttls{}), send(Config, #starttls{}),
#starttls_proceed{} = recv(), case recv() of
TLSSocket = ejabberd_socket:starttls( #starttls_proceed{} when ShouldFail ->
?config(socket, Config), ct:fail(starttls_should_have_failed);
[{certfile, ?config(certfile, Config)}, #starttls_failure{} when ShouldFail ->
connect]), Config;
process_stream_features(init_stream(set_opt(socket, TLSSocket, Config))). #starttls_failure{} ->
ct:fail(starttls_failed);
#starttls_proceed{} ->
TLSSocket = ejabberd_socket:starttls(
?config(socket, Config),
[{certfile, ?config(certfile, Config)},
connect]),
set_opt(socket, TLSSocket, Config)
end.
zlib(Config) -> zlib(Config) ->
send(Config, #compress{methods = [<<"zlib">>]}), send(Config, #compress{methods = [<<"zlib">>]}),
@ -228,14 +256,19 @@ auth(Config, ShouldFail) ->
Mechs = ?config(mechs, Config), Mechs = ?config(mechs, Config),
HaveMD5 = lists:member(<<"DIGEST-MD5">>, Mechs), HaveMD5 = lists:member(<<"DIGEST-MD5">>, Mechs),
HavePLAIN = lists:member(<<"PLAIN">>, Mechs), HavePLAIN = lists:member(<<"PLAIN">>, Mechs),
HaveExternal = lists:member(<<"EXTERNAL">>, Mechs),
if HavePLAIN -> if HavePLAIN ->
auth_SASL(<<"PLAIN">>, Config, ShouldFail); auth_SASL(<<"PLAIN">>, Config, ShouldFail);
HaveMD5 -> HaveMD5 ->
auth_SASL(<<"DIGEST-MD5">>, Config, ShouldFail); auth_SASL(<<"DIGEST-MD5">>, Config, ShouldFail);
HaveExternal andalso Type == server ->
auth_SASL(<<"EXTERNAL">>, Config, ShouldFail);
Type == client -> Type == client ->
auth_legacy(Config, false, ShouldFail); auth_legacy(Config, false, ShouldFail);
Type == component -> Type == component ->
auth_component(Config, ShouldFail) auth_component(Config, ShouldFail);
true ->
ct:fail(no_known_sasl_mechanism_available)
end. end.
bind(Config) -> bind(Config) ->
@ -341,10 +374,19 @@ wait_auth_SASL_result(Config, ShouldFail) ->
ct:fail(sasl_auth_should_have_failed); ct:fail(sasl_auth_should_have_failed);
#sasl_success{} -> #sasl_success{} ->
ejabberd_socket:reset_stream(?config(socket, Config)), ejabberd_socket:reset_stream(?config(socket, Config)),
send_text(Config, stream_header(Config)), send(Config, stream_header(Config)),
#stream_start{xmlns = ?NS_CLIENT, version = <<"1.0">>} = recv(), Type = ?config(type, Config),
NS = if Type == client -> ?NS_CLIENT;
Type == server -> ?NS_SERVER
end,
#stream_start{xmlns = NS, version = {1,0}} = recv(),
#stream_features{sub_els = Fs} = recv(), #stream_features{sub_els = Fs} = recv(),
#xmpp_session{optional = true} = lists:keyfind(xmpp_session, 1, Fs), if Type == client ->
#xmpp_session{optional = true} =
lists:keyfind(xmpp_session, 1, Fs);
true ->
ok
end,
lists:foldl( lists:foldl(
fun(#feature_sm{}, ConfigAcc) -> fun(#feature_sm{}, ConfigAcc) ->
set_opt(sm, true, ConfigAcc); set_opt(sm, true, ConfigAcc);
@ -427,7 +469,11 @@ send(State, Pkt) ->
end, end,
El = xmpp_codec:encode(NewPkt), El = xmpp_codec:encode(NewPkt),
ct:pal("sent: ~p <-~n~s", [El, xmpp_codec:pp(NewPkt)]), ct:pal("sent: ~p <-~n~s", [El, xmpp_codec:pp(NewPkt)]),
ok = send_text(State, fxml:element_to_binary(El)), Data = case NewPkt of
#stream_start{} -> fxml:element_to_header(El);
_ -> fxml:element_to_binary(El)
end,
ok = send_text(State, Data),
NewID. NewID.
send_recv(State, IQ) -> send_recv(State, IQ) ->
@ -437,6 +483,9 @@ send_recv(State, IQ) ->
sasl_new(<<"PLAIN">>, User, Server, Password) -> sasl_new(<<"PLAIN">>, User, Server, Password) ->
{<<User/binary, $@, Server/binary, 0, User/binary, 0, Password/binary>>, {<<User/binary, $@, Server/binary, 0, User/binary, 0, Password/binary>>,
fun (_) -> {error, <<"Invalid SASL challenge">>} end}; fun (_) -> {error, <<"Invalid SASL challenge">>} end};
sasl_new(<<"EXTERNAL">>, _User, _Server, _Password) ->
{<<"">>,
fun(_) -> ct:fail(sasl_challenge_is_not_expected) end};
sasl_new(<<"DIGEST-MD5">>, User, Server, Password) -> sasl_new(<<"DIGEST-MD5">>, User, Server, Password) ->
{<<"">>, {<<"">>,
fun (ServerIn) -> fun (ServerIn) ->
@ -567,11 +616,21 @@ set_opt(Opt, Val, Config) ->
wait_for_master(Config) -> wait_for_master(Config) ->
put_event(Config, slave_ready), put_event(Config, slave_ready),
master_ready = get_event(Config). case get_event(Config) of
master_ready ->
ok;
Other ->
suite:match_failure([Other], [master_ready])
end.
wait_for_slave(Config) -> wait_for_slave(Config) ->
put_event(Config, master_ready), put_event(Config, master_ready),
slave_ready = get_event(Config). case get_event(Config) of
slave_ready ->
ok;
Other ->
suite:match_failure([Other], [slave_ready])
end.
make_iq_result(#iq{from = From} = IQ) -> make_iq_result(#iq{from = From} = IQ) ->
IQ#iq{type = result, to = From, from = undefined, sub_els = []}. IQ#iq{type = result, to = From, from = undefined, sub_els = []}.
@ -592,6 +651,7 @@ event_relay() ->
event_relay(Events, Subscribers) -> event_relay(Events, Subscribers) ->
receive receive
{subscribe, From} -> {subscribe, From} ->
erlang:monitor(process, From),
From ! {ok, self()}, From ! {ok, self()},
lists:foreach( lists:foreach(
fun(Event) -> From ! {event, Event, self()} fun(Event) -> From ! {event, Event, self()}
@ -605,7 +665,14 @@ event_relay(Events, Subscribers) ->
(_) -> (_) ->
ok ok
end, Subscribers), end, Subscribers),
event_relay([Event|Events], Subscribers) event_relay([Event|Events], Subscribers);
{'DOWN', _MRef, process, Pid, _Info} ->
NewSubscribers = lists:delete(Pid, Subscribers),
lists:foreach(
fun(Subscriber) ->
Subscriber ! {event, peer_down, self()}
end, NewSubscribers),
event_relay(Events, NewSubscribers)
end. end.
subscribe_to_events(Config) -> subscribe_to_events(Config) ->

View File

@ -75,6 +75,7 @@
-define(LDAP_VHOST, <<"ldap.localhost">>). -define(LDAP_VHOST, <<"ldap.localhost">>).
-define(EXTAUTH_VHOST, <<"extauth.localhost">>). -define(EXTAUTH_VHOST, <<"extauth.localhost">>).
-define(RIAK_VHOST, <<"riak.localhost">>). -define(RIAK_VHOST, <<"riak.localhost">>).
-define(S2S_VHOST, <<"s2s.localhost">>).
insert(Val, N, Tuple) -> insert(Val, N, Tuple) ->
L = tuple_to_list(Tuple), L = tuple_to_list(Tuple),

View File

@ -3215,7 +3215,9 @@
default = <<"">>}, default = <<"">>},
#attr{name = <<"xml:lang">>, label = '$lang', #attr{name = <<"xml:lang">>, label = '$lang',
default = <<"">>}, default = <<"">>},
#attr{name = <<"version">>, default = <<"">>}, #attr{name = <<"version">>,
dec = {dec_version, []},
enc = {enc_version, []}},
#attr{name = <<"id">>, default = <<"">>}]}). #attr{name = <<"id">>, default = <<"">>}]}).
-xml(bob_data, -xml(bob_data,
@ -3479,6 +3481,14 @@ enc_host_port({Host, Port}) ->
enc_host_port(Addr) -> enc_host_port(Addr) ->
enc_ip(Addr). enc_ip(Addr).
-spec dec_version(_) -> {non_neg_integer(), non_neg_integer()}.
dec_version(S) ->
[Major, Minor] = binary:split(S, <<$.>>),
{binary_to_integer(Major), binary_to_integer(Minor)}.
enc_version({Maj, Min}) ->
<<(integer_to_binary(Maj))/binary, $., (integer_to_binary(Min))/binary>>.
%% Local Variables: %% Local Variables:
%% mode: erlang %% mode: erlang
%% End: %% End: