diff --git a/ChangeLog b/ChangeLog index 4d6264c0a..fbe370c96 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,22 @@ 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) + * 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 1f99f63ee..c1287e080 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -30,7 +30,7 @@ -export([start/0, register_mechanism/3, listmech/1, - server_new/6, + server_new/7, server_start/3, server_step/2]). @@ -53,7 +53,7 @@ %% State of this process. -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]). @@ -61,7 +61,7 @@ %% @hidden behaviour_info(callbacks) -> - [{mech_new, 3}, {mech_step, 2}]; + [{mech_new, 4}, {mech_step, 2}]; behaviour_info(_Other) -> undefined. @@ -157,12 +157,13 @@ listmech(Host) -> %% CheckPassword = function() 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}. %% @spec (State, Mech, ClientIn) -> Ok | Continue | Error %% State = saslstate() @@ -188,7 +189,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 84dc24831..d90838918 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). @@ -48,13 +48,13 @@ start(_Opts) -> stop() -> ok. -%% @spec (Host, GetPassword, CheckPassword) -> {ok, State} +%% @spec (Host, GetPassword, CheckPassword, CheckPasswordDigest) -> {ok, State} %% Host = string() %% GetPassword = function() %% CheckPassword = function() %% State = mechstate() -mech_new(Host, _GetPassword, _CheckPassword) -> +mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) -> {ok, #state{server = Host}}. %% @spec (State, ClientIn) -> Ok | Error diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index 1f07e407f..4c2a2a103 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). -%% @type mechstate() = {state, Step, Nonce, Username, AuthzId, GetPassword, AuthModule, Host} +%% @type mechstate() = {state, Step, Nonce, Username, AuthzId, GetPassword, CheckPassword, AuthModule, Host} %% Step = 1 | 3 | 5 %% Nonce = string() %% Username = string() @@ -27,7 +27,7 @@ %% AuthModule = atom() %% Host = string(). --record(state, {step, nonce, username, authzid, get_password, auth_module, +-record(state, {step, nonce, username, authzid, get_password, check_password, auth_module, host}). %% @spec (Opts) -> true @@ -41,17 +41,18 @@ start(_Opts) -> stop() -> ok. -%% @spec (Host, GetPassword, CheckPassword) -> {ok, State} +%% @spec (Host, GetPassword, CheckPassword, CheckPasswordDigest) -> {ok, State} %% Host = string() %% GetPassword = function() %% CheckPassword = function() %% State = mechstate() -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}}. %% @spec (State, ClientIn) -> Ok | Continue | Error %% State = mechstate() @@ -91,10 +92,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 proplists:get_value("response", KeyVals, "") of - Response -> + case (State#state.check_password)(UserName, Passwd, + proplists:get_value("response", KeyVals, ""), + fun(PW) -> response(KeyVals, UserName, PW, Nonce, AuthzId, + "AUTHENTICATE") end) of + {true, _} -> RspAuth = response(KeyVals, UserName, Passwd, Nonce, AuthzId, ""), @@ -104,7 +106,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 ffcf4b104..12576c77a 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). @@ -48,13 +48,13 @@ start(_Opts) -> stop() -> ok. -%% @spec (Host, GetPassword, CheckPassword) -> {ok, State} +%% @spec (Host, GetPassword, CheckPassword, CheckPasswordDigest) -> {ok, State} %% Host = string() %% GetPassword = function() %% CheckPassword = function() %% State = mechstate() -mech_new(_Host, _GetPassword, CheckPassword) -> +mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) -> {ok, #state{check_password = CheckPassword}}. %% @spec (State, ClientIn) -> Ok | Error diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 357e5cfae..bce8bd3cf 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -97,19 +97,19 @@ check_password(User, Server, Password) false -> false end. -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() %% @doc Check if the user and password can login in server. -check_password(User, Server, Password, StreamID, Digest) +check_password(User, Server, Password, Digest, DigestGen) when is_list(User), is_list(Server), is_list(Password), - is_list(StreamID), is_list(Digest) -> + is_list(Digest), is_function(DigestGen) -> case check_password_with_authmodule(User, Server, Password, - StreamID, Digest) of + Digest, DigestGen) of {true, _AuthModule} -> true; false -> false end. @@ -128,22 +128,22 @@ check_password_with_authmodule(User, Server, Password) when is_list(User), is_list(Server), is_list(Password) -> check_password_loop(auth_modules(Server), [User, Server, Password]). -%% @spec (User, Server, Password, StreamID, Digest) -> {true, AuthModule} | false +%% @spec (User, Server, Password, Digest, DigestGen) -> {true, AuthModule} | false %% User = string() %% Server = string() %% Password = string() | undefined -%% StreamID = string() %% Digest = string() | undefined +%% DigestGen = function() %% AuthModule = authmodule() %% The password is 'undefined' if the client %% authenticates using the digest method as defined in %% XEP-0078: Non-SASL Authentication -check_password_with_authmodule(User, Server, Password, StreamID, Digest) +check_password_with_authmodule(User, Server, Password, Digest, DigestGen) when is_list(User), is_list(Server), (is_list(Password) orelse Password == 'undefined'), - is_list(StreamID), (is_list(Digest) orelse Digest == 'undefined')-> + is_function(DigestGen), (is_list(Digest) orelse Digest == 'undefined')-> 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 440fa16ca..0a9361180 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -229,7 +229,7 @@ purge_hook(true, LUser, LServer) when is_list(LUser), is_list(LServer) -> 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, @@ -310,7 +310,7 @@ get_password(User, Server) -> %% DefaultValue = string() 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 bcdce272a..d9a32dd20 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -68,14 +68,14 @@ plain_password_required() -> check_password(User, Server, Password) -> extauth:check_password(User, Server, Password) andalso Password /= "". -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() -check_password(User, Server, Password, _StreamID, _Digest) -> +check_password(User, Server, Password, _Digest, _DigestGen) -> check_password(User, Server, Password). %% @spec (User, Server, Password) -> ok | {error, unknown_problem} diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 003b24edf..74aa82c7c 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -84,14 +84,14 @@ check_password(User, Server, Password) -> false end. -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() -check_password(User, Server, Password, StreamID, Digest) -> +check_password(User, Server, Password, Digest, DigestGen) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, @@ -99,7 +99,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 c083cc141..7a31d6bae 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -169,14 +169,14 @@ check_password(User, Server, Password) -> end end. -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() -check_password(User, Server, Password, _StreamID, _Digest) -> +check_password(User, Server, Password, _Digest, _DigestGen) -> check_password(User, Server, Password). %% @spec (User, Server, Password) -> {error, not_allowed} diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 4b390eb06..0943488f4 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -91,14 +91,14 @@ check_password(User, Server, Password) -> false end. -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() -check_password(User, Server, Password, StreamID, Digest) -> +check_password(User, Server, Password, Digest, DigestGen) -> try LUser = exmpp_stringprep:nodeprep(User), Username = ejabberd_odbc:escape(LUser), @@ -108,7 +108,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 e147e1cc0..a5ff59c47 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -64,12 +64,12 @@ start(_Host) -> set_password(_User, _Server, _Password) -> {error, not_allowed}. -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() check_password(User, Server, Password, _StreamID, _Digest) -> check_password(User, Server, Password). diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 762961a95..b15ebdc1b 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -257,6 +257,10 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, 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), SASL_Mechs = [exmpp_server_sasl:feature( cyrsasl:listmech(Server))], @@ -402,9 +406,11 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> case acl:match_rule(ServerString, StateData#state.access, JID) of allow -> + DGen = fun(PW) -> + sha:sha(StateData#state.streamid ++ PW) end, case ejabberd_auth:check_password_with_authmodule( U, ServerString, P, - StateData#state.streamid, D) of + D, DGen) of {true, AuthModule} -> ?INFO_MSG( "(~w) Accepted legacy authentication for ~s by ~s",