Expand secondary password file feature, so that you can use these

files to restrict the set of users that can connect to a database
but can still use the pg_shadow password. (You just leave off the
password field in the secondary file.)
This commit is contained in:
Peter Eisentraut 2000-07-04 16:32:01 +00:00
parent 1c2f735aa7
commit 554e56e628
7 changed files with 115 additions and 92 deletions

View File

@ -1,4 +1,4 @@
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.1 2000/06/18 21:24:51 petere Exp $ --> <!-- $Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.2 2000/07/04 16:31:51 petere Exp $ -->
<chapter id="client-authentication"> <chapter id="client-authentication">
<title>Client Authentication</title> <title>Client Authentication</title>
@ -202,15 +202,15 @@ host all 192.168.2.0 255.255.255.0 ident othermap
<term>password</term> <term>password</term>
<listitem> <listitem>
<para> <para>
The client is required to supply a password for the connection The client is required to supply a password with the connection
attempt which is required to match the password that was set up attempt which is required to match the password that was set up
for the user. (These passwords are separate from any operating for the user.
sytem password.)
</para> </para>
<para> <para>
An optional password file may be specified after the An optional file name may be specified after the
<literal>password</literal> keyword to obtain the password from <literal>password</literal> keyword. This file is expected to
that file rather than the pg_shadow system catalog. contain a list of users that this record pertains to, and
optionally alternative passwords.
</para> </para>
<para> <para>
The password is sent over the wire in clear text. For better The password is sent over the wire in clear text. For better
@ -225,11 +225,11 @@ host all 192.168.2.0 255.255.255.0 ident othermap
<para> <para>
Like the <literal>password</literal> method, but the password Like the <literal>password</literal> method, but the password
is sent over the wire encrypted using a simple is sent over the wire encrypted using a simple
challenge-response protocol. Note that this is still not challenge-response protocol. This is still not
cryptographically secure but it protects against incidental cryptographically secure but it protects against incidental
wire-sniffing. Interestingly enough, the wire-sniffing. The name of a file may follow the
<literal>crypt</literal> does not support secondary password <literal>crypt</literal> keyword that contains a list of users
files. that this record pertains to.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -276,24 +276,36 @@ host all 192.168.2.0 255.255.255.0 ident othermap
<sect2> <sect2>
<title>Password authentication</title> <title>Password authentication</title>
<para> <para>
Ordinarily, the password for each database user is stored in the <productname>Postgres</> database passwords are separate from any
pg_shadow system catalog table. Passwords can be managed with the operating system user passwords. Ordinarily, the password for each
query language commands <command>CREATE USER</command> and database user is stored in the pg_shadow system catalog table.
<command>ALTER USER</command>, e.g., <userinput>CREATE USER foo Passwords can be managed with the query language commands
WITH PASSWORD 'secret';</userinput>. By default, that is, if no <command>CREATE USER</command> and <command>ALTER USER</command>,
password has explicitly been set up, the stored password is e.g., <userinput>CREATE USER foo WITH PASSWORD
<quote>NULL</quote> and password authentication will always fail 'secret';</userinput>. By default, that is, if no password has
for that user. explicitly been set up, the stored password is <quote>NULL</quote>
and password authentication will always fail for that user.
</para> </para>
<para> <para>
Secondary password files can be used if a given set of passwords To restrict the set of users that are allowed to connect to
should only apply to a particular database or set thereof. certain databases, list the set of users in a separate file (one
Secondary password files have a format similar to the standard user name per line) in the same directory that
Unix password file <filename>/etc/passwd</filename>, that is, <filename>pg_hba.conf</> is in, and mention the (base) name of the
<synopsis> file after the <literal>password</> or <literal>crypt</> keyword,
respectively, in <filename>pg_hba.conf</>. If you do not use this
feature, then any user that is known to the database system can
connect (as long as he passes password authentication, of course).
</para>
<para>
These files can also be used a apply a different set of passwords
to a particular database or set thereof. In that case, the files
have a format similar to the standard Unix password file
<filename>/etc/passwd</filename>, that is,
<synopsis>
<replaceable>username</replaceable>:<replaceable>password</replaceable> <replaceable>username</replaceable>:<replaceable>password</replaceable>
</synopsis> </synopsis>
Any extra colon separated fields following the password are Any extra colon separated fields following the password are
ignored. The password is expected to be encrypted using the ignored. The password is expected to be encrypted using the
system's <function>crypt()</function> function. The utility system's <function>crypt()</function> function. The utility
@ -303,20 +315,29 @@ host all 192.168.2.0 255.255.255.0 ident othermap
</para> </para>
<para> <para>
Secondary password files can also be used to restrict certain Lines with and without passwords can be mixed in secondary
users from connecting to certain databases at all. This is password files. Lines without password indicate use the main
currently not possible to achieve using the normal password password in <literal>pg_shadow</> that is managed by
mechanism (because users and passwords are global across all <command>CREATE USER</> and <command>ALTER USER</>. Lines with
databases). If a user is not listed in the applicable password passwords will cause that password to be used. A password entry of
file the connection will be refused. <quote>+</quote> also means using the pg_shadow password.
</para> </para>
<para> <para>
Note that using secondary password files means that one can no Alternative passwords cannot be used when using the
longer use <command>ALTER USER</command> to change one's password. <literal>crypt</> method. The file will still be evaluated as
It will still appear to work but the password one is actually usual but the password field will simply be ignored and the
changing is not the password that the system will end up using. <literal>pg_shadow</> password will be used.
</para> </para>
<para>
Note that using alternative passwords like this means that one can
no longer use <command>ALTER USER</command> to change one's
password. It will still appear to work but the password one is
actually changing is not the password that the system will end up
using.
</para>
</sect2> </sect2>
<sect2> <sect2>
@ -361,14 +382,15 @@ integrated here. -->
The <quote>Identification Protocol</quote> is described in The <quote>Identification Protocol</quote> is described in
<citetitle>RFC 1413</citetitle>. Virtually every Unix-like <citetitle>RFC 1413</citetitle>. Virtually every Unix-like
operating systems ships with an ident server that listens on TCP operating systems ships with an ident server that listens on TCP
port 113 by default. The basic functionality of the ident server port 113 by default. The basic functionality of an ident server
is to answer questions like <quote>What user initiated the is to answer questions like <quote>What user initiated the
connection that goes out of your port <replaceable>X</replaceable> connection that goes out of your port <replaceable>X</replaceable>
and connects to my port <replaceable>Y</replaceable>?</quote>. and connects to my port <replaceable>Y</replaceable>?</quote>.
Since both <replaceable>X</replaceable> and Since <productname>Postgres</> knows both <replaceable>X</> and
<replaceable>Y</replaceable> are known, <replaceable>Y</> when a physical connection is established, it
<productname>Postgres</productname> could theoretically determine can interrogate the ident server on the host of the connecting
the operating system user for any given connection this way. client and could theoretically determine the operating system user
for any given connection this way.
</para> </para>
<para> <para>

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.47 2000/05/27 04:13:05 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.48 2000/07/04 16:31:53 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -52,9 +52,6 @@ static void auth_failed(Port *port);
#ifdef KRB4 #ifdef KRB4
/* This has to be ifdef'd out because krb.h does exist. This needs
to be fixed.
*/
/*---------------------------------------------------------------- /*----------------------------------------------------------------
* MIT Kerberos authentication system - protocol version 4 * MIT Kerberos authentication system - protocol version 4
*---------------------------------------------------------------- *----------------------------------------------------------------
@ -141,9 +138,6 @@ pg_krb4_recvauth(Port *port)
#ifdef KRB5 #ifdef KRB5
/* This needs to be ifdef'd out because krb5.h doesn't exist. This needs
to be fixed.
*/
/*---------------------------------------------------------------- /*----------------------------------------------------------------
* MIT Kerberos authentication system - protocol version 5 * MIT Kerberos authentication system - protocol version 5
*---------------------------------------------------------------- *----------------------------------------------------------------
@ -692,16 +686,14 @@ readPasswordPacket(void *arg, PacketLen len, void *pkt)
/* /*
* Use the local flat password file if clear passwords are used and the file is * Handle `password' and `crypt' records. If an auth argument was
* specified. Otherwise use the password in the pg_shadow table, encrypted or * specified, use the respective file. Else use pg_shadow passwords.
* not.
*/ */
static int static int
checkPassword(Port *port, char *user, char *password) checkPassword(Port *port, char *user, char *password)
{ {
if (port->auth_method == uaPassword && port->auth_arg[0] != '\0') if (port->auth_arg[0] != '\0')
return verify_password(port->auth_arg, user, password); return verify_password(port, user, password);
return crypt_verify(port, user, password); return crypt_verify(port, user, password);
} }

