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

mod_configure: Add option 'access' to let configure the access name

This commit is contained in:
Badlop 2025-02-21 13:45:20 +01:00
parent 6151674e64
commit aa78362c7f
2 changed files with 73 additions and 25 deletions

View file

@ -1,7 +1,7 @@
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% File : mod_configure.erl %%% File : mod_configure.erl
%%% Author : Alexey Shchepin <alexey@process-one.net> %%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : Support for online configuration of ejabberd %%% Purpose : Support for online configuration of ejabberd using XEP-0050
%%% Created : 19 Jan 2003 by Alexey Shchepin <alexey@process-one.net> %%% Created : 19 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%% %%%
%%% %%%
@ -36,6 +36,7 @@
adhoc_local_items/4, adhoc_local_commands/4, adhoc_local_items/4, adhoc_local_commands/4,
get_sm_identity/5, get_sm_features/5, get_sm_items/5, get_sm_identity/5, get_sm_features/5, get_sm_items/5,
adhoc_sm_items/4, adhoc_sm_commands/4, mod_options/1, adhoc_sm_items/4, adhoc_sm_commands/4, mod_options/1,
mod_opt_type/1,
depends/2, mod_doc/0]). depends/2, mod_doc/0]).
-include("logger.hrl"). -include("logger.hrl").
@ -92,6 +93,10 @@ depends(_Host, _Opts) ->
-spec tokenize(binary()) -> [binary()]. -spec tokenize(binary()) -> [binary()].
tokenize(Node) -> str:tokens(Node, <<"/#">>). tokenize(Node) -> str:tokens(Node, <<"/#">>).
acl_match_rule(Host, From) ->
Access = mod_configure_opt:access(Host),
acl:match_rule(Host, Access, From).
-spec get_sm_identity([identity()], jid(), jid(), binary(), binary()) -> [identity()]. -spec get_sm_identity([identity()], jid(), jid(), binary(), binary()) -> [identity()].
get_sm_identity(Acc, _From, _To, Node, Lang) -> get_sm_identity(Acc, _From, _To, Node, Lang) ->
case Node of case Node of
@ -167,7 +172,7 @@ get_sm_features(Acc, From,
case gen_mod:is_loaded(LServer, mod_adhoc) of case gen_mod:is_loaded(LServer, mod_adhoc) of
false -> Acc; false -> Acc;
_ -> _ ->
Allow = acl:match_rule(LServer, configure, From), Allow = acl_match_rule(LServer, From),
case Node of case Node of
<<"config">> -> ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); <<"config">> -> ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang);
_ -> Acc _ -> Acc
@ -182,7 +187,7 @@ get_local_features(Acc, From,
false -> Acc; false -> Acc;
_ -> _ ->
LNode = tokenize(Node), LNode = tokenize(Node),
Allow = acl:match_rule(LServer, configure, From), Allow = acl_match_rule(LServer, From),
case LNode of case LNode of
[<<"config">>] -> ?INFO_RESULT(Allow, [], Lang); [<<"config">>] -> ?INFO_RESULT(Allow, [], Lang);
[<<"user">>] -> ?INFO_RESULT(Allow, [], Lang); [<<"user">>] -> ?INFO_RESULT(Allow, [], Lang);
@ -240,7 +245,7 @@ get_local_features(Acc, From,
jid(), jid(), binary()) -> mod_disco:items_acc(). jid(), jid(), binary()) -> mod_disco:items_acc().
adhoc_sm_items(Acc, From, #jid{lserver = LServer} = To, adhoc_sm_items(Acc, From, #jid{lserver = LServer} = To,
Lang) -> Lang) ->
case acl:match_rule(LServer, configure, From) of case acl_match_rule(LServer, From) of
allow -> allow ->
Items = case Acc of Items = case Acc of
{result, Its} -> Its; {result, Its} -> Its;
@ -266,7 +271,7 @@ get_sm_items(Acc, From,
{result, Its} -> Its; {result, Its} -> Its;
empty -> [] empty -> []
end, end,
case {acl:match_rule(LServer, configure, From), Node} of case {acl_match_rule(LServer, From), Node} of
{allow, <<"">>} -> {allow, <<"">>} ->
Nodes = [?NODEJID(To, ?T("Configuration"), Nodes = [?NODEJID(To, ?T("Configuration"),
<<"config">>), <<"config">>),
@ -295,13 +300,13 @@ get_user_resources(User, Server) ->
jid(), jid(), binary()) -> mod_disco:items_acc(). jid(), jid(), binary()) -> mod_disco:items_acc().
adhoc_local_items(Acc, From, adhoc_local_items(Acc, From,
#jid{lserver = LServer, server = Server} = To, Lang) -> #jid{lserver = LServer, server = Server} = To, Lang) ->
case acl:match_rule(LServer, configure, From) of case acl_match_rule(LServer, From) of
allow -> allow ->
Items = case Acc of Items = case Acc of
{result, Its} -> Its; {result, Its} -> Its;
empty -> [] empty -> []
end, end,
PermLev = get_permission_level(From), PermLev = get_permission_level(From, LServer),
Nodes = recursively_get_local_items(PermLev, LServer, Nodes = recursively_get_local_items(PermLev, LServer,
<<"">>, Server, Lang), <<"">>, Server, Lang),
Nodes1 = lists:filter( Nodes1 = lists:filter(
@ -348,9 +353,10 @@ recursively_get_local_items(PermLev, LServer, Node,
end, end,
Items)). Items)).
-spec get_permission_level(jid()) -> global | vhost. -spec get_permission_level(jid(), binary()) -> global | vhost.
get_permission_level(JID) -> get_permission_level(JID, Host) ->
case acl:match_rule(global, configure, JID) of Access = mod_configure_opt:access(Host),
case acl:match_rule(global, Access, JID) of
allow -> global; allow -> global;
deny -> vhost deny -> vhost
end. end.
@ -361,7 +367,7 @@ get_permission_level(JID) ->
case Allow of case Allow of
deny -> Fallback; deny -> Fallback;
allow -> allow ->
PermLev = get_permission_level(From), PermLev = get_permission_level(From, LServer),
case get_local_items({PermLev, LServer}, LNode, case get_local_items({PermLev, LServer}, LNode,
jid:encode(To), Lang) jid:encode(To), Lang)
of of
@ -381,11 +387,11 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To,
{result, Its} -> Its; {result, Its} -> Its;
empty -> [] empty -> []
end, end,
Allow = acl:match_rule(LServer, configure, From), Allow = acl_match_rule(LServer, From),
case Allow of case Allow of
deny -> {result, Items}; deny -> {result, Items};
allow -> allow ->
PermLev = get_permission_level(From), PermLev = get_permission_level(From, LServer),
case get_local_items({PermLev, LServer}, [], case get_local_items({PermLev, LServer}, [],
jid:encode(To), Lang) jid:encode(To), Lang)
of of
@ -400,7 +406,7 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To,
false -> Acc; false -> Acc;
_ -> _ ->
LNode = tokenize(Node), LNode = tokenize(Node),
Allow = acl:match_rule(LServer, configure, From), Allow = acl_match_rule(LServer, From),
Err = xmpp:err_forbidden(?T("Access denied by service policy"), Lang), Err = xmpp:err_forbidden(?T("Access denied by service policy"), Lang),
case LNode of case LNode of
[<<"config">>] -> [<<"config">>] ->
@ -690,7 +696,7 @@ get_stopped_nodes(_Lang) ->
-define(COMMANDS_RESULT(LServerOrGlobal, From, To, -define(COMMANDS_RESULT(LServerOrGlobal, From, To,
Request, Lang), Request, Lang),
case acl:match_rule(LServerOrGlobal, configure, From) of case acl_match_rule(LServerOrGlobal, From) of
deny -> {error, xmpp:err_forbidden(?T("Access denied by service policy"), Lang)}; deny -> {error, xmpp:err_forbidden(?T("Access denied by service policy"), Lang)};
allow -> adhoc_local_commands(From, To, Request) allow -> adhoc_local_commands(From, To, Request)
end). end).
@ -1268,7 +1274,7 @@ set_form(From, Host, ?NS_ADMINL(<<"add-user">>), _Lang,
Server = AccountJID#jid.lserver, Server = AccountJID#jid.lserver,
true = lists:member(Server, ejabberd_option:hosts()), true = lists:member(Server, ejabberd_option:hosts()),
true = Server == Host orelse true = Server == Host orelse
get_permission_level(From) == global, get_permission_level(From, Host) == global,
case ejabberd_auth:try_register(User, Server, Password) of case ejabberd_auth:try_register(User, Server, Password) of
ok -> {result, undefined}; ok -> {result, undefined};
{error, exists} -> {error, xmpp:err_conflict()}; {error, exists} -> {error, xmpp:err_conflict()};
@ -1284,7 +1290,7 @@ set_form(From, Host, ?NS_ADMINL(<<"delete-user">>),
User = JID#jid.luser, User = JID#jid.luser,
Server = JID#jid.lserver, Server = JID#jid.lserver,
true = Server == Host orelse true = Server == Host orelse
get_permission_level(From) == global, get_permission_level(From, Host) == global,
true = ejabberd_auth:user_exists(User, Server), true = ejabberd_auth:user_exists(User, Server),
{User, Server} {User, Server}
end, end,
@ -1298,7 +1304,7 @@ set_form(From, Host, ?NS_ADMINL(<<"end-user-session">>),
JID = jid:decode(AccountString), JID = jid:decode(AccountString),
LServer = JID#jid.lserver, LServer = JID#jid.lserver,
true = LServer == Host orelse true = LServer == Host orelse
get_permission_level(From) == global, get_permission_level(From, Host) == global,
case JID#jid.lresource of case JID#jid.lresource of
<<>> -> <<>> ->
ejabberd_sm:kick_user(JID#jid.luser, JID#jid.lserver); ejabberd_sm:kick_user(JID#jid.luser, JID#jid.lserver);
@ -1314,7 +1320,7 @@ set_form(From, Host,
User = JID#jid.luser, User = JID#jid.luser,
Server = JID#jid.lserver, Server = JID#jid.lserver,
true = Server == Host orelse true = Server == Host orelse
get_permission_level(From) == global, get_permission_level(From, Host) == global,
true = ejabberd_auth:user_exists(User, Server), true = ejabberd_auth:user_exists(User, Server),
ejabberd_auth:set_password(User, Server, Password), ejabberd_auth:set_password(User, Server, Password),
{result, undefined}; {result, undefined};
@ -1325,7 +1331,7 @@ set_form(From, Host,
User = JID#jid.luser, User = JID#jid.luser,
Server = JID#jid.lserver, Server = JID#jid.lserver,
true = Server == Host orelse true = Server == Host orelse
get_permission_level(From) == global, get_permission_level(From, Host) == global,
FLast = case ejabberd_sm:get_user_resources(User, FLast = case ejabberd_sm:get_user_resources(User,
Server) Server)
of of
@ -1357,7 +1363,7 @@ set_form(From, Host, ?NS_ADMINL(<<"user-stats">>), Lang,
User = JID#jid.luser, User = JID#jid.luser,
Server = JID#jid.lserver, Server = JID#jid.lserver,
true = Server == Host orelse true = Server == Host orelse
get_permission_level(From) == global, get_permission_level(From, Host) == global,
Resources = ejabberd_sm:get_user_resources(User, Resources = ejabberd_sm:get_user_resources(User,
Server), Server),
IPs1 = [ejabberd_sm:get_user_ip(User, Server, Resource) IPs1 = [ejabberd_sm:get_user_ip(User, Server, Resource)
@ -1448,7 +1454,7 @@ adhoc_sm_commands(_Acc, From,
#jid{user = User, server = Server, lserver = LServer}, #jid{user = User, server = Server, lserver = LServer},
#adhoc_command{lang = Lang, node = <<"config">>, #adhoc_command{lang = Lang, node = <<"config">>,
action = Action, xdata = XData} = Request) -> action = Action, xdata = XData} = Request) ->
case acl:match_rule(LServer, configure, From) of case acl_match_rule(LServer, From) of
deny -> deny ->
{error, xmpp:err_forbidden(?T("Access denied by service policy"), Lang)}; {error, xmpp:err_forbidden(?T("Access denied by service policy"), Lang)};
allow -> allow ->
@ -1530,12 +1536,41 @@ set_sm_form(_User, _Server, _Node, _Request) ->
tr(Lang, Text) -> tr(Lang, Text) ->
translate:translate(Lang, Text). translate:translate(Lang, Text).
mod_options(_) -> []. -spec mod_opt_type(atom()) -> econf:validator().
mod_opt_type(access) ->
econf:acl().
-spec mod_options(binary()) -> [{services, [tuple()]} | {atom(), any()}].
mod_options(_Host) ->
[{access, configure}].
%% @format-begin
mod_doc() -> mod_doc() ->
#{desc => #{desc =>
?T("The module provides server configuration functionality via " ?T("The module provides server configuration functionality via "
"https://xmpp.org/extensions/xep-0050.html[XEP-0050: Ad-Hoc Commands]. " "https://xmpp.org/extensions/xep-0050.html[XEP-0050: Ad-Hoc Commands]. "
"Implements many commands as defined in " "It also implements many commands as defined in "
"https://xmpp.org/extensions/xep-0133.html[XEP-0133: Service Administration]. " "https://xmpp.org/extensions/xep-0133.html[XEP-0133: Service Administration]. "
"This module requires _`mod_adhoc`_ to be loaded.")}. "This module requires _`mod_adhoc`_ (to execute the commands), "
"and recommends _`mod_disco`_ (to discover the commands). "),
opts =>
[{access,
#{value => ?T("AccessName"),
note => "added in 25.xx",
desc =>
?T("This option defines which access rule will be used to "
"control who is allowed to access the features provided by this module. "
"The default value is 'configure'.")}}],
example =>
["acl:",
" admin:",
" user: sun@localhost",
"",
"access_rules:",
" configure:",
" allow: admin",
"",
"modules:",
" mod_configure:",
" access: configure"]}.

13
src/mod_configure_opt.erl Normal file
View file

@ -0,0 +1,13 @@
%% Generated automatically
%% DO NOT EDIT: run `make options` instead
-module(mod_configure_opt).
-export([access/1]).
-spec access(gen_mod:opts() | global | binary()) -> 'configure' | acl:acl().
access(Opts) when is_map(Opts) ->
gen_mod:get_opt(access, Opts);
access(Host) ->
gen_mod:get_module_opt(Host, mod_configure, access).