From de3f8ab7f4a9fe328b7e9460ac5e4f29bcd8b2f0 Mon Sep 17 00:00:00 2001 From: Jelte Fennema-Nio Date: Mon, 8 Jan 2024 16:25:16 +0100 Subject: [PATCH v10 10/13] Add GUC contexts for protocol extensions This patch adds two new GUC contexts: PGC_PROTOCOL and PGC_SU_PROTOCOL. These new GUC contexts are intended to be used by protocol extension parameters. Any intermediary component that works at the protocol level, such as clients libraries or connection poolsers, should be notified when changes to such parameters are made because these parameters control the behaviour and interpretation of the protocol. If changes are made without these intermediary components realizing they might interpret protocol messages incorrectly. It's also possible that such intermediary components themselves have certain requirements on the value of such parameters to be able to function correctly. So they might want to block certain changes, or modify the requested value before sending it to the PostgreSQL server. Having these protocol extension parameters use PGC_BACKEND is also not an option, because then these parameters would be unchangable once the connection is set up. Which would limit the ways in which they could be used, especially when considering connection poolers that might want to change the protocol parameters based on the client that the server connection is assigned to. --- src/backend/tcop/postgres.c | 19 ++++++++++-- src/backend/utils/misc/guc.c | 48 ++++++++++++++++++++++++++++- src/backend/utils/misc/guc_tables.c | 2 ++ src/include/utils/guc.h | 2 ++ 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index ec8eb018092..1e39c28a143 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -4879,18 +4879,33 @@ PostgresMain(const char *dbname, const char *username) { const char *parameter_name; const char *parameter_value; + struct config_generic *config; forbidden_in_wal_sender(firstchar); parameter_name = pq_getmsgstring(&input_message); parameter_value = pq_getmsgstring(&input_message); + pq_getmsgend(&input_message); - start_xact_command(); + config = find_option(parameter_name, false, false, ERROR); + if (config->context == PGC_PROTOCOL || config->context == PGC_SU_PROTOCOL) + { + if (IsTransactionOrTransactionBlock()) + { + ereport(ERROR, + (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), + errmsg("parameter \"%s\" cannot be changed within a transaction", parameter_name))); + } + } + else + { + start_xact_command(); + } SetConfigOption( parameter_name, parameter_value, - (superuser() ? PGC_SUSET : PGC_USERSET), + (superuser() ? PGC_SU_PROTOCOL : PGC_PROTOCOL), PGC_S_SESSION); if (whereToSendOutput == DestRemote) pq_putemptymessage(PqMsg_ParameterSetComplete); diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index dd5a46469a6..f8de9ca7b18 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -3567,8 +3567,53 @@ set_config_with_handle(const char *name, config_handle *handle, return 0; } break; + case PGC_SU_PROTOCOL: + if (context == PGC_BACKEND || context == PGC_PROTOCOL) + { + /* + * Check whether the requesting user has been granted + * privilege to set this GUC. + */ + AclResult aclresult; + + aclresult = pg_parameter_aclcheck(name, srole, ACL_SET); + if (aclresult != ACLCHECK_OK) + { + /* No granted privilege */ + ereport(elevel, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to set parameter \"%s\"", + name))); + return 0; + } + } + /* fall through to process the same as PGC_PROTOCOL */ + /* FALLTHROUGH */ + case PGC_PROTOCOL: + if (context == PGC_SIGHUP) + { + /* + * Same SIGHUP treatment as for PGC_BACKEND vars. See comment + * above for details. + */ + if (IsUnderPostmaster && changeVal && !is_reload) + return -1; + } + else if (context != PGC_POSTMASTER && + context != PGC_BACKEND && + context != PGC_SU_BACKEND && + context != PGC_PROTOCOL && + context != PGC_SU_PROTOCOL) + { + ereport(elevel, + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("parameter \"%s\" cannot be set using SQL", + name))); + return 0; + } + break; case PGC_SUSET: - if (context == PGC_USERSET || context == PGC_BACKEND) + if (context == PGC_USERSET || context == PGC_PROTOCOL || context == PGC_BACKEND) { /* * Check whether the requesting user has been granted @@ -4625,6 +4670,7 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt) * to be set in PG_AUTOCONF_FILENAME file. */ if ((record->context == PGC_INTERNAL) || + (record->context == PGC_PROTOCOL) || (record->flags & GUC_DISALLOW_IN_FILE) || (record->flags & GUC_DISALLOW_IN_AUTO_FILE)) ereport(ERROR, diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index d77214795de..09084db0c05 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -633,6 +633,8 @@ const char *const GucContext_Names[] = [PGC_SIGHUP] = "sighup", [PGC_SU_BACKEND] = "superuser-backend", [PGC_BACKEND] = "backend", + [PGC_SU_PROTOCOL] = "superuser-protocol", + [PGC_PROTOCOL] = "protocol", [PGC_SUSET] = "superuser", [PGC_USERSET] = "user", }; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 3712aba09b0..c7a9efe0adf 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -71,6 +71,8 @@ typedef enum PGC_SIGHUP, PGC_SU_BACKEND, PGC_BACKEND, + PGC_SU_PROTOCOL, + PGC_PROTOCOL, PGC_SUSET, PGC_USERSET, } GucContext; -- 2.34.1