postgresql 权限管理
·
ACL权限 (对象访问权限)



以上为执行权限的种类以及适用对象合在系统表中显示的缩写
对象可赋予的访问权限
用户权限
enum RoleRecurseType
{
ROLERECURSE_MEMBERS = 0, //无条件递归(直接和间接成员关系)。
ROLERECURSE_PRIVS = 1, //通过可继承的权限(inheritable grants)递归。
ROLERECURSE_SETROLE = 2 //通过SET ROLE授予的权限递归。
};
//cache提升性能
static Oid cached_role[] = {InvalidOid, InvalidOid, InvalidOid}; //与cached_roles对应的角色OID。
static List *cached_roles[] = {NIL, NIL, NIL}; //三种权限oid递归链表。
static uint32 cached_db_hash;
void
initialize_acl(void)
{
if (!IsBootstrapProcessingMode())
{
cached_db_hash =
GetSysCacheHashValue1(DATABASEOID,
ObjectIdGetDatum(MyDatabaseId));
/*
* In normal mode, set a callback on any syscache invalidation of rows
* of pg_auth_members (for roles_is_member_of()) pg_database (for
* roles_is_member_of())
*/
CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
RoleMembershipCacheCallback,
(Datum) 0);
CacheRegisterSyscacheCallback(AUTHOID,
RoleMembershipCacheCallback,
(Datum) 0);
CacheRegisterSyscacheCallback(DATABASEOID,
RoleMembershipCacheCallback,
(Datum) 0);
}
}
static void
RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
{
if (cacheid == DATABASEOID &&
hashvalue != cached_db_hash &&
hashvalue != 0)
{
return; //修改的别的数据库 不失效
}
/* Force membership caches to be recomputed on next use */
cached_role[ROLERECURSE_MEMBERS] = InvalidOid;
cached_role[ROLERECURSE_PRIVS] = InvalidOid;
cached_role[ROLERECURSE_SETROLE] = InvalidOid;
}
默认缓存当前活跃用户(current user)的角色成员关系,但未来可能扩展为支持多角色缓存。
记录的缓存将在 pg_auth_members (for roles_is_member_of()) pg_database (for roles_is_member_of())表更改时失效
static List *
roles_is_member_of(Oid roleid, enum RoleRecurseType type,
Oid admin_of, Oid *admin_role)
{
Oid dba;
List *roles_list;
ListCell *l;
List *new_cached_roles;
MemoryContext oldctx;
bloom_filter *bf = NULL;
Assert(OidIsValid(admin_of) == PointerIsValid(admin_role));
if (admin_role != NULL)
*admin_role = InvalidOid;
/* If cache is valid and ADMIN OPTION not sought, just return the list */
if (cached_role[type] == roleid && !OidIsValid(admin_of) &&
OidIsValid(cached_role[type]))
return cached_roles[type];
/*
* Role expansion happens in a non-database backend when guc.c checks
* ROLE_PG_READ_ALL_SETTINGS for a physical walsender SHOW command. In
* that case, no role gets pg_database_owner.
*/
if (!OidIsValid(MyDatabaseId))
dba = InvalidOid;
else
{
HeapTuple dbtup;
dbtup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
if (!HeapTupleIsValid(dbtup))
elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
dba = ((Form_pg_database) GETSTRUCT(dbtup))->datdba;
ReleaseSysCache(dbtup);
}
/*
* Find all the roles that roleid is a member of, including multi-level
* recursion. The role itself will always be the first element of the
* resulting list.
*
* Each element of the list is scanned to see if it adds any indirect
* memberships. We can use a single list as both the record of
* already-found memberships and the agenda of roles yet to be scanned.
* This is a bit tricky but works because the foreach() macro doesn't
* fetch the next list element until the bottom of the loop.
*/
roles_list = list_make1_oid(roleid);
foreach(l, roles_list)
{
Oid memberid = lfirst_oid(l);
CatCList *memlist;
int i;
/* 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;
Form_pg_auth_members form = (Form_pg_auth_members) GETSTRUCT(tup);
Oid otherid = form->roleid;
/*
* While otherid==InvalidOid shouldn't appear in the catalog, the
* OidIsValid() avoids crashing if that arises.
*/
if (otherid == admin_of && form->admin_option &&
OidIsValid(admin_of) && !OidIsValid(*admin_role))
*admin_role = memberid;
/* If we're supposed to ignore non-heritable grants, do so. */
if (type == ROLERECURSE_PRIVS && !form->inherit_option)
continue;
/* If we're supposed to ignore non-SET grants, do so. */
if (type == ROLERECURSE_SETROLE && !form->set_option)
continue;
/*
* Even though there shouldn't be any loops in the membership
* graph, we must test for having already seen this role. It is
* legal for instance to have both A->B and A->C->B.
*/
roles_list = roles_list_append(roles_list, &bf, otherid);
}
ReleaseSysCacheList(memlist);
/* implement pg_database_owner implicit membership */
if (memberid == dba && OidIsValid(dba))
roles_list = roles_list_append(roles_list, &bf,
ROLE_PG_DATABASE_OWNER);
}
/*
* Free the Bloom filter created by roles_list_append(), if there is one.
*/
if (bf)
bloom_free(bf);
/*
* Copy the completed list into TopMemoryContext so it will persist.
*/
oldctx = MemoryContextSwitchTo(TopMemoryContext);
new_cached_roles = list_copy(roles_list);
MemoryContextSwitchTo(oldctx);
list_free(roles_list);
/*
* Now safe to assign to state variable
*/
cached_role[type] = InvalidOid; /* just paranoia */
list_free(cached_roles[type]);
cached_roles[type] = new_cached_roles;
cached_role[type] = roleid;
/* And now we can return the answer */
return cached_roles[type];
}
遍历查找给定角色ID的所有直接和间接成员关系,并给cache赋值
更多推荐

所有评论(0)