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">
<title>Client Authentication</title>
@ -202,15 +202,15 @@ host all 192.168.2.0 255.255.255.0 ident othermap
<term>password</term>
<listitem>
<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
for the user. (These passwords are separate from any operating
sytem password.)
for the user.
</para>
<para>
An optional password file may be specified after the
<literal>password</literal> keyword to obtain the password from
that file rather than the pg_shadow system catalog.
An optional file name may be specified after the
<literal>password</literal> keyword. This file is expected to
contain a list of users that this record pertains to, and
optionally alternative passwords.
</para>
<para>
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>
Like the <literal>password</literal> method, but the password
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
wire-sniffing. Interestingly enough, the
<literal>crypt</literal> does not support secondary password
files.
wire-sniffing. The name of a file may follow the
<literal>crypt</literal> keyword that contains a list of users
that this record pertains to.
</para>
</listitem>
</varlistentry>
@ -276,24 +276,36 @@ host all 192.168.2.0 255.255.255.0 ident othermap
<sect2>
<title>Password authentication</title>
<para>
Ordinarily, the password for each database user is stored in the
pg_shadow system catalog table. Passwords can be managed with the
query language commands <command>CREATE USER</command> and
<command>ALTER USER</command>, e.g., <userinput>CREATE USER foo
WITH PASSWORD 'secret';</userinput>. By default, that is, if no
password has explicitly been set up, the stored password is
<quote>NULL</quote> and password authentication will always fail
for that user.
<productname>Postgres</> database passwords are separate from any
operating system user passwords. Ordinarily, the password for each
database user is stored in the pg_shadow system catalog table.
Passwords can be managed with the query language commands
<command>CREATE USER</command> and <command>ALTER USER</command>,
e.g., <userinput>CREATE USER foo WITH PASSWORD
'secret';</userinput>. By default, that is, if no password has
explicitly been set up, the stored password is <quote>NULL</quote>
and password authentication will always fail for that user.
</para>
<para>
Secondary password files can be used if a given set of passwords
should only apply to a particular database or set thereof.
Secondary password files have a format similar to the standard
Unix password file <filename>/etc/passwd</filename>, that is,
<synopsis>
To restrict the set of users that are allowed to connect to
certain databases, list the set of users in a separate file (one
user name per line) in the same directory that
<filename>pg_hba.conf</> is in, and mention the (base) name of the
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>
</synopsis>
</synopsis>
Any extra colon separated fields following the password are
ignored. The password is expected to be encrypted using the
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>
Secondary password files can also be used to restrict certain
users from connecting to certain databases at all. This is
currently not possible to achieve using the normal password
mechanism (because users and passwords are global across all
databases). If a user is not listed in the applicable password
file the connection will be refused.
Lines with and without passwords can be mixed in secondary
password files. Lines without password indicate use the main
password in <literal>pg_shadow</> that is managed by
<command>CREATE USER</> and <command>ALTER USER</>. Lines with
passwords will cause that password to be used. A password entry of
<quote>+</quote> also means using the pg_shadow password.
</para>
<para>
Note that using secondary password files 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.
Alternative passwords cannot be used when using the
<literal>crypt</> method. 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.
</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>
@ -361,14 +382,15 @@ integrated here. -->
The <quote>Identification Protocol</quote> is described in
<citetitle>RFC 1413</citetitle>. Virtually every Unix-like
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
connection that goes out of your port <replaceable>X</replaceable>
and connects to my port <replaceable>Y</replaceable>?</quote>.
Since both <replaceable>X</replaceable> and
<replaceable>Y</replaceable> are known,
<productname>Postgres</productname> could theoretically determine
the operating system user for any given connection this way.
Since <productname>Postgres</> knows both <replaceable>X</> and
<replaceable>Y</> when a physical connection is established, it
can interrogate the ident server on the host of the connecting
client and could theoretically determine the operating system user
for any given connection this way.
</para>
<para>

View File

@ -8,7 +8,7 @@
*
*
* 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
/* This has to be ifdef'd out because krb.h does exist. This needs
to be fixed.
*/
/*----------------------------------------------------------------
* MIT Kerberos authentication system - protocol version 4
*----------------------------------------------------------------
@ -141,9 +138,6 @@ pg_krb4_recvauth(Port *port)
#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
*----------------------------------------------------------------
@ -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
* specified. Otherwise use the password in the pg_shadow table, encrypted or
* not.
* Handle `password' and `crypt' records. If an auth argument was
* specified, use the respective file. Else use pg_shadow passwords.
*/
static int
checkPassword(Port *port, char *user, char *password)
{
if (port->auth_method == uaPassword && port->auth_arg[0] != '\0')
return verify_password(port->auth_arg, user, password);
if (port->auth_arg[0] != '\0')
return verify_password(port, user, password);
return crypt_verify(port, user, password);
}

View File

@ -9,7 +9,7 @@
* Dec 17, 1997 - Todd A. Brandys
* 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
crypt_verify(Port *port, const char *user, const char *pgpass)
crypt_verify(const Port *port, const char *user, const char *pgpass)
{
char *passwd,

View File

@ -2,7 +2,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* 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/password.h"
#include "libpq/crypt.h"
#include "miscadmin.h"
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;
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);
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);
if (!pw_file)
@ -52,23 +53,32 @@ verify_password(char *auth_arg, char *user, char *password)
*test_pw;
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;
test_user = strtok(p, ":");
test_pw = strtok(NULL, ":");
if (!test_user || !test_pw ||
test_user[0] == '\0' || test_pw[0] == '\0')
if (!test_user || test_user[0] == '\0')
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)
{
/* we're outta here one way or the other, so close 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)
{
/* it matched. */

View File

@ -105,13 +105,9 @@ try_again:
/* get user name */
p = line;
if ((q = strchr(p, ':')) == NULL)
{
fprintf(stderr, "%s: line %d: illegal format.\n",
filename, npwds + 1);
exit(1);
}
*(q++) = '\0';
if ((q = strchr(p, ':')) != NULL)
*q = '\0';
if (strlen(p) == 0)
{
fprintf(stderr, "%s: line %d: null user name.\n",
@ -131,23 +127,23 @@ try_again:
}
/* get password field */
p = 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)
if (q)
{
fprintf(stderr, "WARNING: %s: line %d: illegal password length.\n",
filename, npwds + 1);
p = q + 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 */
if (q == NULL)
@ -193,9 +189,12 @@ link_again:
/* write file */
for (i = 0; i < npwds; ++i)
{
fprintf(fp, "%s:%s%s%s\n", pwds[i].uname, pwds[i].pwd,
pwds[i].rest ? ":" : "",
pwds[i].rest ? pwds[i].rest : "");
fprintf(fp, "%s", pwds[i].uname);
if (pwds[i].pwd)
fprintf(fp, ":%s", pwds[i].pwd);
if (pwds[i].rest)
fprintf(fp, ":%s", pwds[i].rest);
fprintf(fp, "\n");
}
fclose(fp);

View File

@ -26,6 +26,6 @@ extern char *crypt_getpwdreloadfilename(void);
extern MsgType crypt_salt(const char *user);
#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

View File

@ -1,6 +1,6 @@
#ifndef 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