diff --git a/ChangeLog b/ChangeLog index 8cc8ecfd0..efc445b25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2009-04-22 Badlop + * src/cyrsasl.erl: Change API of check_password: pass a function + to generate the digest (thanks to Graham Whitted)(EJAB-863) + * src/cyrsasl_anonymous.erl: Likewise + * src/cyrsasl_digest.erl: Likewise + * src/cyrsasl_plain.erl: Likewise + * src/ejabberd_auth.erl: Likewise + * src/ejabberd_auth_anonymous.erl: Likewise + * src/ejabberd_auth_external.erl: Likewise + * src/ejabberd_auth_internal.erl: Likewise + * src/ejabberd_auth_ldap.erl: Likewise + * src/ejabberd_auth_odbc.erl: Likewise + * src/ejabberd_auth_pam.erl: Likewise + * src/ejabberd_c2s.erl: Likewise + * src/ejabberd_c2s.erl: Fix for SASL Anonymous connections not stored or purged (thanks to Andy Skelton)(EJAB-912) diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl index fb47b036b..f993b992a 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -30,19 +30,19 @@ -export([start/0, register_mechanism/3, listmech/1, - server_new/6, + server_new/7, server_start/3, server_step/2]). -record(sasl_mechanism, {mechanism, module, require_plain_password}). -record(sasl_state, {service, myname, realm, - get_password, check_password, + get_password, check_password, check_password_digest, mech_mod, mech_state}). -export([behaviour_info/1]). behaviour_info(callbacks) -> - [{mech_new, 3}, {mech_step, 2}]; + [{mech_new, 4}, {mech_step, 2}]; behaviour_info(_Other) -> undefined. @@ -113,12 +113,13 @@ listmech(Host) -> filter_anonymous(Host, Mechs). server_new(Service, ServerFQDN, UserRealm, _SecFlags, - GetPassword, CheckPassword) -> + GetPassword, CheckPassword, CheckPasswordDigest) -> #sasl_state{service = Service, myname = ServerFQDN, realm = UserRealm, get_password = GetPassword, - check_password = CheckPassword}. + check_password = CheckPassword, + check_password_digest= CheckPasswordDigest}. server_start(State, Mech, ClientIn) -> case lists:member(Mech, listmech(State#sasl_state.myname)) of @@ -128,7 +129,8 @@ server_start(State, Mech, ClientIn) -> {ok, MechState} = Module:mech_new( State#sasl_state.myname, State#sasl_state.get_password, - State#sasl_state.check_password), + State#sasl_state.check_password, + State#sasl_state.check_password_digest), server_step(State#sasl_state{mech_mod = Module, mech_state = MechState}, ClientIn); diff --git a/src/cyrsasl_anonymous.erl b/src/cyrsasl_anonymous.erl index 9fa51764c..19e65d6d8 100644 --- a/src/cyrsasl_anonymous.erl +++ b/src/cyrsasl_anonymous.erl @@ -27,7 +27,7 @@ -module(cyrsasl_anonymous). --export([start/1, stop/0, mech_new/3, mech_step/2]). +-export([start/1, stop/0, mech_new/4, mech_step/2]). -behaviour(cyrsasl). @@ -40,7 +40,7 @@ start(_Opts) -> stop() -> ok. -mech_new(Host, _GetPassword, _CheckPassword) -> +mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) -> {ok, #state{server = Host}}. mech_step(State, _ClientIn) -> diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index 0d27dbb68..49ea6a6d4 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -11,14 +11,14 @@ -export([start/1, stop/0, - mech_new/3, + mech_new/4, mech_step/2]). -include("ejabberd.hrl"). -behaviour(cyrsasl). --record(state, {step, nonce, username, authzid, get_password, auth_module, +-record(state, {step, nonce, username, authzid, get_password, check_password, auth_module, host}). start(_Opts) -> @@ -27,11 +27,12 @@ start(_Opts) -> stop() -> ok. -mech_new(Host, GetPassword, _CheckPassword) -> +mech_new(Host, GetPassword, _CheckPassword, CheckPasswordDigest) -> {ok, #state{step = 1, nonce = randoms:get_string(), host = Host, - get_password = GetPassword}}. + get_password = GetPassword, + check_password = CheckPasswordDigest}}. mech_step(#state{step = 1, nonce = Nonce} = State, _) -> {continue, @@ -56,10 +57,11 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> {false, _} -> {error, "not-authorized", UserName}; {Passwd, AuthModule} -> - Response = response(KeyVals, UserName, Passwd, - Nonce, AuthzId, "AUTHENTICATE"), - case xml:get_attr_s("response", KeyVals) of - Response -> + case (State#state.check_password)(UserName, Passwd, + xml:get_attr_s("response", KeyVals), + fun(PW) -> response(KeyVals, UserName, PW, Nonce, AuthzId, + "AUTHENTICATE") end) of + {true, _} -> RspAuth = response(KeyVals, UserName, Passwd, Nonce, AuthzId, ""), @@ -69,7 +71,7 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> auth_module = AuthModule, username = UserName, authzid = AuthzId}}; - _ -> + {false, _} -> {error, "not-authorized", UserName} end end diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl index d9c7f1a50..4e69b06ba 100644 --- a/src/cyrsasl_plain.erl +++ b/src/cyrsasl_plain.erl @@ -27,7 +27,7 @@ -module(cyrsasl_plain). -author('alexey@process-one.net'). --export([start/1, stop/0, mech_new/3, mech_step/2, parse/1]). +-export([start/1, stop/0, mech_new/4, mech_step/2, parse/1]). -behaviour(cyrsasl). @@ -40,7 +40,7 @@ start(_Opts) -> stop() -> ok. -mech_new(_Host, _GetPassword, CheckPassword) -> +mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) -> {ok, #state{check_password = CheckPassword}}. mech_step(State, ClientIn) -> diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 35b434f63..90bb34d17 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -84,12 +84,12 @@ check_password(User, Server, Password) -> end. %% @doc Check if the user and password can login in server. -%% @spec (User::string(), Server::string(), Password::string(), -%% StreamID::string(), Digest::string()) -> +%% @spec (User::string(), Server::string(), Password::string() +%% Digest::string(), DigestGen::function()) -> %% true | false -check_password(User, Server, Password, StreamID, Digest) -> +check_password(User, Server, Password, Digest, DigestGen) -> case check_password_with_authmodule(User, Server, Password, - StreamID, Digest) of + Digest, DigestGen) of {true, _AuthModule} -> true; false -> false end. @@ -107,9 +107,9 @@ check_password(User, Server, Password, StreamID, Digest) -> check_password_with_authmodule(User, Server, Password) -> check_password_loop(auth_modules(Server), [User, Server, Password]). -check_password_with_authmodule(User, Server, Password, StreamID, Digest) -> +check_password_with_authmodule(User, Server, Password, Digest, DigestGen) -> check_password_loop(auth_modules(Server), [User, Server, Password, - StreamID, Digest]). + Digest, DigestGen]). check_password_loop([], _Args) -> false; diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 9540e7c8c..05b9c98f5 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -173,7 +173,7 @@ purge_hook(true, LUser, LServer) -> %% before allowing access check_password(User, Server, Password) -> check_password(User, Server, Password, undefined, undefined). -check_password(User, Server, _Password, _StreamID, _Digest) -> +check_password(User, Server, _Password, _Digest, _DigestGen) -> %% We refuse login for registered accounts (They cannot logged but %% they however are "reserved") case ejabberd_auth:is_user_exists_in_other_modules(?MODULE, @@ -226,7 +226,7 @@ get_password(User, Server) -> get_password(User, Server, ""). get_password(User, Server, DefaultValue) -> - case anonymous_user_exist(User, Server) of + case anonymous_user_exist(User, Server) or login(User, Server) of %% We return the default value if the user is anonymous true -> DefaultValue; diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index d35d37f73..a5818a606 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -57,7 +57,7 @@ plain_password_required() -> check_password(User, Server, Password) -> extauth:check_password(User, Server, Password) andalso Password /= "". -check_password(User, Server, Password, _StreamID, _Digest) -> +check_password(User, Server, Password, _Digest, _DigestGen) -> check_password(User, Server, Password). set_password(User, Server, Password) -> diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 2b8c62fd6..a3851b532 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -73,7 +73,7 @@ check_password(User, Server, Password) -> false end. -check_password(User, Server, Password, StreamID, Digest) -> +check_password(User, Server, Password, Digest, DigestGen) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), US = {LUser, LServer}, @@ -81,7 +81,7 @@ check_password(User, Server, Password, StreamID, Digest) -> [#passwd{password = Passwd}] -> DigRes = if Digest /= "" -> - Digest == sha:sha(StreamID ++ Passwd); + Digest == DigestGen(Passwd); true -> false end, diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index 1e57e0216..ea3de540a 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -147,7 +147,7 @@ check_password(User, Server, Password) -> end end. -check_password(User, Server, Password, _StreamID, _Digest) -> +check_password(User, Server, Password, _Digest, _DigestGen) -> check_password(User, Server, Password). set_password(_User, _Server, _Password) -> diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index edd493581..e06ebc560 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -80,8 +80,8 @@ check_password(User, Server, Password) -> end end. -%% @spec (User, Server, Password, StreamID, Digest) -> true | false | {error, Error} -check_password(User, Server, Password, StreamID, Digest) -> +%% @spec (User, Server, Password, Digest, DigestGen) -> true | false | {error, Error} +check_password(User, Server, Password, Digest, DigestGen) -> case jlib:nodeprep(User) of error -> false; @@ -93,7 +93,7 @@ check_password(User, Server, Password, StreamID, Digest) -> {selected, ["password"], [{Passwd}]} -> DigRes = if Digest /= "" -> - Digest == sha:sha(StreamID ++ Passwd); + Digest == DigestGen(Passwd); true -> false end, diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl index 72237282e..304f025ac 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -55,7 +55,7 @@ start(_Host) -> set_password(_User, _Server, _Password) -> {error, not_allowed}. -check_password(User, Server, Password, _StreamID, _Digest) -> +check_password(User, Server, Password, _Digest, _DigestGen) -> check_password(User, Server, Password). check_password(User, Host, Password) -> diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 78fcd0761..df6144203 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -258,6 +258,10 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> fun(U, P) -> ejabberd_auth:check_password_with_authmodule( U, Server, P) + end, + fun(U, P, D, DG) -> + ejabberd_auth:check_password_with_authmodule( + U, Server, P, D, DG) end), Mechs = lists:map( fun(S) -> @@ -444,9 +448,10 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> (acl:match_rule(StateData#state.server, StateData#state.access, JID) == allow) of true -> + DGen = fun(PW) -> + sha:sha(StateData#state.streamid ++ PW) end, case ejabberd_auth:check_password_with_authmodule( - U, StateData#state.server, P, - StateData#state.streamid, D) of + U, StateData#state.server, P, D, DGen) of {true, AuthModule} -> ?INFO_MSG( "(~w) Accepted legacy authentication for ~s by ~p",