diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 74110f0772..5be8fdcc25 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -4345,8 +4345,9 @@ local0.* /var/log/postgresql
Causes each attempted connection to the server to be logged,
as well as successful completion of client authentication.
- This parameter cannot be changed after session start.
- The default is off.
+ Only superusers can change this parameter at session start,
+ and it cannot be changed at all within a session.
+ The default is off>.
@@ -4368,11 +4369,12 @@ local0.* /var/log/postgresql
- This outputs a line in the server log similar to
- log_connections but at session termination,
- and includes the duration of the session. This is off by
- default.
- This parameter cannot be changed after session start.
+ Causes session terminations to be logged. The log output
+ provides information similar to log_connections,
+ plus the duration of the session.
+ Only superusers can change this parameter at session start,
+ and it cannot be changed at all within a session.
+ The default is off>.
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 7b5480faf8..61f17bf1e9 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -3258,7 +3258,7 @@ get_stats_option_name(const char *arg)
* argv[0] is ignored in either case (it's assumed to be the program name).
*
* ctx is PGC_POSTMASTER for secure options, PGC_BACKEND for insecure options
- * coming from the client, or PGC_SUSET for insecure options coming from
+ * coming from the client, or PGC_SU_BACKEND for insecure options coming from
* a superuser client.
*
* If a database name is present in the command line arguments, it's
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index f5a6a67134..6a6a4453cd 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -425,7 +425,7 @@ pg_split_opts(char **argv, int *argcp, char *optstr)
while (*optstr)
{
- bool last_was_escape = false;
+ bool last_was_escape = false;
resetStringInfo(&s);
@@ -982,7 +982,7 @@ process_startup_options(Port *port, bool am_superuser)
GucContext gucctx;
ListCell *gucopts;
- gucctx = am_superuser ? PGC_SUSET : PGC_BACKEND;
+ gucctx = am_superuser ? PGC_SU_BACKEND : PGC_BACKEND;
/*
* First process any command-line switches that were included in the
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0192def17a..b87bfb3ff0 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -493,7 +493,7 @@ static bool data_checksums;
static int wal_segment_size;
static bool integer_datetimes;
static int effective_io_concurrency;
-static bool assert_enabled;
+static bool assert_enabled;
/* should be static, but commands/variable.c needs to get at this */
char *role_string;
@@ -509,6 +509,7 @@ const char *const GucContext_Names[] =
/* PGC_INTERNAL */ "internal",
/* PGC_POSTMASTER */ "postmaster",
/* PGC_SIGHUP */ "sighup",
+ /* PGC_SU_BACKEND */ "superuser-backend",
/* PGC_BACKEND */ "backend",
/* PGC_SUSET */ "superuser",
/* PGC_USERSET */ "user"
@@ -907,7 +908,7 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL
},
{
- {"log_connections", PGC_BACKEND, LOGGING_WHAT,
+ {"log_connections", PGC_SU_BACKEND, LOGGING_WHAT,
gettext_noop("Logs each successful connection."),
NULL
},
@@ -916,7 +917,7 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL
},
{
- {"log_disconnections", PGC_BACKEND, LOGGING_WHAT,
+ {"log_disconnections", PGC_SU_BACKEND, LOGGING_WHAT,
gettext_noop("Logs end of a session, including duration."),
NULL
},
@@ -4389,10 +4390,10 @@ SelectConfigFiles(const char *userDoption, const char *progname)
SetConfigOption("data_directory", DataDir, PGC_POSTMASTER, PGC_S_OVERRIDE);
/*
- * Now read the config file a second time, allowing any settings in
- * the PG_AUTOCONF_FILENAME file to take effect. (This is pretty ugly,
- * but since we have to determine the DataDir before we can find the
- * autoconf file, the alternatives seem worse.)
+ * Now read the config file a second time, allowing any settings in the
+ * PG_AUTOCONF_FILENAME file to take effect. (This is pretty ugly, but
+ * since we have to determine the DataDir before we can find the autoconf
+ * file, the alternatives seem worse.)
*/
ProcessConfigFile(PGC_POSTMASTER);
@@ -5694,16 +5695,27 @@ set_config_option(const char *name, const char *value,
* signals to individual backends only.
*/
break;
+ case PGC_SU_BACKEND:
+ /* Reject if we're connecting but user is not superuser */
+ if (context == PGC_BACKEND)
+ {
+ ereport(elevel,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to set parameter \"%s\"",
+ name)));
+ return 0;
+ }
+ /* FALL THRU to process the same as PGC_BACKEND */
case PGC_BACKEND:
if (context == PGC_SIGHUP)
{
/*
- * If a PGC_BACKEND parameter is changed in the config file,
- * we want to accept the new value in the postmaster (whence
- * it will propagate to subsequently-started backends), but
- * ignore it in existing backends. This is a tad klugy, but
- * necessary because we don't re-read the config file during
- * backend start.
+ * If a PGC_BACKEND or PGC_SU_BACKEND parameter is changed in
+ * the config file, we want to accept the new value in the
+ * postmaster (whence it will propagate to
+ * subsequently-started backends), but ignore it in existing
+ * backends. This is a tad klugy, but necessary because we
+ * don't re-read the config file during backend start.
*
* In EXEC_BACKEND builds, this works differently: we load all
* nondefault settings from the CONFIG_EXEC_PARAMS file during
@@ -5722,7 +5734,9 @@ set_config_option(const char *name, const char *value,
return -1;
#endif
}
- else if (context != PGC_POSTMASTER && context != PGC_BACKEND &&
+ else if (context != PGC_POSTMASTER &&
+ context != PGC_BACKEND &&
+ context != PGC_SU_BACKEND &&
source != PGC_S_CLIENT)
{
ereport(elevel,
@@ -6771,7 +6785,8 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
if (record == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\"", name)));
+ errmsg("unrecognized configuration parameter \"%s\"",
+ name)));
/*
* Don't allow the parameters which can't be set in configuration
@@ -6780,16 +6795,17 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
if ((record->context == PGC_INTERNAL) ||
(record->flags & GUC_DISALLOW_IN_FILE) ||
(record->flags & GUC_DISALLOW_IN_AUTO_FILE))
- ereport(ERROR,
- (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
- errmsg("parameter \"%s\" cannot be changed",
- name)));
+ ereport(ERROR,
+ (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
+ errmsg("parameter \"%s\" cannot be changed",
+ name)));
if (!validate_conf_option(record, name, value, PGC_S_FILE,
ERROR, true, NULL,
&newextra))
ereport(ERROR,
- (errmsg("invalid value for parameter \"%s\": \"%s\"", name, value)));
+ (errmsg("invalid value for parameter \"%s\": \"%s\"",
+ name, value)));
}
@@ -6817,7 +6833,7 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
if (Tmpfd < 0)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("failed to open auto conf temp file \"%s\": %m ",
+ errmsg("failed to open auto conf temp file \"%s\": %m",
AutoConfTmpFileName)));
PG_TRY();
@@ -6835,8 +6851,8 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
infile = AllocateFile(AutoConfFileName, "r");
if (infile == NULL)
ereport(ERROR,
- (errmsg("failed to open auto conf file \"%s\": %m ",
- AutoConfFileName)));
+ (errmsg("failed to open auto conf file \"%s\": %m",
+ AutoConfFileName)));
/* parse it */
ParseConfigFp(infile, AutoConfFileName, 0, LOG, &head, &tail);
@@ -8388,8 +8404,8 @@ read_nondefault_variables(void)
GucContext varscontext;
/*
- * Assert that PGC_BACKEND case in set_config_option() will do the right
- * thing.
+ * Assert that PGC_BACKEND/PGC_SU_BACKEND case in set_config_option() will
+ * do the right thing.
*/
Assert(IsInitProcessingMode());
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 0a729c1190..66b5cd36c5 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -36,15 +36,17 @@
* certain point in their main loop. It's safer to wait than to read a
* file asynchronously.)
*
- * BACKEND options can only be set at postmaster startup, from the
- * configuration file, or by client request in the connection startup
- * packet (e.g., from libpq's PGOPTIONS variable). Furthermore, an
- * already-started backend will ignore changes to such an option in the
- * configuration file. The idea is that these options are fixed for a
- * given backend once it's started, but they can vary across backends.
+ * BACKEND and SU_BACKEND options can only be set at postmaster startup,
+ * from the configuration file, or by client request in the connection
+ * startup packet (e.g., from libpq's PGOPTIONS variable). SU_BACKEND
+ * options can be set from the startup packet only when the user is a
+ * superuser. Furthermore, an already-started backend will ignore changes
+ * to such an option in the configuration file. The idea is that these
+ * options are fixed for a given backend once it's started, but they can
+ * vary across backends.
*
* SUSET options can be set at postmaster startup, with the SIGHUP
- * mechanism, or from SQL if you're a superuser.
+ * mechanism, or from the startup packet or SQL if you're a superuser.
*
* USERSET options can be set by anyone any time.
*/
@@ -53,6 +55,7 @@ typedef enum
PGC_INTERNAL,
PGC_POSTMASTER,
PGC_SIGHUP,
+ PGC_SU_BACKEND,
PGC_BACKEND,
PGC_SUSET,
PGC_USERSET
@@ -195,7 +198,8 @@ typedef enum
#define GUC_UNIT_TIME 0x7000 /* mask for MS, S, MIN */
#define GUC_NOT_WHILE_SEC_REST 0x8000 /* can't set if security restricted */
-#define GUC_DISALLOW_IN_AUTO_FILE 0x00010000 /* can't set in PG_AUTOCONF_FILENAME */
+#define GUC_DISALLOW_IN_AUTO_FILE 0x00010000 /* can't set in
+ * PG_AUTOCONF_FILENAME */
/* GUC vars that are actually declared in guc.c, rather than elsewhere */
extern bool log_duration;