diff options
author | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2018-02-09 18:12:50 +0300 |
---|---|---|
committer | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2018-02-09 18:12:50 +0300 |
commit | 672c2f75d3ebd659c514b0ce1ecc70ecaa99f31f (patch) | |
tree | 92111588ed1c5d5877dac12d348652cb87b44f6c /src | |
parent | Fix 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.erl | 3 | ||||
-rw-r--r-- | src/ejabberd_c2s.erl | 4 | ||||
-rw-r--r-- | src/ejabberd_config.erl | 14 | ||||
-rw-r--r-- | src/ejabberd_s2s_in.erl | 3 | ||||
-rw-r--r-- | src/ejabberd_service.erl | 15 | ||||
-rw-r--r-- | src/mod_admin_extra.erl | 3 | ||||
-rw-r--r-- | src/mod_announce.erl | 6 | ||||
-rw-r--r-- | src/mod_delegation.erl | 3 | ||||
-rw-r--r-- | src/mod_mam.erl | 3 | ||||
-rw-r--r-- | src/mod_offline.erl | 6 | ||||
-rw-r--r-- | src/mod_privilege.erl | 3 | ||||
-rw-r--r-- | src/xmpp_stream_in.erl | 5 | ||||
-rw-r--r-- | src/xmpp_stream_out.erl | 5 |
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 |