Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf687bf6

Browse files
committed
Merge similar algorithms into roles_is_member_of().
The next commit would have complicated two or three algorithms, so takethis opportunity to consolidate. No functional changes.Reviewed by John Naylor.Discussion:https://postgr.es/m/20201228043148.GA1053024@rfd.leadboat.com
1 parent73b96ba commitf687bf6

File tree

1 file changed

+59
-165
lines changed
  • src/backend/utils/adt

1 file changed

+59
-165
lines changed

‎src/backend/utils/adt/acl.c

Lines changed: 59 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -50,32 +50,24 @@ typedef struct
5050
/*
5151
* We frequently need to test whether a given role is a member of some other
5252
* role. In most of these tests the "given role" is the same, namely the
53-
* active current user. So we can optimize it by keeping a cached list of
54-
* all the roles the "given role" is a member of, directly or indirectly.
55-
*
56-
* There are actually two caches, one computed under "has_privs" rules
57-
* (do not recurse where rolinherit isn't true) and one computed under
58-
* "is_member" rules (recurse regardless of rolinherit).
53+
* active current user. So we can optimize it by keeping cached lists of all
54+
* the roles the "given role" is a member of, directly or indirectly.
5955
*
6056
* Possibly this mechanism should be generalized to allow caching membership
6157
* info for multiple roles?
6258
*
63-
* The has_privs cache is:
64-
* cached_privs_role is the role OID the cache is for.
65-
* cached_privs_roles is an OID list of roles that cached_privs_role
66-
*has the privileges of (always including itself).
67-
* The cache is valid if cached_privs_role is not InvalidOid.
68-
*
69-
* The is_member cache is similarly:
70-
* cached_member_role is the role OID the cache is for.
71-
* cached_membership_roles is an OID list of roles that cached_member_role
72-
*is a member of (always including itself).
73-
* The cache is valid if cached_member_role is not InvalidOid.
59+
* Each element of cached_roles is an OID list of constituent roles for the
60+
* corresponding element of cached_role (always including the cached_role
61+
* itself). One cache has ROLERECURSE_PRIVS semantics, and the other has
62+
* ROLERECURSE_MEMBERS semantics.
7463
*/
75-
staticOidcached_privs_role=InvalidOid;
76-
staticList*cached_privs_roles=NIL;
77-
staticOidcached_member_role=InvalidOid;
78-
staticList*cached_membership_roles=NIL;
64+
enumRoleRecurseType
65+
{
66+
ROLERECURSE_PRIVS=0,/* recurse if rolinherit */
67+
ROLERECURSE_MEMBERS=1/* recurse unconditionally */
68+
};
69+
staticOidcached_role[]= {InvalidOid,InvalidOid};
70+
staticList*cached_roles[]= {NIL,NIL};
7971

8072

