summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>2018-02-09 18:12:50 +0300
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>2018-02-09 18:12:50 +0300
commit672c2f75d3ebd659c514b0ce1ecc70ecaa99f31f (patch)
tree92111588ed1c5d5877dac12d348652cb87b44f6c /src
parentFix type spec (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/ejabberd_bosh.erl3
-rw-r--r--src/ejabberd_c2s.erl4
-rw-r--r--src/ejabberd_config.erl14
-rw-r--r--src/ejabberd_s2s_in.erl3
-rw-r--r--src/ejabberd_service.erl15
-rw-r--r--src/mod_admin_extra.erl3
-rw-r--r--src/mod_announce.erl6
-rw-r--r--src/mod_delegation.erl3
-rw-r--r--src/mod_mam.erl3
-rw-r--r--src/mod_offline.erl6
-rw-r--r--src/mod_privilege.erl3
-rw-r--r--src/xmpp_stream_in.erl5
-rw-r--r--src/xmpp_stream_out.erl5
13 files changed, 49 insertions, 24 deletions
diff --git a/src/ejabberd_bosh.erl b/src/ejabberd_bosh.erl
index 4a552f43..1ec45a3e 100644
--- a/src/ejabberd_bosh.erl
+++ b/src/ejabberd_bosh.erl
@@ -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{}} ->
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index e7ce7b91..1e81f4d1 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -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) ->
diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl
index f898936f..5ec2556f 100644
--- a/src/ejabberd_config.erl
+++ b/src/ejabberd_config.erl
@@ -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.
diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl
index 025dc296..5345727a 100644
--- a/src/ejabberd_s2s_in.erl
+++ b/src/ejabberd_s2s_in.erl
@@ -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) ->
diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl
index 7b3543ae..7016cd77 100644
--- a/src/ejabberd_service.erl
+++ b/src/ejabberd_service.erl
@@ -116,22 +116,23 @@ handle_stream_start(_StreamStart,
lang := Lang,
host_opts := HostOpts} = State) ->
case ejabberd_router:is_my_host(RemoteServer) of
- true ->
+ true ->
Txt = <<"Unable to register route on existing local domain">>,
xmpp_stream_in:send(State, xmpp:serr_conflict(Txt, Lang));
- false ->
+ false ->
NewHostOpts = case dict:is_key(RemoteServer, HostOpts) of
true ->
HostOpts;
false ->
case dict:find(global, HostOpts) of
- {ok, GlobalPass} ->
+ {ok, GlobalPass} ->
dict:from_list([{RemoteServer, GlobalPass}]);
- error ->
+ error ->
HostOpts
- end
- end,
- State#{host_opts => NewHostOpts}
+ end
+ end,
+ CodecOpts = ejabberd_config:codec_options(global),
+ State#{host_opts => NewHostOpts, codec_options => CodecOpts}
end.
get_password_fun(#{remote_server := RemoteServer,
diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl
index ec7376e1..8d530e5c 100644
--- a/src/mod_admin_extra.erl
+++ b/src/mod_admin_extra.erl
@@ -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)]),
diff --git a/src/mod_announce.erl b/src/mod_announce.erl
index 6db1e452..e9da1d9c 100644
--- a/src/mod_announce.erl
+++ b/src/mod_announce.erl
@@ -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} ->
diff --git a/src/mod_delegation.erl b/src/mod_delegation.erl
index 350a2db3..9822e81f 100644
--- a/src/mod_delegation.erl
+++ b/src/mod_delegation.erl
@@ -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)
diff --git a/src/mod_mam.erl b/src/mod_mam.erl
index 8e8f5717..97033baf 100644
--- a/src/mod_mam.erl
+++ b/src/mod_mam.erl
@@ -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(
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index d9f66843..6b32fc98 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -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),
diff --git a/src/mod_privilege.erl b/src/mod_privilege.erl
index 8f2f446e..ceed74d3 100644
--- a/src/mod_privilege.erl
+++ b/src/mod_privilege.erl
@@ -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} ->
diff --git a/src/xmpp_stream_in.erl b/src/xmpp_stream_in.erl
index 6e07e900..4f8be911 100644
--- a/src/xmpp_stream_in.erl
+++ b/src/xmpp_stream_in.erl
@@ -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
diff --git a/src/xmpp_stream_out.erl b/src/xmpp_stream_out.erl
index ce67d423..b2367a09 100644
--- a/src/xmpp_stream_out.erl
+++ b/src/xmpp_stream_out.erl
@@ -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