ACL权限 (对象访问权限)

在这里插入图片描述
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e6dd995f1c734e52ab69a0f054a20be1.png
在这里插入图片描述

以上为执行权限的种类以及适用对象合在系统表中显示的缩写
在这里插入图片描述
对象可赋予的访问权限

用户权限

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赋值

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