diff options
author | Bruce Momjian <bruce@momjian.us> | 2003-07-09 06:47:34 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 2003-07-09 06:47:34 +0000 |
commit | bf889e649acf5286e588ad824e3a6bb804cd59d1 (patch) | |
tree | a88dcb5dc949510f6f9f8d746c34a407e5d29466 /src | |
parent | 6896bfa86c179dccd7091dc439dceb541fc98116 (diff) | |
download | postgresql-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.c | 66 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 117 | ||||
-rw-r--r-- | src/include/utils/guc.h | 21 |
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; |