Update of /cvsroot/jungerl/jungerl/lib/pgsql/src
In directory sc8-pr-cvs6.sourceforge.net:/tmp/cvs-serv28180
Modified Files:
pgsql_proto.erl pgsql_util.erl
Log Message:
MD5 authentication method. Thanks to Juhani Rankimies <juhani@...> for this feature.
Index: pgsql_util.erl
===================================================================
RCS file: /cvsroot/jungerl/jungerl/lib/pgsql/src/pgsql_util.erl,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- pgsql_util.erl 17 Dec 2005 21:57:40 -0000 1.3
+++ pgsql_util.erl 28 Oct 2006 21:05:29 -0000 1.4
@@ -24,6 +24,11 @@
-export([zip/2]).
+%% Constructing authentication messages.
+-export([pass_plain/1, pass_md5/3]).
+-import(erlang, [md5/1]).
+-export([hexlist/2]).
+
%% Lookup key in a plist stored in process dictionary under 'options'.
%% Default is returned if there is no value for Key in the plist.
option(Key, Default) ->
@@ -72,7 +77,7 @@
case gen_tcp:recv(Sock, 1, Timeout) of
{ok, <<Byte:1/integer-unit:8>>} ->
{ok, Byte};
- E={error, Reason} ->
+ E={error, _Reason} ->
throw(E)
end.
@@ -123,7 +128,7 @@
{N, <<>>};
count_string(<<0/integer, Rest/binary>>, N) ->
{N, Rest};
-count_string(<<C/integer, Rest/binary>>, N) ->
+count_string(<<_C/integer, Rest/binary>>, N) ->
count_string(Rest, N+1).
to_string(Bin) when binary(Bin) ->
@@ -161,7 +166,7 @@
<<Len:32/integer, Data:Len/binary, Rest/binary>>,
Descs) when N >= 0 ->
datacoldescs(N-1, Rest, [Data|Descs]);
-datacoldescs(N, _, Descs) ->
+datacoldescs(_N, _, Descs) ->
lists:reverse(Descs).
decode_descs(Cols) ->
@@ -195,7 +200,7 @@
errordesc(Bin) ->
errordesc(Bin, []).
-errordesc(<<0/integer, Rest/binary>>, Lines) ->
+errordesc(<<0/integer, _Rest/binary>>, Lines) ->
lists:reverse(Lines);
errordesc(<<Code/integer, Rest/binary>>, Lines) ->
{String, Count} = to_string(Rest),
@@ -236,3 +241,52 @@
lists:reverse(Result);
zip([H1|List1], [H2|List2], Result) ->
zip(List1, List2, [{H1, H2}|Result]).
+
+%%% Authentication utils
+
+pass_plain(Password) ->
+ Pass = [Password, 0],
+ list_to_binary(Pass).
+
+%% MD5 authentication patch from
+%% Juhani Rankimies <juhani@...>
+%% (patch slightly rewritten, new bugs are mine :] /Christian Sunesson)
+
+%%
+%% MD5(MD5(password + user) + salt)
+%%
+
+pass_md5(User, Password, Salt) ->
+ Digest = hex(md5([Password, User])),
+ Encrypt = hex(md5([Digest, Salt])),
+ Pass = ["md5", Encrypt, 0],
+ list_to_binary(Pass).
+
+hex(B) when binary(B) ->
+ hexlist(binary_to_list(B), []).
+
+hexlist([], Acc) ->
+ lists:reverse(Acc);
+hexlist([N|Rest], Acc) ->
+ HighNibble = (N band 16#f0) bsr 4,
+ LowNibble = (N band 16#0f),
+ hexlist(Rest, [hexdigit(LowNibble), hexdigit(HighNibble)|Acc]).
+
+hexdigit(0) -> $0;
+hexdigit(1) -> $1;
+hexdigit(2) -> $2;
+hexdigit(3) -> $3;
+hexdigit(4) -> $4;
+hexdigit(5) -> $5;
+hexdigit(6) -> $6;
+hexdigit(7) -> $7;
+hexdigit(8) -> $8;
+hexdigit(9) -> $9;
+hexdigit(10) -> $a;
+hexdigit(11) -> $b;
+hexdigit(12) -> $c;
+hexdigit(13) -> $d;
+hexdigit(14) -> $e;
+hexdigit(15) -> $f.
+
+
Index: pgsql_proto.erl
===================================================================
RCS file: /cvsroot/jungerl/jungerl/lib/pgsql/src/pgsql_proto.erl,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- pgsql_proto.erl 17 Dec 2005 21:57:40 -0000 1.4
+++ pgsql_proto.erl 28 Oct 2006 21:05:29 -0000 1.5
@@ -108,7 +108,7 @@
%% Error response
{error_message, Message} ->
exit({authentication, Message});
- {authenticate, AuthMethod} ->
+ {authenticate, {AuthMethod, Salt}} ->
case AuthMethod of
0 -> % Auth ok
setup(Sock, []);
@@ -116,17 +116,19 @@
exit({nyi, auth_kerberos4});
2 -> % Kerberos 5
exit({nyi, auth_kerberos5});
- 3 -> % Password
- PassString = list_to_binary(option(password, "")),
- PassWordLen = size(PassString) + 5,
- Password = <<$p, PassWordLen:32/integer,
- PassString/binary, 0>>,
- ok = send(Sock, Password),
+ 3 -> % Plaintext password
+ Password = option(password, ""),
+ EncodedPass = encode_message(pass_plain, Password),
+ ok = send(Sock, EncodedPass),
authenticate(Sock);
4 -> % Hashed password
exit({nyi, auth_crypt});
5 -> % MD5 password
- exit({nyi, auth_md5});
+ Password = option(password, ""),
+ User = option(user, ""),
+ EncodedPass = encode_message(pass_md5, {User, Password, Salt}),
+ ok = send(Sock, EncodedPass),
+ authenticate(Sock);
_ ->
exit({authentication, {unknown, AuthMethod}})
end;
@@ -507,8 +509,8 @@
?PG_NOTICE_RESPONSE ->
Ret(notice_response, []);
?PG_AUTHENTICATE ->
- <<AuthMethod:32/integer, _Rest/binary>> = Packet,
- Ret(authenticate, AuthMethod);
+ <<AuthMethod:32/integer, Salt/binary>> = Packet,
+ Ret(authenticate, {AuthMethod, Salt});
?PG_PARSE_COMPLETE ->
Ret(parse_complete, []);
?PG_BIND_COMPLETE ->
@@ -539,6 +541,12 @@
<<Code:8/integer, Len:4/integer-unit:8, Packet/binary>>.
%% Encode a message of a given type.
+encode_message(pass_plain, Password) ->
+ Pass = pgsql_util:pass_plain(Password),
+ encode($p, Pass);
+encode_message(pass_md5, {User, Password, Salt}) ->
+ Pass = pgsql_util:pass_md5(User, Password, Salt),
+ encode($p, Pass);
encode_message(terminate, _) ->
encode($X, <<>>);
encode_message(squery, Query) -> % squery as in simple query.
|