diff --git a/ChangeLog b/ChangeLog index 509d4ce67..8b9a029d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,13 @@ +2008-12-08 Mickael Remond + + * src/ejabberd_c2s.erl: Enforce client stanza from attribute + (EJAB-812). + * src/jlib.erl: Likewise. + 2008-12-01 Badlop * doc/guide.tex: New subsection Database Connection - * doc/guide.html: Likewise + * doc/guide.html: Like wise 2008-12-01 Christophe Romain diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 0d6b7747d..b147aba28 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -62,6 +62,8 @@ -define(SETS, gb_sets). -define(DICT, dict). +%% pres_a contains all the presence available send (either through roster mechanism or directed). +%% Directed presence unavailable remove user from pres_a. -record(state, {socket, sockmod, socket_monitor, @@ -131,6 +133,9 @@ xml:element_to_string(?SERR_HOST_UNKNOWN)). -define(POLICY_VIOLATION_ERR(Lang, Text), xml:element_to_string(?SERRT_POLICY_VIOLATION(Lang, Text))). +-define(INVALID_FROM, + xml:element_to_string(?SERR_INVALID_FROM)). + %%%---------------------------------------------------------------------- %%% API @@ -861,13 +866,41 @@ wait_for_session(closed, StateData) -> {stop, normal, StateData}. - - session_established({xmlstreamelement, El}, StateData) -> + FromJID = StateData#state.jid, + % Check 'from' attribute in stanza RFC 3920 Section 9.1.2 + case check_from(El, FromJID) of + 'invalid-from' -> + send_text(StateData, ?INVALID_FROM ++ ?STREAM_TRAILER), + {stop, normal, StateData}; + _NewEl -> + session_established2(El, StateData) + end; + +%% We hibernate the process to reduce memory consumption after a +%% configurable activity timeout +session_established(timeout, StateData) -> + %% TODO: Options must be stored in state: + Options = [], + proc_lib:hibernate(gen_fsm, enter_loop, + [?MODULE, Options, session_established, StateData]), + fsm_next_state(session_established, StateData); + +session_established({xmlstreamend, _Name}, StateData) -> + send_text(StateData, ?STREAM_TRAILER), + {stop, normal, StateData}; + +session_established({xmlstreamerror, _}, StateData) -> + send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), + {stop, normal, StateData}; + +session_established(closed, StateData) -> + {stop, normal, StateData}. + +session_established2(El, StateData) -> {xmlelement, Name, Attrs, _Els} = El, User = StateData#state.user, Server = StateData#state.server, - % TODO: check 'from' attribute in stanza FromJID = StateData#state.jid, To = xml:get_attr_s("to", Attrs), ToJID = case To of @@ -943,27 +976,7 @@ session_established({xmlstreamelement, El}, StateData) -> end end, ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, El}]), - fsm_next_state(session_established, NewState); - -%% We hibernate the process to reduce memory consumption after a -%% configurable activity timeout -session_established(timeout, StateData) -> - %% TODO: Options must be stored in state: - Options = [], - proc_lib:hibernate(gen_fsm, enter_loop, - [?MODULE, Options, session_established, StateData]), - fsm_next_state(session_established, StateData); - -session_established({xmlstreamend, _Name}, StateData) -> - send_text(StateData, ?STREAM_TRAILER), - {stop, normal, StateData}; - -session_established({xmlstreamerror, _}, StateData) -> - send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), - {stop, normal, StateData}; - -session_established(closed, StateData) -> - {stop, normal, StateData}. + fsm_next_state(session_established, NewState). @@ -1984,3 +1997,32 @@ fsm_reply(Reply, StateName, StateData) -> %% Used by c2s blacklist plugins is_ip_blacklisted({IP,_Port}) -> ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]). + +%% Check from attributes +%% returns invalid-from|NewElement +check_from(El, FromJID) -> + case xml:get_tag_attr("from", El) of + false -> + jlib:replace_from(FromJID, El); + {value, JIDElString} -> + JIDEl = jlib:string_to_jid(JIDElString), + case JIDEl#jid.lresource of + "" -> + %% Matching JID: The stanza is ok + if JIDEl#jid.luser == FromJID#jid.luser andalso + JIDEl#jid.lserver == FromJID#jid.lserver -> + El; + true -> + 'invalid-from' + end; + _ -> + %% Matching JID: The stanza is ok + if JIDEl#jid.luser == FromJID#jid.luser andalso + JIDEl#jid.lserver == FromJID#jid.lserver andalso + JIDEl#jid.lresource == FromJID#jid.lresource -> + El; + true -> + 'invalid-from' + end + end + end. diff --git a/src/jlib.erl b/src/jlib.erl index 70f190a93..765457a5b 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -34,6 +34,8 @@ make_correct_from_to_attrs/3, replace_from_to_attrs/3, replace_from_to/3, + replace_from_attrs/2, + replace_from/2, remove_attr/2, make_jid/3, make_jid/1, @@ -153,6 +155,13 @@ replace_from_to(From, To, {xmlelement, Name, Attrs, Els}) -> Attrs), {xmlelement, Name, NewAttrs, Els}. +replace_from_attrs(From, Attrs) -> + Attrs1 = lists:keydelete("from", 1, Attrs), + [{"from", From} | Attrs1]. + +replace_from(From, {xmlelement, Name, Attrs, Els}) -> + NewAttrs = replace_from_attrs(jlib:jid_to_string(From), Attrs), + {xmlelement, Name, NewAttrs, Els}. remove_attr(Attr, {xmlelement, Name, Attrs, Els}) -> NewAttrs = lists:keydelete(Attr, 1, Attrs),