OSDN Git Service

I'm giving a try at some TODO items. Currently it's the turn of the
authorBruce Momjian <bruce@momjian.us>
Thu, 15 Aug 2002 02:56:19 +0000 (02:56 +0000)
committerBruce Momjian <bruce@momjian.us>
Thu, 15 Aug 2002 02:56:19 +0000 (02:56 +0000)
PGPASSWORDFILE environment variable.  I have modified libpq to make use
of this variable.  I present the first cut here.

Currently the format for the file should be

host:port:database:user:password

Alvaro Herrera

doc/src/sgml/libpq++.sgml
doc/src/sgml/libpq.sgml
src/interfaces/libpq/fe-connect.c
src/interfaces/perl5/Pg.pm

index cd6d2a6..eaf9113 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/Attic/libpq++.sgml,v 1.41 2002/03/22 19:20:12 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/Attic/libpq++.sgml,v 1.42 2002/08/15 02:56:19 momjian Exp $
 -->
 
  <chapter id="libpqplusplus">
@@ -117,11 +117,14 @@ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/libpq++.sgml,v 1.41 2002/03/22 19:20:
       </listitem>
       <listitem>
        <para>
-       <envar>PGPASSWORD</envar>
-       sets the password used if the backend demands password
-       authentication. This is not recommended because the password can
-       be read by others using the <command>ps</command> command with special options
-       on some platforms.
+        <envar>PGPASSWORD</envar>
+        sets the password used if the backend demands password
+        authentication.  This is deprecated; use <envar>PGPASSWORDFILE</envar> instead.
+      <listitem>
+       <para>
+       <envar>PGPASSWORDFILE</envar>
+       sets the password file used if the backend demands password
+       authentication. Refer to the libpq documentation for more details.
        </para>
       </listitem>
       <listitem>
index 1fb6519..f1cb03f 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.90 2002/03/22 19:20:13 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.91 2002/08/15 02:56:19 momjian Exp $
 -->
 
  <chapter id="libpq">
@@ -2038,9 +2038,25 @@ sets the user name used to connect to the database and for authentication.
 </indexterm>
 <envar>PGPASSWORD</envar>
 sets the password used if the backend demands password
-authentication. This is not recommended because the password can
-be read by others using the <command>ps</command> command with special options
-on some platforms.
+authentication.  This functionality is deprecated for security
+reasons; consider migrating to <envar>PGPASSWORDFILE</envar>.
+</para>
+</listitem>
+<listitem>
+<para>
+<indexterm>
+ <primary><envar>PGPASSWORDFILE</envar></primary>
+</indexterm>
+<envar>PGPASSWORDFILE</envar>
+sets the password file used if the backend demands password authentication.
+This file should have the format
+<screen>
+<replaceable>hostname</replaceable>:<replaceable>port</replaceable>:<replaceable>database</replaceable>:<replaceable>username</replaceable>:<replaceable>password</replaceable>
+</screen>
+Any of these may be a literal name, or a <literal>*</literal> that matches
+anything.  The first match will be the one used, so put more specific entries first.
+Entries with <literal>:</literal> or <literal>\</literal> should be escaped
+with <literal>\</literal>.
 </para>
 </listitem>
 <listitem>
index 19805db..4047465 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.190 2002/07/20 05:43:31 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.191 2002/08/15 02:56:19 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -182,6 +182,9 @@ static char *conninfo_getval(PQconninfoOption *connOptions,
 static void defaultNoticeProcessor(void *arg, const char *message);
 static int parseServiceInfo(PQconninfoOption *options,
                                 PQExpBuffer errorMessage);
+char *pwdfMatchesString(char *buf, char *token);
+char *PasswordFromFile(char *hostname, char *port, char *dbname,
+               char *username, char *pwdfile);
 
 /*
  *             Connecting to a Database
@@ -388,6 +391,10 @@ PQconndefaults(void)
  *
  *       PGPASSWORD   The user's password.
  *
+ *       PGPASSWORDFILE
+ *                                A file that contains host:port:database:user:password
+ *                                for authentication
+ *
  *       PGDATABASE   name of database to which to connect if <pgdatabase>
  *                                argument is NULL or a null string
  *
@@ -476,13 +483,6 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
                                                  libpq_gettext("could not determine the PostgreSQL user name to use\n"));
        }
 
-       if (pwd)
-               conn->pgpass = strdup(pwd);
-       else if ((tmp = getenv("PGPASSWORD")) != NULL)
-               conn->pgpass = strdup(tmp);
-       else
-               conn->pgpass = strdup(DefaultPassword);
-
        if (dbName == NULL)
        {
                if ((tmp = getenv("PGDATABASE")) != NULL)
@@ -493,6 +493,17 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
        else
                conn->dbName = strdup(dbName);
 
+       /* getPasswordFromFile mallocs its result, so we don't need strdup here */
+       if (pwd)
+               conn->pgpass = strdup(pwd);
+       else if ((tmp = getenv("PGPASSWORD")) != NULL)
+               conn->pgpass = strdup(tmp);
+       else if ((tmp = PasswordFromFile(conn->pghost, conn->pgport,
+                                       conn->dbName, conn->pguser,
+                                       getenv("PGPASSWORDFILE"))) != NULL)
+               conn->pgpass = tmp;
+       else
+               conn->pgpass = strdup(DefaultPassword);
 
 #ifdef USE_SSL
        if ((tmp = getenv("PGREQUIRESSL")) != NULL)
@@ -2810,3 +2821,92 @@ defaultNoticeProcessor(void *arg, const char *message)
        /* Note: we expect the supplied string to end with a newline already. */
        fprintf(stderr, "%s", message);
 }
