diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cyrsasl.erl | 2 | ||||
-rw-r--r-- | src/cyrsasl_digest.erl | 14 | ||||
-rw-r--r-- | src/cyrsasl_plain.erl | 13 | ||||
-rw-r--r-- | src/ejabberd.erl | 2 | ||||
-rw-r--r-- | src/ejabberd_admin.erl | 4 | ||||
-rw-r--r-- | src/ejabberd_auth.erl | 40 | ||||
-rw-r--r-- | src/ejabberd_auth_anonymous.erl | 10 | ||||
-rw-r--r-- | src/ejabberd_auth_external.erl | 50 | ||||
-rw-r--r-- | src/ejabberd_auth_internal.erl | 24 | ||||
-rw-r--r-- | src/ejabberd_auth_ldap.erl | 12 | ||||
-rw-r--r-- | src/ejabberd_auth_odbc.erl | 30 | ||||
-rw-r--r-- | src/ejabberd_auth_pam.erl | 14 | ||||
-rw-r--r-- | src/ejabberd_auth_riak.erl | 24 | ||||
-rw-r--r-- | src/ejabberd_c2s.erl | 28 | ||||
-rw-r--r-- | src/ejabberd_commands.erl | 2 | ||||
-rw-r--r-- | src/ejabberd_config.erl | 71 | ||||
-rw-r--r-- | src/ejabberd_oauth.erl | 2 | ||||
-rw-r--r-- | src/ejabberd_odbc.erl | 18 | ||||
-rw-r--r-- | src/ejabberd_riak.erl | 25 | ||||
-rw-r--r-- | src/ejabberd_riak_sup.erl | 43 | ||||
-rw-r--r-- | src/ejabberd_web_admin.erl | 2 | ||||
-rw-r--r-- | src/ejd2odbc.erl | 35 | ||||
-rw-r--r-- | src/jid.erl | 10 | ||||
-rw-r--r-- | src/mod_admin_extra.erl | 16 | ||||
-rw-r--r-- | src/mod_http_api.erl | 2 | ||||
-rw-r--r-- | src/mod_proxy65_stream.erl | 2 | ||||
-rw-r--r-- | src/mod_register_web.erl | 2 |
27 files changed, 314 insertions, 183 deletions
diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl index cc03a49c..21fbc966 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -132,7 +132,7 @@ register_mechanism(Mechanism, Module, PasswordType) -> %% end. check_credentials(_State, Props) -> - User = proplists:get_value(username, Props, <<>>), + User = proplists:get_value(authzid, Props, <<>>), case jid:nodeprep(User) of error -> {error, <<"not-authorized">>}; <<"">> -> {error, <<"not-authorized">>}; diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index 976e49e8..e58cb303 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -50,7 +50,7 @@ username = <<"">> :: binary(), authzid = <<"">> :: binary(), get_password = fun(_) -> {false, <<>>} end :: get_password_fun(), - check_password = fun(_, _, _, _) -> false end :: check_password_fun(), + check_password = fun(_, _, _, _, _) -> false end :: check_password_fun(), auth_module :: atom(), host = <<"">> :: binary(), hostfqdn = <<"">> :: binary()}). @@ -83,9 +83,7 @@ mech_step(#state{step = 3, nonce = Nonce} = State, bad -> {error, <<"bad-protocol">>}; KeyVals -> DigestURI = proplists:get_value(<<"digest-uri">>, KeyVals, <<>>), - %DigestURI = fxml:get_attr_s(<<"digest-uri">>, KeyVals), UserName = proplists:get_value(<<"username">>, KeyVals, <<>>), - %UserName = fxml:get_attr_s(<<"username">>, KeyVals), case is_digesturi_valid(DigestURI, State#state.host, State#state.hostfqdn) of @@ -97,13 +95,11 @@ mech_step(#state{step = 3, nonce = Nonce} = State, {error, <<"not-authorized">>, UserName}; true -> AuthzId = proplists:get_value(<<"authzid">>, KeyVals, <<>>), - %AuthzId = fxml:get_attr_s(<<"authzid">>, KeyVals), case (State#state.get_password)(UserName) of {false, _} -> {error, <<"not-authorized">>, UserName}; {Passwd, AuthModule} -> - case (State#state.check_password)(UserName, <<"">>, + case (State#state.check_password)(UserName, UserName, <<"">>, proplists:get_value(<<"response">>, KeyVals, <<>>), - %fxml:get_attr_s(<<"response">>, KeyVals), fun (PW) -> response(KeyVals, UserName, @@ -130,7 +126,11 @@ mech_step(#state{step = 5, auth_module = AuthModule, username = UserName, authzid = AuthzId}, <<"">>) -> {ok, - [{username, UserName}, {authzid, AuthzId}, + [{username, UserName}, {authzid, case AuthzId of + <<"">> -> UserName; + _ -> AuthzId + end + }, {auth_module, AuthModule}]}; mech_step(A, B) -> ?DEBUG("SASL DIGEST: A ~p B ~p", [A, B]), diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl index a9c1de05..82d68f87 100644 --- a/src/cyrsasl_plain.erl +++ b/src/cyrsasl_plain.erl @@ -45,7 +45,7 @@ mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) -> mech_step(State, ClientIn) -> case prepare(ClientIn) of [AuthzId, User, Password] -> - case (State#state.check_password)(User, Password) of + case (State#state.check_password)(User, AuthzId, Password) of {true, AuthModule} -> {ok, [{username, User}, {authzid, AuthzId}, @@ -60,12 +60,17 @@ prepare(ClientIn) -> [<<"">>, UserMaybeDomain, Password] -> case parse_domain(UserMaybeDomain) of %% <NUL>login@domain<NUL>pwd - [User, _Domain] -> [UserMaybeDomain, User, Password]; + [User, _Domain] -> [User, User, Password]; %% <NUL>login<NUL>pwd - [User] -> [<<"">>, User, Password] + [User] -> [User, User, Password] end; + [AuthzId, User, Password] -> + case parse_domain(AuthzId) of %% login@domain<NUL>login<NUL>pwd - [AuthzId, User, Password] -> [AuthzId, User, Password]; + [AuthzUser, _Domain] -> [AuthzUser, User, Password]; + %% login<NUL>login<NUL>pwd + [AuthzUser] -> [AuthzUser, User, Password] + end; _ -> error end. diff --git a/src/ejabberd.erl b/src/ejabberd.erl index e1b92c26..6bd2422a 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -79,7 +79,7 @@ is_loaded() -> start_app(App, Type, StartFlag) when not is_list(App) -> start_app([App], Type, StartFlag); start_app([App|Apps], Type, StartFlag) -> - case application:start(App) of + case application:start(App,Type) of ok -> spawn(fun() -> check_app_modules(App, StartFlag) end), start_app(Apps, Type, StartFlag); diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index c9e5b178..b22a7038 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -196,6 +196,10 @@ get_commands_spec() -> desc = "Export all tables as SQL queries to a file", module = ejd2odbc, function = export, args = [{host, string}, {file, string}], result = {res, rescode}}, + #ejabberd_commands{name = delete_mnesia, tags = [mnesia, odbc], + desc = "Export all tables as SQL queries to a file", + module = ejd2odbc, function = delete, + args = [{host, string}], result = {res, rescode}}, #ejabberd_commands{name = convert_to_scram, tags = [odbc], desc = "Convert the passwords in 'users' ODBC table to SCRAM", module = ejabberd_auth_odbc, function = convert_to_scram, diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 2cc37c6e..343ad943 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -32,9 +32,9 @@ -author('alexey@process-one.net'). %% External exports --export([start/0, set_password/3, check_password/3, - check_password/5, check_password_with_authmodule/3, - check_password_with_authmodule/5, try_register/3, +-export([start/0, set_password/3, check_password/4, + check_password/6, check_password_with_authmodule/4, + check_password_with_authmodule/6, try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, get_vh_registered_users/2, export/1, import/1, get_vh_registered_users_number/1, import/3, @@ -63,8 +63,8 @@ -callback remove_user(binary(), binary()) -> any(). -callback remove_user(binary(), binary(), binary()) -> any(). -callback is_user_exists(binary(), binary()) -> boolean() | {error, atom()}. --callback check_password(binary(), binary(), binary()) -> boolean(). --callback check_password(binary(), binary(), binary(), binary(), +-callback check_password(binary(), binary(), binary(), binary()) -> boolean(). +-callback check_password(binary(), binary(), binary(), binary(), binary(), fun((binary()) -> binary())) -> boolean(). -callback try_register(binary(), binary(), binary()) -> {atomic, atom()} | {error, atom()}. @@ -102,10 +102,10 @@ store_type(Server) -> end, plain, auth_modules(Server)). --spec check_password(binary(), binary(), binary()) -> boolean(). +-spec check_password(binary(), binary(), binary(), binary()) -> boolean(). -check_password(User, Server, Password) -> - case check_password_with_authmodule(User, Server, +check_password(User, AuthzId, Server, Password) -> + case check_password_with_authmodule(User, AuthzId, Server, Password) of {true, _AuthModule} -> true; @@ -113,15 +113,15 @@ check_password(User, Server, Password) -> end. %% @doc Check if the user and password can login in server. -%% @spec (User::string(), Server::string(), Password::string(), +%% @spec (User::string(), AuthzId::string(), Server::string(), Password::string(), %% Digest::string(), DigestGen::function()) -> %% true | false --spec check_password(binary(), binary(), binary(), binary(), +-spec check_password(binary(), binary(), binary(), binary(), binary(), fun((binary()) -> binary())) -> boolean(). -check_password(User, Server, Password, Digest, +check_password(User, AuthzId, Server, Password, Digest, DigestGen) -> - case check_password_with_authmodule(User, Server, + case check_password_with_authmodule(User, AuthzId, Server, Password, Digest, DigestGen) of {true, _AuthModule} -> true; @@ -132,28 +132,28 @@ check_password(User, Server, Password, Digest, %% 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()) -> +%% @spec (User::string(), AuthzId::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 --spec check_password_with_authmodule(binary(), binary(), binary()) -> false | +%% | ejabberd_auth_odbc | ejabberd_auth_pam | ejabberd_auth_riak +-spec check_password_with_authmodule(binary(), binary(), binary(), binary()) -> false | {true, atom()}. -check_password_with_authmodule(User, Server, +check_password_with_authmodule(User, AuthzId, Server, Password) -> check_password_loop(auth_modules(Server), - [User, Server, Password]). + [User, AuthzId, Server, Password]). --spec check_password_with_authmodule(binary(), binary(), binary(), binary(), +-spec check_password_with_authmodule(binary(), binary(), binary(), binary(), binary(), fun((binary()) -> binary())) -> false | {true, atom()}. -check_password_with_authmodule(User, Server, Password, +check_password_with_authmodule(User, AuthzId, Server, Password, Digest, DigestGen) -> check_password_loop(auth_modules(Server), - [User, Server, Password, Digest, DigestGen]). + [User, AuthzId, Server, Password, Digest, DigestGen]). check_password_loop([], _Args) -> false; check_password_loop([AuthModule | AuthModules], Args) -> diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 7b21752a..9c4b719c 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -38,8 +38,8 @@ unregister_connection/3 ]). --export([login/2, set_password/3, check_password/3, - check_password/5, try_register/3, +-export([login/2, set_password/3, check_password/4, + check_password/6, try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, get_vh_registered_users/2, get_vh_registered_users_number/1, @@ -175,11 +175,11 @@ purge_hook(true, LUser, LServer) -> %% 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, +check_password(User, AuthzId, Server, Password) -> + check_password(User, AuthzId, Server, Password, undefined, undefined). -check_password(User, Server, _Password, _Digest, +check_password(User, _AuthzId, Server, _Password, _Digest, _DigestGen) -> case ejabberd_auth:is_user_exists_in_other_modules(?MODULE, diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index 2944ac3f..5897fba5 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -31,8 +31,8 @@ -behaviour(ejabberd_auth). --export([start/1, set_password/3, check_password/3, - check_password/5, try_register/3, +-export([start/1, set_password/3, check_password/4, + check_password/6, try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, get_vh_registered_users/2, get_vh_registered_users_number/1, @@ -76,16 +76,20 @@ plain_password_required() -> true. store_type() -> external. -check_password(User, Server, Password) -> +check_password(User, AuthzId, Server, Password) -> + if AuthzId /= <<>> andalso AuthzId /= User -> + false; + true -> case get_cache_option(Server) of - false -> check_password_extauth(User, Server, Password); + false -> check_password_extauth(User, AuthzId, Server, Password); {true, CacheTime} -> - check_password_cache(User, Server, Password, CacheTime) + check_password_cache(User, AuthzId, Server, Password, CacheTime) + end end. -check_password(User, Server, Password, _Digest, +check_password(User, AuthzId, Server, Password, _Digest, _DigestGen) -> - check_password(User, Server, Password). + check_password(User, AuthzId, Server, Password). set_password(User, Server, Password) -> case extauth:set_password(User, Server, Password) of @@ -178,8 +182,8 @@ get_cache_option(Host) -> CacheTime -> {true, CacheTime} end. -%% @spec (User, Server, Password) -> true | false -check_password_extauth(User, Server, Password) -> +%% @spec (User, AuthzId, Server, Password) -> true | false +check_password_extauth(User, _AuthzId, Server, Password) -> extauth:check_password(User, Server, Password) andalso Password /= <<"">>. @@ -187,35 +191,35 @@ check_password_extauth(User, Server, Password) -> try_register_extauth(User, Server, Password) -> extauth:try_register(User, Server, Password). -check_password_cache(User, Server, Password, 0) -> - check_password_external_cache(User, Server, Password); -check_password_cache(User, Server, Password, +check_password_cache(User, AuthzId, Server, Password, 0) -> + check_password_external_cache(User, AuthzId, Server, Password); +check_password_cache(User, AuthzId, Server, Password, CacheTime) -> case get_last_access(User, Server) of online -> - check_password_internal(User, Server, Password); + check_password_internal(User, AuthzId, Server, Password); never -> - check_password_external_cache(User, Server, Password); + check_password_external_cache(User, AuthzId, Server, Password); mod_last_required -> ?ERROR_MSG("extauth is used, extauth_cache is enabled " "but mod_last is not enabled in that " "host", []), - check_password_external_cache(User, Server, Password); + check_password_external_cache(User, AuthzId, Server, Password); TimeStamp -> case is_fresh_enough(TimeStamp, CacheTime) of %% If no need to refresh, check password against Mnesia true -> - case check_password_internal(User, Server, Password) of + case check_password_internal(User, AuthzId, Server, Password) of %% If password valid in Mnesia, accept it true -> true; %% Else (password nonvalid in Mnesia), check in extauth and cache result false -> - check_password_external_cache(User, Server, Password) + check_password_external_cache(User, AuthzId, Server, Password) end; %% Else (need to refresh), check in extauth and cache result false -> - check_password_external_cache(User, Server, Password) + check_password_external_cache(User, AuthzId, Server, Password) end end. @@ -241,8 +245,8 @@ get_password_cache(User, Server, CacheTime) -> end. %% Check the password using extauth; if success then cache it -check_password_external_cache(User, Server, Password) -> - case check_password_extauth(User, Server, Password) of +check_password_external_cache(User, AuthzId, Server, Password) -> + case check_password_extauth(User, AuthzId, Server, Password) of true -> set_password_internal(User, Server, Password), true; false -> false @@ -256,9 +260,9 @@ try_register_external_cache(User, Server, Password) -> _ -> {error, not_allowed} end. -%% @spec (User, Server, Password) -> true | false -check_password_internal(User, Server, Password) -> - ejabberd_auth_internal:check_password(User, Server, +%% @spec (User, AuthzId, Server, Password) -> true | false +check_password_internal(User, AuthzId, Server, Password) -> + ejabberd_auth_internal:check_password(User, AuthzId, Server, Password). %% @spec (User, Server, Password) -> ok | {error, invalid_jid} diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index d60e0fc5..3b30b360 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -31,8 +31,8 @@ -behaviour(ejabberd_auth). --export([start/1, set_password/3, check_password/3, - check_password/5, try_register/3, +-export([start/1, set_password/3, check_password/4, + check_password/6, try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, get_vh_registered_users/2, get_vh_registered_users_number/1, @@ -86,9 +86,12 @@ store_type() -> true -> scram %% allows: PLAIN SCRAM end. -check_password(User, Server, Password) -> - LUser = jid:nodeprep(User), - LServer = jid:nameprep(Server), +check_password(User, AuthzId, Server, Password) -> + if AuthzId /= <<>> andalso AuthzId /= User -> + false; + true -> + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), US = {LUser, LServer}, case catch mnesia:dirty_read({passwd, US}) of [#passwd{password = Password}] @@ -98,12 +101,16 @@ check_password(User, Server, Password) -> when is_record(Scram, scram) -> is_password_scram_valid(Password, Scram); _ -> false + end end. -check_password(User, Server, Password, Digest, +check_password(User, AuthzId, Server, Password, Digest, DigestGen) -> - LUser = jid:nodeprep(User), - LServer = jid:nameprep(Server), + if AuthzId /= <<>> andalso AuthzId /= User -> + false; + true -> + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), US = {LUser, LServer}, case catch mnesia:dirty_read({passwd, US}) of [#passwd{password = Passwd}] when is_binary(Passwd) -> @@ -125,6 +132,7 @@ check_password(User, Server, Password, Digest, true -> (Passwd == Password) and (Password /= <<"">>) end; _ -> false + end end. %% @spec (User::string(), Server::string(), Password::string()) -> diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index dd5d54a7..51b466ef 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -37,7 +37,7 @@ handle_cast/2, terminate/2, code_change/3]). -export([start/1, stop/1, start_link/1, set_password/3, - check_password/3, check_password/5, try_register/3, + check_password/4, check_password/6, try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, get_vh_registered_users/2, get_vh_registered_users_number/1, @@ -116,7 +116,10 @@ plain_password_required() -> true. store_type() -> external. -check_password(User, Server, Password) -> +check_password(User, AuthzId, Server, Password) -> + if AuthzId /= <<>> andalso AuthzId /= User -> + false; + true -> if Password == <<"">> -> false; true -> case catch check_password_ldap(User, Server, Password) @@ -124,11 +127,12 @@ check_password(User, Server, Password) -> {'EXIT', _} -> false; Result -> Result end + end end. -check_password(User, Server, Password, _Digest, +check_password(User, AuthzId, Server, Password, _Digest, _DigestGen) -> - check_password(User, Server, Password). + check_password(User, AuthzId, Server, Password). set_password(User, Server, Password) -> {ok, State} = eldap_utils:get_state(Server, ?MODULE), diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 18d06201..dc3248fe 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -31,8 +31,8 @@ -behaviour(ejabberd_auth). --export([start/1, set_password/3, check_password/3, - check_password/5, try_register/3, +-export([start/1, set_password/3, check_password/4, + check_password/6, try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, get_vh_registered_users/2, get_vh_registered_users_number/1, @@ -63,10 +63,13 @@ store_type() -> true -> scram %% allows: PLAIN SCRAM end. -%% @spec (User, Server, Password) -> true | false | {error, Error} -check_password(User, Server, Password) -> - LServer = jid:nameprep(Server), - LUser = jid:nodeprep(User), +%% @spec (User, AuthzId, Server, Password) -> true | false | {error, Error} +check_password(User, AuthzId, Server, Password) -> + if AuthzId /= <<>> andalso AuthzId /= User -> + false; + true -> + LServer = jid:nameprep(Server), + LUser = jid:nodeprep(User), if (LUser == error) or (LServer == error) -> false; (LUser == <<>>) or (LServer == <<>>) -> @@ -106,13 +109,17 @@ check_password(User, Server, Password) -> false %% Typical error is database not accessible end end + end end. -%% @spec (User, Server, Password, Digest, DigestGen) -> true | false | {error, Error} -check_password(User, Server, Password, Digest, +%% @spec (User, AuthzId, Server, Password, Digest, DigestGen) -> true | false | {error, Error} +check_password(User, AuthzId, Server, Password, Digest, DigestGen) -> - LServer = jid:nameprep(Server), - LUser = jid:nodeprep(User), + if AuthzId /= <<>> andalso AuthzId /= User -> + false; + true -> + LServer = jid:nameprep(Server), + LUser = jid:nodeprep(User), if (LUser == error) or (LServer == error) -> false; (LUser == <<>>) or (LServer == <<>>) -> @@ -141,6 +148,7 @@ check_password(User, Server, Password, Digest, true -> false end + end end. %% @spec (User::string(), Server::string(), Password::string()) -> @@ -359,7 +367,7 @@ remove_user(User, Server, Password) -> true -> case is_scrammed() of true -> - case check_password(User, Server, Password) of + case check_password(User, <<"">>, Server, Password) of true -> remove_user(User, Server), ok; diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl index ee5123c5..fa4b9f07 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -30,8 +30,8 @@ -behaviour(ejabberd_auth). --export([start/1, set_password/3, check_password/3, - check_password/5, try_register/3, +-export([start/1, set_password/3, check_password/4, + check_password/6, try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, get_vh_registered_users/2, get_vh_registered_users_number/1, @@ -46,11 +46,14 @@ start(_Host) -> set_password(_User, _Server, _Password) -> {error, not_allowed}. -check_password(User, Server, Password, _Digest, +check_password(User, AuthzId, Server, Password, _Digest, _DigestGen) -> - check_password(User, Server, Password). + check_password(User, AuthzId, Server, Password). -check_password(User, Host, Password) -> +check_password(User, AuthzId, Host, Password) -> + if AuthzId /= <<>> andalso AuthzId /= User -> + false; + true -> Service = get_pam_service(Host), UserInfo = case get_pam_userinfotype(Host) of username -> User; @@ -61,6 +64,7 @@ check_password(User, Host, Password) -> of true -> true; _ -> false + end end. try_register(_User, _Server, _Password) -> diff --git a/src/ejabberd_auth_riak.erl b/src/ejabberd_auth_riak.erl index 64bf12c6..bc745fea 100644 --- a/src/ejabberd_auth_riak.erl +++ b/src/ejabberd_auth_riak.erl @@ -30,8 +30,8 @@ -behaviour(ejabberd_auth). %% External exports --export([start/1, set_password/3, check_password/3, - check_password/5, try_register/3, +-export([start/1, set_password/3, check_password/4, + check_password/6, try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, get_vh_registered_users/2, get_vh_registered_users_number/1, @@ -66,9 +66,12 @@ store_type() -> passwd_schema() -> {record_info(fields, passwd), #passwd{}}. -check_password(User, Server, Password) -> - LUser = jid:nodeprep(User), - LServer = jid:nameprep(Server), +check_password(User, AuthzId, Server, Password) -> + if AuthzId /= <<>> andalso AuthzId /= User -> + false; + true -> + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of {ok, #passwd{password = Password}} when is_binary(Password) -> Password /= <<"">>; @@ -76,12 +79,16 @@ check_password(User, Server, Password) -> is_password_scram_valid(Password, Scram); _ -> false + end end. -check_password(User, Server, Password, Digest, +check_password(User, AuthzId, Server, Password, Digest, DigestGen) -> - LUser = jid:nodeprep(User), - LServer = jid:nameprep(Server), + if AuthzId /= <<>> andalso AuthzId /= User -> + false; + true -> + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of {ok, #passwd{password = Passwd}} when is_binary(Passwd) -> DigRes = if Digest /= <<"">> -> @@ -102,6 +109,7 @@ check_password(User, Server, Password, Digest, true -> (Passwd == Password) and (Password /= <<"">>) end; _ -> false + end end. set_password(User, Server, Password) -> diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index d58c1e1d..936abc7a 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -382,13 +382,13 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> ejabberd_auth:get_password_with_authmodule( U, Server) end, - fun (U, P) -> + fun(U, AuthzId, P) -> ejabberd_auth:check_password_with_authmodule( - U, Server, P) + U, AuthzId, Server, P) end, - fun (U, P, D, DG) -> + fun(U, AuthzId, P, D, DG) -> ejabberd_auth:check_password_with_authmodule( - U, Server, P, D, DG) + U, AuthzId, Server, P, D, DG) end), Mechs = case TLSEnabled or not TLSRequired of @@ -634,7 +634,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> DGen = fun (PW) -> p1_sha:sha(<<(StateData#state.streamid)/binary, PW/binary>>) end, - case ejabberd_auth:check_password_with_authmodule(U, + case ejabberd_auth:check_password_with_authmodule(U, U, StateData#state.server, P, D, DGen) of @@ -752,9 +752,7 @@ wait_for_feature_request({xmlstreamelement, El}, of {ok, Props} -> (StateData#state.sockmod):reset_stream(StateData#state.socket), - %U = fxml:get_attr_s(username, Props), - U = proplists:get_value(username, Props, <<>>), - %AuthModule = fxml:get_attr_s(auth_module, Props), + U = identity(Props), AuthModule = proplists:get_value(auth_module, Props, undefined), ?INFO_MSG("(~w) Accepted authentication for ~s " "by ~p from ~s", @@ -876,9 +874,7 @@ wait_for_sasl_response({xmlstreamelement, El}, {ok, Props} -> catch (StateData#state.sockmod):reset_stream(StateData#state.socket), -% U = fxml:get_attr_s(username, Props), - U = proplists:get_value(username, Props, <<>>), -% AuthModule = fxml:get_attr_s(auth_module, Props), + U = identity(Props), AuthModule = proplists:get_value(auth_module, Props, <<>>), ?INFO_MSG("(~w) Accepted authentication for ~s " "by ~p from ~s", @@ -899,9 +895,7 @@ wait_for_sasl_response({xmlstreamelement, El}, user = U}); {ok, Props, ServerOut} -> (StateData#state.sockmod):reset_stream(StateData#state.socket), -% U = fxml:get_attr_s(username, Props), - U = proplists:get_value(username, Props, <<>>), -% AuthModule = fxml:get_attr_s(auth_module, Props), + U = identity(Props), AuthModule = proplists:get_value(auth_module, Props, undefined), ?INFO_MSG("(~w) Accepted authentication for ~s " "by ~p from ~s", @@ -3129,6 +3123,12 @@ pack_string(String, Pack) -> transform_listen_option(Opt, Opts) -> [Opt|Opts]. +identity(Props) -> + case proplists:get_value(authzid, Props, <<>>) of + <<>> -> proplists:get_value(username, Props, <<>>); + AuthzId -> AuthzId + end. + opt_type(domain_certfile) -> fun iolist_to_binary/1; opt_type(max_fsm_queue) -> fun (I) when is_integer(I), I > 0 -> I end; diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 265d7141..3c98316d 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -517,7 +517,7 @@ check_auth(Command, {User, Server, {oauth, Token}, _}) -> end; check_auth(_Command, {User, Server, Password, _}) when is_binary(Password) -> %% Check the account exists and password is valid - case ejabberd_auth:check_password(User, Server, Password) of + case ejabberd_auth:check_password(User, <<"">>, Server, Password) of true -> {ok, User, Server}; _ -> throw({error, invalid_account_data}) end. diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index eb06b98f..6f7368b7 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -38,6 +38,8 @@ convert_to_yaml/1, convert_to_yaml/2, env_binary_to_list/2, opt_type/1, may_hide_data/1]). +-export([start/2]). + -include("ejabberd.hrl"). -include("logger.hrl"). -include("ejabberd_config.hrl"). @@ -52,22 +54,12 @@ %% @type macro_value() = term(). - start() -> - case catch mnesia:table_info(local_config, storage_type) of - disc_copies -> - mnesia:delete_table(local_config); - _ -> - ok - end, - mnesia:create_table(local_config, - [{ram_copies, [node()]}, - {local_content, true}, - {attributes, record_info(fields, local_config)}]), - mnesia:add_table_copy(local_config, node(), ram_copies), + mnesia_init(), Config = get_ejabberd_config_path(), State0 = read_file(Config), - State = validate_opts(State0), + State1 = hosts_to_start(State0), + State2 = validate_opts(State1), %% This start time is used by mod_last: UnixTime = p1_time_compat:system_time(seconds), SharedKey = case erlang:get_cookie() of @@ -76,9 +68,45 @@ start() -> Cookie -> p1_sha:sha(jlib:atom_to_binary(Cookie)) end, - State1 = set_option({node_start, global}, UnixTime, State), - State2 = set_option({shared_key, global}, SharedKey, State1), - set_opts(State2). + State3 = set_option({node_start, global}, UnixTime, State2), + State4 = set_option({shared_key, global}, SharedKey, State3), + set_opts(State4). + +%% When starting ejabberd for testing, we sometimes want to start a +%% subset of hosts from the one define in the config file. +%% This function override the host list read from config file by the +%% one we provide. +%% Hosts to start are defined in an ejabberd application environment +%% variable 'hosts' to make it easy to ignore some host in config +%% file. +hosts_to_start(State) -> + case application:get_env(ejabberd, hosts) of + undefined -> + %% Start all hosts as defined in config file + State; + {ok, Hosts} -> + set_hosts_in_options(Hosts, State) + end. + +%% @private +%% At the moment, these functions are mainly used to setup unit tests. +-spec(start/2 :: (Hosts :: [binary()], Opts :: [acl:acl() | local_config()]) -> ok). +start(Hosts, Opts) -> + mnesia_init(), + set_opts(#state{hosts = Hosts, opts = Opts}). + +mnesia_init() -> + case catch mnesia:table_info(local_config, storage_type) of + disc_copies -> + mnesia:delete_table(local_config); + _ -> + ok + end, + mnesia:create_table(local_config, + [{ram_copies, [node()]}, + {local_content, true}, + {attributes, record_info(fields, local_config)}]), + mnesia:add_table_copy(local_config, node(), ram_copies). %% @doc Get the filename of the ejabberd configuration file. %% The filename can be specified with: erl -config "/path/to/ejabberd.yml". @@ -277,7 +305,7 @@ search_hosts(Term, State) -> {host, Host} -> if State#state.hosts == [] -> - add_hosts_to_option([Host], State); + set_hosts_in_options([Host], State); true -> ?ERROR_MSG("Can't load config file: " "too many hosts definitions", []), @@ -286,7 +314,7 @@ search_hosts(Term, State) -> {hosts, Hosts} -> if State#state.hosts == [] -> - add_hosts_to_option(Hosts, State); + set_hosts_in_options(Hosts, State); true -> ?ERROR_MSG("Can't load config file: " "too many hosts definitions", []), @@ -296,9 +324,12 @@ search_hosts(Term, State) -> State end. -add_hosts_to_option(Hosts, State) -> +set_hosts_in_options(Hosts, State) -> PrepHosts = normalize_hosts(Hosts), - set_option({hosts, global}, PrepHosts, State#state{hosts = PrepHosts}). + NewOpts = lists:filter(fun({local_config,{hosts,global},_}) -> false; + (_) -> true + end, State#state.opts), + set_option({hosts, global}, PrepHosts, State#state{hosts = PrepHosts, opts = NewOpts}). normalize_hosts(Hosts) -> normalize_hosts(Hosts,[]). diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl index 1925a2f7..d8e0a435 100644 --- a/src/ejabberd_oauth.erl +++ b/src/ejabberd_oauth.erl @@ -134,7 +134,7 @@ authenticate_user({User, Server}, {password, Password} = Ctx) -> none), case acl:match_rule(JID#jid.lserver, Access, JID) of allow -> - case ejabberd_auth:check_password(User, Server, Password) of + case ejabberd_auth:check_password(User, <<"">>, Server, Password) of true -> {ok, {Ctx, {user, User, Server}}}; false -> diff --git a/src/ejabberd_odbc.erl b/src/ejabberd_odbc.erl index f756fdeb..e9866586 100644 --- a/src/ejabberd_odbc.erl +++ b/src/ejabberd_odbc.erl @@ -898,8 +898,7 @@ db_opts(Host) -> <<"">>), case Type of mssql -> - Username = get_mssql_user(Server, User), - [odbc, <<"DSN=", Host/binary, ";UID=", Username/binary, + [odbc, <<"DSN=", Host/binary, ";UID=", User/binary, ";PWD=", Pass/binary>>]; _ -> [Type, Server, Port, DB, User, Pass] @@ -959,21 +958,6 @@ init_mssql(Host) -> Err end. -get_mssql_user(Server, User) -> - HostName = case inet_parse:address(binary_to_list(Server)) of - {ok, _} -> - Server; - {error, _} -> - hd(str:tokens(Server, <<".">>)) - end, - UserName = case str:chr(User, $@) of - 0 -> - <<User/binary, $@, HostName/binary>>; - _ -> - User - end, - UserName. - tmp_dir() -> filename:join(["/tmp", "ejabberd"]). diff --git a/src/ejabberd_riak.erl b/src/ejabberd_riak.erl index 22da9d2e..575810ac 100644 --- a/src/ejabberd_riak.erl +++ b/src/ejabberd_riak.erl @@ -28,7 +28,7 @@ -behaviour(gen_server). %% API --export([start_link/4, get_proc/1, make_bucket/1, put/2, put/3, +-export([start_link/5, get_proc/1, make_bucket/1, put/2, put/3, get/2, get/3, get_by_index/4, delete/1, delete/2, count_by_index/3, get_by_index_range/5, get_keys/1, get_keys_by_index/3, is_connected/0, @@ -68,12 +68,20 @@ %%% API %%%=================================================================== %% @private -start_link(Num, Server, Port, _StartInterval) -> - gen_server:start_link({local, get_proc(Num)}, ?MODULE, [Server, Port], []). +start_link(Num, Server, Port, _StartInterval, Options) -> + gen_server:start_link({local, get_proc(Num)}, ?MODULE, [Server, Port, Options], []). %% @private is_connected() -> - catch riakc_pb_socket:is_connected(get_random_pid()). + lists:all( + fun({_Id, Pid, _Type, _Modules}) when is_pid(Pid) -> + case catch riakc_pb_socket:is_connected(get_riak_pid(Pid)) of + true -> true; + _ -> false + end; + (_) -> + false + end, supervisor:which_children(ejabberd_riak_sup)). %% @private get_proc(I) -> @@ -429,10 +437,8 @@ map_key(Obj, _, _) -> %%% gen_server API %%%=================================================================== %% @private -init([Server, Port]) -> - case riakc_pb_socket:start( - Server, Port, - [auto_reconnect]) of +init([Server, Port, Options]) -> + case riakc_pb_socket:start(Server, Port, Options) of {ok, Pid} -> erlang:monitor(process, Pid), {ok, #state{pid = Pid}}; @@ -517,6 +523,9 @@ make_invalid_object(Val) -> get_random_pid() -> PoolPid = ejabberd_riak_sup:get_random_pid(), + get_riak_pid(PoolPid). + +get_riak_pid(PoolPid) -> case catch gen_server:call(PoolPid, get_pid) of {ok, Pid} -> Pid; diff --git a/src/ejabberd_riak_sup.erl b/src/ejabberd_riak_sup.erl index 319d1707..af811441 100644 --- a/src/ejabberd_riak_sup.erl +++ b/src/ejabberd_riak_sup.erl @@ -103,12 +103,27 @@ init([]) -> StartInterval = get_start_interval(), Server = get_riak_server(), Port = get_riak_port(), + CACertFile = get_riak_cacertfile(), + Username = get_riak_username(), + Password = get_riak_password(), + Options = lists:filter( + fun(X) -> X /= nil end, + [auto_reconnect, + {keepalive, true}, + if CACertFile /= nil -> {cacertfile ,CACertFile}; + true -> nil + end, + if (Username /= nil) and (Password /= nil) -> + {credentials, Username, Password}; + true -> nil + end + ]), {ok, {{one_for_one, PoolSize*10, 1}, lists:map( fun(I) -> {ejabberd_riak:get_proc(I), {ejabberd_riak, start_link, - [I, Server, Port, StartInterval*1000]}, + [I, Server, Port, StartInterval*1000, Options]}, transient, 2000, worker, [?MODULE]} end, lists:seq(1, PoolSize))}}. @@ -131,6 +146,27 @@ get_riak_server() -> binary_to_list(iolist_to_binary(S)) end, ?DEFAULT_RIAK_HOST). +get_riak_cacertfile() -> + ejabberd_config:get_option( + riak_cacertfile, + fun(S) -> + binary_to_list(iolist_to_binary(S)) + end, nil). + +get_riak_username() -> + ejabberd_config:get_option( + riak_username, + fun(S) -> + binary_to_list(iolist_to_binary(S)) + end, nil). + +get_riak_password() -> + ejabberd_config:get_option( + riak_password, + fun(S) -> + binary_to_list(iolist_to_binary(S)) + end, nil). + get_riak_port() -> ejabberd_config:get_option( riak_port, @@ -162,6 +198,9 @@ opt_type(riak_port) -> fun (_) -> true end; opt_type(riak_server) -> fun (_) -> true end; opt_type(riak_start_interval) -> fun (N) when is_integer(N), N >= 1 -> N end; +opt_type(riak_cacertfile) -> fun iolist_to_binary/1; +opt_type(riak_username) -> fun iolist_to_binary/1; +opt_type(riak_password) -> fun iolist_to_binary/1; opt_type(_) -> [modules, riak_pool_size, riak_port, riak_server, - riak_start_interval]. + riak_start_interval, riak_cacertfile, riak_username, riak_password]. diff --git a/src/ejabberd_web_admin.erl b/src/ejabberd_web_admin.erl index 11d90ab8..f525a4d3 100644 --- a/src/ejabberd_web_admin.erl +++ b/src/ejabberd_web_admin.erl @@ -264,7 +264,7 @@ get_auth_admin(Auth, HostHTTP, RPath, Method) -> get_auth_account(HostOfRule, AccessRule, User, Server, Pass) -> - case ejabberd_auth:check_password(User, Server, Pass) of + case ejabberd_auth:check_password(User, <<"">>, Server, Pass) of true -> case is_acl_match(HostOfRule, AccessRule, jid:make(User, Server, <<"">>)) diff --git a/src/ejd2odbc.erl b/src/ejd2odbc.erl index 4cb937ef..1df88470 100644 --- a/src/ejd2odbc.erl +++ b/src/ejd2odbc.erl @@ -30,7 +30,7 @@ -include("logger.hrl"). -export([export/2, export/3, import_file/2, import/2, - import/3]). + import/3, delete/1]). -define(MAX_RECORDS_PER_TRANSACTION, 100). @@ -80,6 +80,20 @@ export(Server, Output, Module) -> end, Module:export(Server)), close_output(Output, IO). +delete(Server) -> + Modules = modules(), + lists:foreach( + fun(Module) -> + delete(Server, Module) + end, Modules). + +delete(Server, Module) -> + LServer = jid:nameprep(iolist_to_binary(Server)), + lists:foreach( + fun({Table, ConvertFun}) -> + delete(LServer, Table, ConvertFun) + end, Module:export(Server)). + import_file(Server, FileName) when is_binary(FileName) -> import(Server, binary_to_list(FileName)); import_file(Server, FileName) -> @@ -160,6 +174,25 @@ output(_LServer, Table, Fd, SQLs) -> file:write(Fd, ["-- \n-- Mnesia table: ", atom_to_list(Table), "\n--\n", SQLs]). +delete(LServer, Table, ConvertFun) -> + F = fun () -> + mnesia:write_lock_table(Table), + {_N, SQLs} = + mnesia:foldl( + fun(R, {N, SQLs} = Acc) -> + case ConvertFun(LServer, R) of + [] -> + Acc; + _SQL -> + mnesia:delete_object(R), + Acc + end + end, + {0, []}, Table), + delete(LServer, Table, SQLs) + end, + mnesia:transaction(F). + import(LServer, SelectQuery, IO, ConvertFun, Opts) -> F = case proplists:get_bool(fast, Opts) of true -> diff --git a/src/jid.erl b/src/jid.erl index cc387ecb..7bdd652a 100644 --- a/src/jid.erl +++ b/src/jid.erl @@ -87,9 +87,13 @@ split(#jid{user = U, server = S, resource = R}) -> split(_) -> error. --spec from_string(binary()) -> jid() | error. - -from_string(S) -> +-spec from_string([binary()|string()]) -> jid() | error. +from_string(S) when is_list(S) -> + %% We do not accept list because we want to enforce good practice of + %% using binaries for string. However, we do not let it crash to avoid + %% losing associated ets table. + {error, need_jid_as_binary}; +from_string(S) when is_binary(S) -> SplitPattern = ets:lookup_element(jlib, string_to_jid_pattern, 2), Size = size(S), End = Size-1, diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 343a1a3a..f0e56719 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -748,21 +748,7 @@ kick_sessions(User, Server, Reason) -> fun(Resource) -> kick_this_session(User, Server, Resource, Reason) end, - get_resources(User, Server)). - -get_resources(User, Server) -> - lists:map( - fun(Session) -> - element(3, Session#session.usr) - end, - get_sessions(User, Server)). - -get_sessions(User, Server) -> - LUser = jid:nodeprep(User), - LServer = jid:nameprep(Server), - Sessions = mnesia:dirty_index_read(session, {LUser, LServer}, #session.us), - true = is_list(Sessions), - Sessions. + ejabberd_sm:get_user_resources(User, Server)). set_random_password(User, Server, Reason) -> NewPass = build_random_password(Reason), diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index 7f86d5cc..3b7a09cb 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -116,7 +116,7 @@ check_permissions(#request{auth = HTTPAuth, headers = Headers}, Command) {SJID, Pass} -> case jid:from_string(SJID) of #jid{user = User, server = Server} -> - case ejabberd_auth:check_password(User, Server, Pass) of + case ejabberd_auth:check_password(User, <<"">>, Server, Pass) of true -> {ok, {User, Server, Pass, Admin}}; false -> false end; diff --git a/src/mod_proxy65_stream.erl b/src/mod_proxy65_stream.erl index 36dd7af1..84017329 100644 --- a/src/mod_proxy65_stream.erl +++ b/src/mod_proxy65_stream.erl @@ -153,7 +153,7 @@ wait_for_auth(Packet, #state{socket = Socket, host = Host} = StateData) -> case mod_proxy65_lib:unpack_auth_request(Packet) of {User, Pass} -> - Result = ejabberd_auth:check_password(User, Host, Pass), + Result = ejabberd_auth:check_password(User, <<"">>, Host, Pass), gen_tcp:send(Socket, mod_proxy65_lib:make_auth_reply(Result)), case Result of diff --git a/src/mod_register_web.erl b/src/mod_register_web.erl index 5b7f950a..d9314031 100644 --- a/src/mod_register_web.erl +++ b/src/mod_register_web.erl @@ -438,7 +438,7 @@ check_account_exists(Username, Host) -> end. check_password(Username, Host, Password) -> - case ejabberd_auth:check_password(Username, Host, + case ejabberd_auth:check_password(Username, <<"">>, Host, Password) of true -> password_correct; |