From 00105260dd70a3239dddc87e2d908ee977a86495 Mon Sep 17 00:00:00 2001
From: Gabriele Bartolini <gabriele.bartolini@enterprisedb.com>
Date: Fri, 8 Sep 2023 20:25:36 +0200
Subject: [PATCH v2] Add `enable_alter_system` GUC

Introduce the `enable_alter_system` GUC (by default set to `true`)
to be configured as an option at startup of the postmaster.

Signed-off-by: Gabriele Bartolini <gabriele.bartolini@enterprisedb.com>
---
 doc/src/sgml/config.sgml                      | 23 +++++++++++++++++++
 doc/src/sgml/ref/alter_system.sgml            |  6 +++++
 doc/src/sgml/ref/pg_ctl-ref.sgml              |  9 ++++++++
 src/backend/utils/misc/guc.c                  |  8 +++++++
 src/backend/utils/misc/guc_tables.c           | 12 ++++++++++
 src/backend/utils/misc/postgresql.conf.sample |  5 ++++
 src/include/utils/guc_tables.h                |  4 ++++
 src/test/regress/expected/sysviews.out        |  3 ++-
 8 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 65a6e6c4086..ed02bc4fc8d 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -631,6 +631,29 @@ include_dir 'conf.d'
      </para>
    </sect1>
 
+   <sect1 id="runtime-config-usage-restrictions">
+    <title>Usage Restrictions</title>
+    <variablelist>
+     <varlistentry id="guc-enable-alter-system" xreflabel="enable_alter_system">
+      <term><varname>enable_alter_system</varname> (<type>string</type>)
+      <indexterm>
+       <primary><varname>enable_alter_system</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        When set to <literal>on</literal> (default), the
+        <command>ALTER SYSTEM</command> command can be used by the superuser.
+        When set to <literal>off</literal> and error is returned if the command
+        is used. This parameter can only be set in the
+        <filename>postgresql.conf</filename> file or on the server command
+        line.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </sect1>
+
    <sect1 id="runtime-config-connection">
     <title>Connections and Authentication</title>
 
diff --git a/doc/src/sgml/ref/alter_system.sgml b/doc/src/sgml/ref/alter_system.sgml
index bea5714ba1a..3e727d08dab 100644
--- a/doc/src/sgml/ref/alter_system.sgml
+++ b/doc/src/sgml/ref/alter_system.sgml
@@ -111,6 +111,12 @@ ALTER SYSTEM RESET ALL
   <para>
    See <xref linkend="config-setting"/> for other ways to set the parameters.
   </para>
+
+  <para>
+   <literal>ALTER SYSTEM</literal> can be disabled at startup by passing
+   <literal>enable_alter_system=off</literal> to the <command>postgres</command>
+   command.
+  </para>
  </refsect1>
 
  <refsect1>
diff --git a/doc/src/sgml/ref/pg_ctl-ref.sgml b/doc/src/sgml/ref/pg_ctl-ref.sgml
index 46906966eb9..f6d573084fc 100644
--- a/doc/src/sgml/ref/pg_ctl-ref.sgml
+++ b/doc/src/sgml/ref/pg_ctl-ref.sgml
@@ -645,6 +645,15 @@ PostgreSQL documentation
 <screen>
 <prompt>$</prompt> <userinput>pg_ctl -o "-F -p 5433" start</userinput>
 </screen></para>
+
+   <para>
+    To start the server and disable <command>ALTER SYSTEM</command>,
+    waiting until the server is accepting connections:
+<screen>
+<prompt>$</prompt> <userinput>pg_ctl start -o "-c enable_alter_system=off"</userinput>
+</screen>
+   </para>
+
   </refsect2>
 
   <refsect2 id="r2-app-pgctl-4">
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 391866145ee..bcefbed8800 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -4563,6 +4563,14 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
 	 */
 	name = altersysstmt->setstmt->name;
 
