Code review for MD5 authorization patch. Clean up some breakage

(salts were always zero!?), add much missing documentation.
This commit is contained in:
Tom Lane 2001-09-21 20:31:49 +00:00
parent 4e77b4a548
commit c1c888a9de
13 changed files with 269 additions and 153 deletions

View File

@ -1,4 +1,4 @@
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.19 2001/09/09 23:52:12 petere Exp $ -->
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.20 2001/09/21 20:31:41 tgl Exp $ -->
<chapter id="client-authentication">
<title>Client Authentication</title>
@ -219,7 +219,13 @@ hostssl <replaceable>database</replaceable> <replaceable>IP-address</replaceable
<listitem>
<para>
Like the <literal>md5</literal> method but uses older crypt
authentication for pre-7.2 clients.
authentication for pre-7.2 clients. <literal>md5</literal>
is preferred, unless you need to support old clients that
do not have <literal>md5</literal>. The <literal>crypt</>
method is not compatible with encrypting passwords in
<filename>pg_shadow</>, and it has been observed to fail
when client and server machines have different implementations
of the crypt() library routine.
</para>
</listitem>
</varlistentry>
@ -284,7 +290,7 @@ hostssl <replaceable>database</replaceable> <replaceable>IP-address</replaceable
<term><literal>pam</></term>
<listitem>
<para>
This authentication type operates similar to
This authentication type operates similarly to
<firstterm>password</firstterm>, with the main difference that
it will use PAM (Pluggable Authentication Modules) as the
authentication mechanism. The <replaceable>authentication
@ -448,9 +454,9 @@ host all 192.168.0.0 255.255.0.0 ident omicron
<para>
Alternative passwords cannot be used when using the <literal>md5</>
or <literal>crypt</> methods. The file will still be evaluated as
usual but the password field will simply be ignored and the
<literal>pg_shadow</> password will be used.
or <literal>crypt</> methods. The file will be read as
usual, but the password field will simply be ignored and the
<literal>pg_shadow</> password will always be used.
</para>
<para>

View File

