Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions src/mod_privilege.erl
Original file line number Diff line number Diff line change
Expand Up @@ -214,15 +214,17 @@ component_connected(Host) ->
fun(ServerHost) ->
Proc = gen_mod:get_module_proc_check(ServerHost, ?MODULE),
gen_server:cast(Proc, {component_connected, Host})
end, ejabberd_option:hosts()).
end, [H || H <- ejabberd_option:hosts(),
gen_mod:is_loaded(H, ?MODULE)]).

-spec component_disconnected(binary(), binary()) -> ok.
component_disconnected(Host, _Reason) ->
lists:foreach(
fun(ServerHost) ->
Proc = gen_mod:get_module_proc_check(ServerHost, ?MODULE),
gen_server:cast(Proc, {component_disconnected, Host})
end, ejabberd_option:hosts()).
end, [H || H <- ejabberd_option:hosts(),
gen_mod:is_loaded(H, ?MODULE)]).

%%
%% Message processing
Expand Down Expand Up @@ -266,12 +268,16 @@ component_send_packet({#iq{from = From,
type = Type} =
IQ,
State})
when Type /= error ->
when Type == get; Type == set ->
Host = From#jid.lserver,
ServerHost = To#jid.lserver,
Permissions = get_permissions(ServerHost),
Result =
case {maps:find(Host, Permissions), get_iq_encapsulated_details(IQ)} of
{_, {unprivileged_iq}} ->
?DEBUG("Component ~ts sent a not-wrapped IQ stanza, routing it as-is.",
[From#jid.lserver]),
IQ;
{{ok, Access}, {privileged_iq, EncapType, EncapNs, EncapFrom, EncIq}}
when (EncapType == Type) and ((EncapFrom == undefined) or (EncapFrom == To)) ->
NsPermissions = proplists:get_value(iq, Access, []),
Expand Down Expand Up @@ -307,10 +313,6 @@ component_send_packet({#iq{from = From,
"IQ stanza and the TO in top-level IQ stanza do not match",
[]),
drop;
{_, {unprivileged_iq}} ->
?DEBUG("Component ~ts sent a not-wrapped IQ stanza, routing it as-is.",
[From#jid.lserver]),
IQ;
{_, {error, ErrType, _Err}} ->
?INFO_MSG("IQ not forwarded: Component tried to send not valid IQ stanza: ~p.",
[ErrType]),
Expand Down
79 changes: 79 additions & 0 deletions test/ejabberd_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,9 @@ component_tests() ->
test_missing_to,
test_invalid_from,
test_component_send,
test_component_privilege,
test_component_privilege_vhosts,
test_component_privilege_result,
bad_nonza,
codec_failure]}].

Expand Down Expand Up @@ -831,6 +834,82 @@ test_component_send(Config) ->
sub_els = [#ping{}]}),
disconnect(Config).

test_component_privilege(Config) ->
Server = ?COMMON_VHOST,
Host = jid:make(Server),
Upload = jid:make(?UPLOAD_VHOST),
User = jid:make(<<"test_privilege">>, Server),
From = server_jid(Config),
%% Without privileges, plain IQs go to the host and to a service
%% that is not a host, as if mod_privilege were not loaded (#4472)
#iq{type = result, from = Upload} =
send_recv(Config, #iq{type = get, to = Upload, from = From,
sub_els = [#disco_info{}]}),
gen_mod:update_module(Server, mod_privilege,
#{iq => [{?NS_PING, [{both, all}]}]}),
ejabberd_hooks:run(component_connected, [From#jid.lserver]),
?recv1(#message{from = Host, sub_els = [#privilege{}]}),
%% With privileges, plain IQs still go anywhere
#iq{type = result, from = Host} =
send_recv(Config, #iq{type = get, to = Host, from = From,
sub_els = [#ping{}]}),
#iq{type = result, from = Upload} =
send_recv(Config, #iq{type = get, to = Upload, from = From,
sub_els = [#disco_info{}]}),
%% A privileged IQ in a granted namespace is forwarded
#iq{type = result, from = User,
sub_els = [#privilege{forwarded = #forwarded{sub_els = [_]}}]} =
send_recv(Config, #iq{type = get, to = User, from = From,
sub_els = [#privileged_iq{
iq = #iq{type = get, to = User, from = User,
sub_els = [#ping{}]}}]}),
%% A privileged IQ in a namespace not granted is dropped
send(Config, #iq{type = get, to = User, from = From,
sub_els = [#privileged_iq{
iq = #iq{type = get, to = User, from = User,
sub_els = [#disco_info{}]}}]}),
ID = send(Config, #iq{type = get, to = Host, from = From,
sub_els = [#ping{}]}),
?recv1(#iq{type = result, id = ID, from = Host}),
gen_mod:update_module(Server, mod_privilege, #{iq => []}),
disconnect(Config).

test_component_privilege_vhosts(Config) ->
%% mod_privilege is loaded on a vhost that comes after vhosts
%% that do not load it: the component still gets its privileges there
Server = ?MNESIA_VHOST,
From = server_jid(Config),
Modules = ejabberd_option:modules(Server),
Opts = #{roster => [{both, none}, {get, none}, {set, none}],
iq => [{?NS_PING, [{both, all}]}],
presence => [{managed_entity, none}, {roster, none}],
message => [{outgoing, none}]},
%% The suite's configuration may load mod_privilege everywhere:
%% start it here with this vhost's own options
Loaded = gen_mod:is_loaded(Server, mod_privilege),
Loaded andalso gen_mod:stop_module(Server, mod_privilege),
ejabberd_config:set_option({modules, Server},
[{mod_privilege, Opts, 0} | Modules]),
{ok, _} = gen_mod:start_module(Server, mod_privilege),
ejabberd_hooks:run(component_connected, [From#jid.lserver]),
?recv1(#message{from = #jid{lserver = Server}, sub_els = [#privilege{}]}),
gen_mod:stop_module(Server, mod_privilege),
ejabberd_config:set_option({modules, Server}, Modules),
Loaded andalso gen_mod:start_module(Server, mod_privilege),
disconnect(Config).

test_component_privilege_result(Config) ->
%% A component's answer to an IQ from the server, a result without a
%% payload (a push service's to mod_push), is routed as it is: it is
%% not a privileged IQ, which only a get or a set can be
From = server_jid(Config),
To = jid:make(?COMMON_VHOST),
IQ = #iq{type = result, id = p1_rand:get_string(), from = From, to = To},
{IQ, state} = mod_privilege:component_send_packet({IQ, state}),
Err = IQ#iq{type = error, sub_els = [xmpp:err_service_unavailable()]},
{Err, state} = mod_privilege:component_send_packet({Err, state}),
disconnect(Config).

s2s_dialback(Config) ->
Server = ?config(server, Config),
ejabberd_s2s:stop_s2s_connections(),
Expand Down
1 change: 1 addition & 0 deletions test/ejabberd_SUITE_data/ejabberd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ modules:
mod_configure: []
mod_disco: []
mod_ping: []
mod_privilege: []
mod_proxy65:
port: PROXY_PORT
vcard: VCARD
Expand Down
Loading