Skip to content

Commit 4f9bf7f

Browse files
committed
Fix up the PQconnectionUsedPassword mess: create a separate
PQconnectionNeedsPassword function that tells the right thing for whether to prompt for a password, and improve PQconnectionUsedPassword so that it checks whether the password used by the connection was actually supplied as a connection argument, instead of coming from environment or a password file. Per bug report from Mark Cave-Ayland and subsequent discussion.
1 parent cb1ab30 commit 4f9bf7f

File tree

13 files changed

+102
-41
lines changed

13 files changed

+102
-41
lines changed

doc/src/sgml/libpq.sgml

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.247 2007/11/28 15:42:31 petere Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.248 2007/12/09 19:01:40 tgl Exp $ -->
22

33
<chapter id="libpq">
44
<title><application>libpq</application> - C Library</title>
@@ -1145,12 +1145,33 @@ typedef struct
11451145
</listitem>
11461146
</varlistentry>
11471147

1148+
<varlistentry>
1149+
<term><function>PQconnectionNeedsPassword</function><indexterm><primary>PQconnectionNeedsPassword</></></term>
1150+
<listitem>
1151+
<para>
1152+
Returns true (1) if the connection authentication method
1153+
required a password, but none was available.
1154+
Returns false (0) if not.
1155+
1156+
<synopsis>
1157+
int PQconnectionNeedsPassword(const PGconn *conn);
1158+
</synopsis>
1159+
1160+
</para>
1161+
1162+
<para>
1163+
This function can be applied after a failed connection attempt
1164+
to decide whether to prompt the user for a password.
1165+
</para>
1166+
</listitem>
1167+
</varlistentry>
1168+
11481169
<varlistentry>
11491170
<term><function>PQconnectionUsedPassword</function><indexterm><primary>PQconnectionUsedPassword</></></term>
11501171
<listitem>
11511172
<para>
11521173
Returns true (1) if the connection authentication method
1153-
required a password to be supplied. Returns false (0) if not.
1174+
used a caller-supplied password. Returns false (0) if not.
11541175

11551176
<synopsis>
11561177
int PQconnectionUsedPassword(const PGconn *conn);
@@ -1159,9 +1180,10 @@ typedef struct
11591180
</para>
11601181

11611182
<para>
1162-
This function can be applied after either successful or failed
1163-
connection attempts. In the case of failure, it can for example
1164-
be used to decide whether to prompt the user for a password.
1183+
This function detects whether a password supplied to the connection
1184+
function was actually used. Passwords obtained from other
1185+
sources (such as the <filename>.pgpass</> file) are not considered
1186+
caller-supplied.
11651187
</para>
11661188
</listitem>
11671189
</varlistentry>

doc/src/sgml/release.sgml

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/release.sgml,v 1.563 2007/12/08 17:24:03 momjian Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/release.sgml,v 1.564 2007/12/09 19:01:40 tgl Exp $ -->
22
<!--
33

44
Typical markup:
@@ -2184,8 +2184,9 @@ current_date &lt; 2017-11-17
21842184

21852185
<listitem>
21862186
<para>
2187-
Add <function>PQconnectionUsedPassword()</function> that returns
2188-
true if the server required a password (Joe Conway)
2187+
Add <function>PQconnectionNeedsPassword()</function> that returns
2188+
true if the server required a password but none was supplied
2189+
(Joe Conway, Tom)
21892190
</para>
21902191

21912192
<para>
@@ -2197,6 +2198,19 @@ current_date &lt; 2017-11-17
21972198
</para>
21982199
</listitem>
21992200

2201+
<listitem>
2202+
<para>
2203+
Add <function>PQconnectionUsedPassword()</function> that returns
2204+
true if the supplied password was actually used
2205+
(Joe Conway, Tom)
2206+
</para>
2207+
2208+
<para>
2209+
This is useful in some security contexts where it is important
2210+
to know whether a user-supplied password is actually valid.
2211+
</para>
2212+
</listitem>
2213+
22002214
</itemizedlist>
22012215

22022216
</sect3>

