diff --git a/doc/src/sgml/libpq++.sgml b/doc/src/sgml/libpq++.sgml index cd6d2a6a91..eaf9113cf8 100644 --- a/doc/src/sgml/libpq++.sgml +++ b/doc/src/sgml/libpq++.sgml @@ -1,5 +1,5 @@ @@ -117,11 +117,14 @@ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/libpq++.sgml,v 1.41 2002/03/22 19:20: - PGPASSWORD - sets the password used if the backend demands password - authentication. This is not recommended because the password can - be read by others using the ps command with special options - on some platforms. + PGPASSWORD + sets the password used if the backend demands password + authentication. This is deprecated; use PGPASSWORDFILE instead. + + + PGPASSWORDFILE + sets the password file used if the backend demands password + authentication. Refer to the libpq documentation for more details. diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 1fb6519806..f1cb03f887 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,5 +1,5 @@ @@ -2038,9 +2038,25 @@ sets the user name used to connect to the database and for authentication. PGPASSWORD sets the password used if the backend demands password -authentication. This is not recommended because the password can -be read by others using the ps command with special options -on some platforms. +authentication. This functionality is deprecated for security +reasons; consider migrating to PGPASSWORDFILE. + + + + + + PGPASSWORDFILE + +PGPASSWORDFILE +sets the password file used if the backend demands password authentication. +This file should have the format + +hostname:port:database:username:password + +Any of these may be a literal name, or a * that matches +anything. The first match will be the one used, so put more specific entries first. +Entries with : or \ should be escaped +with \. diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 19805db981..40474657c2 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 * 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 920612ebb4..14d010dba8 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.