8173
staticconstchar*getid(constchar*s,char*n);
@@ -4675,8 +4667,8 @@ initialize_acl(void)
46754667
{
46764668
/*
46774669
* In normal mode, set a callback on any syscache invalidation of rows
4678-
* of pg_auth_members (foreach AUTHMEM search in this file) or
4679-
*pg_authid (forhas_rolinherit())
4670+
* of pg_auth_members (forroles_is_member_of()) or pg_authid (for
4671+
* has_rolinherit())
46804672
*/
46814673
CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
46824674
RoleMembershipCacheCallback,
@@ -4695,8 +4687,8 @@ static void
46954687
RoleMembershipCacheCallback(Datumarg,intcacheid,uint32hashvalue)
46964688
{
46974689
/* Force membership caches to be recomputed on next use */
4698-
cached_privs_role=InvalidOid;
4699-
cached_member_role=InvalidOid;
4690+
cached_role[ROLERECURSE_PRIVS]=InvalidOid;
4691+
cached_role[ROLERECURSE_MEMBERS]=InvalidOid;
47004692
}
47014693

47024694

@@ -4718,30 +4710,35 @@ has_rolinherit(Oid roleid)
47184710

47194711

47204712
/*
4721-
* Get a list of roles that the specified roleidhas the privileges of
4713+
* Get a list of roles that the specified roleidis a member of
47224714
*
4723-
* This is defined not to recurse through roles that don't have rolinherit
4724-
* set; for such roles, membership implies the ability to do SET ROLE, but
4725-
* the privileges are not available until you've done so.
4715+
* Type ROLERECURSE_PRIVS recurses only through roles that have rolinherit
4716+
* set, while ROLERECURSE_MEMBERS recurses through all roles. This sets
4717+
* *is_admin==true if and only if role "roleid" has an ADMIN OPTION membership
4718+
* in role "admin_of".
47264719
*
47274720
* Since indirect membership testing is relatively expensive, we cache
47284721
* a list of memberships. Hence, the result is only guaranteed good until
4729-
* the next call ofroles_has_privs_of()!
4722+
* the next call ofroles_is_member_of()!
47304723
*
47314724
* For the benefit of select_best_grantor, the result is defined to be
47324725
* in breadth-first order, ie, closer relationships earlier.
47334726
*/
47344727
staticList*
4735-
roles_has_privs_of(Oidroleid)
4728+
roles_is_member_of(Oidroleid,enumRoleRecurseTypetype,
4729+
Oidadmin_of,bool*is_admin)
47364730
{
47374731
List*roles_list;
47384732
ListCell*l;
4739-
List*new_cached_privs_roles;
4733+
List*new_cached_roles;
47404734
MemoryContextoldctx;
47414735

4742-
/* If cache is already valid, just return the list */
4743-
if (OidIsValid(cached_privs_role)&&cached_privs_role==roleid)
4744-
returncached_privs_roles;
4736+
Assert(OidIsValid(admin_of)==PointerIsValid(is_admin));
4737+
4738+
/* If cache is valid and ADMIN OPTION not sought, just return the list */
4739+
if (cached_role[type]==roleid&& !OidIsValid(admin_of)&&
4740+
OidIsValid(cached_role[type]))
4741+
returncached_roles[type];
47454742

47464743
/*
47474744
* Find all the roles that roleid is a member of, including multi-level
@@ -4762,9 +4759,8 @@ roles_has_privs_of(Oid roleid)
47624759
CatCList*memlist;
47634760
inti;
47644761

4765-
/* Ignore non-inheriting roles */
4766-
if (!has_rolinherit(memberid))
4767-
continue;
4762+
if (type==ROLERECURSE_PRIVS&& !has_rolinherit(memberid))
4763+
continue;/* ignore non-inheriting roles */
47684764

47694765
/* Find roles that memberid is directly a member of */
47704766
memlist=SearchSysCacheList1(AUTHMEMMEMROLE,
@@ -4775,83 +4771,13 @@ roles_has_privs_of(Oid roleid)
47754771
Oidotherid= ((Form_pg_auth_members)GETSTRUCT(tup))->roleid;
47764772

47774773
/*
4778-
* Even though there shouldn't be any loops in the membership
4779-
* graph, we must test for having already seen this role. It is
4780-
* legal for instance to have both A->B and A->C->B.
4774+
* While otherid==InvalidOid shouldn't appear in the catalog, the
4775+
* OidIsValid() avoids crashing if that arises.
47814776
*/
4782-
roles_list=list_append_unique_oid(roles_list,otherid);
4783-
}
4784-
ReleaseSysCacheList(memlist);
4785-
}
4786-
4787-
/*
4788-
* Copy the completed list into TopMemoryContext so it will persist.
4789-
*/
4790-
oldctx=MemoryContextSwitchTo(TopMemoryContext);
4791-
new_cached_privs_roles=list_copy(roles_list);
4792-
MemoryContextSwitchTo(oldctx);
4793-
list_free(roles_list);
4794-
4795-
/*
4796-
* Now safe to assign to state variable
4797-
*/
4798-
cached_privs_role=InvalidOid;/* just paranoia */
4799-
list_free(cached_privs_roles);
4800-
cached_privs_roles=new_cached_privs_roles;
4801-
cached_privs_role=roleid;
4802-
4803-
/* And now we can return the answer */
4804-
returncached_privs_roles;
4805-
}
4806-
4807-
4808-
/*
4809-
* Get a list of roles that the specified roleid is a member of
4810-
*
4811-
* This is defined to recurse through roles regardless of rolinherit.
4812-
*
4813-
* Since indirect membership testing is relatively expensive, we cache
4814-
* a list of memberships. Hence, the result is only guaranteed good until
4815-
* the next call of roles_is_member_of()!
4816-
*/
4817-
staticList*
4818-
roles_is_member_of(Oidroleid)
4819-
{
4820-
List*roles_list;
4821-
ListCell*l;
4822-
List*new_cached_membership_roles;
4823-
MemoryContextoldctx;
4824-
4825-
/* If cache is already valid, just return the list */
4826-
if (OidIsValid(cached_member_role)&&cached_member_role==roleid)
4827-
returncached_membership_roles;
4828-
4829-
/*
4830-
* Find all the roles that roleid is a member of, including multi-level
4831-
* recursion. The role itself will always be the first element of the
4832-
* resulting list.
4833-
*
4834-
* Each element of the list is scanned to see if it adds any indirect
4835-
* memberships. We can use a single list as both the record of
4836-
* already-found memberships and the agenda of roles yet to be scanned.
4837-
* This is a bit tricky but works because the foreach() macro doesn't
4838-
* fetch the next list element until the bottom of the loop.
4839-
*/
4840-
roles_list=list_make1_oid(roleid);
4841-
4842-
foreach(l,roles_list)
4843-
{
4844-
Oidmemberid=lfirst_oid(l);
4845-
CatCList*memlist;
4846-
inti;
4847-
4848-
/* Find roles that memberid is directly a member of */
4849-
memlist=SearchSysCacheList1(AUTHMEMMEMROLE,
4850-
ObjectIdGetDatum(memberid));
4851-
for (i=0;i<memlist->n_members;i++)
4852-
{
4853-
HeapTupletup=&memlist->members[i]->tuple;
4854-
Oidotherid= ((Form_pg_auth_members)GETSTRUCT(tup))->roleid;
4777+
if (otherid==admin_of&&
4778+
((Form_pg_auth_members)GETSTRUCT(tup))->admin_option&&
4779+
OidIsValid(admin_of))
4780+
*is_admin= true;
48554781

48564782
/*
48574783
* Even though there shouldn't be any loops in the membership
@@ -4867,20 +4793,20 @@ roles_is_member_of(Oid roleid)
48674793
* Copy the completed list into TopMemoryContext so it will persist.
48684794
*/
48694795
oldctx=MemoryContextSwitchTo(TopMemoryContext);
4870-
new_cached_membership_roles=list_copy(roles_list);
4796+
new_cached_roles=list_copy(roles_list);
48714797
MemoryContextSwitchTo(oldctx);
48724798
list_free(roles_list);
48734799

48744800
/*
48754801
* Now safe to assign to state variable
48764802
*/
4877-
cached_member_role=InvalidOid;/* just paranoia */
4878-
list_free(cached_membership_roles);
4879-
cached_membership_roles=new_cached_membership_roles;
4880-
cached_member_role=roleid;
4803+
cached_role[type]=InvalidOid;/* just paranoia */
4804+
list_free(cached_roles[type]);
4805+
cached_roles[type]=new_cached_roles;
4806+
cached_role[type]=roleid;
48814807

48824808
/* And now we can return the answer */
4883-
returncached_membership_roles;
4809+
returncached_roles[type];
48844810
}
48854811

48864812

@@ -4906,7 +4832,9 @@ has_privs_of_role(Oid member, Oid role)
49064832
* Find all the roles that member has the privileges of, including
49074833
* multi-level recursion, then see if target role is any one of them.
49084834
*/
4909-
returnlist_member_oid(roles_has_privs_of(member),role);
4835+
returnlist_member_oid(roles_is_member_of(member,ROLERECURSE_PRIVS,
4836+
InvalidOid,NULL),
4837+
role);
49104838
}
49114839

49124840

@@ -4930,7 +4858,9 @@ is_member_of_role(Oid member, Oid role)
49304858
* Find all the roles that member is a member of, including multi-level
49314859
* recursion, then see if target role is any one of them.
49324860
*/
4933-
returnlist_member_oid(roles_is_member_of(member),role);
4861+
returnlist_member_oid(roles_is_member_of(member,ROLERECURSE_MEMBERS,
4862+
InvalidOid,NULL),
4863+
role);
49344864
}
49354865

