Skip to content

Commit 6655c07

Browse files
committed
Introduce a psql "\connect -reuse-previous=on|off" option.
The decision to reuse values of parameters from a previous connection has been based on whether the new target is a conninfo string. Add this means of overriding that default. This feature arose as one component of a fix for security vulnerabilities in pg_dump, pg_dumpall, and pg_upgrade, so back-patch to 9.1 (all supported versions). In 9.3 and later, comment paragraphs that required update had already-incorrect claims about behavior when no connection is open; fix those problems. Security: CVE-2016-5424
1 parent db951dd commit 6655c07

File tree

3 files changed

+88
-44
lines changed

3 files changed

+88
-44
lines changed

doc/src/sgml/ref/psql-ref.sgml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ testdb=>
799799
</varlistentry>
800800

801801
<varlistentry>
802-
<term><literal>\c</literal> or <literal>\connect</literal> <literal>[ <replaceable class="parameter">dbname</replaceable> [ <replaceable class="parameter">username</replaceable> ] [ <replaceable class="parameter">host</replaceable> ] [ <replaceable class="parameter">port</replaceable> ] ] | <replaceable class="parameter">conninfo</replaceable> </literal></term>
802+
<term><literal>\c</literal> or <literal>\connect [ -reuse-previous=<replaceable class="parameter">on|off</replaceable> ] [ <replaceable class="parameter">dbname</replaceable> [ <replaceable class="parameter">username</replaceable> ] [ <replaceable class="parameter">host</replaceable> ] [ <replaceable class="parameter">port</replaceable> ] | <replaceable class="parameter">conninfo</replaceable> ]</literal></term>
803803
<listitem>
804804
<para>
805805
Establishes a new connection to a <productname>PostgreSQL</>
@@ -809,16 +809,19 @@ testdb=&gt;
809809
</para>
810810

811811
<para>
812-
When using positional parameters, if any of
813-
<replaceable class="parameter">dbname</replaceable>,
812+
Where the command omits database name, user, host, or port, the new
813+
connection can reuse values from the previous connection. By default,
814+
values from the previous connection are reused except when processing
815+
a <literal>conninfo</> string. Passing a first argument
816+
of <literal>-reuse-previous=on</>
817+
or <literal>-reuse-previous=off</literal> overrides that default.
818+
When the command neither specifies nor reuses a particular parameter,
819+
the <application>libpq</application> default is used. Specifying any
820+
of <replaceable class="parameter">dbname</replaceable>,
814821
<replaceable class="parameter">username</replaceable>,
815822
<replaceable class="parameter">host</replaceable> or
816-
<replaceable class="parameter">port</replaceable> are omitted or
817-
specified as <literal>-</literal>, the value of that parameter from
818-
the previous connection is used; if there is no previous connection,
819-
the <application>libpq</application> default for the parameter's value
820-
is used. When using <literal>conninfo</> strings, no values from the
821-
previous connection are used for the new connection.
823+
<replaceable class="parameter">port</replaceable>
824+
as <literal>-</literal> is equivalent to omitting that parameter.
822825
</para>
823826

824827
<para>

src/bin/psql/command.c

