diff --git a/ChangeLog b/ChangeLog index 72b293491..7f57a5a7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2004-12-12 Alexey Shchepin + + * src/ejabberd_sm.erl: Added unset_presence_hook + * src/mod_last.erl: Use unset_presence_hook instead of direct call + + * src/ejabberd_auth.erl: Splitted into ejabberd_auth_internal.erl, + ejabberd_auth_ldap.erl, and ejabberd_auth_external.erl, + * src/ejabberd_auth_internal.erl: Likewise + * src/ejabberd_auth_ldap.erl: Likewise + * src/ejabberd_auth_external.erl: Likewise + 2004-12-05 Alexey Shchepin * src/web/ejabberd_web_admin.erl: Changed type of password field diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index d7f6b3668..2c548a33c 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -1,7 +1,7 @@ %%%---------------------------------------------------------------------- %%% File : ejabberd_auth.erl %%% Author : Alexey Shchepin -%%% Purpose : +%%% Purpose : Authentification %%% Created : 23 Nov 2002 by Alexey Shchepin %%% Id : $Id$ %%%---------------------------------------------------------------------- @@ -10,10 +10,8 @@ -author('alexey@sevcom.net'). -vsn('$Revision$ '). --behaviour(gen_server). - %% External exports --export([start/0, start_link/0, +-export([start/0, set_password/2, check_password/2, check_password/4, @@ -24,387 +22,59 @@ is_user_exists/1, remove_user/1, remove_user/2, - plain_password_required/0, - check_password_ldap/2, % TODO: remove - is_user_exists_ldap/1 % TODO: remove + plain_password_required/0 ]). -%% gen_server callbacks --export([init/1, - handle_call/3, - handle_cast/2, - code_change/3, - handle_info/2, - terminate/2]). - --include("eldap/eldap.hrl"). - --record(state, {}). - --record(passwd, {user, password}). - %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- start() -> - case auth_method() of - external -> - extauth:start(ejabberd_config:get_local_option(extauth_program)); - _ -> - ok - end, - gen_server:start({local, ejabberd_auth}, ejabberd_auth, [], []). + (auth_module()):start(). -start_link() -> - gen_server:start_link({local, ejabberd_auth}, ejabberd_auth, [], []). +plain_password_required() -> + (auth_module()):plain_password_required(). -%%%---------------------------------------------------------------------- -%%% Callback functions from gen_server -%%%---------------------------------------------------------------------- +check_password(User, Password) -> + (auth_module()):check_password(User, Password). -%%---------------------------------------------------------------------- -%% Func: init/1 -%% Returns: {ok, State} | -%% {ok, State, Timeout} | -%% ignore | -%% {stop, Reason} -%%---------------------------------------------------------------------- -init([]) -> - mnesia:create_table(passwd,[{disc_copies, [node()]}, - {attributes, record_info(fields, passwd)}]), - case auth_method() of - internal -> - ok; - external -> - ok; - ldap -> - LDAPServers = ejabberd_config:get_local_option(ldap_servers), - RootDN = ejabberd_config:get_local_option(ldap_rootdn), - Password = ejabberd_config:get_local_option(ldap_password), - eldap:start_link("ejabberd", LDAPServers, 389, RootDN, Password), - eldap:start_link("ejabberd_bind", LDAPServers, 389, RootDN, Password) - end, - {ok, #state{}}. +check_password(User, Password, StreamID, Digest) -> + (auth_module()):check_password(User, Password, StreamID, Digest). -%%---------------------------------------------------------------------- -%% Func: handle_call/3 -%% Returns: {reply, Reply, State} | -%% {reply, Reply, State, Timeout} | -%% {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, Reply, State} | (terminate/2 is called) -%% {stop, Reason, State} (terminate/2 is called) -%%---------------------------------------------------------------------- -handle_call(_Request, _From, State) -> - Reply = ok, - {reply, Reply, State}. +set_password(User, Password) -> + (auth_module()):set_password(User, Password). -%%---------------------------------------------------------------------- -%% Func: handle_cast/2 -%% Returns: {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, State} (terminate/2 is called) -%%---------------------------------------------------------------------- -handle_cast(_Msg, State) -> - {noreply, State}. +try_register(User, Password) -> + (auth_module()):try_register(User, Password). +dirty_get_registered_users() -> + (auth_module()):dirty_get_registered_users(). -code_change(_OldVsn, State, _Extra) -> - {ok, State}. +get_password(User) -> + (auth_module()):get_password(User). -%%---------------------------------------------------------------------- -%% Func: handle_info/2 -%% Returns: {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, State} (terminate/2 is called) -%%---------------------------------------------------------------------- -handle_info(_Info, State) -> - {noreply, State}. +get_password_s(User) -> + (auth_module()):get_password_s(User). -%%---------------------------------------------------------------------- -%% Func: terminate/2 -%% Purpose: Shutdown the server -%% Returns: any (ignored by gen_server) -%%---------------------------------------------------------------------- -terminate(_Reason, _State) -> - ok. +is_user_exists(User) -> + (auth_module()):is_user_exists(User). + +remove_user(User) -> + (auth_module()):remove_user(User). + +remove_user(User, Password) -> + (auth_module()):remove_user(User, Password). %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- -auth_method() -> +auth_module() -> case ejabberd_config:get_local_option(auth_method) of external -> - external; + ejabberd_auth_external; ldap -> - ldap; + ejabberd_auth_ldap; _ -> - internal + ejabberd_auth_internal end. -user_method() -> - case ejabberd_config:get_local_option(user_method) of - ldap -> - ldap; - _ -> - internal - end. - -plain_password_required() -> - case auth_method() of - internal -> - false; - external -> - true; - ldap -> - true - end. - -check_password(User, Password) -> - case auth_method() of - internal -> - check_password_internal(User, Password); - external -> - check_password_external(User, Password); - ldap -> - check_password_ldap(User, Password) - end. - -check_password_external(User, Password) -> - extauth:check_password(User, Password). - -set_password_external(User, Password) -> - extauth:set_password(User, Password). - -is_user_exists_external(User) -> - extauth:is_user_exists(User). - -check_password_internal(User, Password) -> - LUser = jlib:nodeprep(User), - case catch mnesia:dirty_read({passwd, LUser}) of - [#passwd{password = Password}] -> - true; - _ -> - false - end. - -check_password(User, Password, StreamID, Digest) -> - case auth_method() of - internal -> - check_password_internal(User, Password, StreamID, Digest); - external -> - check_password_external(User, Password, StreamID, Digest); - ldap -> - check_password_ldap(User, Password, StreamID, Digest) - end. - -check_password_internal(User, Password, StreamID, Digest) -> - LUser = jlib:nodeprep(User), - case catch mnesia:dirty_read({passwd, LUser}) of - [#passwd{password = Passwd}] -> - DigRes = if - Digest /= "" -> - Digest == sha:sha(StreamID ++ Passwd); - true -> - false - end, - if DigRes -> - true; - true -> - (Passwd == Password) and (Password /= "") - end; - _ -> - false - end. - -set_password(User, Password) -> - case auth_method() of - internal -> - set_password_internal(User,Password); - external -> - set_password_external(User,Password); - ldap -> {error, not_allowed} - end. - -set_password_internal(User, Password) -> - case jlib:nodeprep(User) of - error -> {error, invalid_jid}; - LUser -> - F = fun() -> - mnesia:write(#passwd{user = LUser, - password = Password}) - end, - mnesia:transaction(F) - end. - - -try_register(User, Password) -> - case auth_method() of - internal -> - try_register_internal(User, Password); - external -> - {error, not_allowed}; - ldap -> - {error, not_allowed} - end. - -try_register_internal(User, Password) -> - case jlib:nodeprep(User) of - error -> {error, invalid_jid}; - LUser -> - F = fun() -> - case mnesia:read({passwd, LUser}) of - [] -> - mnesia:write(#passwd{user = LUser, - password = Password}), - ok; - [_E] -> - exists - end - end, - mnesia:transaction(F) - end. - -dirty_get_registered_users() -> - mnesia:dirty_all_keys(passwd). - -get_password(User) -> - LUser = jlib:nodeprep(User), - case catch mnesia:dirty_read(passwd, LUser) of - [#passwd{password = Password}] -> - Password; - _ -> - false - end. - -get_password_s(User) -> - LUser = jlib:nodeprep(User), - case catch mnesia:dirty_read(passwd, LUser) of - [#passwd{password = Password}] -> - Password; - _ -> - [] - end. - -is_user_exists(User) -> - case auth_method() of - internal -> - is_user_exists_internal(User); - external -> - is_user_exists_external(User); - ldap -> - is_user_exists_ldap(User) - end. - -is_user_exists_internal(User) -> - LUser = jlib:nodeprep(User), - case catch mnesia:dirty_read({passwd, LUser}) of - [] -> - false; - [_] -> - true; - _ -> - false - end. - -remove_user(User) -> - case user_method() of - internal -> - remove_user_internal(User); - ldap -> - {error, not_allowed} - end. - -remove_user_internal(User) -> - LUser = jlib:nodeprep(User), - F = fun() -> - mnesia:delete({passwd, LUser}) - end, - mnesia:transaction(F), - catch mod_roster:remove_user(User), - catch mod_offline:remove_user(User), - catch mod_last:remove_user(User), - catch mod_vcard:remove_user(User), - catch mod_private:remove_user(User). - -remove_user(User, Password) -> - case user_method() of - internal -> - remove_user_internal(User, Password); - ldap -> - not_allowed - end. - -remove_user_internal(User, Password) -> - LUser = jlib:nodeprep(User), - F = fun() -> - case mnesia:read({passwd, LUser}) of - [#passwd{password = Password}] -> - mnesia:delete({passwd, LUser}), - ok; - [_] -> - not_allowed; - _ -> - not_exists - end - end, - case mnesia:transaction(F) of - {atomic, ok} -> - catch mod_roster:remove_user(User), - catch mod_offline:remove_user(User), - catch mod_last:remove_user(User), - catch mod_vcard:remove_user(User), - catch mod_private:remove_user(User), - ok; - {atomic, Res} -> - Res; - _ -> - bad_request - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -check_password_ldap(User, Password, StreamID, Digest) -> - check_password_ldap(User, Password). - -check_password_external(User, Password, StreamID, Digest) -> - check_password_external(User, Password). - -check_password_ldap(User, Password) -> - case find_user_dn(User) of - false -> - false; - DN -> - case eldap:bind("ejabberd_bind", DN, Password) of - ok -> - true; - _ -> - false - end - end. - -is_user_exists_ldap(User) -> - case find_user_dn(User) of - false -> - false; - _DN -> - true - end. - -find_user_dn(User) -> - Attr = ejabberd_config:get_local_option(ldap_uidattr), - Filter = eldap:equalityMatch(Attr, User), - Base = ejabberd_config:get_local_option(ldap_base), - case eldap:search("ejabberd", [{base, Base}, - {filter, Filter}, - {attributes, []}]) of - #eldap_search_result{entries = [E | _]} -> - E#eldap_entry.object_name; - _ -> - false - end. - - - diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl new file mode 100644 index 000000000..e379fb9df --- /dev/null +++ b/src/ejabberd_auth_external.erl @@ -0,0 +1,67 @@ +%%%---------------------------------------------------------------------- +%%% File : ejabberd_auth_external.erl +%%% Author : Alexey Shchepin +%%% Purpose : Authentification via LDAP external script +%%% Created : 12 Dec 2004 by Alexey Shchepin +%%% Id : $Id$ +%%%---------------------------------------------------------------------- + +-module(ejabberd_auth_external). +-author('alexey@sevcom.net'). +-vsn('$Revision$ '). + +%% External exports +-export([start/0, + set_password/2, + check_password/2, + check_password/4, + try_register/2, + dirty_get_registered_users/0, + get_password/1, + get_password_s/1, + is_user_exists/1, + remove_user/1, + remove_user/2, + plain_password_required/0 + ]). + +%%%---------------------------------------------------------------------- +%%% API +%%%---------------------------------------------------------------------- +start() -> + extauth:start(ejabberd_config:get_local_option(extauth_program)), + ok. + +plain_password_required() -> + true. + +check_password(User, Password) -> + extauth:check_password(User, Password). + +check_password(User, Password, _StreamID, _Digest) -> + check_password(User, Password). + +set_password(User, Password) -> + extauth:set_password(User, Password). + +try_register(_User, _Password) -> + {error, not_allowed}. + +dirty_get_registered_users() -> + []. + +get_password(_User) -> + false. + +get_password_s(_User) -> + "". + +is_user_exists(User) -> + extauth:is_user_exists(User). + +remove_user(_User) -> + {error, not_allowed}. + +remove_user(_User, _Password) -> + not_allowed. + diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl new file mode 100644 index 000000000..b502eaf95 --- /dev/null +++ b/src/ejabberd_auth_internal.erl @@ -0,0 +1,167 @@ +%%%---------------------------------------------------------------------- +%%% File : ejabberd_auth_internal.erl +%%% Author : Alexey Shchepin +%%% Purpose : Authentification via mnesia +%%% Created : 12 Dec 2004 by Alexey Shchepin +%%% Id : $Id$ +%%%---------------------------------------------------------------------- + +-module(ejabberd_auth_internal). +-author('alexey@sevcom.net'). +-vsn('$Revision$ '). + +%% External exports +-export([start/0, + set_password/2, + check_password/2, + check_password/4, + try_register/2, + dirty_get_registered_users/0, + get_password/1, + get_password_s/1, + is_user_exists/1, + remove_user/1, + remove_user/2, + plain_password_required/0 + ]). + +-record(passwd, {user, password}). + +%%%---------------------------------------------------------------------- +%%% API +%%%---------------------------------------------------------------------- +start() -> + mnesia:create_table(passwd,[{disc_copies, [node()]}, + {attributes, record_info(fields, passwd)}]), + ok. + +plain_password_required() -> + false. + +check_password(User, Password) -> + LUser = jlib:nodeprep(User), + case catch mnesia:dirty_read({passwd, LUser}) of + [#passwd{password = Password}] -> + true; + _ -> + false + end. + +check_password(User, Password, StreamID, Digest) -> + LUser = jlib:nodeprep(User), + case catch mnesia:dirty_read({passwd, LUser}) of + [#passwd{password = Passwd}] -> + DigRes = if + Digest /= "" -> + Digest == sha:sha(StreamID ++ Passwd); + true -> + false + end, + if DigRes -> + true; + true -> + (Passwd == Password) and (Password /= "") + end; + _ -> + false + end. + +set_password(User, Password) -> + case jlib:nodeprep(User) of + error -> {error, invalid_jid}; + LUser -> + F = fun() -> + mnesia:write(#passwd{user = LUser, + password = Password}) + end, + mnesia:transaction(F) + end. + + +try_register(User, Password) -> + case jlib:nodeprep(User) of + error -> {error, invalid_jid}; + LUser -> + F = fun() -> + case mnesia:read({passwd, LUser}) of + [] -> + mnesia:write(#passwd{user = LUser, + password = Password}), + ok; + [_E] -> + exists + end + end, + mnesia:transaction(F) + end. + +dirty_get_registered_users() -> + mnesia:dirty_all_keys(passwd). + +get_password(User) -> + LUser = jlib:nodeprep(User), + case catch mnesia:dirty_read(passwd, LUser) of + [#passwd{password = Password}] -> + Password; + _ -> + false + end. + +get_password_s(User) -> + LUser = jlib:nodeprep(User), + case catch mnesia:dirty_read(passwd, LUser) of + [#passwd{password = Password}] -> + Password; + _ -> + [] + end. + +is_user_exists(User) -> + LUser = jlib:nodeprep(User), + case catch mnesia:dirty_read({passwd, LUser}) of + [] -> + false; + [_] -> + true; + _ -> + false + end. + +remove_user(User) -> + LUser = jlib:nodeprep(User), + F = fun() -> + mnesia:delete({passwd, LUser}) + end, + mnesia:transaction(F), + catch mod_roster:remove_user(User), + catch mod_offline:remove_user(User), + catch mod_last:remove_user(User), + catch mod_vcard:remove_user(User), + catch mod_private:remove_user(User). + +remove_user(User, Password) -> + LUser = jlib:nodeprep(User), + F = fun() -> + case mnesia:read({passwd, LUser}) of + [#passwd{password = Password}] -> + mnesia:delete({passwd, LUser}), + ok; + [_] -> + not_allowed; + _ -> + not_exists + end + end, + case mnesia:transaction(F) of + {atomic, ok} -> + catch mod_roster:remove_user(User), + catch mod_offline:remove_user(User), + catch mod_last:remove_user(User), + catch mod_vcard:remove_user(User), + catch mod_private:remove_user(User), + ok; + {atomic, Res} -> + Res; + _ -> + bad_request + end. diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl new file mode 100644 index 000000000..63c23c701 --- /dev/null +++ b/src/ejabberd_auth_ldap.erl @@ -0,0 +1,106 @@ +%%%---------------------------------------------------------------------- +%%% File : ejabberd_auth_ldap.erl +%%% Author : Alexey Shchepin +%%% Purpose : Authentification via LDAP +%%% Created : 12 Dec 2004 by Alexey Shchepin +%%% Id : $Id$ +%%%---------------------------------------------------------------------- + +-module(ejabberd_auth_ldap). +-author('alexey@sevcom.net'). +-vsn('$Revision$ '). + +%% External exports +-export([start/0, + set_password/2, + check_password/2, + check_password/4, + try_register/2, + dirty_get_registered_users/0, + get_password/1, + get_password_s/1, + is_user_exists/1, + remove_user/1, + remove_user/2, + plain_password_required/0 + ]). + +-include("eldap/eldap.hrl"). + +%%%---------------------------------------------------------------------- +%%% API +%%%---------------------------------------------------------------------- +start() -> + LDAPServers = ejabberd_config:get_local_option(ldap_servers), + RootDN = ejabberd_config:get_local_option(ldap_rootdn), + Password = ejabberd_config:get_local_option(ldap_password), + eldap:start_link("ejabberd", LDAPServers, 389, RootDN, Password), + eldap:start_link("ejabberd_bind", LDAPServers, 389, RootDN, Password), + ok. + +plain_password_required() -> + true. + +check_password(User, Password) -> + case find_user_dn(User) of + false -> + false; + DN -> + case eldap:bind("ejabberd_bind", DN, Password) of + ok -> + true; + _ -> + false + end + end. + +check_password(User, Password, _StreamID, _Digest) -> + check_password(User, Password). + +set_password(_User, _Password) -> + {error, not_allowed}. + +try_register(_User, _Password) -> + {error, not_allowed}. + +dirty_get_registered_users() -> + []. + +get_password(_User) -> + false. + +get_password_s(_User) -> + "". + +is_user_exists(User) -> + case find_user_dn(User) of + false -> + false; + _DN -> + true + end. + +remove_user(_User) -> + {error, not_allowed}. + +remove_user(_User, _Password) -> + not_allowed. + + +%%%---------------------------------------------------------------------- +%%% Internal functions +%%%---------------------------------------------------------------------- + +find_user_dn(User) -> + Attr = ejabberd_config:get_local_option(ldap_uidattr), + Filter = eldap:equalityMatch(Attr, User), + Base = ejabberd_config:get_local_option(ldap_base), + case eldap:search("ejabberd", [{base, Base}, + {filter, Filter}, + {attributes, []}]) of + #eldap_search_result{entries = [E | _]} -> + E#eldap_entry.object_name; + _ -> + false + end. + diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index ef0fa1e1c..30a494163 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -331,13 +331,12 @@ set_presence(User, Resource, Priority) -> mnesia:transaction(F). unset_presence(User, Resource, Status) -> - LUser = jlib:nodeprep(User), F = fun() -> UR = {User, Resource}, mnesia:delete({presence, UR}) end, mnesia:transaction(F), - catch mod_last:on_presence_update(LUser, Status). + ejabberd_hooks:run(unset_presence_hook, [User, Resource, Status]). get_user_present_resources(LUser) -> case catch mnesia:dirty_index_read(presence, LUser, #presence.user) of diff --git a/src/mod_last.erl b/src/mod_last.erl index 8f106d9e3..3e7a73fd9 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -16,7 +16,7 @@ stop/0, process_local_iq/3, process_sm_iq/3, - on_presence_update/2, + on_presence_update/3, remove_user/1]). -include("ejabberd.hrl"). @@ -34,7 +34,9 @@ start(Opts) -> gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_LAST, ?MODULE, process_local_iq, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_LAST, - ?MODULE, process_sm_iq, IQDisc). + ?MODULE, process_sm_iq, IQDisc), + ejabberd_hooks:add(unset_presence_hook, + ?MODULE, on_presence_update, 50). stop() -> gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_LAST), @@ -107,7 +109,8 @@ get_last(IQ, SubEl, LUser) -> -on_presence_update(LUser, Status) -> +on_presence_update(User, _Resource, Status) -> + LUser = jlib:nodeprep(User), {MegaSecs, Secs, _MicroSecs} = now(), TimeStamp = MegaSecs * 1000000 + Secs, F = fun() ->