+
+/* returns a pointer to the next token or NULL if the current
+ * token doesn't match */
+char *
+pwdfMatchesString(char *buf, char *token)
+{
+       char   *tbuf,
+                  *ttok;
+       bool    bslash = false;
+       if (buf == NULL || token == NULL)
+               return NULL;
+       tbuf = buf;
+       ttok = token;
+       if (*tbuf == '*')
+               return tbuf + 2;
+       while (*tbuf != 0)
+       {
+               if (*tbuf == '\\' && !bslash)
+               {
+                       tbuf++;
+                       bslash = true;
+               }
+               if (*tbuf == ':' && *ttok == 0 && !bslash)
+                       return tbuf+1;
+               bslash = false;
+               if (*ttok == 0)
+                       return NULL;
+               if (*tbuf == *ttok)
+               {
+                       tbuf++;
+                       ttok++;
+               }
+               else
+                       return NULL;
+       }
+       return NULL;
+}
+
+/* get a password from the password file. */
+char *
+PasswordFromFile(char *hostname, char *port, char *dbname,
+               char *username, char *pwdfile)
+{
+       FILE   *fp;
+#define LINELEN NAMEDATALEN*5
+       char    buf[LINELEN];
+
+       if (pwdfile == NULL || strcmp(pwdfile, "") == 0)
+               return NULL;
+
+       if (dbname == NULL || strcmp(dbname, "") == 0)
+               return NULL;
+
+       if (username == NULL || strcmp(username, "") == 0)
+               return NULL;
+
+       if (hostname == NULL)
+               hostname = DefaultHost;
+
+       if (port == NULL)
+               port = DEF_PGPORT_STR;
+
+       fp = fopen(pwdfile, "r");
+       if (fp == NULL)
+               return NULL;
+
+       while (!feof(fp)) {
+               char *t = buf,
+                    *ret;
+               fgets(buf, LINELEN - 1, fp);
+               if (strlen(buf) == 0)
+                       continue;
+
+               buf[strlen(buf) - 1] = 0;
+               if ((t = pwdfMatchesString(t, hostname)) == NULL ||
+                               (t = pwdfMatchesString(t, port)) == NULL ||
+                               (t = pwdfMatchesString(t, dbname)) == NULL ||
+                               (t = pwdfMatchesString(t, username)) == NULL)
+                       continue;
+               ret=(char *)malloc(sizeof(char)*strlen(t));
+               strncpy(ret, t, strlen(t));
+               fclose(fp);
+               return ret;
+       }
+       fclose(fp);
+       return NULL;
+
+#undef LINELEN
+}
index 920612e..14d010d 100644 (file)
@@ -1,6 +1,6 @@
 #-------------------------------------------------------
 #
-# $Id: Pg.pm,v 1.10 2001/09/10 04:19:19 momjian Exp $
+# $Id: Pg.pm,v 1.11 2002/08/15 02:56:19 momjian Exp $
 #
 # Copyright (c) 1997, 1998  Edmund Mergl
 #
@@ -260,15 +260,16 @@ When opening a connection a given database name is always converted to
 lower-case, unless it is surrounded by double quotes. All unspecified 
 parameters are replaced by environment variables or by hard coded defaults: 
 
-    parameter  environment variable  hard coded default
-    --------------------------------------------------
-    host       PGHOST                localhost
-    port       PGPORT                5432
-    options    PGOPTIONS             ""
-    tty        PGTTY                 ""
-    dbname     PGDATABASE            current userid
-    user       PGUSER                current userid
-    password   PGPASSWORD            ""
+    parameter     environment variable  hard coded default
+    ------------------------------------------------------
+    host           PGHOST                localhost
+    port           PGPORT                5432
+    options        PGOPTIONS             ""
+    tty            PGTTY                 ""
+    dbname         PGDATABASE            current userid
+    user           PGUSER                current userid
+    password       PGPASSWORD            ""
+    passwordfile   PGPASSWORDFILE        ""
 
 Using appropriate methods you can access almost all fields of the 
 returned PGconn structure.