Skip to content

Commit 9d924e9

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 984e5be commit 9d924e9

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
@@ -825,7 +825,7 @@ testdb=>
825825
</varlistentry>
826826

827827
<varlistentry>
828-
<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>
828+
<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>
829829
<listitem>
830830
<para>
831831
Establishes a new connection to a <productname>PostgreSQL</>
@@ -835,16 +835,19 @@ testdb=&gt;
835835
</para>
836836

837837
<para>
838-
When using positional parameters, if any of
839-
<replaceable class="parameter">dbname</replaceable>,
838+
Where the command omits database name, user, host, or port, the new
839+
connection can reuse values from the previous connection. By default,
840+
values from the previous connection are reused except when processing
841+
a <literal>conninfo</> string. Passing a first argument
842+
of <literal>-reuse-previous=on</>
843+
or <literal>-reuse-previous=off</literal> overrides that default.
844+
When the command neither specifies nor reuses a particular parameter,
845+
the <application>libpq</application> default is used. Specifying any
846+
of <replaceable class="parameter">dbname</replaceable>,
840847
<replaceable class="parameter">username</replaceable>,
841848
<replaceable class="parameter">host</replaceable> or
842-
<replaceable class="parameter">port</replaceable> are omitted or
843-
specified as <literal>-</literal>, the value of that parameter from
844-
the previous connection is used; if there is no previous connection,
845-
the <application>libpq</application> default for the parameter's value
846-
is used. When using <literal>conninfo</> strings, no values from the
847-
previous connection are used for the new connection.
849+
<replaceable class="parameter">port</replaceable>
850+
as <literal>-</literal> is equivalent to omitting that parameter.
848851
</para>
849852

850853
<para>

src/bin/psql/command.c