@ -1,4 +1,4 @@
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.20 2001/09/13 15:55:23 petere Exp $ -->
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.21 2001/09/21 20:31:42 tgl Exp $ -->
<chapter id="protocol">
<title>Frontend/Backend Protocol</title>
@ -142,10 +142,11 @@
</VarListEntry>
<VarListEntry>
<Term>AuthenticationUnencryptedPassword</Term>
<Term>AuthenticationCleartextPassword</Term>
<ListItem>
<Para>
The frontend must then send an UnencryptedPasswordPacket. If
The frontend must then send a PasswordPacket containing the
password in clear-text form. If
this is the correct password, the server responds with an
AuthenticationOk, otherwise it responds with an ErrorResponse.
</Para>
@ -153,16 +154,47 @@
</VarListEntry>
<VarListEntry>
<Term>AuthenticationEncryptedPassword</Term>
<Term>AuthenticationCryptPassword</Term>
<ListItem>
<Para>
The frontend must then send an EncryptedPasswordPacket. If
The frontend must then send a PasswordPacket containing the
password encrypted via crypt(3), using the 2-character salt
specified in the AuthenticationCryptPassword packet. If
this is the correct password, the server responds with an
AuthenticationOk, otherwise it responds with an ErrorResponse.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>AuthenticationMD5Password</Term>
<ListItem>
<Para>
The frontend must then send a PasswordPacket containing the
password encrypted via MD5, using the 4-character salt
specified in the AuthenticationMD5Password packet. If
this is the correct password, the server responds with an
AuthenticationOk, otherwise it responds with an ErrorResponse.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>AuthenticationSCMCredential</Term>
<ListItem>
<Para>
This method is only possible for local Unix-domain connections
on platforms that support SCM credential messages. The frontend
must issue an SCM credential message and then send a single data
byte. (The contents of the data byte are uninteresting; it's
only used to ensure that the server waits long enough to receive
the credential message.) If the credential is acceptable,
the server responds with an
AuthenticationOk, otherwise it responds with an ErrorResponse.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
@ -857,7 +889,7 @@ AuthenticationKerberosV5 (B)
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationUnencryptedPassword (B)
AuthenticationCleartextPassword (B)
</Term>
<ListItem>
<Para>
@ -879,19 +911,18 @@ AuthenticationUnencryptedPassword (B)
</Term>
<ListItem>
<Para>
Specifies that an unencrypted password is required.
Specifies that a cleartext password is required.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationEncryptedPassword (B)
AuthenticationCryptPassword (B)
</Term>
<ListItem>
<Para>
@ -913,7 +944,7 @@ AuthenticationEncryptedPassword (B)
</Term>
<ListItem>
<Para>
Specifies that an encrypted password is required.
Specifies that a crypt()-encrypted password is required.
</Para>
</ListItem>
</VarListEntry>
@ -932,6 +963,85 @@ AuthenticationEncryptedPassword (B)
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationMD5Password (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('R')
</Term>
<ListItem>
<Para>
Identifies the message as an authentication request.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32(5)
</Term>
<ListItem>
<Para>
Specifies that an MD5-encrypted password is required.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte4
</Term>
<ListItem>
<Para>
The salt to use when encrypting the password.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationSCMCredential (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('R')
</Term>
<ListItem>
<Para>
Identifies the message as an authentication request.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32(6)
</Term>
<ListItem>
<Para>
Specifies that an SCM credentials message is required.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
BackendKeyData (B)
@ -1271,40 +1381,7 @@ EmptyQueryResponse (B)
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
EncryptedPasswordPacket (F)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The size of the packet in bytes.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The encrypted (using MD5 or crypt()) password.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
ErrorResponse (B)
@ -1602,6 +1679,40 @@ NotificationResponse (B)
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
PasswordPacket (F)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The size of the packet in bytes.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The password (encrypted, if requested).
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Query (F)
@ -1852,39 +1963,7 @@ Terminate (F)
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
UnencryptedPasswordPacket (F)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The size of the packet in bytes.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The unencrypted password.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</sect1>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.16 2001/09/03 12:57:49 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.17 2001/09/21 20:31:45 tgl Exp $
Postgres documentation
-->
@ -53,13 +53,23 @@ where <replaceable class="PARAMETER">option</replaceable> can be:
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">[ encrypted | unencrypted ] password</replaceable></term>
<term><replaceable class="PARAMETER">password</replaceable></term>
<listitem>
<para>
The new password to be used for this account.
<literal>Encrypted</literal>/ <literal>unencrypted</literal>
controls whether the password is stored encrypted in the
database.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ENCRYPTED</term>
<term>UNENCRYPTED</term>
<listitem>
<para>
These keywords control whether the
password is stored encrypted in <literal>pg_shadow</>. (See
<xref linkend="SQL-CREATEUSER" endterm="SQL-CREATEUSER-title">
for more information about this choice.)
</para>
</listitem>
</varlistentry>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_user.sgml,v 1.20 2001/09/14 08:24:29 ishii Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_user.sgml,v 1.21 2001/09/21 20:31:45 tgl Exp $
Postgres documentation
-->
@ -66,28 +66,45 @@ where <replaceable class="PARAMETER">option</replaceable> can be:
</para>
<para>
If this is not specified, the highest assigned user id plus one
will be used as default.
(with a minimum of 100) will be used as default.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">[ encrypted | unencrypted ] password</replaceable></term>
<term><replaceable class="parameter">password</replaceable></term>
<listitem>
<para>
Sets the user's password. If you do not plan to use password
authentication you can omit this option, otherwise the user
authentication you can omit this option, but the user
won't be able to connect to a password-authenticated server.
</para>
<para>
<literal>ENCRYPTED/UNENCRYPTED</literal> controls whether the
password is stored encrypted in the database. Older clients may
have trouble communicating using encrypted password storage.
The password can be set or changed later, using
<xref linkend="SQL-ALTERUSER" endterm="SQL-ALTERUSER-title">.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ENCRYPTED</term>
<term>UNENCRYPTED</term>
<listitem>
<para>
These keywords control whether the
password is stored encrypted in <literal>pg_shadow</>. (If neither
is specified, the default behavior is determined by the
<varname>PASSWORD_ENCRYPTION</varname> server parameter.)
If the presented string is already in MD5-encrypted format,
then it is stored as-is, regardless of whether
ENCRYPTED or UNENCRYPTED
is specified. This allows reloading of encrypted passwords
during dump/restore.
</para>
<para>
See the chapter on client authentication in the
<citetitle>Administrator's Guide</citetitle> for details on
how to set up authentication mechanisms.
how to set up authentication mechanisms. Note that older clients
may lack support for the MD5 authentication mechanism that's needed
to work with passwords that are stored encrypted.
</para>
</listitem>
</varlistentry>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.83 2001/09/21 17:06:12 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.84 2001/09/21 20:31:43 tgl Exp $
-->
<Chapter Id="runtime">
@ -1260,7 +1260,8 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
<para>
When a password is specified in <command>CREATE USER</> or
<command>ALTER USER</> without writing either ENCRYPTED or
UNENCRYPTED, this flag determines whether the password is encrypted.
UNENCRYPTED, this flag determines whether the password is to be
encrypted.
The default is off (do not encrypt the password), but this choice
may change in a future release.
</para>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.66 2001/09/07 19:52:53 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.67 2001/09/21 20:31:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -594,15 +594,11 @@ sendAuthRequest(Port *port, AuthRequest areq)
/* Add the salt for encrypted passwords. */
if (areq == AUTH_REQ_MD5)
{
pq_sendint(&buf, port->md5Salt[0], 1);
pq_sendint(&buf, port->md5Salt[1], 1);
pq_sendint(&buf, port->md5Salt[2], 1);
pq_sendint(&buf, port->md5Salt[3], 1);
pq_sendbytes(&buf, port->md5Salt, 4);
}
if (areq == AUTH_REQ_CRYPT)
else if (areq == AUTH_REQ_CRYPT)
{
pq_sendint(&buf, port->cryptSalt[0], 1);
pq_sendint(&buf, port->cryptSalt[1], 1);
pq_sendbytes(&buf, port->cryptSalt, 2);
}
pq_endmessage(&buf);

View File

@ -9,7 +9,7 @@
* Dec 17, 1997 - Todd A. Brandys
* Orignal Version Completed.
*
* $Id: crypt.c,v 1.37 2001/08/17 15:40:07 momjian Exp $
* $Id: crypt.c,v 1.38 2001/09/21 20:31:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -282,7 +282,7 @@ md5_crypt_verify(const Port *port, const char *user, const char *pgpass)
{
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
"Password is stored MD5 encrypted. "
"Only pg_hba.conf's MD5 protocol can be used for this user.\n");
"'password' and 'crypt' auth methods cannot be used.\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
@ -339,7 +339,7 @@ md5_crypt_verify(const Port *port, const char *user, const char *pgpass)
break;
}
if (!strcmp(pgpass, crypt_pwd))
if (strcmp(pgpass, crypt_pwd) == 0)
{
/*
* check here to be sure we are not past valuntil

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.71 2001/09/07 19:59:04 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.72 2001/09/21 20:31:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -208,8 +208,8 @@ free_lines(List **lines)
* *error_p. line points to the next token of the line.
*/
static void
parse_hba_auth(List *line, ProtocolVersion proto, UserAuth *userauth_p,
char *auth_arg, bool *error_p)
parse_hba_auth(List *line, UserAuth *userauth_p, char *auth_arg,
bool *error_p)
{
char *token;
@ -295,8 +295,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
line = lnext(line);
if (!line)
goto hba_syntax;
parse_hba_auth(line, port->proto, &port->auth_method,
port->auth_arg, error_p);
parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p);
if (*error_p)
goto hba_syntax;
@ -365,8 +364,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
line = lnext(line);
if (!line)
goto hba_syntax;
parse_hba_auth(line, port->proto, &port->auth_method,
port->auth_arg, error_p);
parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p);
if (*error_p)
goto hba_syntax;

View File

@ -9,27 +9,20 @@
* generating hashed passwords from limited input.
*
* Sverre H. Huseby <sverrehu@online.no>
*
* $Header: /cvsroot/pgsql/src/backend/libpq/md5.c,v 1.6 2001/09/21 20:31:47 tgl Exp $
*/
#include "postgres.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "postgres.h"
#include "libpq/crypt.h"
/*
* PRIVATE FUNCTIONS
*/
#ifdef FRONTEND
#undef palloc
#define palloc malloc
#undef pfree
#define pfree free
#endif
/*
* The returned array is allocated using malloc. the caller should free it

View File

@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.242 2001/09/21 17:06:12 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.243 2001/09/21 20:31:48 tgl Exp $
*
* NOTES
*
@ -1235,6 +1235,14 @@ ConnCreate(int serverFd)
}
else
{
/*
* Precompute password salt values to use for this connection.
* It's slightly annoying to do this long in advance of knowing
* whether we'll need 'em or not, but we must do the random()
* calls before we fork, not after. Else the postmaster's random
* sequence won't get advanced, and all backends would end up
* using the same salt...
*/
RandomSalt(port->cryptSalt, port->md5Salt);
port->pktInfo.state = Idle;
}
@ -2145,16 +2153,16 @@ schedule_checkpoint(SIGNAL_ARGS)
/*
* CharRemap
* CharRemap: given an int in range 0..61, produce textual encoding of it
* per crypt(3) conventions.
*/
static char
CharRemap(long int ch)
CharRemap(long ch)
{
if (ch < 0)
ch = -ch;
ch = ch % 62;
if (ch < 26)
return 'A' + ch;
@ -2176,13 +2184,22 @@ RandomSalt(char *cryptSalt, char *md5Salt)
cryptSalt[0] = CharRemap(rand % 62);
cryptSalt[1] = CharRemap(rand / 62);
/* Grab top 16-bits of two random runs so as not to send full
random value over the network. The high-order bits are more random. */
md5Salt[0] = rand & 0xff000000;
md5Salt[1] = rand & 0x00ff0000;
/*
* It's okay to reuse the first random value for one of the MD5 salt bytes,
* since only one of the two salts will be sent to the client. After that
* we need to compute more random bits.
*
* We use % 255, sacrificing one possible byte value, so as to ensure
* that all bits of the random() value participate in the result. While
* at it, add one to avoid generating any null bytes.
*/
md5Salt[0] = (rand % 255) + 1;
rand = PostmasterRandom();
md5Salt[2] = rand & 0xff000000;
md5Salt[3] = rand & 0x00ff0000;
md5Salt[1] = (rand % 255) + 1;
rand = PostmasterRandom();
md5Salt[2] = (rand % 255) + 1;
rand = PostmasterRandom();
md5Salt[3] = (rand % 255) + 1;
}
/*
@ -2200,7 +2217,7 @@ PostmasterRandom(void)
initialized = true;
}
return random() ^ random_seed;
return random();
}
/*

View File

@ -4,7 +4,7 @@
* Interface to hba.c
*
*
* $Id: hba.h,v 1.26 2001/09/06 03:23:38 momjian Exp $
* $Id: hba.h,v 1.27 2001/09/21 20:31:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -31,9 +31,6 @@
typedef enum UserAuth
{
#ifdef USE_PAM
uaPAM,
#endif /* USE_PAM */
uaReject,
uaKrb4,
uaKrb5,
@ -41,7 +38,10 @@ typedef enum UserAuth
uaIdent,
uaPassword,
uaCrypt,
uaMD5
uaMD5,
#ifdef USE_PAM
uaPAM
#endif /* USE_PAM */
} UserAuth;
typedef struct Port hbaPort;

