From 9e83d73b6cf1e4280d438fb172b8b9c9233a656b Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 22 Oct 2004 19:48:19 +0000 Subject: [PATCH] Add a GUC_SUPERUSER_ONLY flag to mark GUC variables that should not be examinable by non-superusers, and use it to protect the recently-added GUC variables for data directory and config files. For now I have only flagged those variables that could be used to deduce something about the server's filesystem layout, but possibly we should also mark vars related to logging settings and other admin-only information? --- src/backend/utils/misc/guc.c | 68 ++++++++++++++++++++++++---------- src/include/utils/guc.h | 4 +- src/include/utils/guc_tables.h | 6 +-- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 5b5a2a309f..366ef77cf6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.245 2004/10/17 22:01:51 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.246 2004/10/22 19:48:19 tgl Exp $ * *-------------------------------------------------------------------- */ @@ -1522,7 +1522,8 @@ static struct config_string ConfigureNamesString[] = gettext_noop("If a dynamically loadable module needs to be opened and " "the specified name does not have a directory component (i.e., the " "name does not contain a slash), the system will search this path for " - "the specified file.") + "the specified file."), + GUC_SUPERUSER_ONLY }, &Dynamic_library_path, "$libdir", NULL, NULL @@ -1531,7 +1532,8 @@ static struct config_string ConfigureNamesString[] = { {"krb_server_keyfile", PGC_POSTMASTER, CONN_AUTH_SECURITY, gettext_noop("Sets the location of the Kerberos server key file."), - NULL + NULL, + GUC_SUPERUSER_ONLY }, &pg_krb_server_keyfile, PG_KRB_SRVTAB, NULL, NULL @@ -1608,7 +1610,7 @@ static struct config_string ConfigureNamesString[] = {"preload_libraries", PGC_POSTMASTER, RESOURCES_KERNEL, gettext_noop("Lists shared libraries to preload into server."), NULL, - GUC_LIST_INPUT | GUC_LIST_QUOTE + GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY }, &preload_libraries_string, "", NULL, NULL @@ -1680,7 +1682,8 @@ static struct config_string ConfigureNamesString[] = {"log_directory", PGC_SIGHUP, LOGGING_WHERE, gettext_noop("Sets the destination directory for log files."), gettext_noop("May be specified as relative to the data directory " - "or as absolute path.") + "or as absolute path."), + GUC_SUPERUSER_ONLY }, &Log_directory, "pg_log", assign_canonical_path, NULL @@ -1688,7 +1691,8 @@ static struct config_string ConfigureNamesString[] = { {"log_filename", PGC_SIGHUP, LOGGING_WHERE, gettext_noop("Sets the file name pattern for log files."), - NULL + NULL, + GUC_SUPERUSER_ONLY }, &Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log", NULL, NULL @@ -1747,7 +1751,8 @@ static struct config_string ConfigureNamesString[] = { {"unix_socket_directory", PGC_POSTMASTER, CONN_AUTH_SETTINGS, gettext_noop("Sets the directory where the Unix-domain socket will be created."), - NULL + NULL, + GUC_SUPERUSER_ONLY }, &UnixSocketDir, "", assign_canonical_path, NULL @@ -1774,7 +1779,7 @@ static struct config_string ConfigureNamesString[] = { {"custom_variable_classes", PGC_POSTMASTER, RESOURCES_KERNEL, - gettext_noop("Sets the list of known custom variable classes"), + gettext_noop("Sets the list of known custom variable classes."), NULL, GUC_LIST_INPUT | GUC_LIST_QUOTE }, @@ -1785,7 +1790,8 @@ static struct config_string ConfigureNamesString[] = { {"data_directory", PGC_POSTMASTER, FILE_LOCATIONS, gettext_noop("Sets the server's data directory."), - NULL + NULL, + GUC_SUPERUSER_ONLY }, &data_directory, NULL, NULL, NULL @@ -1795,7 +1801,7 @@ static struct config_string ConfigureNamesString[] = {"config_file", PGC_POSTMASTER, FILE_LOCATIONS, gettext_noop("Sets the server's main configuration file."), NULL, - GUC_DISALLOW_IN_FILE + GUC_DISALLOW_IN_FILE | GUC_SUPERUSER_ONLY }, &ConfigFileName, NULL, NULL, NULL @@ -1804,7 +1810,8 @@ static struct config_string ConfigureNamesString[] = { {"hba_file", PGC_POSTMASTER, FILE_LOCATIONS, gettext_noop("Sets the server's \"hba\" configuration file"), - NULL + NULL, + GUC_SUPERUSER_ONLY }, &HbaFileName, NULL, NULL, NULL @@ -1813,7 +1820,8 @@ static struct config_string ConfigureNamesString[] = { {"ident_file", PGC_POSTMASTER, FILE_LOCATIONS, gettext_noop("Sets the server's \"ident\" configuration file"), - NULL + NULL, + GUC_SUPERUSER_ONLY }, &IdentFileName, NULL, NULL, NULL @@ -1822,7 +1830,8 @@ static struct config_string ConfigureNamesString[] = { {"external_pid_file", PGC_POSTMASTER, FILE_LOCATIONS, gettext_noop("Writes the postmaster PID to the specified file."), - NULL + NULL, + GUC_SUPERUSER_ONLY }, &external_pid_file, NULL, assign_canonical_path, NULL @@ -1874,6 +1883,8 @@ static int guc_var_compare(const void *a, const void *b); static int guc_name_compare(const char *namea, const char *nameb); static void push_old_value(struct config_generic * gconf); static void ReportGUCOption(struct config_generic * record); +static void ShowGUCConfigOption(const char *name, DestReceiver *dest); +static void ShowAllGUCConfig(DestReceiver *dest); static char *_ShowOption(struct config_generic * record); static bool check_userlimit_privilege(struct config_generic *record, GucSource source, int elevel); @@ -3966,6 +3977,10 @@ GetConfigOption(const char *name) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("unrecognized configuration parameter \"%s\"", name))); + if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to examine \"%s\"", name))); switch (record->vartype) { @@ -4002,6 +4017,10 @@ GetConfigOptionResetString(const char *name) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("unrecognized configuration parameter \"%s\"", name))); + if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to examine \"%s\"", name))); switch (record->vartype) { @@ -4268,8 +4287,7 @@ define_custom_variable(struct config_generic * variable) } static void -init_custom_variable( - struct config_generic * gen, +init_custom_variable(struct config_generic * gen, const char *name, const char *short_desc, const char *long_desc, @@ -4462,7 +4480,7 @@ ResetPGVariable(const char *name) /* * SHOW command */ -void +static void ShowGUCConfigOption(const char *name, DestReceiver *dest) { TupOutputState *tstate; @@ -4490,9 +4508,10 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest) /* * SHOW ALL command */ -void +static void ShowAllGUCConfig(DestReceiver *dest) { + bool am_superuser = superuser(); int i; TupOutputState *tstate; TupleDesc tupdesc; @@ -4512,7 +4531,8 @@ ShowAllGUCConfig(DestReceiver *dest) { struct config_generic *conf = guc_variables[i]; - if (conf->flags & GUC_NO_SHOW_ALL) + if ((conf->flags & GUC_NO_SHOW_ALL) || + ((conf->flags & GUC_SUPERUSER_ONLY) && !am_superuser)) continue; /* assign to the values array */ @@ -4544,6 +4564,10 @@ GetConfigOptionByName(const char *name, const char **varname) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("unrecognized configuration parameter \"%s\"", name))); + if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to examine \"%s\"", name))); if (varname) *varname = record->name; @@ -4567,7 +4591,13 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) conf = guc_variables[varnum]; if (noshow) - *noshow = (conf->flags & GUC_NO_SHOW_ALL) ? true : false; + { + if ((conf->flags & GUC_NO_SHOW_ALL) || + ((conf->flags & GUC_SUPERUSER_ONLY) && !superuser())) + *noshow = true; + else + *noshow = false; + } /* first get the generic attributes */ diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 38eba48aae..0559264dd1 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -7,7 +7,7 @@ * Copyright (c) 2000-2004, PostgreSQL Global Development Group * Written by Peter Eisentraut . * - * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.53 2004/10/09 23:13:22 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.54 2004/10/22 19:48:19 tgl Exp $ *-------------------------------------------------------------------- */ #ifndef GUC_H @@ -194,8 +194,6 @@ extern void ParseLongOption(const char *string, char **name, char **value); extern bool set_config_option(const char *name, const char *value, GucContext context, GucSource source, bool isLocal, bool changeVal); -extern void ShowGUCConfigOption(const char *name, DestReceiver *dest); -extern void ShowAllGUCConfig(DestReceiver *dest); extern char *GetConfigOptionByName(const char *name, const char **varname); extern void GetConfigOptionByNum(int varnum, const char **values, bool *noshow); extern int GetNumConfigOptions(void); diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h index 718fac30cb..f22bb9a781 100644 --- a/src/include/utils/guc_tables.h +++ b/src/include/utils/guc_tables.h @@ -7,7 +7,7 @@ * * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.17 2004/10/08 01:36:36 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.18 2004/10/22 19:48:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -123,8 +123,8 @@ struct config_generic #define GUC_REPORT 0x0010 /* auto-report changes to client */ #define GUC_NOT_IN_SAMPLE 0x0020 /* not in postgresql.conf.sample */ #define GUC_DISALLOW_IN_FILE 0x0040 /* can't set in postgresql.conf */ -#define GUC_CUSTOM_PLACEHOLDER 0x0080 /* placeholder for a custom - * variable */ +#define GUC_CUSTOM_PLACEHOLDER 0x0080 /* placeholder for custom variable */ +#define GUC_SUPERUSER_ONLY 0x0100 /* show only to superusers */ /* bit values in status field */ #define GUC_HAVE_TENTATIVE 0x0001 /* tentative value is defined */