Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/processone/ejabberd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/guide.tex24
-rw-r--r--src/ejabberd_c2s.erl34
-rw-r--r--src/mod_roster.erl12
3 files changed, 57 insertions, 13 deletions
diff --git a/doc/guide.tex b/doc/guide.tex
index e0ff370f9..2f573aa4f 100644
--- a/doc/guide.tex
+++ b/doc/guide.tex
@@ -3869,6 +3869,13 @@ Options:
\begin{description}
\backend{\term{rosteritem} and \term{rostergroup}}
\iqdiscitem{Roster Management (\ns{jabber:iq:roster})}
+ \titem{access} \ind{options!access}
+ This option can be configured to specify rules to restrict roster management.
+ If a rule returns `deny' on the requested user name,
+ that user cannot modify his personal roster:
+ not add/remove/modify contacts,
+ or subscribe/unsubscribe presence.
+ By default there aren't restrictions.
\titem{\{versioning, false|true\}} \ind{options!versioning}Enables
Roster Versioning.
This option is disabled by default.
@@ -3892,6 +3899,23 @@ This example configuration enables Roster Versioning with storage of current id:
]}.
\end{verbatim}
+With this example configuration only admins can manage their rosters;
+everybody else cannot modify the roster:
+\begin{verbatim}
+{acl, admin, {user, "bob", "example.org"}}.
+{acl, admin, {user, "sarah", "example.org"}}.
+
+{access, roster, [{allow, admin},
+ {deny, all}]}.
+
+{modules,
+ [
+ ...
+ {mod_roster, [{access, roster}]},
+ ...
+ ]}.
+\end{verbatim}
+
\makesubsection{modservicelog}{\modservicelog{}}
\ind{modules!\modservicelog{}}\ind{message auditing}\ind{Bandersnatch}
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index 2ee4e0a22..309287721 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -1764,11 +1764,12 @@ presence_track(From, To, Packet, StateData) ->
StateData#state{pres_i = I,
pres_a = A};
'subscribe' ->
- ejabberd_hooks:run(roster_out_subscription,
- StateData#state.server,
- [StateData#state.user, StateData#state.server, To, subscribe]),
- check_privacy_route(From, StateData, exmpp_jid:bare(From),
- To, Packet),
+ try_check_privacy_route(subscribe, StateData#state.user, StateData#state.server,
+ From, StateData, exmpp_jid:bare(From), To, Packet),
+ StateData;
+ 'unsubscribe' ->
+ try_check_privacy_route(subscribe, StateData#state.user, StateData#state.server,
+ From, StateData, exmpp_jid:bare(From), To, Packet),
StateData;
'subscribed' ->
ejabberd_hooks:run(roster_out_subscription,
@@ -1777,13 +1778,6 @@ presence_track(From, To, Packet, StateData) ->
check_privacy_route(From, StateData, exmpp_jid:bare(From),
To, Packet),
StateData;
- 'unsubscribe' ->
- ejabberd_hooks:run(roster_out_subscription,
- StateData#state.server,
- [StateData#state.user, StateData#state.server, To, unsubscribe]),
- check_privacy_route(From, StateData, exmpp_jid:bare(From),
- To, Packet),
- StateData;
'unsubscribed' ->
ejabberd_hooks:run(roster_out_subscription,
StateData#state.server,
@@ -1805,6 +1799,22 @@ presence_track(From, To, Packet, StateData) ->
pres_a = A}
end.
+%%% Check ACL before allowing to send a subscription stanza
+try_check_privacy_route(Type, User, Server, From, StateData, FromRoute, To, Packet) ->
+ JID1 = exmpp_jid:make(User, Server, undefined),
+ Access = gen_mod:get_module_opt(Server, mod_roster, access, all),
+ case acl:match_rule(Server, Access, JID1) of
+ deny ->
+ %% Silently drop this (un)subscription request
+ ok;
+ allow ->
+ ejabberd_hooks:run(roster_out_subscription,
+ Server,
+ [User, Server, To, Type]),
+ check_privacy_route(From, StateData, FromRoute,
+ To, Packet)
+ end.
+
check_privacy_route(From, StateData, FromRoute, To, Packet) ->
case ejabberd_hooks:run_fold(
privacy_check_packet, StateData#state.server,
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index 2ee73e1f6..39c8c50b9 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -238,7 +238,7 @@ process_local_iq(From, To, #iq{type = get} = IQ_Rec)
process_iq_get(From, To, IQ_Rec);
process_local_iq(From, To, #iq{type = set} = IQ_Rec)
when ?IS_JID(From), ?IS_JID(To), ?IS_IQ_RECORD(IQ_Rec) ->
- process_iq_set(From, To, IQ_Rec).
+ try_process_iq_set(From, To, IQ_Rec).
roster_hash(Items) ->
sha:sha(term_to_binary(
@@ -449,6 +449,16 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) ->
end,
exmpp_iq:result(IQ_Rec).
+try_process_iq_set(From, To, IQ) ->
+ LServer = exmpp_jid:prep_domain_as_list(From),
+ Access = gen_mod:get_module_opt(LServer, ?MODULE, access, all),
+ case acl:match_rule(LServer, Access, From) of
+ deny ->
+ exmpp_iq:error(IQ, 'not-allowed');
+ allow ->
+ process_iq_set(From, To, IQ)
+ end.
+
%% @spec (From, To, El) -> ok
%% From = exmpp_jid:jid()
%% To = exmpp_jid:jid()