Commit c32416eb authored by Tom Lane's avatar Tom Lane

Code review for various recent GUC hacking. Don't elog(ERROR) when

not supposed to (fixes problem with postmaster aborting due to mistaken
postgresql.conf change); don't call superuser() when not inside a
transaction (fixes coredump when, eg, try to set log_statement from
PGOPTIONS); some message style guidelines enforcement.
parent 617d6ea7
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.102 2004/08/30 02:54:38 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.103 2004/08/31 19:28:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -475,16 +475,23 @@ show_timezone(void) ...@@ -475,16 +475,23 @@ show_timezone(void)
const char * const char *
assign_XactIsoLevel(const char *value, bool doit, GucSource source) assign_XactIsoLevel(const char *value, bool doit, GucSource source)
{ {
if (doit && source >= PGC_S_INTERACTIVE)
{
if (SerializableSnapshot != NULL) if (SerializableSnapshot != NULL)
{
if (source >= PGC_S_INTERACTIVE)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query"))); errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query")));
else
return NULL;
}
if (IsSubTransaction()) if (IsSubTransaction())
{
if (source >= PGC_S_INTERACTIVE)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction"))); errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction")));
else
return NULL;
} }
if (strcmp(value, "serializable") == 0) if (strcmp(value, "serializable") == 0)
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>. * Written by Peter Eisentraut <peter_e@gmx.net>.
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.236 2004/08/31 04:53:44 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.237 2004/08/31 19:28:51 tgl Exp $
* *
*-------------------------------------------------------------------- *--------------------------------------------------------------------
*/ */
...@@ -1848,6 +1848,10 @@ static int guc_name_compare(const char *namea, const char *nameb); ...@@ -1848,6 +1848,10 @@ static int guc_name_compare(const char *namea, const char *nameb);
static void push_old_value(struct config_generic * gconf); static void push_old_value(struct config_generic * gconf);
static void ReportGUCOption(struct config_generic * record); static void ReportGUCOption(struct config_generic * record);
static char *_ShowOption(struct config_generic * record); static char *_ShowOption(struct config_generic * record);
static bool check_userlimit_privilege(struct config_generic *record,
GucSource source, int elevel);
static bool check_userlimit_override(struct config_generic *record,
GucSource source);
/* /*
...@@ -2034,7 +2038,7 @@ static bool ...@@ -2034,7 +2038,7 @@ static bool
is_custom_class(const char *name, int dotPos) is_custom_class(const char *name, int dotPos)
{ {
/* /*
* The assign_custom_variable_classes has made sure no empty * assign_custom_variable_classes() has made sure no empty
* identifiers or whitespace exists in the variable * identifiers or whitespace exists in the variable
*/ */
bool result = false; bool result = false;
...@@ -3233,22 +3237,14 @@ set_config_option(const char *name, const char *value, ...@@ -3233,22 +3237,14 @@ set_config_option(const char *name, const char *value,
if (newval < conf->reset_val) if (newval < conf->reset_val)
{ {
/* Limit non-superuser changes */ /* Limit non-superuser changes */
if (source > PGC_S_UNPRIVILEGED && !superuser()) if (!check_userlimit_privilege(record, source,
{ elevel))
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name),
errhint("must be superuser to change this value to false")));
return false; return false;
} }
}
if (newval > *conf->variable) if (newval > *conf->variable)
{ {
/* Allow change if admin should override */ /* Allow change if admin should override */
if (source < PGC_S_UNPRIVILEGED && if (check_userlimit_override(record, source))
record->source > PGC_S_UNPRIVILEGED &&
!superuser())
changeVal = changeValOrig; changeVal = changeValOrig;
} }
} }
...@@ -3338,30 +3334,25 @@ set_config_option(const char *name, const char *value, ...@@ -3338,30 +3334,25 @@ set_config_option(const char *name, const char *value,
} }
if (record->context == PGC_USERLIMIT) if (record->context == PGC_USERLIMIT)
{ {
/* handle log_min_duration_statement, -1=disable */ /*
if ((newval != -1 && conf->reset_val != -1 && * handle log_min_duration_statement: if it's enabled
newval > conf->reset_val) || /* increase duration */ * then either turning it off or increasing it
(newval == -1 && conf->reset_val != -1)) /* turn off */ * requires privileges.
*/
if (conf->reset_val != -1 &&
(newval == -1 || newval > conf->reset_val))
{ {
/* Limit non-superuser changes */ /* Limit non-superuser changes */
if (source > PGC_S_UNPRIVILEGED && !superuser()) if (!check_userlimit_privilege(record, source,
{ elevel))
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name),
errhint("Must be superuser to increase this value or turn it off.")));
return false; return false;
} }
} /* Admin override includes turning on or decreasing */
/* Allow change if admin should override */ if (newval != -1 &&
if ((newval != -1 && *conf->variable != -1 && (*conf->variable == -1 || newval < *conf->variable))
newval < *conf->variable) || /* decrease duration */
(newval != -1 && *conf->variable == -1)) /* turn on */
{ {
if (source < PGC_S_UNPRIVILEGED && /* Allow change if admin should override */
record->source > PGC_S_UNPRIVILEGED && if (check_userlimit_override(record, source))
!superuser())
changeVal = changeValOrig; changeVal = changeValOrig;
} }
} }
...@@ -3450,23 +3441,21 @@ set_config_option(const char *name, const char *value, ...@@ -3450,23 +3441,21 @@ set_config_option(const char *name, const char *value,
return false; return false;
} }
if (record->context == PGC_USERLIMIT) if (record->context == PGC_USERLIMIT)
/* No REAL PGC_USERLIMIT */
{ {
/* Limit non-superuser changes */ /* No REAL PGC_USERLIMIT at present */
if (source > PGC_S_UNPRIVILEGED && !superuser()) if (newval < conf->reset_val)
{ {
ereport(elevel, /* Limit non-superuser changes */
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), if (!check_userlimit_privilege(record, source,
errmsg("permission denied to set parameter \"%s\"", elevel))
name),
errhint("Must be superuser to increase this value or turn it off.")));
return false; return false;
} }
if (newval > *conf->variable)
{
/* Allow change if admin should override */ /* Allow change if admin should override */
if (source < PGC_S_UNPRIVILEGED && if (check_userlimit_override(record, source))
record->source > PGC_S_UNPRIVILEGED && changeVal = changeValOrig;
!superuser()) }
changeVal = false;
} }
} }
else else
...@@ -3559,27 +3548,17 @@ set_config_option(const char *name, const char *value, ...@@ -3559,27 +3548,17 @@ set_config_option(const char *name, const char *value,
(*var_hook) (&var_value, *conf->variable, true, (*var_hook) (&var_value, *conf->variable, true,
source); source);
/* Limit non-superuser changes */
if (new_value > reset_value) if (new_value > reset_value)
{ {
/* Limit non-superuser changes */ /* Limit non-superuser changes */
if (source > PGC_S_UNPRIVILEGED && !superuser()) if (!check_userlimit_privilege(record, source,
{ elevel))
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name),
errhint("Must be superuser to increase this value.")));
return false; return false;
} }
}
/* Allow change if admin should override */
if (new_value < var_value) if (new_value < var_value)
{ {
if (source < PGC_S_UNPRIVILEGED && /* Allow change if admin should override */
record->source > PGC_S_UNPRIVILEGED && if (check_userlimit_override(record, source))
!superuser())
changeVal = changeValOrig; changeVal = changeValOrig;
} }
} }
...@@ -3702,6 +3681,71 @@ set_config_option(const char *name, const char *value, ...@@ -3702,6 +3681,71 @@ set_config_option(const char *name, const char *value,
return true; return true;
} }
/*
* Check whether we should allow a USERLIMIT parameter to be set
*
* This is invoked only when the desired new setting is "less" than the
* old and so appropriate privileges are needed. If the setting should
* be disallowed, either throw an error (in interactive case) or return false.
*/
static bool
check_userlimit_privilege(struct config_generic *record, GucSource source,
int elevel)
{
/* Allow if trusted source (e.g., config file) */
if (source < PGC_S_UNPRIVILEGED)
return true;
/*
* Allow if superuser. We can only check this inside a transaction,
* though, so assume not-superuser otherwise. (In practice this means
* that settings coming from PGOPTIONS will be treated as non-superuser)
*/
if (IsTransactionState() && superuser())
return true;
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
record->name),
(record->vartype == PGC_BOOL) ?
errhint("Must be superuser to change this value to false.")
: ((record->vartype == PGC_INT) ?
errhint("Must be superuser to increase this value or turn it off.")
: errhint("Must be superuser to increase this value."))));
return false;
}
/*
* Check whether we should allow a USERLIMIT parameter to be overridden
*
* This is invoked when the desired new setting is "greater" than the
* old; if the old setting was unprivileged and the new one is privileged,
* we should apply it, even though the normal rule would be not to.
*/
static bool
check_userlimit_override(struct config_generic *record, GucSource source)
{
/* Unprivileged source never gets to override this way */
if (source > PGC_S_UNPRIVILEGED)
return false;
/* If existing setting is from privileged source, keep it */
if (record->source < PGC_S_UNPRIVILEGED)
return false;
/*
* If user is a superuser, he gets to keep his setting. We can't check
* this unless inside a transaction, though. XXX in practice that
* restriction means this code is essentially worthless, because the
* result will depend on whether we happen to be inside a transaction
* block when SIGHUP arrives. Dike out until we can think of something
* that actually works.
*/
#ifdef NOT_USED
if (IsTransactionState() && superuser())
return false;
#endif
/* Otherwise override */
return true;
}
/* /*
...@@ -5450,22 +5494,19 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source) ...@@ -5450,22 +5494,19 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
* Syntax error due to token following space after token or * Syntax error due to token following space after token or
* non alpha numeric character * non alpha numeric character
*/ */
pfree(buf.data); ereport(LOG,
ereport(WARNING,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("illegal syntax for custom_variable_classes \"%s\"", newval))); errmsg("invalid syntax for custom_variable_classes: \"%s\"", newval)));
pfree(buf.data);
return NULL; return NULL;
} }
symLen++; symLen++;
appendStringInfoChar(&buf, (char) c); appendStringInfoChar(&buf, (char) c);
} }
/* Remove stray ',' at end */
if (symLen == 0 && buf.len > 0) if (symLen == 0 && buf.len > 0)
buf.data[--buf.len] = '\0';
/*
* Remove stray ',' at end
*/
buf.data[--buf.len] = 0;
if (buf.len == 0) if (buf.len == 0)
newval = NULL; newval = NULL;
...@@ -5479,41 +5520,34 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source) ...@@ -5479,41 +5520,34 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
static bool static bool
assign_stage_log_stats(bool newval, bool doit, GucSource source) assign_stage_log_stats(bool newval, bool doit, GucSource source)
{ {
if (newval) if (newval && log_statement_stats)
{ {
if (log_statement_stats) if (source >= PGC_S_INTERACTIVE)
{
if (doit)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot enable parameter when \"log_statement_stats\" is true."))); errmsg("cannot enable parameter when \"log_statement_stats\" is true")));
else else
return false; return false;
} }
return true; return true;
}
return true;
} }
static bool static bool
assign_log_stats(bool newval, bool doit, GucSource source) assign_log_stats(bool newval, bool doit, GucSource source)
{ {
if (newval) if (newval &&
{ (log_parser_stats || log_planner_stats || log_executor_stats))
if (log_parser_stats || log_planner_stats || log_executor_stats)
{ {
if (doit) if (source >= PGC_S_INTERACTIVE)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot enable \"log_statement_stats\" when \"log_parser_stats\",\n" errmsg("cannot enable \"log_statement_stats\" when "
"\"log_planner_stats\", or \"log_executor_stats\" is true."))); "\"log_parser_stats\", \"log_planner_stats\", "
"or \"log_executor_stats\" is true")));
else else
return false; return false;
} }
return true; return true;
}
return true;
} }
static bool static bool
...@@ -5534,7 +5568,6 @@ assign_transaction_read_only(bool newval, bool doit, GucSource source) ...@@ -5534,7 +5568,6 @@ assign_transaction_read_only(bool newval, bool doit, GucSource source)
static const char * static const char *
assign_canonical_path(const char *newval, bool doit, GucSource source) assign_canonical_path(const char *newval, bool doit, GucSource source)
{ {
if (doit) if (doit)
{ {
/* We have to create a new pointer to force the change */ /* We have to create a new pointer to force the change */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment