Author: Saimonmoore URL: http://www.ejabberd.im/node/2835#comment-51756 diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index 13dafa7..09c9518 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -35,6 +35,9 @@ try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, + get_vh_registered_users/2, + get_vh_registered_users_number/1, + get_vh_registered_users_number/2, get_password/2, get_password_s/2, is_user_exists/2, @@ -43,10 +46,21 @@ plain_password_required/0 ]). +-include("ejabberd.hrl"). + +-record(passwd, {us, password}). + %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- start(Host) -> + mnesia:create_table(passwd, [{disc_copies, [node()]}, + {attributes, record_info(fields, passwd)}]), + update_table(), + ejabberd_ctl:register_commands( + Host, + [{"registered-users", "list all registered users"}], + ejabberd_auth, ctl_process_get_registered), extauth:start( Host, ejabberd_config:get_local_option({extauth_program, Host})), ok. @@ -63,27 +77,196 @@ check_password(User, Server, Password, _StreamID, _Digest) -> set_password(User, Server, Password) -> extauth:set_password(User, Server, Password). -try_register(_User, _Server, _Password) -> - {error, not_allowed}. +try_register(User, Server, Password) -> + LUser = jlib:nodeprep(User), + LServer = jlib:nameprep(Server), + US = {LUser, LServer}, + if + (LUser == error) or (LServer == error) -> + {error, invalid_jid}; + true -> + F = fun() -> + case mnesia:read({passwd, US}) of + [] -> + mnesia:write(#passwd{us = US, + password = Password}), + extauth:try_register(User, Server, Password), + ok; + [_E] -> + exists + end + end, + mnesia:transaction(F) + end. dirty_get_registered_users() -> - []. + mnesia:dirty_all_keys(passwd). + +get_vh_registered_users(Server) -> + LServer = jlib:nameprep(Server), + mnesia:dirty_select( + passwd, + [{#passwd{us = '$1', _ = '_'}, + [{'==', {element, 2, '$1'}, LServer}], + ['$1']}]). + +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}]); + +get_vh_registered_users(Server, [{limit, Limit}, {offset, Offset}]) + when is_integer(Limit) and is_integer(Offset) -> + case get_vh_registered_users(Server) of + [] -> + []; + Users -> + Set = lists:keysort(1, Users), + L = length(Set), + Start = if Offset < 1 -> 1; + Offset > L -> L; + true -> Offset + end, + lists:sublist(Set, Start, Limit) + end; + +get_vh_registered_users(Server, [{prefix, Prefix}]) + when is_list(Prefix) -> + Set = [{U,S} || {U, S} <- get_vh_registered_users(Server), lists:prefix(Prefix, U)], + lists:keysort(1, Set); + +get_vh_registered_users(Server, [{prefix, Prefix}, {from, Start}, {to, End}]) + when is_list(Prefix) and is_integer(Start) and is_integer(End) -> + get_vh_registered_users(Server, [{prefix, Prefix}, {limit, End-Start+1}, {offset, Start}]); + +get_vh_registered_users(Server, [{prefix, Prefix}, {limit, Limit}, {offset, Offset}]) + when is_list(Prefix) and is_integer(Limit) and is_integer(Offset) -> + case [{U,S} || {U, S} <- get_vh_registered_users(Server), lists:prefix(Prefix, U)] of + [] -> + []; + Users -> + Set = lists:keysort(1, Users), + L = length(Set), + Start = if Offset < 1 -> 1; + Offset > L -> L; + true -> Offset + end, + lists:sublist(Set, Start, Limit) + end; + +get_vh_registered_users(Server, _) -> + get_vh_registered_users(Server). + +get_vh_registered_users_number(Server) -> + Set = get_vh_registered_users(Server), + length(Set). -get_vh_registered_users(_Server) -> - []. +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); + +get_vh_registered_users_number(Server, _) -> + get_vh_registered_users_number(Server). -get_password(_User, _Server) -> - false. +get_password(User, Server) -> + LUser = jlib:nodeprep(User), + LServer = jlib:nameprep(Server), + US = {LUser, LServer}, + case catch mnesia:dirty_read(passwd, US) of + [#passwd{password = Password}] -> + Password; + _ -> + false + end. -get_password_s(_User, _Server) -> - "". +get_password_s(User, Server) -> + LUser = jlib:nodeprep(User), + LServer = jlib:nameprep(Server), + US = {LUser, LServer}, + case catch mnesia:dirty_read(passwd, US) of + [#passwd{password = Password}] -> + Password; + _ -> + [] + end. is_user_exists(User, Server) -> extauth:is_user_exists(User, Server). -remove_user(_User, _Server) -> - {error, not_allowed}. +remove_user(User, Server) -> + LUser = jlib:nodeprep(User), + LServer = jlib:nameprep(Server), + US = {LUser, LServer}, + F = fun() -> + mnesia:delete({passwd, US}) + end, + mnesia:transaction(F), + ejabberd_hooks:run(remove_user, LServer, [User, Server]), + extauth:remove_user(User, Server). -remove_user(_User, _Server, _Password) -> - not_allowed. +remove_user(User, Server, Password) -> + LUser = jlib:nodeprep(User), + LServer = jlib:nameprep(Server), + US = {LUser, LServer}, + F = fun() -> + case mnesia:read({passwd, US}) of + [#passwd{password = Password}] -> + mnesia:delete({passwd, US}), + ok; + [_] -> + not_allowed; + _ -> + not_exists + end + end, + case mnesia:transaction(F) of + {atomic, ok} -> + ejabberd_hooks:run(remove_user, LServer, [User, Server]), + extauth:remove_user(User, Server, Password), + ok; + {atomic, Res} -> + Res; + _ -> + bad_request + end. +update_table() -> + Fields = record_info(fields, passwd), + case mnesia:table_info(passwd, attributes) of + Fields -> + ok; + [user, password] -> + ?INFO_MSG("Converting passwd table from " + "{user, password} format", []), + Host = ?MYNAME, + {atomic, ok} = mnesia:create_table( + ejabberd_auth_internal_tmp_table, + [{disc_only_copies, [node()]}, + {type, bag}, + {local_content, true}, + {record_name, passwd}, + {attributes, record_info(fields, passwd)}]), + mnesia:transform_table(passwd, ignore, Fields), + F1 = fun() -> + mnesia:write_lock_table(ejabberd_auth_internal_tmp_table), + mnesia:foldl( + fun(#passwd{us = U} = R, _) -> + mnesia:dirty_write( + ejabberd_auth_internal_tmp_table, + R#passwd{us = {U, Host}}) + end, ok, passwd) + end, + mnesia:transaction(F1), + mnesia:clear_table(passwd), + F2 = fun() -> + mnesia:write_lock_table(passwd), + mnesia:foldl( + fun(R, _) -> + mnesia:dirty_write(R) + end, ok, ejabberd_auth_internal_tmp_table) + end, + mnesia:transaction(F2), + mnesia:delete_table(ejabberd_auth_internal_tmp_table); + _ -> + ?INFO_MSG("Recreating passwd table", []), + mnesia:transform_table(passwd, ignore, Fields) + end. \ No newline at end of file diff --git a/src/extauth.erl b/src/extauth.erl index b84546d..0188d4c 100644 --- a/src/extauth.erl +++ b/src/extauth.erl @@ -27,8 +27,15 @@ -module(extauth). -author('leifj@it.su.se'). --export([start/2, stop/1, init/2, - check_password/3, set_password/3, is_user_exists/2]). +-export([start/2, + stop/1, + init/2, + check_password/3, + set_password/3, + try_register/3, + remove_user/2, + remove_user/3, + is_user_exists/2]). start(Host, ExtPrg) -> @@ -51,6 +58,15 @@ is_user_exists(User, Server) -> set_password(User, Server, Password) -> call_port(Server, ["setpass", User, Server, Password]). + +try_register(User, Server, Password) -> + call_port(Server, ["tryregister", User, Server, Password]). + +remove_user(User, Server) -> + call_port(Server, ["removeuser", User, Server]). + +remove_user(User, Server, Password) -> + call_port(Server, ["removeuser", User, Server, Password]). call_port(Server, Msg) -> LServer = jlib:nameprep(Server),