!49 Proposal: Support the 13.3 version of PostgreSQL in openEuler
From: @bzhaoop Reviewed-by: @zhengzhenyu Signed-off-by: @zhengzhenyu
This commit is contained in:
commit
23d04570b6
@ -1,108 +0,0 @@
|
||||
From 90adc16ea13750a6b6f704c6cf65dc0f1bdb845c Mon Sep 17 00:00:00 2001
|
||||
From: Michael Paquier <michael@paquier.xyz>
|
||||
Date: Mon, 17 Jun 2019 21:48:34 +0900
|
||||
Subject: [PATCH] Fix buffer overflow when parsing SCRAM verifiers in backend
|
||||
|
||||
Any authenticated user can overflow a stack-based buffer by changing the
|
||||
user's own password to a purpose-crafted value. This often suffices to
|
||||
execute arbitrary code as the PostgreSQL operating system account.
|
||||
|
||||
This fix is contributed by multiple folks, based on an initial analysis
|
||||
from Tom Lane. This issue has been introduced by 68e61ee, so it was
|
||||
possible to make use of it at authentication time. It became more
|
||||
easily to trigger after ccae190 which has made the SCRAM parsing more
|
||||
strict when changing a password, in the case where the client passes
|
||||
down a verifier already hashed using SCRAM. Back-patch to v10 where
|
||||
SCRAM has been introduced.
|
||||
|
||||
Reported-by: Alexander Lakhin
|
||||
Author: Jonathan Katz, Heikki Linnakangas, Michael Paquier
|
||||
Security: CVE-2019-10164
|
||||
Backpatch-through: 10
|
||||
---
|
||||
src/backend/libpq/auth-scram.c | 35 ++++++++++++++++++++++++++--------
|
||||
src/test/regress/expected/password.out | 23 ++++++++++++++++++++++
|
||||
src/test/regress/sql/password.sql | 18 +++++++++++++++++
|
||||
3 files changed, 68 insertions(+), 8 deletions(-)
|
||||
|
||||
diff -Nurp postgresql-10.5/src/backend/libpq/auth-scram.c postgresql-10.5-bak/src/backend/libpq/auth-scram.c
|
||||
--- postgresql-10.5/src/backend/libpq/auth-scram.c 2018-08-06 16:05:31.000000000 -0400
|
||||
+++ postgresql-10.5-bak/src/backend/libpq/auth-scram.c 2019-08-01 10:03:08.505000000 -0400
|
||||
@@ -474,6 +474,12 @@ scram_verify_plain_password(const char *
|
||||
/*
|
||||
* Parse and validate format of given SCRAM verifier.
|
||||
*
|
||||
+ * On success, the iteration count, salt, stored key, and server key are
|
||||
+ * extracted from the verifier, and returned to the caller. For 'stored_key'
|
||||
+ * and 'server_key', the caller must pass pre-allocated buffers of size
|
||||
+ * SCRAM_KEY_LEN. Salt is returned as a base64-encoded, null-terminated
|
||||
+ * string. The buffer for the salt is palloc'd by this function.
|
||||
+ *
|
||||
* Returns true if the SCRAM verifier has been parsed, and false otherwise.
|
||||
*/
|
||||
static bool
|
||||
@@ -489,6 +495,8 @@ parse_scram_verifier(const char *verifie
|
||||
char *serverkey_str;
|
||||
int decoded_len;
|
||||
char *decoded_salt_buf;
|
||||
+ char *decoded_stored_buf;
|
||||
+ char *decoded_server_buf;
|
||||
|
||||
/*
|
||||
* The verifier is of form:
|
||||
@@ -521,7 +529,8 @@ parse_scram_verifier(const char *verifie
|
||||
* although we return the encoded version to the caller.
|
||||
*/
|
||||
decoded_salt_buf = palloc(pg_b64_dec_len(strlen(salt_str)));
|
||||
- decoded_len = pg_b64_decode(salt_str, strlen(salt_str), decoded_salt_buf);
|
||||
+ decoded_len = pg_b64_decode(salt_str, strlen(salt_str),
|
||||
+ decoded_salt_buf);
|
||||
if (decoded_len < 0)
|
||||
goto invalid_verifier;
|
||||
*salt = pstrdup(salt_str);
|
||||
@@ -529,28 +538,38 @@ parse_scram_verifier(const char *verifie
|
||||
/*
|
||||
* Decode StoredKey and ServerKey.
|
||||
*/
|
||||
- if (pg_b64_dec_len(strlen(storedkey_str) != SCRAM_KEY_LEN))
|
||||
- goto invalid_verifier;
|
||||
+ decoded_stored_buf = palloc(pg_b64_dec_len(strlen(storedkey_str)));
|
||||
decoded_len = pg_b64_decode(storedkey_str, strlen(storedkey_str),
|
||||
- (char *) stored_key);
|
||||
+ decoded_stored_buf);
|
||||
if (decoded_len != SCRAM_KEY_LEN)
|
||||
goto invalid_verifier;
|
||||
+ memcpy(stored_key, decoded_stored_buf, SCRAM_KEY_LEN);
|
||||
|
||||
- if (pg_b64_dec_len(strlen(serverkey_str) != SCRAM_KEY_LEN))
|
||||
- goto invalid_verifier;
|
||||
+ decoded_server_buf = palloc(pg_b64_dec_len(strlen(serverkey_str)));
|
||||
decoded_len = pg_b64_decode(serverkey_str, strlen(serverkey_str),
|
||||
- (char *) server_key);
|
||||
+ decoded_server_buf);
|
||||
if (decoded_len != SCRAM_KEY_LEN)
|
||||
goto invalid_verifier;
|
||||
+ memcpy(server_key, decoded_server_buf, SCRAM_KEY_LEN);
|
||||
|
||||
return true;
|
||||
|
||||
invalid_verifier:
|
||||
- pfree(v);
|
||||
*salt = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Generate plausible SCRAM verifier parameters for mock authentication.
|
||||
+ *
|
||||
+ * In a normal authentication, these are extracted from the verifier
|
||||
+ * stored in the server. This function generates values that look
|
||||
+ * realistic, for when there is no stored verifier.
|
||||
+ *
|
||||
+ * Like in parse_scram_verifier(), for 'stored_key' and 'server_key', the
|
||||
+ * caller must pass pre-allocated buffers of size SCRAM_KEY_LEN, and
|
||||
+ * the buffer for the salt is palloc'd by this function.
|
||||
+ */
|
||||
static void
|
||||
mock_scram_verifier(const char *username, int *iterations, char **salt,
|
||||
uint8 *stored_key, uint8 *server_key)
|
||||
@ -1,77 +0,0 @@
|
||||
From d72a7e4da1001b29a661a4b1a52cb5c4d708bab0 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Paquier <michael@paquier.xyz>
|
||||
Date: Mon, 17 Jun 2019 22:14:09 +0900
|
||||
Subject: [PATCH] Fix buffer overflow when processing SCRAM final message in
|
||||
libpq
|
||||
|
||||
When a client connects to a rogue server sending specifically-crafted
|
||||
messages, this can suffice to execute arbitrary code as the operating
|
||||
system account used by the client.
|
||||
|
||||
While on it, fix one error handling when decoding an incorrect salt
|
||||
included in the first message received from server.
|
||||
|
||||
Author: Michael Paquier
|
||||
Reviewed-by: Jonathan Katz, Heikki Linnakangas
|
||||
Security: CVE-2019-10164
|
||||
Backpatch-through: 10
|
||||
---
|
||||
src/interfaces/libpq/fe-auth-scram.c | 21 ++++++++++++++++++++-
|
||||
1 file changed, 20 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c
|
||||
index 7fa7f34c80..4cdf9ba93b 100644
|
||||
--- a/src/interfaces/libpq/fe-auth-scram.c
|
||||
+++ b/src/interfaces/libpq/fe-auth-scram.c
|
||||
@@ -462,6 +462,12 @@ read_server_first_message(fe_scram_state *state, char *input,
|
||||
state->saltlen = pg_b64_decode(encoded_salt,
|
||||
strlen(encoded_salt),
|
||||
state->salt);
|
||||
+ if (state->saltlen < 0)
|
||||
+ {
|
||||
+ printfPQExpBuffer(errormessage,
|
||||
+ libpq_gettext("malformed SCRAM message (invalid salt)\n"));
|
||||
+ return false;
|
||||
+ }
|
||||
|
||||
iterations_str = read_attr_value(&input, 'i', errormessage);
|
||||
if (iterations_str == NULL)
|
||||
@@ -492,6 +498,7 @@ read_server_final_message(fe_scram_state *state, char *input,
|
||||
PQExpBuffer errormessage)
|
||||
{
|
||||
char *encoded_server_signature;
|
||||
+ char *decoded_server_signature;
|
||||
int server_signature_len;
|
||||
|
||||
state->server_final_message = strdup(input);
|
||||
@@ -525,15 +532,27 @@ read_server_final_message(fe_scram_state *state, char *input,
|
||||
printfPQExpBuffer(errormessage,
|
||||
libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n"));
|
||||
|
||||
+ server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature));
|
||||
+ decoded_server_signature = malloc(server_signature_len);
|
||||
+ if (!decoded_server_signature)
|
||||
+ {
|
||||
+ printfPQExpBuffer(errormessage,
|
||||
+ libpq_gettext("out of memory\n"));
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
server_signature_len = pg_b64_decode(encoded_server_signature,
|
||||
strlen(encoded_server_signature),
|
||||
- state->ServerSignature);
|
||||
+ decoded_server_signature);
|
||||
if (server_signature_len != SCRAM_KEY_LEN)
|
||||
{
|
||||
+ free(decoded_server_signature);
|
||||
printfPQExpBuffer(errormessage,
|
||||
libpq_gettext("malformed SCRAM message (invalid server signature)\n"));
|
||||
return false;
|
||||
}
|
||||
+ memcpy(state->ServerSignature, decoded_server_signature, SCRAM_KEY_LEN);
|
||||
+ free(decoded_server_signature);
|
||||
|
||||
return true;
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
@ -1,224 +0,0 @@
|
||||
From 2062007cbf7008de383c8f2f4a9ad466ea243acf Mon Sep 17 00:00:00 2001
|
||||
From: Noah Misch <noah@leadboat.com>
|
||||
Date: Mon, 5 Aug 2019 07:48:41 -0700
|
||||
Subject: [PATCH] Require the schema qualification in pg_temp.type_name(arg).
|
||||
|
||||
Commit aa27977fe21a7dfa4da4376ad66ae37cb8f0d0b5 introduced this
|
||||
restriction for pg_temp.function_name(arg); do likewise for types
|
||||
created in temporary schemas. Programs that this breaks should add
|
||||
"pg_temp." schema qualification or switch to arg::type_name syntax.
|
||||
Back-patch to 9.4 (all supported versions).
|
||||
|
||||
Reviewed by Tom Lane. Reported by Tom Lane.
|
||||
|
||||
Security: CVE-2019-10208
|
||||
---
|
||||
src/backend/catalog/namespace.c | 15 ++++++++++++++-
|
||||
src/backend/parser/parse_func.c | 7 ++++++-
|
||||
src/backend/parser/parse_type.c | 24 +++++++++++++++++++++---
|
||||
src/backend/utils/adt/ruleutils.c | 8 ++++++++
|
||||
src/include/catalog/namespace.h | 1 +
|
||||
src/include/parser/parse_type.h | 3 +++
|
||||
src/test/regress/expected/temp.out | 15 +++++++++++++++
|
||||
src/test/regress/sql/temp.sql | 12 ++++++++++++
|
||||
8 files changed, 79 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
|
||||
index 5a737c8ab3..6b75ce10da 100644
|
||||
--- a/src/backend/catalog/namespace.c
|
||||
+++ b/src/backend/catalog/namespace.c
|
||||
@@ -739,13 +739,23 @@ RelationIsVisible(Oid relid)
|
||||
|
||||
/*
|
||||
* 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;
|
||||
@@ -756,6 +766,9 @@ TypenameGetTypid(const char *typname)
|
||||
{
|
||||
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 --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
|
||||
index 25ae4e5949..571d3d1b62 100644
|
||||
--- a/src/backend/parser/parse_func.c
|
||||
+++ b/src/backend/parser/parse_func.c
|
||||
@@ -1769,7 +1769,12 @@ FuncNameAsType(List *funcname)
|
||||
Oid result;
|
||||
Type typtup;
|
||||
|
||||
- typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
|
||||
+ /*
|
||||
+ * temp_ok=false protects the <refsect1 id="sql-createfunction-security">
|
||||
+ * contract for writing SECURITY DEFINER functions safely.
|
||||
+ */
|
||||
+ typtup = LookupTypeNameExtended(NULL, makeTypeNameFromNameList(funcname),
|
||||
+ NULL, false, false);
|
||||
if (typtup == NULL)
|
||||
return InvalidOid;
|
||||
|
||||
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
|
||||
index d0b3fbeb57..1171381487 100644
|
||||
--- a/src/backend/parser/parse_type.c
|
||||
+++ b/src/backend/parser/parse_type.c
|
||||
@@ -33,6 +33,18 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
|
||||
|
||||
/*
|
||||
* LookupTypeName
|
||||
+ * Wrapper for typical case.
|
||||
+ */
|
||||
+Type
|
||||
+LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
||||
+ int32 *typmod_p, bool missing_ok)
|
||||
+{
|
||||
+ return LookupTypeNameExtended(pstate,
|
||||
+ typeName, typmod_p, true, missing_ok);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * 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 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
|
||||
* 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, bool missing_ok)
|
||||
+LookupTypeNameExtended(ParseState *pstate,
|
||||
+ const TypeName *typeName, int32 *typmod_p,
|
||||
+ bool temp_ok, bool missing_ok)
|
||||
{
|
||||
Oid typoid;
|
||||
HeapTuple tup;
|
||||
@@ -172,7 +190,7 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
||||
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 --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
|
||||
index 3d1a701775..01789291bb 100644
|
||||
--- a/src/backend/utils/adt/ruleutils.c
|
||||
+++ b/src/backend/utils/adt/ruleutils.c
|
||||
@@ -9273,6 +9273,14 @@ get_coercion_expr(Node *arg, deparse_context *context,
|
||||
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 --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
|
||||
index f2ee935623..59c5ea5be2 100644
|
||||
--- a/src/include/catalog/namespace.h
|
||||
+++ b/src/include/catalog/namespace.h
|
||||
@@ -66,6 +66,7 @@ extern Oid RelnameGetRelid(const char *relname);
|
||||
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 --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
|
||||
index 7b843d0b9d..ac1bf1009e 100644
|
||||
--- a/src/include/parser/parse_type.h
|
||||
+++ b/src/include/parser/parse_type.h
|
||||
@@ -21,6 +21,9 @@ typedef HeapTuple Type;
|
||||
|
||||
extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
||||
int32 *typmod_p, bool missing_ok);
|
||||
+extern Type LookupTypeNameExtended(ParseState *pstate,
|
||||
+ const TypeName *typeName, int32 *typmod_p,
|
||||
+ bool temp_ok, bool missing_ok);
|
||||
extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
|
||||
bool missing_ok);
|
||||
extern Type typenameType(ParseState *pstate, const TypeName *typeName,
|
||||
diff --git a/src/test/regress/expected/temp.out b/src/test/regress/expected/temp.out
|
||||
index 7046deb0c8..aad562791e 100644
|
||||
--- a/src/test/regress/expected/temp.out
|
||||
+++ b/src/test/regress/expected/temp.out
|
||||
@@ -199,3 +199,18 @@ select pg_temp.whoami();
|
||||
(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 --git a/src/test/regress/sql/temp.sql b/src/test/regress/sql/temp.sql
|
||||
index d69a243fe7..c14c11444c 100644
|
||||
--- a/src/test/regress/sql/temp.sql
|
||||
+++ b/src/test/regress/sql/temp.sql
|
||||
@@ -151,3 +151,15 @@ select pg_temp.whoami();
|
||||
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;
|
||||
+
|
||||
--
|
||||
2.11.0
|
||||
@ -1,44 +0,0 @@
|
||||
From 21a134a26100b377191735ad49f996eac03047de Mon Sep 17 00:00:00 2001
|
||||
From: guiyao <guiyao@huawei.com>
|
||||
Date: Thu, 17 Dec 2020 09:34:13 -0500
|
||||
Subject: [PATCH] backport to fix CVE-2018-16850
|
||||
|
||||
---
|
||||
src/backend/utils/adt/ruleutils.c | 10 ++++++----
|
||||
1 files changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
|
||||
index 4c9a49c..0eea491 100644
|
||||
--- a/src/backend/utils/adt/ruleutils.c
|
||||
+++ b/src/backend/utils/adt/ruleutils.c
|
||||
@@ -952,22 +952,24 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
|
||||
value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
|
||||
tgrel->rd_att, &isnull);
|
||||
if (!isnull)
|
||||
- tgoldtable = NameStr(*((NameData *) DatumGetPointer(value)));
|
||||
+ tgoldtable = NameStr(*DatumGetName(value));
|
||||
else
|
||||
tgoldtable = NULL;
|
||||
value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
|
||||
tgrel->rd_att, &isnull);
|
||||
if (!isnull)
|
||||
- tgnewtable = NameStr(*((NameData *) DatumGetPointer(value)));
|
||||
+ tgnewtable = NameStr(*DatumGetName(value));
|
||||
else
|
||||
tgnewtable = NULL;
|
||||
if (tgoldtable != NULL || tgnewtable != NULL)
|
||||
{
|
||||
appendStringInfoString(&buf, "REFERENCING ");
|
||||
if (tgoldtable != NULL)
|
||||
- appendStringInfo(&buf, "OLD TABLE AS %s ", tgoldtable);
|
||||
+ appendStringInfo(&buf, "OLD TABLE AS %s ",
|
||||
+ quote_identifier(tgoldtable));
|
||||
if (tgnewtable != NULL)
|
||||
- appendStringInfo(&buf, "NEW TABLE AS %s ", tgnewtable);
|
||||
+ appendStringInfo(&buf, "NEW TABLE AS %s ",
|
||||
+ quote_identifier(tgnewtable));
|
||||
}
|
||||
|
||||
if (TRIGGER_FOR_ROW(trigrec->tgtype))
|
||||
--
|
||||
1.8.3.1
|
||||
@ -1,75 +0,0 @@
|
||||
From 1aebfbea83c4a3e1a0aba4b0910135dc5a45666c Mon Sep 17 00:00:00 2001
|
||||
From: Dean Rasheed <dean.a.rasheed@gmail.com>
|
||||
Date: Mon, 6 May 2019 11:38:43 +0100
|
||||
Subject: [PATCH] Fix security checks for selectivity estimation functions with
|
||||
RLS.
|
||||
|
||||
In commit e2d4ef8de8, security checks were added to prevent
|
||||
user-supplied operators from running over data from pg_statistic
|
||||
unless the user has table or column privileges on the table, or the
|
||||
operator is leakproof. For a table with RLS, however, checking for
|
||||
table or column privileges is insufficient, since that does not
|
||||
guarantee that the user has permission to view all of the column's
|
||||
data.
|
||||
|
||||
Fix this by also checking for securityQuals on the RTE, and insisting
|
||||
that the operator be leakproof if there are any. Thus the
|
||||
leakproofness check will only be skipped if there are no securityQuals
|
||||
and the user has table or column privileges on the table -- i.e., only
|
||||
if we know that the user has access to all the data in the column.
|
||||
|
||||
Back-patch to 9.5 where RLS was added.
|
||||
|
||||
Dean Rasheed, reviewed by Jonathan Katz and Stephen Frost.
|
||||
|
||||
Security: CVE-2019-10130
|
||||
---
|
||||
src/backend/utils/adt/selfuncs.c | 21 +++++++++++++++------
|
||||
src/test/regress/expected/rowsecurity.out | 21 +++++++++++++++++++++
|
||||
src/test/regress/sql/rowsecurity.sql | 20 ++++++++++++++++++++
|
||||
3 files changed, 56 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
|
||||
index b41991315520..514612857ad6 100644
|
||||
--- a/src/backend/utils/adt/selfuncs.c
|
||||
+++ b/src/backend/utils/adt/selfuncs.c
|
||||
@@ -4597,9 +4597,13 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
|
||||
* For simplicity, we insist on the whole
|
||||
* table being selectable, rather than trying
|
||||
* to identify which column(s) the index
|
||||
- * depends on.
|
||||
+ * depends on. Also require all rows to be
|
||||
+ * selectable --- there must be no
|
||||
+ * securityQuals from security barrier views
|
||||
+ * or RLS policies.
|
||||
*/
|
||||
vardata->acl_ok =
|
||||
+ rte->securityQuals == NIL &&
|
||||
(pg_class_aclcheck(rte->relid, GetUserId(),
|
||||
ACL_SELECT) == ACLCHECK_OK);
|
||||
}
|
||||
@@ -4663,12 +4667,17 @@ examine_simple_variable(PlannerInfo *root, Var *var,
|
||||
|
||||
if (HeapTupleIsValid(vardata->statsTuple))
|
||||
{
|
||||
- /* check if user has permission to read this column */
|
||||
+ /*
|
||||
+ * Check if user has permission to read this column. We require
|
||||
+ * all rows to be accessible, so there must be no securityQuals
|
||||
+ * from security barrier views or RLS policies.
|
||||
+ */
|
||||
vardata->acl_ok =
|
||||
- (pg_class_aclcheck(rte->relid, GetUserId(),
|
||||
- ACL_SELECT) == ACLCHECK_OK) ||
|
||||
- (pg_attribute_aclcheck(rte->relid, var->varattno, GetUserId(),
|
||||
- ACL_SELECT) == ACLCHECK_OK);
|
||||
+ rte->securityQuals == NIL &&
|
||||
+ ((pg_class_aclcheck(rte->relid, GetUserId(),
|
||||
+ ACL_SELECT) == ACLCHECK_OK) ||
|
||||
+ (pg_attribute_aclcheck(rte->relid, var->varattno, GetUserId(),
|
||||
+ ACL_SELECT) == ACLCHECK_OK));
|
||||
}
|
||||
else
|
||||
{
|
||||
--
|
||||
2.11.0
|
||||
@ -1,42 +0,0 @@
|
||||
From b048f558dd7c26a0c630a2cff29d3d8981eaf6b9 Mon Sep 17 00:00:00 2001
|
||||
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
|
||||
Date: Mon, 10 Feb 2020 11:47:09 -0300
|
||||
Subject: [PATCH] Fix priv checks for ALTER <object> DEPENDS ON EXTENSION
|
||||
|
||||
Marking an object as dependant on an extension did not have any
|
||||
privilege check whatsoever; this allowed any user to mark objects as
|
||||
droppable by anyone able to DROP EXTENSION, which could be used to cause
|
||||
system-wide havoc. Disallow by checking that the calling user owns the
|
||||
mentioned object.
|
||||
|
||||
(No constraints are placed on the extension.)
|
||||
|
||||
Security: CVE-2020-1720
|
||||
Reported-by: Tom Lane
|
||||
Discussion: 31605.1566429043@sss.pgh.pa.us
|
||||
---
|
||||
src/backend/commands/alter.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
|
||||
index fca85ba2c17f..1cb84182b05f 100644
|
||||
--- a/src/backend/commands/alter.c
|
||||
+++ b/src/backend/commands/alter.c
|
||||
@@ -430,6 +430,17 @@ ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddre
|
||||
get_object_address_rv(stmt->objectType, stmt->relation, (List *) stmt->object,
|
||||
&rel, AccessExclusiveLock, false);
|
||||
|
||||
+ /*
|
||||
+ * Verify that the user is entitled to run the command.
|
||||
+ *
|
||||
+ * We don't check any privileges on the extension, because that's not
|
||||
+ * needed. The object owner is stipulating, by running this command, that
|
||||
+ * the extension owner can drop the object whenever they feel like it,
|
||||
+ * which is not considered a problem.
|
||||
+ */
|
||||
+ check_object_ownership(GetUserId(),
|
||||
+ stmt->objectType, address, stmt->object, rel);
|
||||
+
|
||||
/*
|
||||
* If a relation was involved, it would have been opened and locked. We
|
||||
* don't need the relation here, but we'll retain the lock until commit.
|
||||
@ -1,96 +0,0 @@
|
||||
From 11da97024abbe76b8c81e3f2375b2a62e9717c67 Mon Sep 17 00:00:00 2001
|
||||
From: Noah Misch <noah@leadboat.com>
|
||||
Date: Mon, 10 Aug 2020 09:22:54 -0700
|
||||
Subject: [PATCH] Empty search_path in logical replication apply worker and
|
||||
walsender.
|
||||
|
||||
This is like CVE-2018-1058 commit
|
||||
582edc369cdbd348d68441fc50fa26a84afd0c1a. Today, a malicious user of a
|
||||
publisher or subscriber database can invoke arbitrary SQL functions
|
||||
under an identity running replication, often a superuser. This fix may
|
||||
cause "does not exist" or "no schema has been selected to create in"
|
||||
errors in a replication process. After upgrading, consider watching
|
||||
server logs for these errors. Objects accruing schema qualification in
|
||||
the wake of the earlier commit are unlikely to need further correction.
|
||||
Back-patch to v10, which introduced logical replication.
|
||||
|
||||
Security: CVE-2020-14349
|
||||
reason: fix CVE-2020-14349
|
||||
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=11da97024abbe76b8c81e3f2375b2a62e9717c67
|
||||
|
||||
Signed-off-by: Noah Misch <noah@leadboat.com>
|
||||
---
|
||||
.../libpqwalreceiver/libpqwalreceiver.c | 17 +++++++++++++++++
|
||||
src/backend/replication/logical/worker.c | 6 ++++++
|
||||
src/test/subscription/t/001_rep_changes.pl | 4 ++++
|
||||
3 files changed, 27 insertions(+)
|
||||
|
||||
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
|
||||
index 37b481c..564e6d3 100644
|
||||
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
|
||||
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "pqexpbuffer.h"
|
||||
#include "access/xlog.h"
|
||||
#include "catalog/pg_type.h"
|
||||
+#include "fe_utils/connect.h"
|
||||
#include "funcapi.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -210,6 +211,22 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+ if (logical)
|
||||
+ {
|
||||
+ PGresult *res;
|
||||
+
|
||||
+ res = libpqrcv_PQexec(conn->streamConn,
|
||||
+ ALWAYS_SECURE_SEARCH_PATH_SQL);
|
||||
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
+ {
|
||||
+ PQclear(res);
|
||||
+ ereport(ERROR,
|
||||
+ (errmsg("could not clear search path: %s",
|
||||
+ pchomp(PQerrorMessage(conn->streamConn)))));
|
||||
+ }
|
||||
+ PQclear(res);
|
||||
+ }
|
||||
+
|
||||
conn->logical = logical;
|
||||
|
||||
return conn;
|
||||
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
|
||||
index bd60094..07b765a 100644
|
||||
--- a/src/backend/replication/logical/worker.c
|
||||
+++ b/src/backend/replication/logical/worker.c
|
||||
@@ -1548,6 +1548,12 @@ ApplyWorkerMain(Datum main_arg)
|
||||
BackgroundWorkerInitializeConnectionByOid(MyLogicalRepWorker->dbid,
|
||||
MyLogicalRepWorker->userid);
|
||||
|
||||
+ /*
|
||||
+ * Set always-secure search path, so malicious users can't redirect user
|
||||
+ * code (e.g. pg_index.indexprs).
|
||||
+ */
|
||||
+ SetConfigOption("search_path", "", PGC_SUSET, PGC_S_OVERRIDE);
|
||||
+
|
||||
/* Load the subscription into persistent memory context. */
|
||||
ApplyContext = AllocSetContextCreate(TopMemoryContext,
|
||||
"ApplyContext",
|
||||
diff --git a/src/test/subscription/t/001_rep_changes.pl b/src/test/subscription/t/001_rep_changes.pl
|
||||
index 0136c79..cda275b 100644
|
||||
--- a/src/test/subscription/t/001_rep_changes.pl
|
||||
+++ b/src/test/subscription/t/001_rep_changes.pl
|
||||
@@ -16,6 +16,10 @@ $node_subscriber->init(allows_streaming => 'logical');
|
||||
$node_subscriber->start;
|
||||
|
||||
# Create some preexisting content on publisher
|
||||
+$node_publisher->safe_psql(
|
||||
+ 'postgres',
|
||||
+ "CREATE FUNCTION public.pg_get_replica_identity_index(int)
|
||||
+ RETURNS regclass LANGUAGE sql AS 'SELECT 1/0'"); # shall not call
|
||||
$node_publisher->safe_psql('postgres',
|
||||
"CREATE TABLE tab_notrep AS SELECT generate_series(1,10) AS a");
|
||||
$node_publisher->safe_psql('postgres',
|
||||
--
|
||||
2.23.0
|
||||
@ -1,54 +0,0 @@
|
||||
From cec57b1a0fbcd3833086ba686897c5883e0a2afc Mon Sep 17 00:00:00 2001
|
||||
From: Noah Misch <noah@leadboat.com>
|
||||
Date: Mon, 10 Aug 2020 09:22:54 -0700
|
||||
Subject: [PATCH] Document clashes between logical replication and untrusted
|
||||
users.
|
||||
|
||||
Back-patch to v10, which introduced logical replication.
|
||||
|
||||
Security: CVE-2020-14349
|
||||
reason: fix CVE-2020-14349
|
||||
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=cec57b1a0fbcd3833086ba686897c5883e0a2afc
|
||||
|
||||
Signed-off-by: Noah Misch <noah@leadboat.com>
|
||||
---
|
||||
doc/src/sgml/logical-replication.sgml | 22 +++++++++++++++++++---
|
||||
1 file changed, 19 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
|
||||
index 41770a4..f5086b2 100644
|
||||
--- a/doc/src/sgml/logical-replication.sgml
|
||||
+++ b/doc/src/sgml/logical-replication.sgml
|
||||
@@ -490,11 +490,27 @@
|
||||
<sect1 id="logical-replication-security">
|
||||
<title>Security</title>
|
||||
|
||||
+ <para>
|
||||
+ A user able to modify the schema of subscriber-side tables can execute
|
||||
+ arbitrary code as a superuser. Limit ownership
|
||||
+ and <literal>TRIGGER</literal> privilege on such tables to roles that
|
||||
+ superusers trust. Moreover, if untrusted users can create tables, use only
|
||||
+ publications that list tables explicitly. That is to say, create a
|
||||
+ subscription <literal>FOR ALL TABLES</literal> only when superusers trust
|
||||
+ every user permitted to create a non-temp table on the publisher or the
|
||||
+ subscriber.
|
||||
+ </para>
|
||||
+
|
||||
<para>
|
||||
The role used for the replication connection must have
|
||||
- the <literal>REPLICATION</literal> attribute (or be a superuser). Access for the role must be
|
||||
- configured in <filename>pg_hba.conf</filename> and it must have the
|
||||
- <literal>LOGIN</literal> attribute.
|
||||
+ the <literal>REPLICATION</literal> attribute (or be a superuser). If the
|
||||
+ role lacks <literal>SUPERUSER</literal> and <literal>BYPASSRLS</literal>,
|
||||
+ publisher row security policies can execute. If the role does not trust
|
||||
+ all table owners, include <literal>options=-crow_security=off</literal> in
|
||||
+ the connection string; if a table owner then adds a row security policy,
|
||||
+ that setting will cause replication to halt rather than execute the policy.
|
||||
+ Access for the role must be configured in <filename>pg_hba.conf</filename>
|
||||
+ and it must have the <literal>LOGIN</literal> attribute.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
--
|
||||
2.23.0
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,492 +0,0 @@
|
||||
From a062fb822382398c7282810029016400feecf644 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Lane <tgl@sss.pgh.pa.us>
|
||||
Date: Wed, 21 Oct 2020 16:18:41 -0400
|
||||
Subject: [PATCH] Fix connection string handling in psql's \connect command.
|
||||
|
||||
psql's \connect claims to be able to re-use previous connection
|
||||
parameters, but in fact it only re-uses the database name, user name,
|
||||
host name (and possibly hostaddr, depending on version), and port.
|
||||
This is problematic for assorted use cases. Notably, pg_dump[all]
|
||||
emits "\connect databasename" commands which we would like to have
|
||||
re-use all other parameters. If such a script is loaded in a psql run
|
||||
that initially had "-d connstring" with some non-default parameters,
|
||||
those other parameters would be lost, potentially causing connection
|
||||
failure. (Thus, this is the same kind of bug addressed in commits
|
||||
a45bc8a4f and 8e5793ab6, although the details are much different.)
|
||||
|
||||
To fix, redesign do_connect() so that it pulls out all properties
|
||||
of the old PGconn using PQconninfo(), and then replaces individual
|
||||
properties in that array. In the case where we don't wish to re-use
|
||||
anything, get libpq's default settings using PQconndefaults() and
|
||||
replace entries in that, so that we don't need different code paths
|
||||
for the two cases.
|
||||
|
||||
This does result in an additional behavioral change for cases where
|
||||
the original connection parameters allowed multiple hosts, say
|
||||
"psql -h host1,host2", and the \connect request allows re-use of the
|
||||
host setting. Because the previous coding relied on PQhost(), it
|
||||
would only permit reconnection to the same host originally selected.
|
||||
Although one can think of scenarios where that's a good thing, there
|
||||
are others where it is not. Moreover, that behavior doesn't seem to
|
||||
meet the principle of least surprise, nor was it documented; nor is
|
||||
it even clear it was intended, since that coding long pre-dates the
|
||||
addition of multi-host support to libpq. Hence, this patch is content
|
||||
to drop it and re-use the host list as given.
|
||||
|
||||
Per Peter Eisentraut's comments on bug #16604. Back-patch to all
|
||||
supported branches.
|
||||
|
||||
Discussion: https://postgr.es/m/16604-933f4b8791227b15@postgresql.org
|
||||
---
|
||||
doc/src/sgml/ref/psql-ref.sgml | 44 ++++--
|
||||
src/bin/psql/command.c | 272 ++++++++++++++++++++++++---------
|
||||
2 files changed, 230 insertions(+), 86 deletions(-)
|
||||
|
||||
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
|
||||
index c8388513b8..7fda949f3b 100644
|
||||
--- a/doc/src/sgml/ref/psql-ref.sgml
|
||||
+++ b/doc/src/sgml/ref/psql-ref.sgml
|
||||
@@ -875,21 +875,17 @@ testdb=>
|
||||
<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>
|
||||
<listitem>
|
||||
<para>
|
||||
- Establishes a new connection to a <productname>PostgreSQL</>
|
||||
+ Establishes a new connection to a <productname>PostgreSQL</productname>
|
||||
server. The connection parameters to use can be specified either
|
||||
- using a positional syntax, or using <replaceable>conninfo</> connection
|
||||
- strings as detailed in <xref linkend="libpq-connstring">.
|
||||
+ using a positional syntax (one or more of database name, user,
|
||||
+ host, and port), or using a <replaceable>conninfo</replaceable>
|
||||
+ connection string as detailed in
|
||||
+ <xref linkend="libpq-connstring">. If no arguments are given, a
|
||||
+ new connection is made using the same parameters as before.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
- Where the command omits database name, user, host, or port, the new
|
||||
- connection can reuse values from the previous connection. By default,
|
||||
- values from the previous connection are reused except when processing
|
||||
- a <replaceable>conninfo</> string. Passing a first argument
|
||||
- of <literal>-reuse-previous=on</>
|
||||
- or <literal>-reuse-previous=off</literal> overrides that default.
|
||||
- When the command neither specifies nor reuses a particular parameter,
|
||||
- the <application>libpq</application> default is used. Specifying any
|
||||
+ Specifying any
|
||||
of <replaceable class="parameter">dbname</replaceable>,
|
||||
<replaceable class="parameter">username</replaceable>,
|
||||
<replaceable class="parameter">host</replaceable> or
|
||||
@@ -897,12 +893,31 @@ testdb=>
|
||||
as <literal>-</literal> is equivalent to omitting that parameter.
|
||||
</para>
|
||||
|
||||
+ <para>
|
||||
+ The new connection can re-use connection parameters from the previous
|
||||
+ connection; not only database name, user, host, and port, but other
|
||||
+ settings such as <replaceable>sslmode</replaceable>. By default,
|
||||
+ parameters are re-used in the positional syntax, but not when
|
||||
+ a <replaceable>conninfo</replaceable> string is given. Passing a
|
||||
+ first argument of <literal>-reuse-previous=on</literal>
|
||||
+ or <literal>-reuse-previous=off</literal> overrides that default. If
|
||||
+ parameters are re-used, then any parameter not explicitly specified as
|
||||
+ a positional parameter or in the <replaceable>conninfo</replaceable>
|
||||
+ string is taken from the existing connection's parameters. An
|
||||
+ exception is that if the <replaceable>host</replaceable> setting
|
||||
+ is changed from its previous value using the positional syntax,
|
||||
+ any <replaceable>hostaddr</replaceable> setting present in the
|
||||
+ existing connection's parameters is dropped.
|
||||
+ When the command neither specifies nor reuses a particular parameter,
|
||||
+ the <application>libpq</application> default is used.
|
||||
+ </para>
|
||||
+
|
||||
<para>
|
||||
If the new connection is successfully made, the previous
|
||||
connection is closed.
|
||||
- If the connection attempt failed (wrong user name, access
|
||||
- denied, etc.), the previous connection will only be kept if
|
||||
- <application>psql</application> is in interactive mode. When
|
||||
+ If the connection attempt fails (wrong user name, access
|
||||
+ denied, etc.), the previous connection will be kept if
|
||||
+ <application>psql</application> is in interactive mode. But when
|
||||
executing a non-interactive script, processing will
|
||||
immediately stop with an error. This distinction was chosen as
|
||||
a user convenience against typos on the one hand, and a safety
|
||||
@@ -917,6 +932,7 @@ testdb=>
|
||||
=> \c mydb myuser host.dom 6432
|
||||
=> \c service=foo
|
||||
=> \c "host=localhost port=5432 dbname=mydb connect_timeout=10 sslmode=disable"
|
||||
+=> \c -reuse-previous=on sslmode=require -- changes only sslmode
|
||||
=> \c postgresql://tom@localhost/mydb?application_name=myapp
|
||||
</programlisting>
|
||||
</listitem>
|
||||
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
|
||||
index a30a5f8ea0..91f7f0adc3 100644
|
||||
--- a/src/bin/psql/command.c
|
||||
+++ b/src/bin/psql/command.c
|
||||
@@ -2979,12 +2979,15 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
char *dbname, char *user, char *host, char *port)
|
||||
{
|
||||
PGconn *o_conn = pset.db,
|
||||
- *n_conn;
|
||||
+ *n_conn = NULL;
|
||||
+ PQconninfoOption *cinfo;
|
||||
+ int nconnopts = 0;
|
||||
+ bool same_host = false;
|
||||
char *password = NULL;
|
||||
- bool keep_password;
|
||||
+ bool success = true;
|
||||
+ bool keep_password = true;
|
||||
bool has_connection_string;
|
||||
bool reuse_previous;
|
||||
- PQExpBufferData connstr;
|
||||
|
||||
if (!o_conn && (!dbname || !user || !host || !port))
|
||||
{
|
||||
@@ -3012,6 +3015,11 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
reuse_previous = !has_connection_string;
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ /* If the old connection does not exist, there is nothing to reuse. */
|
||||
+ if (!o_conn)
|
||||
+ reuse_previous = false;
|
||||
+
|
||||
/* Silently ignore arguments subsequent to a connection string. */
|
||||
if (has_connection_string)
|
||||
{
|
||||
@@ -3020,41 +3028,126 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
port = NULL;
|
||||
}
|
||||
|
||||
- /* grab missing values from the old connection */
|
||||
- if (!user && reuse_previous)
|
||||
- user = PQuser(o_conn);
|
||||
- if (!host && reuse_previous)
|
||||
- host = PQhost(o_conn);
|
||||
- if (!port && reuse_previous)
|
||||
- port = PQport(o_conn);
|
||||
-
|
||||
/*
|
||||
- * Any change in the parameters read above makes us discard the password.
|
||||
- * We also discard it if we're to use a conninfo rather than the
|
||||
- * positional syntax.
|
||||
+ * If we intend to re-use connection parameters, collect them out of the
|
||||
+ * old connection, then replace individual values as necessary. Otherwise,
|
||||
+ * obtain a PQconninfoOption array containing libpq's defaults, and modify
|
||||
+ * that. Note this function assumes that PQconninfo, PQconndefaults, and
|
||||
+ * PQconninfoParse will all produce arrays containing the same options in
|
||||
+ * the same order.
|
||||
*/
|
||||
- if (has_connection_string)
|
||||
- keep_password = false;
|
||||
+ if (reuse_previous)
|
||||
+ cinfo = PQconninfo(o_conn);
|
||||
else
|
||||
- keep_password =
|
||||
- (user && PQuser(o_conn) && strcmp(user, PQuser(o_conn)) == 0) &&
|
||||
- (host && PQhost(o_conn) && strcmp(host, PQhost(o_conn)) == 0) &&
|
||||
- (port && PQport(o_conn) && strcmp(port, PQport(o_conn)) == 0);
|
||||
+ cinfo = PQconndefaults();
|
||||
|
||||
- /*
|
||||
- * Grab missing dbname from old connection. No password discard if this
|
||||
- * changes: passwords aren't (usually) database-specific.
|
||||
- */
|
||||
- if (!dbname && reuse_previous)
|
||||
+ if (cinfo)
|
||||
{
|
||||
- initPQExpBuffer(&connstr);
|
||||
- appendPQExpBuffer(&connstr, "dbname=");
|
||||
- appendConnStrVal(&connstr, PQdb(o_conn));
|
||||
- dbname = connstr.data;
|
||||
- /* has_connection_string=true would be a dead store */
|
||||
+ if (has_connection_string)
|
||||
+ {
|
||||
+ /* Parse the connstring and insert values into cinfo */
|
||||
+ PQconninfoOption *replcinfo;
|
||||
+ char *errmsg;
|
||||
+
|
||||
+ replcinfo = PQconninfoParse(dbname, &errmsg);
|
||||
+ if (replcinfo)
|
||||
+ {
|
||||
+ PQconninfoOption *ci;
|
||||
+ PQconninfoOption *replci;
|
||||
+
|
||||
+ for (ci = cinfo, replci = replcinfo;
|
||||
+ ci->keyword && replci->keyword;
|
||||
+ ci++, replci++)
|
||||
+ {
|
||||
+ Assert(strcmp(ci->keyword, replci->keyword) == 0);
|
||||
+ /* Insert value from connstring if one was provided */
|
||||
+ if (replci->val)
|
||||
+ {
|
||||
+ /*
|
||||
+ * We know that both val strings were allocated by
|
||||
+ * libpq, so the least messy way to avoid memory leaks
|
||||
+ * is to swap them.
|
||||
+ */
|
||||
+ char *swap = replci->val;
|
||||
+
|
||||
+ replci->val = ci->val;
|
||||
+ ci->val = swap;
|
||||
+ }
|
||||
+ }
|
||||
+ Assert(ci->keyword == NULL && replci->keyword == NULL);
|
||||
+
|
||||
+ /* While here, determine how many option slots there are */
|
||||
+ nconnopts = ci - cinfo;
|
||||
+
|
||||
+ PQconninfoFree(replcinfo);
|
||||
+
|
||||
+ /* We never re-use a password with a conninfo string. */
|
||||
+ keep_password = false;
|
||||
+
|
||||
+ /* Don't let code below try to inject dbname into params. */
|
||||
+ dbname = NULL;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* PQconninfoParse failed */
|
||||
+ if (errmsg)
|
||||
+ {
|
||||
+ psql_error("%s", errmsg);
|
||||
+ PQfreemem(errmsg);
|
||||
+ }
|
||||
+ else
|
||||
+ psql_error("out of memory\n");
|
||||
+ success = false;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /*
|
||||
+ * If dbname isn't a connection string, then we'll inject it and
|
||||
+ * the other parameters into the keyword array below. (We can't
|
||||
+ * easily insert them into the cinfo array because of memory
|
||||
+ * management issues: PQconninfoFree would misbehave on Windows.)
|
||||
+ * However, to avoid dependencies on the order in which parameters
|
||||
+ * appear in the array, make a preliminary scan to set
|
||||
+ * keep_password and same_host correctly.
|
||||
+ *
|
||||
+ * While any change in user, host, or port causes us to ignore the
|
||||
+ * old connection's password, we don't force that for dbname,
|
||||
+ * since passwords aren't database-specific.
|
||||
+ */
|
||||
+ PQconninfoOption *ci;
|
||||
+
|
||||
+ for (ci = cinfo; ci->keyword; ci++)
|
||||
+ {
|
||||
+ if (user && strcmp(ci->keyword, "user") == 0)
|
||||
+ {
|
||||
+ if (!(ci->val && strcmp(user, ci->val) == 0))
|
||||
+ keep_password = false;
|
||||
+ }
|
||||
+ else if (host && strcmp(ci->keyword, "host") == 0)
|
||||
+ {
|
||||
+ if (ci->val && strcmp(host, ci->val) == 0)
|
||||
+ same_host = true;
|
||||
+ else
|
||||
+ keep_password = false;
|
||||
+ }
|
||||
+ else if (port && strcmp(ci->keyword, "port") == 0)
|
||||
+ {
|
||||
+ if (!(ci->val && strcmp(port, ci->val) == 0))
|
||||
+ keep_password = false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* While here, determine how many option slots there are */
|
||||
+ nconnopts = ci - cinfo;
|
||||
+ }
|
||||
}
|
||||
else
|
||||
- connstr.data = NULL;
|
||||
+ {
|
||||
+ /* We failed to create the cinfo structure */
|
||||
+ psql_error("out of memory\n");
|
||||
+ success = false;
|
||||
+ }
|
||||
|
||||
/*
|
||||
* If the user asked to be prompted for a password, ask for one now. If
|
||||
@@ -3066,7 +3159,7 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
* the postmaster's log. But libpq offers no API that would let us obtain
|
||||
* a password and then continue with the first connection attempt.
|
||||
*/
|
||||
- if (pset.getPassword == TRI_YES)
|
||||
+ if (pset.getPassword == TRI_YES && success)
|
||||
{
|
||||
password = prompt_for_password(user);
|
||||
}
|
||||
@@ -3079,52 +3172,60 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
password = NULL;
|
||||
}
|
||||
|
||||
- while (true)
|
||||
+ /* Loop till we have a connection or fail, which we might've already */
|
||||
+ while (success)
|
||||
{
|
||||
-#define PARAMS_ARRAY_SIZE 8
|
||||
- const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
|
||||
- const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
|
||||
- int paramnum = -1;
|
||||
-
|
||||
- keywords[++paramnum] = "host";
|
||||
- values[paramnum] = host;
|
||||
- keywords[++paramnum] = "port";
|
||||
- values[paramnum] = port;
|
||||
- keywords[++paramnum] = "user";
|
||||
- values[paramnum] = user;
|
||||
+ const char **keywords = pg_malloc((nconnopts + 1) * sizeof(*keywords));
|
||||
+ const char **values = pg_malloc((nconnopts + 1) * sizeof(*values));
|
||||
+ int paramnum = 0;
|
||||
+ PQconninfoOption *ci;
|
||||
|
||||
/*
|
||||
- * Position in the array matters when the dbname is a connection
|
||||
- * string, because settings in a connection string override earlier
|
||||
- * array entries only. Thus, user= in the connection string always
|
||||
- * takes effect, but client_encoding= often will not.
|
||||
+ * Copy non-default settings into the PQconnectdbParams parameter
|
||||
+ * arrays; but override any values specified old-style, as well as the
|
||||
+ * password and a couple of fields we want to set forcibly.
|
||||
*
|
||||
- * If you change this code, also change the initial-connection code in
|
||||
+ * If you change this code, see also the initial-connection code in
|
||||
* main(). For no good reason, a connection string password= takes
|
||||
* precedence in main() but not here.
|
||||
*/
|
||||
- keywords[++paramnum] = "dbname";
|
||||
- values[paramnum] = dbname;
|
||||
- keywords[++paramnum] = "password";
|
||||
- values[paramnum] = password;
|
||||
- keywords[++paramnum] = "fallback_application_name";
|
||||
- values[paramnum] = pset.progname;
|
||||
- keywords[++paramnum] = "client_encoding";
|
||||
- values[paramnum] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
|
||||
-
|
||||
+ for (ci = cinfo; ci->keyword; ci++)
|
||||
+ {
|
||||
+ keywords[paramnum] = ci->keyword;
|
||||
+
|
||||
+ if (dbname && strcmp(ci->keyword, "dbname") == 0)
|
||||
+ values[paramnum++] = dbname;
|
||||
+ else if (user && strcmp(ci->keyword, "user") == 0)
|
||||
+ values[paramnum++] = user;
|
||||
+ else if (host && strcmp(ci->keyword, "host") == 0)
|
||||
+ values[paramnum++] = host;
|
||||
+ else if (host && !same_host && strcmp(ci->keyword, "hostaddr") == 0)
|
||||
+ {
|
||||
+ /* If we're changing the host value, drop any old hostaddr */
|
||||
+ values[paramnum++] = NULL;
|
||||
+ }
|
||||
+ else if (port && strcmp(ci->keyword, "port") == 0)
|
||||
+ values[paramnum++] = port;
|
||||
+ else if (strcmp(ci->keyword, "password") == 0)
|
||||
+ values[paramnum++] = password;
|
||||
+ else if (strcmp(ci->keyword, "fallback_application_name") == 0)
|
||||
+ values[paramnum++] = pset.progname;
|
||||
+ else if (strcmp(ci->keyword, "client_encoding") == 0)
|
||||
+ values[paramnum++] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
|
||||
+ else if (ci->val)
|
||||
+ values[paramnum++] = ci->val;
|
||||
+ /* else, don't bother making libpq parse this keyword */
|
||||
+ }
|
||||
/* add array terminator */
|
||||
- keywords[++paramnum] = NULL;
|
||||
+ keywords[paramnum] = NULL;
|
||||
values[paramnum] = NULL;
|
||||
|
||||
- n_conn = PQconnectdbParams(keywords, values, true);
|
||||
+ /* Note we do not want libpq to re-expand the dbname parameter */
|
||||
+ n_conn = PQconnectdbParams(keywords, values, false);
|
||||
|
||||
pg_free(keywords);
|
||||
pg_free(values);
|
||||
|
||||
- /* We can immediately discard the password -- no longer needed */
|
||||
- if (password)
|
||||
- pg_free(password);
|
||||
-
|
||||
if (PQstatus(n_conn) == CONNECTION_OK)
|
||||
break;
|
||||
|
||||
@@ -3134,11 +3235,34 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
*/
|
||||
if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
|
||||
{
|
||||
+ /*
|
||||
+ * Prompt for password using the username we actually connected
|
||||
+ * with --- it might've come out of "dbname" rather than "user".
|
||||
+ */
|
||||
+ password = prompt_for_password(PQuser(n_conn));
|
||||
PQfinish(n_conn);
|
||||
- password = prompt_for_password(user);
|
||||
+ n_conn = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * We'll report the error below ... unless n_conn is NULL, indicating
|
||||
+ * that libpq didn't have enough memory to make a PGconn.
|
||||
+ */
|
||||
+ if (n_conn == NULL)
|
||||
+ psql_error("out of memory\n");
|
||||
+
|
||||
+ success = false;
|
||||
+ } /* end retry loop */
|
||||
+
|
||||
+ /* Release locally allocated data, whether we succeeded or not */
|
||||
+ if (password)
|
||||
+ pg_free(password);
|
||||
+ if (cinfo)
|
||||
+ PQconninfoFree(cinfo);
|
||||
+
|
||||
+ if (!success)
|
||||
+ {
|
||||
/*
|
||||
* Failed to connect to the database. In interactive mode, keep the
|
||||
* previous connection to the DB; in scripting mode, close our
|
||||
@@ -3146,7 +3270,11 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
*/
|
||||
if (pset.cur_cmd_interactive)
|
||||
{
|
||||
- psql_error("%s", PQerrorMessage(n_conn));
|
||||
+ if (n_conn)
|
||||
+ {
|
||||
+ psql_error("%s", PQerrorMessage(n_conn));
|
||||
+ PQfinish(n_conn);
|
||||
+ }
|
||||
|
||||
/* pset.db is left unmodified */
|
||||
if (o_conn)
|
||||
@@ -3154,7 +3282,12 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
}
|
||||
else
|
||||
{
|
||||
- psql_error("\\connect: %s", PQerrorMessage(n_conn));
|
||||
+ if (n_conn)
|
||||
+ {
|
||||
+ psql_error("\\connect: %s", PQerrorMessage(n_conn));
|
||||
+ PQfinish(n_conn);
|
||||
+ }
|
||||
+
|
||||
if (o_conn)
|
||||
{
|
||||
PQfinish(o_conn);
|
||||
@@ -3162,13 +3295,8 @@ 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
|
||||
--
|
||||
2.23.0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,782 +0,0 @@
|
||||
From bb3ab8bfb690721923e987d2dfab683b462c1e88 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Lane <tgl@sss.pgh.pa.us>
|
||||
Date: Thu, 24 Sep 2020 18:19:39 -0400
|
||||
Subject: [PATCH] Fix handling of -d "connection string" in pg_dump/pg_restore.
|
||||
|
||||
Parallel pg_dump failed if its -d parameter was a connection string
|
||||
containing any essential information other than host, port, or username.
|
||||
The same was true for pg_restore with --create.
|
||||
|
||||
The reason is that these scenarios failed to preserve the connection
|
||||
string from the command line; the code felt free to replace that with
|
||||
just the database name when reconnecting from a pg_dump parallel worker
|
||||
or after creating the target database. By chance, parallel pg_restore
|
||||
did not suffer this defect, as long as you didn't say --create.
|
||||
|
||||
In practice it seems that the error would be obvious only if the
|
||||
connstring included essential, non-default SSL or GSS parameters.
|
||||
This may explain why it took us so long to notice. (It also makes
|
||||
it very difficult to craft a regression test case illustrating the
|
||||
problem, since the test would fail in builds without those options.)
|
||||
|
||||
Fix by refactoring so that ConnectDatabase always receives all the
|
||||
relevant options directly from the command line, rather than
|
||||
reconstructed values. Inject a different database name, when necessary,
|
||||
by relying on libpq's rules for handling multiple "dbname" parameters.
|
||||
|
||||
While here, let's get rid of the essentially duplicate _connectDB
|
||||
function, as well as some obsolete nearby cruft.
|
||||
|
||||
Per bug #16604 from Zsolt Ero. Back-patch to all supported branches.
|
||||
|
||||
Discussion: https://postgr.es/m/16604-933f4b8791227b15@postgresql.org
|
||||
---
|
||||
src/bin/pg_dump/pg_backup.h | 36 ++--
|
||||
src/bin/pg_dump/pg_backup_archiver.c | 96 +++--------
|
||||
src/bin/pg_dump/pg_backup_archiver.h | 3 +-
|
||||
src/bin/pg_dump/pg_backup_db.c | 249 +++++++--------------------
|
||||
src/bin/pg_dump/pg_dump.c | 24 +--
|
||||
src/bin/pg_dump/pg_restore.c | 14 +-
|
||||
6 files changed, 131 insertions(+), 291 deletions(-)
|
||||
|
||||
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
|
||||
index 560de01884..72c6a8db6c 100644
|
||||
--- a/src/bin/pg_dump/pg_backup.h
|
||||
+++ b/src/bin/pg_dump/pg_backup.h
|
||||
@@ -58,6 +58,20 @@ typedef enum _teSection
|
||||
SECTION_POST_DATA /* stuff to be processed after data */
|
||||
} teSection;
|
||||
|
||||
+/* 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;
|
||||
+ 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 */
|
||||
@@ -106,12 +120,9 @@ typedef struct _restoreOptions
|
||||
SimpleStringList tableNames;
|
||||
|
||||
int useDB;
|
||||
- char *dbname; /* subject to expand_dbname */
|
||||
- char *pgport;
|
||||
- char *pghost;
|
||||
- char *username;
|
||||
+ ConnParams cparams; /* parameters to use if useDB */
|
||||
+
|
||||
int noDataForFailedTables;
|
||||
- trivalue promptPassword;
|
||||
int exit_on_error;
|
||||
int compression;
|
||||
int suppressDumpWarnings; /* Suppress output of WARNING entries
|
||||
@@ -126,10 +137,8 @@ typedef struct _restoreOptions
|
||||
|
||||
typedef struct _dumpOptions
|
||||
{
|
||||
- const char *dbname; /* subject to expand_dbname */
|
||||
- const char *pghost;
|
||||
- const char *pgport;
|
||||
- const char *username;
|
||||
+ ConnParams cparams;
|
||||
+
|
||||
bool oids;
|
||||
|
||||
int binary_upgrade;
|
||||
@@ -239,12 +248,9 @@ typedef void (*SetupWorkerPtrType) (Archive *AH);
|
||||
* Main archiver interface.
|
||||
*/
|
||||
|
||||
-extern void ConnectDatabase(Archive *AH,
|
||||
- const char *dbname,
|
||||
- const char *pghost,
|
||||
- const char *pgport,
|
||||
- const char *username,
|
||||
- trivalue prompt_password);
|
||||
+extern void ConnectDatabase(Archive *AHX,
|
||||
+ const ConnParams *cparams,
|
||||
+ bool isReconnect);
|
||||
extern void DisconnectDatabase(Archive *AHX);
|
||||
extern PGconn *GetConnection(Archive *AHX);
|
||||
|
||||
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
|
||||
index 8892b17790..4003ab3b13 100644
|
||||
--- a/src/bin/pg_dump/pg_backup_archiver.c
|
||||
+++ b/src/bin/pg_dump/pg_backup_archiver.c
|
||||
@@ -144,6 +144,7 @@ InitDumpOptions(DumpOptions *opts)
|
||||
memset(opts, 0, sizeof(DumpOptions));
|
||||
/* set any fields that shouldn't default to zeroes */
|
||||
opts->include_everything = true;
|
||||
+ opts->cparams.promptPassword = TRI_DEFAULT;
|
||||
opts->dumpSections = DUMP_UNSECTIONED;
|
||||
}
|
||||
|
||||
@@ -157,6 +158,11 @@ dumpOptionsFromRestoreOptions(RestoreOptions *ropt)
|
||||
DumpOptions *dopt = NewDumpOptions();
|
||||
|
||||
/* this is the inverse of what's at the end of pg_dump.c's main() */
|
||||
+ dopt->cparams.dbname = ropt->cparams.dbname ? pg_strdup(ropt->cparams.dbname) : NULL;
|
||||
+ dopt->cparams.pgport = ropt->cparams.pgport ? pg_strdup(ropt->cparams.pgport) : NULL;
|
||||
+ dopt->cparams.pghost = ropt->cparams.pghost ? pg_strdup(ropt->cparams.pghost) : NULL;
|
||||
+ dopt->cparams.username = ropt->cparams.username ? pg_strdup(ropt->cparams.username) : NULL;
|
||||
+ dopt->cparams.promptPassword = ropt->cparams.promptPassword;
|
||||
dopt->outputClean = ropt->dropSchema;
|
||||
dopt->dataOnly = ropt->dataOnly;
|
||||
dopt->schemaOnly = ropt->schemaOnly;
|
||||
@@ -401,9 +407,7 @@ RestoreArchive(Archive *AHX)
|
||||
AHX->minRemoteVersion = 0;
|
||||
AHX->maxRemoteVersion = 9999999;
|
||||
|
||||
- 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
|
||||
@@ -823,16 +827,8 @@ 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 = connstr.data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -966,7 +962,7 @@ NewRestoreOptions(void)
|
||||
|
||||
/* 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;
|
||||
|
||||
return opts;
|
||||
@@ -2388,8 +2384,6 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
|
||||
else
|
||||
AH->format = fmt;
|
||||
|
||||
- AH->promptPassword = TRI_DEFAULT;
|
||||
-
|
||||
switch (AH->format)
|
||||
{
|
||||
case archCustom:
|
||||
@@ -3157,27 +3151,20 @@ _doSetWithOids(ArchiveHandle *AH, const bool withOids)
|
||||
* If we're currently restoring right into a database, this will
|
||||
* actually establish a connection. Otherwise it puts a \connect into
|
||||
* the script output.
|
||||
- *
|
||||
- * NULL dbname implies reconnecting to the current DB (pretty useless).
|
||||
*/
|
||||
static void
|
||||
_reconnectToDB(ArchiveHandle *AH, const char *dbname)
|
||||
{
|
||||
if (RestoringToDB(AH))
|
||||
- ReconnectToServer(AH, dbname, NULL);
|
||||
+ ReconnectToServer(AH, dbname);
|
||||
else
|
||||
{
|
||||
- if (dbname)
|
||||
- {
|
||||
- PQExpBufferData connectbuf;
|
||||
+ PQExpBufferData connectbuf;
|
||||
|
||||
- initPQExpBuffer(&connectbuf);
|
||||
- appendPsqlMetaConnect(&connectbuf, dbname);
|
||||
- ahprintf(AH, "%s\n", connectbuf.data);
|
||||
- termPQExpBuffer(&connectbuf);
|
||||
- }
|
||||
- else
|
||||
- ahprintf(AH, "%s\n", "\\connect -\n");
|
||||
+ initPQExpBuffer(&connectbuf);
|
||||
+ appendPsqlMetaConnect(&connectbuf, dbname);
|
||||
+ ahprintf(AH, "%s\n", connectbuf.data);
|
||||
+ termPQExpBuffer(&connectbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4107,9 +4094,7 @@ restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* re-establish fixed state */
|
||||
_doSetFixedOutputState(AH);
|
||||
@@ -4690,54 +4675,15 @@ CloneArchive(ArchiveHandle *AH)
|
||||
clone->public.n_errors = 0;
|
||||
|
||||
/*
|
||||
- * Connect our new clone object to the database: In parallel restore the
|
||||
- * parent is already disconnected, because we can connect the worker
|
||||
- * processes independently to the database (no snapshot sync required). In
|
||||
- * parallel backup we clone the parent's existing connection.
|
||||
+ * Connect our new clone object to the database, using the same connection
|
||||
+ * parameters used for the original connection.
|
||||
*/
|
||||
- if (AH->mode == archModeRead)
|
||||
- {
|
||||
- RestoreOptions *ropt = AH->public.ropt;
|
||||
-
|
||||
- Assert(AH->connection == NULL);
|
||||
-
|
||||
- /* this also sets clone->connection */
|
||||
- ConnectDatabase((Archive *) clone, ropt->dbname,
|
||||
- ropt->pghost, ropt->pgport, ropt->username,
|
||||
- ropt->promptPassword);
|
||||
+ ConnectDatabase((Archive *) clone, &clone->public.ropt->cparams, true);
|
||||
|
||||
- /* re-establish fixed state */
|
||||
+ /* re-establish fixed state */
|
||||
+ if (AH->mode == archModeRead)
|
||||
_doSetFixedOutputState(clone);
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- PQExpBufferData connstr;
|
||||
- char *pghost;
|
||||
- char *pgport;
|
||||
- char *username;
|
||||
-
|
||||
- Assert(AH->connection != NULL);
|
||||
-
|
||||
- /*
|
||||
- * Even though we are technically accessing the parent's database
|
||||
- * object here, these functions are fine to be called like that
|
||||
- * because all just return a pointer and do not actually send/receive
|
||||
- * any data to/from the database.
|
||||
- */
|
||||
- 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, connstr.data,
|
||||
- pghost, pgport, username, TRI_NO);
|
||||
-
|
||||
- termPQExpBuffer(&connstr);
|
||||
- /* setupDumpWorker will fix up connection state */
|
||||
- }
|
||||
+ /* in write case, setupDumpWorker will fix up connection state */
|
||||
|
||||
/* Let the format-specific code have a chance too */
|
||||
(clone->ClonePtr) (clone);
|
||||
diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h
|
||||
index 3b69868359..50829c4b2e 100644
|
||||
--- a/src/bin/pg_dump/pg_backup_archiver.h
|
||||
+++ b/src/bin/pg_dump/pg_backup_archiver.h
|
||||
@@ -304,7 +304,6 @@ struct _archiveHandle
|
||||
|
||||
/* Stuff for direct DB connection */
|
||||
char *archdbname; /* DB name *read* from archive */
|
||||
- trivalue promptPassword;
|
||||
char *savedPassword; /* password for ropt->username, if known */
|
||||
char *use_role;
|
||||
PGconn *connection;
|
||||
@@ -450,7 +449,7 @@ extern void InitArchiveFmt_Tar(ArchiveHandle *AH);
|
||||
|
||||
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);
|
||||
|
||||
void ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);
|
||||
diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
|
||||
index 43f5941f93..4eaea4af4f 100644
|
||||
--- a/src/bin/pg_dump/pg_backup_db.c
|
||||
+++ b/src/bin/pg_dump/pg_backup_db.c
|
||||
@@ -30,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 void
|
||||
@@ -76,186 +75,51 @@ _check_database_version(ArchiveHandle *AH)
|
||||
|
||||
/*
|
||||
* 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.
|
||||
+ * else the one associated with the archive handle.
|
||||
*/
|
||||
-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);
|
||||
-
|
||||
- /* Update ArchiveHandle's connCancel before closing old connection */
|
||||
- set_archive_cancel_info(AH, newConn);
|
||||
-
|
||||
- PQfinish(AH->connection);
|
||||
- AH->connection = newConn;
|
||||
-
|
||||
- /* Start strict; later phases may override this. */
|
||||
- PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,
|
||||
- ALWAYS_SECURE_SEARCH_PATH_SQL));
|
||||
-
|
||||
- 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
|
||||
- * 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;
|
||||
- char passbuf[100];
|
||||
- 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);
|
||||
-
|
||||
- password = AH->savedPassword;
|
||||
-
|
||||
- if (AH->promptPassword == TRI_YES && password == NULL)
|
||||
- {
|
||||
- simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
|
||||
- password = passbuf;
|
||||
- }
|
||||
-
|
||||
- initPQExpBuffer(&connstr);
|
||||
- appendPQExpBuffer(&connstr, "dbname=");
|
||||
- appendConnStrVal(&connstr, newdb);
|
||||
-
|
||||
- do
|
||||
- {
|
||||
- const char *keywords[7];
|
||||
- const char *values[7];
|
||||
-
|
||||
- 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);
|
||||
-
|
||||
- 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 (AH->promptPassword != TRI_NO)
|
||||
- {
|
||||
- simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
|
||||
- password = passbuf;
|
||||
- }
|
||||
- else
|
||||
- exit_horribly(modulename, "connection needs password\n");
|
||||
-
|
||||
- new_pass = true;
|
||||
- }
|
||||
- } while (new_pass);
|
||||
+ PGconn *oldConn = AH->connection;
|
||||
+ RestoreOptions *ropt = AH->public.ropt;
|
||||
|
||||
/*
|
||||
- * We want to remember connection's actual password, whether or not we got
|
||||
- * it by prompting. So we don't just store the password variable.
|
||||
+ * Save the dbname, if given, in override_dbname so that it will also
|
||||
+ * affect any later reconnection attempt.
|
||||
*/
|
||||
- if (PQconnectionUsedPassword(newConn))
|
||||
- {
|
||||
- if (AH->savedPassword)
|
||||
- free(AH->savedPassword);
|
||||
- AH->savedPassword = pg_strdup(PQpass(newConn));
|
||||
- }
|
||||
+ if (dbname)
|
||||
+ ropt->cparams.override_dbname = pg_strdup(dbname);
|
||||
|
||||
- termPQExpBuffer(&connstr);
|
||||
-
|
||||
- /* check for version mismatch */
|
||||
- _check_database_version(AH);
|
||||
+ /*
|
||||
+ * 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 */
|
||||
|
||||
- PQsetNoticeProcessor(newConn, notice_processor, NULL);
|
||||
+ ConnectDatabase((Archive *) AH, &ropt->cparams, true);
|
||||
|
||||
- return newConn;
|
||||
+ PQfinish(oldConn);
|
||||
}
|
||||
|
||||
-
|
||||
/*
|
||||
- * Make a database connection with the given parameters. The
|
||||
- * connection handle is returned, the parameters are stored in AHX.
|
||||
- * An interactive password prompt is automatically issued if required.
|
||||
+ * 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
|
||||
* username never does change, so one savedPassword is sufficient.
|
||||
*/
|
||||
void
|
||||
ConnectDatabase(Archive *AHX,
|
||||
- const char *dbname,
|
||||
- const char *pghost,
|
||||
- const char *pgport,
|
||||
- const char *username,
|
||||
- trivalue prompt_password)
|
||||
+ const ConnParams *cparams,
|
||||
+ bool isReconnect)
|
||||
{
|
||||
ArchiveHandle *AH = (ArchiveHandle *) AHX;
|
||||
+ trivalue prompt_password;
|
||||
char *password;
|
||||
char passbuf[100];
|
||||
bool new_pass;
|
||||
@@ -263,6 +127,9 @@ ConnectDatabase(Archive *AHX,
|
||||
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;
|
||||
+
|
||||
password = AH->savedPassword;
|
||||
|
||||
if (prompt_password == TRI_YES && password == NULL)
|
||||
@@ -270,7 +137,6 @@ ConnectDatabase(Archive *AHX,
|
||||
simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
|
||||
password = passbuf;
|
||||
}
|
||||
- AH->promptPassword = prompt_password;
|
||||
|
||||
/*
|
||||
* Start the connection. Loop until we have a password if requested by
|
||||
@@ -278,23 +144,35 @@ ConnectDatabase(Archive *AHX,
|
||||
*/
|
||||
do
|
||||
{
|
||||
- const char *keywords[7];
|
||||
- const char *values[7];
|
||||
-
|
||||
- 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;
|
||||
+ 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;
|
||||
+ Assert(i <= lengthof(keywords));
|
||||
|
||||
new_pass = false;
|
||||
AH->connection = PQconnectdbParams(keywords, values, true);
|
||||
@@ -316,9 +194,16 @@ ConnectDatabase(Archive *AHX,
|
||||
|
||||
/* 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));
|
||||
+ }
|
||||
|
||||
/* Start strict; later phases may override this. */
|
||||
PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,
|
||||
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
|
||||
index 8080155a95..abcee89d10 100644
|
||||
--- a/src/bin/pg_dump/pg_dump.c
|
||||
+++ b/src/bin/pg_dump/pg_dump.c
|
||||
@@ -302,7 +302,6 @@ main(int argc, char **argv)
|
||||
const char *dumpsnapshot = NULL;
|
||||
char *use_role = NULL;
|
||||
int numWorkers = 1;
|
||||
- trivalue prompt_password = TRI_DEFAULT;
|
||||
int compressLevel = -1;
|
||||
int plainText = 0;
|
||||
ArchiveFormat archiveFormat = archUnknown;
|
||||
@@ -431,7 +430,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'd': /* database name */
|
||||
- dopt.dbname = pg_strdup(optarg);
|
||||
+ dopt.cparams.dbname = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'E': /* Dump encoding */
|
||||
@@ -447,7 +446,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'h': /* server host */
|
||||
- dopt.pghost = pg_strdup(optarg);
|
||||
+ dopt.cparams.pghost = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'j': /* number of dump jobs */
|
||||
@@ -472,7 +471,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'p': /* server port */
|
||||
- dopt.pgport = pg_strdup(optarg);
|
||||
+ dopt.cparams.pgport = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
@@ -497,7 +496,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
- dopt.username = pg_strdup(optarg);
|
||||
+ dopt.cparams.username = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'v': /* verbose */
|
||||
@@ -505,11 +504,11 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
- prompt_password = TRI_NO;
|
||||
+ dopt.cparams.promptPassword = TRI_NO;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
- prompt_password = TRI_YES;
|
||||
+ dopt.cparams.promptPassword = TRI_YES;
|
||||
break;
|
||||
|
||||
case 'x': /* skip ACL dump */
|
||||
@@ -563,8 +562,8 @@ main(int argc, char **argv)
|
||||
* Non-option argument specifies database name as long as it wasn't
|
||||
* already specified with -d / --dbname
|
||||
*/
|
||||
- if (optind < argc && dopt.dbname == NULL)
|
||||
- dopt.dbname = argv[optind++];
|
||||
+ if (optind < argc && dopt.cparams.dbname == NULL)
|
||||
+ dopt.cparams.dbname = argv[optind++];
|
||||
|
||||
/* Complain if any arguments remain */
|
||||
if (optind < argc)
|
||||
@@ -677,7 +676,7 @@ main(int argc, char **argv)
|
||||
* Open the database using the Archiver, so it knows about it. Errors mean
|
||||
* death.
|
||||
*/
|
||||
- ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
|
||||
+ ConnectDatabase(fout, &dopt.cparams, false);
|
||||
setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
|
||||
|
||||
/*
|
||||
@@ -860,6 +859,11 @@ main(int argc, char **argv)
|
||||
ropt->filename = filename;
|
||||
|
||||
/* if you change this list, see dumpOptionsFromRestoreOptions */
|
||||
+ ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
|
||||
+ ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
|
||||
+ ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
|
||||
+ ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
|
||||
+ ropt->cparams.promptPassword = dopt.cparams.promptPassword;
|
||||
ropt->dropSchema = dopt.outputClean;
|
||||
ropt->dataOnly = dopt.dataOnly;
|
||||
ropt->schemaOnly = dopt.schemaOnly;
|
||||
diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
|
||||
index 860a211a3c..ce03ded8ec 100644
|
||||
--- a/src/bin/pg_dump/pg_restore.c
|
||||
+++ b/src/bin/pg_dump/pg_restore.c
|
||||
@@ -163,7 +163,7 @@ main(int argc, char **argv)
|
||||
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;
|
||||
@@ -177,7 +177,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
case 'h':
|
||||
if (strlen(optarg) != 0)
|
||||
- opts->pghost = pg_strdup(optarg);
|
||||
+ opts->cparams.pghost = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'j': /* number of restore jobs */
|
||||
@@ -206,7 +206,7 @@ main(int argc, char **argv)
|
||||
|
||||
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 */
|
||||
@@ -240,7 +240,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
- opts->username = pg_strdup(optarg);
|
||||
+ opts->cparams.username = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'v': /* verbose */
|
||||
@@ -248,11 +248,11 @@ main(int argc, char **argv)
|
||||
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 */
|
||||
@@ -302,7 +302,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* Should get at most one of -d and -f, else user is confused */
|
||||
- if (opts->dbname)
|
||||
+ if (opts->cparams.dbname)
|
||||
{
|
||||
if (opts->filename)
|
||||
{
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,241 +0,0 @@
|
||||
From f97ecea1ed7b09c6f1398540a1d72a57eee70c9f Mon Sep 17 00:00:00 2001
|
||||
From: Noah Misch <noah@leadboat.com>
|
||||
Date: Mon, 9 Nov 2020 07:32:09 -0800
|
||||
Subject: [PATCH] In security-restricted operations, block enqueue of at-commit
|
||||
user code.
|
||||
|
||||
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).
|
||||
|
||||
Reviewed by Robert Haas. Reported by Etienne Stalmans.
|
||||
|
||||
Security: CVE-2020-25695
|
||||
---
|
||||
contrib/postgres_fdw/connection.c | 4 +++
|
||||
src/backend/access/transam/xact.c | 13 ++++----
|
||||
src/backend/commands/portalcmds.c | 5 +++
|
||||
src/backend/commands/trigger.c | 12 +++++++
|
||||
src/test/regress/expected/privileges.out | 42 ++++++++++++++++++++++++
|
||||
src/test/regress/sql/privileges.sql | 34 +++++++++++++++++++
|
||||
6 files changed, 104 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
|
||||
index 885bd075798c..5dcff3d07624 100644
|
||||
--- a/contrib/postgres_fdw/connection.c
|
||||
+++ b/contrib/postgres_fdw/connection.c
|
||||
@@ -645,6 +645,10 @@ pgfdw_report_error(int elevel, PGresult *res, PGconn *conn,
|
||||
|
||||
/*
|
||||
* pgfdw_xact_callback --- cleanup at main-transaction end.
|
||||
+ *
|
||||
+ * This runs just late enough that it must not enter user-defined code
|
||||
+ * locally. (Entering such code on the remote side is fine. Its remote
|
||||
+ * COMMIT TRANSACTION may run deferred triggers.)
|
||||
*/
|
||||
static void
|
||||
pgfdw_xact_callback(XactEvent event, void *arg)
|
||||
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
|
||||
index 37f31a2c31ea..00cec50e8402 100644
|
||||
--- a/src/backend/access/transam/xact.c
|
||||
+++ b/src/backend/access/transam/xact.c
|
||||
@@ -1994,9 +1994,10 @@ CommitTransaction(void)
|
||||
|
||||
/*
|
||||
* Do pre-commit processing that involves calling user-defined code, such
|
||||
- * as triggers. Since closing cursors could queue trigger actions,
|
||||
- * triggers could open cursors, etc, we have to keep looping until there's
|
||||
- * nothing left to do.
|
||||
+ * as triggers. SECURITY_RESTRICTED_OPERATION contexts must not queue an
|
||||
+ * action that would run here, because that would bypass the sandbox.
|
||||
+ * Since closing cursors could queue trigger actions, triggers could open
|
||||
+ * cursors, etc, we have to keep looping until there's nothing left to do.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
@@ -2014,9 +2015,6 @@ CommitTransaction(void)
|
||||
break;
|
||||
}
|
||||
|
||||
- CallXactCallbacks(is_parallel_worker ? XACT_EVENT_PARALLEL_PRE_COMMIT
|
||||
- : XACT_EVENT_PRE_COMMIT);
|
||||
-
|
||||
/*
|
||||
* The remaining actions cannot call any user-defined code, so it's safe
|
||||
* to start shutting down within-transaction services. But note that most
|
||||
@@ -2024,6 +2022,9 @@ CommitTransaction(void)
|
||||
* the transaction-abort path.
|
||||
*/
|
||||
|
||||
+ CallXactCallbacks(is_parallel_worker ? XACT_EVENT_PARALLEL_PRE_COMMIT
|
||||
+ : XACT_EVENT_PRE_COMMIT);
|
||||
+
|
||||
/* If we might have parallel workers, clean them up now. */
|
||||
if (IsInParallelMode())
|
||||
AtEOXact_Parallel(true);
|
||||
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
|
||||
index 46369cf3dbee..3d01a782da06 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 "rewrite/rewriteHandler.h"
|
||||
#include "tcop/pquery.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
@@ -64,6 +65,10 @@ PerformCursorOpen(DeclareCursorStmt *cstmt, 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")));
|
||||
|
||||
/*
|
||||
* Parse analysis was done already, but we still have to run the rule
|
||||
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
|
||||
index f83840625348..9c04eee48422 100644
|
||||
--- a/src/backend/commands/trigger.c
|
||||
+++ b/src/backend/commands/trigger.c
|
||||
@@ -4144,6 +4144,7 @@ afterTriggerMarkEvents(AfterTriggerEventList *events,
|
||||
bool immediate_only)
|
||||
{
|
||||
bool found = false;
|
||||
+ bool deferred_found = false;
|
||||
AfterTriggerEvent event;
|
||||
AfterTriggerEventChunk *chunk;
|
||||
|
||||
@@ -4179,6 +4180,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 */
|
||||
@@ -4186,6 +4188,16 @@ 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;
|
||||
}
|
||||
|
||||
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
|
||||
index dacc98450514..26ee16a0c370 100644
|
||||
--- a/src/test/regress/expected/privileges.out
|
||||
+++ b/src/test/regress/expected/privileges.out
|
||||
@@ -1253,6 +1253,48 @@ SELECT has_table_privilege('regress_user1', 'atest4', 'SELECT WITH GRANT OPTION'
|
||||
t
|
||||
(1 row)
|
||||
|
||||
+-- security-restricted operations
|
||||
+\c -
|
||||
+CREATE ROLE regress_sro_user;
|
||||
+SET SESSION AUTHORIZATION regress_sro_user;
|
||||
+CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
|
||||
+ 'GRANT regress_group2 TO regress_sro_user';
|
||||
+CREATE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
+ 'DECLARE c CURSOR WITH HOLD FOR SELECT unwanted_grant(); SELECT true';
|
||||
+-- REFRESH of this MV will queue a GRANT at end of transaction
|
||||
+CREATE MATERIALIZED VIEW sro_mv AS SELECT mv_action() WITH NO DATA;
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+ERROR: cannot create a cursor WITH HOLD within security-restricted operation
|
||||
+CONTEXT: SQL function "mv_action" statement 1
|
||||
+\c -
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+ERROR: cannot create a cursor WITH HOLD within security-restricted operation
|
||||
+CONTEXT: SQL function "mv_action" statement 1
|
||||
+SET SESSION AUTHORIZATION regress_sro_user;
|
||||
+-- INSERT to this table will queue a GRANT at end of transaction
|
||||
+CREATE TABLE sro_trojan_table ();
|
||||
+CREATE FUNCTION sro_trojan() RETURNS trigger LANGUAGE plpgsql AS
|
||||
+ 'BEGIN PERFORM unwanted_grant(); RETURN NULL; END';
|
||||
+CREATE CONSTRAINT TRIGGER t AFTER INSERT ON sro_trojan_table
|
||||
+ INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE sro_trojan();
|
||||
+-- Now, REFRESH will issue such an INSERT, queueing the GRANT
|
||||
+CREATE OR REPLACE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
+ 'INSERT INTO sro_trojan_table DEFAULT VALUES; SELECT true';
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+ERROR: cannot fire deferred trigger within security-restricted operation
|
||||
+CONTEXT: SQL function "mv_action" statement 1
|
||||
+\c -
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+ERROR: cannot fire deferred trigger within security-restricted operation
|
||||
+CONTEXT: SQL function "mv_action" statement 1
|
||||
+BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT;
|
||||
+ERROR: must have admin option on role "regress_group2"
|
||||
+CONTEXT: SQL function "unwanted_grant" statement 1
|
||||
+SQL statement "SELECT unwanted_grant()"
|
||||
+PL/pgSQL function sro_trojan() line 1 at PERFORM
|
||||
+SQL function "mv_action" statement 1
|
||||
+DROP OWNED BY regress_sro_user;
|
||||
+DROP ROLE regress_sro_user;
|
||||
-- Admin options
|
||||
SET SESSION AUTHORIZATION regress_user4;
|
||||
CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS
|
||||
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
|
||||
index 4263315a2d87..f979cccea03f 100644
|
||||
--- a/src/test/regress/sql/privileges.sql
|
||||
+++ b/src/test/regress/sql/privileges.sql
|
||||
@@ -761,6 +761,40 @@ SELECT has_table_privilege('regress_user3', 'atest4', 'SELECT'); -- false
|
||||
SELECT has_table_privilege('regress_user1', 'atest4', 'SELECT WITH GRANT OPTION'); -- true
|
||||
|
||||
|
||||
+-- security-restricted operations
|
||||
+\c -
|
||||
+CREATE ROLE regress_sro_user;
|
||||
+
|
||||
+SET SESSION AUTHORIZATION regress_sro_user;
|
||||
+CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
|
||||
+ 'GRANT regress_group2 TO regress_sro_user';
|
||||
+CREATE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
+ 'DECLARE c CURSOR WITH HOLD FOR SELECT unwanted_grant(); SELECT true';
|
||||
+-- REFRESH of this MV will queue a GRANT at end of transaction
|
||||
+CREATE MATERIALIZED VIEW sro_mv AS SELECT mv_action() WITH NO DATA;
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+\c -
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+
|
||||
+SET SESSION AUTHORIZATION regress_sro_user;
|
||||
+-- INSERT to this table will queue a GRANT at end of transaction
|
||||
+CREATE TABLE sro_trojan_table ();
|
||||
+CREATE FUNCTION sro_trojan() RETURNS trigger LANGUAGE plpgsql AS
|
||||
+ 'BEGIN PERFORM unwanted_grant(); RETURN NULL; END';
|
||||
+CREATE CONSTRAINT TRIGGER t AFTER INSERT ON sro_trojan_table
|
||||
+ INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE sro_trojan();
|
||||
+-- Now, REFRESH will issue such an INSERT, queueing the GRANT
|
||||
+CREATE OR REPLACE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
+ 'INSERT INTO sro_trojan_table DEFAULT VALUES; SELECT true';
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+\c -
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT;
|
||||
+
|
||||
+DROP OWNED BY regress_sro_user;
|
||||
+DROP ROLE regress_sro_user;
|
||||
+
|
||||
+
|
||||
-- Admin options
|
||||
|
||||
SET SESSION AUTHORIZATION regress_user4;
|
||||
@ -1,121 +0,0 @@
|
||||
From a498db87be103f93856dd515a574b2d67d3c1237 Mon Sep 17 00:00:00 2001
|
||||
From: Noah Misch <noah@leadboat.com>
|
||||
Date: Mon, 9 Nov 2020 07:32:09 -0800
|
||||
Subject: [PATCH] Ignore attempts to \gset into specially treated variables.
|
||||
|
||||
If an interactive psql session used \gset when querying a compromised
|
||||
server, the attacker could execute arbitrary code as the operating
|
||||
system account running psql. Using a prefix not found among specially
|
||||
treated variables, e.g. every lowercase string, precluded the attack.
|
||||
Fix by issuing a warning and setting no variable for the column in
|
||||
question. Users wanting the old behavior can use a prefix and then a
|
||||
meta-command like "\set HISTSIZE :prefix_HISTSIZE". Back-patch to 9.5
|
||||
(all supported versions).
|
||||
|
||||
Reviewed by Robert Haas. Reported by Nick Cleaton.
|
||||
|
||||
Security: CVE-2020-25696
|
||||
---
|
||||
src/bin/psql/common.c | 7 +++++++
|
||||
src/bin/psql/variables.c | 26 ++++++++++++++++++++++++++
|
||||
src/bin/psql/variables.h | 1 +
|
||||
src/test/regress/expected/psql.out | 4 ++++
|
||||
src/test/regress/sql/psql.sql | 3 +++
|
||||
5 files changed, 41 insertions(+)
|
||||
|
||||
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
|
||||
index d04a7943d6a9..4e342c180a6c 100644
|
||||
--- a/src/bin/psql/common.c
|
||||
+++ b/src/bin/psql/common.c
|
||||
@@ -894,6 +894,13 @@ StoreQueryTuple(const PGresult *result)
|
||||
/* concatenate prefix and column name */
|
||||
varname = psprintf("%s%s", pset.gset_prefix, colname);
|
||||
|
||||
+ if (VariableHasHook(pset.vars, varname))
|
||||
+ {
|
||||
+ psql_error("attempt to \\gset into specially treated variable \"%s\" ignored\n",
|
||||
+ varname);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
if (!PQgetisnull(result, 0, i))
|
||||
value = PQgetvalue(result, 0, i);
|
||||
else
|
||||
diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c
|
||||
index 120b25c69661..0d28ba9c92bb 100644
|
||||
--- a/src/bin/psql/variables.c
|
||||
+++ b/src/bin/psql/variables.c
|
||||
@@ -360,6 +360,32 @@ SetVariableHooks(VariableSpace space, const char *name,
|
||||
(void) (*ahook) (current->value);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Return true iff the named variable has substitute and/or assign hook
|
||||
+ * functions.
|
||||
+ */
|
||||
+bool
|
||||
+VariableHasHook(VariableSpace space, const char *name)
|
||||
+{
|
||||
+ struct _variable *current;
|
||||
+
|
||||
+ Assert(space);
|
||||
+ Assert(name);
|
||||
+
|
||||
+ for (current = space->next; current; current = current->next)
|
||||
+ {
|
||||
+ int cmp = strcmp(current->name, name);
|
||||
+
|
||||
+ if (cmp == 0)
|
||||
+ return (current->substitute_hook != NULL ||
|
||||
+ current->assign_hook != NULL);
|
||||
+ if (cmp > 0)
|
||||
+ break; /* it's not there */
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Convenience function to set a variable's value to "on".
|
||||
*/
|
||||
diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h
|
||||
index 02d85b1bc2e4..8dc5c20ee8fc 100644
|
||||
--- a/src/bin/psql/variables.h
|
||||
+++ b/src/bin/psql/variables.h
|
||||
@@ -90,6 +90,7 @@ bool DeleteVariable(VariableSpace space, const char *name);
|
||||
void SetVariableHooks(VariableSpace space, const char *name,
|
||||
VariableSubstituteHook shook,
|
||||
VariableAssignHook ahook);
|
||||
+bool VariableHasHook(VariableSpace space, const char *name);
|
||||
|
||||
void PsqlVarEnumError(const char *name, const char *value, const char *suggestions);
|
||||
|
||||
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
|
||||
index 0c94144575af..1ae81912c734 100644
|
||||
--- a/src/test/regress/expected/psql.out
|
||||
+++ b/src/test/regress/expected/psql.out
|
||||
@@ -84,6 +84,10 @@ select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_
|
||||
select 10 as "bad name"
|
||||
\gset
|
||||
invalid variable name: "bad name"
|
||||
+select 97 as "EOF", 'ok' as _foo \gset IGNORE
|
||||
+attempt to \gset into specially treated variable "IGNOREEOF" ignored
|
||||
+\echo :IGNORE_foo :IGNOREEOF
|
||||
+ok 0
|
||||
-- multiple backslash commands in one line
|
||||
select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x
|
||||
1
|
||||
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
|
||||
index 4a676c311955..7f8ab2e5c218 100644
|
||||
--- a/src/test/regress/sql/psql.sql
|
||||
+++ b/src/test/regress/sql/psql.sql
|
||||
@@ -48,6 +48,9 @@ select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_
|
||||
select 10 as "bad name"
|
||||
\gset
|
||||
|
||||
+select 97 as "EOF", 'ok' as _foo \gset IGNORE
|
||||
+\echo :IGNORE_foo :IGNOREEOF
|
||||
+
|
||||
-- multiple backslash commands in one line
|
||||
select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x
|
||||
select 3 as x, 4 as y \gset pref01_ \echo :pref01_x \echo :pref01_y
|
||||
@ -1,163 +0,0 @@
|
||||
From eeede2470a8ec902c80de449d2c4822330c689ca Mon Sep 17 00:00:00 2001
|
||||
From: wang_yue111 <648774160@qq.com>
|
||||
Date: Fri, 26 Feb 2021 12:57:48 +0800
|
||||
Subject: [PATCH] Fix mishandling of column-level SELECT privileges for join
|
||||
aliases.
|
||||
|
||||
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
|
||||
pass the wrong RTE to markVarForSelectPriv when dealing with a join
|
||||
ParseNamespaceItem: they'd pass the join RTE, when what we need to
|
||||
mark is the base table that the join column came from. The end
|
||||
result was to not fill the base table's selectedCols bitmap correctly,
|
||||
resulting in an understatement of the set of columns that are read
|
||||
by the query. The executor would still insist on there being at
|
||||
least one selectable column; but with a correctly crafted query,
|
||||
a user having SELECT privilege on just one column of a table would
|
||||
nonetheless be allowed to read all its columns.
|
||||
|
||||
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
|
||||
ignoring the possibly-mismatched RTE passed by the caller. Later,
|
||||
we'll get rid of some now-unused RTE arguments, but that risks
|
||||
API breaks so we won't do it in released branches.
|
||||
|
||||
This problem was introduced by commit 9ce77d75c, so back-patch
|
||||
to v13 where that came in. Thanks to Sven Klemm for reporting
|
||||
the problem.
|
||||
|
||||
Security: CVE-2021-20229
|
||||
|
||||
---
|
||||
src/backend/parser/parse_relation.c | 40 ++++++++++-----------
|
||||
src/backend/parser/parse_target.c | 8 +++--
|
||||
4 files changed, 91 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
|
||||
index bbbb0b6..7ab4ba7 100644
|
||||
--- a/src/backend/parser/parse_relation.c
|
||||
+++ b/src/backend/parser/parse_relation.c
|
||||
@@ -43,7 +43,8 @@ static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid,
|
||||
int location);
|
||||
static void check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem,
|
||||
int location);
|
||||
-static void markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
||||
+static void markRTEForSelectPriv(ParseState *pstate,
|
||||
+
|
||||
int rtindex, AttrNumber col);
|
||||
static void expandRelation(Oid relid, Alias *eref,
|
||||
int rtindex, int sublevels_up,
|
||||
@@ -897,20 +898,15 @@ searchRangeTableForCol(ParseState *pstate, const char *alias, char *colname,
|
||||
|
||||
/*
|
||||
* markRTEForSelectPriv
|
||||
- * Mark the specified column of an RTE as requiring SELECT privilege
|
||||
+ * Mark the specified column of the RTE with index rtindex
|
||||
+ * as requiring SELECT privilege
|
||||
*
|
||||
* col == InvalidAttrNumber means a "whole row" reference
|
||||
- *
|
||||
- * The caller should pass the actual RTE if it has it handy; otherwise pass
|
||||
- * NULL, and we'll look it up here. (This uglification of the API is
|
||||
- * worthwhile because nearly all external callers have the RTE at hand.)
|
||||
*/
|
||||
static void
|
||||
-markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
||||
- int rtindex, AttrNumber col)
|
||||
+markRTEForSelectPriv(ParseState *pstate, int rtindex, AttrNumber col)
|
||||
{
|
||||
- if (rte == NULL)
|
||||
- rte = rt_fetch(rtindex, pstate->p_rtable);
|
||||
+ RangeTblEntry *rte = rt_fetch(rtindex, pstate->p_rtable);
|
||||
|
||||
if (rte->rtekind == RTE_RELATION)
|
||||
{
|
||||
@@ -942,13 +938,13 @@ markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
||||
{
|
||||
int varno = ((RangeTblRef *) j->larg)->rtindex;
|
||||
|
||||
- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
||||
+ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
||||
}
|
||||
else if (IsA(j->larg, JoinExpr))
|
||||
{
|
||||
int varno = ((JoinExpr *) j->larg)->rtindex;
|
||||
|
||||
- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
||||
+ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
||||
}
|
||||
else
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
@@ -957,13 +953,13 @@ markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
||||
{
|
||||
int varno = ((RangeTblRef *) j->rarg)->rtindex;
|
||||
|
||||
- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
||||
+ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
||||
}
|
||||
else if (IsA(j->rarg, JoinExpr))
|
||||
{
|
||||
int varno = ((JoinExpr *) j->rarg)->rtindex;
|
||||
|
||||
- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
||||
+ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
||||
}
|
||||
else
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
@@ -994,10 +990,10 @@ markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
||||
|
||||
/*
|
||||
* markVarForSelectPriv
|
||||
- * Mark the RTE referenced by a Var as requiring SELECT privilege
|
||||
+ * Mark the RTE referenced by the Var as requiring SELECT privilege
|
||||
+ * for the Var's column (the Var could be a whole-row Var, too)
|
||||
*
|
||||
- * The caller should pass the Var's referenced RTE if it has it handy
|
||||
- * (nearly all do); otherwise pass NULL.
|
||||
+ * The rte argument is unused and will be removed later.
|
||||
*/
|
||||
void
|
||||
markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte)
|
||||
@@ -1008,7 +1004,7 @@ markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte)
|
||||
/* Find the appropriate pstate if it's an uplevel Var */
|
||||
for (lv = 0; lv < var->varlevelsup; lv++)
|
||||
pstate = pstate->parentParseState;
|
||||
- markRTEForSelectPriv(pstate, rte, var->varno, var->varattno);
|
||||
+ markRTEForSelectPriv(pstate, var->varno, var->varattno);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2629,9 +2625,13 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
|
||||
/*
|
||||
* Require read access to the table. This is normally redundant with the
|
||||
* markVarForSelectPriv calls below, but not if the table has zero
|
||||
- * columns.
|
||||
+ * columns. We need not do anything if the nsitem is for a join: its
|
||||
+ * component tables will have been marked ACL_SELECT when they were added
|
||||
+ * to the rangetable. (This step changes things only for the target
|
||||
+ * relation of UPDATE/DELETE, which cannot be under a join.)
|
||||
*/
|
||||
- rte->requiredPerms |= ACL_SELECT;
|
||||
+ if (rte->rtekind == RTE_RELATION)
|
||||
+ rte->requiredPerms |= ACL_SELECT;
|
||||
|
||||
forboth(name, names, var, vars)
|
||||
{
|
||||
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
|
||||
index 64a1b75..c7165cb 100644
|
||||
--- a/src/backend/parser/parse_target.c
|
||||
+++ b/src/backend/parser/parse_target.c
|
||||
@@ -1328,9 +1328,13 @@ ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
|
||||
/*
|
||||
* Require read access to the table. This is normally redundant with
|
||||
* the markVarForSelectPriv calls below, but not if the table has zero
|
||||
- * columns.
|
||||
+ * columns. We need not do anything if the nsitem is for a join: its
|
||||
+ * component tables will have been marked ACL_SELECT when they were
|
||||
+ * added to the rangetable. (This step changes things only for the
|
||||
+ * target relation of UPDATE/DELETE, which cannot be under a join.)
|
||||
*/
|
||||
- rte->requiredPerms |= ACL_SELECT;
|
||||
+ if (rte->rtekind == RTE_RELATION)
|
||||
+ rte->requiredPerms |= ACL_SELECT;
|
||||
|
||||
/* Require read access to each column */
|
||||
foreach(l, vars)
|
||||
@ -1,70 +0,0 @@
|
||||
From eec462367ee2b41e02c6e29135c857ad6f2da66a Mon Sep 17 00:00:00 2001
|
||||
From: Michael Paquier <michael@paquier.xyz>
|
||||
Date: Mon, 26 Aug 2019 11:14:33 +0900
|
||||
Subject: [PATCH] Fix error handling of vacuumdb when running out of fds
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When trying to use a high number of jobs, vacuumdb has only checked for
|
||||
a maximum number of jobs used, causing confusing failures when running
|
||||
out of file descriptors when the jobs open connections to Postgres.
|
||||
This commit changes the error handling so as we do not check anymore for
|
||||
a maximum number of allowed jobs when parsing the option value with
|
||||
FD_SETSIZE, but check instead if a file descriptor is within the
|
||||
supported range when opening the connections for the jobs so as this is
|
||||
detected at the earliest time possible.
|
||||
|
||||
Also, improve the error message to give a hint about the number of jobs
|
||||
recommended, using a wording given by the reviewers of the patch.
|
||||
|
||||
Reported-by: Andres Freund
|
||||
Author: Michael Paquier
|
||||
Reviewed-by: Andres Freund, Álvaro Herrera, Tom Lane
|
||||
Discussion: https://postgr.es/m/20190818001858.ho3ev4z57fqhs7a5@alap3.anarazel.de
|
||||
Backpatch-through: 9.5
|
||||
---
|
||||
src/bin/scripts/vacuumdb.c | 20 ++++++++++++++------
|
||||
1 file changed, 14 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
|
||||
index f888bf73bc..4ac765244a 100644
|
||||
--- a/src/bin/scripts/vacuumdb.c
|
||||
+++ b/src/bin/scripts/vacuumdb.c
|
||||
@@ -200,12 +200,6 @@ main(int argc, char *argv[])
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
- if (concurrentCons > FD_SETSIZE - 1)
|
||||
- {
|
||||
- fprintf(stderr, _("%s: too many parallel jobs requested (maximum: %d)\n"),
|
||||
- progname, FD_SETSIZE - 1);
|
||||
- exit(1);
|
||||
- }
|
||||
break;
|
||||
case 2:
|
||||
maintenance_db = pg_strdup(optarg);
|
||||
@@ -443,6 +437,20 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
|
||||
{
|
||||
conn = connectDatabase(dbname, host, port, username, prompt_password,
|
||||
progname, echo, false, true);
|
||||
+
|
||||
+ /*
|
||||
+ * Fail and exit immediately if trying to use a socket in an
|
||||
+ * unsupported range. POSIX requires open(2) to use the lowest
|
||||
+ * unused file descriptor and the hint given relies on that.
|
||||
+ */
|
||||
+ if (PQsocket(conn) >= FD_SETSIZE)
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ _("%s: too many jobs for this platform -- try %d"),
|
||||
+ progname, i);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
init_slot(slots + i, conn);
|
||||
}
|
||||
}
|
||||
--
|
||||
2.23.0
|
||||
|
||||
69
Makefile.regress
Normal file
69
Makefile.regress
Normal file
@ -0,0 +1,69 @@
|
||||
#
|
||||
# Simplified makefile for running the PostgreSQL regression tests
|
||||
# in an RPM installation
|
||||
#
|
||||
|
||||
# maximum simultaneous connections for parallel tests
|
||||
MAXCONNOPT =
|
||||
ifdef MAX_CONNECTIONS
|
||||
MAXCONNOPT += --max-connections=$(MAX_CONNECTIONS)
|
||||
endif
|
||||
|
||||
# locale
|
||||
NOLOCALE =
|
||||
ifdef NO_LOCALE
|
||||
NOLOCALE += --no-locale
|
||||
endif
|
||||
|
||||
srcdir := .
|
||||
|
||||
REGRESS_OPTS += --dlpath=.
|
||||
|
||||
pg_regress_locale_flags = $(if $(ENCODING),--encoding=$(ENCODING)) $(NOLOCALE)
|
||||
|
||||
pg_regress_installcheck = ./pg_regress --inputdir=$(srcdir) --bindir=@bindir@ $(pg_regress_locale_flags)
|
||||
|
||||
# Test input and expected files. These are created by pg_regress itself, so we
|
||||
# don't have a rule to create them. We do need rules to clean them however.
|
||||
ifile_list := $(subst .source,, $(notdir $(wildcard $(srcdir)/input/*.source)))
|
||||
input_files := $(foreach file, $(ifile_list), sql/$(file).sql)
|
||||
ofile_list := $(subst .source,, $(notdir $(wildcard $(srcdir)/output/*.source)))
|
||||
output_files := $(foreach file, $(ofile_list), expected/$(file).out)
|
||||
|
||||
abs_srcdir := $(shell pwd)
|
||||
abs_builddir := $(shell pwd)
|
||||
|
||||
check: installcheck-parallel
|
||||
|
||||
installcheck: cleandirs
|
||||
$(pg_regress_installcheck) $(REGRESS_OPTS) --schedule=$(srcdir)/serial_schedule $(EXTRA_TESTS)
|
||||
|
||||
installcheck-parallel: cleandirs
|
||||
$(pg_regress_installcheck) $(REGRESS_OPTS) --schedule=$(srcdir)/parallel_schedule $(MAXCONNOPT) $(EXTRA_TESTS)
|
||||
|
||||
# The tests command the server to write into testtablespace and results.
|
||||
# On a SELinux-enabled system this will fail unless we mark those directories
|
||||
# as writable by the server.
|
||||
cleandirs:
|
||||
-rm -rf testtablespace results
|
||||
mkdir testtablespace results
|
||||
if test -x /usr/bin/chcon && ! test -f /.dockerenv; then \
|
||||
/usr/bin/chcon -u system_u -r object_r -t postgresql_db_t testtablespace results ; \
|
||||
fi
|
||||
|
||||
# old interfaces follow...
|
||||
|
||||
runcheck: check
|
||||
runtest: installcheck
|
||||
runtest-parallel: installcheck-parallel
|
||||
|
||||
|
||||
##
|
||||
## Clean up
|
||||
##
|
||||
|
||||
clean distclean maintainer-clean:
|
||||
rm -f $(output_files) $(input_files)
|
||||
rm -rf testtablespace
|
||||
rm -rf results tmp_check log
|
||||
rm -f regression.diffs regression.out regress.out run_check.out
|
||||
@ -1,50 +0,0 @@
|
||||
From 57ba539775f1dd0b0460f1dfe673da00eeef3a2f Mon Sep 17 00:00:00 2001
|
||||
From: Michael Paquier <michael@paquier.xyz>
|
||||
Date: Tue, 7 May 2019 14:20:01 +0900
|
||||
Subject: [PATCH] Remove some code related to 7.3 and older servers from tools
|
||||
of src/bin/
|
||||
|
||||
This code was broken as of 582edc3, and is most likely not used anymore.
|
||||
Note that pg_dump supports servers down to 8.0, and psql has code to
|
||||
support servers down to 7.4.
|
||||
|
||||
Author: Julien Rouhaud
|
||||
Reviewed-by: Tom Lane
|
||||
Discussion: https://postgr.es/m/CAOBaU_Y5y=zo3+2gf+2NJC1pvMYPcbRXoQaPXx=U7+C8Qh4CzQ@mail.gmail.com
|
||||
---
|
||||
src/bin/scripts/common.c | 12 ++----------
|
||||
1 file changed, 2 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c
|
||||
index 8073ee0d0e..5088c4c48e 100644
|
||||
--- a/src/bin/scripts/common.c
|
||||
+++ b/src/bin/scripts/common.c
|
||||
@@ -145,9 +145,8 @@ connectDatabase(const char *dbname, const char *pghost,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
- if (PQserverVersion(conn) >= 70300)
|
||||
- PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL,
|
||||
- progname, echo));
|
||||
+ PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL,
|
||||
+ progname, echo));
|
||||
|
||||
return conn;
|
||||
}
|
||||
@@ -311,13 +310,6 @@ appendQualifiedRelation(PQExpBuffer buf, const char *spec,
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
|
||||
- /* Before 7.3, the concept of qualifying a name did not exist. */
|
||||
- if (PQserverVersion(conn) < 70300)
|
||||
- {
|
||||
- appendPQExpBufferStr(&sql, spec);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
split_table_columns_spec(spec, PQclientEncoding(conn), &table, &columns);
|
||||
|
||||
/*
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,76 +0,0 @@
|
||||
From a1413123f80f470da1ec422592f228aebe4a8866 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Paquier <michael@paquier.xyz>
|
||||
Date: Thu, 27 Feb 2020 11:21:14 +0900
|
||||
Subject: [PATCH 1/2] createdb: Fix quoting of --encoding, --lc-ctype and
|
||||
--lc-collate
|
||||
|
||||
The original coding failed to properly quote those arguments, leading to
|
||||
failures when using quotes in the values used. As the quoting can be
|
||||
encoding-sensitive, the connection to the backend needs to be taken
|
||||
before applying the correct quoting.
|
||||
|
||||
Author: Michael Paquier
|
||||
Reviewed-by: Daniel Gustafsson
|
||||
Discussion: https://postgr.es/m/20200214041004.GB1998@paquier.xyz
|
||||
Backpatch-through: 9.5
|
||||
---
|
||||
src/bin/scripts/createdb.c | 29 +++++++++++++++++++----------
|
||||
1 file changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/src/bin/scripts/createdb.c b/src/bin/scripts/createdb.c
|
||||
index 8116b084ff..45d26ecb8c 100644
|
||||
--- a/src/bin/scripts/createdb.c
|
||||
+++ b/src/bin/scripts/createdb.c
|
||||
@@ -177,6 +177,13 @@ main(int argc, char *argv[])
|
||||
dbname = get_user_name_or_exit(progname);
|
||||
}
|
||||
|
||||
+ /* No point in trying to use postgres db when creating postgres db. */
|
||||
+ if (maintenance_db == NULL && strcmp(dbname, "postgres") == 0)
|
||||
+ maintenance_db = "template1";
|
||||
+
|
||||
+ conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
|
||||
+ prompt_password, progname, echo);
|
||||
+
|
||||
initPQExpBuffer(&sql);
|
||||
|
||||
appendPQExpBuffer(&sql, "CREATE DATABASE %s",
|
||||
@@ -187,23 +194,25 @@ main(int argc, char *argv[])
|
||||
if (tablespace)
|
||||
appendPQExpBuffer(&sql, " TABLESPACE %s", fmtId(tablespace));
|
||||
if (encoding)
|
||||
- appendPQExpBuffer(&sql, " ENCODING '%s'", encoding);
|
||||
+ {
|
||||
+ appendPQExpBufferStr(&sql, " ENCODING ");
|
||||
+ appendStringLiteralConn(&sql, encoding, conn);
|
||||
+ }
|
||||
if (template)
|
||||
appendPQExpBuffer(&sql, " TEMPLATE %s", fmtId(template));
|
||||
if (lc_collate)
|
||||
- appendPQExpBuffer(&sql, " LC_COLLATE '%s'", lc_collate);
|
||||
+ {
|
||||
+ appendPQExpBufferStr(&sql, " LC_COLLATE ");
|
||||
+ appendStringLiteralConn(&sql, lc_collate, conn);
|
||||
+ }
|
||||
if (lc_ctype)
|
||||
- appendPQExpBuffer(&sql, " LC_CTYPE '%s'", lc_ctype);
|
||||
+ {
|
||||
+ appendPQExpBufferStr(&sql, " LC_CTYPE ");
|
||||
+ appendStringLiteralConn(&sql, lc_ctype, conn);
|
||||
+ }
|
||||
|
||||
appendPQExpBufferChar(&sql, ';');
|
||||
|
||||
- /* No point in trying to use postgres db when creating postgres db. */
|
||||
- if (maintenance_db == NULL && strcmp(dbname, "postgres") == 0)
|
||||
- maintenance_db = "template1";
|
||||
-
|
||||
- conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
|
||||
- prompt_password, progname, echo);
|
||||
-
|
||||
if (echo)
|
||||
printf("%s\n", sql.data);
|
||||
result = PQexec(conn, sql.data);
|
||||
--
|
||||
2.23.0
|
||||
|
||||
58
generate-pdf.sh
Normal file
58
generate-pdf.sh
Normal file
@ -0,0 +1,58 @@
|
||||
#! /bin/sh
|
||||
|
||||
# This script builds the PDF version of the PostgreSQL documentation.
|
||||
#
|
||||
# In principle we could do this as part of the RPM build, but there are
|
||||
# good reasons not to:
|
||||
# 1. The build would take longer and have a larger BuildRequires footprint.
|
||||
# 2. The generated PDF has timestamps in it, which would inevitably result
|
||||
# in multilib conflicts due to slightly different timestamps.
|
||||
# So instead, we run this manually when rebasing to a new upstream release,
|
||||
# and treat the resulting PDF as a separate Source file.
|
||||
#
|
||||
# You will need to have the docbook packages installed to run this.
|
||||
# Expect it to take about 20 minutes and use about 160MB of disk.
|
||||
|
||||
set -e
|
||||
|
||||
# Pass package version (e.g., 9.1.2) as argument
|
||||
VERSION=$1
|
||||
|
||||
test -z "$VERSION" && VERSION=`awk '/^Version:/ { print $2; }' postgresql.spec`
|
||||
|
||||
TARGETFILE=postgresql-$VERSION-US.pdf
|
||||
test -f "$TARGETFILE" && echo "$TARGETFILE exists" && exit 1
|
||||
|
||||
echo Building $TARGETFILE ...
|
||||
|
||||
# Unpack postgresql
|
||||
|
||||
rm -rf postgresql-$VERSION
|
||||
|
||||
tar xfj postgresql-$VERSION.tar.bz2
|
||||
|
||||
cd postgresql-$VERSION
|
||||
|
||||
# Apply any patches that affect the PDF documentation
|
||||
|
||||
# patch -p1 < ../xxx.patch
|
||||
|
||||
# Configure ...
|
||||
|
||||
./configure >/dev/null
|
||||
|
||||
# Build the PDF docs
|
||||
|
||||
cd doc/src/sgml
|
||||
|
||||
make postgres-US.pdf >make.log
|
||||
|
||||
mv -f postgres-US.pdf ../../../../$TARGETFILE
|
||||
|
||||
# Clean up
|
||||
|
||||
cd ../../../..
|
||||
|
||||
rm -rf postgresql-$VERSION
|
||||
|
||||
exit 0
|
||||
12
generate-sources.sh
Normal file
12
generate-sources.sh
Normal file
@ -0,0 +1,12 @@
|
||||
#! /bin/sh
|
||||
|
||||
rm sources
|
||||
set -e
|
||||
spectool -S *.spec | cut -d' ' -f2 \
|
||||
| grep -E -e 'postgresql-.*\.tar\.*' -e 'postgresql.*\.pdf' | sort | \
|
||||
while read line
|
||||
do
|
||||
base=`basename "$line"`
|
||||
echo " * handling $base"
|
||||
sha512sum --tag "$base" >> sources
|
||||
done
|
||||
62
library.sh
62
library.sh
@ -1,62 +0,0 @@
|
||||
die() { echo >&2 $"FATAL: $@" ; exit 1 ; }
|
||||
error() { echo >&2 $"ERROR: $@" ; }
|
||||
error_q() { echo >&2 $" $@" ; }
|
||||
warn() { echo >&2 $"WARNING: $@" ; }
|
||||
warn_q() { echo >&2 $" $@" ; }
|
||||
info() { echo >&2 $" * $@" ; }
|
||||
info_q() { echo >&2 $" $@" ; }
|
||||
debug() { test "$option_debug" != "1" || echo >&2 $"DEBUG: $@"; }
|
||||
|
||||
|
||||
set_var()
|
||||
{
|
||||
eval "$1=\"$2\""
|
||||
}
|
||||
|
||||
|
||||
root_prereq()
|
||||
{
|
||||
test -z "$PGSETUP_TEST" || return 0
|
||||
test "$(id -u)" -eq 0 || die "$0 requires root access for this action"
|
||||
}
|
||||
|
||||
|
||||
read_config_file()
|
||||
{
|
||||
local key="" val=""
|
||||
|
||||
test -r "$1" || die "can't read file '$1'"
|
||||
|
||||
for i in $2; do
|
||||
eval "unset __pg_conf_$i"
|
||||
done
|
||||
|
||||
# No easy (and secure) way to read configuration files from bash script,
|
||||
# sorry.
|
||||
while read key val; do
|
||||
[[ $key =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] || return 1
|
||||
|
||||
case " $2 " in
|
||||
*" $key "*)
|
||||
;;
|
||||
*)
|
||||
warn "config file '$1': unknown key '$key'"
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
# Strip double quotes
|
||||
case "$val" in
|
||||
\"*\")
|
||||
val=${val##\"}
|
||||
val=${val%%\"}
|
||||
;;
|
||||
esac
|
||||
|
||||
# Make it reasonably safe. Keep dolar-sign escaped.
|
||||
eval "__pg_conf_$key=\$val"
|
||||
|
||||
done < <(grep -v -e "^$" -e "^#" < "$1")
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
# Macros from this file should exist on system only once, so it package
|
||||
# maintainer's responsibility to guarantee that all packages which install
|
||||
# these macros collide, or that (during package-build time) only one such
|
||||
# package is installed (e.g. similarly to %%scl macro defined installed by
|
||||
# *-build subpackage).
|
||||
|
||||
%postgresql_major 10
|
||||
|
||||
%postgresql_module_requires Requires: postgresql-server(:MODULE_COMPAT_10)
|
||||
@ -1,18 +0,0 @@
|
||||
# Initialize the PostgreSQL tests environment. This is supposed to be invoked
|
||||
# in prep/build/install (where you plan to run the testsuite), while it defines
|
||||
# several useful shell variables and provies useful commands. Effect of this
|
||||
# command end with shell exit.
|
||||
%postgresql_tests_init . "/usr/share/postgresql-setup/postgresql_pkg_tests.sh"
|
||||
|
||||
# Start the testing postgresql server, setting the actual unix user to be the
|
||||
# PostgreSQL admin. The $PGHOST/$PGPORT are set appropriately, so psql is able
|
||||
# to run without passwords. This also sets shell exit trap callback so that if
|
||||
# something goes wrong and package build fails, the temporary database is
|
||||
# automatically cleaned up.
|
||||
%postgresql_tests_start pgtests_start
|
||||
|
||||
# Initialize database and run server in one step, if this works well-enough.
|
||||
%postgresql_tests_run %postgresql_tests_init ; %postgresql_tests_start
|
||||
|
||||
%pgtests_init echo 2>&1 WARN: macro pgtests_init will be removed, use postgresql_tests_init ; %postgresql_tests_init
|
||||
%pgtests_start echo 2>&1 WARN: macro pgtests_start will be removed, use postgresql_tests_start ; %postgresql_tests_start
|
||||
@ -1 +0,0 @@
|
||||
6c8e616c91a45142b85c0aeb1f29ebba4a361309e86469e0fb4617b6a73c4011 postgresql-10.5.tar.bz2
|
||||
Binary file not shown.
1
postgresql-12.7.tar.bz2.sha256
Normal file
1
postgresql-12.7.tar.bz2.sha256
Normal file
@ -0,0 +1 @@
|
||||
8490741f47c88edc8b6624af009ce19fda4dc9b31c4469ce2551d84075d5d995 postgresql-12.7.tar.bz2
|
||||
BIN
postgresql-13.3-US.pdf
Normal file
BIN
postgresql-13.3-US.pdf
Normal file
Binary file not shown.
BIN
postgresql-13.3.tar.bz2
Normal file
BIN
postgresql-13.3.tar.bz2
Normal file
Binary file not shown.
1
postgresql-13.3.tar.bz2.sha256
Normal file
1
postgresql-13.3.tar.bz2.sha256
Normal file
@ -0,0 +1 @@
|
||||
3cd9454fa8c7a6255b6743b767700925ead1b9ab0d7a0f9dcb1151010f8eb4a1 postgresql-13.3.tar.bz2
|
||||
@ -1,104 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script verifies that the postgresql data directory has been correctly
|
||||
# initialized. We do not want to automatically initdb it, because that has
|
||||
# a risk of catastrophic failure (ie, overwriting a valuable database) in
|
||||
# corner cases, such as a remotely mounted database on a volume that's a
|
||||
# bit slow to mount. But we can at least emit a message advising newbies
|
||||
# what to do.
|
||||
|
||||
if test -z "$1"; then
|
||||
echo "Maintainer error: $0 must be run with one argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
service_name="$1"
|
||||
|
||||
if [ -z "$PGDATA" ]; then
|
||||
echo $"You try to start '$service_name' service"
|
||||
echo $"but the required \$PGDATA environment variable is not set."
|
||||
|
||||
if test 0 -eq 1; then
|
||||
echo $"You should use the /etc/sysconfig/pgsql/$service_name"
|
||||
else
|
||||
echo $"You should use the /etc/systemd/system/$service_name.service.d/ANYTHING.conf"
|
||||
fi
|
||||
|
||||
echo $"configuration file to set \$PGDATA. For more info see"
|
||||
echo $"the /usr/share/doc/postgresql/README.rpm-dist file."
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Warn the user that the configuration should be adjusted via drop-in, in case
|
||||
# the $PGDATA variable is set different way (and non-default service name is
|
||||
# used, systemd systems only).
|
||||
conf_dir="/etc/systemd/system/$service_name.service.d"
|
||||
if test 0 = 0 && [[ "$service_name" == *@* ]] && test ! -d "$conf_dir"; then
|
||||
echo >&2 $"WARNING: Note that the '$conf_dir'"
|
||||
echo >&2 $"directory does not exist while you are using non-default service"
|
||||
echo >&2 $"name '$service_name'. You are encouraged to use the"
|
||||
echo >&2 $"$conf_dir directory for systemd configuration according"
|
||||
echo >&2 $"to /usr/share/doc/postgresql/README.rpm-dist documentation."
|
||||
fi
|
||||
|
||||
# Full PostgreSQL version, e.g. 9.0.2
|
||||
PGVERSION=10.5
|
||||
|
||||
# Major version of PostgreSQL, e.g. 9.0
|
||||
PGMAJORVERSION=10
|
||||
|
||||
# Distribution README file
|
||||
README_DIST=/usr/share/doc/postgresql/README.rpm-dist
|
||||
|
||||
bad_version()
|
||||
{
|
||||
local real_version="$1"
|
||||
|
||||
. "/usr/share/postgresql-setup/library.sh"
|
||||
|
||||
while read id version; do
|
||||
test "$version" = "$real_version" || continue
|
||||
|
||||
local cmd="postgresql-setup --upgrade"
|
||||
|
||||
test "postgresql" = "$id" \
|
||||
|| cmd="$cmd --upgrade-from $id"
|
||||
|
||||
echo $"An old version of the database format was found."
|
||||
echo $"Use '$cmd' to upgrade to version '$PGMAJORVERSION'"
|
||||
echo $"See $README_DIST for more information."
|
||||
|
||||
return
|
||||
done < <(parse_upgrade_setup list)
|
||||
|
||||
echo $"An old version '$real_version' of the database format was found."
|
||||
echo $"You need to dump and reload before using PostgreSQL $PGVERSION."
|
||||
echo $"See $README_DIST for more information."
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
# Check for the PGDATA structure
|
||||
if [ -f "$PGDATA/PG_VERSION" ] && [ -d "$PGDATA/base" ]
|
||||
then
|
||||
real_version=`cat "$PGDATA/PG_VERSION"`
|
||||
# Check version of existing PGDATA
|
||||
if [ x"$real_version" = x"$PGMAJORVERSION" ]
|
||||
then
|
||||
: A-OK
|
||||
else
|
||||
bad_version "$real_version"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# No existing PGDATA! Warn the user to initdb it.
|
||||
echo $"Directory \"$PGDATA\" is missing or empty."
|
||||
echo $"Use \"/usr/bin/postgresql-setup --initdb\""
|
||||
echo $"to initialize the database cluster."
|
||||
echo $"See $README_DIST for more information."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
99
postgresql-datalayout-mismatch-on-s390.patch
Normal file
99
postgresql-datalayout-mismatch-on-s390.patch
Normal file
@ -0,0 +1,99 @@
|
||||
From 0edaa982336823d4d7af8f10b91579fe0099ef3d Mon Sep 17 00:00:00 2001
|
||||
From: Tom Stellard <tstellar@redhat.com>
|
||||
Date: Tue, 20 Apr 2021 20:14:21 -0700
|
||||
Subject: [PATCH] jit: Workaround potential datalayout mismatch on s390x
|
||||
|
||||
LLVM's s390x target uses a different datalayout for z13 and newer processors.
|
||||
If llvmjit_types.bc is compiled to target a processor older than z13, and
|
||||
then the JIT runs on a z13 or newer processor, then there will be a mismatch
|
||||
in datalayouts between llvmjit_types.bc and the JIT engine. This mismatch
|
||||
causes the JIT to fail at runtime.
|
||||
---
|
||||
src/backend/jit/llvm/llvmjit.c | 46 ++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 44 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
|
||||
index 98a27f08bf..05b6438ba8 100644
|
||||
--- a/src/backend/jit/llvm/llvmjit.c
|
||||
+++ b/src/backend/jit/llvm/llvmjit.c
|
||||
@@ -776,6 +776,35 @@ llvm_compile_module(LLVMJitContext *context)
|
||||
errhidecontext(true)));
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * For the systemz target, LLVM uses a different datalayout for z13 and newer
|
||||
+ * CPUs than it does for older CPUs. This can cause a mismatch in datalayouts
|
||||
+ * in the case where the llvm_types_module is compiled with a pre-z13 CPU
|
||||
+ * and the JIT is running on z13 or newer.
|
||||
+ * See computeDataLayout() function in
|
||||
+ * llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp for information on the
|
||||
+ * datalayout differences.
|
||||
+ */
|
||||
+static bool
|
||||
+needs_systemz_workaround(void)
|
||||
+{
|
||||
+ bool ret = false;
|
||||
+ LLVMContextRef llvm_context;
|
||||
+ LLVMTypeRef vec_type;
|
||||
+ LLVMTargetDataRef llvm_layoutref;
|
||||
+ if (strncmp(LLVMGetTargetName(llvm_targetref), "systemz", strlen("systemz")))
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ llvm_context = LLVMGetModuleContext(llvm_types_module);
|
||||
+ vec_type = LLVMVectorType(LLVMIntTypeInContext(llvm_context, 32), 4);
|
||||
+ llvm_layoutref = LLVMCreateTargetData(llvm_layout);
|
||||
+ ret = (LLVMABIAlignmentOfType(llvm_layoutref, vec_type) == 16);
|
||||
+ LLVMDisposeTargetData(llvm_layoutref);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Per session initialization.
|
||||
*/
|
||||
@@ -785,6 +814,7 @@ llvm_session_initialize(void)
|
||||
MemoryContext oldcontext;
|
||||
char *error = NULL;
|
||||
char *cpu = NULL;
|
||||
+ char *host_features = NULL;
|
||||
char *features = NULL;
|
||||
LLVMTargetMachineRef opt0_tm;
|
||||
LLVMTargetMachineRef opt3_tm;
|
||||
@@ -816,10 +846,17 @@ llvm_session_initialize(void)
|
||||
* features not all CPUs have (weird, huh).
|
||||
*/
|
||||
cpu = LLVMGetHostCPUName();
|
||||
- features = LLVMGetHostCPUFeatures();
|
||||
+ features = host_features = LLVMGetHostCPUFeatures();
|
||||
elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"",
|
||||
cpu, features);
|
||||
|
||||
+ if (needs_systemz_workaround())
|
||||
+ {
|
||||
+ const char *no_vector =",-vector";
|
||||
+ features = malloc(sizeof(char) * (strlen(host_features) + strlen(no_vector) + 1));
|
||||
+ sprintf(features, "%s%s", host_features, no_vector);
|
||||
+ }
|
||||
+
|
||||
opt0_tm =
|
||||
LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
|
||||
LLVMCodeGenLevelNone,
|
||||
@@ -833,8 +870,13 @@ llvm_session_initialize(void)
|
||||
|
||||
LLVMDisposeMessage(cpu);
|
||||
cpu = NULL;
|
||||
- LLVMDisposeMessage(features);
|
||||
+ if (features != host_features)
|
||||
+ {
|
||||
+ free(features);
|
||||
+ }
|
||||
features = NULL;
|
||||
+ LLVMDisposeMessage(host_features);
|
||||
+ host_features = NULL;
|
||||
|
||||
/* force symbols in main binary to be loaded */
|
||||
LLVMLoadLibraryPermanently(NULL);
|
||||
--
|
||||
2.27.0
|
||||
|
||||
43
postgresql-external-libpq.patch
Normal file
43
postgresql-external-libpq.patch
Normal file
@ -0,0 +1,43 @@
|
||||
We don't build/install interfaces by upstream's implicit rules.
|
||||
|
||||
This patch is used on two places; postgresql.spec and libecpg.spec -- keep those
|
||||
in sync!
|
||||
|
||||
Related: rhbz#1618698
|
||||
|
||||
diff --git a/src/Makefile b/src/Makefile
|
||||
index bcdbd95..4bea236 100644
|
||||
--- a/src/Makefile
|
||||
+++ b/src/Makefile
|
||||
@@ -20,7 +20,6 @@ SUBDIRS = \
|
||||
backend/utils/mb/conversion_procs \
|
||||
backend/snowball \
|
||||
include \
|
||||
- interfaces \
|
||||
backend/replication/libpqwalreceiver \
|
||||
backend/replication/pgoutput \
|
||||
fe_utils \
|
||||
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
|
||||
index b9d86ac..29df69f 100644
|
||||
--- a/src/Makefile.global.in
|
||||
+++ b/src/Makefile.global.in
|
||||
@@ -549,7 +549,7 @@ endif
|
||||
# How to link to libpq. (This macro may be used as-is by backend extensions.
|
||||
# Client-side code should go through libpq_pgport or libpq_pgport_shlib,
|
||||
# instead.)
|
||||
-libpq = -L$(libpq_builddir) -lpq
|
||||
+libpq = -lpq
|
||||
|
||||
# libpq_pgport is for use by client executables (not libraries) that use libpq.
|
||||
# We force clients to pull symbols from the non-shared libraries libpgport
|
||||
@@ -579,7 +579,6 @@ endif
|
||||
# Commonly used submake targets
|
||||
|
||||
submake-libpq: | submake-generated-headers
|
||||
- $(MAKE) -C $(libpq_builddir) all
|
||||
|
||||
submake-libpgport: | submake-generated-headers
|
||||
$(MAKE) -C $(top_builddir)/src/port all
|
||||
--
|
||||
2.21.0
|
||||
|
||||
41
postgresql-logging.patch
Normal file
41
postgresql-logging.patch
Normal file
@ -0,0 +1,41 @@
|
||||
Default to stderr-based logging with a week's worth of daily logfiles.
|
||||
|
||||
|
||||
diff -Naur postgresql-9.1rc1.orig/src/backend/utils/misc/postgresql.conf.sample postgresql-9.1rc1/src/backend/utils/misc/postgresql.conf.sample
|
||||
--- postgresql-9.1rc1.orig/src/backend/utils/misc/postgresql.conf.sample 2011-08-18 17:23:13.000000000 -0400
|
||||
+++ postgresql-9.1rc1/src/backend/utils/misc/postgresql.conf.sample 2011-08-18 18:39:39.697526799 -0400
|
||||
@@ -279,7 +279,7 @@
|
||||
# requires logging_collector to be on.
|
||||
|
||||
# This is used when logging to stderr:
|
||||
-#logging_collector = off # Enable capturing of stderr and csvlog
|
||||
+logging_collector = on # Enable capturing of stderr and csvlog
|
||||
# into log files. Required to be on for
|
||||
# csvlogs.
|
||||
# (change requires restart)
|
||||
@@ -355,11 +355,11 @@
|
||||
# These are only used if logging_collector is on:
|
||||
#log_directory = 'log' # directory where log files are written,
|
||||
# can be absolute or relative to PGDATA
|
||||
-#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,
|
||||
+log_filename = 'postgresql-%a.log' # log file name pattern,
|
||||
# can include strftime() escapes
|
||||
#log_file_mode = 0600 # creation mode for log files,
|
||||
# begin with 0 to use octal notation
|
||||
-#log_truncate_on_rotation = off # If on, an existing log file with the
|
||||
+log_truncate_on_rotation = on # If on, an existing log file with the
|
||||
# same name as the new log file will be
|
||||
# truncated rather than appended to.
|
||||
# But such truncation only occurs on
|
||||
@@ -367,9 +367,9 @@
|
||||
# or size-driven rotation. Default is
|
||||
# off, meaning append to existing files
|
||||
# in all cases.
|
||||
-#log_rotation_age = 1d # Automatic rotation of logfiles will
|
||||
+log_rotation_age = 1d # Automatic rotation of logfiles will
|
||||
# happen after that time. 0 disables.
|
||||
-#log_rotation_size = 10MB # Automatic rotation of logfiles will
|
||||
+log_rotation_size = 0 # Automatic rotation of logfiles will
|
||||
# happen after that much log output.
|
||||
# 0 disables.
|
||||
|
||||
49
postgresql-man.patch
Normal file
49
postgresql-man.patch
Normal file
@ -0,0 +1,49 @@
|
||||
PostgreSQL ecpg/initdb manual page fixes
|
||||
|
||||
This was generated based on automatic Red Hat manual page scan (private
|
||||
RHBZ#948933).
|
||||
|
||||
diff -up postgresql-13.1/doc/src/sgml/man1/ecpg.1.patch6 postgresql-13.1/doc/src/sgml/man1/ecpg.1
|
||||
--- postgresql-13.1/doc/src/sgml/man1/ecpg.1.patch6 2020-11-09 23:38:03.000000000 +0100
|
||||
+++ postgresql-13.1/doc/src/sgml/man1/ecpg.1 2020-11-18 09:26:40.547324791 +0100
|
||||
@@ -81,6 +81,11 @@ ORACLE\&.
|
||||
Define a C preprocessor symbol\&.
|
||||
.RE
|
||||
.PP
|
||||
+\fB\-h \fR
|
||||
+.RS 4
|
||||
+Parse a header file, this option includes option \fB\-c\fR\&.
|
||||
+.RE
|
||||
+.PP
|
||||
\fB\-h\fR
|
||||
.RS 4
|
||||
Process header files\&. When this option is specified, the output file extension becomes
|
||||
@@ -144,6 +149,11 @@ Allow question mark as placeholder for c
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
+\fB\-\-regression\fR
|
||||
+.RS 4
|
||||
+Run in regression testing mode\&.
|
||||
+.RE
|
||||
+.PP
|
||||
\fB\-t\fR
|
||||
.RS 4
|
||||
Turn on autocommit of transactions\&. In this mode, each SQL command is automatically committed unless it is inside an explicit transaction block\&. In the default mode, commands are committed only when
|
||||
diff -up postgresql-13.1/doc/src/sgml/man1/initdb.1.patch6 postgresql-13.1/doc/src/sgml/man1/initdb.1
|
||||
--- postgresql-13.1/doc/src/sgml/man1/initdb.1.patch6 2020-11-09 23:38:05.000000000 +0100
|
||||
+++ postgresql-13.1/doc/src/sgml/man1/initdb.1 2020-11-18 09:25:05.082348424 +0100
|
||||
@@ -311,6 +311,13 @@ determines that an error prevented it fr
|
||||
.PP
|
||||
Other options:
|
||||
.PP
|
||||
+\fB\-s\fR
|
||||
+.br
|
||||
+\fB\-\-show\fR
|
||||
+.RS 4
|
||||
+Print the internal settings, then exit\&.
|
||||
+.RE
|
||||
+.PP
|
||||
\fB\-V\fR
|
||||
.br
|
||||
\fB\-\-version\fR
|
||||
12
postgresql-no-libecpg.patch
Normal file
12
postgresql-no-libecpg.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff -up postgresql-13.1/src/interfaces/Makefile.patch10 postgresql-13.1/src/interfaces/Makefile
|
||||
--- postgresql-13.1/src/interfaces/Makefile.patch10 2021-02-02 21:33:23.235292305 +0100
|
||||
+++ postgresql-13.1/src/interfaces/Makefile 2021-02-02 21:33:30.281365440 +0100
|
||||
@@ -12,7 +12,7 @@ subdir = src/interfaces
|
||||
top_builddir = ../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
-SUBDIRS = libpq ecpg
|
||||
+SUBDIRS = libpq
|
||||
|
||||
$(recurse)
|
||||
|
||||
58
postgresql-server-pg_config.patch
Normal file
58
postgresql-server-pg_config.patch
Normal file
@ -0,0 +1,58 @@
|
||||
We should ideally provide '/bin/pg_config' in postgresql-server-devel, and
|
||||
provide no pg_config binary in libpq package. But most of the Fedora packages
|
||||
that use pg_config actually only build against PG libraries (and
|
||||
postgresql-server-devel isn't needed). So.., to avoid the initial rush around
|
||||
rhbz#1618698 change, rather provide pg_server_config binary, which int urn means
|
||||
that we'll have to fix only a minimal set of packages which really build
|
||||
PostgreSQL server modules.
|
||||
|
||||
diff -up postgresql-13.1/src/bin/pg_config/Makefile.patch9 postgresql-13.1/src/bin/pg_config/Makefile
|
||||
--- postgresql-13.1/src/bin/pg_config/Makefile.patch9 2020-11-18 09:28:30.885453275 +0100
|
||||
+++ postgresql-13.1/src/bin/pg_config/Makefile 2020-11-18 09:31:33.926325327 +0100
|
||||
@@ -11,6 +11,8 @@
|
||||
PGFILEDESC = "pg_config - report configuration information"
|
||||
PGAPPICON=win32
|
||||
|
||||
+PG_CONFIG = pg_server_config$(X)
|
||||
+
|
||||
subdir = src/bin/pg_config
|
||||
top_builddir = ../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
@@ -19,22 +21,22 @@ OBJS = \
|
||||
$(WIN32RES) \
|
||||
pg_config.o
|
||||
|
||||
-all: pg_config
|
||||
+all: $(PG_CONFIG)
|
||||
|
||||
-pg_config: $(OBJS) | submake-libpgport
|
||||
- $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
|
||||
+$(PG_CONFIG): $(OBJS) | submake-libpgport
|
||||
+ $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@
|
||||
|
||||
install: all installdirs
|
||||
- $(INSTALL_SCRIPT) pg_config$(X) '$(DESTDIR)$(bindir)/pg_config$(X)'
|
||||
+ $(INSTALL_SCRIPT) $(PG_CONFIG) '$(DESTDIR)$(bindir)/$(PG_CONFIG)'
|
||||
|
||||
installdirs:
|
||||
$(MKDIR_P) '$(DESTDIR)$(bindir)'
|
||||
|
||||
uninstall:
|
||||
- rm -f '$(DESTDIR)$(bindir)/pg_config$(X)'
|
||||
+ rm -f '$(DESTDIR)$(bindir)/$(PG_CONFIG)'
|
||||
|
||||
clean distclean maintainer-clean:
|
||||
- rm -f pg_config$(X) $(OBJS)
|
||||
+ rm -f $(PG_CONFIG) $(OBJS)
|
||||
rm -rf tmp_check
|
||||
|
||||
check:
|
||||
diff -up postgresql-13.1/src/bin/pg_config/nls.mk.patch9 postgresql-13.1/src/bin/pg_config/nls.mk
|
||||
--- postgresql-13.1/src/bin/pg_config/nls.mk.patch9 2020-11-18 09:28:30.885453275 +0100
|
||||
+++ postgresql-13.1/src/bin/pg_config/nls.mk 2020-11-18 09:32:00.735599526 +0100
|
||||
@@ -1,4 +1,4 @@
|
||||
# src/bin/pg_config/nls.mk
|
||||
-CATALOG_NAME = pg_config
|
||||
+CATALOG_NAME = pg_server_config
|
||||
AVAIL_LANGUAGES = cs de es fr he it ja ko pl pt_BR ru sv tr uk vi zh_CN
|
||||
GETTEXT_FILES = pg_config.c ../../common/config_info.c ../../common/exec.c
|
||||
777
postgresql-setup
777
postgresql-setup
@ -1,777 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# postgresql-setup - Initialization and upgrade operations for PostgreSQL
|
||||
|
||||
if test "$(id -u)" -eq 0; then
|
||||
cmd=
|
||||
for v in PGSETUP_DEBUG PGSETUP_INITDB_OPTIONS PGSETUP_PGUPGRADE_OPTIONS; do
|
||||
eval var_content=\$$v
|
||||
test -z "$var_content" && continue
|
||||
cmd+=$v="$(printf %q "$var_content") "
|
||||
done
|
||||
cmd+=$(printf %q "$(readlink -f "$0")")
|
||||
for arg; do cmd+=" $(printf %q "$arg")" ; done
|
||||
# Drop root privileges asap. It's not recommended to run postgresql-setup
|
||||
# script under root nowadays; so we take the liberty to switch to the
|
||||
# PostgreSQL admin user (by default 'postgres') without any other option.
|
||||
exec /usr/sbin/runuser -s /bin/sh -l postgres -c "$cmd"
|
||||
fi
|
||||
|
||||
# ensure privacy
|
||||
umask 0077
|
||||
|
||||
: ${RESTORECON=/sbin/restorecon}
|
||||
test -x $RESTORECON || RESTORECON=:
|
||||
|
||||
test -z "$PATH" && export PATH="/sbin:/usr/sbin:/bin:/usr/bin"
|
||||
|
||||
test x"$PGSETUP_DEBUG" != x && set -x && PS4='${LINENO}: '
|
||||
|
||||
# The current user name.
|
||||
USER=$(id -u -n)
|
||||
|
||||
# Directory containing the postmaster executable
|
||||
PGENGINE=/usr/bin
|
||||
|
||||
# Distribution README file
|
||||
README_DIST=/usr/share/doc/postgresql/README.rpm-dist
|
||||
|
||||
# Home directory of postgres user
|
||||
POSTGRES_HOMEDIR=/var/lib/pgsql
|
||||
|
||||
# The where PostgreSQL server listens by default
|
||||
PGPORT_DEF=5432
|
||||
|
||||
|
||||
. "/usr/share/postgresql-setup/library.sh"
|
||||
|
||||
:
|
||||
|
||||
# We upgrade by default from system's default PostgreSQL installation
|
||||
option_upgradefrom="postgresql"
|
||||
|
||||
srvsuff=
|
||||
test 0 -eq 0 && srvsuff=".service"
|
||||
|
||||
USAGE_STRING=$"\
|
||||
Usage: $0 MODE_OPTION [--unit=UNIT_NAME] [OPTION...]
|
||||
|
||||
Script is aimed to help sysadmin with basic database cluster administration.
|
||||
Usually, \"postgresql-setup --initdb\" and \"postgresql-setup --upgrade\" is
|
||||
enough, however there are other options described below.
|
||||
|
||||
For more info and howto/when use this script please look at the documentation
|
||||
file $README_DIST.
|
||||
|
||||
Available operation mode:
|
||||
--initdb Initialize new PostgreSQL database cluster. This is usually the
|
||||
first action you perform after PostgreSQL server installation.
|
||||
--upgrade Upgrade database cluster for new major version of PostgreSQL
|
||||
server. See the --upgrade-from option for more info.
|
||||
|
||||
Options:
|
||||
--unit=UNIT_NAME The UNIT_NAME is used to select proper unit
|
||||
configuration (unit == service or initscript name
|
||||
on non-systemd systems). For example, if you want
|
||||
to work with unit called
|
||||
'postgresql@com_example.service', you should use
|
||||
'postgresql@com_example' (without trailing .service
|
||||
string). When no UNIT_NAME is explicitly passed,
|
||||
the 'postgresql' string is used by default.
|
||||
--port=PORT port where the initialized server will listen for
|
||||
connections"
|
||||
|
||||
test 0 -eq 0 && \
|
||||
USAGE_STRING+="
|
||||
--new-systemd-unit We dropped this option for security reasons.
|
||||
Nowadays, please use the root-only script
|
||||
/usr/sbin/postgresql-new-systemd-unit.
|
||||
--datadir Dropped with --new-systemd-unit."
|
||||
|
||||
USAGE_STRING+="
|
||||
--upgrade-from-unit=UNIT Select proper unit name to upgrade from. This
|
||||
has similar semantics as --unit option.
|
||||
--upgrade-ids Print list of available IDs of upgrade scenarios to
|
||||
standard output.
|
||||
--upgrade-from=ID Specify id \"old\" postgresql stack to upgrade
|
||||
from. List of available IDs can be listed by
|
||||
--upgrade-ids. Default is '$option_upgradefrom'.
|
||||
|
||||
Other options:
|
||||
--help show this help
|
||||
--version show version of this package
|
||||
--debug show basic debugging information
|
||||
|
||||
Environment:
|
||||
PGSETUP_INITDB_OPTIONS Options carried by this variable are passed to
|
||||
subsequent call of \`initdb\` binary (see man
|
||||
initdb(1)). This variable is used also during
|
||||
'upgrade' mode because the new cluster is actually
|
||||
re-initialized from the old one.
|
||||
PGSETUP_PGUPGRADE_OPTIONS Options in this variable are passed next to the
|
||||
subsequent call of \`pg_upgrade\`. For more info
|
||||
about possible options please look at man
|
||||
pg_upgrade(1).
|
||||
PGSETUP_DEBUG Set to '1' if you want to see very verbose shell
|
||||
debugging output."
|
||||
|
||||
|
||||
print_version()
|
||||
{
|
||||
echo "postgresql-setup 8.2"
|
||||
echo $"Built against PostgreSQL version 10.5."
|
||||
}
|
||||
|
||||
|
||||
check_not_initialized()
|
||||
{
|
||||
if test -f "$pgdata/PG_VERSION"; then
|
||||
error $"Data directory $pgdata is not empty!"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
# code shared between initdb and upgrade actions
|
||||
perform_initdb()
|
||||
{
|
||||
if [ ! -e "$pgdata" ]; then
|
||||
mkdir "$pgdata" || return 1
|
||||
fi
|
||||
$RESTORECON "$pgdata"
|
||||
test -w "$pgdata" || die "$pgdata is not writeable by $USER"
|
||||
|
||||
# Clean up SELinux tagging for pgdata
|
||||
[ -x /sbin/restorecon ] && /sbin/restorecon "$pgdata"
|
||||
|
||||
# Create the initdb log file if needed
|
||||
if [ ! -e "$initdb_log" ]; then
|
||||
touch "$initdb_log" || return 1
|
||||
fi
|
||||
$RESTORECON "$initdb_log"
|
||||
test -w "$initdb_log" || echo "$initdb_log is not writeable by $USER"
|
||||
|
||||
# Initialize the database
|
||||
initdbcmd+=( "$PGENGINE"/initdb --pgdata="$pgdata" --auth=ident )
|
||||
eval "initdbcmd+=( $PGSETUP_INITDB_OPTIONS )"
|
||||
"${initdbcmd[@]}" >> "$initdb_log" 2>&1 < /dev/null
|
||||
|
||||
# Create directory for postmaster log files
|
||||
mkdir "$pgdata/pg_log"
|
||||
$RESTORECON "$pgdata/pg_log"
|
||||
|
||||
# This if-fork is just to not unnecessarily overwrite what upstream
|
||||
# generates by initdb (upstream implicitly uses PGPORT_DEF).
|
||||
if test "$pgport" != "$PGPORT_DEF"; then
|
||||
local pgconf="$pgdata/postgresql.conf"
|
||||
sed -i "s|^[[:space:]#]*port[[:space:]]=[^#]*|port = $pgport |g" \
|
||||
"$pgconf" \
|
||||
&& grep "^port = " "$pgconf" >/dev/null
|
||||
|
||||
if test $? -ne 0; then
|
||||
error "can not change port in $pgdata/postgresql.conf"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
test -f "$pgdata/PG_VERSION"
|
||||
}
|
||||
|
||||
|
||||
initdb()
|
||||
{
|
||||
port_info=
|
||||
test "$pgport" != "$PGPORT_DEF" \
|
||||
&& port_info=$", listening on port '$pgport'"
|
||||
|
||||
info $"Initializing database in '$pgdata'$port_info"
|
||||
if check_not_initialized && perform_initdb; then
|
||||
info $"Initialized, logs are in ${initdb_log}"
|
||||
else
|
||||
error $"Initializing database failed, possibly see $initdb_log"
|
||||
script_result=1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
old_data_in_use()
|
||||
{
|
||||
local pidfile="$pgdataold/postmaster.pid"
|
||||
test -f "$pidfile" || return 1
|
||||
error $"The pidfile '$pidfile' exists. Verify that there is no postmaster"
|
||||
error_q $"running the $pgdataold directory."
|
||||
}
|
||||
|
||||
|
||||
upgrade()
|
||||
{
|
||||
local inplace=false
|
||||
test "$pgdata" = "$upgradefrom_data" && inplace=true
|
||||
|
||||
debug "running inplace upgrade: $inplace"
|
||||
|
||||
# must see previous version in PG_VERSION
|
||||
local old_data_version="`cat "$upgradefrom_data/PG_VERSION"`"
|
||||
if [ ! -f "$upgradefrom_data/PG_VERSION" -o \
|
||||
x"$old_data_version" != x"$upgradefrom_major" ]
|
||||
then
|
||||
error $"Cannot upgrade because the database in $upgradefrom_data is of"
|
||||
error_q $"version $old_data_version but it should be $upgradefrom_major"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -x "$upgradefrom_engine/postgres" ]; then
|
||||
error $"Please install the $upgradefrom_package package."
|
||||
exit 5
|
||||
fi
|
||||
if [ ! -x "$PGENGINE/pg_upgrade" ]; then
|
||||
# The "$PGENGINE/postgres" depends transitively on
|
||||
# pg_upgrade binary in rather newer packaging, but SCL with PostgreSQL
|
||||
# 9.4 provides '*-upgrade' package having `pg_upgrade` inside. We need
|
||||
# to have this installed, too. Keep till {rh,sclo}-postgresql94 is
|
||||
# still a thing.
|
||||
error $"Please install the postgresql-upgrade package."
|
||||
exit 5
|
||||
fi
|
||||
|
||||
# Set up log file for pg_upgrade
|
||||
rm -f "$upgrade_log"
|
||||
touch "$upgrade_log" || die "can't write into $upgrade_log file"
|
||||
$RESTORECON "$upgrade_log"
|
||||
|
||||
# Move old DB to pgdataold
|
||||
|
||||
if $inplace; then
|
||||
pgdataold="${pgdata}-old"
|
||||
rm -rf "$pgdataold"
|
||||
mv "$pgdata" "$pgdataold" || exit 1
|
||||
else
|
||||
pgdataold="$upgradefrom_data"
|
||||
fi
|
||||
|
||||
# Create configuration file for upgrade process
|
||||
HBA_CONF_BACKUP="$pgdataold/pg_hba.conf.postgresql-setup.`date +%s`"
|
||||
HBA_CONF_BACKUP_EXISTS=0
|
||||
|
||||
if [ ! -f $HBA_CONF_BACKUP ]; then
|
||||
mv "$pgdataold/pg_hba.conf" "$HBA_CONF_BACKUP"
|
||||
HBA_CONF_BACKUP_EXISTS=1
|
||||
|
||||
# For fluent upgrade 'postgres' user should be able to connect
|
||||
# to any database without password. Temporarily, no other type
|
||||
# of connection is needed.
|
||||
echo "local all postgres ident" > "$pgdataold/pg_hba.conf"
|
||||
$RESTORECON "$pgdataold"
|
||||
fi
|
||||
|
||||
info $"Upgrading database."
|
||||
|
||||
scls_upgrade_hacks=
|
||||
test -n "$upgradefrom_scls" && {
|
||||
debug "scls [$upgradefrom_scls] will be enabled"
|
||||
scls_upgrade_hacks="source scl_source enable $upgradefrom_scls"
|
||||
}
|
||||
|
||||
test x"$upgradefrom_redhat_sockets_hack" = xyes && {
|
||||
debug "upgrading from redhat server"
|
||||
socket_hacks="export REDHAT_PGUPGRADE_FROM_RHEL=yes"
|
||||
}
|
||||
|
||||
test -n "$upgradefrom_pghost_override" && {
|
||||
pghost_override="export PGHOST='$upgradefrom_pghost_override'"
|
||||
}
|
||||
|
||||
local failure_cleanup=true
|
||||
if old_data_in_use; then
|
||||
script_result=1
|
||||
# Cleanup makes sense once perform_initdb gets called.
|
||||
failure_cleanup=false
|
||||
elif ! check_not_initialized; then
|
||||
# Don't try to re-init initialized data directory and also do not
|
||||
# remove it after this unsuccessful upgrade.
|
||||
script_result=1
|
||||
failure_cleanup=false
|
||||
elif perform_initdb; then
|
||||
$inplace && link_option=--link
|
||||
|
||||
# After creating the empty new-format database, do the upgrade
|
||||
(
|
||||
cd # pg_upgrade writes to $PWD
|
||||
eval "
|
||||
$scls_upgrade_hacks
|
||||
$socket_hacks
|
||||
$pghost_override
|
||||
"
|
||||
eval "add_options=( $PGSETUP_PGUPGRADE_OPTIONS )"
|
||||
|
||||
"$PGENGINE"/pg_upgrade \
|
||||
--old-bindir="$upgradefrom_engine" \
|
||||
--new-bindir="$PGENGINE" \
|
||||
--old-datadir="$pgdataold" \
|
||||
--new-datadir="$pgdata" \
|
||||
$link_option \
|
||||
--old-port="$PGPORT" \
|
||||
--new-port="$PGPORT" \
|
||||
--username=postgres \
|
||||
"${add_options[@]}" \
|
||||
>>"$upgrade_log" 2>>"$upgrade_log"
|
||||
)
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
# pg_upgrade failed
|
||||
error $"pg_upgrade tool failed"
|
||||
script_result=1
|
||||
fi
|
||||
else
|
||||
error $"initdb failed"
|
||||
script_result=1
|
||||
fi
|
||||
|
||||
# Move back the backed-up pg_hba.conf regardless of the script_result.
|
||||
if [ x$HBA_CONF_BACKUP_EXISTS = x1 ]; then
|
||||
mv -f "$HBA_CONF_BACKUP" "$pgdataold/pg_hba.conf"
|
||||
fi
|
||||
|
||||
if [ $script_result -eq 0 ]; then
|
||||
info $"Upgraded OK."
|
||||
warn $"The configuration files were replaced by default configuration."
|
||||
warn $"The previous configuration and data are stored in folder"
|
||||
warn $pgdataold.
|
||||
else
|
||||
# Clean up after failure.
|
||||
$failure_cleanup && rm -rf "$pgdata"
|
||||
$inplace && mv "$pgdataold" "$pgdata"
|
||||
error $"Upgrade failed."
|
||||
fi
|
||||
info $"See $upgrade_log for details."
|
||||
}
|
||||
|
||||
|
||||
check_daemon_reload()
|
||||
{
|
||||
local nr_option=NeedDaemonReload
|
||||
|
||||
test 0 = 1 && return 0
|
||||
|
||||
local nr_out="`systemctl show -p $nr_option $option_service.service 2>/dev/null`"
|
||||
if [[ "$nr_out" != "$nr_option=no" ]]; then
|
||||
error $"Note that systemd configuration for '$option_service' changed."
|
||||
error_q $"You need to perform 'systemctl daemon-reload' otherwise the"
|
||||
error_q $"results of this script can be inadequate."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
handle_service_env()
|
||||
{
|
||||
local service="$1"
|
||||
|
||||
local systemd_env="$(systemctl show -p Environment "${service}.service")" \
|
||||
|| { return; }
|
||||
|
||||
for env_var in `echo "$systemd_env" | sed 's/^Environment=//'`; do
|
||||
# If one variable name is defined multiple times the last definition wins.
|
||||
case "$env_var" in
|
||||
PGDATA=*)
|
||||
unit_pgdata="${env_var##PGDATA=}"
|
||||
debug "unit's datadir: '$unit_pgdata'"
|
||||
;;
|
||||
PGPORT=*)
|
||||
unit_pgport="${env_var##PGPORT=}"
|
||||
debug "unit's pgport: $unit_pgport"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
handle_envfile()
|
||||
{
|
||||
local file="$1"
|
||||
|
||||
debug "trying to read '$file' env file"
|
||||
if test ! -r "$file"; then
|
||||
if test 0 = 1; then
|
||||
return
|
||||
fi
|
||||
error "Can not read EnvironmentFile '$file' specified"
|
||||
error_q "in ${service}.service"
|
||||
fi
|
||||
|
||||
# Note that the env file parser in systemd does not perform exactly the
|
||||
# same job.
|
||||
unset PGPORT PGDATA
|
||||
. "$file"
|
||||
envfile_pgdata="$PGDATA"
|
||||
envfile_pgport="$PGPORT"
|
||||
unset PGPORT PGDATA
|
||||
}
|
||||
|
||||
|
||||
handle_service_envfiles()
|
||||
{
|
||||
local mode="$1"
|
||||
local service="$2"
|
||||
|
||||
local envfiles="$(systemctl show -p EnvironmentFiles "${service}.service")"\
|
||||
|| return
|
||||
|
||||
test -z "$envfiles" && return
|
||||
|
||||
envfiles=$(echo $envfiles | \
|
||||
sed -e 's/^EnvironmentFile=//' \
|
||||
-e 's| ([^)]*)$||'
|
||||
)
|
||||
|
||||
# Read the file names line-by-line (spaces may be inside)
|
||||
while read line; do
|
||||
handle_envfile "$line"
|
||||
done <<<"$envfiles"
|
||||
}
|
||||
|
||||
|
||||
handle_pgconf()
|
||||
{
|
||||
local datadir="$1"
|
||||
local conffile="$datadir/postgresql.conf"
|
||||
|
||||
debug "postgresql.conf: $conffile"
|
||||
|
||||
test -r "$conffile" || {
|
||||
error "config file $conffile is not readable or does not exist"
|
||||
die "Old cluster in '$data' does not seem to be initialized"
|
||||
}
|
||||
|
||||
local sp='[[:space:]]'
|
||||
local sed_expr="s/^$sp*port$sp*=$sp\([0-9]\+\).*/\1/p"
|
||||
|
||||
rv=0
|
||||
conf_pgport=`sed -n "$sed_expr" $conffile | tail -1` || rv=1
|
||||
test -n "$conf_pgport" && debug "postgresql.conf pgport: $conf_pgport"
|
||||
return $rv
|
||||
}
|
||||
|
||||
|
||||
service_configuration()
|
||||
{
|
||||
local data=
|
||||
local port=
|
||||
local unit_pgport=
|
||||
local unit_pgdata=
|
||||
local envfile_pgport=
|
||||
local envfile_pgdata=
|
||||
|
||||
# 'mode' is 'initdb' or 'upgrade'. Basically, if called with mode=initdb, we
|
||||
# parse configuration of the current (maybe already configured) service.
|
||||
# When run with mode=upgrade, we try to parse the configuration of the old
|
||||
# PostgreSQL configuration that we try to upgrade from.
|
||||
|
||||
local mode="$1" datavar="$2" portvar="$3" service="$4"
|
||||
|
||||
debug "running service_configuration() for $service, mode: $mode"
|
||||
|
||||
if test "0" = 1; then
|
||||
# Sysvinit has the default PGDATA (for default unit name only)
|
||||
# configured directly in the initscript, so no additional configuration
|
||||
# must exist. Set the default value of pgdata here to match whats in
|
||||
# initscript for the cases when no additional configuration file exists.
|
||||
# This is done to avoid parsing of whole initscript (for the real value)
|
||||
# and mainly to not fail in the logic following 'service_configuration'
|
||||
# call, where we usually want to error that pgdata is not defined..
|
||||
# Don't set the default pgdata for upgrade case, however, as we must
|
||||
# upgrade only from already properly configured & working stack (missing
|
||||
# pgdata here is a good reason to die later).
|
||||
test initdb = "$mode" && test "$service" = "postgresql" \
|
||||
&& set_var "$datavar" "/var/lib/pgsql/data"
|
||||
handle_envfile "/etc/sysconfig/pgsql/$service"
|
||||
else
|
||||
# We ship two service files, postgresql.service and
|
||||
# postgresql@.service. The former has PGDATA set by default
|
||||
# similarly to sysvinit case.
|
||||
handle_service_env "$service"
|
||||
handle_service_envfiles "$option_mode" "$service"
|
||||
fi
|
||||
|
||||
# EnvironmentFile beats Environment configuration in systemd. In sysvinit
|
||||
# there is no "unit_pgdata". So make sure the envfile_gpdata is used later
|
||||
# than unit_pgdata.
|
||||
test -n "$unit_pgdata" && set_var "$datavar" "$unit_pgdata"
|
||||
test -n "$envfile_pgdata" && set_var "$datavar" "$envfile_pgdata"
|
||||
|
||||
# skip for the first run
|
||||
test initdb = "$mode" && return
|
||||
|
||||
set_var data "\$$datavar"
|
||||
handle_pgconf "$data"
|
||||
|
||||
test -n "$conf_pgport" && set_var "$portvar" "$conf_pgport"
|
||||
test -n "$unit_pgport" && set_var "$portvar" "$unit_pgport"
|
||||
test -n "$envfile_pgport" && set_var "$portvar" "$envfile_pgport"
|
||||
}
|
||||
|
||||
# <Compat>
|
||||
# Alow users to use the old style arguments like
|
||||
# 'postgresql-setup initdb $SERVICE_NAME'.
|
||||
case "$1" in initdb|upgrade)
|
||||
action="--$1"
|
||||
shift
|
||||
|
||||
warn "using obsoleted argument syntax, try --help"
|
||||
old_long_args="help,usage,version,debug"
|
||||
oldargs=`getopt -o "" -l "$old_long_args" -n "old-options" -- "$@"` \
|
||||
|| die "can't parse old arguments"
|
||||
eval set -- "$oldargs"
|
||||
additional_opts=
|
||||
while true; do
|
||||
case "$1" in
|
||||
--version|--help|--usage|--debug)
|
||||
additional_opts="$additional_opts $1"
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
service="postgresql"
|
||||
if test -n "$1"; then
|
||||
service=$1
|
||||
shift
|
||||
fi
|
||||
|
||||
set -- $additional_opts "$action" --unit "$service" "$@"
|
||||
warn "arguments transformed to: ${0##*/} $*"
|
||||
esac
|
||||
# </Compat>
|
||||
|
||||
|
||||
# postgresql-setup arguments are parsed into those variables
|
||||
option_mode=none
|
||||
option_service="postgresql"
|
||||
option_port=
|
||||
option_debug=0
|
||||
option_upgradefrom_unit=
|
||||
|
||||
# Content of EnvironmentFile= files fills those:
|
||||
envfile_pgdata=
|
||||
envfile_pgport=
|
||||
|
||||
# Configuration from (/etc/systemd/system/$option_service.service) fills those
|
||||
# variables.
|
||||
unit_pgdata=
|
||||
unit_pgport=
|
||||
|
||||
# Configuration from postgresql.conf:
|
||||
conf_pgport=
|
||||
|
||||
# Key variables. Try to fill them by postgresql.conf, Environment= statement in
|
||||
# service file or EnvironmentFile= content (the later mentioned has more
|
||||
# priority).
|
||||
pgdata=default
|
||||
pgport=default
|
||||
|
||||
## PARSE SCRIPT ARGUMENTS ##
|
||||
|
||||
short_opts=""
|
||||
long_opts="\
|
||||
initdb,upgrade,\
|
||||
new-systemd-unit,upgrade-ids,\
|
||||
unit:,service:,port:,datadir:,upgrade-from:,upgrade-from-unit:,\
|
||||
debug,\
|
||||
version,help,usage"
|
||||
|
||||
args=`getopt -o "$short_opts" -l "$long_opts" -n "postgresql-setup" -- "$@"` \
|
||||
|| die "can't parse arguments"
|
||||
eval set -- "$args"
|
||||
parse_fail=0
|
||||
while true; do
|
||||
case "$1" in
|
||||
--initdb|--upgrade)
|
||||
if test "$option_mode" != none; then
|
||||
error "bad argument $1, mode already specified: --$option_mode"
|
||||
parse_fail=1
|
||||
else
|
||||
option_mode=${1##--}
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
|
||||
--unit|--service)
|
||||
option_service=$2
|
||||
shift 2
|
||||
;;
|
||||
|
||||
--port)
|
||||
option_port=$2
|
||||
shift 2
|
||||
;;
|
||||
|
||||
--datadir|--new-systemd-unit)
|
||||
error $"Removed option --new-systemd-unit/--datadir, please use"
|
||||
error_q $"/usr/sbin/postgresql-new-systemd-unit script"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
--debug)
|
||||
option_debug=1
|
||||
shift
|
||||
;;
|
||||
|
||||
--help|--usage)
|
||||
echo "$USAGE_STRING"
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--upgrade-from)
|
||||
option_upgradefrom="$2"
|
||||
shift 2
|
||||
;;
|
||||
|
||||
--upgrade-from-unit)
|
||||
option_upgradefrom_unit="$2"
|
||||
shift 2
|
||||
;;
|
||||
|
||||
--version)
|
||||
print_version
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
|
||||
*)
|
||||
die "author's fault: option $1 not handled"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test $parse_fail -ne 0 && die "can't parse arguments"
|
||||
|
||||
test "$option_mode" = none \
|
||||
&& die "no mode specified, use --initdb or --upgrade, or --help"
|
||||
|
||||
## GATHER THE SETUP FIRST ##
|
||||
|
||||
initdb_log="$POSTGRES_HOMEDIR/initdb_${option_service}.log"
|
||||
upgrade_log="$POSTGRES_HOMEDIR/upgrade_${option_service}.log"
|
||||
|
||||
debug "mode used: $option_mode"
|
||||
debug "service name: $option_service"
|
||||
|
||||
# load service's pgdata
|
||||
service_configuration initdb pgdata UNUSED "$option_service"
|
||||
|
||||
test "$pgdata" = default \
|
||||
&& die $"no db datadir (PGDATA) configured for '$option_service$srvsuff' unit"
|
||||
|
||||
[[ "$pgdata" =~ ^/.* ]] \
|
||||
|| die $"the PostgreSQL datadir not absolute path: '$pgdata', try --debug"
|
||||
|
||||
## GATHER DATA FROM INITIALIZED DATADIR ##
|
||||
|
||||
test -n "$option_port" && pgport=$option_port
|
||||
|
||||
if test upgrade = "$option_mode"; then
|
||||
upgradefrom_data="$upgradefrom_data_default"
|
||||
|
||||
if test -z "$option_upgradefrom_unit"; then
|
||||
if test "postgresql" = "postgresql"; then
|
||||
# Fedora usecase -> upgrade while keeping the same name of
|
||||
# service/unit.
|
||||
option_upgradefrom_unit=$option_service
|
||||
else
|
||||
# PGRPMs/RHSCL usecase -> we upgrade from one service/unit name to
|
||||
# a different one, e.g. from postgresql92 to postgresql93, or from
|
||||
# postgresql (system version) to postgresql94 (scl).
|
||||
option_upgradefrom_unit=$upgradefrom_id
|
||||
|
||||
# Try to predict situations: postgresql93@second -> postgresql94@second
|
||||
if [[ "$option_service" =~ ^postgresql@(.*)$ ]]; then
|
||||
option_upgradefrom_unit="$upgradefrom_id@${BASH_REMATCH[1]}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
test "$option_service" = "$option_upgradefrom_unit" \
|
||||
|| info "upgrading from '$option_upgradefrom_unit$srvsuff'" \
|
||||
"to '$option_service$srvsuff'"
|
||||
|
||||
service_configuration upgrade upgradefrom_data pgport \
|
||||
"$option_upgradefrom_unit"
|
||||
test -n "$option_port" -a "$option_port" != "$pgport" \
|
||||
&& warn "Old pgport $pgport has bigger priority than --pgport value."
|
||||
fi
|
||||
|
||||
# We expect that for upgrade - the previous stack was in working state (thus
|
||||
# running on the default port).
|
||||
test "$option_mode" = upgrade -a "$pgport" = default \
|
||||
&& pgport=$PGPORT_DEF
|
||||
|
||||
# This is mostly for 'initdb'. We assume that the default port is $PGPORT_DEF
|
||||
# if not set explicitly for default service name 'postgresql'.
|
||||
if test "$pgport" = default -a "$option_service" = "postgresql"; then
|
||||
debug $"Using the default port '$PGPORT_DEF'"
|
||||
pgport=$PGPORT_DEF
|
||||
fi
|
||||
|
||||
if test "$pgport" = default; then
|
||||
# initdb case.. Note that this may be called by initscripts. If this gets
|
||||
# called by legacy script, we can't help too much because systemd does not
|
||||
# allow passing additional arguments to 'service XX initdb' command.
|
||||
die $"For non-default unit names you must specify port by --port option."
|
||||
fi
|
||||
|
||||
[[ "$option_port" =~ ^[0-9]*$ ]] \
|
||||
|| die $"port set to '$option_port', must be integer number"
|
||||
|
||||
## LAST CHECK THE SETUP ##
|
||||
|
||||
check_daemon_reload
|
||||
|
||||
# These variables are read by underlying utilites, rather export them.
|
||||
export PGDATA=$pgdata
|
||||
export PGPORT=$pgport
|
||||
|
||||
debug "final pgdata: $pgdata"
|
||||
debug "final pgport: $pgport"
|
||||
|
||||
script_result=0
|
||||
|
||||
test -w "/var/lib/pgsql" || {
|
||||
# pg_upgrade binary needs to have write-able $PWD (and we use 'su -')
|
||||
error $"The /var/lib/pgsql directory has wrong permissions."
|
||||
error_q $"Please make sure the directory is writable by $USER."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if /usr/bin/mountpoint -q "$pgdata" || /usr/bin/mountpoint -q "$(dirname "$pgdata")"; then
|
||||
warn $"Note that either your data directory '$pgdata' or"
|
||||
warn_q $"the parent directory '$(dirname "$pgdata")'"
|
||||
warn_q $"is a direct mountpoint. This is usually a bad idea and your"
|
||||
warn_q $"filesystem layout should ideally look like:"
|
||||
warn_q $"/ROOT_OWNED_MOUNTPOINT/POSTGRES_OWNED_DIRECTORY/DATADIR."
|
||||
warn_q $"See the upstream documentation for more info:"
|
||||
warn_q $"http://www.postgresql.org/docs/10/static/creating-cluster.html"
|
||||
fi
|
||||
|
||||
# See how we were called.
|
||||
case "$option_mode" in
|
||||
initdb)
|
||||
initdb
|
||||
;;
|
||||
upgrade)
|
||||
upgrade
|
||||
;;
|
||||
*)
|
||||
echo >&2 "$USAGE_STRING"
|
||||
exit 2
|
||||
esac
|
||||
|
||||
exit $script_result
|
||||
BIN
postgresql-setup-8.5.tar.gz
Normal file
BIN
postgresql-setup-8.5.tar.gz
Normal file
Binary file not shown.
@ -42,12 +42,12 @@ diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h
|
||||
index e278fa0..9ee15d4 100644
|
||||
--- a/src/include/pg_config_manual.h
|
||||
+++ b/src/include/pg_config_manual.h
|
||||
@@ -169,7 +169,7 @@
|
||||
* here's where to twiddle it. You can also override this at runtime
|
||||
* with the postmaster's -k switch.
|
||||
@@ -201,7 +201,7 @@
|
||||
* support them yet.
|
||||
*/
|
||||
#ifndef WIN32
|
||||
-#define DEFAULT_PGSOCKET_DIR "/tmp"
|
||||
+#define DEFAULT_PGSOCKET_DIR "/var/run/postgresql"
|
||||
|
||||
/*
|
||||
* This is the default event source for Windows event log.
|
||||
#else
|
||||
#define DEFAULT_PGSOCKET_DIR ""
|
||||
#endif
|
||||
3
postgresql.pam
Normal file
3
postgresql.pam
Normal file
@ -0,0 +1,3 @@
|
||||
#%PAM-1.0
|
||||
auth include password-auth
|
||||
account include password-auth
|
||||
@ -1,23 +0,0 @@
|
||||
[Unit]
|
||||
Description=PostgreSQL database server
|
||||
After=network.target
|
||||
[Service]
|
||||
Type=notify
|
||||
|
||||
User=postgres
|
||||
Group=postgres
|
||||
OOMScoreAdjust=-1000
|
||||
Environment=PG_OOM_ADJUST_FILE=/proc/self/oom_score_adj
|
||||
Environment=PG_OOM_ADJUST_VALUE=0
|
||||
Environment=PGDATA=/var/lib/pgsql/data
|
||||
|
||||
ExecStartPre=/usr/libexec/postgresql-check-db-dir %N
|
||||
ExecStart=/usr/bin/postmaster -D ${PGDATA}
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
KillMode=mixed
|
||||
KillSignal=SIGINT
|
||||
|
||||
TimeoutSec=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
1420
postgresql.spec
1420
postgresql.spec
File diff suppressed because it is too large
Load Diff
@ -1,193 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Do some "integration" testing against running PostgreSQL server.
|
||||
|
||||
# This file is to be sourced.
|
||||
|
||||
try_random_port ()
|
||||
{
|
||||
_port=$RANDOM
|
||||
if test -n "$_port" && eval '_port=$(( $_port + 32000 ))' 2>/dev/null; then
|
||||
echo "$_port"
|
||||
elif test -x /usr/bin/shuf; then
|
||||
/usr/bin/shuf -r -n 1 -i 32000-64767
|
||||
else
|
||||
echo 54321
|
||||
fi
|
||||
}
|
||||
|
||||
: ${PGTESTS_DATADIR=`pwd`/datadir}
|
||||
: ${PGTESTS_ADMIN=`id -u -n`}
|
||||
: ${PGTESTS_ADMINDB=$PGTESTS_ADMIN}
|
||||
: ${PGTESTS_ADMINPASS=$PGTESTS_ADMIN}
|
||||
: ${PGTESTS_PORT=`try_random_port`}
|
||||
: ${PGTESTS_SOCKETDIR=/tmp}
|
||||
: ${PGTESTS_USERS=test:test}
|
||||
: ${PGTESTS_DATABASES=test:test}
|
||||
|
||||
# Stop the old cluster and/or remove it's data.
|
||||
: ${PGTESTS_STARTCLEANUP=:}
|
||||
|
||||
# Cleanup once we exit the script.
|
||||
: ${PGTESTS_CLEANUP=:}
|
||||
|
||||
# Cleanup once we exit the script.
|
||||
: ${PGTESTS_CLEANUP=:}
|
||||
|
||||
export PGPORT=$PGTESTS_PORT
|
||||
export PGHOST=$PGTESTS_SOCKETDIR
|
||||
|
||||
:
|
||||
|
||||
warning ()
|
||||
{
|
||||
echo >&2 " ! $*"
|
||||
}
|
||||
|
||||
|
||||
__trap_cb ()
|
||||
{
|
||||
IFS=' '
|
||||
for __func in $__TRAP_ACTIONS
|
||||
do
|
||||
$__func
|
||||
done
|
||||
}
|
||||
trap __trap_cb EXIT
|
||||
|
||||
|
||||
__pgtests_initdb ()
|
||||
{
|
||||
initdb "$PGTESTS_DATADIR" -U "$PGTESTS_ADMIN" \
|
||||
--auth-local=peer --auth-host=md5 \
|
||||
${PGTESTS_LOCALE+--locale="$PGTESTS_LOCALE"}
|
||||
}
|
||||
|
||||
|
||||
__pgtests_start ()
|
||||
{
|
||||
pg_ctl -D "$PGTESTS_DATADIR" -l "$PGTESTS_DATADIR"/start.log start \
|
||||
-o "-k $PGTESTS_SOCKETDIR -p $PGTESTS_PORT" -w || {
|
||||
cat >&2 "$PGTESTS_DATADIR"/start.log
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__pgtests_create_admins_db ()
|
||||
{
|
||||
createdb -h "$PGTESTS_SOCKETDIR" "$PGTESTS_ADMINDB" --owner "$PGTESTS_ADMIN" -p "$PGTESTS_PORT"
|
||||
}
|
||||
|
||||
|
||||
__pgtests_passwd()
|
||||
{
|
||||
psql -d postgres --set=user="$1" --set=pass="$2" -tA \
|
||||
<<<"ALTER USER :\"user\" WITH ENCRYPTED PASSWORD :'pass';"
|
||||
}
|
||||
|
||||
pgtests_start ()
|
||||
{
|
||||
unset __TRAP_ACTIONS
|
||||
|
||||
if $PGTESTS_STARTCLEANUP; then
|
||||
# We don't plan to be serious here. This pgtests_* effort is just to
|
||||
# ease _testing_ against running postgresql server without too much
|
||||
# writing.
|
||||
if test -f "$PGTESTS_DATADIR"/postmaster.pid; then
|
||||
# Give it a try.
|
||||
warning "Seems like server works, trying to stop."
|
||||
pg_ctl stop -D "$PGTESTS_DATADIR" -w
|
||||
fi
|
||||
|
||||
# Cleanup testing directory
|
||||
if test -e "$PGTESTS_DATADIR"; then
|
||||
warning "Removing old data directory."
|
||||
rm -r "$PGTESTS_DATADIR"
|
||||
fi
|
||||
fi
|
||||
|
||||
__pgtests_initdb
|
||||
__TRAP_ACTIONS="pgtests_cleanup $__TRAP_ACTIONS"
|
||||
__pgtests_start
|
||||
__TRAP_ACTIONS="pgtests_stop $__TRAP_ACTIONS"
|
||||
__pgtests_create_admins_db
|
||||
|
||||
__pgtests_passwd "$PGTESTS_ADMIN" "$PGTESTS_ADMINPASS"
|
||||
|
||||
|
||||
for _pgt_user in $PGTESTS_USERS
|
||||
do
|
||||
save_IFS=$IFS
|
||||
IFS=:
|
||||
_user=
|
||||
_pass=
|
||||
for _part in $_pgt_user
|
||||
do
|
||||
if test -z "$_user"; then
|
||||
_user=$_part
|
||||
else
|
||||
_pass=$_part
|
||||
fi
|
||||
done
|
||||
|
||||
createuser "$_user"
|
||||
__pgtests_passwd "$_user" "$_pass"
|
||||
IFS=$save_IFS
|
||||
done
|
||||
|
||||
|
||||
for _pgt_db in $PGTESTS_DATABASES
|
||||
do
|
||||
save_IFS=$IFS
|
||||
IFS=:
|
||||
_db=
|
||||
_user=
|
||||
for _part in $_pgt_db
|
||||
do
|
||||
if test -z "$_user"; then
|
||||
_user=$_part
|
||||
else
|
||||
_db=$_part
|
||||
fi
|
||||
done
|
||||
|
||||
createdb "$_db" --owner "$_part"
|
||||
|
||||
IFS=$save_IFS
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
__clean_trap_action ()
|
||||
{
|
||||
__new_actions=
|
||||
for __action in $__TRAP_ACTIONS
|
||||
do
|
||||
if test "$__action" = "$1"; then
|
||||
:
|
||||
else
|
||||
__new_actions="$__action $__new_actions"
|
||||
fi
|
||||
done
|
||||
|
||||
__TRAP_ACTIONS=$__new_actions
|
||||
}
|
||||
|
||||
|
||||
pgtests_cleanup ()
|
||||
{
|
||||
if $PGTESTS_CLEANUP && $PGTESTS_AUTOSTOP; then
|
||||
rm -r "$PGTESTS_DATADIR"
|
||||
fi
|
||||
__clean_trap_action pgtests_cleanup
|
||||
}
|
||||
|
||||
|
||||
pgtests_stop ()
|
||||
{
|
||||
if $PGTESTS_AUTOSTOP; then
|
||||
pg_ctl stop -D "$PGTESTS_DATADIR" -w
|
||||
fi
|
||||
__clean_trap_action pgtests_stop
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user