49364866
/*
@@ -4964,7 +4894,9 @@ is_member_of_role_nosuper(Oid member, Oid role)
49644894
* Find all the roles that member is a member of, including multi-level
49654895
* recursion, then see if target role is any one of them.
49664896
*/
4967-
returnlist_member_oid(roles_is_member_of(member),role);
4897+
returnlist_member_oid(roles_is_member_of(member,ROLERECURSE_MEMBERS,
4898+
InvalidOid,NULL),
4899+
role);
49684900
}
49694901

49704902

@@ -4977,8 +4909,6 @@ bool
49774909
is_admin_of_role(Oidmember,Oidrole)
49784910
{
49794911
boolresult= false;
4980-
List*roles_list;
4981-
ListCell*l;
49824912

49834913
if (superuser_arg(member))
49844914
return true;
@@ -5016,44 +4946,7 @@ is_admin_of_role(Oid member, Oid role)
50164946
returnmember==GetSessionUserId()&&
50174947
!InLocalUserIdChange()&& !InSecurityRestrictedOperation();
50184948

5019-
/*
5020-
* Find all the roles that member is a member of, including multi-level
5021-
* recursion. We build a list in the same way that is_member_of_role does
5022-
* to track visited and unvisited roles.
5023-
*/
5024-
roles_list=list_make1_oid(member);
5025-
5026-
foreach(l,roles_list)
5027-
{
5028-
Oidmemberid=lfirst_oid(l);
5029-
CatCList*memlist;
5030-
inti;
5031-
5032-
/* Find roles that memberid is directly a member of */
5033-
memlist=SearchSysCacheList1(AUTHMEMMEMROLE,
5034-
ObjectIdGetDatum(memberid));
5035-
for (i=0;i<memlist->n_members;i++)
5036-
{
5037-
HeapTupletup=&memlist->members[i]->tuple;
5038-
Oidotherid= ((Form_pg_auth_members)GETSTRUCT(tup))->roleid;
5039-
5040-
if (otherid==role&&
5041-
((Form_pg_auth_members)GETSTRUCT(tup))->admin_option)
5042-
{
5043-
/* Found what we came for, so can stop searching */
5044-
result= true;
5045-
break;
5046-
}
5047-
5048-
roles_list=list_append_unique_oid(roles_list,otherid);
5049-
}
5050-
ReleaseSysCacheList(memlist);
5051-
if (result)
5052-
break;
5053-
}
5054-
5055-
list_free(roles_list);
5056-
4949+
(void)roles_is_member_of(member,ROLERECURSE_MEMBERS,role,&result);
50574950
returnresult;
50584951
}
50594952

@@ -5125,10 +5018,11 @@ select_best_grantor(Oid roleId, AclMode privileges,
51255018
/*
51265019
* Otherwise we have to do a careful search to see if roleId has the
51275020
* privileges of any suitable role. Note: we can hang onto the result of
5128-
*roles_has_privs_of() throughout this loop, because aclmask_direct()
5021+
*roles_is_member_of() throughout this loop, because aclmask_direct()
51295022
* doesn't query any role memberships.
51305023
*/
5131-
roles_list=roles_has_privs_of(roleId);
5024+
roles_list=roles_is_member_of(roleId,ROLERECURSE_PRIVS,
5025+
InvalidOid,NULL);
51325026

51335027
/* initialize candidate result as default */
51345028
*grantorId=roleId;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp