Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)