View File

@ -4,7 +4,7 @@
#
# Copyright (c) 1994, Regents of the University of California
#
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.57 2001/09/06 04:57:30 ishii Exp $
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.58 2001/09/21 20:31:48 tgl Exp $
#
#-------------------------------------------------------------------------
@ -84,5 +84,5 @@ uninstall: uninstall-lib
rm -f $(DESTDIR)$(includedir)/libpq-fe.h $(DESTDIR)$(includedir_internal)/libpq-int.h $(includedir_internal)/pqexpbuffer.h
clean distclean maintainer-clean: clean-lib
rm -f $(OBJS) dllist.c md5.c md5.h wchar.c encnames.c
rm -f $(OBJS) dllist.c md5.c wchar.c encnames.c
rm -f $(OBJS) inet_aton.c snprintf.c strerror.c

View File

@ -10,7 +10,7 @@
* exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.59 2001/09/07 19:52:54 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.60 2001/09/21 20:31:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,12 +30,6 @@
#include "postgres_fe.h"
/* XXX is there a reason these appear before the system defines? */
#include "libpq-fe.h"
#include "libpq-int.h"
#include "fe-auth.h"
#include "libpq/crypt.h"
#ifdef WIN32
#include "win32.h"
#else
@ -59,6 +53,11 @@
#include <crypt.h>
#endif
#include "libpq-fe.h"
#include "libpq-int.h"
#include "fe-auth.h"
#include "libpq/crypt.h"
/*
* common definitions for generic fe/be routines