-include("ejabberd.hrl").
-include("jlib.hrl").
+-include("mod_privacy.hrl").
-define(SETS, gb_sets).
-define(DICT, dict).
pres_last, pres_pri,
pres_timestamp,
pres_invis = false,
- privacy_list = none,
+ privacy_list = #userlist{},
conn = unknown,
+ auth_module = unknown,
ip,
lang}).
(_) -> false
end, Opts),
IP = peerip(SockMod, Socket),
- %% Check if IP is blacklisted:
- case is_ip_blacklisted(IP) of
- true ->
- ?INFO_MSG("Connection attempt from blacklisted IP: ~s",
- [jlib:ip_to_list(IP)]),
- {stop, normal};
- false ->
- Socket1 =
- if
- TLSEnabled ->
- SockMod:starttls(Socket, TLSOpts);
- true ->
- Socket
- end,
- SocketMonitor = SockMod:monitor(Socket1),
- {ok, wait_for_stream, #state{socket = Socket1,
- sockmod = SockMod,
- socket_monitor = SocketMonitor,
- zlib = Zlib,
- tls = TLS,
- tls_required = StartTLSRequired,
- tls_enabled = TLSEnabled,
- tls_options = TLSOpts,
- streamid = new_id(),
- access = Access,
- shaper = Shaper,
- ip = IP},
- ?C2S_OPEN_TIMEOUT}
- end.
+ Socket1 =
+ if
+ TLSEnabled ->
+ SockMod:starttls(Socket, TLSOpts);
+ true ->
+ Socket
+ end,
+ SocketMonitor = SockMod:monitor(Socket1),
+ {ok, wait_for_stream, #state{socket = Socket1,
+ sockmod = SockMod,
+ socket_monitor = SocketMonitor,
+ zlib = Zlib,
+ tls = TLS,
+ tls_required = StartTLSRequired,
+ tls_enabled = TLSEnabled,
+ tls_options = TLSOpts,
+ streamid = new_id(),
+ access = Access,
+ shaper = Shaper,
+ ip = IP}, ?C2S_OPEN_TIMEOUT}.
%% Return list of all available resources of contacts,
%% in form [{JID, Caps}].
cyrsasl:server_new(
"jabber", Server, "", [],
fun(U) ->
- ejabberd_auth:get_password(
+ ejabberd_auth:get_password_with_authmodule(
U, Server)
end,
fun(U, P) ->
- ejabberd_auth:check_password(
+ ejabberd_auth:check_password_with_authmodule(
U, Server, P)
end),
Mechs = lists:map(
true ->
send_text(StateData, Header),
fsm_next_state(wait_for_auth,
- StateData#state{
- server = Server,
- lang = Lang})
+ StateData#state{
+ server = Server,
+ lang = Lang})
end
end;
_ ->
(acl:match_rule(StateData#state.server,
StateData#state.access, JID) == allow) of
true ->
- case ejabberd_auth:check_password(
+ case ejabberd_auth:check_password_with_authmodule(
U, StateData#state.server, P,
StateData#state.streamid, D) of
- true ->
+ {true, AuthModule} ->
?INFO_MSG(
"(~w) Accepted legacy authentication for ~s",
[StateData#state.socket,
jlib:jid_to_string(JID)]),
SID = {now(), self()},
Conn = get_conn_type(StateData),
- Info = [{ip, StateData#state.ip}, {conn, Conn}],
+ Info = [{ip, StateData#state.ip}, {conn, Conn},
+ {auth_module, AuthModule}],
ejabberd_sm:open_session(
SID, U, StateData#state.server, R, Info),
Res1 = jlib:make_result_iq_reply(El),
PrivList =
ejabberd_hooks:run_fold(
privacy_get_user_list, StateData#state.server,
- none,
+ #userlist{},
[U, StateData#state.server]),
fsm_next_state(session_established,
StateData#state{
jid = JID,
sid = SID,
conn = Conn,
+ auth_module = AuthModule,
pres_f = ?SETS:from_list(Fs1),
pres_t = ?SETS:from_list(Ts1),
privacy_list = PrivList});
{xmlelement, "success",
[{"xmlns", ?NS_SASL}], []}),
U = xml:get_attr_s(username, Props),
+ AuthModule = xml:get_attr_s(auth_module, Props),
?INFO_MSG("(~w) Accepted authentication for ~s",
[StateData#state.socket, U]),
fsm_next_state(wait_for_stream,
StateData#state{
streamid = new_id(),
authenticated = true,
+ auth_module = AuthModule,
user = U});
{continue, ServerOut, NewSASLState} ->
send_element(StateData,
jlib:jid_to_string(JID)]),
SID = {now(), self()},
Conn = get_conn_type(StateData),
- Info = [{ip, StateData#state.ip}, {conn, Conn}],
+ Info = [{ip, StateData#state.ip}, {conn, Conn},
+ {auth_module, StateData#state.auth_module}],
ejabberd_sm:open_session(
SID, U, StateData#state.server, R, Info),
Res = jlib:make_result_iq_reply(El),
PrivList =
ejabberd_hooks:run_fold(
privacy_get_user_list, StateData#state.server,
- none,
+ #userlist{},
[U, StateData#state.server]),
fsm_next_state(session_established,
StateData#state{
{stop, normal, StateData}.
+
+
session_established({xmlstreamelement, El}, StateData) ->
{xmlelement, Name, Attrs, _Els} = El,
User = StateData#state.user,
StateData)
end;
"iq" ->
- case StateData#state.privacy_list of
- none ->
- ejabberd_router:route(FromJID, ToJID, NewEl),
- StateData;
- _PrivList ->
- case jlib:iq_query_info(NewEl) of
- #iq{xmlns = ?NS_PRIVACY} = IQ ->
- process_privacy_iq(
- FromJID, ToJID, IQ, StateData);
- _ ->
- ejabberd_hooks:run(
- user_send_packet,
- Server,
- [FromJID, ToJID, NewEl]),
- ejabberd_router:route(
- FromJID, ToJID, NewEl),
- StateData
- end
+ case jlib:iq_query_info(NewEl) of
+ #iq{xmlns = ?NS_PRIVACY} = IQ ->
+ process_privacy_iq(
+ FromJID, ToJID, IQ, StateData);
+ _ ->
+ ejabberd_hooks:run(
+ user_send_packet,
+ Server,
+ [FromJID, ToJID, NewEl]),
+ ejabberd_router:route(
+ FromJID, ToJID, NewEl),
+ StateData
end;
"message" ->
ejabberd_hooks:run(user_send_packet,
allow ->
Pid=element(2, StateData#state.sid),
ejabberd_hooks:run(presence_probe_hook, StateData#state.server, [From, To, Pid]),
- ejabberd_router:route(To, From, Packet)
+ %% Don't route a presence probe to oneself
+ case From == To of
+ false ->
+ ejabberd_router:route(To, From, Packet);
+ true ->
+ ok
+ end
end;
Cond2 ->
ejabberd_router:route(To, From,
Res = ejabberd_hooks:run_fold(c2s_unauthenticated_iq,
StateData#state.server,
empty,
- [StateData#state.server, IQ]),
+ [StateData#state.server, IQ,
+ StateData#state.ip]),
case Res of
empty ->
% The only reasonable IQ's here are auth and register IQ's
{reply, Reply, session_established, StateData, ?C2S_HIBERNATE_TIMEOUT};
fsm_reply(Reply, StateName, StateData) ->
{reply, Reply, StateName, StateData, ?C2S_OPEN_TIMEOUT}.
-
-%% Used by c2s blacklist plugins
-is_ip_blacklisted({IP,_Port}) ->
- ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]).
+++ /dev/null
-%%%----------------------------------------------------------------------
-%%% File : mod_ip_blacklist.erl
-%%% Author : Mickael Remond <mremond@process-one.net>
-%%% Purpose : Download blacklists from ProcessOne
-%%% Created : 5 May 2008 by Mickael Remond <mremond@process-one.net>
-%%% Usage : Add the following line in modules section of ejabberd.cfg:
-%%% {mod_ip_blacklist, []}
-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-2008 Process-one
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License
-%%% along with this program; if not, write to the Free Software
-%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-%%% 02111-1307 USA
-%%%
-%%%----------------------------------------------------------------------
-
--module(mod_ip_blacklist).
--author('mremond@process-one.net').
-
--behaviour(gen_mod).
-
-%% API:
--export([start/2,
- init/1,
- stop/1]).
--export([update_bl_c2s/0]).
-%% Hooks:
--export([is_ip_in_c2s_blacklist/2]).
-
--include("ejabberd.hrl").
-
--define(PROCNAME, ?MODULE).
--define(BLC2S, "http://xaai.process-one.net/bl_c2s.txt").
--define(UPDATE_INTERVAL, 6). %% in hours
-
--record(state, {timer}).
--record(bl_c2s, {ip}).
-
-%% Start once for all vhost
-start(Host, Opts) ->
- case whereis(?PROCNAME) of
- undefined ->
- ?DEBUG("Starting mod_ip_blacklist ~p ~p~n", [Host, Opts]),
- register(?PROCNAME,
- spawn(?MODULE, init, [#state{}]));
- _ ->
- ok
- end.
-
-%% TODO:
-stop(_Host) ->
- ok.
-
-init(State)->
- inets:start(),
- ets:new(bl_c2s, [named_table, public, {keypos, #bl_c2s.ip}]),
- update_bl_c2s(),
- %% Register hooks for blacklist
- ejabberd_hooks:add(check_bl_c2s, ?MODULE, is_ip_in_c2s_blacklist, 50),
- %% Set timer: Download the blacklist file every 6 hours
- timer:apply_interval(timer:hours(?UPDATE_INTERVAL), ?MODULE, update_bl_c2s, []),
- loop(State).
-
-%% Remove timer when stop is received.
-loop(_State) ->
- receive
- stop ->
- ok
- end.
-
-%% Download blacklist file from ProcessOne XAAI
-%% and update the table internal table
-%% TODO: Support comment lines starting by %
-update_bl_c2s() ->
- ?INFO_MSG("Updating C2S Blacklist", []),
- {ok, {{_Version, 200, _Reason}, _Headers, Body}} = http:request(?BLC2S),
- IPs = string:tokens(Body,"\n"),
- ets:delete_all_objects(bl_c2s),
- lists:foreach(
- fun(IP) ->
- ets:insert(bl_c2s, #bl_c2s{ip=list_to_binary(IP)})
- end, IPs).
-
-%% Hook is run with:
-%% ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]),
-%% Return: false: IP not blacklisted
-%% true: IP is blacklisted
-%% IPV4 IP tuple:
-is_ip_in_c2s_blacklist(_Val, IP) ->
- BinaryIP = list_to_binary(jlib:ip_to_list(IP)),
- case ets:lookup(bl_c2s, BinaryIP) of
- [] -> %% Not in blacklist
- false;
- [_] -> %% Blacklisted!
- {stop, true}
- end.
-
-
-%% TODO:
-%% - For now, we do not kick user already logged on a given IP after
-%% we update the blacklist.