Lines changed: 75 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ static backslashResult exec_command(const char *cmd,
6565
PQExpBuffer query_buf);
6666
static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
6767
int lineno, bool *edited);
68-
static bool do_connect(char *dbname, char *user, char *host, char *port);
68+
static bool do_connect(enum trivalue reuse_previous_specification,
69+
char *dbname, char *user, char *host, char *port);
6970
static bool do_shell(const char *command);
7071
static bool do_watch(PQExpBuffer query_buf, double sleep);
7172
static bool lookup_object_oid(EditableObjectType obj_type, const char *desc,
@@ -231,12 +232,9 @@ exec_command(const char *cmd,
231232
/*
232233
* \c or \connect -- connect to database using the specified parameters.
233234
*
234-
* \c dbname user host port
235+
* \c [-reuse-previous=BOOL] dbname user host port
235236
*
236-
* If any of these parameters are omitted or specified as '-', the current
237-
* value of the parameter will be used instead. If the parameter has no
238-
* current value, the default value for that parameter will be used. Some
239-
* examples:
237+
* Specifying a parameter as '-' is equivalent to omitting it. Examples:
240238
*
241239
* \c - - hst Connect to current database on current port of host
242240
* "hst" as current user. \c - usr - prt Connect to current database on
@@ -245,17 +243,31 @@ exec_command(const char *cmd,
245243
*/
246244
else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
247245
{
246+
static const char prefix[] = "-reuse-previous=";
248247
char *opt1,
249248
*opt2,
250249
*opt3,
251250
*opt4;
251+
enum trivalue reuse_previous;
252252

253253
opt1 = read_connect_arg(scan_state);
254+
if (opt1 != NULL && strncmp(opt1, prefix, sizeof(prefix) - 1) == 0)
255+
{
256+
reuse_previous =
257+
ParseVariableBool(opt1 + sizeof(prefix) - 1, prefix) ?
258+
TRI_YES : TRI_NO;
259+
260+
free(opt1);
261+
opt1 = read_connect_arg(scan_state);
262+
}
263+
else
264+
reuse_previous = TRI_DEFAULT;
265+
254266
opt2 = read_connect_arg(scan_state);
255267
opt3 = read_connect_arg(scan_state);
256268
opt4 = read_connect_arg(scan_state);
257269

258-
success = do_connect(opt1, opt2, opt3, opt4);
270+
success = do_connect(reuse_previous, opt1, opt2, opt3, opt4);
259271

260272
free(opt1);
261273
free(opt2);
@@ -1754,22 +1766,25 @@ param_is_newly_set(const char *old_val, const char *new_val)
17541766
/*
17551767
* do_connect -- handler for \connect
17561768
*
1757-
* Connects to a database with given parameters. If there exists an
1758-
* established connection, NULL values will be replaced with the ones
1759-
* in the current connection. Otherwise NULL will be passed for that
1760-
* parameter to PQconnectdbParams(), so the libpq defaults will be used.
1769+
* Connects to a database with given parameters. Absent an established
1770+
* connection, all parameters are required. Given -reuse-previous=off or a
1771+
* connection string without -reuse-previous=on, NULL values will pass through
1772+
* to PQconnectdbParams(), so the libpq defaults will be used. Otherwise, NULL
1773+
* values will be replaced with the ones in the current connection.
17611774
*
17621775
* In interactive mode, if connection fails with the given parameters,
17631776
* the old connection will be kept.
17641777
*/
17651778
static bool
1766-
do_connect(char *dbname, char *user, char *host, char *port)
1779+
do_connect(enum trivalue reuse_previous_specification,
1780+
char *dbname, char *user, char *host, char *port)
17671781
{
17681782
PGconn *o_conn = pset.db,
17691783
*n_conn;
17701784
char *password = NULL;
17711785
bool keep_password;
17721786
bool has_connection_string;
1787+
bool reuse_previous;
17731788

17741789
if (!o_conn && (!dbname || !user || !host || !port))
17751790
{
@@ -1783,17 +1798,36 @@ do_connect(char *dbname, char *user, char *host, char *port)
17831798
return false;
17841799
}
17851800

1786-
/* grab values from the old connection, unless supplied by caller */
1787-
if (!user)
1801+
has_connection_string = dbname ?
1802+
recognized_connection_string(dbname) : false;
1803+
switch (reuse_previous_specification)
1804+
{
1805+
case TRI_YES:
1806+
reuse_previous = true;
1807+
break;
1808+
case TRI_NO:
1809+
reuse_previous = false;
1810+
break;
1811+
default:
1812+
reuse_previous = !has_connection_string;
1813+
break;
1814+
}
1815+
/* Silently ignore arguments subsequent to a connection string. */
1816+
if (has_connection_string)
1817+
{
1818+
user = NULL;
1819+
host = NULL;
1820+
port = NULL;
1821+
}
1822+
1823+
/* grab missing values from the old connection */
1824+
if (!user && reuse_previous)
17881825
user = PQuser(o_conn);
1789-
if (!host)
1826+
if (!host && reuse_previous)
17901827
host = PQhost(o_conn);
1791-
if (!port)
1828+
if (!port && reuse_previous)
17921829
port = PQport(o_conn);
17931830

1794-
has_connection_string =
1795-
dbname ? recognized_connection_string(dbname) : false;
1796-
17971831
/*
17981832
* Any change in the parameters read above makes us discard the password.
17991833
* We also discard it if we're to use a conninfo rather than the
@@ -1808,10 +1842,10 @@ do_connect(char *dbname, char *user, char *host, char *port)
18081842
(port && PQport(o_conn) && strcmp(port, PQport(o_conn)) == 0);
18091843

18101844
/*
1811-
* Grab dbname from old connection unless supplied by caller. No password
1812-
* discard if this changes: passwords aren't (usually) database-specific.
1845+
* Grab missing dbname from old connection. No password discard if this
1846+
* changes: passwords aren't (usually) database-specific.
18131847
*/
1814-
if (!dbname)
1848+
if (!dbname && reuse_previous)
18151849
dbname = PQdb(o_conn);
18161850

18171851
/*
@@ -1842,20 +1876,27 @@ do_connect(char *dbname, char *user, char *host, char *port)
18421876
#define PARAMS_ARRAY_SIZE 8
18431877
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
18441878
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
1845-
int paramnum = 0;
1879+
int paramnum = -1;
18461880

1847-
keywords[0] = "dbname";
1848-
values[0] = dbname;
1881+
keywords[++paramnum] = "host";
1882+
values[paramnum] = host;
1883+
keywords[++paramnum] = "port";
1884+
values[paramnum] = port;
1885+
keywords[++paramnum] = "user";
1886+
values[paramnum] = user;
18491887

1850-
if (!has_connection_string)
1851-
{
1852-
keywords[++paramnum] = "host";
1853-
values[paramnum] = host;
1854-
keywords[++paramnum] = "port";
1855-
values[paramnum] = port;
1856-
keywords[++paramnum] = "user";
1857-
values[paramnum] = user;
1858-
}
1888+
/*
1889+
* Position in the array matters when the dbname is a connection
1890+
* string, because settings in a connection string override earlier
1891+
* array entries only. Thus, user= in the connection string always
1892+
* takes effect, but client_encoding= often will not.
1893+
*
1894+
* If you change this code, also change the initial-connection code in
1895+
* main(). For no good reason, a connection string password= takes
1896+
* precedence in main() but not here.
1897+
*/
1898+
keywords[++paramnum] = "dbname";
1899+
values[paramnum] = dbname;
18591900
keywords[++paramnum] = "password";
18601901
values[paramnum] = password;
18611902
keywords[++paramnum] = "fallback_application_name";

src/bin/psql/startup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ main(int argc, char *argv[])
227227
values[2] = options.username;
228228
keywords[3] = "password";
229229
values[3] = password;
230-
keywords[4] = "dbname";
230+
keywords[4] = "dbname"; /* see do_connect() */
231231
values[4] = (options.list_dbs && options.dbname == NULL) ?
232232
"postgres" : options.dbname;
233233
keywords[5] = "fallback_application_name";

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