diff options
author | Robert Haas <rhaas@postgresql.org> | 2022-08-25 10:06:02 -0400 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2022-08-25 10:06:02 -0400 |
commit | e3ce2de09d814f8770b2e3b3c152b7671bcdb83f (patch) | |
tree | 1ca5cf6da0ce86056ad4e573231a44ff651e252d /src/backend/utils/adt/acl.c | |
parent | 2059c5e3b06545e7d0650dba9c665332374c3c21 (diff) |
Allow grant-level control of role inheritance behavior.
The GRANT statement can now specify WITH INHERIT TRUE or WITH
INHERIT FALSE to control whether the member inherits the granted
role's permissions. For symmetry, you can now likewise write
WITH ADMIN TRUE or WITH ADMIN FALSE to turn ADMIN OPTION on or off.
If a GRANT does not specify WITH INHERIT, the behavior based on
whether the member role is marked INHERIT or NOINHERIT. This means
that if all roles are marked INHERIT or NOINHERIT before any role
grants are performed, the behavior is identical to what we had before;
otherwise, it's different, because ALTER ROLE [NO]INHERIT now only
changes the default behavior of future grants, and has no effect on
existing ones.
Patch by me. Reviewed and testing by Nathan Bossart and Tushar Ahuja,
with design-level comments from various others.
Discussion: http://postgr.es/m/CA+Tgmoa5Sf4PiWrfxA=sGzDKg0Ojo3dADw=wAHOhR9dggV=RmQ@mail.gmail.com
Diffstat (limited to 'src/backend/utils/adt/acl.c')
-rw-r--r-- | src/backend/utils/adt/acl.c | 47 |
1 files changed, 15 insertions, 32 deletions
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 3e045da31fc..ea28da26a89 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -66,7 +66,7 @@ typedef struct */ enum RoleRecurseType { - ROLERECURSE_PRIVS = 0, /* recurse if rolinherit */ + ROLERECURSE_PRIVS = 0, /* recurse through inheritable grants */ ROLERECURSE_MEMBERS = 1 /* recurse unconditionally */ }; static Oid cached_role[] = {InvalidOid, InvalidOid}; @@ -4735,8 +4735,8 @@ initialize_acl(void) /* * In normal mode, set a callback on any syscache invalidation of rows - * of pg_auth_members (for roles_is_member_of()), pg_authid (for - * has_rolinherit()), or pg_database (for roles_is_member_of()) + * of pg_auth_members (for roles_is_member_of()) pg_database (for + * roles_is_member_of()) */ CacheRegisterSyscacheCallback(AUTHMEMROLEMEM, RoleMembershipCacheCallback, @@ -4769,29 +4769,11 @@ RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue) cached_role[ROLERECURSE_MEMBERS] = InvalidOid; } - -/* Check if specified role has rolinherit set */ -static bool -has_rolinherit(Oid roleid) -{ - bool result = false; - HeapTuple utup; - - utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); - if (HeapTupleIsValid(utup)) - { - result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit; - ReleaseSysCache(utup); - } - return result; -} - - /* * Get a list of roles that the specified roleid is a member of * - * Type ROLERECURSE_PRIVS recurses only through roles that have rolinherit - * set, while ROLERECURSE_MEMBERS recurses through all roles. + * Type ROLERECURSE_PRIVS recurses only through inheritable grants, + * while ROLERECURSE_MEMBERS recurses through all grants. * * Since indirect membership testing is relatively expensive, we cache * a list of memberships. Hence, the result is only guaranteed good until @@ -4861,23 +4843,24 @@ roles_is_member_of(Oid roleid, enum RoleRecurseType type, CatCList *memlist; int i; - if (type == ROLERECURSE_PRIVS && !has_rolinherit(memberid)) - continue; /* ignore non-inheriting roles */ - /* Find roles that memberid is directly a member of */ memlist = SearchSysCacheList1(AUTHMEMMEMROLE, ObjectIdGetDatum(memberid)); for (i = 0; i < memlist->n_members; i++) { HeapTuple tup = &memlist->members[i]->tuple; - Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid; + Form_pg_auth_members form = (Form_pg_auth_members) GETSTRUCT(tup); + Oid otherid = form->roleid; + + /* If we're supposed to ignore non-heritable grants, do so. */ + if (type == ROLERECURSE_PRIVS && !form->inherit_option) + continue; /* * While otherid==InvalidOid shouldn't appear in the catalog, the * OidIsValid() avoids crashing if that arises. */ - if (otherid == admin_of && - ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option && + if (otherid == admin_of && form->admin_option && OidIsValid(admin_of) && !OidIsValid(*admin_role)) *admin_role = memberid; @@ -4920,8 +4903,8 @@ roles_is_member_of(Oid roleid, enum RoleRecurseType type, /* * Does member have the privileges of role (directly or indirectly)? * - * This is defined not to recurse through roles that don't have rolinherit - * set; for such roles, membership implies the ability to do SET ROLE, but + * This is defined not to recurse through grants that are not inherited; + * in such cases, membership implies the ability to do SET ROLE, but * the privileges are not available until you've done so. */ bool @@ -4948,7 +4931,7 @@ has_privs_of_role(Oid member, Oid role) /* * Is member a member of role (directly or indirectly)? * - * This is defined to recurse through roles regardless of rolinherit. + * This is defined to recurse through grants whether they are inherited or not. * * Do not use this for privilege checking, instead use has_privs_of_role() */ |