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;