Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas2022-11-18 17:32:50 +0000
committerRobert Haas2022-11-18 17:32:56 +0000
commit3d14e171e9e2236139e8976f3309a588bcc8683b (patch)
tree3a93134fefd39082982fc4aedc9cecedceea48a5 /src/backend/commands
parentf84ff0c6d4eb4e470e55f48103a7edd269d13c49 (diff)
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the permissions of the granted role are automatically available to the grantee, the new SET permission controls whether or not the grantee may use the SET ROLE command to assume the privileges of the granted role. In addition, the new SET permission controls whether or not it is possible to transfer ownership of objects to the target role or to create new objects owned by the target role using commands such as CREATE DATABASE .. OWNER. We could alternatively have made this controlled by the INHERIT option, or allow it when either option is given. An advantage of this approach is that if you are granted a predefined role with INHERIT TRUE, SET FALSE, you can't go and create objects owned by that role. The underlying theory here is that the ability to create objects as a target role is not a privilege per se, and thus does not depend on whether you inherit the target role's privileges. However, it's surely something you could do anyway if you could SET ROLE to the target role, and thus making it contingent on whether you have that ability is reasonable. Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis, Peter Eisentraut, and Stephen Frost. Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/alter.c2
-rw-r--r--src/backend/commands/dbcommands.c4
-rw-r--r--src/backend/commands/foreigncmds.c2
-rw-r--r--src/backend/commands/publicationcmds.c2
-rw-r--r--src/backend/commands/schemacmds.c4
-rw-r--r--src/backend/commands/tablecmds.c2
-rw-r--r--src/backend/commands/typecmds.c2
-rw-r--r--src/backend/commands/user.c44
-rw-r--r--src/backend/commands/variable.c2
9 files changed, 51 insertions, 13 deletions
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index b2089d785b6..10b6fe19a2c 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -999,7 +999,7 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
objname);
}
/* Must be able to become new owner */
- check_is_member_of_role(GetUserId(), new_ownerId);
+ check_can_set_role(GetUserId(), new_ownerId);
/* New owner must have CREATE privilege on namespace */
if (OidIsValid(namespaceId))
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index a67ea86619c..6eb87427181 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -941,7 +941,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create database")));
- check_is_member_of_role(GetUserId(), datdba);
+ check_can_set_role(GetUserId(), datdba);
/*
* Lookup database (template) to be cloned, and obtain share lock on it.
@@ -2495,7 +2495,7 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
dbname);
/* Must be able to become new owner */
- check_is_member_of_role(GetUserId(), newOwnerId);
+ check_can_set_role(GetUserId(), newOwnerId);
/*
* must have createdb rights
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 55b0be9e1d1..28b5c75f110 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -363,7 +363,7 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
NameStr(form->srvname));
/* Must be able to become new owner */
- check_is_member_of_role(GetUserId(), newOwnerId);
+ check_can_set_role(GetUserId(), newOwnerId);
/* New owner must have USAGE privilege on foreign-data wrapper */
aclresult = object_aclcheck(ForeignDataWrapperRelationId, form->srvfdw, newOwnerId, ACL_USAGE);
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 940655b9be0..20fa72c5c80 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -1911,7 +1911,7 @@ AlterPublicationOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
NameStr(form->pubname));
/* Must be able to become new owner */
- check_is_member_of_role(GetUserId(), newOwnerId);
+ check_can_set_role(GetUserId(), newOwnerId);
/* New owner must have CREATE privilege on database */
aclresult = object_aclcheck(DatabaseRelationId, MyDatabaseId, newOwnerId, ACL_CREATE);
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index b03f07a2322..12cbfba7d06 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -97,7 +97,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString,
aclcheck_error(aclresult, OBJECT_DATABASE,
get_database_name(MyDatabaseId));
- check_is_member_of_role(saved_uid, owner_uid);
+ check_can_set_role(saved_uid, owner_uid);
/* Additional check to protect reserved schema names */
if (!allowSystemTableMods && IsReservedName(schemaName))
@@ -370,7 +370,7 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
NameStr(nspForm->nspname));
/* Must be able to become new owner */
- check_is_member_of_role(GetUserId(), newOwnerId);
+ check_can_set_role(GetUserId(), newOwnerId);
/*
* must have create-schema rights
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f0068078520..845208d662b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13833,7 +13833,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
RelationGetRelationName(target_rel));
/* Must be able to become new owner */
- check_is_member_of_role(GetUserId(), newOwnerId);
+ check_can_set_role(GetUserId(), newOwnerId);
/* New owner must have CREATE privilege on namespace */
aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index ecc8b3f44c9..7770a86bee0 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -3745,7 +3745,7 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
aclcheck_error_type(ACLCHECK_NOT_OWNER, typTup->oid);
/* Must be able to become new owner */
- check_is_member_of_role(GetUserId(), newOwnerId);
+ check_can_set_role(GetUserId(), newOwnerId);
/* New owner must have CREATE privilege on namespace */
aclresult = object_aclcheck(NamespaceRelationId, typTup->typnamespace,
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 2369cc600c7..8b6543edee2 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -51,8 +51,8 @@
* RRG_REMOVE_ADMIN_OPTION indicates a grant that would need to have
* admin_option set to false by the operation.
*
- * RRG_REMOVE_INHERIT_OPTION indicates a grant that would need to have
- * inherit_option set to false by the operation.
+ * Similarly, RRG_REMOVE_INHERIT_OPTION and RRG_REMOVE_SET_OPTION indicate
+ * grants that would need to have the corresponding options set to false.
*
* RRG_DELETE_GRANT indicates a grant that would need to be removed entirely
* by the operation.
@@ -62,6 +62,7 @@ typedef enum
RRG_NOOP,
RRG_REMOVE_ADMIN_OPTION,
RRG_REMOVE_INHERIT_OPTION,
+ RRG_REMOVE_SET_OPTION,
RRG_DELETE_GRANT
} RevokeRoleGrantAction;
@@ -73,10 +74,12 @@ typedef struct
unsigned specified;
bool admin;
bool inherit;
+ bool set;
} GrantRoleOptions;
#define GRANT_ROLE_SPECIFIED_ADMIN 0x0001
#define GRANT_ROLE_SPECIFIED_INHERIT 0x0002
+#define GRANT_ROLE_SPECIFIED_SET 0x0004
/* GUC parameter */
int Password_encryption = PASSWORD_TYPE_SCRAM_SHA_256;
@@ -1389,6 +1392,12 @@ GrantRole(ParseState *pstate, GrantRoleStmt *stmt)
if (parse_bool(optval, &popt.inherit))
continue;
}
+ else if (strcmp(opt->defname, "set") == 0)
+ {
+ popt.specified |= GRANT_ROLE_SPECIFIED_SET;
+ if (parse_bool(optval, &popt.set))
+ continue;
+ }
else
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
@@ -1776,6 +1785,16 @@ AddRoleMems(const char *rolename, Oid roleid,
at_least_one_change = true;
}
+ if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0
+ && authmem_form->set_option != popt->set)
+ {
+ new_record[Anum_pg_auth_members_set_option - 1] =
+ BoolGetDatum(popt->set);
+ new_record_repl[Anum_pg_auth_members_set_option - 1] =
+ true;
+ at_least_one_change = true;
+ }
+
if (!at_least_one_change)
{
ereport(NOTICE,
@@ -1798,9 +1817,15 @@ AddRoleMems(const char *rolename, Oid roleid,
Oid objectId;
Oid *newmembers = palloc(sizeof(Oid));
- /* Set admin option if user set it to true, otherwise not. */
+ /*
+ * The values for these options can be taken directly from 'popt'.
+ * Either they were specified, or the defaults as set by
+ * InitGrantRoleOptions are correct.
+ */
new_record[Anum_pg_auth_members_admin_option - 1] =
BoolGetDatum(popt->admin);
+ new_record[Anum_pg_auth_members_set_option - 1] =
+ BoolGetDatum(popt->set);
/*
* If the user specified a value for the inherit option, use
@@ -1989,6 +2014,13 @@ DelRoleMems(const char *rolename, Oid roleid,
new_record_repl[Anum_pg_auth_members_inherit_option - 1] =
true;
}
+ else if (actions[i] == RRG_REMOVE_SET_OPTION)
+ {
+ new_record[Anum_pg_auth_members_set_option - 1] =
+ BoolGetDatum(false);
+ new_record_repl[Anum_pg_auth_members_set_option - 1] =
+ true;
+ }
else
elog(ERROR, "unknown role revoke action");
@@ -2182,6 +2214,11 @@ plan_single_revoke(CatCList *memlist, RevokeRoleGrantAction *actions,
*/
actions[i] = RRG_REMOVE_INHERIT_OPTION;
}
+ else if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0)
+ {
+ /* Here too, no need to recurse. */
+ actions[i] = RRG_REMOVE_SET_OPTION;
+ }
else
{
bool revoke_admin_option_only;
@@ -2331,4 +2368,5 @@ InitGrantRoleOptions(GrantRoleOptions *popt)
popt->specified = 0;
popt->admin = false;
popt->inherit = false;
+ popt->set = true;
}
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 791bac6715c..00d8d54d820 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -939,7 +939,7 @@ check_role(char **newval, void **extra, GucSource source)
* leader's state.
*/
if (!InitializingParallelWorker &&
- !is_member_of_role(GetSessionUserId(), roleid))
+ !member_can_set_role(GetSessionUserId(), roleid))
{
if (source == PGC_S_TEST)
{