From 829002694030f805386745043598ca9b498f9345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 5 Feb 2009 11:13:01 +0000 Subject: [PATCH] o Document the type of the argument(s) and the returned type of every functions. o Add guardians expression to many functions of ejabberd_auth and ejabberd_auth_anonymous to ensure at an early stage that we were given the right arguments. Other modules are not changed because they are only used by ejabberd_auth which already does the check. PR: EJABP-1 SVN Revision: 1863 --- ChangeLog | 14 +++ src/ejabberd_auth.erl | 197 ++++++++++++++++++++++++-------- src/ejabberd_auth_anonymous.erl | 160 ++++++++++++++++++++------ src/ejabberd_auth_external.erl | 58 +++++++++- src/ejabberd_auth_internal.erl | 92 ++++++++++++++- src/ejabberd_auth_ldap.erl | 87 ++++++++++++++ src/ejabberd_auth_odbc.erl | 78 ++++++++++++- src/ejabberd_auth_pam.erl | 78 +++++++++++-- 8 files changed, 672 insertions(+), 92 deletions(-) diff --git a/ChangeLog b/ChangeLog index f0a4cbbaa..263a79620 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2009-02-05 Jean-Sébastien Pédron + + * src/ejabberd_auth.erl, src/ejabberd_auth_anonymous.erl, + src/ejabberd_auth_external.erl, src/ejabberd_auth_internal.erl, + src/ejabberd_auth_ldap.erl, src/ejabberd_auth_odbc.erl, + src/ejabberd_auth_pam.erl: Document the type of the argument(s) and + the returned type of every functions. + + * src/ejabberd_auth.erl, src/ejabberd_auth_anonymous.erl: Add + guardians expression to many functions to ensure at an early stage + that we were given the right arguments. Other modules are not changed + because they are only used by ejabberd_auth which already does the + check. + 2009-01-30 Jean-Sébastien Pédron * doc/api/Makefile: Disable "TODO:" interpretation in eDoc because diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 209373174..6156b13bc 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -56,9 +56,16 @@ -include("ejabberd.hrl"). +%% @type authmodule() = ejabberd_auth_anonymous | ejabberd_auth_external | +%% ejabberd_auth_internal | ejabberd_auth_ldap | +%% ejabberd_auth_odbc | ejabberd_auth_pam | atom(). + %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- + +%% @spec () -> term() + start() -> lists:foreach( fun(Host) -> @@ -68,42 +75,56 @@ start() -> end, auth_modules(Host)) end, ?MYHOSTS). -plain_password_required(Server) -> +%% @spec (Server) -> bool() +%% Server = string() + +plain_password_required(Server) when is_list(Server) -> lists:any( fun(M) -> M:plain_password_required() end, auth_modules(Server)). +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() %% @doc Check if the user and password can login in server. -%% @spec (User::string(), Server::string(), Password::string()) -> -%% true | false -check_password(User, Server, Password) -> + +check_password(User, Server, Password) + when is_list(User), is_list(Server), is_list(Password) -> lists:any( fun(M) -> M:check_password(User, Server, Password) end, auth_modules(Server)). +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() %% @doc Check if the user and password can login in server. -%% @spec (User::string(), Server::string(), Password::string(), -%% StreamID::string(), Digest::string()) -> -%% true | false -check_password(User, Server, Password, StreamID, Digest) -> + +check_password(User, Server, Password, StreamID, Digest) + when is_list(User), is_list(Server), is_list(Password), + is_list(StreamID), is_list(Digest) -> lists:any( fun(M) -> M:check_password(User, Server, Password, StreamID, Digest) end, auth_modules(Server)). +%% @spec (User, Server, Password) -> {true, AuthModule} | false +%% User = string() +%% Server = string() +%% Password = string() +%% AuthModule = authmodule() %% @doc Check if the user and password can login in server. %% The user can login if at least an authentication method accepts the user %% and the password. %% The first authentication method that accepts the credentials is returned. -%% @spec (User::string(), Server::string(), Password::string()) -> -%% {true, AuthModule} | false -%% where -%% AuthModule = ejabberd_auth_anonymous | ejabberd_auth_external -%% | ejabberd_auth_internal | ejabberd_auth_ldap -%% | ejabberd_auth_odbc | ejabberd_auth_pam -check_password_with_authmodule(User, Server, Password) -> + +check_password_with_authmodule(User, Server, Password) + when is_list(User), is_list(Server), is_list(Password) -> Res = lists:dropwhile( fun(M) -> not apply(M, check_password, @@ -114,7 +135,17 @@ check_password_with_authmodule(User, Server, Password) -> [AuthMod | _] -> {true, AuthMod} end. -check_password_with_authmodule(User, Server, Password, StreamID, Digest) -> +%% @spec (User, Server, Password, StreamID, Digest) -> {true, AuthModule} | false +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() +%% AuthModule = authmodule() + +check_password_with_authmodule(User, Server, Password, StreamID, Digest) + when is_list(User), is_list(Server), is_list(Password), + is_list(StreamID), is_list(Digest) -> Res = lists:dropwhile( fun(M) -> not apply(M, check_password, @@ -125,13 +156,17 @@ check_password_with_authmodule(User, Server, Password, StreamID, Digest) -> [AuthMod | _] -> {true, AuthMod} end. -%% @spec (User::string(), Server::string(), Password::string()) -> -%% ok | {error, ErrorType} -%% where ErrorType = empty_password | not_allowed | invalid_jid +%% @spec (User, Server, Password) -> ok | {error, ErrorType} +%% User = string() +%% Server = string() +%% Password = string() +%% ErrorType = empty_password | not_allowed | invalid_jid + set_password(_User, _Server, "") -> %% We do not allow empty password {error, empty_password}; -set_password(User, Server, Password) -> +set_password(User, Server, Password) + when is_list(User), is_list(Server), is_list(Password) -> lists:foldl( fun(M, {error, _}) -> M:set_password(User, Server, Password); @@ -140,10 +175,15 @@ set_password(User, Server, Password) -> end, {error, not_allowed}, auth_modules(Server)). %% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() | nil() + try_register(_User, _Server, "") -> %% We do not allow empty password {error, not_allowed}; -try_register(User, Server, Password) -> +try_register(User, Server, Password) + when is_list(User), is_list(Server), is_list(Password) -> case is_user_exists(User,Server) of true -> {atomic, exists}; @@ -168,27 +208,48 @@ try_register(User, Server, Password) -> end end. -%% Registered users list do not include anonymous users logged +%% @spec () -> [{LUser, LServer}] +%% LUser = string() +%% LServer = string() +%% @doc Registered users list do not include anonymous users logged. + dirty_get_registered_users() -> lists:flatmap( fun(M) -> M:dirty_get_registered_users() end, auth_modules()). -%% Registered users list do not include anonymous users logged -get_vh_registered_users(Server) -> +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() +%% @doc Registered users list do not include anonymous users logged. + +get_vh_registered_users(Server) when is_list(Server) -> lists:flatmap( fun(M) -> M:get_vh_registered_users(Server) end, auth_modules(Server)). -get_vh_registered_users(Server, Opts) -> +%% @spec (Server, Opts) -> [{LUser, LServer}] +%% Server = string() +%% Opts = [{Opt, Val}] +%% Opt = atom() +%% Val = term() +%% LUser = string() +%% LServer = string() + +get_vh_registered_users(Server, Opts) when is_list(Server) -> lists:flatmap( fun(M) -> M:get_vh_registered_users(Server, Opts) end, auth_modules(Server)). -get_vh_registered_users_number(Server) -> +%% @spec (Server) -> Users_Number +%% Server = string() +%% Users_Number = integer() + +get_vh_registered_users_number(Server) when is_list(Server) -> lists:sum( lists:map( fun(M) -> @@ -201,7 +262,14 @@ get_vh_registered_users_number(Server) -> end end, auth_modules(Server))). -get_vh_registered_users_number(Server, Opts) -> +%% @spec (Server, Opts) -> Users_Number +%% Server = string() +%% Opts = [{Opt, Val}] +%% Opt = atom() +%% Val = term() +%% Users_Number = integer() + +get_vh_registered_users_number(Server, Opts) when is_list(Server) -> lists:sum( lists:map( fun(M) -> @@ -214,9 +282,13 @@ get_vh_registered_users_number(Server, Opts) -> end end, auth_modules(Server))). +%% @spec (User, Server) -> Password | false +%% User = string() +%% Server = string() +%% Password = string() %% @doc Get the password of the user. -%% @spec (User::string(), Server::string()) -> Password::string() -get_password(User, Server) -> + +get_password(User, Server) when is_list(User), is_list(Server) -> lists:foldl( fun(M, false) -> M:get_password(User, Server); @@ -224,7 +296,13 @@ get_password(User, Server) -> Password end, false, auth_modules(Server)). -get_password_s(User, Server) -> +%% @spec (User, Server) -> Password | nil() +%% User = string() +%% Server = string() +%% Password = string() +%% @doc Get the password of the user. + +get_password_s(User, Server) when is_list(User), is_list(Server) -> case get_password(User, Server) of false -> ""; @@ -232,10 +310,15 @@ get_password_s(User, Server) -> Password end. +%% @spec (User, Server) -> {Password, AuthModule} | {false, none} +%% User = string() +%% Server = string() +%% Password = string() +%% AuthModule = authmodule() %% @doc Get the password of the user and the auth module. -%% @spec (User::string(), Server::string()) -> -%% {Password::string(), AuthModule::atom()} | {false, none} -get_password_with_authmodule(User, Server) -> + +get_password_with_authmodule(User, Server) + when is_list(User), is_list(Server) -> lists:foldl( fun(M, {false, _}) -> {M:get_password(User, Server), M}; @@ -243,26 +326,39 @@ get_password_with_authmodule(User, Server) -> {Password, AuthModule} end, {false, none}, auth_modules(Server)). -%% Returns true if the user exists in the DB or if an anonymous user is logged -%% under the given name -is_user_exists(User, Server) -> +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() +%% @doc Returns true if the user exists in the DB or if an anonymous +%% user is logged under the given name. + +is_user_exists(User, Server) when is_list(User), is_list(Server) -> lists:any( fun(M) -> M:is_user_exists(User, Server) end, auth_modules(Server)). -%% Check if the user exists in all authentications module except the module -%% passed as parameter -is_user_exists_in_other_modules(Module, User, Server) -> +%% @spec (Module, User, Server) -> bool +%% Module = authmodule() +%% User = string() +%% Server = string() +%% @doc Check if the user exists in all authentications module except +%% the module passed as parameter. + +is_user_exists_in_other_modules(Module, User, Server) + when is_list(User), is_list(Server) -> lists:any( fun(M) -> M:is_user_exists(User, Server) end, auth_modules(Server)--[Module]). %% @spec (User, Server) -> ok | error | {error, not_allowed} +%% User = string() +%% Server = string() %% @doc Remove user. %% Note: it may return ok even if there was some problem removing the user. -remove_user(User, Server) -> + +remove_user(User, Server) when is_list(User), is_list(Server) -> R = lists:foreach( fun(M) -> M:remove_user(User, Server) @@ -274,11 +370,16 @@ remove_user(User, Server) -> R. %% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error +%% User = string() +%% Server = string() +%% Password = string() %% @doc Try to remove user if the provided password is correct. %% The removal is attempted in each auth method provided: %% when one returns 'ok' the loop stops; %% if no method returns 'ok' then it returns the error message indicated by the last method attempted. -remove_user(User, Server, Password) -> + +remove_user(User, Server, Password) + when is_list(User), is_list(Server), is_list(Password) -> R = lists:foldl( fun(_M, ok = Res) -> Res; @@ -295,8 +396,11 @@ remove_user(User, Server, Password) -> %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- -%% Return the lists of all the auth modules actually used in the -%% configuration + +%% @spec () -> [authmodule()] +%% @doc Return the lists of all the auth modules actually used in the +%% configuration. + auth_modules() -> lists:usort( lists:flatmap( @@ -304,8 +408,11 @@ auth_modules() -> auth_modules(Server) end, ?MYHOSTS)). -%% Return the list of authenticated modules for a given host -auth_modules(Server) -> +%% @spec (Server) -> [authmodule()] +%% Server = string() +%% @doc Return the list of authenticated modules for a given host. + +auth_modules(Server) when is_list(Server) -> LServer = exmpp_stringprep:nameprep(Server), Method = ejabberd_config:get_local_option({auth_method, LServer}), Methods = if diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 3135c6dd3..419398fc2 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -53,12 +53,18 @@ remove_user/3, plain_password_required/0]). +-include_lib("exmpp/include/exmpp_xmpp.hrl"). + -include("ejabberd.hrl"). -record(anonymous, {us, sid}). -%% Create the anonymous table if at least one virtual host has anonymous features enabled -%% Register to login / logout events -start(Host) -> +%% @spec (Host) -> ok +%% Host = string() +%% @doc Create the anonymous table if at least one virtual host has +%% anonymous features enabled. +%% Register to login / logout events. + +start(Host) when is_list(Host) -> %% TODO: Check cluster mode mnesia:create_table(anonymous, [{ram_copies, [node()]}, {type, bag}, @@ -70,13 +76,20 @@ start(Host) -> ?MODULE, unregister_connection, 100), ok. -%% Return true if anonymous is allowed for host or false otherwise -allow_anonymous(Host) -> +%% @spec (Host) -> bool() +%% Host = string() +%% @doc Return true if anonymous is allowed for host or false otherwise. + +allow_anonymous(Host) when is_list(Host) -> lists:member(?MODULE, ejabberd_auth:auth_modules(Host)). -%% Return true if anonymous mode is enabled and if anonymous protocol is SASL -%% anonymous protocol can be: sasl_anon|login_anon|both -is_sasl_anonymous_enabled(Host) -> +%% @spec (Host) -> bool() +%% Host = string() +%% @doc Return true if anonymous mode is enabled and if anonymous +%% protocol is SASL anonymous. +%% protocol can be: sasl_anon|login_anon|both + +is_sasl_anonymous_enabled(Host) when is_list(Host) -> case allow_anonymous(Host) of false -> false; true -> @@ -87,10 +100,13 @@ is_sasl_anonymous_enabled(Host) -> end end. -%% Return true if anonymous login is enabled on the server +%% @spec (Host) -> bool() +%% Host = string() +%% @doc Return true if anonymous login is enabled on the server. %% anonymous login can be use using standard authentication method (i.e. with %% clients that do not support anonymous login) -is_login_anonymous_enabled(Host) -> + +is_login_anonymous_enabled(Host) when is_list(Host) -> case allow_anonymous(Host) of false -> false; true -> @@ -101,9 +117,12 @@ is_login_anonymous_enabled(Host) -> end end. -%% Return the anonymous protocol to use: sasl_anon|login_anon|both +%% @spec (Host) -> sasl_anon | login_anon | both +%% Host = string() +%% @doc Return the anonymous protocol to use: sasl_anon|login_anon|both. %% defaults to login_anon -anonymous_protocol(Host) -> + +anonymous_protocol(Host) when is_list(Host) -> case ejabberd_config:get_local_option({anonymous_protocol, Host}) of sasl_anon -> sasl_anon; login_anon -> login_anon; @@ -111,16 +130,24 @@ anonymous_protocol(Host) -> _Other -> sasl_anon end. -%% Return true if multiple connections have been allowed in the config file +%% @spec (Host) -> bool() +%% Host = string() +%% @doc Return true if multiple connections have been allowed in the +%% config file. %% defaults to false -allow_multiple_connections(Host) -> + +allow_multiple_connections(Host) when is_list(Host) -> case ejabberd_config:get_local_option({allow_multiple_connections, Host}) of true -> true; _Other -> false end. -%% Check if user exist in the anonymus database -anonymous_user_exist(User, Server) -> +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() +%% @doc Check if user exist in the anonymus database. + +anonymous_user_exist(User, Server) when is_list(User), is_list(Server) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, @@ -131,16 +158,26 @@ anonymous_user_exist(User, Server) -> true end. -%% Remove connection from Mnesia tables -remove_connection(SID, LUser, LServer) -> +%% @spec (SID, LUser, LServer) -> term() +%% SID = term() +%% LUser = string() +%% LServer = string() +%% @doc Remove connection from Mnesia tables. + +remove_connection(SID, LUser, LServer) when is_list(LUser), is_list(LServer) -> US = {LUser, LServer}, F = fun() -> mnesia:delete_object({anonymous, US, SID}) end, mnesia:transaction(F). -%% Register connection -register_connection(SID, JID, Info) -> +%% @spec (SID, JID, Info) -> term() +%% SID = term() +%% JID = exmpp_jid:jid() +%% Info = [term()] +%% @doc Register connection. + +register_connection(SID, JID, Info) when ?IS_JID(JID) -> LUser = exmpp_jid:lnode(JID), LServer = exmpp_jid:ldomain(JID), case proplists:get_value(auth_module, Info) of @@ -155,26 +192,40 @@ register_connection(SID, JID, Info) -> ok end. -%% Remove an anonymous user from the anonymous users table -unregister_connection(SID, JID, _) -> +%% @spec (SID, JID, Ignored) -> term() +%% SID = term() +%% JID = exmpp_jid:jid() +%% Ignored = term() +%% @doc Remove an anonymous user from the anonymous users table. + +unregister_connection(SID, JID, _) when ?IS_JID(JID) -> LUser = exmpp_jid:lnode(JID), LServer = exmpp_jid:ldomain(JID), purge_hook(anonymous_user_exist(LUser, LServer), LUser, LServer), remove_connection(SID, LUser, LServer). -%% Launch the hook to purge user data only for anonymous users +%% @spec (bool(), LUser, LServer) -> term() +%% LUser = string() +%% LServer = string() +%% @doc Launch the hook to purge user data only for anonymous users. + purge_hook(false, _LUser, _LServer) -> ok; -purge_hook(true, LUser, LServer) -> +purge_hook(true, LUser, LServer) when is_list(LUser), is_list(LServer) -> ejabberd_hooks:run(anonymous_purge_hook, LServer, [LUser, LServer]). %% --------------------------------- %% Specific anonymous auth functions %% --------------------------------- -%% When anonymous login is enabled, check the password for permenant users -%% before allowing access +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% @doc When anonymous login is enabled, check the password for +%% permenant users before allowing access. + check_password(User, Server, Password) -> check_password(User, Server, Password, undefined, undefined). check_password(User, Server, _Password, _StreamID, _Digest) -> @@ -186,6 +237,10 @@ check_password(User, Server, _Password, _StreamID, _Digest) -> false -> login(User, Server) end. +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + login(User, Server) -> case is_login_anonymous_enabled(Server) of false -> false; @@ -200,8 +255,13 @@ login(User, Server) -> end end. -%% When anonymous login is enabled, check that the user is permanent before -%% changing its password +%% @spec (User, Server, Password) -> ok | {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() +%% @doc When anonymous login is enabled, check that the user is +%% permanent before changing its password. + set_password(User, Server, _Password) -> case anonymous_user_exist(User, Server) of true -> @@ -210,22 +270,41 @@ set_password(User, Server, _Password) -> {error, not_allowed} end. -%% When anonymous login is enabled, check if permanent users are allowed on -%% the server: +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() +%% @doc When anonymous login is enabled, check if permanent users are +%% allowed on the server: + try_register(_User, _Server, _Password) -> {error, not_allowed}. +%% @spec () -> nil() + dirty_get_registered_users() -> []. +%% @spec (Server) -> nil() +%% Server = string() + get_vh_registered_users(_Server) -> []. +%% @spec (User, Server) -> Password | false +%% User = string() +%% Server = string() +%% Password = nil() +%% @doc Return password of permanent user or false for anonymous users. -%% Return password of permanent user or false for anonymous users get_password(User, Server) -> get_password(User, Server, ""). +%% @spec (User, Server, DefaultValue) -> DefaultValue | false +%% User = string() +%% Server = string() +%% DefaultValue = string() + get_password(User, Server, DefaultValue) -> case anonymous_user_exist(User, Server) of %% We return the default value if the user is anonymous @@ -236,17 +315,32 @@ get_password(User, Server, DefaultValue) -> false end. -%% Returns true if the user exists in the DB or if an anonymous user is logged -%% under the given name +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() +%% @doc Returns true if the user exists in the DB or if an anonymous +%% user is logged under the given name. + is_user_exists(User, Server) -> anonymous_user_exist(User, Server). +%% @spec (User, Server) -> {error, not_allowed} +%% User = string() +%% Server = string() + remove_user(_User, _Server) -> {error, not_allowed}. +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + remove_user(_User, _Server, _Password) -> not_allowed. +%% @spec () -> bool() + plain_password_required() -> false. diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index af7c5b048..9c6dec870 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -46,49 +46,103 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- + +%% @spec (Host) -> ok +%% Host = string() + start(Host) -> extauth:start( Host, ejabberd_config:get_local_option({extauth_program, Host})), ok. +%% @spec () -> bool() + plain_password_required() -> true. +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + check_password(User, Server, Password) -> extauth:check_password(User, Server, Password) andalso Password /= "". +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() + check_password(User, Server, Password, _StreamID, _Digest) -> check_password(User, Server, Password). +%% @spec (User, Server, Password) -> ok | {error, unknown_problem} +%% User = string() +%% Server = string() +%% Password = string() + set_password(User, Server, Password) -> case extauth:set_password(User, Server, Password) of true -> ok; _ -> {error, unknown_problem} end. +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + try_register(_User, _Server, _Password) -> {error, not_allowed}. -%% TODO -%% Return the list of all users handled by external +%% @spec () -> nil() +%% @todo Write it. +%% @doc Return the list of all users handled by external. + dirty_get_registered_users() -> []. +%% @spec (Server) -> nil() +%% Server = string() + get_vh_registered_users(_Server) -> []. +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + get_password(_User, _Server) -> false. +%% @spec (User, Server) -> nil() +%% User = string() +%% Server = string() + get_password_s(_User, _Server) -> "". +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + is_user_exists(User, Server) -> extauth:is_user_exists(User, Server). +%% @spec (User, Server) -> {error, not_allowed} +%% User = string() +%% Server = string() + remove_user(_User, _Server) -> {error, not_allowed}. +%% @spec (User, Server, Password) -> not_allowed +%% User = string() +%% Server = string() +%% Password = string() + remove_user(_User, _Server, _Password) -> not_allowed. diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 527c183b7..2df3cab39 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -53,15 +53,26 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- + +%% @spec (Host) -> ok +%% Host = string() + start(_Host) -> mnesia:create_table(passwd, [{disc_copies, [node()]}, {attributes, record_info(fields, passwd)}]), update_table(), ok. +%% @spec () -> bool() + plain_password_required() -> false. +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + check_password(User, Server, Password) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -73,6 +84,13 @@ check_password(User, Server, Password) -> false end. +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() + check_password(User, Server, Password, StreamID, Digest) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -94,8 +112,11 @@ check_password(User, Server, Password, StreamID, Digest) -> false end. -%% @spec (User::string(), Server::string(), Password::string()) -> -%% ok | {error, invalid_jid} +%% @spec (User, Server, Password) -> ok | {error, invalid_jid} +%% User = string() +%% Server = string() +%% Password = string() + set_password(User, Server, Password) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -113,6 +134,10 @@ set_password(User, Server, Password) -> end. %% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid} | {aborted, Reason} +%% User = string() +%% Server = string() +%% Password = string() + try_register(User, Server, Password) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -134,10 +159,19 @@ try_register(User, Server, Password) -> mnesia:transaction(F) end. -%% Get all registered users in Mnesia +%% @spec () -> [{LUser, LServer}] +%% LUser = string() +%% LServer = string() +%% @doc Get all registered users in Mnesia. + dirty_get_registered_users() -> mnesia:dirty_all_keys(passwd). +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() + get_vh_registered_users(Server) -> LServer = exmpp_stringprep:nameprep(Server), mnesia:dirty_select( @@ -146,6 +180,24 @@ get_vh_registered_users(Server) -> [{'==', {element, 2, '$1'}, LServer}], ['$1']}]). +%% @spec (Server, Opts) -> [{LUser, LServer}] +%% Server = string() +%% Opts = [{Opt, Val}] +%% Opt = atom() +%% Val = term() +%% LUser = string() +%% LServer = string() +%% @doc Return the registered users for the specified host. +%% +%% `Opts' can be one of the following: +%%
    +%%
  • `[{from, integer()}, {to, integer()}]'
  • +%%
  • `[{limit, integer()}, {offset, integer()}]'
  • +%%
  • `[{prefix, string()}]'
  • +%%
  • `[{prefix, string()}, {from, integer()}, {to, integer()}]'
  • +%%
  • `[{prefix, string()}, {limit, integer()}, {offset, integer()}]'
  • +%%
+ get_vh_registered_users(Server, [{from, Start}, {to, End}]) when is_integer(Start) and is_integer(End) -> get_vh_registered_users(Server, [{limit, End-Start+1}, {offset, Start}]); @@ -192,10 +244,19 @@ get_vh_registered_users(Server, [{prefix, Prefix}, {limit, Limit}, {offset, Offs get_vh_registered_users(Server, _) -> get_vh_registered_users(Server). +%% @spec (Server) -> Users_Number +%% Server = string() +%% Users_Number = integer() + get_vh_registered_users_number(Server) -> Set = get_vh_registered_users(Server), length(Set). +%% @spec (Server, [{prefix, Prefix}]) -> Users_Number +%% Server = string() +%% Prefix = string() +%% Users_Number = integer() + get_vh_registered_users_number(Server, [{prefix, Prefix}]) when is_list(Prefix) -> Set = [{U, S} || {U, S} <- get_vh_registered_users(Server), lists:prefix(Prefix, U)], length(Set); @@ -203,6 +264,11 @@ get_vh_registered_users_number(Server, [{prefix, Prefix}]) when is_list(Prefix) get_vh_registered_users_number(Server, _) -> get_vh_registered_users_number(Server). +%% @spec (User, Server) -> Password | false +%% User = string() +%% Server = string() +%% Password = string() + get_password(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -219,6 +285,11 @@ get_password(User, Server) -> false end. +%% @spec (User, Server) -> Password | nil() +%% User = string() +%% Server = string() +%% Password = string() + get_password_s(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -235,6 +306,10 @@ get_password_s(User, Server) -> [] end. +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + is_user_exists(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -254,8 +329,11 @@ is_user_exists(User, Server) -> end. %% @spec (User, Server) -> ok +%% User = string() +%% Server = string() %% @doc Remove user. %% Note: it returns ok even if there was some problem removing the user. + remove_user(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -272,7 +350,11 @@ remove_user(User, Server) -> end. %% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request +%% User = string() +%% Server = string() +%% Password = string() %% @doc Remove user if the provided password is correct. + remove_user(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -302,11 +384,15 @@ remove_user(User, Server, Password) -> bad_request end. +%% @spec () -> term() update_table() -> Fields = record_info(fields, passwd), case mnesia:table_info(passwd, attributes) of Fields -> + % No conversion is needed when the table comes from an exmpp-less + % Ejabberd because ejabberd_auth* modules use string() and not + % binary(). ok; [user, password] -> ?INFO_MSG("Converting passwd table from " diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index b8c6a971e..c73ad0a55 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -94,6 +94,9 @@ handle_info(_Info, State) -> %%% API %%%---------------------------------------------------------------------- +%% @spec (Host) -> term() +%% Host = string() + start(Host) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), ChildSpec = { @@ -102,19 +105,31 @@ start(Host) -> }, supervisor:start_child(ejabberd_sup, ChildSpec). +%% @spec (Host) -> term() +%% Host = string() + stop(Host) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), gen_server:call(Proc, stop), supervisor:terminate_child(ejabberd_sup, Proc), supervisor:delete_child(ejabberd_sup, Proc). +%% @spec (Host) -> term() +%% Host = string() + start_link(Host) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), gen_server:start_link({local, Proc}, ?MODULE, Host, []). +%% @hidden + terminate(_Reason, _State) -> ok. +%% @spec (Host) -> {ok, State} +%% Host = string() +%% State = term() + init(Host) -> State = parse_options(Host), eldap_pool:start_link(State#state.eldap_id, @@ -131,9 +146,16 @@ init(Host) -> State#state.password), {ok, State}. +%% @spec () -> true + plain_password_required() -> true. +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + check_password(User, Server, Password) -> %% In LDAP spec: empty password means anonymous authentication. %% As ejabberd is providing other anonymous authentication mechanisms @@ -147,16 +169,36 @@ check_password(User, Server, Password) -> end end. +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() + check_password(User, Server, Password, _StreamID, _Digest) -> check_password(User, Server, Password). +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + set_password(_User, _Server, _Password) -> {error, not_allowed}. %% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + try_register(_User, _Server, _Password) -> {error, not_allowed}. +%% @spec () -> [{LUser, LServer}] +%% LUser = string() +%% LServer = string() + dirty_get_registered_users() -> Servers = ejabberd_config:get_vh_by_auth_method(ldap), lists:flatmap( @@ -164,21 +206,42 @@ dirty_get_registered_users() -> get_vh_registered_users(Server) end, Servers). +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() + get_vh_registered_users(Server) -> case catch get_vh_registered_users_ldap(Server) of {'EXIT', _} -> []; Result -> Result end. +%% @spec (Server) -> Users_Number +%% Server = string() +%% Users_Number = integer() + get_vh_registered_users_number(Server) -> length(get_vh_registered_users(Server)). +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + get_password(_User, _Server) -> false. +%% @spec (User, Server) -> nil() +%% User = string() +%% Server = string() + get_password_s(_User, _Server) -> "". +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + is_user_exists(User, Server) -> case catch is_user_exists_ldap(User, Server) of {'EXIT', _} -> @@ -187,15 +250,30 @@ is_user_exists(User, Server) -> Result end. +%% @spec (User, Server) -> {error, not_allowed} +%% User = string() +%% Server = string() + remove_user(_User, _Server) -> {error, not_allowed}. +%% @spec (User, Server, Password) -> not_allowed +%% User = string() +%% Server = string() +%% Password = string() + remove_user(_User, _Server, _Password) -> not_allowed. %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- + +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + check_password_ldap(User, Server, Password) -> {ok, State} = eldap_utils:get_state(Server, ?MODULE), case find_user_dn(User, State) of @@ -208,6 +286,11 @@ check_password_ldap(User, Server, Password) -> end end. +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() + get_vh_registered_users_ldap(Server) -> {ok, State} = eldap_utils:get_state(Server, ?MODULE), UIDs = State#state.uids, @@ -250,6 +333,10 @@ get_vh_registered_users_ldap(Server) -> [] end. +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + is_user_exists_ldap(User, Server) -> {ok, State} = eldap_utils:get_state(Server, ?MODULE), case find_user_dn(User, State) of diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 92a8493b6..bee6d9013 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -51,12 +51,23 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- + +%% @spec (Host) -> ok +%% Host = string() + start(_Host) -> ok. +%% @spec () -> bool() + plain_password_required() -> false. +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + check_password(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -73,6 +84,13 @@ check_password(User, Server, Password) -> false end. +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() + check_password(User, Server, Password, StreamID, Digest) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -99,8 +117,11 @@ check_password(User, Server, Password, StreamID, Digest) -> false end. -%% @spec (User::string(), Server::string(), Password::string()) -> -%% ok | {error, invalid_jid} +%% @spec (User, Server, Password) -> ok | {error, invalid_jid} +%% User = string() +%% Server = string() +%% Password = string() + set_password(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -118,6 +139,10 @@ set_password(User, Server, Password) -> %% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid} +%% User = string() +%% Server = string() +%% Password = string() + try_register(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -135,6 +160,10 @@ try_register(User, Server, Password) -> {error, invalid_jid} end. +%% @spec () -> [{LUser, LServer}] +%% LUser = string() +%% LServer = string() + dirty_get_registered_users() -> Servers = ejabberd_config:get_vh_by_auth_method(odbc), lists:flatmap( @@ -142,6 +171,11 @@ dirty_get_registered_users() -> get_vh_registered_users(Server) end, Servers). +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() + get_vh_registered_users(Server) -> LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:list_users(LServer) of @@ -151,6 +185,14 @@ get_vh_registered_users(Server) -> [] end. +%% @spec (Server, Opts) -> [{LUser, LServer}] +%% Server = string() +%% Opts = [{Opt, Val}] +%% Opt = atom() +%% Val = term() +%% LUser = string() +%% LServer = string() + get_vh_registered_users(Server, Opts) -> LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:list_users(LServer, Opts) of @@ -160,6 +202,10 @@ get_vh_registered_users(Server, Opts) -> [] end. +%% @spec (Server) -> Users_Number +%% Server = string() +%% Users_Number = integer() + get_vh_registered_users_number(Server) -> LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:users_number(LServer) of @@ -169,6 +215,13 @@ get_vh_registered_users_number(Server) -> 0 end. +%% @spec (Server, Opts) -> Users_Number +%% Server = string() +%% Opts = [{Opt, Val}] +%% Opt = atom() +%% Val = term() +%% Users_Number = integer() + get_vh_registered_users_number(Server, Opts) -> LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:users_number(LServer, Opts) of @@ -178,6 +231,11 @@ get_vh_registered_users_number(Server, Opts) -> 0 end. +%% @spec (User, Server) -> Password | false +%% User = string() +%% Server = string() +%% Password = string() + get_password(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -194,6 +252,11 @@ get_password(User, Server) -> false end. +%% @spec (User, Server) -> Password | nil() +%% User = string() +%% Server = string() +%% Password = string() + get_password_s(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -210,6 +273,10 @@ get_password_s(User, Server) -> "" end. +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + is_user_exists(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -227,8 +294,11 @@ is_user_exists(User, Server) -> end. %% @spec (User, Server) -> ok | error +%% User = string() +%% Server = string() %% @doc Remove user. %% Note: it may return ok even if there was some problem removing the user. + remove_user(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -242,7 +312,11 @@ remove_user(User, Server) -> end. %% @spec (User, Server, Password) -> ok | error | not_exists | not_allowed +%% User = string() +%% Server = string() +%% Password = string() %% @doc Remove user if the provided password is correct. + remove_user(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl index c8a8031c2..a09bbac65 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -45,6 +45,10 @@ %%==================================================================== %% API %%==================================================================== + +%% @spec (Host) -> ok | term() +%% Host = string() + start(_Host) -> case epam:start() of {ok, _} -> ok; @@ -52,55 +56,115 @@ start(_Host) -> Err -> Err end. +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + set_password(_User, _Server, _Password) -> {error, not_allowed}. +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() + check_password(User, Server, Password, _StreamID, _Digest) -> check_password(User, Server, Password). -check_password(User, Host, Password) -> - Service = get_pam_service(Host), +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + +check_password(User, Server, Password) -> + Service = get_pam_service(Server), case catch epam:authenticate(Service, User, Password) of true -> true; _ -> false end. +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + try_register(_User, _Server, _Password) -> {error, not_allowed}. +%% @spec () -> [{LUser, LServer}] +%% LUser = string() +%% LServer = string() + dirty_get_registered_users() -> []. -get_vh_registered_users(_Host) -> +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() + +get_vh_registered_users(_Server) -> []. +%% @spec (User, Server) -> Password | false +%% User = string() +%% Server = string() +%% Password = string() + get_password(_User, _Server) -> false. +%% @spec (User, Server) -> Password | nil() +%% User = string() +%% Server = string() +%% Password = string() + get_password_s(_User, _Server) -> "". -is_user_exists(User, Host) -> - Service = get_pam_service(Host), +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + +is_user_exists(User, Server) -> + Service = get_pam_service(Server), case catch epam:acct_mgmt(Service, User) of true -> true; _ -> false end. +%% @spec (User, Server) -> {error, not_allowed} +%% User = string() +%% Server = string() + remove_user(_User, _Server) -> {error, not_allowed}. +%% @spec (User, Server, Password) -> not_allowed +%% User = string() +%% Server = string() +%% Password = string() + remove_user(_User, _Server, _Password) -> not_allowed. +%% @spec () -> bool() + plain_password_required() -> true. %%==================================================================== %% Internal functions %%==================================================================== -get_pam_service(Host) -> - case ejabberd_config:get_local_option({pam_service, Host}) of + +%% @spec (Server) -> string() +%% Server = string() + +get_pam_service(Server) -> + case ejabberd_config:get_local_option({pam_service, Server}) of undefined -> "ejabberd"; Service -> Service end.