src/bin/pg_ctl/pg_ctl.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
66
*
7-
* $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.90 2007/11/20 19:24:26 momjian Exp $
7+
* $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.91 2007/12/09 19:01:40 tgl Exp $
88
*
99
*-------------------------------------------------------------------------
1010
*/
@@ -492,7 +492,7 @@ test_postmaster_connection(bool do_checkpoint)
492492
{
493493
if ((conn = PQconnectdb(connstr)) != NULL &&
494494
(PQstatus(conn) == CONNECTION_OK ||
495-
PQconnectionUsedPassword(conn)))
495+
PQconnectionNeedsPassword(conn)))
496496
{
497497
PQfinish(conn);
498498
success = true;

src/bin/pg_dump/pg_backup_db.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Implements the basic DB functions used by the archiver.
66
*
77
* IDENTIFICATION
8-
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.76 2007/07/08 19:07:38 tgl Exp $
8+
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.77 2007/12/09 19:01:40 tgl Exp $
99
*
1010
*-------------------------------------------------------------------------
1111
*/
@@ -159,7 +159,7 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
159159

160160
if (PQstatus(newConn) == CONNECTION_BAD)
161161
{
162-
if (!PQconnectionUsedPassword(newConn))
162+
if (!PQconnectionNeedsPassword(newConn))
163163
die_horribly(AH, modulename, "could not reconnect to database: %s",
164164
PQerrorMessage(newConn));
165165
PQfinish(newConn);
@@ -234,7 +234,7 @@ ConnectDatabase(Archive *AHX,
234234
die_horribly(AH, modulename, "failed to connect to database\n");
235235

236236
if (PQstatus(AH->connection) == CONNECTION_BAD &&
237-
PQconnectionUsedPassword(AH->connection) &&
237+
PQconnectionNeedsPassword(AH->connection) &&
238238
password == NULL &&
239239
!feof(stdin))
240240
{

src/bin/pg_dump/pg_dumpall.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1994, Regents of the University of California
77
*
88
*
9-
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.98 2007/11/15 21:14:42 momjian Exp $
9+
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.99 2007/12/09 19:01:40 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -1336,7 +1336,7 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
13361336
}
13371337

13381338
if (PQstatus(conn) == CONNECTION_BAD &&
1339-
PQconnectionUsedPassword(conn) &&
1339+
PQconnectionNeedsPassword(conn) &&
13401340
password == NULL &&
13411341
!feof(stdin))
13421342
{

src/bin/psql/command.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2007, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.183 2007/11/15 21:14:42 momjian Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.184 2007/12/09 19:01:40 tgl Exp $
77
*/
88
#include "postgres_fe.h"
99
#include "command.h"
@@ -1164,7 +1164,7 @@ do_connect(char *dbname, char *user, char *host, char *port)
11641164
* Connection attempt failed; either retry the connection attempt with
11651165
* a new password, or give up.
11661166
*/
1167-
if (!password && PQconnectionUsedPassword(n_conn))
1167+
if (!password && PQconnectionNeedsPassword(n_conn))
11681168
{
11691169
PQfinish(n_conn);
11701170
password = prompt_for_password(user);

src/bin/psql/startup.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2007, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.141 2007/07/08 19:07:38 tgl Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.142 2007/12/09 19:01:40 tgl Exp $
77
*/
88
#include "postgres_fe.h"
99

@@ -211,7 +211,7 @@ main(int argc, char *argv[])
211211
username, password);
212212

213213
if (PQstatus(pset.db) == CONNECTION_BAD &&
214-
PQconnectionUsedPassword(pset.db) &&
214+
PQconnectionNeedsPassword(pset.db) &&
215215
password == NULL &&
216216
!feof(stdin))
217217
{

src/bin/scripts/common.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.29 2007/11/15 21:14:42 momjian Exp $
10+
* $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.30 2007/12/09 19:01:40 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -123,7 +123,7 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
123123
}
124124

125125
if (PQstatus(conn) == CONNECTION_BAD &&
126-
PQconnectionUsedPassword(conn) &&
126+
PQconnectionNeedsPassword(conn) &&
127127
password == NULL &&
128128
!feof(stdin))
129129
{

src/interfaces/libpq/exports.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.17 2007/10/13 20:18:41 tgl Exp $
1+
# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.18 2007/12/09 19:01:40 tgl Exp $
22
# Functions to be exported by libpq DLLs
33
PQconnectdb 1
44
PQsetdbLogin 2
@@ -139,3 +139,4 @@ PQsendDescribePortal 136
139139
lo_truncate 137
140140
PQconnectionUsedPassword 138
141141
pg_valid_server_encoding_id 139
142+
PQconnectionNeedsPassword 140

src/interfaces/libpq/fe-auth.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.134 2007/12/04 13:02:53 mha Exp $
10+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.135 2007/12/09 19:01:40 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -954,7 +954,8 @@ pg_fe_sendauth(AuthRequest areq, PGconn *conn)
954954
case AUTH_REQ_MD5:
955955
case AUTH_REQ_CRYPT:
956956
case AUTH_REQ_PASSWORD:
957-
if (conn->pgpass == NULL || *conn->pgpass == '\0')
957+
conn->password_needed = true;
958+
if (conn->pgpass == NULL || conn->pgpass[0] == '\0')
958959
{
959960
printfPQExpBuffer(&conn->errorMessage,
960961
PQnoPasswordSupplied);

src/interfaces/libpq/fe-connect.c

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.353 2007/11/15 21:14:46 momjian Exp $
11+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.354 2007/12/09 19:01:40 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -232,7 +232,7 @@ static PGconn *makeEmptyPGconn(void);
232232
static void freePGconn(PGconn *conn);
233233
static void closePGconn(PGconn *conn);
234234
static PQconninfoOption *conninfo_parse(const char *conninfo,
235-
PQExpBuffer errorMessage);
235+
PQExpBuffer errorMessage, bool *password_from_string);
236236
static char *conninfo_getval(PQconninfoOption *connOptions,
237237
const char *keyword);
238238
static void defaultNoticeReceiver(void *arg, const PGresult *res);
@@ -376,7 +376,8 @@ connectOptions1(PGconn *conn, const char *conninfo)
376376
/*
377377
* Parse the conninfo string
378378
*/
379-
connOptions = conninfo_parse(conninfo, &conn->errorMessage);
379+
connOptions = conninfo_parse(conninfo, &conn->errorMessage,
380+
&conn->pgpass_from_client);
380381
if (connOptions == NULL)
381382
{
382383
conn->status = CONNECTION_BAD;
@@ -472,6 +473,7 @@ connectOptions2(PGconn *conn)
472473
conn->dbName, conn->pguser);
473474
if (conn->pgpass == NULL)
474475
conn->pgpass = strdup(DefaultPassword);
476+
conn->pgpass_from_client = false;
475477
}
476478

477479
/*
@@ -555,10 +557,11 @@ PQconninfoOption *
555557
PQconndefaults(void)
556558
{
557559
PQExpBufferData errorBuf;
560+
bool password_from_string;
558561
PQconninfoOption *connOptions;
559562

560563
initPQExpBuffer(&errorBuf);
561-
connOptions = conninfo_parse("", &errorBuf);
564+
connOptions = conninfo_parse("", &errorBuf, &password_from_string);
562565
termPQExpBuffer(&errorBuf);
563566
return connOptions;
564567
}
@@ -659,6 +662,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
659662
if (conn->pgpass)
660663
free(conn->pgpass);
661664
conn->pgpass = strdup(pwd);
665+
conn->pgpass_from_client = true;
662666
}
663667

664668
/*
@@ -1718,10 +1722,6 @@ PQconnectPoll(PGconn *conn)
17181722
*/
17191723
conn->inStart = conn->inCursor;
17201724

1721-
/* Save the authentication request type, if first one. */
1722-
if (conn->areq == AUTH_REQ_OK)
1723-
conn->areq = areq;
1724-
17251725
/* Respond to the request if necessary. */
17261726

17271727
/*
@@ -1924,7 +1924,7 @@ makeEmptyPGconn(void)
19241924
conn->std_strings = false; /* unless server says differently */
19251925
conn->verbosity = PQERRORS_DEFAULT;
19261926
conn->sock = -1;
1927-
conn->areq = AUTH_REQ_OK; /* until we receive something else */
1927+
conn->password_needed = false;
19281928
#ifdef USE_SSL
19291929
conn->allow_ssl_try = true;
19301930
conn->wait_ssl_try = false;
@@ -3064,9 +3064,12 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
30643064
* If successful, a malloc'd PQconninfoOption array is returned.
30653065
* If not successful, NULL is returned and an error message is
30663066
* left in errorMessage.
3067+
* *password_from_string is set TRUE if we got a password from the
3068+
* conninfo string, otherwise FALSE.
30673069
*/
30683070
static PQconninfoOption *
3069-
conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
3071+
conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
3072+
bool *password_from_string)
30703073
{
30713074
char *pname;
30723075
char *pval;
@@ -3077,6 +3080,8 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
30773080
PQconninfoOption *options;
30783081
PQconninfoOption *option;
30793082

3083+
*password_from_string = false; /* default result */
3084+
30803085
/* Make a working copy of PQconninfoOptions */
30813086
options = malloc(sizeof(PQconninfoOptions));
30823087
if (options == NULL)
@@ -3233,6 +3238,12 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
32333238
free(buf);
32343239
return NULL;
32353240
}
3241+
3242+
/*
3243+
* Special handling for password
3244+
*/
3245+
if (strcmp(option->keyword, "password") == 0)
3246+
*password_from_string = (option->val[0] != '\0');
32363247
}
32373248

32383249
/* Done with the modifiable input string */
@@ -3475,14 +3486,24 @@ PQbackendPID(const PGconn *conn)
34753486
return conn->be_pid;
34763487
}
34773488

3489+
int
3490+
PQconnectionNeedsPassword(const PGconn *conn)
3491+
{
3492+
if (!conn)
3493+
return false;
3494+
if (conn->password_needed &&
3495+
(conn->pgpass == NULL || conn->pgpass[0] == '\0'))
3496+
return true;
3497+
else
3498+
return false;
3499+
}
3500+
34783501
int
34793502
PQconnectionUsedPassword(const PGconn *conn)
34803503
{
34813504
if (!conn)
34823505
return false;
3483-
if (conn->areq == AUTH_REQ_MD5 ||
3484-
conn->areq == AUTH_REQ_CRYPT ||
3485-
conn->areq == AUTH_REQ_PASSWORD)
3506+
if (conn->password_needed && conn->pgpass_from_client)
34863507
return true;
34873508
else
34883509
return false;

0 commit comments

Comments
 (0)