mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-22 16:20:52 +01:00
Introduce option 'validate_stream'
If set to `true`, all incoming XML packets are fully validated against known schemas. If an error occurs, the packet will be bounced with the corresponding error reason. The default value is `false`. The option might be useful to protect client software from sofisticated bugs related to XML validation as well as for client developers who want to catch validation errors at early stage of development. Note that the option might have slight performance impact, so use it with care on loaded machines.
This commit is contained in:
parent
5c85106a41
commit
672c2f75d3
@ -739,9 +739,10 @@ bounce_receivers(State, Reason) ->
|
||||
State, Receivers ++ ShapedReceivers).
|
||||
|
||||
bounce_els_from_obuf(State) ->
|
||||
Opts = ejabberd_config:codec_options(State#state.host),
|
||||
p1_queue:foreach(
|
||||
fun({xmlstreamelement, El}) ->
|
||||
try xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of
|
||||
try xmpp:decode(El, ?NS_CLIENT, Opts) of
|
||||
Pkt when ?is_stanza(Pkt) ->
|
||||
case {xmpp:get_from(Pkt), xmpp:get_to(Pkt)} of
|
||||
{#jid{}, #jid{}} ->
|
||||
|
@ -418,8 +418,10 @@ handle_stream_start(StreamStart, #{lserver := LServer} = State) ->
|
||||
send(State#{lserver => ?MYNAME}, xmpp:serr_host_unknown());
|
||||
true ->
|
||||
State1 = change_shaper(State),
|
||||
Opts = ejabberd_config:codec_options(LServer),
|
||||
State2 = State1#{codec_options => Opts},
|
||||
ejabberd_hooks:run_fold(
|
||||
c2s_stream_started, LServer, State1, [StreamStart])
|
||||
c2s_stream_started, LServer, State2, [StreamStart])
|
||||
end.
|
||||
|
||||
handle_stream_end(Reason, #{lserver := LServer} = State) ->
|
||||
|
@ -36,7 +36,8 @@
|
||||
is_elixir_enabled/0, v_dbs/1, v_dbs_mods/1,
|
||||
default_db/1, default_db/2, default_ram_db/1, default_ram_db/2,
|
||||
default_queue_type/1, queue_dir/0, fsm_limit_opts/1,
|
||||
use_cache/1, cache_size/1, cache_missed/1, cache_life_time/1]).
|
||||
use_cache/1, cache_size/1, cache_missed/1, cache_life_time/1,
|
||||
codec_options/1]).
|
||||
|
||||
-export([start/2]).
|
||||
|
||||
@ -1418,11 +1419,13 @@ opt_type(shared_key) ->
|
||||
fun iolist_to_binary/1;
|
||||
opt_type(node_start) ->
|
||||
fun(I) when is_integer(I), I>=0 -> I end;
|
||||
opt_type(validate_stream) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
opt_type(_) ->
|
||||
[hide_sensitive_log_data, hosts, language, max_fsm_queue,
|
||||
default_db, default_ram_db, queue_type, queue_dir, loglevel,
|
||||
use_cache, cache_size, cache_missed, cache_life_time,
|
||||
shared_key, node_start].
|
||||
shared_key, node_start, validate_stream].
|
||||
|
||||
-spec may_hide_data(any()) -> any().
|
||||
may_hide_data(Data) ->
|
||||
@ -1469,3 +1472,10 @@ cache_missed(Host) ->
|
||||
%% NOTE: the integer value returned is in *seconds*
|
||||
cache_life_time(Host) ->
|
||||
get_option({cache_life_time, Host}, 3600).
|
||||
|
||||
-spec codec_options(binary() | global) -> [xmpp:decode_option()].
|
||||
codec_options(Host) ->
|
||||
case get_option({validate_stream, Host}, false) of
|
||||
true -> [];
|
||||
false -> [ignore_els]
|
||||
end.
|
||||
|
@ -169,7 +169,8 @@ handle_stream_start(_StreamStart, #{lserver := LServer} = State) ->
|
||||
send(State, xmpp:serr_host_unknown());
|
||||
true ->
|
||||
ServerHost = ejabberd_router:host_of_route(LServer),
|
||||
State#{server_host => ServerHost}
|
||||
Opts = ejabberd_config:codec_options(LServer),
|
||||
State#{server_host => ServerHost, codec_options => Opts}
|
||||
end.
|
||||
|
||||
handle_stream_end(Reason, #{server_host := LServer} = State) ->
|
||||
|
@ -131,7 +131,8 @@ handle_stream_start(_StreamStart,
|
||||
HostOpts
|
||||
end
|
||||
end,
|
||||
State#{host_opts => NewHostOpts}
|
||||
CodecOpts = ejabberd_config:codec_options(global),
|
||||
State#{host_opts => NewHostOpts, codec_options => CodecOpts}
|
||||
end.
|
||||
|
||||
get_password_fun(#{remote_server := RemoteServer,
|
||||
|
@ -1549,7 +1549,8 @@ send_stanza(FromString, ToString, Stanza) ->
|
||||
#xmlel{} = El = fxml_stream:parse_element(Stanza),
|
||||
From = jid:decode(FromString),
|
||||
To = jid:decode(ToString),
|
||||
Pkt = xmpp:decode(El, ?NS_CLIENT, [ignore_els]),
|
||||
CodecOpts = ejabberd_config:codec_options(From#jid.lserver),
|
||||
Pkt = xmpp:decode(El, ?NS_CLIENT, CodecOpts),
|
||||
ejabberd_router:route(xmpp:set_from_to(Pkt, From, To))
|
||||
catch _:{xmpp_codec, Why} ->
|
||||
io:format("incorrect stanza: ~s~n", [xmpp:format_error(Why)]),
|
||||
|
@ -715,7 +715,8 @@ send_motd({#presence{type = available},
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
case get_motd(Mod, LServer) of
|
||||
{ok, Packet} ->
|
||||
try xmpp:decode(Packet, ?NS_CLIENT, [ignore_els]) of
|
||||
CodecOpts = ejabberd_config:codec_options(LServer),
|
||||
try xmpp:decode(Packet, ?NS_CLIENT, CodecOpts) of
|
||||
Msg ->
|
||||
case is_motd_user(Mod, LUser, LServer) of
|
||||
false ->
|
||||
@ -806,7 +807,8 @@ get_stored_motd(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
case get_motd(Mod, LServer) of
|
||||
{ok, Packet} ->
|
||||
try xmpp:decode(Packet, ?NS_CLIENT, [ignore_els]) of
|
||||
CodecOpts = ejabberd_config:codec_options(LServer),
|
||||
try xmpp:decode(Packet, ?NS_CLIENT, CodecOpts) of
|
||||
#message{body = Body, subject = Subject} ->
|
||||
{xmpp:get_text(Subject), xmpp:get_text(Body)}
|
||||
catch _:{xmpp_codec, Why} ->
|
||||
|
@ -261,9 +261,10 @@ process_iq(#iq{to = To, lang = Lang, sub_els = [SubEl]} = IQ, Type) ->
|
||||
process_iq_result(#iq{from = From, to = To, id = ID, lang = Lang} = IQ,
|
||||
#iq{type = result} = ResIQ) ->
|
||||
try
|
||||
CodecOpts = ejabberd_config:codec_options(To#jid.lserver),
|
||||
#delegation{forwarded = #forwarded{sub_els = [SubEl]}} =
|
||||
xmpp:get_subtag(ResIQ, #delegation{}),
|
||||
case xmpp:decode(SubEl, ?NS_CLIENT, [ignore_els]) of
|
||||
case xmpp:decode(SubEl, ?NS_CLIENT, CodecOpts) of
|
||||
#iq{from = To, to = From, type = Type, id = ID} = Reply
|
||||
when Type == error; Type == result ->
|
||||
ejabberd_router:route(Reply)
|
||||
|
@ -918,7 +918,8 @@ select(LServer, JidRequestor, JidArchive, Query, RSM, MsgType) ->
|
||||
msg_to_el(#archive_msg{timestamp = TS, packet = El, nick = Nick,
|
||||
peer = Peer, id = ID},
|
||||
MsgType, JidRequestor, #jid{lserver = LServer} = JidArchive) ->
|
||||
try xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of
|
||||
CodecOpts = ejabberd_config:codec_options(LServer),
|
||||
try xmpp:decode(El, ?NS_CLIENT, CodecOpts) of
|
||||
Pkt1 ->
|
||||
Pkt2 = set_stanza_id(Pkt1, JidArchive, ID),
|
||||
Pkt3 = maybe_update_from_to(
|
||||
|
@ -596,7 +596,8 @@ get_offline_els(LUser, LServer) ->
|
||||
-spec offline_msg_to_route(binary(), #offline_msg{}) ->
|
||||
{route, message()} | error.
|
||||
offline_msg_to_route(LServer, #offline_msg{from = From, to = To} = R) ->
|
||||
try xmpp:decode(R#offline_msg.packet, ?NS_CLIENT, [ignore_els]) of
|
||||
CodecOpts = ejabberd_config:codec_options(LServer),
|
||||
try xmpp:decode(R#offline_msg.packet, ?NS_CLIENT, CodecOpts) of
|
||||
Pkt ->
|
||||
Pkt1 = xmpp:set_from_to(Pkt, From, To),
|
||||
Pkt2 = add_delay_info(Pkt1, LServer, R#offline_msg.timestamp),
|
||||
@ -611,10 +612,11 @@ offline_msg_to_route(LServer, #offline_msg{from = From, to = To} = R) ->
|
||||
-spec read_messages(binary(), binary()) -> [{binary(), message()}].
|
||||
read_messages(LUser, LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
CodecOpts = ejabberd_config:codec_options(LServer),
|
||||
lists:flatmap(
|
||||
fun({Seq, From, To, TS, El}) ->
|
||||
Node = integer_to_binary(Seq),
|
||||
try xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of
|
||||
try xmpp:decode(El, ?NS_CLIENT, CodecOpts) of
|
||||
Pkt ->
|
||||
Node = integer_to_binary(Seq),
|
||||
Pkt1 = add_delay_info(Pkt, LServer, TS),
|
||||
|
@ -276,9 +276,10 @@ get_permissions(ServerHost) ->
|
||||
forward_message(#message{to = To} = Msg) ->
|
||||
ServerHost = To#jid.lserver,
|
||||
Lang = xmpp:get_lang(Msg),
|
||||
CodecOpts = ejabberd_config:codec_options(ServerHost),
|
||||
try xmpp:try_subtag(Msg, #privilege{}) of
|
||||
#privilege{forwarded = #forwarded{sub_els = [SubEl]}} ->
|
||||
try xmpp:decode(SubEl, ?NS_CLIENT, [ignore_els]) of
|
||||
try xmpp:decode(SubEl, ?NS_CLIENT, CodecOpts) of
|
||||
#message{} = NewMsg ->
|
||||
case NewMsg#message.from of
|
||||
#jid{lresource = <<"">>, lserver = ServerHost} ->
|
||||
|
@ -230,6 +230,7 @@ init([Module, {_SockMod, Socket}, Opts]) ->
|
||||
stream_encrypted => Encrypted,
|
||||
stream_version => {1,0},
|
||||
stream_authenticated => false,
|
||||
codec_options => [ignore_els],
|
||||
xmlns => ?NS_CLIENT,
|
||||
lang => <<"">>,
|
||||
user => <<"">>,
|
||||
@ -342,9 +343,9 @@ handle_info({'$gen_event', El}, #{stream_state := wait_for_stream} = State) ->
|
||||
false -> send_pkt(State1, xmpp:serr_invalid_xml())
|
||||
end);
|
||||
handle_info({'$gen_event', {xmlstreamelement, El}},
|
||||
#{xmlns := NS, mod := Mod} = State) ->
|
||||
#{xmlns := NS, mod := Mod, codec_options := Opts} = State) ->
|
||||
noreply(
|
||||
try xmpp:decode(El, NS, [ignore_els]) of
|
||||
try xmpp:decode(El, NS, Opts) of
|
||||
Pkt ->
|
||||
State1 = try Mod:handle_recv(El, Pkt, State)
|
||||
catch _:undef -> State
|
||||
|
@ -244,6 +244,7 @@ init([Mod, _SockMod, From, To, Opts]) ->
|
||||
lang => <<"">>,
|
||||
remote_server => To,
|
||||
xmlns => ?NS_SERVER,
|
||||
codec_options => [ignore_els],
|
||||
stream_direction => out,
|
||||
stream_timeout => {timer:seconds(30), Time},
|
||||
stream_id => new_id(),
|
||||
@ -347,9 +348,9 @@ handle_info({'$gen_event', {xmlstreamerror, Reason}}, #{lang := Lang}= State) ->
|
||||
send_pkt(State1, Err)
|
||||
end);
|
||||
handle_info({'$gen_event', {xmlstreamelement, El}},
|
||||
#{xmlns := NS, mod := Mod} = State) ->
|
||||
#{xmlns := NS, mod := Mod, codec_options := Opts} = State) ->
|
||||
noreply(
|
||||
try xmpp:decode(El, NS, [ignore_els]) of
|
||||
try xmpp:decode(El, NS, Opts) of
|
||||
Pkt ->
|
||||
State1 = try Mod:handle_recv(El, Pkt, State)
|
||||
catch _:undef -> State
|
||||
|
Loading…
Reference in New Issue
Block a user