1
0
Fork 0
mirror of https://github.com/processone/ejabberd synced 2025-10-03 09:49:18 +02:00

mod_privilege: Accept non-privileged IQs from privileged components.

mod_privilege current drops any non-privileged IQ received from a component
with an error about it not being properly wrapped. While this might
represent a mistake on the part of the component, it means that well-
behaved components can no longer send non-privileged IQs (something they
normally can do if mod_privilege isn't enabled).

Since mod_privilege is intended to grant additional permissions, and not
remove existing ones, route non-privileged IQs received from the component
normally.

This also removes the special-case for roster-query IQ stanzas, since
those are also non-privileged and will be routed along with any other
non-privileged IQ packet. This mirrors the privileged-IQ/everything-else
structure of the XEP, which defined the handling of privileged IQ
stanzas and leaves all other IQ stanzas as defined in their own specs.

To make this clearer, the predicate function now returns distinct
results indicating privileged IQs, non-privileged IQs, and error
conditions, rather than treating non-privilege IQs as an error that gets
handled by routing the packet normally.
This commit is contained in:
Matthew Stickney 2025-01-18 13:57:26 -05:00
parent 76baf58d5d
commit a4062f6ac0

View file

@ -272,7 +272,7 @@ component_send_packet({#iq{from = From,
Permissions = get_permissions(ServerHost), Permissions = get_permissions(ServerHost),
Result = Result =
case {maps:find(Host, Permissions), get_iq_encapsulated_details(IQ)} of case {maps:find(Host, Permissions), get_iq_encapsulated_details(IQ)} of
{{ok, Access}, {ok, EncapType, EncapNs, EncapFrom, EncIq}} {{ok, Access}, {privileged_iq, EncapType, EncapNs, EncapFrom, EncIq}}
when (EncapType == Type) and ((EncapFrom == undefined) or (EncapFrom == To)) -> when (EncapType == Type) and ((EncapFrom == undefined) or (EncapFrom == To)) ->
NsPermissions = proplists:get_value(iq, Access, []), NsPermissions = proplists:get_value(iq, Access, []),
Permission = Permission =
@ -297,20 +297,18 @@ component_send_packet({#iq{from = From,
%% Component is disconnected %% Component is disconnected
?INFO_MSG("IQ not forwarded: Component seems disconnected", []), ?INFO_MSG("IQ not forwarded: Component seems disconnected", []),
drop; drop;
{_, {ok, E, _, _, _}} when E /= Type -> {_, {privileged_iq, E, _, _, _}} when E /= Type ->
?INFO_MSG("IQ not forwarded: The encapsulated IQ stanza type=~p " ?INFO_MSG("IQ not forwarded: The encapsulated IQ stanza type=~p "
"does not match the top-level IQ stanza type=~p", "does not match the top-level IQ stanza type=~p",
[E, Type]), [E, Type]),
drop; drop;
{_, {ok, _, _, EF, _}} when (EF /= undefined) and (EF /= To) -> {_, {privileged_iq, _, _, EF, _}} when (EF /= undefined) and (EF /= To) ->
?INFO_MSG("IQ not forwarded: The FROM attribute in the encapsulated " ?INFO_MSG("IQ not forwarded: The FROM attribute in the encapsulated "
"IQ stanza and the TO in top-level IQ stanza do not match", "IQ stanza and the TO in top-level IQ stanza do not match",
[]), []),
drop; drop;
{_, {error, no_privileged_iq, _Err}} -> {_, {unprivileged_iq}} ->
?INFO_MSG("IQ not forwarded: Component tried to send not wrapped IQ stanza.", []), ?DEBUG("Component ~ts sent a not-wrapped IQ stanza, routing it as-is.", [From#jid.lserver]),
drop;
{_, {error, roster_query, _Err}} ->
IQ; IQ;
{_, {error, ErrType, _Err}} -> {_, {error, ErrType, _Err}} ->
?INFO_MSG("IQ not forwarded: Component tried to send not valid IQ stanza: ~p.", ?INFO_MSG("IQ not forwarded: Component tried to send not valid IQ stanza: ~p.",
@ -566,7 +564,8 @@ forward_message(#message{to = To} = Msg) ->
%% @format-begin %% @format-begin
-spec get_iq_encapsulated_details(iq()) -> -spec get_iq_encapsulated_details(iq()) ->
{ok, iq_type(), binary(), jid(), iq()} | {privileged_iq, iq_type(), binary(), jid(), iq()} |
{unprivileged_iq} |
{error, Why :: atom(), stanza_error()}. {error, Why :: atom(), stanza_error()}.
get_iq_encapsulated_details(#iq{sub_els = [IqSub]} = Msg) -> get_iq_encapsulated_details(#iq{sub_els = [IqSub]} = Msg) ->
Lang = xmpp:get_lang(Msg), Lang = xmpp:get_lang(Msg),
@ -575,21 +574,9 @@ get_iq_encapsulated_details(#iq{sub_els = [IqSub]} = Msg) ->
[IqSubSub] = xmpp:get_els(IqSub), [IqSubSub] = xmpp:get_els(IqSub),
[Element] = xmpp:get_els(IqSubSub), [Element] = xmpp:get_els(IqSubSub),
Ns = xmpp:get_ns(Element), Ns = xmpp:get_ns(Element),
{ok, EncapsulatedType, Ns, From, EncIq}; {privileged_iq, EncapsulatedType, Ns, From, EncIq};
_ -> _ ->
try xmpp:try_subtag(Msg, #roster_query{}) of {unprivileged_iq}
#roster_query{} ->
{error, roster_query, xmpp:err_bad_request()};
_ ->
Txt = ?T("No <privileged_iq/> element found"),
Err = xmpp:err_bad_request(Txt, Lang),
{error, no_privileged_iq, Err}
catch
_:{xmpp_codec, Why} ->
Txt = xmpp:io_format_error(Why),
Err = xmpp:err_bad_request(Txt, Lang),
{error, codec_error, Err}
end
catch catch
_:{xmpp_codec, Why} -> _:{xmpp_codec, Why} ->
Txt = xmpp:io_format_error(Why), Txt = xmpp:io_format_error(Why),