+	if (! EnableAlterSystem)
+	{
+
+		ereport(ERROR,
+			(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				errmsg("permission denied to run ALTER SYSTEM")));
+	}
+
 	switch (altersysstmt->setstmt->kind)
 	{
 		case VAR_SET_VALUE:
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 57d9de4dd92..df956986c08 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -494,6 +494,7 @@ extern const struct config_enum_entry dynamic_shared_memory_options[];
 /*
  * GUC option variables that are exported from this module
  */
+bool		EnableAlterSystem = true;
 bool		log_duration = false;
 bool		Debug_print_plan = false;
 bool		Debug_print_parse = false;
@@ -677,6 +678,7 @@ const char *const config_group_names[] =
 	[CONN_AUTH_TCP] = gettext_noop("Connections and Authentication / TCP Settings"),
 	[CONN_AUTH_AUTH] = gettext_noop("Connections and Authentication / Authentication"),
 	[CONN_AUTH_SSL] = gettext_noop("Connections and Authentication / SSL"),
+	[USAGE_RESTRICTIONS] = gettext_noop("Restricting Usage"),
 	[RESOURCES_MEM] = gettext_noop("Resource Usage / Memory"),
 	[RESOURCES_DISK] = gettext_noop("Resource Usage / Disk"),
 	[RESOURCES_KERNEL] = gettext_noop("Resource Usage / Kernel Resources"),
@@ -1040,6 +1042,16 @@ struct config_bool ConfigureNamesBool[] =
 		false,
 		NULL, NULL, NULL
 	},
+	{
+		{"enable_alter_system", PGC_SIGHUP, USAGE_RESTRICTIONS,
+			gettext_noop("Enable ALTER SYSTEM command"),
+			NULL,
+			GUC_DISALLOW_IN_AUTO_FILE
+		},
+		&EnableAlterSystem,
+		true,
+		NULL, NULL, NULL
+	},
 	{
 		{"bonjour", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
 			gettext_noop("Enables advertising the server via Bonjour."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 2244ee52f79..63fd71fdd21 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -128,6 +128,11 @@
 #ssl_passphrase_command = ''
 #ssl_passphrase_command_supports_reload = off
 
+#------------------------------------------------------------------------------
+# USAGE RESTRICTIONS
+#------------------------------------------------------------------------------
+
+#enable_alter_system = on
 
 #------------------------------------------------------------------------------
 # RESOURCE USAGE (except WAL)
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 0a2e274ebb2..6fa6a69df50 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -60,6 +60,7 @@ enum config_group
 	CONN_AUTH_TCP,
 	CONN_AUTH_AUTH,
 	CONN_AUTH_SSL,
+	USAGE_RESTRICTIONS,
 	RESOURCES_MEM,
 	RESOURCES_DISK,
 	RESOURCES_KERNEL,
@@ -320,4 +321,7 @@ extern char *config_enum_get_options(struct config_enum *record,
 									 const char *suffix,
 									 const char *separator);
 
+/* GUC reference to enable/disable alter system */
+extern PGDLLIMPORT bool EnableAlterSystem;
+
 #endif							/* GUC_TABLES_H */
diff --git a/src/test/regress/expected/sysviews.out b/src/test/regress/expected/sysviews.out
index 9be7aca2b8a..a4aa012b36f 100644
--- a/src/test/regress/expected/sysviews.out
+++ b/src/test/regress/expected/sysviews.out
@@ -111,6 +111,7 @@ select count(*) = 0 as ok from pg_stat_wal_receiver;
 select name, setting from pg_settings where name like 'enable%';
               name              | setting 
 --------------------------------+---------
+ enable_alter_system            | on
  enable_async_append            | on
  enable_bitmapscan              | on
  enable_gathermerge             | on
@@ -134,7 +135,7 @@ select name, setting from pg_settings where name like 'enable%';
  enable_seqscan                 | on
  enable_sort                    | on
  enable_tidscan                 | on
-(23 rows)
+(24 rows)
 
 -- There are always wait event descriptions for various types.
 select type, count(*) > 0 as ok FROM pg_wait_events

base-commit: 84c18acaf690e438e953e387caf1c13298d4ecb4
-- 
2.34.1

