Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 15be274

Browse files
committed
Avoid misleading psql password prompt when username is multiply specified.
When a password is needed, cases such as psql -d "postgresql://alice@localhost/testdb" -U bob would incorrectly prompt for "Password for user bob: ", when actually the connection will be attempted with username alice. The priority order of which name to use isn't that important here, but the misleading prompt is. When we are prompting for a password after initial connection failure, we can fix this reliably by looking at PQuser(conn) to see how libpq interpreted the connection arguments. But when we're doing a forced password prompt because of a -W switch, we can't use that solution. Fortunately, because the main use of -W is for noninteractive situations, it's less critical to produce a helpful prompt in such cases. I made the startup prompt for -W just say "Password: " all the time, rather than expending extra code on trying to identify which username to use. In the case of a \c command (after -W has been given), there's already logic in do_connect that determines whether the "dbname" is a connstring or URI, so we can avoid lobotomizing the prompt except in cases that are actually dubious. (We could do similarly in startup.c if anyone complains, but for now it seems not worthwhile, especially since that would still be only a partial solution.) Per bug #15025 from Akos Vandra. Although this is arguably a bug fix, it doesn't seem worth back-patching. The case where it matters seems like a very corner-case usage, and someone might complain that we'd changed the behavior of -W in a minor release. Discussion: https://postgr.es/m/20180123130013.7407.24749@wrigleys.postgresql.org
1 parent 35a5280 commit 15be274

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

src/bin/psql/command.c

+14-3
Original file line numberDiff line numberDiff line change
@@ -2829,7 +2829,7 @@ prompt_for_password(const char *username)
28292829
{
28302830
char buf[100];
28312831

2832-
if (username == NULL)
2832+
if (username == NULL || username[0] == '\0')
28332833
simple_prompt("Password: ", buf, sizeof(buf), false);
28342834
else
28352835
{
@@ -2960,7 +2960,14 @@ do_connect(enum trivalue reuse_previous_specification,
29602960
*/
29612961
if (pset.getPassword == TRI_YES)
29622962
{
2963-
password = prompt_for_password(user);
2963+
/*
2964+
* If a connstring or URI is provided, we can't be sure we know which
2965+
* username will be used, since we haven't parsed that argument yet.
2966+
* Don't risk issuing a misleading prompt. As in startup.c, it does
2967+
* not seem worth working harder, since this getPassword option is
2968+
* normally only used in noninteractive cases.
2969+
*/
2970+
password = prompt_for_password(has_connection_string ? NULL : user);
29642971
}
29652972
else if (o_conn && keep_password)
29662973
{
@@ -3026,8 +3033,12 @@ do_connect(enum trivalue reuse_previous_specification,
30263033
*/
30273034
if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
30283035
{
3036+
/*
3037+
* Prompt for password using the username we actually connected
3038+
* with --- it might've come out of "dbname" rather than "user".
3039+
*/
3040+
password = prompt_for_password(PQuser(n_conn));
30293041
PQfinish(n_conn);
3030-
password = prompt_for_password(user);
30313042
continue;
30323043
}
30333044

src/bin/psql/startup.c

+21-10
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ main(int argc, char *argv[])
101101
int successResult;
102102
bool have_password = false;
103103
char password[100];
104-
char *password_prompt = NULL;
105104
bool new_pass;
106105

107106
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql"));
@@ -205,15 +204,14 @@ main(int argc, char *argv[])
205204
pset.popt.topt.recordSep.separator_zero = false;
206205
}
207206

208-
if (options.username == NULL)
209-
password_prompt = pg_strdup(_("Password: "));
210-
else
211-
password_prompt = psprintf(_("Password for user %s: "),
212-
options.username);
213-
214207
if (pset.getPassword == TRI_YES)
215208
{
216-
simple_prompt(password_prompt, password, sizeof(password), false);
209+
/*
210+
* We can't be sure yet of the username that will be used, so don't
211+
* offer a potentially wrong one. Typical uses of this option are
212+
* noninteractive anyway.
213+
*/
214+
simple_prompt("Password: ", password, sizeof(password), false);
217215
have_password = true;
218216
}
219217

@@ -252,15 +250,28 @@ main(int argc, char *argv[])
252250
!have_password &&
253251
pset.getPassword != TRI_NO)
254252
{
253+
/*
254+
* Before closing the old PGconn, extract the user name that was
255+
* actually connected with --- it might've come out of a URI or
256+
* connstring "database name" rather than options.username.
257+
*/
258+
const char *realusername = PQuser(pset.db);
259+
char *password_prompt;
260+
261+
if (realusername && realusername[0])
262+
password_prompt = psprintf(_("Password for user %s: "),
263+
realusername);
264+
else
265+
password_prompt = pg_strdup(_("Password: "));
255266
PQfinish(pset.db);
267+
256268
simple_prompt(password_prompt, password, sizeof(password), false);
269+
free(password_prompt);
257270
have_password = true;
258271
new_pass = true;
259272
}
260273
} while (new_pass);
261274

262-
free(password_prompt);
263-
264275
if (PQstatus(pset.db) == CONNECTION_BAD)
265276
{
266277
fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));

0 commit comments

Comments
 (0)