Lines changed: 75 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ static backslashResult exec_command(const char *cmd,
5656
PQExpBuffer query_buf);
5757
static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
5858
int lineno, bool *edited);
59-
static bool do_connect(char *dbname, char *user, char *host, char *port);
59+
static bool do_connect(enum trivalue reuse_previous_specification,
60+
char *dbname, char *user, char *host, char *port);
6061
static bool do_shell(const char *command);
6162
static bool do_watch(PQExpBuffer query_buf, long sleep);
6263
static bool lookup_function_oid(const char *desc, Oid *foid);
@@ -217,12 +218,9 @@ exec_command(const char *cmd,
217218
/*
218219
* \c or \connect -- connect to database using the specified parameters.
219220
*
220-
* \c dbname user host port
221+
* \c [-reuse-previous=BOOL] dbname user host port
221222
*
222-
* If any of these parameters are omitted or specified as '-', the current
223-
* value of the parameter will be used instead. If the parameter has no
224-
* current value, the default value for that parameter will be used. Some
225-
* examples:
223+
* Specifying a parameter as '-' is equivalent to omitting it. Examples:
226224
*
227225
* \c - - hst Connect to current database on current port of host
228226
* "hst" as current user. \c - usr - prt Connect to current database on
@@ -231,17 +229,31 @@ exec_command(const char *cmd,
231229
*/
232230
else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
233231
{
232+
static const char prefix[] = "-reuse-previous=";
234233
char *opt1,
235234
*opt2,
236235
*opt3,
237236
*opt4;
237+
enum trivalue reuse_previous;
238238

239239
opt1 = read_connect_arg(scan_state);
240+
if (opt1 != NULL && strncmp(opt1, prefix, sizeof(prefix) - 1) == 0)
241+
{
242+
reuse_previous =
243+
ParseVariableBool(opt1 + sizeof(prefix) - 1, prefix) ?
244+
TRI_YES : TRI_NO;
245+
246+
free(opt1);
247+
opt1 = read_connect_arg(scan_state);
248+
}
249+
else
250+
reuse_previous = TRI_DEFAULT;
251+
240252
opt2 = read_connect_arg(scan_state);
241253
opt3 = read_connect_arg(scan_state);
242254
opt4 = read_connect_arg(scan_state);
243255

244-
success = do_connect(opt1, opt2, opt3, opt4);
256+
success = do_connect(reuse_previous, opt1, opt2, opt3, opt4);
245257

246258
free(opt1);
247259
free(opt2);
@@ -1599,22 +1611,25 @@ param_is_newly_set(const char *old_val, const char *new_val)
15991611
/*
16001612
* do_connect -- handler for \connect
16011613
*
1602-
* Connects to a database with given parameters. If there exists an
1603-
* established connection, NULL values will be replaced with the ones
1604-
* in the current connection. Otherwise NULL will be passed for that
1605-
* parameter to PQconnectdbParams(), so the libpq defaults will be used.
1614+
* Connects to a database with given parameters. Absent an established
1615+
* connection, all parameters are required. Given -reuse-previous=off or a
1616+
* connection string without -reuse-previous=on, NULL values will pass through
1617+
* to PQconnectdbParams(), so the libpq defaults will be used. Otherwise, NULL
1618+
* values will be replaced with the ones in the current connection.
16061619
*
16071620
* In interactive mode, if connection fails with the given parameters,
16081621
* the old connection will be kept.
16091622
*/
16101623
static bool
1611-
do_connect(char *dbname, char *user, char *host, char *port)
1624+
do_connect(enum trivalue reuse_previous_specification,
1625+
char *dbname, char *user, char *host, char *port)
16121626
{
16131627
PGconn *o_conn = pset.db,
16141628
*n_conn;
16151629
char *password = NULL;
16161630
bool keep_password;
16171631
bool has_connection_string;
1632+
bool reuse_previous;
16181633

16191634
if (!o_conn && (!dbname || !user || !host || !port))
16201635
{
@@ -1628,17 +1643,36 @@ do_connect(char *dbname, char *user, char *host, char *port)
16281643
return false;
16291644
}
16301645

1631-
/* grab values from the old connection, unless supplied by caller */
1632-
if (!user)
1646+
has_connection_string = dbname ?
1647+
recognized_connection_string(dbname) : false;
1648+
switch (reuse_previous_specification)
1649+
{
1650+
case TRI_YES:
1651+
reuse_previous = true;
1652+
break;
1653+
case TRI_NO:
1654+
reuse_previous = false;
1655+
break;
1656+
default:
1657+
reuse_previous = !has_connection_string;
1658+
break;
1659+
}
1660+
/* Silently ignore arguments subsequent to a connection string. */
1661+
if (has_connection_string)
1662+
{
1663+
user = NULL;
1664+
host = NULL;
1665+
port = NULL;
1666+
}
1667+
1668+
/* grab missing values from the old connection */
1669+
if (!user && reuse_previous)
16331670
user = PQuser(o_conn);
1634-
if (!host)
1671+
if (!host && reuse_previous)
16351672
host = PQhost(o_conn);
1636-
if (!port)
1673+
if (!port && reuse_previous)
16371674
port = PQport(o_conn);
16381675

1639-
has_connection_string =
1640-
dbname ? recognized_connection_string(dbname) : false;
1641-
16421676
/*
16431677
* Any change in the parameters read above makes us discard the password.
16441678
* We also discard it if we're to use a conninfo rather than the
@@ -1655,10 +1689,10 @@ do_connect(char *dbname, char *user, char *host, char *port)
16551689
(port && PQport(o_conn) && strcmp(port, PQport(o_conn)) == 0);
16561690

16571691
/*
1658-
* Grab dbname from old connection unless supplied by caller. No password
1659-
* discard if this changes: passwords aren't (usually) database-specific.
1692+
* Grab missing dbname from old connection. No password discard if this
1693+
* changes: passwords aren't (usually) database-specific.
16601694
*/
1661-
if (!dbname)
1695+
if (!dbname && reuse_previous)
16621696
dbname = PQdb(o_conn);
16631697

16641698
/*
@@ -1689,20 +1723,27 @@ do_connect(char *dbname, char *user, char *host, char *port)
16891723
#define PARAMS_ARRAY_SIZE 8
16901724
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
16911725
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
1692-
int paramnum = 0;
1726+
int paramnum = -1;
16931727

1694-
keywords[0] = "dbname";
1695-
values[0] = dbname;
1728+
keywords[++paramnum] = "host";
1729+
values[paramnum] = host;
1730+
keywords[++paramnum] = "port";
1731+
values[paramnum] = port;
1732+
keywords[++paramnum] = "user";
1733+
values[paramnum] = user;
16961734

1697-
if (!has_connection_string)
1698-
{
1699-
keywords[++paramnum] = "host";
1700-
values[paramnum] = host;
1701-
keywords[++paramnum] = "port";
1702-
values[paramnum] = port;
1703-
keywords[++paramnum] = "user";
1704-
values[paramnum] = user;
1705-
}
1735+
/*
1736+
* Position in the array matters when the dbname is a connection
1737+
* string, because settings in a connection string override earlier
1738+
* array entries only. Thus, user= in the connection string always
1739+
* takes effect, but client_encoding= often will not.
1740+
*
1741+
* If you change this code, also change the initial-connection code in
1742+
* main(). For no good reason, a connection string password= takes
1743+
* precedence in main() but not here.
1744+
*/
1745+
keywords[++paramnum] = "dbname";
1746+
values[paramnum] = dbname;
17061747
keywords[++paramnum] = "password";
17071748
values[paramnum] = password;
17081749
keywords[++paramnum] = "fallback_application_name";

src/bin/psql/startup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ main(int argc, char *argv[])
215215
values[2] = options.username;
216216
keywords[3] = "password";
217217
values[3] = password;
218-
keywords[4] = "dbname";
218+
keywords[4] = "dbname"; /* see do_connect() */
219219
values[4] = (options.action == ACT_LIST_DB &&
220220
options.dbname == NULL) ?
221221
"postgres" : options.dbname;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy