diff --git a/SOURCES/postgresql-9.2.24-CVE-2019-10208.patch b/SOURCES/postgresql-9.2.24-CVE-2019-10208.patch new file mode 100644 index 0000000..6a00250 --- /dev/null +++ b/SOURCES/postgresql-9.2.24-CVE-2019-10208.patch @@ -0,0 +1,188 @@ +diff -u -r postgresql-9.2.24_orig/src/backend/catalog/namespace.c postgresql-9.2.24/src/backend/catalog/namespace.c +--- postgresql-9.2.24_orig/src/backend/catalog/namespace.c 2020-07-07 12:40:46.051801024 +0200 ++++ postgresql-9.2.24/src/backend/catalog/namespace.c 2020-07-07 12:41:06.373887594 +0200 +@@ -740,13 +740,23 @@ + + /* + * TypenameGetTypid ++ * Wrapper for binary compatibility. ++ */ ++Oid ++TypenameGetTypid(const char *typname) ++{ ++ return TypenameGetTypidExtended(typname, true); ++} ++ ++/* ++ * TypenameGetTypidExtended + * Try to resolve an unqualified datatype name. + * Returns OID if type found in search path, else InvalidOid. + * + * This is essentially the same as RelnameGetRelid. + */ + Oid +-TypenameGetTypid(const char *typname) ++TypenameGetTypidExtended(const char *typname, bool temp_ok) + { + Oid typid; + ListCell *l; +@@ -757,6 +767,9 @@ + { + Oid namespaceId = lfirst_oid(l); + ++ if (!temp_ok && namespaceId == myTempNamespace) ++ continue; /* do not look in temp namespace */ ++ + typid = GetSysCacheOid2(TYPENAMENSP, + PointerGetDatum(typname), + ObjectIdGetDatum(namespaceId)); +diff -u -r postgresql-9.2.24_orig/src/backend/parser/parse_func.c postgresql-9.2.24/src/backend/parser/parse_func.c +--- postgresql-9.2.24_orig/src/backend/parser/parse_func.c 2020-07-07 12:40:46.010800850 +0200 ++++ postgresql-9.2.24/src/backend/parser/parse_func.c 2020-07-07 12:41:06.375887602 +0200 +@@ -1377,7 +1377,12 @@ + Oid result; + Type typtup; + +- typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL); ++ /* ++ * temp_ok=false protects the ++ * contract for writing SECURITY DEFINER functions safely. ++ */ ++ typtup = LookupTypeNameExtended(NULL, makeTypeNameFromNameList(funcname), ++ NULL, false, false); + if (typtup == NULL) + return InvalidOid; + +diff -u -r postgresql-9.2.24_orig/src/backend/parser/parse_type.c postgresql-9.2.24/src/backend/parser/parse_type.c +--- postgresql-9.2.24_orig/src/backend/parser/parse_type.c 2020-07-07 12:40:46.013800862 +0200 ++++ postgresql-9.2.24/src/backend/parser/parse_type.c 2020-07-07 12:44:09.366660007 +0200 +@@ -33,6 +33,18 @@ + + /* + * LookupTypeName ++ * Wrapper for typical case. ++ */ ++Type ++LookupTypeName(ParseState *pstate, const TypeName *typeName, ++ int32 *typmod_p) ++{ ++ return LookupTypeNameExtended(pstate, ++ typeName, typmod_p, true, false); ++} ++ ++/* ++ * LookupTypeNameExtended + * Given a TypeName object, lookup the pg_type syscache entry of the type. + * Returns NULL if no such type can be found. If the type is found, + * the typmod value represented in the TypeName struct is computed and +@@ -51,11 +63,17 @@ + * found but is a shell, and there is typmod decoration, an error will be + * thrown --- this is intentional. + * ++ * If temp_ok is false, ignore types in the temporary namespace. Pass false ++ * when the caller will decide, using goodness of fit criteria, whether the ++ * typeName is actually a type or something else. If typeName always denotes ++ * a type (or denotes nothing), pass true. ++ * + * pstate is only used for error location info, and may be NULL. + */ + Type +-LookupTypeName(ParseState *pstate, const TypeName *typeName, +- int32 *typmod_p) ++LookupTypeNameExtended(ParseState *pstate, ++ const TypeName *typeName, int32 *typmod_p, ++ bool temp_ok, bool missing_ok) + { + Oid typoid; + HeapTuple tup; +@@ -156,7 +174,7 @@ + else + { + /* Unqualified type name, so search the search path */ +- typoid = TypenameGetTypid(typname); ++ typoid = TypenameGetTypidExtended(typname, temp_ok); + } + + /* If an array reference, return the array type instead */ +diff -u -r postgresql-9.2.24_orig/src/backend/utils/adt/ruleutils.c postgresql-9.2.24/src/backend/utils/adt/ruleutils.c +--- postgresql-9.2.24_orig/src/backend/utils/adt/ruleutils.c 2020-07-07 12:40:46.022800901 +0200 ++++ postgresql-9.2.24/src/backend/utils/adt/ruleutils.c 2020-07-07 12:41:06.376887607 +0200 +@@ -6421,6 +6421,14 @@ + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, ')'); + } ++ ++ /* ++ * Never emit resulttype(arg) functional notation. A pg_proc entry could ++ * take precedence, and a resulttype in pg_temp would require schema ++ * qualification that format_type_with_typemod() would usually omit. We've ++ * standardized on arg::resulttype, but CAST(arg AS resulttype) notation ++ * would work fine. ++ */ + appendStringInfo(buf, "::%s", + format_type_with_typemod(resulttype, resulttypmod)); + } +diff -u -r postgresql-9.2.24_orig/src/include/catalog/namespace.h postgresql-9.2.24/src/include/catalog/namespace.h +--- postgresql-9.2.24_orig/src/include/catalog/namespace.h 2020-07-07 12:40:45.955800615 +0200 ++++ postgresql-9.2.24/src/include/catalog/namespace.h 2020-07-07 12:41:06.376887607 +0200 +@@ -66,6 +66,7 @@ + extern bool RelationIsVisible(Oid relid); + + extern Oid TypenameGetTypid(const char *typname); ++extern Oid TypenameGetTypidExtended(const char *typname, bool temp_ok); + extern bool TypeIsVisible(Oid typid); + + extern FuncCandidateList FuncnameGetCandidates(List *names, +diff -u -r postgresql-9.2.24_orig/src/include/parser/parse_type.h postgresql-9.2.24/src/include/parser/parse_type.h +--- postgresql-9.2.24_orig/src/include/parser/parse_type.h 2020-07-07 12:40:45.944800568 +0200 ++++ postgresql-9.2.24/src/include/parser/parse_type.h 2020-07-07 13:29:21.426589374 +0200 +@@ -21,6 +21,9 @@ + + extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName, + int32 *typmod_p); ++extern Type LookupTypeNameExtended(ParseState *pstate, ++ const TypeName *typeName, int32 *typmod_p, ++ bool temp_ok, bool missing_ok); + extern Type typenameType(ParseState *pstate, const TypeName *typeName, + int32 *typmod_p); + extern Oid typenameTypeId(ParseState *pstate, const TypeName *typeName); +diff -u -r postgresql-9.2.24_orig/src/test/regress/expected/temp.out postgresql-9.2.24/src/test/regress/expected/temp.out +--- postgresql-9.2.24_orig/src/test/regress/expected/temp.out 2020-07-07 12:40:45.975800701 +0200 ++++ postgresql-9.2.24/src/test/regress/expected/temp.out 2020-07-07 12:41:06.377887611 +0200 +@@ -201,3 +201,18 @@ + (1 row) + + drop table public.whereami; ++-- types in temp schema ++set search_path = pg_temp, public; ++create domain pg_temp.nonempty as text check (value <> ''); ++-- function-syntax invocation of types matches rules for functions ++select nonempty(''); ++ERROR: function nonempty(unknown) does not exist ++LINE 1: select nonempty(''); ++ ^ ++HINT: No function matches the given name and argument types. You might need to add explicit type casts. ++select pg_temp.nonempty(''); ++ERROR: value for domain nonempty violates check constraint "nonempty_check" ++-- other syntax matches rules for tables ++select ''::nonempty; ++ERROR: value for domain nonempty violates check constraint "nonempty_check" ++reset search_path; +diff -u -r postgresql-9.2.24_orig/src/test/regress/sql/temp.sql postgresql-9.2.24/src/test/regress/sql/temp.sql +--- postgresql-9.2.24_orig/src/test/regress/sql/temp.sql 2020-07-07 12:40:45.970800679 +0200 ++++ postgresql-9.2.24/src/test/regress/sql/temp.sql 2020-07-07 12:41:06.377887611 +0200 +@@ -151,3 +151,14 @@ + select pg_temp.whoami(); + + drop table public.whereami; ++ ++-- types in temp schema ++set search_path = pg_temp, public; ++create domain pg_temp.nonempty as text check (value <> ''); ++-- function-syntax invocation of types matches rules for functions ++select nonempty(''); ++select pg_temp.nonempty(''); ++-- other syntax matches rules for tables ++select ''::nonempty; ++ ++reset search_path; diff --git a/SOURCES/postgresql-9.2.24-CVE-2020-25694.patch b/SOURCES/postgresql-9.2.24-CVE-2020-25694.patch new file mode 100644 index 0000000..b1fa7cf --- /dev/null +++ b/SOURCES/postgresql-9.2.24-CVE-2020-25694.patch @@ -0,0 +1,1579 @@ +diff -ru postgresql-9.2.24/src/bin/pg_dump/pg_backup_archiver.c postgresql-9.2.24_new/src/bin/pg_dump/pg_backup_archiver.c +--- postgresql-9.2.24/src/bin/pg_dump/pg_backup_archiver.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/pg_dump/pg_backup_archiver.c 2021-04-13 08:08:24.730000000 +0200 +@@ -368,9 +368,7 @@ + AHX->minRemoteVersion = 0; + AHX->maxRemoteVersion = 999999; + +- ConnectDatabase(AHX, ropt->dbname, +- ropt->pghost, ropt->pgport, ropt->username, +- ropt->promptPassword); ++ ConnectDatabase(AHX, &ropt->cparams, false); + + /* + * If we're talking to the DB directly, don't send comments since they +@@ -640,16 +638,8 @@ + /* 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 = connstr.data; + } + } + +@@ -778,7 +768,7 @@ + + /* set any fields that shouldn't default to zeroes */ + opts->format = archUnknown; +- opts->promptPassword = TRI_DEFAULT; ++ opts->cparams.promptPassword = TRI_DEFAULT; + opts->dumpSections = DUMP_UNSECTIONED; + opts->number_of_jobs = 1; + +@@ -2155,8 +2145,6 @@ + else + AH->format = fmt; + +- AH->promptPassword = TRI_DEFAULT; +- + switch (AH->format) + { + case archCustom: +@@ -2764,7 +2752,7 @@ + _reconnectToDB(ArchiveHandle *AH, const char *dbname) + { + if (RestoringToDB(AH)) +- ReconnectToServer(AH, dbname, NULL); ++ ReconnectToServer(AH, dbname); + else + { + if (dbname) +@@ -2777,7 +2765,13 @@ + termPQExpBuffer(&connectbuf); + } + else ++ { ++ PQExpBufferData connectbuf; ++ initPQExpBuffer(&connectbuf); + ahprintf(AH, "%s\n", "\\connect -\n"); ++ appendPsqlMetaConnect(&connectbuf, dbname); ++ termPQExpBuffer(&connectbuf); ++ } + } + + /* +@@ -2798,7 +2792,8 @@ + AH->currWithOids = -1; + + /* re-establish fixed state */ +- _doSetFixedOutputState(AH); ++ if (AH->mode == archModeRead) ++ _doSetFixedOutputState(AH); + } + + /* +@@ -3775,9 +3770,7 @@ + /* + * Now reconnect the single parent connection. + */ +- ConnectDatabase((Archive *) AH, ropt->dbname, +- ropt->pghost, ropt->pgport, ropt->username, +- ropt->promptPassword); ++ ConnectDatabase((Archive *) AH, &ropt->cparams, true); + + _doSetFixedOutputState(AH); + +@@ -4092,11 +4085,10 @@ + /* + * We need our own database connection, too + */ +- ConnectDatabase((Archive *) AH, ropt->dbname, +- ropt->pghost, ropt->pgport, ropt->username, +- ropt->promptPassword); ++ ConnectDatabase((Archive *) AH, &AH->ropt->cparams, true); + +- _doSetFixedOutputState(AH); ++ if (AH->mode == archModeRead) ++ _doSetFixedOutputState(AH); + + /* Restore the TOC item */ + retval = restore_toc_entry(AH, te, ropt, true); +diff -ru postgresql-9.2.24/src/bin/pg_dump/pg_backup_archiver.h postgresql-9.2.24_new/src/bin/pg_dump/pg_backup_archiver.h +--- postgresql-9.2.24/src/bin/pg_dump/pg_backup_archiver.h 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/pg_dump/pg_backup_archiver.h 2021-04-13 08:08:24.730000000 +0200 +@@ -234,7 +234,6 @@ + + /* Stuff for direct DB connection */ + char *archdbname; /* DB name *read* from archive */ +- enum trivalue promptPassword; + char *savedPassword; /* password for ropt->username, if known */ + PGconn *connection; + int connectToDB; /* Flag to indicate if direct DB connection is +@@ -372,7 +371,7 @@ + + extern bool isValidTarHeader(char *header); + +-extern int ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser); ++extern void ReconnectToServer(ArchiveHandle *AH, const char *dbname); + extern void DropBlobIfExists(ArchiveHandle *AH, Oid oid); + + int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH); +diff -ru postgresql-9.2.24/src/bin/pg_dump/pg_backup_db.c postgresql-9.2.24_new/src/bin/pg_dump/pg_backup_db.c +--- postgresql-9.2.24/src/bin/pg_dump/pg_backup_db.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/pg_dump/pg_backup_db.c 2021-04-13 08:08:54.527000000 +0200 +@@ -10,9 +10,12 @@ + *------------------------------------------------------------------------- + */ + +-#include "pg_backup_db.h" ++#include "postgres_fe.h" ++ + #include "dumpmem.h" + #include "dumputils.h" ++#include "pg_backup_archiver.h" ++#include "pg_backup_db.h" + + #include + #include +@@ -27,7 +30,6 @@ + static const char *modulename = gettext_noop("archiver (db)"); + + static void _check_database_version(ArchiveHandle *AH); +-static PGconn *_connectDB(ArchiveHandle *AH, const char *newdbname, const char *newUser); + static void notice_processor(void *arg, const char *message); + + static int +@@ -74,160 +76,37 @@ + + /* + * Reconnect to the server. If dbname is not NULL, use that database, +- * else the one associated with the archive handle. If username is +- * not NULL, use that user name, else the one from the handle. If +- * both the database and the user match the existing connection already, +- * nothing will be done. +- * +- * Returns 1 in any case. +- */ +-int +-ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username) +-{ +- PGconn *newConn; +- const char *newdbname; +- const char *newusername; +- +- if (!dbname) +- newdbname = PQdb(AH->connection); +- else +- newdbname = dbname; +- +- if (!username) +- newusername = PQuser(AH->connection); +- else +- newusername = username; +- +- /* Let's see if the request is already satisfied */ +- if (strcmp(newdbname, PQdb(AH->connection)) == 0 && +- strcmp(newusername, PQuser(AH->connection)) == 0) +- return 1; +- +- newConn = _connectDB(AH, newdbname, newusername); +- +- PQfinish(AH->connection); +- AH->connection = newConn; +- +- return 1; +-} +- +-/* +- * Connect to the db again. +- * +- * Note: it's not really all that sensible to use a single-entry password +- * cache if the username keeps changing. In current usage, however, the +- * username never does change, so one savedPassword is sufficient. We do +- * update the cache on the off chance that the password has changed since the ++ * else the one associated with the archive handle + * start of the run. + */ +-static PGconn * +-_connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) ++void ++ReconnectToServer(ArchiveHandle *AH, const char *dbname) + { +- PQExpBufferData connstr; +- PGconn *newConn; +- const char *newdb; +- const char *newuser; +- char *password = AH->savedPassword; +- bool new_pass; +- +- if (!reqdb) +- newdb = PQdb(AH->connection); +- else +- newdb = reqdb; +- +- if (!requser || strlen(requser) == 0) +- newuser = PQuser(AH->connection); +- else +- newuser = requser; +- +- ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n", +- newdb, newuser); +- +- if (AH->promptPassword == TRI_YES && password == NULL) +- { +- password = simple_prompt("Password: ", 100, false); +- if (password == NULL) +- exit_horribly(modulename, "out of memory\n"); +- } +- +- initPQExpBuffer(&connstr); +- appendPQExpBuffer(&connstr, "dbname="); +- appendConnStrVal(&connstr, newdb); ++ PGconn *oldConn = AH->connection; ++ RestoreOptions *ropt = AH->ropt; + +- do +- { +-#define PARAMS_ARRAY_SIZE 7 +- const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); +- const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); +- +- keywords[0] = "host"; +- values[0] = PQhost(AH->connection); +- keywords[1] = "port"; +- values[1] = PQport(AH->connection); +- keywords[2] = "user"; +- values[2] = newuser; +- keywords[3] = "password"; +- values[3] = password; +- keywords[4] = "dbname"; +- values[4] = connstr.data; +- keywords[5] = "fallback_application_name"; +- values[5] = progname; +- keywords[6] = NULL; +- values[6] = NULL; +- +- new_pass = false; +- newConn = PQconnectdbParams(keywords, values, true); +- +- free(keywords); +- free(values); +- +- if (!newConn) +- exit_horribly(modulename, "failed to reconnect to database\n"); +- +- if (PQstatus(newConn) == CONNECTION_BAD) +- { +- if (!PQconnectionNeedsPassword(newConn)) +- exit_horribly(modulename, "could not reconnect to database: %s", +- PQerrorMessage(newConn)); +- PQfinish(newConn); +- +- if (password) +- fprintf(stderr, "Password incorrect\n"); +- +- fprintf(stderr, "Connecting to %s as %s\n", +- newdb, newuser); +- +- if (password) +- free(password); +- +- if (AH->promptPassword != TRI_NO) +- password = simple_prompt("Password: ", 100, false); +- else +- exit_horribly(modulename, "connection needs password\n"); +- +- if (password == NULL) +- exit_horribly(modulename, "out of memory\n"); +- new_pass = true; +- } +- } while (new_pass); +- +- AH->savedPassword = password; +- +- termPQExpBuffer(&connstr); +- +- /* check for version mismatch */ +- _check_database_version(AH); +- +- PQsetNoticeProcessor(newConn, notice_processor, NULL); +- +- return newConn; ++ if (dbname) ++ ropt->cparams.override_dbname = pg_strdup(dbname); ++ /* ++ * Note: we want to establish the new connection, and in particular update ++ * ArchiveHandle's connCancel, before closing old connection. Otherwise ++ * an ill-timed SIGINT could try to access a dead connection. ++ */ ++ AH->connection = NULL; /* dodge error check in ConnectDatabase */ ++ ++ ConnectDatabase((Archive *) AH, &ropt->cparams, true); ++ ++ PQfinish(oldConn); + } + + + /* +- * Make a database connection with the given parameters. The +- * connection handle is returned, the parameters are stored in AHX. ++ * Make, or remake, a database connection with the given parameters. ++ * ++ * The resulting connection handle is stored in AHX->connection. ++ * + * An interactive password prompt is automatically issued if required. ++ * We store the results of that in AHX->savedPassword. + * + * Note: it's not really all that sensible to use a single-entry password + * cache if the username keeps changing. In current usage, however, the +@@ -235,26 +114,26 @@ + */ + void + ConnectDatabase(Archive *AHX, +- const char *dbname, +- const char *pghost, +- const char *pgport, +- const char *username, +- enum trivalue prompt_password) ++ const ConnParams *cparams, ++ bool isReconnect) + { + ArchiveHandle *AH = (ArchiveHandle *) AHX; ++ enum trivalue prompt_password; + char *password = AH->savedPassword; + bool new_pass; + + if (AH->connection) + exit_horribly(modulename, "already connected to a database\n"); + ++ /* Never prompt for a password during a reconnection */ ++ prompt_password = isReconnect ? TRI_NO : cparams->promptPassword; ++ + if (prompt_password == TRI_YES && password == NULL) + { + password = simple_prompt("Password: ", 100, false); + if (password == NULL) + exit_horribly(modulename, "out of memory\n"); + } +- AH->promptPassword = prompt_password; + + /* + * Start the connection. Loop until we have a password if requested by +@@ -263,53 +142,70 @@ + do + { + #define PARAMS_ARRAY_SIZE 7 +- const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); +- const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); +- +- keywords[0] = "host"; +- values[0] = pghost; +- keywords[1] = "port"; +- values[1] = pgport; +- keywords[2] = "user"; +- values[2] = username; +- keywords[3] = "password"; +- values[3] = password; +- keywords[4] = "dbname"; +- values[4] = dbname; +- keywords[5] = "fallback_application_name"; +- values[5] = progname; +- keywords[6] = NULL; +- values[6] = NULL; +- +- new_pass = false; +- AH->connection = PQconnectdbParams(keywords, values, true); +- +- free(keywords); +- free(values); +- +- if (!AH->connection) +- exit_horribly(modulename, "failed to connect to database\n"); +- +- if (PQstatus(AH->connection) == CONNECTION_BAD && +- PQconnectionNeedsPassword(AH->connection) && +- password == NULL && +- prompt_password != TRI_NO) +- { +- PQfinish(AH->connection); +- password = simple_prompt("Password: ", 100, false); +- if (password == NULL) +- exit_horribly(modulename, "out of memory\n"); +- new_pass = true; +- } ++ const char *keywords[8]; ++ const char *values[8]; ++ int i = 0; ++ ++ /* ++ * If dbname is a connstring, its entries can override the other ++ * values obtained from cparams; but in turn, override_dbname can ++ * override the dbname component of it. ++ */ ++ keywords[i] = "host"; ++ values[i++] = cparams->pghost; ++ keywords[i] = "port"; ++ values[i++] = cparams->pgport; ++ keywords[i] = "user"; ++ values[i++] = cparams->username; ++ keywords[i] = "password"; ++ values[i++] = password; ++ keywords[i] = "dbname"; ++ values[i++] = cparams->dbname; ++ if (cparams->override_dbname) ++ { ++ keywords[i] = "dbname"; ++ values[i++] = cparams->override_dbname; ++ } ++ keywords[i] = "fallback_application_name"; ++ values[i++] = progname; ++ keywords[i] = NULL; ++ values[i++] = NULL; ++ ++ new_pass = false; ++ AH->connection = PQconnectdbParams(keywords, values, true); ++ ++ ++ if (!AH->connection) ++ exit_horribly(modulename, "failed to connect to database\n"); ++ ++ if (PQstatus(AH->connection) == CONNECTION_BAD && ++ PQconnectionNeedsPassword(AH->connection) && ++ password == NULL && ++ prompt_password != TRI_NO) ++ { ++ PQfinish(AH->connection); ++ password = simple_prompt("Password: ", 100, false); ++ if (password == NULL) ++ exit_horribly(modulename, "out of memory\n"); ++ new_pass = true; ++ } + } while (new_pass); + + AH->savedPassword = password; + + /* check to see that the backend connection was successfully made */ + if (PQstatus(AH->connection) == CONNECTION_BAD) +- exit_horribly(modulename, "connection to database \"%s\" failed: %s", +- PQdb(AH->connection) ? PQdb(AH->connection) : "", +- PQerrorMessage(AH->connection)); ++ { ++ if (isReconnect) ++ exit_horribly(modulename, "reconnection to database \"%s\" failed: %s", ++ PQdb(AH->connection) ? PQdb(AH->connection) : "", ++ PQerrorMessage(AH->connection)); ++ else ++ exit_horribly(modulename, "connection to database \"%s\" failed: %s", ++ PQdb(AH->connection) ? PQdb(AH->connection) : "", ++ PQerrorMessage(AH->connection)); ++ } ++ + + /* check for version mismatch */ + _check_database_version(AH); +diff -ru postgresql-9.2.24/src/bin/pg_dump/pg_backup.h postgresql-9.2.24_new/src/bin/pg_dump/pg_backup.h +--- postgresql-9.2.24/src/bin/pg_dump/pg_backup.h 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/pg_dump/pg_backup.h 2021-04-13 08:08:24.728000000 +0200 +@@ -94,6 +94,20 @@ + + typedef int (*DataDumperPtr) (Archive *AH, void *userArg); + ++/* Parameters needed by ConnectDatabase; same for dump and restore */ ++typedef struct _connParams ++{ ++ /* These fields record the actual command line parameters */ ++ char *dbname; /* this may be a connstring! */ ++ char *pgport; ++ char *pghost; ++ char *username; ++ enum trivalue promptPassword; ++ /* If not NULL, this overrides the dbname obtained from command line */ ++ /* (but *only* the DB name, not anything else in the connstring) */ ++ char *override_dbname; ++} ConnParams; ++ + typedef struct _restoreOptions + { + int createDB; /* Issue commands to create the database */ +@@ -130,10 +144,7 @@ + char *triggerNames; + + int useDB; +- char *dbname; /* subject to expand_dbname */ +- char *pgport; +- char *pghost; +- char *username; ++ ConnParams cparams; + int noDataForFailedTables; + enum trivalue promptPassword; + int exit_on_error; +@@ -152,11 +163,8 @@ + */ + + extern void ConnectDatabase(Archive *AH, +- const char *dbname, +- const char *pghost, +- const char *pgport, +- const char *username, +- enum trivalue prompt_password); ++ const ConnParams *cparams, ++ bool isReconnect); + extern void DisconnectDatabase(Archive *AHX); + extern PGconn *GetConnection(Archive *AHX); + +diff -ru postgresql-9.2.24/src/bin/pg_dump/pg_dump.c postgresql-9.2.24_new/src/bin/pg_dump/pg_dump.c +--- postgresql-9.2.24/src/bin/pg_dump/pg_dump.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/pg_dump/pg_dump.c 2021-04-13 08:08:54.530000000 +0200 +@@ -276,10 +276,7 @@ + int c; + const char *filename = NULL; + const char *format = "p"; +- const char *dbname = NULL; +- const char *pghost = NULL; +- const char *pgport = NULL; +- const char *username = NULL; ++ ConnParams cparams; + const char *dumpencoding = NULL; + bool oids = false; + TableInfo *tblinfo; +@@ -288,7 +285,6 @@ + int numObjs; + DumpableObject *boundaryObjs; + int i; +- enum trivalue prompt_password = TRI_DEFAULT; + int compressLevel = -1; + int plainText = 0; + int outputClean = 0; +@@ -307,7 +303,12 @@ + static int disable_triggers = 0; + static int outputNoTablespaces = 0; + static int use_setsessauth = 0; +- ++ cparams.pghost = NULL; ++ cparams.pgport = NULL; ++ cparams.username = NULL; ++ cparams.dbname = NULL; ++ cparams.override_dbname = NULL; ++ + static struct option long_options[] = { + {"data-only", no_argument, NULL, 'a'}, + {"blobs", no_argument, NULL, 'b'}, +@@ -427,7 +428,7 @@ + break; + + case 'h': /* server host */ +- pghost = optarg; ++ cparams.pghost = optarg; + break; + + case 'i': +@@ -452,7 +453,7 @@ + break; + + case 'p': /* server port */ +- pgport = optarg; ++ cparams.pgport = optarg; + break; + + case 'R': +@@ -477,7 +478,7 @@ + break; + + case 'U': +- username = optarg; ++ cparams.username = optarg; + break; + + case 'v': /* verbose */ +@@ -485,11 +486,11 @@ + break; + + case 'w': +- prompt_password = TRI_NO; ++ cparams.promptPassword = TRI_NO; + break; + + case 'W': +- prompt_password = TRI_YES; ++ cparams.promptPassword = TRI_YES; + break; + + case 'x': /* skip ACL dump */ +@@ -532,8 +533,8 @@ + } + + /* Get database name from command line */ +- if (optind < argc) +- dbname = argv[optind++]; ++ if (optind < argc && cparams.dbname == NULL) ++ cparams.dbname = argv[optind++]; + + /* Complain if any arguments remain */ + if (optind < argc) +@@ -605,7 +606,7 @@ + * Open the database using the Archiver, so it knows about it. Errors mean + * death. + */ +- ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password); ++ ConnectDatabase(fout, &cparams, false); + setup_connection(fout, dumpencoding, use_role); + + /* +@@ -791,9 +792,15 @@ + for (i = 0; i < numObjs; i++) + dumpDumpableObject(fout, dobjs[i]); + ++ ropt=malloc(sizeof(RestoreOptions)); + /* + * Set up options info to ensure we dump what we want. + */ ++ ropt->cparams.dbname = cparams.dbname ? pg_strdup(cparams.dbname) : NULL; ++ ropt->cparams.pgport = cparams.pgport ? pg_strdup(cparams.pgport) : NULL; ++ ropt->cparams.pghost = cparams.pghost ? pg_strdup(cparams.pghost) : NULL; ++ ropt->cparams.username = cparams.username ? pg_strdup(cparams.username) : NULL; ++ ropt->cparams.promptPassword = cparams.promptPassword; + ropt = NewRestoreOptions(); + ropt->filename = filename; + ropt->dropSchema = outputClean; +@@ -837,6 +844,7 @@ + RestoreArchive(fout); + + CloseArchive(fout); ++ free(ropt); + + exit_nicely(0); + } +diff -ru postgresql-9.2.24/src/bin/pg_dump/pg_restore.c postgresql-9.2.24_new/src/bin/pg_dump/pg_restore.c +--- postgresql-9.2.24/src/bin/pg_dump/pg_restore.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/pg_dump/pg_restore.c 2021-04-13 08:08:24.736000000 +0200 +@@ -162,7 +162,7 @@ + opts->createDB = 1; + break; + case 'd': +- opts->dbname = pg_strdup(optarg); ++ opts->cparams.dbname = pg_strdup(optarg); + break; + case 'e': + opts->exit_on_error = true; +@@ -176,7 +176,7 @@ + break; + case 'h': + if (strlen(optarg) != 0) +- opts->pghost = pg_strdup(optarg); ++ opts->cparams.pghost = pg_strdup(optarg); + break; + case 'i': + /* ignored, deprecated option */ +@@ -204,7 +204,7 @@ + + case 'p': + if (strlen(optarg) != 0) +- opts->pgport = pg_strdup(optarg); ++ opts->cparams.pgport = pg_strdup(optarg); + break; + case 'R': + /* no-op, still accepted for backwards compatibility */ +@@ -238,7 +238,7 @@ + break; + + case 'U': +- opts->username = optarg; ++ opts->cparams.username = optarg; + break; + + case 'v': /* verbose */ +@@ -246,11 +246,11 @@ + break; + + case 'w': +- opts->promptPassword = TRI_NO; ++ opts->cparams.promptPassword = TRI_NO; + break; + + case 'W': +- opts->promptPassword = TRI_YES; ++ opts->cparams.promptPassword = TRI_YES; + break; + + case 'x': /* skip ACL dump */ +@@ -300,7 +300,7 @@ + } + + /* Should get at most one of -d and -f, else user is confused */ +- if (opts->dbname) ++ if (opts->cparams.dbname) + { + if (opts->filename) + { +diff -ru postgresql-9.2.24/src/bin/scripts/clusterdb.c postgresql-9.2.24_new/src/bin/scripts/clusterdb.c +--- postgresql-9.2.24/src/bin/scripts/clusterdb.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/clusterdb.c 2021-04-13 08:08:24.736000000 +0200 +@@ -14,14 +14,10 @@ + #include "dumputils.h" + + +-static void cluster_one_database(const char *dbname, bool verbose, const char *table, +- const char *host, const char *port, +- const char *username, enum trivalue prompt_password, +- const char *progname, bool echo); +-static void cluster_all_databases(bool verbose, const char *maintenance_db, +- const char *host, const char *port, +- const char *username, enum trivalue prompt_password, +- const char *progname, bool echo, bool quiet); ++static void cluster_one_database(const ConnParams *cparams, const char *table, ++ const char *progname, bool verbose, bool echo); ++static void cluster_all_databases(ConnParams *cparams, const char *progname, ++ bool verbose, bool echo, bool quiet); + + static void help(const char *progname); + +@@ -55,6 +51,7 @@ + char *port = NULL; + char *username = NULL; + enum trivalue prompt_password = TRI_DEFAULT; ++ ConnParams cparams; + bool echo = false; + bool quiet = false; + bool alldb = false; +@@ -130,6 +127,13 @@ + exit(1); + } + ++ /* fill cparams except for dbname, which is set below */ ++ cparams.pghost = host; ++ cparams.pgport = port; ++ cparams.pguser = username; ++ cparams.prompt_password = prompt_password; ++ cparams.override_dbname = NULL; ++ + setup_cancel_handler(); + + if (alldb) +@@ -147,8 +151,9 @@ + exit(1); + } + +- cluster_all_databases(verbose, maintenance_db, host, port, username, prompt_password, +- progname, echo, quiet); ++ cparams.dbname = maintenance_db; ++ ++ cluster_all_databases(&cparams, progname, verbose, echo, quiet); + } + else + { +@@ -162,9 +167,9 @@ + dbname = get_user_name(progname); + } + +- cluster_one_database(dbname, verbose, table, +- host, port, username, prompt_password, +- progname, echo); ++ cparams.dbname = dbname; ++ ++ cluster_one_database(&cparams, table, progname, verbose, echo); + } + + exit(0); +@@ -172,10 +177,8 @@ + + + static void +-cluster_one_database(const char *dbname, bool verbose, const char *table, +- const char *host, const char *port, +- const char *username, enum trivalue prompt_password, +- const char *progname, bool echo) ++cluster_one_database(const ConnParams *cparams, const char *table, ++ const char *progname, bool verbose, bool echo) + { + PQExpBufferData sql; + +@@ -190,8 +193,7 @@ + appendPQExpBuffer(&sql, " %s", table); + appendPQExpBuffer(&sql, ";\n"); + +- conn = connectDatabase(dbname, host, port, username, prompt_password, +- progname, false); ++ conn = connectDatabase(cparams, progname, echo, false, false); + if (!executeMaintenanceCommand(conn, sql.data, echo)) + { + if (table) +@@ -209,22 +211,17 @@ + + + static void +-cluster_all_databases(bool verbose, const char *maintenance_db, +- const char *host, const char *port, +- const char *username, enum trivalue prompt_password, +- const char *progname, bool echo, bool quiet) ++cluster_all_databases(ConnParams *cparams, const char *progname, ++ bool verbose, bool echo, bool quiet) + { + PGconn *conn; + PGresult *result; +- PQExpBufferData connstr; + int i; + +- conn = connectMaintenanceDatabase(maintenance_db, host, port, username, +- prompt_password, progname); ++ conn = connectMaintenanceDatabase(cparams, progname, echo); + 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); +@@ -235,15 +232,10 @@ + fflush(stdout); + } + +- resetPQExpBuffer(&connstr); +- appendPQExpBuffer(&connstr, "dbname="); +- appendConnStrVal(&connstr, dbname); +- +- cluster_one_database(connstr.data, verbose, NULL, +- host, port, username, prompt_password, +- progname, echo); ++ cparams->override_dbname = dbname; ++ ++ cluster_one_database(cparams, NULL, progname, verbose, echo); + } +- termPQExpBuffer(&connstr); + + PQclear(result); + } +diff -ru postgresql-9.2.24/src/bin/scripts/common.c postgresql-9.2.24_new/src/bin/scripts/common.c +--- postgresql-9.2.24/src/bin/scripts/common.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/common.c 2021-04-13 08:08:54.530000000 +0200 +@@ -91,15 +91,14 @@ + * interactive password prompt is automatically issued if required. + */ + PGconn * +-connectDatabase(const char *dbname, const char *pghost, const char *pgport, +- const char *pguser, enum trivalue prompt_password, +- const char *progname, bool fail_ok) ++connectDatabase(const ConnParams *cparams, const char *progname, ++ bool echo, bool fail_ok, bool allow_password_reuse) + { + PGconn *conn; + char *password = NULL; + bool new_pass; + +- if (prompt_password == TRI_YES) ++ if (cparams->prompt_password == TRI_YES) + password = simple_prompt("Password: ", 100, false); + + /* +@@ -109,47 +108,50 @@ + do + { + #define PARAMS_ARRAY_SIZE 7 +- const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); +- const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); +- +- if (!keywords || !values) ++ const char *keywords[8]; ++ const char *values[8]; ++ int i = 0; ++ ++ /* ++ * If dbname is a connstring, its entries can override the other ++ * values obtained from cparams; but in turn, override_dbname can ++ * override the dbname component of it. ++ */ ++ keywords[i] = "host"; ++ values[i++] = cparams->pghost; ++ keywords[i] = "port"; ++ values[i++] = cparams->pgport; ++ keywords[i] = "user"; ++ values[i++] = cparams->pguser; ++ keywords[i] = "password"; ++ values[i++] = password; ++ keywords[i] = "dbname"; ++ values[i++] = cparams->dbname; ++ if (cparams->override_dbname) + { +- fprintf(stderr, _("%s: out of memory\n"), progname); +- exit(1); ++ keywords[i] = "dbname"; ++ values[i++] = cparams->override_dbname; + } +- +- keywords[0] = "host"; +- values[0] = pghost; +- keywords[1] = "port"; +- values[1] = pgport; +- keywords[2] = "user"; +- values[2] = pguser; +- keywords[3] = "password"; +- values[3] = password; +- keywords[4] = "dbname"; +- values[4] = dbname; +- keywords[5] = "fallback_application_name"; +- values[5] = progname; +- keywords[6] = NULL; +- values[6] = NULL; ++ keywords[i] = "fallback_application_name"; ++ values[i++] = progname; ++ keywords[i] = NULL; ++ values[i++] = NULL; + + new_pass = false; + conn = PQconnectdbParams(keywords, values, true); + +- free(keywords); +- free(values); + + if (!conn) + { + fprintf(stderr, _("%s: could not connect to database %s\n"), +- progname, dbname); ++ progname, cparams->dbname); + exit(1); + } + + if (PQstatus(conn) == CONNECTION_BAD && +- PQconnectionNeedsPassword(conn) && +- password == NULL && +- prompt_password != TRI_NO) ++ PQconnectionNeedsPassword(conn) && ++ password == NULL && ++ cparams->prompt_password != TRI_NO) + { + PQfinish(conn); + password = simple_prompt("Password: ", 100, false); +@@ -169,7 +171,7 @@ + return NULL; + } + fprintf(stderr, _("%s: could not connect to database %s: %s"), +- progname, dbname, PQerrorMessage(conn)); ++ progname, cparams->dbname, PQerrorMessage(conn)); + exit(1); + } + +@@ -178,26 +180,29 @@ + + /* + * Try to connect to the appropriate maintenance database. ++ * ++ * This differs from connectDatabase only in that it has a rule for ++ * inserting a default "dbname" if none was given (which is why cparams ++ * is not const). Note that cparams->dbname should typically come from ++ * a --maintenance-db command line parameter. + */ + PGconn * +-connectMaintenanceDatabase(const char *maintenance_db, const char *pghost, +- const char *pgport, const char *pguser, +- enum trivalue prompt_password, +- const char *progname) ++connectMaintenanceDatabase(ConnParams *cparams, const char *progname, bool echo) + { + PGconn *conn; + + /* If a maintenance database name was specified, just connect to it. */ +- if (maintenance_db) +- return connectDatabase(maintenance_db, pghost, pgport, pguser, +- prompt_password, progname, false); ++ if (cparams->dbname) ++ return connectDatabase(cparams, progname, echo, false, false); + + /* Otherwise, try postgres first and then template1. */ +- conn = connectDatabase("postgres", pghost, pgport, pguser, prompt_password, +- progname, true); ++ cparams->dbname = "postgres"; ++ conn = connectDatabase(cparams, progname, echo, true, false); + if (!conn) +- conn = connectDatabase("template1", pghost, pgport, pguser, +- prompt_password, progname, false); ++ { ++ cparams->dbname = "template1"; ++ conn = connectDatabase(cparams, progname, echo, false, false); ++ } + + return conn; + } +diff -ru postgresql-9.2.24/src/bin/scripts/common.h postgresql-9.2.24_new/src/bin/scripts/common.h +--- postgresql-9.2.24/src/bin/scripts/common.h 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/common.h 2021-04-13 08:08:24.737000000 +0200 +@@ -20,6 +20,20 @@ + TRI_YES + }; + ++/* Parameters needed by connectDatabase/connectMaintenanceDatabase */ ++typedef struct _connParams ++{ ++ /* These fields record the actual command line parameters */ ++ const char *dbname; /* this may be a connstring! */ ++ const char *pghost; ++ const char *pgport; ++ const char *pguser; ++ enum trivalue prompt_password; ++ /* If not NULL, this overrides the dbname obtained from command line */ ++ /* (but *only* the DB name, not anything else in the connstring) */ ++ const char *override_dbname; ++} ConnParams; ++ + typedef void (*help_handler) (const char *progname); + + extern const char *get_user_name(const char *progname); +@@ -28,14 +42,13 @@ + const char *fixed_progname, + help_handler hlp); + +-extern PGconn *connectDatabase(const char *dbname, const char *pghost, +- const char *pgport, const char *pguser, +- enum trivalue prompt_password, const char *progname, +- bool fail_ok); +- +-extern PGconn *connectMaintenanceDatabase(const char *maintenance_db, +- const char *pghost, const char *pgport, const char *pguser, +- enum trivalue prompt_password, const char *progname); ++extern PGconn *connectDatabase(const ConnParams *cparams, ++ const char *progname, ++ bool echo, bool fail_ok, ++ bool allow_password_reuse); ++ ++extern PGconn *connectMaintenanceDatabase(ConnParams *cparams, ++ const char *progname, bool echo); + + extern PGresult *executeQuery(PGconn *conn, const char *query, + const char *progname, bool echo); +diff -ru postgresql-9.2.24/src/bin/scripts/createdb.c postgresql-9.2.24_new/src/bin/scripts/createdb.c +--- postgresql-9.2.24/src/bin/scripts/createdb.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/createdb.c 2021-04-13 08:08:24.737000000 +0200 +@@ -50,6 +50,7 @@ + char *port = NULL; + char *username = NULL; + enum trivalue prompt_password = TRI_DEFAULT; ++ ConnParams cparams; + bool echo = false; + char *owner = NULL; + char *tablespace = NULL; +@@ -201,8 +202,14 @@ + if (maintenance_db == NULL && strcmp(dbname, "postgres") == 0) + maintenance_db = "template1"; + +- conn = connectMaintenanceDatabase(maintenance_db, host, port, username, +- prompt_password, progname); ++ cparams.dbname = maintenance_db; ++ cparams.pghost = host; ++ cparams.pgport = port; ++ cparams.pguser = username; ++ cparams.prompt_password = prompt_password; ++ cparams.override_dbname = NULL; ++ ++ conn = connectMaintenanceDatabase(&cparams, progname, echo); + + if (echo) + printf("%s", sql.data); +diff -ru postgresql-9.2.24/src/bin/scripts/createlang.c postgresql-9.2.24_new/src/bin/scripts/createlang.c +--- postgresql-9.2.24/src/bin/scripts/createlang.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/createlang.c 2021-04-13 08:08:24.737000000 +0200 +@@ -42,6 +42,7 @@ + char *port = NULL; + char *username = NULL; + enum trivalue prompt_password = TRI_DEFAULT; ++ ConnParams cparams; + bool echo = false; + char *langname = NULL; + +@@ -130,6 +131,13 @@ + dbname = get_user_name(progname); + } + ++ cparams.dbname = dbname; ++ cparams.pghost = host; ++ cparams.pgport = port; ++ cparams.pguser = username; ++ cparams.prompt_password = prompt_password; ++ cparams.override_dbname = NULL; ++ + initPQExpBuffer(&sql); + + /* +@@ -140,8 +148,8 @@ + printQueryOpt popt; + static const bool translate_columns[] = {false, true}; + +- conn = connectDatabase(dbname, host, port, username, prompt_password, +- progname, false); ++ conn = connectDatabase(&cparams, ++ progname, echo, false, false); + + printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", " + "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" " +@@ -178,8 +186,8 @@ + if (*p >= 'A' && *p <= 'Z') + *p += ('a' - 'A'); + +- conn = connectDatabase(dbname, host, port, username, prompt_password, +- progname, false); ++ conn = connectDatabase(&cparams, ++ progname, echo, false, false); + + /* + * Make sure the language isn't already installed +diff -ru postgresql-9.2.24/src/bin/scripts/createuser.c postgresql-9.2.24_new/src/bin/scripts/createuser.c +--- postgresql-9.2.24/src/bin/scripts/createuser.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/createuser.c 2021-04-13 08:08:24.738000000 +0200 +@@ -58,6 +58,7 @@ + char *port = NULL; + char *username = NULL; + enum trivalue prompt_password = TRI_DEFAULT; ++ ConnParams cparams; + bool echo = false; + bool interactive = false; + char *conn_limit = NULL; +@@ -245,8 +246,14 @@ + if (login == 0) + login = TRI_YES; + +- conn = connectDatabase("postgres", host, port, username, prompt_password, +- progname, false); ++ cparams.dbname = NULL; /* this program lacks any dbname option... */ ++ cparams.pghost = host; ++ cparams.pgport = port; ++ cparams.pguser = username; ++ cparams.prompt_password = prompt_password; ++ cparams.override_dbname = NULL; ++ ++ conn = connectMaintenanceDatabase(&cparams, progname, echo); + + initPQExpBuffer(&sql); + +diff -ru postgresql-9.2.24/src/bin/scripts/dropdb.c postgresql-9.2.24_new/src/bin/scripts/dropdb.c +--- postgresql-9.2.24/src/bin/scripts/dropdb.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/dropdb.c 2021-04-13 08:08:24.738000000 +0200 +@@ -46,6 +46,7 @@ + char *port = NULL; + char *username = NULL; + enum trivalue prompt_password = TRI_DEFAULT; ++ ConnParams cparams; + bool echo = false; + bool interactive = false; + +@@ -128,8 +129,14 @@ + if (maintenance_db == NULL && strcmp(dbname, "postgres") == 0) + maintenance_db = "template1"; + +- conn = connectMaintenanceDatabase(maintenance_db, +- host, port, username, prompt_password, progname); ++ cparams.dbname = maintenance_db; ++ cparams.pghost = host; ++ cparams.pgport = port; ++ cparams.pguser = username; ++ cparams.prompt_password = prompt_password; ++ cparams.override_dbname = NULL; ++ ++ conn = connectMaintenanceDatabase(&cparams, progname, echo); + + if (echo) + printf("%s", sql.data); +diff -ru postgresql-9.2.24/src/bin/scripts/droplang.c postgresql-9.2.24_new/src/bin/scripts/droplang.c +--- postgresql-9.2.24/src/bin/scripts/droplang.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/droplang.c 2021-04-13 08:08:24.738000000 +0200 +@@ -44,6 +44,7 @@ + char *port = NULL; + char *username = NULL; + enum trivalue prompt_password = TRI_DEFAULT; ++ ConnParams cparams; + bool echo = false; + char *langname = NULL; + char *p; +@@ -129,6 +130,13 @@ + dbname = get_user_name(progname); + } + ++ cparams.dbname = dbname; ++ cparams.pghost = host; ++ cparams.pgport = port; ++ cparams.pguser = username; ++ cparams.prompt_password = prompt_password; ++ cparams.override_dbname = NULL; ++ + initPQExpBuffer(&sql); + + /* +@@ -139,8 +147,8 @@ + printQueryOpt popt; + static const bool translate_columns[] = {false, true}; + +- conn = connectDatabase(dbname, host, port, username, prompt_password, +- progname, false); ++ conn = connectDatabase(&cparams, ++ progname, echo, false, false); + + printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", " + "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" " +@@ -179,8 +187,8 @@ + if (*p >= 'A' && *p <= 'Z') + *p += ('a' - 'A'); + +- conn = connectDatabase(dbname, host, port, username, prompt_password, +- progname, false); ++ conn = connectDatabase(&cparams, ++ progname, echo, false, false); + + /* + * Force schema search path to be just pg_catalog, so that we don't have +diff -ru postgresql-9.2.24/src/bin/scripts/dropuser.c postgresql-9.2.24_new/src/bin/scripts/dropuser.c +--- postgresql-9.2.24/src/bin/scripts/dropuser.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/dropuser.c 2021-04-13 08:08:24.738000000 +0200 +@@ -44,6 +44,7 @@ + char *port = NULL; + char *username = NULL; + enum trivalue prompt_password = TRI_DEFAULT; ++ ConnParams cparams; + bool echo = false; + bool interactive = false; + +@@ -124,13 +125,19 @@ + exit(0); + } + ++ cparams.dbname = NULL; /* this program lacks any dbname option... */ ++ cparams.pghost = host; ++ cparams.pgport = port; ++ cparams.pguser = username; ++ cparams.prompt_password = prompt_password; ++ cparams.override_dbname = NULL; ++ ++ conn = connectMaintenanceDatabase(&cparams, progname, echo); ++ + initPQExpBuffer(&sql); + appendPQExpBuffer(&sql, "DROP ROLE %s%s;\n", + (if_exists ? "IF EXISTS " : ""), fmtId(dropuser)); + +- conn = connectDatabase("postgres", host, port, username, prompt_password, +- progname, false); +- + if (echo) + printf("%s", sql.data); + result = PQexec(conn, sql.data); +diff -ru postgresql-9.2.24/src/bin/scripts/reindexdb.c postgresql-9.2.24_new/src/bin/scripts/reindexdb.c +--- postgresql-9.2.24/src/bin/scripts/reindexdb.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/reindexdb.c 2021-04-13 08:08:24.739000000 +0200 +@@ -14,20 +14,15 @@ + #include "dumputils.h" + + +-static void reindex_one_database(const char *name, const char *dbname, +- const char *type, const char *host, +- const char *port, const char *username, +- enum trivalue prompt_password, const char *progname, +- bool echo); +-static void reindex_all_databases(const char *maintenance_db, +- const char *host, const char *port, +- const char *username, enum trivalue prompt_password, +- const char *progname, bool echo, +- bool quiet); +-static void reindex_system_catalogs(const char *dbname, +- const char *host, const char *port, +- const char *username, enum trivalue prompt_password, +- const char *progname, bool echo); ++static void reindex_one_database(const ConnParams *cparams, ++ const char *type, const char *name, ++ const char *progname, ++ bool echo); ++static void reindex_all_databases(ConnParams *cparams, ++ const char *progname, bool echo, ++ bool quiet); ++static void reindex_system_catalogs(const ConnParams *cparams, ++ const char *progname, bool echo); + static void help(const char *progname); + + int +@@ -60,6 +55,7 @@ + const char *port = NULL; + const char *username = NULL; + enum trivalue prompt_password = TRI_DEFAULT; ++ ConnParams cparams; + bool syscatalog = false; + bool alldb = false; + bool echo = false; +@@ -140,6 +136,13 @@ + exit(1); + } + ++ /* fill cparams except for dbname, which is set below */ ++ cparams.pghost = host; ++ cparams.pgport = port; ++ cparams.pguser = username; ++ cparams.prompt_password = prompt_password; ++ cparams.override_dbname = NULL; ++ + setup_cancel_handler(); + + if (alldb) +@@ -165,8 +168,9 @@ + exit(1); + } + +- reindex_all_databases(maintenance_db, host, port, username, +- prompt_password, progname, echo, quiet); ++ cparams.dbname = maintenance_db; ++ ++ reindex_all_databases(&cparams, progname, echo, quiet); + } + else if (syscatalog) + { +@@ -191,8 +195,9 @@ + dbname = get_user_name(progname); + } + +- reindex_system_catalogs(dbname, host, port, username, prompt_password, +- progname, echo); ++ cparams.dbname = dbname; ++ ++ reindex_system_catalogs(&cparams, progname, echo); + } + else + { +@@ -206,32 +211,34 @@ + dbname = get_user_name(progname); + } + ++ cparams.dbname = dbname; ++ + if (index) +- reindex_one_database(index, dbname, "INDEX", host, port, +- username, prompt_password, progname, echo); ++ reindex_one_database(&cparams, "INDEX", table, ++ progname, echo); + if (table) +- reindex_one_database(table, dbname, "TABLE", host, port, +- username, prompt_password, progname, echo); ++ reindex_one_database(&cparams, "TABLE", table, ++ progname, echo); + /* reindex database only if index or table is not specified */ + if (index == NULL && table == NULL) +- reindex_one_database(NULL, dbname, "DATABASE", host, port, +- username, prompt_password, progname, echo); ++ reindex_one_database(&cparams, "DATABASE", table, ++ progname, echo); + } + + exit(0); + } + + static void +-reindex_one_database(const char *name, const char *dbname, const char *type, +- const char *host, const char *port, const char *username, +- enum trivalue prompt_password, const char *progname, bool echo) ++reindex_one_database(const ConnParams *cparams, ++ const char *type, const char *name, ++ const char *progname, ++ bool echo) + { + PQExpBufferData sql; + + PGconn *conn; + +- conn = connectDatabase(dbname, host, port, username, prompt_password, +- progname, false); ++ conn = connectDatabase(cparams, progname, echo, false, false); + + initPQExpBuffer(&sql); + +@@ -264,22 +271,17 @@ + } + + static void +-reindex_all_databases(const char *maintenance_db, +- const char *host, const char *port, +- const char *username, enum trivalue prompt_password, +- const char *progname, bool echo, bool quiet) ++reindex_all_databases(ConnParams *cparams, const char *progname, bool echo, bool quiet) + { + PGconn *conn; + PGresult *result; + PQExpBufferData connstr; + int i; + +- conn = connectMaintenanceDatabase(maintenance_db, host, port, username, +- prompt_password, progname); ++ conn = connectMaintenanceDatabase(cparams, progname, echo); + 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); +@@ -293,26 +295,22 @@ + resetPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, dbname); ++ cparams->override_dbname = dbname; + +- reindex_one_database(NULL, connstr.data, "DATABASE", host, +- port, username, prompt_password, +- progname, echo); ++ reindex_one_database(cparams, "DATABASE", NULL, progname, echo); + } +- termPQExpBuffer(&connstr); + + PQclear(result); + } + + static void +-reindex_system_catalogs(const char *dbname, const char *host, const char *port, +- const char *username, enum trivalue prompt_password, +- const char *progname, bool echo) ++reindex_system_catalogs(const ConnParams *cparams, ++ const char *progname, bool echo) + { + PGconn *conn; + PQExpBufferData sql; + +- conn = connectDatabase(dbname, host, port, username, prompt_password, +- progname, false); ++ conn = connectDatabase(cparams, progname, echo, false, false); + + initPQExpBuffer(&sql); + +diff -ru postgresql-9.2.24/src/bin/scripts/vacuumdb.c postgresql-9.2.24_new/src/bin/scripts/vacuumdb.c +--- postgresql-9.2.24/src/bin/scripts/vacuumdb.c 2017-11-06 23:17:39.000000000 +0100 ++++ postgresql-9.2.24_new/src/bin/scripts/vacuumdb.c 2021-04-13 08:08:24.739000000 +0200 +@@ -15,16 +15,13 @@ + #include "dumputils.h" + + +-static void vacuum_one_database(const char *dbname, bool full, bool verbose, ++static void vacuum_one_database(const ConnParams *cparams, bool full, bool verbose, + bool and_analyze, bool analyze_only, bool freeze, +- const char *table, const char *host, const char *port, +- const char *username, enum trivalue prompt_password, +- const char *progname, bool echo); +-static void vacuum_all_databases(bool full, bool verbose, bool and_analyze, ++ const char *table, const char *progname, bool echo); ++ ++static void vacuum_all_databases(ConnParams *cparams, bool full, bool verbose, ++ bool and_analyze, + bool analyze_only, bool freeze, +- const char *maintenance_db, +- const char *host, const char *port, +- const char *username, enum trivalue prompt_password, + const char *progname, bool echo, bool quiet); + + static void help(const char *progname); +@@ -63,6 +60,7 @@ + char *port = NULL; + char *username = NULL; + enum trivalue prompt_password = TRI_DEFAULT; ++ ConnParams cparams; + bool echo = false; + bool quiet = false; + bool and_analyze = false; +@@ -172,6 +170,13 @@ + /* allow 'and_analyze' with 'analyze_only' */ + } + ++ /* fill cparams except for dbname, which is set below */ ++ cparams.pghost = host; ++ cparams.pgport = port; ++ cparams.pguser = username; ++ cparams.prompt_password = prompt_password; ++ cparams.override_dbname = NULL; ++ + setup_cancel_handler(); + + if (alldb) +@@ -189,9 +194,10 @@ + exit(1); + } + +- vacuum_all_databases(full, verbose, and_analyze, analyze_only, freeze, +- maintenance_db, host, port, username, +- prompt_password, progname, echo, quiet); ++ cparams.dbname = maintenance_db; ++ ++ vacuum_all_databases(&cparams, full, verbose, and_analyze, analyze_only, freeze, ++ progname, echo, quiet); + } + else + { +@@ -205,9 +211,10 @@ + dbname = get_user_name(progname); + } + +- vacuum_one_database(dbname, full, verbose, and_analyze, analyze_only, ++ cparams.dbname = dbname; ++ ++ vacuum_one_database(&cparams, full, verbose, and_analyze, analyze_only, + freeze, table, +- host, port, username, prompt_password, + progname, echo); + } + +@@ -216,10 +223,8 @@ + + + static void +-vacuum_one_database(const char *dbname, bool full, bool verbose, bool and_analyze, ++vacuum_one_database(const ConnParams *cparams, bool full, bool verbose, bool and_analyze, + bool analyze_only, bool freeze, const char *table, +- const char *host, const char *port, +- const char *username, enum trivalue prompt_password, + const char *progname, bool echo) + { + PQExpBufferData sql; +@@ -228,8 +233,7 @@ + + initPQExpBuffer(&sql); + +- conn = connectDatabase(dbname, host, port, username, prompt_password, +- progname, false); ++ conn = connectDatabase(cparams, progname, echo, false, true); + + if (analyze_only) + { +@@ -302,19 +306,15 @@ + + + static void +-vacuum_all_databases(bool full, bool verbose, bool and_analyze, bool analyze_only, +- bool freeze, const char *maintenance_db, +- const char *host, const char *port, +- const char *username, enum trivalue prompt_password, +- const char *progname, bool echo, bool quiet) ++vacuum_all_databases(ConnParams *cparams, bool full, bool verbose, bool and_analyze, bool analyze_only, ++ bool freeze, const char *progname, bool echo, bool quiet) + { + PGconn *conn; + PGresult *result; + PQExpBufferData connstr; + int i; + +- conn = connectMaintenanceDatabase(maintenance_db, host, port, +- username, prompt_password, progname); ++ conn = connectMaintenanceDatabase(cparams, progname, echo); + result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo); + PQfinish(conn); + +@@ -329,13 +329,10 @@ + fflush(stdout); + } + +- resetPQExpBuffer(&connstr); +- appendPQExpBuffer(&connstr, "dbname="); +- appendConnStrVal(&connstr, PQgetvalue(result, i, 0)); +- +- vacuum_one_database(connstr.data, full, verbose, and_analyze, +- analyze_only, +- freeze, NULL, host, port, username, prompt_password, ++ cparams->override_dbname = PQgetvalue(result, i, 0); ++ ++ vacuum_one_database(cparams, full, verbose, and_analyze, ++ analyze_only, freeze, NULL, + progname, echo); + } + termPQExpBuffer(&connstr); diff --git a/SOURCES/postgresql-9.2.24-CVE-2020-25695.patch b/SOURCES/postgresql-9.2.24-CVE-2020-25695.patch new file mode 100644 index 0000000..7bcd863 --- /dev/null +++ b/SOURCES/postgresql-9.2.24-CVE-2020-25695.patch @@ -0,0 +1,91 @@ +From ad6890564c9408c299460decf013c02ce8f44e2a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Patrik=20Novotn=C3=BD?= +Date: Tue, 30 Mar 2021 11:27:29 +0200 +Subject: [PATCH] In security-restricted operations, block enqueue of at-commit + user code. + +Original commit: 0c3185e963d9f9dd0608214f7d732b84aa0888fe + +Original commit message: + + Specifically, this blocks DECLARE ... WITH HOLD and firing of deferred + triggers within index expressions and materialized view queries. An + attacker having permission to create non-temp objects in at least one + schema could execute arbitrary SQL functions under the identity of the + bootstrap superuser. One can work around the vulnerability by disabling + autovacuum and not manually running ANALYZE, CLUSTER, REINDEX, CREATE + INDEX, VACUUM FULL, or REFRESH MATERIALIZED VIEW. (Don't restore from + pg_dump, since it runs some of those commands.) Plain VACUUM (without + FULL) is safe, and all commands are fine when a trusted user owns the + target object. Performance may degrade quickly under this workaround, + however. Back-patch to 9.5 (all supported versions). +--- + src/backend/commands/portalcmds.c | 6 ++++++ + src/backend/commands/trigger.c | 13 +++++++++++++ + 2 files changed, 19 insertions(+) + +diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c +index e458adfad1..ea1b198dc8 100644 +--- a/src/backend/commands/portalcmds.c ++++ b/src/backend/commands/portalcmds.c +@@ -27,6 +27,7 @@ + #include "commands/portalcmds.h" + #include "executor/executor.h" + #include "executor/tstoreReceiver.h" ++#include "miscadmin.h" + #include "tcop/pquery.h" + #include "utils/memutils.h" + #include "utils/snapmgr.h" +@@ -67,6 +68,11 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, + */ + if (!(cstmt->options & CURSOR_OPT_HOLD)) + RequireTransactionChain(isTopLevel, "DECLARE CURSOR"); ++ else if (InSecurityRestrictedOperation()) ++ ereport(ERROR, ++ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ++ errmsg("cannot create a cursor WITH HOLD within security-restricted operation"))); ++ + + /* + * Create a portal and copy the plan and queryString into its memory. +diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c +index 357313dffa..5a0c65fcaa 100644 +--- a/src/backend/commands/trigger.c ++++ b/src/backend/commands/trigger.c +@@ -3480,6 +3480,7 @@ afterTriggerMarkEvents(AfterTriggerEventList *events, + bool immediate_only) + { + bool found = false; ++ bool deferred_found = false; + AfterTriggerEvent event; + AfterTriggerEventChunk *chunk; + +@@ -3515,6 +3516,7 @@ afterTriggerMarkEvents(AfterTriggerEventList *events, + */ + if (defer_it && move_list != NULL) + { ++ deferred_found = true; + /* add it to move_list */ + afterTriggerAddEvent(move_list, event, evtshared); + /* mark original copy "done" so we don't do it again */ +@@ -3522,6 +3524,17 @@ afterTriggerMarkEvents(AfterTriggerEventList *events, + } + } + ++ /* ++ * We could allow deferred triggers if, before the end of the ++ * security-restricted operation, we were to verify that a SET CONSTRAINTS ++ * ... IMMEDIATE has fired all such triggers. For now, don't bother. ++ */ ++ if (deferred_found && InSecurityRestrictedOperation()) ++ ereport(ERROR, ++ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ++ errmsg("cannot fire deferred trigger within security-restricted operation"))); ++ ++ + return found; + } + +-- +2.26.2 + diff --git a/SPECS/postgresql.spec b/SPECS/postgresql.spec index 0fa50bc..7a8be89 100644 --- a/SPECS/postgresql.spec +++ b/SPECS/postgresql.spec @@ -63,7 +63,7 @@ Summary: PostgreSQL client programs Name: postgresql %global majorversion 9.2 Version: 9.2.24 -Release: 4%{?dist} +Release: 6%{?dist} # The PostgreSQL license is very similar to other MIT licenses, but the OSI # recognizes it as an independent license, so we do as well. @@ -141,6 +141,22 @@ Patch15: postgresql-libpq-crypto-no-callback-stomping-v2.patch # See BZ#1754816 Patch16: postgresql-9.2.24-handle-EAGAIN-on-socket-write.patch +# Backport fix for CVE-2020-25694 +# Upstream commit: da129a04a6dea8c30eec2477c08d17736c92d431 +# Upstream commit: 6997da09a41f613695575fbfcb213f14784c92bb +# Upstream commit: 56b46d3a1a620548b4728b48bd28cdf11d88e101 +# Upstream commit: 65c3bf19fd3e1f6a591618e92eb4c54d0b217564 +Patch17: postgresql-9.2.24-CVE-2020-25694.patch + +# Backport fix for CVE-2020-25695 +# Upstream commit: 0c3185e963d9f9dd0608214f7d732b84aa0888fe +Patch18: postgresql-9.2.24-CVE-2020-25695.patch + +# Backport fix for CVE-2019-10208 +# Upstream commit: ffa2d37e5fbd1243f918f622113d6e371667e5a0 +# See BZ#1741488 +Patch19: postgresql-9.2.24-CVE-2019-10208.patch + BuildRequires: perl(ExtUtils::MakeMaker) glibc-devel bison flex gawk help2man BuildRequires: perl(ExtUtils::Embed), perl-devel BuildRequires: readline-devel zlib-devel @@ -381,6 +397,9 @@ benchmarks. %patch14 -p1 %patch15 -p1 %patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 # We used to run autoconf here, but there's no longer any real need to, # since Postgres ships with a reasonably modern configure script. @@ -1178,6 +1197,13 @@ fi %endif %changelog +* Wed Apr 14 2021 Patrik Novotný - 9.2.24-6 +- Patch fixing BZ#1741488 CVE-2019-10208 + +* Thu Jan 07 2021 Patrik Novotný - 9.2.24-5 +- Patch fixing CVE-2020-25694 BZ#1907894 +- Patch fixing CVE-2020-25695 BZ#1907895 + * Fri Jan 24 2020 Patrik Novotný - 9.2.24-4 - Patch fixing BZ#1754816: handle EAGAIN error on socket write