From 9475db3a4eb5876b364254886d2730db01e042fd Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sun, 17 Feb 2013 23:45:36 -0500 Subject: [PATCH] Add ALTER ROLE ALL SET command This generalizes the existing ALTER ROLE ... SET and ALTER DATABASE ... SET functionality to allow creating settings that apply to all users in all databases. reviewed by Pavel Stehule --- doc/src/sgml/ref/alter_role.sgml | 27 ++++++--- src/backend/commands/user.c | 92 +++++++++++++++++++------------ src/backend/parser/gram.y | 8 +++ src/backend/utils/init/postinit.c | 1 + src/backend/utils/misc/guc.c | 3 +- src/include/utils/guc.h | 1 + 6 files changed, 90 insertions(+), 42 deletions(-) diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml index 2fbba53d25..b0981fdd5d 100644 --- a/doc/src/sgml/ref/alter_role.sgml +++ b/doc/src/sgml/ref/alter_role.sgml @@ -39,9 +39,9 @@ ALTER ROLE name [ [ WITH ] name RENAME TO new_name ALTER ROLE name [ IN DATABASE database_name ] SET configuration_parameter { TO | = } { value | DEFAULT } -ALTER ROLE name [ IN DATABASE database_name ] SET configuration_parameter FROM CURRENT -ALTER ROLE name [ IN DATABASE database_name ] RESET configuration_parameter -ALTER ROLE name [ IN DATABASE database_name ] RESET ALL +ALTER ROLE { name | ALL } [ IN DATABASE database_name ] SET configuration_parameter FROM CURRENT +ALTER ROLE { name | ALL } [ IN DATABASE database_name ] RESET configuration_parameter +ALTER ROLE { name | ALL } [ IN DATABASE database_name ] RESET ALL @@ -83,8 +83,15 @@ ALTER ROLE name [ IN DATABASE The remaining variants change a role's session default for a configuration variable, either for all databases or, when the IN - DATABASE clause is specified, only for sessions in - the named database. Whenever the role subsequently + DATABASE clause is specified, only for sessions in the named + database. If ALL is specified instead of a role name, + this changes the setting for all roles. Using ALL + with IN DATABASE is effectively the same as using the + command ALTER DATABASE ... SET .... + + + + Whenever the role subsequently starts a new session, the specified value becomes the session default, overriding whatever setting is present in postgresql.conf or has been received from the postgres @@ -93,12 +100,17 @@ ALTER ROLE name [ IN DATABASE does not cause new configuration values to be set. Settings set for all databases are overridden by database-specific settings - attached to a role. + attached to a role. Settings for specific databases or specific roles override + settings for all roles. + + + Superusers can change anyone's session defaults. Roles having CREATEROLE privilege can change defaults for non-superuser roles. Ordinary roles can only set defaults for themselves. Certain configuration variables cannot be set this way, or can only be - set if a superuser issues the command. + set if a superuser issues the command. Only superusers can change a setting + for all roles in all databases. @@ -307,6 +319,7 @@ ALTER ROLE fred IN DATABASE devel SET client_min_messages = DEBUG; + diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 3ba877d253..5edb59af36 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -814,41 +814,46 @@ AlterRoleSet(AlterRoleSetStmt *stmt) { HeapTuple roletuple; Oid databaseid = InvalidOid; - Oid roleid; + Oid roleid = InvalidOid; - roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role)); - - if (!HeapTupleIsValid(roletuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("role \"%s\" does not exist", stmt->role))); - - roleid = HeapTupleGetOid(roletuple); - - /* - * Obtain a lock on the role and make sure it didn't go away in the - * meantime. - */ - shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple)); - - /* - * To mess with a superuser you gotta be superuser; else you need - * createrole, or just want to change your own settings - */ - if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper) + if (stmt->role) { - if (!superuser()) + roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role)); + + if (!HeapTupleIsValid(roletuple)) ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to alter superusers"))); - } - else - { - if (!have_createrole_privilege() && - HeapTupleGetOid(roletuple) != GetUserId()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied"))); + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("role \"%s\" does not exist", stmt->role))); + + roleid = HeapTupleGetOid(roletuple); + + /* + * Obtain a lock on the role and make sure it didn't go away in the + * meantime. + */ + shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple)); + + /* + * To mess with a superuser you gotta be superuser; else you need + * createrole, or just want to change your own settings + */ + if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper) + { + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to alter superusers"))); + } + else + { + if (!have_createrole_privilege() && + HeapTupleGetOid(roletuple) != GetUserId()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied"))); + } + + ReleaseSysCache(roletuple); } /* look up and lock the database, if specified */ @@ -856,10 +861,29 @@ AlterRoleSet(AlterRoleSetStmt *stmt) { databaseid = get_database_oid(stmt->database, false); shdepLockAndCheckObject(DatabaseRelationId, databaseid); + + if (!stmt->role) + { + /* + * If no role is specified, then this is effectively the same as + * ALTER DATABASE ... SET, so use the same permission check. + */ + if (!pg_database_ownercheck(databaseid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + stmt->database); + } } - AlterSetting(databaseid, HeapTupleGetOid(roletuple), stmt->setstmt); - ReleaseSysCache(roletuple); + if (!stmt->role && !stmt->database) + { + /* Must be superuser to alter settings globally. */ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to alter settings globally"))); + } + + AlterSetting(databaseid, roleid, stmt->setstmt); return roleid; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index fee05311c5..b998431f5f 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -1020,6 +1020,14 @@ AlterRoleSetStmt: n->setstmt = $5; $$ = (Node *)n; } + | ALTER ROLE ALL opt_in_database SetResetClause + { + AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); + n->role = NULL; + n->database = $4; + n->setstmt = $5; + $$ = (Node *)n; + } ; diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 7e21ceae88..84270061d8 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -1010,6 +1010,7 @@ process_settings(Oid databaseid, Oid roleid) ApplySetting(databaseid, roleid, relsetting, PGC_S_DATABASE_USER); ApplySetting(InvalidOid, roleid, relsetting, PGC_S_USER); ApplySetting(databaseid, InvalidOid, relsetting, PGC_S_DATABASE); + ApplySetting(InvalidOid, InvalidOid, relsetting, PGC_S_GLOBAL); heap_close(relsetting, AccessShareLock); } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 6128694200..5437e0744f 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -500,6 +500,7 @@ const char *const GucSource_Names[] = /* PGC_S_ENV_VAR */ "environment variable", /* PGC_S_FILE */ "configuration file", /* PGC_S_ARGV */ "command line", + /* PGC_S_GLOBAL */ "global", /* PGC_S_DATABASE */ "database", /* PGC_S_USER */ "user", /* PGC_S_DATABASE_USER */ "database user", @@ -5149,7 +5150,7 @@ set_config_option(const char *name, const char *value, */ elevel = IsUnderPostmaster ? DEBUG3 : LOG; } - else if (source == PGC_S_DATABASE || source == PGC_S_USER || + else if (source == PGC_S_GLOBAL || source == PGC_S_DATABASE || source == PGC_S_USER || source == PGC_S_DATABASE_USER) elevel = WARNING; else diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 0023c007e0..d497b1f654 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -87,6 +87,7 @@ typedef enum PGC_S_ENV_VAR, /* postmaster environment variable */ PGC_S_FILE, /* postgresql.conf */ PGC_S_ARGV, /* postmaster command line */ + PGC_S_GLOBAL, /* global in-database setting */ PGC_S_DATABASE, /* per-database setting */ PGC_S_USER, /* per-user setting */ PGC_S_DATABASE_USER, /* per-user-and-database setting */