Skip to content

Commit f56802a

Browse files
committed
In pg_dump, remember connection passwords no matter how we got them.
When pg_dump prompts the user for a password, it remembers the password for possible re-use by parallel worker processes. However, libpq might have extracted the password from a connection string originally passed as "dbname". Since we don't record the original form of dbname but break it down to host/port/etc, the password gets lost. Fix that by retrieving the actual password from the PGconn. (It strikes me that this whole approach is rather broken, as it will also lose other information such as options that might have been present in the connection string. But we'll leave that problem for another day.) In passing, get rid of rather silly use of malloc() for small fixed-size arrays. Back-patch to 9.3 where parallel pg_dump was introduced. Report and fix by Zeus Kronion, adjusted a bit by Michael Paquier and me
1 parent d07afa4 commit f56802a

File tree

1 file changed

+35
-17
lines changed

1 file changed

+35
-17
lines changed

src/bin/pg_dump/pg_backup_db.c

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
111111
PGconn *newConn;
112112
const char *newdb;
113113
const char *newuser;
114-
char *password = AH->savedPassword;
114+
char *password;
115115
bool new_pass;
116116

117117
if (!reqdb)
@@ -127,6 +127,8 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
127127
ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n",
128128
newdb, newuser);
129129

130+
password = AH->savedPassword ? pg_strdup(AH->savedPassword) : NULL;
131+
130132
if (AH->promptPassword == TRI_YES && password == NULL)
131133
{
132134
password = simple_prompt("Password: ", 100, false);
@@ -136,9 +138,8 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
136138

137139
do
138140
{
139-
#define PARAMS_ARRAY_SIZE 7
140-
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
141-
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
141+
const char *keywords[7];
142+
const char *values[7];
142143

143144
keywords[0] = "host";
144145
values[0] = PQhost(AH->connection);
@@ -158,9 +159,6 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
158159
new_pass = false;
159160
newConn = PQconnectdbParams(keywords, values, true);
160161

161-
free(keywords);
162-
free(values);
163-
164162
if (!newConn)
165163
exit_horribly(modulename, "failed to reconnect to database\n");
166164

@@ -191,7 +189,18 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
191189
}
192190
} while (new_pass);
193191

194-
AH->savedPassword = password;
192+
/*
193+
* We want to remember connection's actual password, whether or not we got
194+
* it by prompting. So we don't just store the password variable.
195+
*/
196+
if (PQconnectionUsedPassword(newConn))
197+
{
198+
if (AH->savedPassword)
199+
free(AH->savedPassword);
200+
AH->savedPassword = pg_strdup(PQpass(newConn));
201+
}
202+
if (password)
203+
free(password);
195204

196205
/* check for version mismatch */
197206
_check_database_version(AH);
@@ -220,12 +229,14 @@ ConnectDatabase(Archive *AHX,
220229
enum trivalue prompt_password)
221230
{
222231
ArchiveHandle *AH = (ArchiveHandle *) AHX;
223-
char *password = AH->savedPassword;
232+
char *password;
224233
bool new_pass;
225234

226235
if (AH->connection)
227236
exit_horribly(modulename, "already connected to a database\n");
228237

238+
password = AH->savedPassword ? pg_strdup(AH->savedPassword) : NULL;
239+
229240
if (prompt_password == TRI_YES && password == NULL)
230241
{
231242
password = simple_prompt("Password: ", 100, false);
@@ -240,9 +251,8 @@ ConnectDatabase(Archive *AHX,
240251
*/
241252
do
242253
{
243-
#define PARAMS_ARRAY_SIZE 7
244-
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
245-
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
254+
const char *keywords[7];
255+
const char *values[7];
246256

247257
keywords[0] = "host";
248258
values[0] = pghost;
@@ -262,9 +272,6 @@ ConnectDatabase(Archive *AHX,
262272
new_pass = false;
263273
AH->connection = PQconnectdbParams(keywords, values, true);
264274

265-
free(keywords);
266-
free(values);
267-
268275
if (!AH->connection)
269276
exit_horribly(modulename, "failed to connect to database\n");
270277

@@ -281,14 +288,25 @@ ConnectDatabase(Archive *AHX,
281288
}
282289
} while (new_pass);
283290

284-
AH->savedPassword = password;
285-
286291
/* check to see that the backend connection was successfully made */
287292
if (PQstatus(AH->connection) == CONNECTION_BAD)
288293
exit_horribly(modulename, "connection to database \"%s\" failed: %s",
289294
PQdb(AH->connection) ? PQdb(AH->connection) : "",
290295
PQerrorMessage(AH->connection));
291296

297+
/*
298+
* We want to remember connection's actual password, whether or not we got
299+
* it by prompting. So we don't just store the password variable.
300+
*/
301+
if (PQconnectionUsedPassword(AH->connection))
302+
{
303+
if (AH->savedPassword)
304+
free(AH->savedPassword);
305+
AH->savedPassword = pg_strdup(PQpass(AH->connection));
306+
}
307+
if (password)
308+
free(password);
309+
292310
/* check for version mismatch */
293311
_check_database_version(AH);
294312

0 commit comments

Comments
 (0)