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