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

github.com/processone/ejabberd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
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
parent5c85106a41cffd52f68471597a1eb597e38bfdcd (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.
-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 4a552f43c..1ec45a3e2 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 e7ce7b910..1e81f4d1a 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 f898936f5..5ec2556f6 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 025dc2962..5345727a2 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 7b3543ae2..7016cd77d 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 ec7376e1d..8d530e5c8 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 6db1e4529..e9da1d9c7 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 350a2db37..9822e81fd 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 8e8f57171..97033bafb 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 d9f66843e..6b32fc98c 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 8f2f446ee..ceed74d31 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 6e07e9006..4f8be911e 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 ce67d4231..b2367a09b 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