]> granicus.if.org Git - postgresql/commitdiff
Expand secondary password file feature, so that you can use these
authorPeter Eisentraut <peter_e@gmx.net>
Tue, 4 Jul 2000 16:32:01 +0000 (16:32 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Tue, 4 Jul 2000 16:32:01 +0000 (16:32 +0000)
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.)

doc/src/sgml/client-auth.sgml
src/backend/libpq/auth.c
src/backend/libpq/crypt.c
src/backend/libpq/password.c
src/bin/pg_passwd/pg_passwd.c
src/include/libpq/crypt.h
src/include/libpq/password.h

index b8970f27ec146b1481e86af1eeacdc3909c1c8dd..500fc6ea3fab9310d4c045c8aa341960742b9eb7 100644 (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>
index 5cd049062cb6412597a657a31899142e40ce524a..4f0dc6a31a0a8550f81fc797b06fadc28756aaac 100644 (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);
 }
index 38b8e0ed383cf1122d5454e5ce9bbba5d5127242..8b9eace73ef9a264d1ef75e05f93a5b0d2f87e3a 100644 (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,
index c7656f8b98fa078efb89f3ddbb04cefc0cfd1f57..6f47d5d4378021393985cbdeea6035c57194f4b6 100644 (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 $
  *
  */
 
 
 #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. */
index b8d1aae97ac55c61125789048aee4b88fd99bd32..50aa4011b5142b69ca072aa9f94bb7f96fa9b661 100644 (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);
index 7827b464081dd1b13c949d54ab4a5704dacebd0a..c3f58ee1639f07af38a03959e9eef1b1d0e705ba 100644 (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
index 9c7421d8935de54f0d4694a500c80782a0ca2019..c704edeb34539da2c3ffba0344448b02fbdb2ce5 100644 (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