View File

@ -9,7 +9,7 @@
* Dec 17, 1997 - Todd A. Brandys * Dec 17, 1997 - Todd A. Brandys
* Orignal Version Completed. * Orignal Version Completed.
* *
* $Id: crypt.c,v 1.26 2000/07/03 20:48:30 petere Exp $ * $Id: crypt.c,v 1.27 2000/07/04 16:31:53 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -249,7 +249,7 @@ crypt_getloginfo(const char *user, char **passwd, char **valuntil)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
int int
crypt_verify(Port *port, const char *user, const char *pgpass) crypt_verify(const Port *port, const char *user, const char *pgpass)
{ {
char *passwd, char *passwd,

View File

@ -2,7 +2,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: password.c,v 1.29 2000/06/02 15:57:21 momjian Exp $ * $Id: password.c,v 1.30 2000/07/04 16:31:53 petere Exp $
* *
*/ */
@ -15,18 +15,19 @@
#include "libpq/libpq.h" #include "libpq/libpq.h"
#include "libpq/password.h" #include "libpq/password.h"
#include "libpq/crypt.h"
#include "miscadmin.h" #include "miscadmin.h"
int int
verify_password(char *auth_arg, char *user, char *password) verify_password(const Port *port, const char *user, const char *password)
{ {
char *pw_file_fullname; char *pw_file_fullname;
FILE *pw_file; FILE *pw_file;
pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(auth_arg) + 2); pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(port->auth_arg) + 2);
strcpy(pw_file_fullname, DataDir); strcpy(pw_file_fullname, DataDir);
strcat(pw_file_fullname, "/"); strcat(pw_file_fullname, "/");
strcat(pw_file_fullname, auth_arg); strcat(pw_file_fullname, port->auth_arg);
pw_file = AllocateFile(pw_file_fullname, PG_BINARY_R); pw_file = AllocateFile(pw_file_fullname, PG_BINARY_R);
if (!pw_file) if (!pw_file)
@ -52,23 +53,32 @@ verify_password(char *auth_arg, char *user, char *password)
*test_pw; *test_pw;
fgets(pw_file_line, sizeof(pw_file_line), pw_file); fgets(pw_file_line, sizeof(pw_file_line), pw_file);
/* kill the newline */
if (pw_file_line[strlen(pw_file_line) - 1] == '\n')
pw_file_line[strlen(pw_file_line) - 1] = '\0';
p = pw_file_line; p = pw_file_line;
test_user = strtok(p, ":"); test_user = strtok(p, ":");
test_pw = strtok(NULL, ":"); test_pw = strtok(NULL, ":");
if (!test_user || !test_pw || if (!test_user || test_user[0] == '\0')
test_user[0] == '\0' || test_pw[0] == '\0')
continue; continue;
/* kill the newline */
if (test_pw[strlen(test_pw) - 1] == '\n')
test_pw[strlen(test_pw) - 1] = '\0';
if (strcmp(user, test_user) == 0) if (strcmp(user, test_user) == 0)
{ {
/* we're outta here one way or the other, so close file */ /* we're outta here one way or the other, so close file */
FreeFile(pw_file); FreeFile(pw_file);
/*
* If the password is empty of "+" then we use the regular
* pg_shadow passwords. If we use crypt then we have to
* use pg_shadow passwords no matter what.
*/
if (port->auth_method == uaCrypt
|| test_pw == NULL || test_pw[0] == '\0'
|| strcmp(test_pw, "+")==0)
return crypt_verify(port, user, password);
if (strcmp(crypt(password, test_pw), test_pw) == 0) if (strcmp(crypt(password, test_pw), test_pw) == 0)
{ {
/* it matched. */ /* it matched. */

View File

@ -105,13 +105,9 @@ try_again:
/* get user name */ /* get user name */
p = line; p = line;
if ((q = strchr(p, ':')) == NULL) if ((q = strchr(p, ':')) != NULL)
{ *q = '\0';
fprintf(stderr, "%s: line %d: illegal format.\n",
filename, npwds + 1);
exit(1);
}
*(q++) = '\0';
if (strlen(p) == 0) if (strlen(p) == 0)
{ {
fprintf(stderr, "%s: line %d: null user name.\n", fprintf(stderr, "%s: line %d: null user name.\n",
@ -131,23 +127,23 @@ try_again:
} }
/* get password field */ /* get password field */
p = q; if (q)
q = strchr(p, ':');
/*
* --- don't care ----- if ((q = strchr(p, ':')) == NULL) {
* fprintf(stderr, "%s: line %d: illegal format.\n", filename,
* npwds + 1); exit(1); }
*/
if (q != NULL)
*(q++) = '\0';
if (strlen(p) != 13)
{ {
fprintf(stderr, "WARNING: %s: line %d: illegal password length.\n", p = q + 1;
filename, npwds + 1); q = strchr(p, ':');
if (q != NULL)
*(q++) = '\0';
if (strlen(p) != 13 && strcmp(p, "+")!=0)
{
fprintf(stderr, "WARNING: %s: line %d: invalid password length.\n",
filename, npwds + 1);
}
pwds[npwds].pwd = strdup(p);
} }
pwds[npwds].pwd = strdup(p); else
pwds[npwds].pwd = NULL;
/* rest of the line is treated as is */ /* rest of the line is treated as is */
if (q == NULL) if (q == NULL)
@ -193,9 +189,12 @@ link_again:
/* write file */ /* write file */
for (i = 0; i < npwds; ++i) for (i = 0; i < npwds; ++i)
{ {
fprintf(fp, "%s:%s%s%s\n", pwds[i].uname, pwds[i].pwd, fprintf(fp, "%s", pwds[i].uname);
pwds[i].rest ? ":" : "", if (pwds[i].pwd)
pwds[i].rest ? pwds[i].rest : ""); fprintf(fp, ":%s", pwds[i].pwd);
if (pwds[i].rest)
fprintf(fp, ":%s", pwds[i].rest);
fprintf(fp, "\n");
} }
fclose(fp); fclose(fp);

View File

@ -26,6 +26,6 @@ extern char *crypt_getpwdreloadfilename(void);
extern MsgType crypt_salt(const char *user); extern MsgType crypt_salt(const char *user);
#endif #endif
extern int crypt_verify(Port *port, const char *user, const char *pgpass); extern int crypt_verify(const Port *port, const char *user, const char *pgpass);
#endif #endif

View File

@ -1,6 +1,6 @@
#ifndef PASSWORD_H #ifndef PASSWORD_H
#define PASSWORD_H #define PASSWORD_H
int verify_password(char *auth_arg, char *user, char *password); int verify_password(const Port *port, const char *user, const char *password);
#endif #endif