Index: doc/src/sgml/libpq.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v retrieving revision 1.247 diff -c -r1.247 libpq.sgml *** doc/src/sgml/libpq.sgml 28 Nov 2007 15:42:31 -0000 1.247 --- doc/src/sgml/libpq.sgml 8 Dec 2007 23:13:35 -0000 *************** *** 1146,1156 **** PQconnectionUsedPasswordPQconnectionUsedPassword Returns true (1) if the connection authentication method ! required a password to be supplied. Returns false (0) if not. int PQconnectionUsedPassword(const PGconn *conn); --- 1146,1177 ---- + PQconnectionNeedsPasswordPQconnectionNeedsPassword + + + Returns true (1) if the connection authentication method + required a password, but none was available. + Returns false (0) if not. + + + int PQconnectionNeedsPassword(const PGconn *conn); + + + + + + This function can be applied after a failed connection attempt + to decide whether to prompt the user for a password. + + + + + PQconnectionUsedPasswordPQconnectionUsedPassword Returns true (1) if the connection authentication method ! used a caller-supplied password. Returns false (0) if not. int PQconnectionUsedPassword(const PGconn *conn); *************** *** 1159,1167 **** ! This function can be applied after either successful or failed ! connection attempts. In the case of failure, it can for example ! be used to decide whether to prompt the user for a password. --- 1180,1189 ---- ! This function detects whether a password supplied to the connection ! function was actually used. Passwords obtained from other ! sources (such as the .pgpass file) are not considered ! caller-supplied. Index: doc/src/sgml/release.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/release.sgml,v retrieving revision 1.563 diff -c -r1.563 release.sgml *** doc/src/sgml/release.sgml 8 Dec 2007 17:24:03 -0000 1.563 --- doc/src/sgml/release.sgml 8 Dec 2007 23:13:37 -0000 *************** *** 2184,2191 **** ! Add PQconnectionUsedPassword() that returns ! true if the server required a password (Joe Conway) --- 2184,2192 ---- ! Add PQconnectionNeedsPassword() that returns ! true if the server required a password but none was supplied ! (Joe Conway, Tom) *************** *** 2197,2202 **** --- 2198,2216 ---- + + + Add PQconnectionUsedPassword() that returns + true if the supplied password was actually used + (Joe Conway, Tom) + + + + This is useful in some security contexts where it is important + to know whether a user-supplied password is actually valid. + + + Index: src/bin/pg_ctl/pg_ctl.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/pg_ctl/pg_ctl.c,v retrieving revision 1.90 diff -c -r1.90 pg_ctl.c *** src/bin/pg_ctl/pg_ctl.c 20 Nov 2007 19:24:26 -0000 1.90 --- src/bin/pg_ctl/pg_ctl.c 8 Dec 2007 23:13:37 -0000 *************** *** 492,498 **** { if ((conn = PQconnectdb(connstr)) != NULL && (PQstatus(conn) == CONNECTION_OK || ! PQconnectionUsedPassword(conn))) { PQfinish(conn); success = true; --- 492,498 ---- { if ((conn = PQconnectdb(connstr)) != NULL && (PQstatus(conn) == CONNECTION_OK || ! PQconnectionNeedsPassword(conn))) { PQfinish(conn); success = true; Index: src/bin/pg_dump/pg_backup_db.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v retrieving revision 1.76 diff -c -r1.76 pg_backup_db.c *** src/bin/pg_dump/pg_backup_db.c 8 Jul 2007 19:07:38 -0000 1.76 --- src/bin/pg_dump/pg_backup_db.c 8 Dec 2007 23:13:37 -0000 *************** *** 159,165 **** if (PQstatus(newConn) == CONNECTION_BAD) { ! if (!PQconnectionUsedPassword(newConn)) die_horribly(AH, modulename, "could not reconnect to database: %s", PQerrorMessage(newConn)); PQfinish(newConn); --- 159,165 ---- if (PQstatus(newConn) == CONNECTION_BAD) { ! if (!PQconnectionNeedsPassword(newConn)) die_horribly(AH, modulename, "could not reconnect to database: %s", PQerrorMessage(newConn)); PQfinish(newConn); *************** *** 234,240 **** die_horribly(AH, modulename, "failed to connect to database\n"); if (PQstatus(AH->connection) == CONNECTION_BAD && ! PQconnectionUsedPassword(AH->connection) && password == NULL && !feof(stdin)) { --- 234,240 ---- die_horribly(AH, modulename, "failed to connect to database\n"); if (PQstatus(AH->connection) == CONNECTION_BAD && ! PQconnectionNeedsPassword(AH->connection) && password == NULL && !feof(stdin)) { Index: src/bin/pg_dump/pg_dumpall.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_dumpall.c,v retrieving revision 1.98 diff -c -r1.98 pg_dumpall.c *** src/bin/pg_dump/pg_dumpall.c 15 Nov 2007 21:14:42 -0000 1.98 --- src/bin/pg_dump/pg_dumpall.c 8 Dec 2007 23:13:37 -0000 *************** *** 1336,1342 **** } if (PQstatus(conn) == CONNECTION_BAD && ! PQconnectionUsedPassword(conn) && password == NULL && !feof(stdin)) { --- 1336,1342 ---- } if (PQstatus(conn) == CONNECTION_BAD && ! PQconnectionNeedsPassword(conn) && password == NULL && !feof(stdin)) { Index: src/bin/psql/command.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/command.c,v retrieving revision 1.183 diff -c -r1.183 command.c *** src/bin/psql/command.c 15 Nov 2007 21:14:42 -0000 1.183 --- src/bin/psql/command.c 8 Dec 2007 23:13:37 -0000 *************** *** 1164,1170 **** * Connection attempt failed; either retry the connection attempt with * a new password, or give up. */ ! if (!password && PQconnectionUsedPassword(n_conn)) { PQfinish(n_conn); password = prompt_for_password(user); --- 1164,1170 ---- * Connection attempt failed; either retry the connection attempt with * a new password, or give up. */ ! if (!password && PQconnectionNeedsPassword(n_conn)) { PQfinish(n_conn); password = prompt_for_password(user); Index: src/bin/psql/startup.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/startup.c,v retrieving revision 1.141 diff -c -r1.141 startup.c *** src/bin/psql/startup.c 8 Jul 2007 19:07:38 -0000 1.141 --- src/bin/psql/startup.c 8 Dec 2007 23:13:37 -0000 *************** *** 211,217 **** username, password); if (PQstatus(pset.db) == CONNECTION_BAD && ! PQconnectionUsedPassword(pset.db) && password == NULL && !feof(stdin)) { --- 211,217 ---- username, password); if (PQstatus(pset.db) == CONNECTION_BAD && ! PQconnectionNeedsPassword(pset.db) && password == NULL && !feof(stdin)) { Index: src/bin/scripts/common.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/scripts/common.c,v retrieving revision 1.29 diff -c -r1.29 common.c *** src/bin/scripts/common.c 15 Nov 2007 21:14:42 -0000 1.29 --- src/bin/scripts/common.c 8 Dec 2007 23:13:37 -0000 *************** *** 123,129 **** } if (PQstatus(conn) == CONNECTION_BAD && ! PQconnectionUsedPassword(conn) && password == NULL && !feof(stdin)) { --- 123,129 ---- } if (PQstatus(conn) == CONNECTION_BAD && ! PQconnectionNeedsPassword(conn) && password == NULL && !feof(stdin)) { Index: src/interfaces/libpq/exports.txt =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/exports.txt,v retrieving revision 1.17 diff -c -r1.17 exports.txt *** src/interfaces/libpq/exports.txt 13 Oct 2007 20:18:41 -0000 1.17 --- src/interfaces/libpq/exports.txt 8 Dec 2007 23:13:37 -0000 *************** *** 139,141 **** --- 139,142 ---- lo_truncate 137 PQconnectionUsedPassword 138 pg_valid_server_encoding_id 139 + PQconnectionNeedsPassword 140 Index: src/interfaces/libpq/fe-auth.c =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v retrieving revision 1.134 diff -c -r1.134 fe-auth.c *** src/interfaces/libpq/fe-auth.c 4 Dec 2007 13:02:53 -0000 1.134 --- src/interfaces/libpq/fe-auth.c 8 Dec 2007 23:13:37 -0000 *************** *** 954,960 **** case AUTH_REQ_MD5: case AUTH_REQ_CRYPT: case AUTH_REQ_PASSWORD: ! if (conn->pgpass == NULL || *conn->pgpass == '\0') { printfPQExpBuffer(&conn->errorMessage, PQnoPasswordSupplied); --- 954,961 ---- case AUTH_REQ_MD5: case AUTH_REQ_CRYPT: case AUTH_REQ_PASSWORD: ! conn->password_needed = true; ! if (conn->pgpass == NULL || conn->pgpass[0] == '\0') { printfPQExpBuffer(&conn->errorMessage, PQnoPasswordSupplied); Index: src/interfaces/libpq/fe-connect.c =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v retrieving revision 1.353 diff -c -r1.353 fe-connect.c *** src/interfaces/libpq/fe-connect.c 15 Nov 2007 21:14:46 -0000 1.353 --- src/interfaces/libpq/fe-connect.c 8 Dec 2007 23:13:37 -0000 *************** *** 232,238 **** static void freePGconn(PGconn *conn); static void closePGconn(PGconn *conn); static PQconninfoOption *conninfo_parse(const char *conninfo, ! PQExpBuffer errorMessage); static char *conninfo_getval(PQconninfoOption *connOptions, const char *keyword); static void defaultNoticeReceiver(void *arg, const PGresult *res); --- 232,238 ---- static void freePGconn(PGconn *conn); static void closePGconn(PGconn *conn); static PQconninfoOption *conninfo_parse(const char *conninfo, ! PQExpBuffer errorMessage, bool *password_from_string); static char *conninfo_getval(PQconninfoOption *connOptions, const char *keyword); static void defaultNoticeReceiver(void *arg, const PGresult *res); *************** *** 376,382 **** /* * Parse the conninfo string */ ! connOptions = conninfo_parse(conninfo, &conn->errorMessage); if (connOptions == NULL) { conn->status = CONNECTION_BAD; --- 376,383 ---- /* * Parse the conninfo string */ ! connOptions = conninfo_parse(conninfo, &conn->errorMessage, ! &conn->pgpass_from_client); if (connOptions == NULL) { conn->status = CONNECTION_BAD; *************** *** 472,477 **** --- 473,479 ---- conn->dbName, conn->pguser); if (conn->pgpass == NULL) conn->pgpass = strdup(DefaultPassword); + conn->pgpass_from_client = false; } /* *************** *** 555,564 **** PQconndefaults(void) { PQExpBufferData errorBuf; PQconninfoOption *connOptions; initPQExpBuffer(&errorBuf); ! connOptions = conninfo_parse("", &errorBuf); termPQExpBuffer(&errorBuf); return connOptions; } --- 557,567 ---- PQconndefaults(void) { PQExpBufferData errorBuf; + bool password_from_string; PQconninfoOption *connOptions; initPQExpBuffer(&errorBuf); ! connOptions = conninfo_parse("", &errorBuf, &password_from_string); termPQExpBuffer(&errorBuf); return connOptions; } *************** *** 659,664 **** --- 662,668 ---- if (conn->pgpass) free(conn->pgpass); conn->pgpass = strdup(pwd); + conn->pgpass_from_client = true; } /* *************** *** 1718,1727 **** */ conn->inStart = conn->inCursor; - /* Save the authentication request type, if first one. */ - if (conn->areq == AUTH_REQ_OK) - conn->areq = areq; - /* Respond to the request if necessary. */ /* --- 1722,1727 ---- *************** *** 1924,1930 **** conn->std_strings = false; /* unless server says differently */ conn->verbosity = PQERRORS_DEFAULT; conn->sock = -1; ! conn->areq = AUTH_REQ_OK; /* until we receive something else */ #ifdef USE_SSL conn->allow_ssl_try = true; conn->wait_ssl_try = false; --- 1924,1930 ---- conn->std_strings = false; /* unless server says differently */ conn->verbosity = PQERRORS_DEFAULT; conn->sock = -1; ! conn->password_needed = false; #ifdef USE_SSL conn->allow_ssl_try = true; conn->wait_ssl_try = false; *************** *** 3064,3072 **** * If successful, a malloc'd PQconninfoOption array is returned. * If not successful, NULL is returned and an error message is * left in errorMessage. */ static PQconninfoOption * ! conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) { char *pname; char *pval; --- 3064,3075 ---- * If successful, a malloc'd PQconninfoOption array is returned. * If not successful, NULL is returned and an error message is * left in errorMessage. + * *password_from_string is set TRUE if we got a password from the + * conninfo string, otherwise FALSE. */ static PQconninfoOption * ! conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, ! bool *password_from_string) { char *pname; char *pval; *************** *** 3077,3082 **** --- 3080,3087 ---- PQconninfoOption *options; PQconninfoOption *option; + *password_from_string = false; /* default result */ + /* Make a working copy of PQconninfoOptions */ options = malloc(sizeof(PQconninfoOptions)); if (options == NULL) *************** *** 3233,3238 **** --- 3238,3249 ---- free(buf); return NULL; } + + /* + * Special handling for password + */ + if (strcmp(option->keyword, "password") == 0) + *password_from_string = (option->val[0] != '\0'); } /* Done with the modifiable input string */ *************** *** 3476,3488 **** } int PQconnectionUsedPassword(const PGconn *conn) { if (!conn) return false; ! if (conn->areq == AUTH_REQ_MD5 || ! conn->areq == AUTH_REQ_CRYPT || ! conn->areq == AUTH_REQ_PASSWORD) return true; else return false; --- 3487,3509 ---- } int + PQconnectionNeedsPassword(const PGconn *conn) + { + if (!conn) + return false; + if (conn->password_needed && + (conn->pgpass == NULL || conn->pgpass[0] == '\0')) + return true; + else + return false; + } + + int PQconnectionUsedPassword(const PGconn *conn) { if (!conn) return false; ! if (conn->password_needed && conn->pgpass_from_client) return true; else return false; Index: src/interfaces/libpq/libpq-fe.h =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/libpq-fe.h,v retrieving revision 1.139 diff -c -r1.139 libpq-fe.h *** src/interfaces/libpq/libpq-fe.h 13 Oct 2007 20:18:42 -0000 1.139 --- src/interfaces/libpq/libpq-fe.h 8 Dec 2007 23:13:37 -0000 *************** *** 263,268 **** --- 263,269 ---- extern char *PQerrorMessage(const PGconn *conn); extern int PQsocket(const PGconn *conn); extern int PQbackendPID(const PGconn *conn); + extern int PQconnectionNeedsPassword(const PGconn *conn); extern int PQconnectionUsedPassword(const PGconn *conn); extern int PQclientEncoding(const PGconn *conn); extern int PQsetClientEncoding(PGconn *conn, const char *encoding); *************** *** 426,432 **** #define PQfreeNotify(ptr) PQfreemem(ptr) /* Error when no password was given. */ ! /* Note: depending on this is deprecated; use PQconnectionUsedPassword(). */ #define PQnoPasswordSupplied "fe_sendauth: no password supplied\n" /* --- 427,433 ---- #define PQfreeNotify(ptr) PQfreemem(ptr) /* Error when no password was given. */ ! /* Note: depending on this is deprecated; use PQconnectionNeedsPassword(). */ #define PQnoPasswordSupplied "fe_sendauth: no password supplied\n" /* Index: src/interfaces/libpq/libpq-int.h =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/libpq-int.h,v retrieving revision 1.127 diff -c -r1.127 libpq-int.h *** src/interfaces/libpq/libpq-int.h 15 Nov 2007 21:14:46 -0000 1.127 --- src/interfaces/libpq/libpq-int.h 8 Dec 2007 23:13:37 -0000 *************** *** 291,296 **** --- 291,297 ---- char *dbName; /* database name */ char *pguser; /* Postgres username and password, if any */ char *pgpass; + bool pgpass_from_client; /* did password come from connect args? */ char *sslmode; /* SSL mode (require,prefer,allow,disable) */ #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI) char *krbsrvname; /* Kerberos service name */ *************** *** 323,329 **** SockAddr raddr; /* Remote address */ ProtocolVersion pversion; /* FE/BE protocol version in use */ int sversion; /* server version, e.g. 70401 for 7.4.1 */ ! AuthRequest areq; /* auth type demanded by server */ /* Transient state needed while establishing connection */ struct addrinfo *addrlist; /* list of possible backend addresses */ --- 324,330 ---- SockAddr raddr; /* Remote address */ ProtocolVersion pversion; /* FE/BE protocol version in use */ int sversion; /* server version, e.g. 70401 for 7.4.1 */ ! bool password_needed; /* true if server demanded a password */ /* Transient state needed while establishing connection */ struct addrinfo *addrlist; /* list of possible backend addresses */