summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorNoah Misch2016-08-08 14:07:46 +0000
committerNoah Misch2016-08-08 14:07:46 +0000
commitfcd15f13581f6d75c63d213220d5a94889206c1b (patch)
tree8d089b7347202753584321cd32c9101f05394834 /src/bin
parent41f18f021a0882eccbeca62e2ed4b66c6b96e9c9 (diff)
Obstruct shell, SQL, and conninfo injection via database and role names.
Due to simplistic quoting and confusion of database names with conninfo strings, roles with the CREATEDB or CREATEROLE option could escalate to superuser privileges when a superuser next ran certain maintenance commands. The new coding rule for PQconnectdbParams() calls, documented at conninfo_array_parse(), is to pass expand_dbname=true and wrap literal database names in a trivial connection string. Escape zero-length values in appendConnStrVal(). Back-patch to 9.1 (all supported versions). Nathan Bossart, Michael Paquier, and Noah Misch. Reviewed by Peter Eisentraut. Reported by Nathan Bossart. Security: CVE-2016-5424
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/pg_basebackup/streamutil.c12
-rw-r--r--src/bin/pg_dump/pg_backup.h4
-rw-r--r--src/bin/pg_dump/pg_backup_archiver.c34
-rw-r--r--src/bin/pg_dump/pg_backup_db.c10
-rw-r--r--src/bin/pg_dump/pg_dumpall.c18
-rw-r--r--src/bin/pg_upgrade/Makefile3
-rw-r--r--src/bin/pg_upgrade/check.c19
-rw-r--r--src/bin/pg_upgrade/dump.c16
-rw-r--r--src/bin/pg_upgrade/pg_upgrade.c16
-rw-r--r--src/bin/pg_upgrade/server.c51
-rw-r--r--src/bin/pg_upgrade/test.sh17
-rw-r--r--src/bin/pg_upgrade/version.c11
-rw-r--r--src/bin/psql/command.c15
-rw-r--r--src/bin/scripts/clusterdb.c10
-rw-r--r--src/bin/scripts/reindexdb.c14
-rw-r--r--src/bin/scripts/vacuumdb.c17
16 files changed, 204 insertions, 63 deletions
diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c
index 4d1ff90ee84..72d86570049 100644
--- a/src/bin/pg_basebackup/streamutil.c
+++ b/src/bin/pg_basebackup/streamutil.c
@@ -64,9 +64,15 @@ GetConnection(void)
PQconninfoOption *conn_opt;
char *err_msg = NULL;
+ /* pg_recvlogical uses dbname only; others use connection_string only. */
+ Assert(dbname == NULL || connection_string == NULL);
+
/*
* Merge the connection info inputs given in form of connection string,
* options and default values (dbname=replication, replication=true, etc.)
+ * Explicitly discard any dbname value in the connection string;
+ * otherwise, PQconnectdbParams() would interpret that value as being
+ * itself a connection string.
*/
i = 0;
if (connection_string)
@@ -80,7 +86,8 @@ GetConnection(void)
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
{
- if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
+ if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
+ strcmp(conn_opt->keyword, "dbname") != 0)
argcount++;
}
@@ -89,7 +96,8 @@ GetConnection(void)
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
{
- if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
+ if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
+ strcmp(conn_opt->keyword, "dbname") != 0)
{
keywords[i] = conn_opt->keyword;
values[i] = conn_opt->val;
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index f94caa3cd43..4afa92f5f67 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -103,7 +103,7 @@ typedef struct _restoreOptions
SimpleStringList tableNames;
int useDB;
- char *dbname;
+ char *dbname; /* subject to expand_dbname */
char *pgport;
char *pghost;
char *username;
@@ -121,7 +121,7 @@ typedef struct _restoreOptions
typedef struct _dumpOptions
{
- const char *dbname;
+ const char *dbname; /* subject to expand_dbname */
const char *pghost;
const char *pgport;
const char *username;
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 17a3050c30a..05bdbdbf02a 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -771,9 +771,16 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
/* If we created a DB, connect to it... */
if (strcmp(te->desc, "DATABASE") == 0)
{
+ PQExpBufferData connstr;
+
+ initPQExpBuffer(&connstr);
+ appendPQExpBufferStr(&connstr, "dbname=");
+ appendConnStrVal(&connstr, te->tag);
+ /* Abandon struct, but keep its buffer until process exit. */
+
ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag);
_reconnectToDB(AH, te->tag);
- ropt->dbname = pg_strdup(te->tag);
+ ropt->dbname = connstr.data;
}
}
@@ -2984,12 +2991,17 @@ _reconnectToDB(ArchiveHandle *AH, const char *dbname)
ReconnectToServer(AH, dbname, NULL);
else
{
- PQExpBuffer qry = createPQExpBuffer();
+ if (dbname)
+ {
+ PQExpBufferData connectbuf;
- appendPQExpBuffer(qry, "\\connect %s\n\n",
- dbname ? fmtId(dbname) : "-");
- ahprintf(AH, "%s", qry->data);
- destroyPQExpBuffer(qry);
+ initPQExpBuffer(&connectbuf);
+ appendPsqlMetaConnect(&connectbuf, dbname);
+ ahprintf(AH, "%s\n", connectbuf.data);
+ termPQExpBuffer(&connectbuf);
+ }
+ else
+ ahprintf(AH, "%s\n", "\\connect -\n");
}
/*
@@ -4463,7 +4475,7 @@ CloneArchive(ArchiveHandle *AH)
}
else
{
- char *dbname;
+ PQExpBufferData connstr;
char *pghost;
char *pgport;
char *username;
@@ -4476,14 +4488,18 @@ CloneArchive(ArchiveHandle *AH)
* because all just return a pointer and do not actually send/receive
* any data to/from the database.
*/
- dbname = PQdb(AH->connection);
+ initPQExpBuffer(&connstr);
+ appendPQExpBuffer(&connstr, "dbname=");
+ appendConnStrVal(&connstr, PQdb(AH->connection));
pghost = PQhost(AH->connection);
pgport = PQport(AH->connection);
username = PQuser(AH->connection);
/* this also sets clone->connection */
- ConnectDatabase((Archive *) clone, dbname, pghost, pgport, username, TRI_NO);
+ ConnectDatabase((Archive *) clone, connstr.data,
+ pghost, pgport, username, TRI_NO);
+ termPQExpBuffer(&connstr);
/* setupDumpWorker will fix up connection state */
}
diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
index 352595e49fa..d2a3de3c5de 100644
--- a/src/bin/pg_dump/pg_backup_db.c
+++ b/src/bin/pg_dump/pg_backup_db.c
@@ -12,6 +12,7 @@
#include "postgres_fe.h"
#include "dumputils.h"
+#include "fe_utils/string_utils.h"
#include "parallel.h"
#include "pg_backup_archiver.h"
#include "pg_backup_db.h"
@@ -128,6 +129,7 @@ ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username)
static PGconn *
_connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
{
+ PQExpBufferData connstr;
PGconn *newConn;
const char *newdb;
const char *newuser;
@@ -156,6 +158,10 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
exit_horribly(modulename, "out of memory\n");
}
+ initPQExpBuffer(&connstr);
+ appendPQExpBuffer(&connstr, "dbname=");
+ appendConnStrVal(&connstr, newdb);
+
do
{
const char *keywords[7];
@@ -170,7 +176,7 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
keywords[3] = "password";
values[3] = password;
keywords[4] = "dbname";
- values[4] = newdb;
+ values[4] = connstr.data;
keywords[5] = "fallback_application_name";
values[5] = progname;
keywords[6] = NULL;
@@ -222,6 +228,8 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
if (password)
free(password);
+ termPQExpBuffer(&connstr);
+
/* check for version mismatch */
_check_database_version(AH);
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 0318f961b9e..fdbaa9dffb5 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -1507,7 +1507,7 @@ dumpCreateDB(PGconn *conn)
fdbname, fmtId(dbtablespace));
/* connect to original database */
- appendPQExpBuffer(buf, "\\connect %s\n", fdbname);
+ appendPsqlMetaConnect(buf, dbname);
}
if (binary_upgrade)
@@ -1740,11 +1740,15 @@ dumpDatabases(PGconn *conn)
int ret;
char *dbname = PQgetvalue(res, i, 0);
+ PQExpBufferData connectbuf;
if (verbose)
fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
- fprintf(OPF, "\\connect %s\n\n", fmtId(dbname));
+ initPQExpBuffer(&connectbuf);
+ appendPsqlMetaConnect(&connectbuf, dbname);
+ fprintf(OPF, "%s\n", connectbuf.data);
+ termPQExpBuffer(&connectbuf);
/*
* Restore will need to write to the target cluster. This connection
@@ -1900,7 +1904,9 @@ connectDatabase(const char *dbname, const char *connection_string,
/*
* Merge the connection info inputs given in form of connection string
- * and other options.
+ * and other options. Explicitly discard any dbname value in the
+ * connection string; otherwise, PQconnectdbParams() would interpret
+ * that value as being itself a connection string.
*/
if (connection_string)
{
@@ -1913,7 +1919,8 @@ connectDatabase(const char *dbname, const char *connection_string,
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
{
- if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
+ if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
+ strcmp(conn_opt->keyword, "dbname") != 0)
argcount++;
}
@@ -1922,7 +1929,8 @@ connectDatabase(const char *dbname, const char *connection_string,
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
{
- if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
+ if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
+ strcmp(conn_opt->keyword, "dbname") != 0)
{
keywords[i] = conn_opt->keyword;
values[i] = conn_opt->val;
diff --git a/src/bin/pg_upgrade/Makefile b/src/bin/pg_upgrade/Makefile
index 0c882d9145b..88232887081 100644
--- a/src/bin/pg_upgrade/Makefile
+++ b/src/bin/pg_upgrade/Makefile
@@ -12,11 +12,12 @@ OBJS = check.o controldata.o dump.o exec.o file.o function.o info.o \
tablespace.o util.o version.o $(WIN32RES)
override CPPFLAGS := -DDLSUFFIX=\"$(DLSUFFIX)\" -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS)
+LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq
all: pg_upgrade
-pg_upgrade: $(OBJS) | submake-libpq submake-libpgport
+pg_upgrade: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
$(CC) $(CFLAGS) $^ $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
install: all installdirs
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 324760b074c..f901e3c5125 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -10,6 +10,7 @@
#include "postgres_fe.h"
#include "catalog/pg_authid.h"
+#include "fe_utils/string_utils.h"
#include "mb/pg_wchar.h"
#include "pg_upgrade.h"
@@ -414,12 +415,17 @@ void
create_script_for_cluster_analyze(char **analyze_script_file_name)
{
FILE *script = NULL;
- char *user_specification = "";
+ PQExpBufferData user_specification;
prep_status("Creating script to analyze new cluster");
+ initPQExpBuffer(&user_specification);
if (os_info.user_specified)
- user_specification = psprintf("-U \"%s\" ", os_info.user);
+ {
+ appendPQExpBufferStr(&user_specification, "-U ");
+ appendShellString(&user_specification, os_info.user);
+ appendPQExpBufferChar(&user_specification, ' ');
+ }
*analyze_script_file_name = psprintf("%sanalyze_new_cluster.%s",
SCRIPT_PREFIX, SCRIPT_EXT);
@@ -459,18 +465,18 @@ create_script_for_cluster_analyze(char **analyze_script_file_name)
fprintf(script, "echo %sthis script and run:%s\n",
ECHO_QUOTE, ECHO_QUOTE);
fprintf(script, "echo %s \"%s/vacuumdb\" %s--all %s%s\n", ECHO_QUOTE,
- new_cluster.bindir, user_specification,
+ new_cluster.bindir, user_specification.data,
/* Did we copy the free space files? */
(GET_MAJOR_VERSION(old_cluster.major_version) >= 804) ?
"--analyze-only" : "--analyze", ECHO_QUOTE);
fprintf(script, "echo%s\n\n", ECHO_BLANK);
fprintf(script, "\"%s/vacuumdb\" %s--all --analyze-in-stages\n",
- new_cluster.bindir, user_specification);
+ new_cluster.bindir, user_specification.data);
/* Did we copy the free space files? */
if (GET_MAJOR_VERSION(old_cluster.major_version) < 804)
fprintf(script, "\"%s/vacuumdb\" %s--all\n", new_cluster.bindir,
- user_specification);
+ user_specification.data);
fprintf(script, "echo%s\n\n", ECHO_BLANK);
fprintf(script, "echo %sDone%s\n",
@@ -484,8 +490,7 @@ create_script_for_cluster_analyze(char **analyze_script_file_name)
*analyze_script_file_name, getErrorText());
#endif
- if (os_info.user_specified)
- pg_free(user_specification);
+ termPQExpBuffer(&user_specification);
check_ok();
}
diff --git a/src/bin/pg_upgrade/dump.c b/src/bin/pg_upgrade/dump.c
index 98034ddb611..81fb7253381 100644
--- a/src/bin/pg_upgrade/dump.c
+++ b/src/bin/pg_upgrade/dump.c
@@ -12,6 +12,7 @@
#include "pg_upgrade.h"
#include <sys/types.h>
+#include "fe_utils/string_utils.h"
void
@@ -46,6 +47,15 @@ generate_old_dump(void)
char sql_file_name[MAXPGPATH],
log_file_name[MAXPGPATH];
DbInfo *old_db = &old_cluster.dbarr.dbs[dbnum];
+ PQExpBufferData connstr,
+ escaped_connstr;
+
+ initPQExpBuffer(&connstr);
+ appendPQExpBuffer(&connstr, "dbname=");
+ appendConnStrVal(&connstr, old_db->db_name);
+ initPQExpBuffer(&escaped_connstr);
+ appendShellString(&escaped_connstr, connstr.data);
+ termPQExpBuffer(&connstr);
pg_log(PG_STATUS, "%s", old_db->db_name);
snprintf(sql_file_name, sizeof(sql_file_name), DB_DUMP_FILE_MASK, old_db->db_oid);
@@ -53,10 +63,12 @@ generate_old_dump(void)
parallel_exec_prog(log_file_name, NULL,
"\"%s/pg_dump\" %s --schema-only --quote-all-identifiers "
- "--binary-upgrade --format=custom %s --file=\"%s\" \"%s\"",
+ "--binary-upgrade --format=custom %s --file=\"%s\" %s",
new_cluster.bindir, cluster_conn_opts(&old_cluster),
log_opts.verbose ? "--verbose" : "",
- sql_file_name, old_db->db_name);
+ sql_file_name, escaped_connstr.data);
+
+ termPQExpBuffer(&escaped_connstr);
}
/* reap all children */
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
index 4d9f496ed30..fa118e9e4fd 100644
--- a/src/bin/pg_upgrade/pg_upgrade.c
+++ b/src/bin/pg_upgrade/pg_upgrade.c
@@ -38,6 +38,7 @@
#include "pg_upgrade.h"
#include "common/restricted_token.h"
+#include "fe_utils/string_utils.h"
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
@@ -305,6 +306,15 @@ create_new_objects(void)
char sql_file_name[MAXPGPATH],
log_file_name[MAXPGPATH];
DbInfo *old_db = &old_cluster.dbarr.dbs[dbnum];
+ PQExpBufferData connstr,
+ escaped_connstr;
+
+ initPQExpBuffer(&connstr);
+ appendPQExpBuffer(&connstr, "dbname=");
+ appendConnStrVal(&connstr, old_db->db_name);
+ initPQExpBuffer(&escaped_connstr);
+ appendShellString(&escaped_connstr, connstr.data);
+ termPQExpBuffer(&connstr);
pg_log(PG_STATUS, "%s", old_db->db_name);
snprintf(sql_file_name, sizeof(sql_file_name), DB_DUMP_FILE_MASK, old_db->db_oid);
@@ -316,11 +326,13 @@ create_new_objects(void)
*/
parallel_exec_prog(log_file_name,
NULL,
- "\"%s/pg_restore\" %s --exit-on-error --verbose --dbname \"%s\" \"%s\"",
+ "\"%s/pg_restore\" %s --exit-on-error --verbose --dbname %s \"%s\"",
new_cluster.bindir,
cluster_conn_opts(&new_cluster),
- old_db->db_name,
+ escaped_connstr.data,
sql_file_name);
+
+ termPQExpBuffer(&escaped_connstr);
}
/* reap all children */
diff --git a/src/bin/pg_upgrade/server.c b/src/bin/pg_upgrade/server.c
index 02b736dbd0b..830335f5019 100644
--- a/src/bin/pg_upgrade/server.c
+++ b/src/bin/pg_upgrade/server.c
@@ -9,6 +9,7 @@
#include "postgres_fe.h"
+#include "fe_utils/string_utils.h"
#include "pg_upgrade.h"
@@ -51,18 +52,25 @@ connectToServer(ClusterInfo *cluster, const char *db_name)
static PGconn *
get_db_conn(ClusterInfo *cluster, const char *db_name)
{
- char conn_opts[2 * NAMEDATALEN + MAXPGPATH + 100];
+ PQExpBufferData conn_opts;
+ PGconn *conn;
+ /* Build connection string with proper quoting */
+ initPQExpBuffer(&conn_opts);
+ appendPQExpBufferStr(&conn_opts, "dbname=");
+ appendConnStrVal(&conn_opts, db_name);
+ appendPQExpBufferStr(&conn_opts, " user=");
+ appendConnStrVal(&conn_opts, os_info.user);
+ appendPQExpBuffer(&conn_opts, " port=%d", cluster->port);
if (cluster->sockdir)
- snprintf(conn_opts, sizeof(conn_opts),
- "dbname = '%s' user = '%s' host = '%s' port = %d",
- db_name, os_info.user, cluster->sockdir, cluster->port);
- else
- snprintf(conn_opts, sizeof(conn_opts),
- "dbname = '%s' user = '%s' port = %d",
- db_name, os_info.user, cluster->port);
+ {
+ appendPQExpBufferStr(&conn_opts, " host=");
+ appendConnStrVal(&conn_opts, cluster->sockdir);
+ }
- return PQconnectdb(conn_opts);
+ conn = PQconnectdb(conn_opts.data);
+ termPQExpBuffer(&conn_opts);
+ return conn;
}
@@ -74,23 +82,28 @@ get_db_conn(ClusterInfo *cluster, const char *db_name)
* sets, but the utilities we need aren't very consistent about the treatment
* of database name options, so we leave that out.
*
- * Note result is in static storage, so use it right away.
+ * Result is valid until the next call to this function.
*/
char *
cluster_conn_opts(ClusterInfo *cluster)
{
- static char conn_opts[MAXPGPATH + NAMEDATALEN + 100];
+ static PQExpBuffer buf;
- if (cluster->sockdir)
- snprintf(conn_opts, sizeof(conn_opts),
- "--host \"%s\" --port %d --username \"%s\"",
- cluster->sockdir, cluster->port, os_info.user);
+ if (buf == NULL)
+ buf = createPQExpBuffer();
else
- snprintf(conn_opts, sizeof(conn_opts),
- "--port %d --username \"%s\"",
- cluster->port, os_info.user);
+ resetPQExpBuffer(buf);
+
+ if (cluster->sockdir)
+ {
+ appendPQExpBufferStr(buf, "--host ");
+ appendShellString(buf, cluster->sockdir);
+ appendPQExpBufferChar(buf, ' ');
+ }
+ appendPQExpBuffer(buf, "--port %d --username ", cluster->port);
+ appendShellString(buf, os_info.user);
- return conn_opts;
+ return buf->data;
}
diff --git a/src/bin/pg_upgrade/test.sh b/src/bin/pg_upgrade/test.sh
index ba79fb319f5..d417932301e 100644
--- a/src/bin/pg_upgrade/test.sh
+++ b/src/bin/pg_upgrade/test.sh
@@ -153,6 +153,20 @@ set -x
standard_initdb "$oldbindir"/initdb
"$oldbindir"/pg_ctl start -l "$logdir/postmaster1.log" -o "$POSTMASTER_OPTS" -w
+
+# Create databases with names covering the ASCII bytes other than NUL, BEL,
+# LF, or CR. BEL would ring the terminal bell in the course of this test, and
+# it is not otherwise a special case. PostgreSQL doesn't support the rest.
+dbname1=`awk 'BEGIN { for (i= 1; i < 46; i++)
+ if (i != 7 && i != 10 && i != 13) printf "%c", i }' </dev/null`
+# Exercise backslashes adjacent to double quotes, a Windows special case.
+dbname1='\"\'$dbname1'\\"\\\'
+dbname2=`awk 'BEGIN { for (i = 46; i < 91; i++) printf "%c", i }' </dev/null`
+dbname3=`awk 'BEGIN { for (i = 91; i < 128; i++) printf "%c", i }' </dev/null`
+createdb "$dbname1" || createdb_status=$?
+createdb "$dbname2" || createdb_status=$?
+createdb "$dbname3" || createdb_status=$?
+
if "$MAKE" -C "$oldsrc" installcheck; then
pg_dumpall -f "$temp_root"/dump1.sql || pg_dumpall1_status=$?
if [ "$newsrc" != "$oldsrc" ]; then
@@ -178,6 +192,9 @@ else
make_installcheck_status=$?
fi
"$oldbindir"/pg_ctl -m fast stop
+if [ -n "$createdb_status" ]; then
+ exit 1
+fi
if [ -n "$make_installcheck_status" ]; then
exit 1
fi
diff --git a/src/bin/pg_upgrade/version.c b/src/bin/pg_upgrade/version.c
index 4e49e9a0f95..36c299c1016 100644
--- a/src/bin/pg_upgrade/version.c
+++ b/src/bin/pg_upgrade/version.c
@@ -10,6 +10,7 @@
#include "postgres_fe.h"
#include "pg_upgrade.h"
+#include "fe_utils/string_utils.h"
@@ -48,10 +49,16 @@ new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster, bool check_mode)
found = true;
if (!check_mode)
{
+ PQExpBufferData connectbuf;
+
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText());
- fprintf(script, "\\connect %s\n",
- quote_identifier(active_db->db_name));
+
+ initPQExpBuffer(&connectbuf);
+ appendPsqlMetaConnect(&connectbuf, active_db->db_name);
+ fputs(connectbuf.data, script);
+ termPQExpBuffer(&connectbuf);
+
fprintf(script,
"SELECT pg_catalog.lo_create(t.loid)\n"
"FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) AS t;\n");
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 1608bf414c4..9c0af4e8482 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -1785,6 +1785,7 @@ do_connect(enum trivalue reuse_previous_specification,
bool keep_password;
bool has_connection_string;
bool reuse_previous;
+ PQExpBufferData connstr;
if (!o_conn && (!dbname || !user || !host || !port))
{
@@ -1846,7 +1847,15 @@ do_connect(enum trivalue reuse_previous_specification,
* changes: passwords aren't (usually) database-specific.
*/
if (!dbname && reuse_previous)
- dbname = PQdb(o_conn);
+ {
+ initPQExpBuffer(&connstr);
+ appendPQExpBuffer(&connstr, "dbname=");
+ appendConnStrVal(&connstr, PQdb(o_conn));
+ dbname = connstr.data;
+ /* has_connection_string=true would be a dead store */
+ }
+ else
+ connstr.data = NULL;
/*
* If the user asked to be prompted for a password, ask for one now. If
@@ -1955,8 +1964,12 @@ do_connect(enum trivalue reuse_previous_specification,
}
PQfinish(n_conn);
+ if (connstr.data)
+ termPQExpBuffer(&connstr);
return false;
}
+ if (connstr.data)
+ termPQExpBuffer(&connstr);
/*
* Replace the old connection with the new one, and update
diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c
index 9b816d9c66f..0b16f34d1eb 100644
--- a/src/bin/scripts/clusterdb.c
+++ b/src/bin/scripts/clusterdb.c
@@ -12,6 +12,7 @@
#include "postgres_fe.h"
#include "common.h"
#include "fe_utils/simple_list.h"
+#include "fe_utils/string_utils.h"
static void cluster_one_database(const char *dbname, bool verbose, const char *table,
@@ -229,6 +230,7 @@ cluster_all_databases(bool verbose, const char *maintenance_db,
{
PGconn *conn;
PGresult *result;
+ PQExpBufferData connstr;
int i;
conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
@@ -236,6 +238,7 @@ cluster_all_databases(bool verbose, const char *maintenance_db,
result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo);
PQfinish(conn);
+ initPQExpBuffer(&connstr);
for (i = 0; i < PQntuples(result); i++)
{
char *dbname = PQgetvalue(result, i, 0);
@@ -246,10 +249,15 @@ cluster_all_databases(bool verbose, const char *maintenance_db,
fflush(stdout);
}
- cluster_one_database(dbname, verbose, NULL,
+ resetPQExpBuffer(&connstr);
+ appendPQExpBuffer(&connstr, "dbname=");
+ appendConnStrVal(&connstr, dbname);
+
+ cluster_one_database(connstr.data, verbose, NULL,
host, port, username, prompt_password,
progname, echo);
}
+ termPQExpBuffer(&connstr);
PQclear(result);
}
diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c
index 43f61013ef1..293522c9022 100644
--- a/src/bin/scripts/reindexdb.c
+++ b/src/bin/scripts/reindexdb.c
@@ -331,6 +331,7 @@ reindex_all_databases(const char *maintenance_db,
{
PGconn *conn;
PGresult *result;
+ PQExpBufferData connstr;
int i;
conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
@@ -338,6 +339,7 @@ reindex_all_databases(const char *maintenance_db,
result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo);
PQfinish(conn);
+ initPQExpBuffer(&connstr);
for (i = 0; i < PQntuples(result); i++)
{
char *dbname = PQgetvalue(result, i, 0);
@@ -348,9 +350,15 @@ reindex_all_databases(const char *maintenance_db,
fflush(stdout);
}
- reindex_one_database(dbname, dbname, "DATABASE", host, port, username,
- prompt_password, progname, echo, verbose);
+ resetPQExpBuffer(&connstr);
+ appendPQExpBuffer(&connstr, "dbname=");
+ appendConnStrVal(&connstr, dbname);
+
+ reindex_one_database(NULL, connstr.data, "DATABASE", host,
+ port, username, prompt_password,
+ progname, echo, verbose);
}
+ termPQExpBuffer(&connstr);
PQclear(result);
}
@@ -373,7 +381,7 @@ reindex_system_catalogs(const char *dbname, const char *host, const char *port,
if (verbose)
appendPQExpBuffer(&sql, " (VERBOSE)");
- appendPQExpBuffer(&sql, " SYSTEM %s;", PQdb(conn));
+ appendPQExpBuffer(&sql, " SYSTEM %s;", fmtId(PQdb(conn)));
if (!executeMaintenanceCommand(conn, sql.data, echo))
{
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
index a6bb135e259..c10b58bf0fc 100644
--- a/src/bin/scripts/vacuumdb.c
+++ b/src/bin/scripts/vacuumdb.c
@@ -540,6 +540,7 @@ vacuum_all_databases(vacuumingOptions *vacopts,
{
PGconn *conn;
PGresult *result;
+ PQExpBufferData connstr;
int stage;
int i;
@@ -550,6 +551,7 @@ vacuum_all_databases(vacuumingOptions *vacopts,
progname, echo);
PQfinish(conn);
+ initPQExpBuffer(&connstr);
if (analyze_in_stages)
{
/*
@@ -564,10 +566,11 @@ vacuum_all_databases(vacuumingOptions *vacopts,
{
for (i = 0; i < PQntuples(result); i++)
{
- const char *dbname;
+ resetPQExpBuffer(&connstr);
+ appendPQExpBuffer(&connstr, "dbname=");
+ appendConnStrVal(&connstr, PQgetvalue(result, i, 0));
- dbname = PQgetvalue(result, i, 0);
- vacuum_one_database(dbname, vacopts,
+ vacuum_one_database(connstr.data, vacopts,
stage,
NULL,
host, port, username, prompt_password,
@@ -580,10 +583,11 @@ vacuum_all_databases(vacuumingOptions *vacopts,
{
for (i = 0; i < PQntuples(result); i++)
{
- const char *dbname;
+ resetPQExpBuffer(&connstr);
+ appendPQExpBuffer(&connstr, "dbname=");
+ appendConnStrVal(&connstr, PQgetvalue(result, i, 0));
- dbname = PQgetvalue(result, i, 0);
- vacuum_one_database(dbname, vacopts,
+ vacuum_one_database(connstr.data, vacopts,
ANALYZE_NO_STAGE,
NULL,
host, port, username, prompt_password,
@@ -591,6 +595,7 @@ vacuum_all_databases(vacuumingOptions *vacopts,
progname, echo, quiet);
}
}
+ termPQExpBuffer(&connstr);
PQclear(result);
}