aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2003-07-09 06:47:34 +0000
committerBruce Momjian <bruce@momjian.us>2003-07-09 06:47:34 +0000
commitbf889e649acf5286e588ad824e3a6bb804cd59d1 (patch)
treea88dcb5dc949510f6f9f8d746c34a407e5d29466 /src
parent6896bfa86c179dccd7091dc439dceb541fc98116 (diff)
downloadpostgresql-bf889e649acf5286e588ad824e3a6bb804cd59d1.tar.gz
postgresql-bf889e649acf5286e588ad824e3a6bb804cd59d1.zip
Add new USERLIMIT GUC source level so certain options can be disabled
or increased only by super-users. This fixes problems caused by making certain variables SUSET for security reasons.
Diffstat (limited to 'src')
-rw-r--r--src/backend/tcop/postgres.c66
-rw-r--r--src/backend/utils/misc/guc.c117
-rw-r--r--src/include/utils/guc.h21
3 files changed, 158 insertions, 46 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index c3480d803cf..f0c2254edd8 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.349 2003/07/04 16:41:21 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.350 2003/07/09 06:47:34 momjian Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -1943,7 +1943,7 @@ PostgresMain(int argc, char *argv[], const char *username)
bool secure;
int errs = 0;
int debug_flag = 0;
- GucContext ctx;
+ GucContext ctx, debug_context;
GucSource gucsource;
char *tmp;
int firstchar;
@@ -2018,7 +2018,7 @@ PostgresMain(int argc, char *argv[], const char *username)
/* all options are allowed until '-p' */
secure = true;
- ctx = PGC_POSTMASTER;
+ ctx = debug_context = PGC_POSTMASTER;
gucsource = PGC_S_ARGV; /* initial switches came from command line */
while ((flag = getopt(argc, argv, "A:B:c:CD:d:Eef:FiNOPo:p:S:st:v:W:x:-:")) != -1)
@@ -2055,25 +2055,34 @@ PostgresMain(int argc, char *argv[], const char *username)
case 'd': /* debug level */
{
- debug_flag = atoi(optarg);
- /* Set server debugging level. */
- if (atoi(optarg) != 0)
+ /*
+ * Client option can't decrease debug level.
+ * We have to do the test here because we group priv and client
+ * set GUC calls below, after we know the final debug value.
+ */
+ if (ctx != PGC_BACKEND || atoi(optarg) > debug_flag)
{
- char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
-
- sprintf(debugstr, "debug%s", optarg);
- SetConfigOption("log_min_messages", debugstr, ctx, gucsource);
- pfree(debugstr);
-
+ debug_flag = atoi(optarg);
+ debug_context = ctx; /* save context for use below */
+ /* Set server debugging level. */
+ if (debug_flag != 0)
+ {
+ char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
+
+ sprintf(debugstr, "debug%s", optarg);
+ SetConfigOption("log_min_messages", debugstr, ctx, gucsource);
+ pfree(debugstr);
+
+ }
+ else
+ /*
+ * -d0 allows user to prevent postmaster debug
+ * from propagating to backend. It would be nice
+ * to set it to the postgresql.conf value here.
+ */
+ SetConfigOption("log_min_messages", "notice",
+ ctx, gucsource);
}
- else
- /*
- * -d0 allows user to prevent postmaster debug
- * from propagating to backend. It would be nice
- * to set it to the postgresql.conf value here.
- */
- SetConfigOption("log_min_messages", "notice",
- ctx, gucsource);
}
break;
@@ -2323,20 +2332,19 @@ PostgresMain(int argc, char *argv[], const char *username)
/*
- * -d is not the same as setting
- * log_min_messages because it enables other
- * output options.
+ * -d is not the same as setting log_min_messages because it enables
+ * other output options.
*/
if (debug_flag >= 1)
- SetConfigOption("log_connections", "true", ctx, gucsource);
+ SetConfigOption("log_connections", "true", debug_context, gucsource);
if (debug_flag >= 2)
- SetConfigOption("log_statement", "true", ctx, gucsource);
+ SetConfigOption("log_statement", "true", debug_context, gucsource);
if (debug_flag >= 3)
- SetConfigOption("debug_print_parse", "true", ctx, gucsource);
+ SetConfigOption("debug_print_parse", "true", debug_context, gucsource);
if (debug_flag >= 4)
- SetConfigOption("debug_print_plan", "true", ctx, gucsource);
+ SetConfigOption("debug_print_plan", "true", debug_context, gucsource);
if (debug_flag >= 5)
- SetConfigOption("debug_print_rewritten", "true", ctx, gucsource);
+ SetConfigOption("debug_print_rewritten", "true", debug_context, gucsource);
/*
* Process any additional GUC variable settings passed in startup packet.
@@ -2548,7 +2556,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.349 $ $Date: 2003/07/04 16:41:21 $\n");
+ puts("$Revision: 1.350 $ $Date: 2003/07/09 06:47:34 $\n");
}
/*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index fc626169ec0..11815b8c137 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.134 2003/07/04 16:41:21 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.135 2003/07/09 06:47:34 momjian Exp $
*
*--------------------------------------------------------------------
*/
@@ -449,7 +449,7 @@ static struct config_bool ConfigureNamesBool[] =
false, NULL, NULL
},
{
- {"log_statement", PGC_SUSET, LOGGING_WHAT,
+ {"log_statement", PGC_USERLIMIT, LOGGING_WHAT,
gettext_noop("Causes each SQL statement to be logged"),
NULL
},
@@ -457,7 +457,7 @@ static struct config_bool ConfigureNamesBool[] =
false, NULL, NULL
},
{
- {"log_duration", PGC_SUSET, LOGGING_WHAT,
+ {"log_duration", PGC_USERLIMIT, LOGGING_WHAT,
gettext_noop("Duration of every completed statement is logged"),
NULL
},
@@ -497,7 +497,7 @@ static struct config_bool ConfigureNamesBool[] =
false, NULL, NULL
},
{
- {"log_parser_stats", PGC_SUSET, STATS_MONITORING,
+ {"log_parser_stats", PGC_USERLIMIT, STATS_MONITORING,
gettext_noop("Write parser performance stats to server log"),
NULL
},
@@ -505,7 +505,7 @@ static struct config_bool ConfigureNamesBool[] =
false, NULL, NULL
},
{
- {"log_planner_stats", PGC_SUSET, STATS_MONITORING,
+ {"log_planner_stats", PGC_USERLIMIT, STATS_MONITORING,
gettext_noop("Write planner performance stats to server log"),
NULL
},
@@ -513,7 +513,7 @@ static struct config_bool ConfigureNamesBool[] =
false, NULL, NULL
},
{
- {"log_executor_stats", PGC_SUSET, STATS_MONITORING,
+ {"log_executor_stats", PGC_USERLIMIT, STATS_MONITORING,
gettext_noop("Write executor performance stats to server log"),
NULL
},
@@ -521,7 +521,7 @@ static struct config_bool ConfigureNamesBool[] =
false, NULL, NULL
},
{
- {"log_statement_stats", PGC_SUSET, STATS_MONITORING,
+ {"log_statement_stats", PGC_USERLIMIT, STATS_MONITORING,
gettext_noop("Write statement performance stats to server log"),
NULL
},
@@ -1107,7 +1107,7 @@ static struct config_int ConfigureNamesInt[] =
},
{
- {"log_min_duration_statement", PGC_SUSET, LOGGING_WHEN,
+ {"log_min_duration_statement", PGC_USERLIMIT, LOGGING_WHEN,
gettext_noop("Min execution time (msec) above which statements will "
"be logged"),
gettext_noop("The default is 0 (turning this feature off).")
@@ -1228,7 +1228,7 @@ static struct config_string ConfigureNamesString[] =
},
{
- {"log_min_messages", PGC_SUSET, LOGGING_WHEN,
+ {"log_min_messages", PGC_USERLIMIT, LOGGING_WHEN,
gettext_noop("Controls which message levels logged"),
gettext_noop("Valid values are DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, "
"INFO, NOTICE, WARNING, ERROR, LOG, FATAL, and PANIC. Each level "
@@ -1248,7 +1248,7 @@ static struct config_string ConfigureNamesString[] =
},
{
- {"log_min_error_statement", PGC_SUSET, LOGGING_WHEN,
+ {"log_min_error_statement", PGC_USERLIMIT, LOGGING_WHEN,
gettext_noop("Controls whether the erroneous statement is logged"),
gettext_noop("All SQL statements that cause an error of the "
"specified level, or a higher level, are logged")
@@ -1714,6 +1714,9 @@ InitializeGUCOptions(void)
Assert(conf->reset_val >= conf->min);
Assert(conf->reset_val <= conf->max);
+ /* Check to make sure we only have valid PGC_USERLIMITs */
+ Assert(conf->gen.context != PGC_USERLIMIT ||
+ strcmp(conf->gen.name, "log_min_duration_statement") == 0);
if (conf->assign_hook)
if (!(*conf->assign_hook) (conf->reset_val, true, false))
fprintf(stderr, "Failed to initialize %s to %d\n",
@@ -1728,6 +1731,7 @@ InitializeGUCOptions(void)
Assert(conf->reset_val >= conf->min);
Assert(conf->reset_val <= conf->max);
+ Assert(conf->gen.context != PGC_USERLIMIT);
if (conf->assign_hook)
if (!(*conf->assign_hook) (conf->reset_val, true, false))
fprintf(stderr, "Failed to initialize %s to %g\n",
@@ -1741,6 +1745,11 @@ InitializeGUCOptions(void)
struct config_string *conf = (struct config_string *) gconf;
char *str;
+ /* Check to make sure we only have valid PGC_USERLIMITs */
+ Assert(conf->gen.context != PGC_USERLIMIT ||
+ conf->assign_hook == assign_log_min_messages ||
+ conf->assign_hook == assign_client_min_messages ||
+ conf->assign_hook == assign_min_error_statement);
*conf->variable = NULL;
conf->reset_val = NULL;
conf->session_val = NULL;
@@ -1837,7 +1846,9 @@ ResetAllOptions(void)
struct config_generic *gconf = guc_variables[i];
/* Don't reset non-SET-able values */
- if (gconf->context != PGC_SUSET && gconf->context != PGC_USERSET)
+ if (gconf->context != PGC_SUSET &&
+ gconf->context != PGC_USERLIMIT &&
+ gconf->context != PGC_USERSET)
continue;
/* Don't reset if special exclusion from RESET ALL */
if (gconf->flags & GUC_NO_RESET_ALL)
@@ -2286,6 +2297,7 @@ set_config_option(const char *name, const char *value,
int elevel;
bool interactive;
bool makeDefault;
+ bool DoIt_orig;
if (context == PGC_SIGHUP || source == PGC_S_DEFAULT)
elevel = DEBUG2;
@@ -2371,6 +2383,7 @@ set_config_option(const char *name, const char *value,
return false;
}
break;
+ case PGC_USERLIMIT: /* USERLIMIT permissions checked below */
case PGC_USERSET:
/* always okay */
break;
@@ -2393,6 +2406,7 @@ set_config_option(const char *name, const char *value,
* to set the reset/session values even if we can't set the variable
* itself.
*/
+ DoIt_orig = DoIt; /* we might have to reverse this later */
if (record->source > source)
{
if (DoIt && !makeDefault)
@@ -2422,6 +2436,24 @@ set_config_option(const char *name, const char *value,
name);
return false;
}
+ /* Limit non-super user changes */
+ if (record->context == PGC_USERLIMIT &&
+ source > PGC_S_USERSTART &&
+ newval < conf->session_val &&
+ !superuser())
+ {
+ elog(elevel, "'%s': permission denied\n"
+ "Only super-users can set this value to false.",
+ name);
+ return false;
+ }
+ /* Allow admin to override non-super user setting */
+ if (record->context == PGC_USERLIMIT &&
+ source < PGC_S_USERSTART &&
+ record->session_source > PGC_S_USERSTART &&
+ newval > conf->session_val &&
+ !superuser())
+ DoIt = DoIt_orig;
}
else
{
@@ -2493,6 +2525,25 @@ set_config_option(const char *name, const char *value,
name, newval, conf->min, conf->max);
return false;
}
+ /* Limit non-super user changes */
+ if (record->context == PGC_USERLIMIT &&
+ source > PGC_S_USERSTART &&
+ conf->session_val != 0 &&
+ newval > conf->session_val &&
+ !superuser())
+ {
+ elog(elevel, "'%s': permission denied\n"
+ "Only super-users can increase this value.",
+ name);
+ return false;
+ }
+ /* Allow admin to override non-super user setting */
+ if (record->context == PGC_USERLIMIT &&
+ source < PGC_S_USERSTART &&
+ record->session_source > PGC_S_USERSTART &&
+ newval < conf->session_val &&
+ !superuser())
+ DoIt = DoIt_orig;
}
else
{
@@ -2564,6 +2615,24 @@ set_config_option(const char *name, const char *value,
name, newval, conf->min, conf->max);
return false;
}
+ /* Limit non-super user changes */
+ if (record->context == PGC_USERLIMIT &&
+ source > PGC_S_USERSTART &&
+ newval > conf->session_val &&
+ !superuser())
+ {
+ elog(elevel, "'%s': permission denied\n"
+ "Only super-users can increase this value.",
+ name);
+ return false;
+ }
+ /* Allow admin to override non-super user setting */
+ if (record->context == PGC_USERLIMIT &&
+ source < PGC_S_USERSTART &&
+ record->session_source > PGC_S_USERSTART &&
+ newval < conf->session_val &&
+ !superuser())
+ DoIt = DoIt_orig;
}
else
{
@@ -2628,6 +2697,32 @@ set_config_option(const char *name, const char *value,
elog(elevel, "out of memory");
return false;
}
+
+ if (*conf->variable)
+ {
+ int old_int_value, new_int_value;
+
+ /* Limit non-super user changes */
+ assign_msglvl(&old_int_value, conf->reset_val, true, interactive);
+ assign_msglvl(&new_int_value, newval, true, interactive);
+ if (record->context == PGC_USERLIMIT &&
+ source > PGC_S_USERSTART &&
+ new_int_value > old_int_value &&
+ !superuser())
+ {
+ elog(elevel, "'%s': permission denied\n"
+ "Only super-users can increase this value.",
+ name);
+ return false;
+ }
+ /* Allow admin to override non-super user setting */
+ if (record->context == PGC_USERLIMIT &&
+ source < PGC_S_USERSTART &&
+ record->session_source > PGC_S_USERSTART &&
+ newval < conf->session_val &&
+ !superuser())
+ DoIt = DoIt_orig;
+ }
}
else if (conf->reset_val)
{
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 2926f0a4134..29669fc7c46 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -7,7 +7,7 @@
* Copyright 2000-2003 by PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
- * $Id: guc.h,v 1.32 2003/06/11 18:01:14 momjian Exp $
+ * $Id: guc.h,v 1.33 2003/07/09 06:47:34 momjian Exp $
*--------------------------------------------------------------------
*/
#ifndef GUC_H
@@ -48,6 +48,9 @@
* be set in the connection startup packet, because when it is processed
* we don't yet know if the user is a superuser.
*
+ * USERLIMIT options can only be manipulated in certain ways by
+ * non-super users.
+ *
* USERSET options can be set by anyone any time.
*/
typedef enum
@@ -57,6 +60,7 @@ typedef enum
PGC_SIGHUP,
PGC_BACKEND,
PGC_SUSET,
+ PGC_USERLIMIT,
PGC_USERSET
} GucContext;
@@ -76,11 +80,16 @@ typedef enum
PGC_S_ENV_VAR = 1, /* postmaster environment variable */
PGC_S_FILE = 2, /* postgresql.conf */
PGC_S_ARGV = 3, /* postmaster command line */
- PGC_S_DATABASE = 4, /* per-database setting */
- PGC_S_USER = 5, /* per-user setting */
- PGC_S_CLIENT = 6, /* from client connection request */
- PGC_S_OVERRIDE = 7, /* special case to forcibly set default */
- PGC_S_SESSION = 8 /* SET command */
+ PGC_S_USERSTART=4, /*
+ * Settings below are controlled by users.
+ * This is used by PGC_USERLIMT to prevent
+ * non-super users from changing certain settings.
+ */
+ PGC_S_DATABASE = 5, /* per-database setting */
+ PGC_S_USER = 6, /* per-user setting */
+ PGC_S_CLIENT = 7, /* from client connection request */
+ PGC_S_OVERRIDE = 8, /* special case to forcibly set default */
+ PGC_S_SESSION = 9 /* SET command */
} GucSource;