diff --git a/doc/src/sgml/libpq++.sgml b/doc/src/sgml/libpq++.sgml index cd6d2a6a9113669fc60c0e935093df0f3e15d49d..eaf9113cf86ccb4737b602122e2b09dbf2b13029 100644 --- a/doc/src/sgml/libpq++.sgml +++ b/doc/src/sgml/libpq++.sgml @@ -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> diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 1fb6519806a384cedc02db82107d9b97413c4d22..f1cb03f887155a6b3713aa1054bfd9ef0b6d0c0c 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -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> diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 19805db98136d5540e36db1fc3f80cfeadd6dc2a..40474657c26ba38708848f556ea3b7c691f84932 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -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 +} diff --git a/src/interfaces/perl5/Pg.pm b/src/interfaces/perl5/Pg.pm index 920612ebb4e09744c8fcae6e22410a20ddacc9f6..14d010dba87a8ae76baebd443c4d7f6572559562 100644 --- a/src/interfaces/perl5/Pg.pm +++ b/src/interfaces/perl5/Pg.pm @@ -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.