'Static' rosters

Hi,

I would like to use ejabberd with a set of 'static' rosters in the following way: roster management is done only via script access (RPC, SQL acccess etc.) or by administrators. Users should not be able to change (add, delete, modify etc.) roster items via their XMPP clients.
I have searched for a solution of this kind of problem for some time now but did not find any acceptable way without being forced to modify the source of ejabberd to block user access to rosters. Any hints / ideas?

Many thanks advance!

Try this small mod_filterroster.erl

Try this small mod_filterroster.erl module. It drops all the XMPP packets that are typically used to modify the roster. Note that it drops packets even from admins, and for all vhosts.

  1. Open a file called mod_filterroster.erl and put the content.
  2. Compile the .erl into a .beam. You need full Erlang/OTP installation, it doesn't care which operating system:
    $ erlc mod_filterroster.erl
    ./mod_filterroster.erl:2: Warning: behaviour gen_mod undefined
  3. Copy the resulting .beam file to the directory where all the other ejabberd .beam files are.
  4. Configure ejabberd to enable this module. For example on ejabberd.cfg:
    {modules, [
      ...
      {mod_filterroster, []},
      ...
    ]}.

Here is the source code:

-module(mod_filterroster).
-behaviour(gen_mod).
-export([start/2, stop/1, filter/1]).

%-include("jlib.hrl").
-define(NS_ROSTER,       "jabber:iq:roster").
-record(iq, {id = "",
	     type,
	     xmlns = "",
	     lang = "",
	     sub_el}).

start(_Host, _Opts) ->
    ejabberd_hooks:add(filter_packet, global, ?MODULE, filter, 10).

stop(_Host) ->
    ejabberd_hooks:delete(filter_packet, global, ?MODULE, filter, 10).

filter(drop) -> drop;
filter({_From, _To, Packet} = Input) ->
	case check_rosterchange(Packet) of
		false -> Input;
		true -> drop
    end.

% http://www.xmpp.org/rfcs/rfc3921.html#roster
check_rosterchange({xmlelement, "iq", _, _} = Packet) ->
	IQ = jlib:iq_query_info(Packet),
	case catch #iq{type = set, xmlns = ?NS_ROSTER} = IQ of
		{'EXIT', _} -> false;
		_ -> true
	end;
	
% http://www.xmpp.org/rfcs/rfc3921.html#sub
check_rosterchange({xmlelement, "presence", Attrs, _}) ->
	case xml:get_attr_s("type", Attrs) of
		"subscribe" -> true;
		"subscribed" -> true;
		"unsubscribe" -> true;
		"unsubscribed" -> true;
		_ -> false
	end.

Thanks a lot!

Hi badlop,

many thanks for providing this filter! It works great!

There is still a small problem: Though all packets regarding the roster are filtered, it is still possible to add an item to an user's roster (checked via Web-Interface). Any other operation (deletion, modification etc.) is blocked successfully.

Legoscia found a bug. Try new version

Legoscia found a bug. I've updated the code on my initial comment. You can see that at the end there are now several "".

Atoms → strings

badlop wrote:
% http://www.xmpp.org/rfcs/rfc3921.html#sub
check_rosterchange({xmlelement, "presence", Attrs, _}) ->
	case xml:get_attr_s("type", Attrs) of
		subscribe -> true;
		subscribed -> true;
		unsubscribe -> true;
		unsubscribed -> true;
		_ -> false
	end.

Shouldn't those be strings?

Syndicate content