ejabberd - Comments for "sha256 Hashing Enabled in ODBC Tables - Fixing MOD_REST and sha256 at the same time" https://www.ejabberd.im/node/5910 en To enable legacy https://www.ejabberd.im/node/5910#comment-59269 <p>To enable legacy authentication you have to change:</p> <div class="codeblock"><code>plain_password_required() -&gt;<br />&nbsp;&nbsp;&nbsp; false.</code></div> <p>to:</p> <div class="codeblock"><code>plain_password_required() -&gt;<br />&nbsp;&nbsp;&nbsp; true.</code></div> <p>in ejabberd_auth_odbc.erl.</p> <p>Without this, older clients (like Jabbin) cannot authenticate. I've debugged it almost a whole day...</p> Mon, 26 Nov 2012 15:06:25 +0000 zoolyka comment 59269 at https://www.ejabberd.im I've added to ejabberd 2.1.x https://www.ejabberd.im/node/5910#comment-59013 <p>I've added to ejabberd 2.1.x branch the fix for ejabberd_commands to check password instead of get password. However, I haven't added the other changes, as I'm not certain if they will collision with SCRAM support.</p> Mon, 27 Aug 2012 15:00:50 +0000 mfoss comment 59013 at https://www.ejabberd.im Found out that we had to https://www.ejabberd.im/node/5910#comment-58886 <p>Found out that we had to remove the cyrsasl digest, scram, and anonymous support from cyrsasl.erl:</p> <div class="codeblock"><code>%%%----------------------------------------------------------------------<br />%%% File&nbsp;&nbsp;&nbsp; : cyrsasl.erl<br />%%% Author&nbsp; : Alexey Shchepin &lt;alexey@process-one.net&gt;<br />%%% Purpose : Cyrus SASL-like library<br />%%% Created :&nbsp; 8 Mar 2003 by Alexey Shchepin &lt;alexey@process-one.net&gt;<br />%%%<br />%%%<br />%%% ejabberd, Copyright (C) 2002-2012&nbsp;&nbsp; ProcessOne<br />%%%<br />%%% This program is free software; you can redistribute it and/or<br />%%% modify it under the terms of the GNU General Public License as<br />%%% published by the Free Software Foundation; either version 2 of the<br />%%% License, or (at your option) any later version.<br />%%%<br />%%% This program is distributed in the hope that it will be useful,<br />%%% but WITHOUT ANY WARRANTY; without even the implied warranty of<br />%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&nbsp; See the GNU<br />%%% General Public License for more details.<br />%%%<br />%%% You should have received a copy of the GNU General Public License<br />%%% along with this program; if not, write to the Free Software<br />%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA<br />%%% 02111-1307 USA<br />%%%<br />%%%---------------------------------------------------------------------- <p>-module(cyrsasl).<br />-author(&#039;alexey@process-one.net&#039;).</p> <p>-export([start/0,<br /> register_mechanism/3,<br /> listmech/1,<br /> server_new/7,<br /> server_start/3,<br /> server_step/2]).</p> <p>-include(&quot;ejabberd.hrl&quot;).</p> <p>-record(sasl_mechanism, {mechanism, module, password_type}).<br />-record(sasl_state, {service, myname, realm,<br /> &nbsp;&nbsp;&nbsp;&nbsp; get_password, check_password, check_password_digest,<br /> &nbsp;&nbsp;&nbsp;&nbsp; mech_mod, mech_state}).</p> <p>-export([behaviour_info/1]).</p> <p>behaviour_info(callbacks) -&gt;<br />&nbsp;&nbsp;&nbsp; [{mech_new, 4}, {mech_step, 2}];<br />behaviour_info(_Other) -&gt;<br />&nbsp;&nbsp;&nbsp; undefined.</p> <p>start() -&gt;<br />&nbsp;&nbsp;&nbsp; ets:new(sasl_mechanism, [named_table,<br /> &nbsp;&nbsp;&nbsp;&nbsp; public,<br /> &nbsp;&nbsp;&nbsp;&nbsp; {keypos, #sasl_mechanism.mechanism}]),<br />&nbsp;&nbsp;&nbsp; cyrsasl_plain:start([]),<br />%%&nbsp;&nbsp;&nbsp; cyrsasl_digest:start([]),<br />%%&nbsp;&nbsp;&nbsp; cyrsasl_scram:start([]),<br />%%&nbsp;&nbsp;&nbsp; cyrsasl_anonymous:start([]),<br />&nbsp;&nbsp;&nbsp; ok.</p> <p>register_mechanism(Mechanism, Module, PasswordType) -&gt;<br />&nbsp;&nbsp;&nbsp; ets:insert(sasl_mechanism,<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #sasl_mechanism{mechanism = Mechanism,<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; module = Module,<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; password_type = PasswordType}).</p> <p>%%% TODO: use callbacks<br />%%-include(&quot;ejabberd.hrl&quot;).<br />%%-include(&quot;jlib.hrl&quot;).<br />%%check_authzid(_State, Props) -&gt;<br />%%&nbsp;&nbsp;&nbsp; AuthzId = xml:get_attr_s(authzid, Props),<br />%%&nbsp;&nbsp;&nbsp; case jlib:string_to_jid(AuthzId) of<br />%% error -&gt;<br />%% &nbsp;&nbsp;&nbsp; {error, &quot;invalid-authzid&quot;};<br />%% JID -&gt;<br />%% &nbsp;&nbsp;&nbsp; LUser = jlib:nodeprep(xml:get_attr_s(username, Props)),<br />%% &nbsp;&nbsp;&nbsp; {U, S, R} = jlib:jid_tolower(JID),<br />%% &nbsp;&nbsp;&nbsp; case R of<br />%% &quot;&quot; -&gt;<br />%% &nbsp;&nbsp;&nbsp; {error, &quot;invalid-authzid&quot;};<br />%% _ -&gt;<br />%% &nbsp;&nbsp;&nbsp; case {LUser, ?MYNAME} of<br />%% {U, S} -&gt;<br />%% &nbsp;&nbsp;&nbsp; ok;<br />%% _ -&gt;<br />%% &nbsp;&nbsp;&nbsp; {error, &quot;invalid-authzid&quot;}<br />%% &nbsp;&nbsp;&nbsp; end<br />%% &nbsp;&nbsp;&nbsp; end<br />%%&nbsp;&nbsp;&nbsp; end.</p> <p>check_credentials(_State, Props) -&gt;<br />&nbsp;&nbsp;&nbsp; User = xml:get_attr_s(username, Props),<br />&nbsp;&nbsp;&nbsp; case jlib:nodeprep(User) of<br /> error -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, &quot;not-authorized&quot;};<br /> &quot;&quot; -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, &quot;not-authorized&quot;};<br /> _LUser -&gt;<br /> &nbsp;&nbsp;&nbsp; ok<br />&nbsp;&nbsp;&nbsp; end.</p> <p>listmech(Host) -&gt;<br />&nbsp;&nbsp;&nbsp; Mechs = ets:select(sasl_mechanism,<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{#sasl_mechanism{mechanism = &#039;$1&#039;,<br /> password_type = &#039;$2&#039;,<br /> _ = &#039;_&#039;},<br /> case catch ejabberd_auth:store_type(Host) of<br /> external -&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{&#039;==&#039;, &#039;$2&#039;, plain}];<br /> scram -&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{&#039;/=&#039;, &#039;$2&#039;, digest}];<br /> {&#039;EXIT&#039;,{undef,[{Module,store_type,[]} | _]}} -&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ?WARNING_MSG(&quot;~p doesn&#039;t implement the function store_type/0&quot;, [Module]),<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [];<br /> _Else -&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; []<br /> end,<br /> [&#039;$1&#039;]}]),<br />&nbsp;&nbsp;&nbsp; filter_anonymous(Host, Mechs).</p> <p>server_new(Service, ServerFQDN, UserRealm, _SecFlags,<br /> &nbsp;&nbsp; GetPassword, CheckPassword, CheckPasswordDigest) -&gt;<br />&nbsp;&nbsp;&nbsp; #sasl_state{service = Service,<br /> myname = ServerFQDN,<br /> realm = UserRealm,<br /> get_password = GetPassword,<br /> check_password = CheckPassword,<br /> check_password_digest= CheckPasswordDigest}.</p> <p>server_start(State, Mech, ClientIn) -&gt;<br />&nbsp;&nbsp;&nbsp; case lists:member(Mech, listmech(State#sasl_state.myname)) of<br /> true -&gt;<br /> &nbsp;&nbsp;&nbsp; case ets:lookup(sasl_mechanism, Mech) of<br /> [#sasl_mechanism{module = Module}] -&gt;<br /> &nbsp;&nbsp;&nbsp; {ok, MechState} = Module:mech_new(<br /> State#sasl_state.myname,<br /> State#sasl_state.get_password,<br /> State#sasl_state.check_password,<br /> State#sasl_state.check_password_digest),<br /> &nbsp;&nbsp;&nbsp; server_step(State#sasl_state{mech_mod = Module,<br /> mech_state = MechState},<br /> ClientIn);<br /> _ -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, &quot;no-mechanism&quot;}<br /> &nbsp;&nbsp;&nbsp; end;<br /> false -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, &quot;no-mechanism&quot;}<br />&nbsp;&nbsp;&nbsp; end.</p> <p>server_step(State, ClientIn) -&gt;<br />&nbsp;&nbsp;&nbsp; Module = State#sasl_state.mech_mod,<br />&nbsp;&nbsp;&nbsp; MechState = State#sasl_state.mech_state,<br />&nbsp;&nbsp;&nbsp; case Module:mech_step(MechState, ClientIn) of<br /> {ok, Props} -&gt;<br /> &nbsp;&nbsp;&nbsp; case check_credentials(State, Props) of<br /> ok -&gt;<br /> &nbsp;&nbsp;&nbsp; {ok, Props};<br /> {error, Error} -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, Error}<br /> &nbsp;&nbsp;&nbsp; end;<br /> {ok, Props, ServerOut} -&gt;<br /> &nbsp;&nbsp;&nbsp; case check_credentials(State, Props) of<br /> ok -&gt;<br /> &nbsp;&nbsp;&nbsp; {ok, Props, ServerOut};<br /> {error, Error} -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, Error}<br /> &nbsp;&nbsp;&nbsp; end;<br /> {continue, ServerOut, NewMechState} -&gt;<br /> &nbsp;&nbsp;&nbsp; {continue, ServerOut,<br /> &nbsp;&nbsp;&nbsp;&nbsp; State#sasl_state{mech_state = NewMechState}};<br /> {error, Error, Username} -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, Error, Username};<br /> {error, Error} -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, Error}<br />&nbsp;&nbsp;&nbsp; end.</p> <p>%% Remove the anonymous mechanism from the list if not enabled for the given<br />%% host<br />filter_anonymous(Host, Mechs) -&gt;<br />&nbsp;&nbsp;&nbsp; case ejabberd_auth_anonymous:is_sasl_anonymous_enabled(Host) of<br /> true&nbsp; -&gt; Mechs;<br /> false -&gt; Mechs -- [&quot;ANONYMOUS&quot;]<br />&nbsp;&nbsp;&nbsp; end.</p></code></div> <p>Also, there was a bug in my auth_odbc changes. Fixed:</p> <div class="codeblock"><code>%%%----------------------------------------------------------------------<br />%%% File&nbsp;&nbsp;&nbsp; : ejabberd_auth_odbc.erl<br />%%% Author&nbsp; : Alexey Shchepin &lt;alexey@process-one.net&gt;<br />%%% Purpose : Authentification via ODBC<br />%%% Created : 12 Dec 2004 by Alexey Shchepin &lt;alexey@process-one.net&gt;<br />%%%<br />%%%<br />%%% ejabberd, Copyright (C) 2002-2012&nbsp;&nbsp; ProcessOne<br />%%%<br />%%% This program is free software; you can redistribute it and/or<br />%%% modify it under the terms of the GNU General Public License as<br />%%% published by the Free Software Foundation; either version 2 of the<br />%%% License, or (at your option) any later version.<br />%%%<br />%%% This program is distributed in the hope that it will be useful,<br />%%% but WITHOUT ANY WARRANTY; without even the implied warranty of<br />%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&nbsp; See the GNU<br />%%% General Public License for more details.<br />%%%<br />%%% You should have received a copy of the GNU General Public License<br />%%% along with this program; if not, write to the Free Software<br />%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA<br />%%% 02111-1307 USA<br />%%%<br />%%%---------------------------------------------------------------------- <p>-module(ejabberd_auth_odbc).<br />-author(&#039;alexey@process-one.net&#039;).</p> <p>%% External exports<br />-export([start/1,<br /> set_password/3,<br /> check_password/3,<br /> check_password/5,<br /> try_register/3,<br /> dirty_get_registered_users/0,<br /> get_vh_registered_users/1,<br /> get_vh_registered_users/2,<br /> get_vh_registered_users_number/1,<br /> get_vh_registered_users_number/2,<br /> get_password/2,<br /> get_password_s/2,<br /> is_user_exists/2,<br /> remove_user/2,<br /> remove_user/3,<br /> store_type/0,<br /> plain_password_required/0<br /> ]).</p> <p>-include(&quot;ejabberd.hrl&quot;).</p> <p>%%%----------------------------------------------------------------------<br />%%% API<br />%%%----------------------------------------------------------------------<br />start(_Host) -&gt;<br />&nbsp;&nbsp;&nbsp; ok.</p> <p>hash(User, Password) -&gt;<br />&nbsp;&nbsp;&nbsp; Split=&quot;--Zach Calvert--&quot;,<br />&nbsp;&nbsp;&nbsp; bitstring_to_list(base64:encode(erlsha2:sha256((string:concat(string:concat(Password, Split), User))))).</p> <p>plain_password_required() -&gt;<br />&nbsp;&nbsp;&nbsp; false.</p> <p>store_type() -&gt;<br /> plain.</p> <p>%% @spec (User, Server, Password) -&gt; true | false | {error, Error}<br />check_password(User, Server, Password) -&gt;<br />&nbsp;&nbsp;&nbsp; HashedPassword = hash(User, Password), <br />&nbsp;&nbsp;&nbsp; case jlib:nodeprep(User) of<br /> error -&gt;<br /> &nbsp;&nbsp;&nbsp; false;<br /> LUser -&gt;<br /> &nbsp;&nbsp;&nbsp; Username = ejabberd_odbc:escape(LUser),<br /> &nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br /> &nbsp;&nbsp;&nbsp; try odbc_queries:get_password(LServer, Username) of<br /> {selected, [&quot;password&quot;], [{HashedPassword}]} -&gt;<br /> &nbsp;&nbsp;&nbsp; Password /= &quot;&quot;; %% Password is correct, and not empty<br /> {selected, [&quot;password&quot;], [{_Password2}]} -&gt;<br /> &nbsp;&nbsp;&nbsp; false; %% Password is not correct<br /> {selected, [&quot;password&quot;], []} -&gt;<br /> &nbsp;&nbsp;&nbsp; false; %% Account does not exist<br /> {error, _Error} -&gt;<br /> &nbsp;&nbsp;&nbsp; false %% Typical error is that table doesn&#039;t exist<br /> &nbsp;&nbsp;&nbsp; catch<br /> _:_ -&gt;<br /> &nbsp;&nbsp;&nbsp; false %% Typical error is database not accessible<br /> &nbsp;&nbsp;&nbsp; end<br />&nbsp;&nbsp;&nbsp; end.</p> <p>%% @spec (User, Server, Password, Digest, DigestGen) -&gt; true | false | {error, Error}<br />check_password(User, Server, Password, Digest, DigestGen) -&gt;<br />&nbsp;&nbsp;&nbsp; HashedPassword = hash(User, Password),<br />&nbsp;&nbsp;&nbsp; case jlib:nodeprep(User) of<br /> error -&gt;<br /> &nbsp;&nbsp;&nbsp; false;<br /> LUser -&gt;<br /> &nbsp;&nbsp;&nbsp; Username = ejabberd_odbc:escape(LUser),<br /> &nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br /> &nbsp;&nbsp;&nbsp; try odbc_queries:get_password(LServer, Username) of<br /> %% Account exists, check if password is valid<br /> {selected, [&quot;password&quot;], [{HashedPassword}]} -&gt;<br /> &nbsp;&nbsp;&nbsp; Password /= &quot;&quot;; %% Password is correct, and not empty<br /> {selected, [&quot;password&quot;], [{Passwd}]} -&gt;<br /> &nbsp;&nbsp;&nbsp; DigRes = if<br /> Digest /= &quot;&quot; -&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp; Digest == DigestGen(Passwd);<br /> true -&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp; false<br /> &nbsp;&nbsp;&nbsp;&nbsp; end,<br /> &nbsp;&nbsp;&nbsp; if DigRes -&gt;<br /> &nbsp;&nbsp;&nbsp; true;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true -&gt;<br /> &nbsp;&nbsp;&nbsp; (Passwd == HashedPassword) and (Password /= &quot;&quot;)<br /> &nbsp;&nbsp;&nbsp; end;<br /> {selected, [&quot;password&quot;], []} -&gt;<br /> &nbsp;&nbsp;&nbsp; false; %% Account does not exist<br /> {error, _Error} -&gt;<br /> &nbsp;&nbsp;&nbsp; false %% Typical error is that table doesn&#039;t exist<br /> &nbsp;&nbsp;&nbsp; catch<br /> _:_ -&gt;<br /> &nbsp;&nbsp;&nbsp; false %% Typical error is database not accessible<br /> &nbsp;&nbsp;&nbsp; end<br />&nbsp;&nbsp;&nbsp; end.</p> <p>%% @spec (User::string(), Server::string(), Password::string()) -&gt;<br />%%&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ok | {error, invalid_jid}<br />set_password(User, Server, Password) -&gt;<br />&nbsp;&nbsp;&nbsp; case jlib:nodeprep(User) of<br /> error -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, invalid_jid};<br /> LUser -&gt;<br /> &nbsp;&nbsp;&nbsp; Username = ejabberd_odbc:escape(LUser),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HashedPassword = hash(User, Password), <br /> &nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br /> &nbsp;&nbsp;&nbsp; case catch odbc_queries:set_password_t(LServer, Username, HashedPassword) of<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {atomic, ok} -&gt; ok;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Other -&gt; {error, Other}<br /> &nbsp;&nbsp;&nbsp; end<br />&nbsp;&nbsp;&nbsp; end.</p> <p>%% @spec (User, Server, Password) -&gt; {atomic, ok} | {atomic, exists} | {error, invalid_jid}<br />try_register(User, Server, Password) -&gt;<br />&nbsp;&nbsp;&nbsp; case jlib:nodeprep(User) of<br /> error -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, invalid_jid};<br /> LUser -&gt;<br /> &nbsp;&nbsp;&nbsp; Username = ejabberd_odbc:escape(LUser),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HashedPassword = hash(User, Password),<br /> &nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br /> &nbsp;&nbsp;&nbsp; case catch odbc_queries:add_user(LServer, Username, HashedPassword) of<br /> {updated, 1} -&gt;<br /> &nbsp;&nbsp;&nbsp; {atomic, ok};<br /> _ -&gt;<br /> &nbsp;&nbsp;&nbsp; {atomic, exists}<br /> &nbsp;&nbsp;&nbsp; end<br />&nbsp;&nbsp;&nbsp; end.</p> <p>dirty_get_registered_users() -&gt;<br />&nbsp;&nbsp;&nbsp; Servers = ejabberd_config:get_vh_by_auth_method(odbc),<br />&nbsp;&nbsp;&nbsp; lists:flatmap(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fun(Server) -&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get_vh_registered_users(Server)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end, Servers).</p> <p>get_vh_registered_users(Server) -&gt;<br />&nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br />&nbsp;&nbsp;&nbsp; case catch odbc_queries:list_users(LServer) of<br /> {selected, [&quot;username&quot;], Res} -&gt;<br /> &nbsp;&nbsp;&nbsp; [{U, LServer} || {U} &lt;- Res];<br /> _ -&gt;<br /> &nbsp;&nbsp;&nbsp; []<br />&nbsp;&nbsp;&nbsp; end.</p> <p>get_vh_registered_users(Server, Opts) -&gt;<br />&nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br />&nbsp;&nbsp;&nbsp; case catch odbc_queries:list_users(LServer, Opts) of<br /> {selected, [&quot;username&quot;], Res} -&gt;<br /> &nbsp;&nbsp;&nbsp; [{U, LServer} || {U} &lt;- Res];<br /> _ -&gt;<br /> &nbsp;&nbsp;&nbsp; []<br />&nbsp;&nbsp;&nbsp; end.</p> <p>get_vh_registered_users_number(Server) -&gt;<br />&nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br />&nbsp;&nbsp;&nbsp; case catch odbc_queries:users_number(LServer) of<br /> {selected, [_], [{Res}]} -&gt;<br /> &nbsp;&nbsp;&nbsp; list_to_integer(Res);<br /> _ -&gt;<br /> &nbsp;&nbsp;&nbsp; 0<br />&nbsp;&nbsp;&nbsp; end.</p> <p>get_vh_registered_users_number(Server, Opts) -&gt;<br />&nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br />&nbsp;&nbsp;&nbsp; case catch odbc_queries:users_number(LServer, Opts) of<br /> {selected, [_], [{Res}]} -&gt;<br /> &nbsp;&nbsp;&nbsp; list_to_integer(Res);<br /> _Other -&gt;<br /> &nbsp;&nbsp;&nbsp; 0<br />&nbsp;&nbsp;&nbsp; end.</p> <p>get_password(User, Server) -&gt;<br />&nbsp;&nbsp;&nbsp; case jlib:nodeprep(User) of<br /> error -&gt;<br /> &nbsp;&nbsp;&nbsp; false;<br /> LUser -&gt;<br /> &nbsp;&nbsp;&nbsp; Username = ejabberd_odbc:escape(LUser),<br /> &nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br /> &nbsp;&nbsp;&nbsp; case catch odbc_queries:get_password(LServer, Username) of<br /> {selected, [&quot;password&quot;], [{Password}]} -&gt;<br /> &nbsp;&nbsp;&nbsp; Password;<br /> _ -&gt;<br /> &nbsp;&nbsp;&nbsp; false<br /> &nbsp;&nbsp;&nbsp; end<br />&nbsp;&nbsp;&nbsp; end.</p> <p>get_password_s(User, Server) -&gt;<br />&nbsp;&nbsp;&nbsp; case jlib:nodeprep(User) of<br /> error -&gt;<br /> &nbsp;&nbsp;&nbsp; &quot;&quot;;<br /> LUser -&gt;<br /> &nbsp;&nbsp;&nbsp; Username = ejabberd_odbc:escape(LUser),<br /> &nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br /> &nbsp;&nbsp;&nbsp; case catch odbc_queries:get_password(LServer, Username) of<br /> {selected, [&quot;password&quot;], [{Password}]} -&gt;<br /> &nbsp;&nbsp;&nbsp; Password;<br /> _ -&gt;<br /> &nbsp;&nbsp;&nbsp; &quot;&quot;<br /> &nbsp;&nbsp;&nbsp; end<br />&nbsp;&nbsp;&nbsp; end.</p> <p>%% @spec (User, Server) -&gt; true | false | {error, Error}<br />is_user_exists(User, Server) -&gt;<br />&nbsp;&nbsp;&nbsp; case jlib:nodeprep(User) of<br /> error -&gt;<br /> &nbsp;&nbsp;&nbsp; false;<br /> LUser -&gt;<br /> &nbsp;&nbsp;&nbsp; Username = ejabberd_odbc:escape(LUser),<br /> &nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br /> &nbsp;&nbsp;&nbsp; try odbc_queries:get_password(LServer, Username) of<br /> {selected, [&quot;password&quot;], [{_Password}]} -&gt;<br /> &nbsp;&nbsp;&nbsp; true; %% Account exists<br /> {selected, [&quot;password&quot;], []} -&gt;<br /> &nbsp;&nbsp;&nbsp; false; %% Account does not exist<br /> {error, Error} -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, Error} %% Typical error is that table doesn&#039;t exist<br /> &nbsp;&nbsp;&nbsp; catch<br /> _:B -&gt;<br /> &nbsp;&nbsp;&nbsp; {error, B} %% Typical error is database not accessible<br /> &nbsp;&nbsp;&nbsp; end<br />&nbsp;&nbsp;&nbsp; end.</p> <p>%% @spec (User, Server) -&gt; ok | error<br />%% @doc Remove user.<br />%% Note: it may return ok even if there was some problem removing the user.<br />remove_user(User, Server) -&gt;<br />&nbsp;&nbsp;&nbsp; case jlib:nodeprep(User) of<br /> error -&gt;<br /> &nbsp;&nbsp;&nbsp; error;<br /> LUser -&gt;<br /> &nbsp;&nbsp;&nbsp; Username = ejabberd_odbc:escape(LUser),<br /> &nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br /> &nbsp;&nbsp;&nbsp; catch odbc_queries:del_user(LServer, Username),<br /> ok<br />&nbsp;&nbsp;&nbsp; end.</p> <p>%% @spec (User, Server, Password) -&gt; ok | error | not_exists | not_allowed<br />%% @doc Remove user if the provided password is correct.<br />remove_user(User, Server, Password) -&gt;<br />&nbsp;&nbsp;&nbsp; case jlib:nodeprep(User) of<br /> error -&gt;<br /> &nbsp;&nbsp;&nbsp; error;<br /> LUser -&gt;<br /> &nbsp;&nbsp;&nbsp; Username = ejabberd_odbc:escape(LUser),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HashedPassword = hash(User, Password),<br /> &nbsp;&nbsp;&nbsp; LServer = jlib:nameprep(Server),<br /> &nbsp;&nbsp;&nbsp; F = fun() -&gt;<br /> Result = odbc_queries:del_user_return_password(<br /> &nbsp;&nbsp; LServer, Username, HashedPassword),<br /> case Result of<br /> &nbsp;&nbsp;&nbsp; {selected, [&quot;password&quot;], [{Password}]} -&gt;<br /> ok;<br /> &nbsp;&nbsp;&nbsp; {selected, [&quot;password&quot;], []} -&gt;<br /> not_exists;<br /> &nbsp;&nbsp;&nbsp; _ -&gt;<br /> not_allowed<br /> end<br /> end,<br /> &nbsp;&nbsp;&nbsp; {atomic, Result} = odbc_queries:sql_transaction(LServer, F),<br /> &nbsp;&nbsp;&nbsp; Result<br />&nbsp;&nbsp;&nbsp; end.</p></code></div> Fri, 20 Jul 2012 21:35:21 +0000 Zach Calvert comment 58886 at https://www.ejabberd.im