⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 acl.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
 */Acl *acldefault(GrantObjectType objtype, Oid ownerId){	AclMode		world_default;	AclMode		owner_default;	Acl		   *acl;	AclItem    *aip;	switch (objtype)	{		case ACL_OBJECT_RELATION:			world_default = ACL_NO_RIGHTS;			owner_default = ACL_ALL_RIGHTS_RELATION;			break;		case ACL_OBJECT_DATABASE:			world_default = ACL_CREATE_TEMP;	/* not NO_RIGHTS! */			owner_default = ACL_ALL_RIGHTS_DATABASE;			break;		case ACL_OBJECT_FUNCTION:			/* Grant EXECUTE by default, for now */			world_default = ACL_EXECUTE;			owner_default = ACL_ALL_RIGHTS_FUNCTION;			break;		case ACL_OBJECT_LANGUAGE:			/* Grant USAGE by default, for now */			world_default = ACL_USAGE;			owner_default = ACL_ALL_RIGHTS_LANGUAGE;			break;		case ACL_OBJECT_NAMESPACE:			world_default = ACL_NO_RIGHTS;			owner_default = ACL_ALL_RIGHTS_NAMESPACE;			break;		case ACL_OBJECT_TABLESPACE:			world_default = ACL_NO_RIGHTS;			owner_default = ACL_ALL_RIGHTS_TABLESPACE;			break;		default:			elog(ERROR, "unrecognized objtype: %d", (int) objtype);			world_default = ACL_NO_RIGHTS;		/* keep compiler quiet */			owner_default = ACL_NO_RIGHTS;			break;	}	acl = allocacl((world_default != ACL_NO_RIGHTS) ? 2 : 1);	aip = ACL_DAT(acl);	if (world_default != ACL_NO_RIGHTS)	{		aip->ai_grantee = ACL_ID_PUBLIC;		aip->ai_grantor = ownerId;		ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);		aip++;	}	/*	 * Note that the owner's entry shows all ordinary privileges but no grant	 * options.  This is because his grant options come "from the system" and	 * not from his own efforts.  (The SQL spec says that the owner's rights	 * come from a "_SYSTEM" authid.)  However, we do consider that the	 * owner's ordinary privileges are self-granted; this lets him revoke	 * them.  We implement the owner's grant options without any explicit	 * "_SYSTEM"-like ACL entry, by internally special-casing the owner	 * whereever we are testing grant options.	 */	aip->ai_grantee = ownerId;	aip->ai_grantor = ownerId;	ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);	return acl;}/* * Update an ACL array to add or remove specified privileges. * *	old_acl: the input ACL array *	mod_aip: defines the privileges to be added, removed, or substituted *	modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL *	ownerId: Oid of object owner *	behavior: RESTRICT or CASCADE behavior for recursive removal * * ownerid and behavior are only relevant when the update operation specifies * deletion of grant options. * * The result is a modified copy; the input object is not changed. * * NB: caller is responsible for having detoasted the input ACL, if needed. */Acl *aclupdate(const Acl *old_acl, const AclItem *mod_aip,		  int modechg, Oid ownerId, DropBehavior behavior){	Acl		   *new_acl = NULL;	AclItem    *old_aip,			   *new_aip = NULL;	AclMode		old_rights,				old_goptions,				new_rights,				new_goptions;	int			dst,				num;	/* These checks for null input are probably dead code, but... */	if (!old_acl || ACL_NUM(old_acl) < 0)		old_acl = allocacl(0);	if (!mod_aip)	{		new_acl = allocacl(ACL_NUM(old_acl));		memcpy(new_acl, old_acl, ACL_SIZE(old_acl));		return new_acl;	}	/* If granting grant options, check for circularity */	if (modechg != ACL_MODECHG_DEL &&		ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)		check_circularity(old_acl, mod_aip, ownerId);	num = ACL_NUM(old_acl);	old_aip = ACL_DAT(old_acl);	/*	 * Search the ACL for an existing entry for this grantee and grantor. If	 * one exists, just modify the entry in-place (well, in the same position,	 * since we actually return a copy); otherwise, insert the new entry at	 * the end.	 */	for (dst = 0; dst < num; ++dst)	{		if (aclitem_match(mod_aip, old_aip + dst))		{			/* found a match, so modify existing item */			new_acl = allocacl(num);			new_aip = ACL_DAT(new_acl);			memcpy(new_acl, old_acl, ACL_SIZE(old_acl));			break;		}	}	if (dst == num)	{		/* need to append a new item */		new_acl = allocacl(num + 1);		new_aip = ACL_DAT(new_acl);		memcpy(new_aip, old_aip, num * sizeof(AclItem));		/* initialize the new entry with no permissions */		new_aip[dst].ai_grantee = mod_aip->ai_grantee;		new_aip[dst].ai_grantor = mod_aip->ai_grantor;		ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],								   ACL_NO_RIGHTS, ACL_NO_RIGHTS);		num++;					/* set num to the size of new_acl */	}	old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);	old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);	/* apply the specified permissions change */	switch (modechg)	{		case ACL_MODECHG_ADD:			ACLITEM_SET_RIGHTS(new_aip[dst],							   old_rights | ACLITEM_GET_RIGHTS(*mod_aip));			break;		case ACL_MODECHG_DEL:			ACLITEM_SET_RIGHTS(new_aip[dst],							   old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));			break;		case ACL_MODECHG_EQL:			ACLITEM_SET_RIGHTS(new_aip[dst],							   ACLITEM_GET_RIGHTS(*mod_aip));			break;	}	new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);	new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);	/*	 * If the adjusted entry has no permissions, delete it from the list.	 */	if (new_rights == ACL_NO_RIGHTS)	{		memmove(new_aip + dst,				new_aip + dst + 1,				(num - dst - 1) * sizeof(AclItem));		ARR_DIMS(new_acl)[0] = num - 1;		ARR_SIZE(new_acl) -= sizeof(AclItem);	}	/*	 * Remove abandoned privileges (cascading revoke).	Currently we can only	 * handle this when the grantee is not PUBLIC.	 */	if ((old_goptions & ~new_goptions) != 0)	{		Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);		new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,								   (old_goptions & ~new_goptions),								   ownerId, behavior);	}	return new_acl;}/* * Update an ACL array to reflect a change of owner to the parent object * *	old_acl: the input ACL array (must not be NULL) *	oldOwnerId: Oid of the old object owner *	newOwnerId: Oid of the new object owner * * The result is a modified copy; the input object is not changed. * * NB: caller is responsible for having detoasted the input ACL, if needed. */Acl *aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId){	Acl		   *new_acl;	AclItem    *new_aip;	AclItem    *old_aip;	AclItem    *dst_aip;	AclItem    *src_aip;	AclItem    *targ_aip;	bool		newpresent = false;	int			dst,				src,				targ,				num;	/*	 * Make a copy of the given ACL, substituting new owner ID for old	 * wherever it appears as either grantor or grantee.  Also note if the new	 * owner ID is already present.	 */	num = ACL_NUM(old_acl);	old_aip = ACL_DAT(old_acl);	new_acl = allocacl(num);	new_aip = ACL_DAT(new_acl);	memcpy(new_aip, old_aip, num * sizeof(AclItem));	for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)	{		if (dst_aip->ai_grantor == oldOwnerId)			dst_aip->ai_grantor = newOwnerId;		else if (dst_aip->ai_grantor == newOwnerId)			newpresent = true;		if (dst_aip->ai_grantee == oldOwnerId)			dst_aip->ai_grantee = newOwnerId;		else if (dst_aip->ai_grantee == newOwnerId)			newpresent = true;	}	/*	 * If the old ACL contained any references to the new owner, then we may	 * now have generated an ACL containing duplicate entries.	Find them and	 * merge them so that there are not duplicates.  (This is relatively	 * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to	 * be the normal case.)	 *	 * To simplify deletion of duplicate entries, we temporarily leave them in	 * the array but set their privilege masks to zero; when we reach such an	 * entry it's just skipped.  (Thus, a side effect of this code will be to	 * remove privilege-free entries, should there be any in the input.)  dst	 * is the next output slot, targ is the currently considered input slot	 * (always >= dst), and src scans entries to the right of targ looking for	 * duplicates.	Once an entry has been emitted to dst it is known	 * duplicate-free and need not be considered anymore.	 */	if (newpresent)	{		dst = 0;		for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)		{			/* ignore if deleted in an earlier pass */			if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)				continue;			/* find and merge any duplicates */			for (src = targ + 1, src_aip = targ_aip + 1; src < num;				 src++, src_aip++)			{				if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)					continue;				if (aclitem_match(targ_aip, src_aip))				{					ACLITEM_SET_RIGHTS(*targ_aip,									   ACLITEM_GET_RIGHTS(*targ_aip) |									   ACLITEM_GET_RIGHTS(*src_aip));					/* mark the duplicate deleted */					ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);				}			}			/* and emit to output */			new_aip[dst] = *targ_aip;			dst++;		}		/* Adjust array size to be 'dst' items */		ARR_DIMS(new_acl)[0] = dst;		ARR_SIZE(new_acl) = ACL_N_SIZE(dst);	}	return new_acl;}/* * When granting grant options, we must disallow attempts to set up circular * chains of grant options.  Suppose A (the object owner) grants B some * privileges with grant option, and B re-grants them to C.  If C could * grant the privileges to B as well, then A would be unable to effectively * revoke the privileges from B, since recursive_revoke would consider that * B still has 'em from C. * * We check for this by recursively deleting all grant options belonging to * the target grantee, and then seeing if the would-be grantor still has the * grant option or not. */static voidcheck_circularity(const Acl *old_acl, const AclItem *mod_aip,				  Oid ownerId){	Acl		   *acl;	AclItem    *aip;	int			i,				num;	AclMode		own_privs;	/*	 * For now, grant options can only be granted to roles, not PUBLIC.	 * Otherwise we'd have to work a bit harder here.	 */	Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);	/* The owner always has grant options, no need to check */	if (mod_aip->ai_grantor == ownerId)		return;	/* Make a working copy */	acl = allocacl(ACL_NUM(old_acl));	memcpy(acl, old_acl, ACL_SIZE(old_acl));	/* Zap all grant options of target grantee, plus what depends on 'em */cc_restart:	num = ACL_NUM(acl);	aip = ACL_DAT(acl);	for (i = 0; i < num; i++)	{		if (aip[i].ai_grantee == mod_aip->ai_grantee &&			ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)		{			Acl		   *new_acl;			/* We'll actually zap ordinary privs too, but no matter */			new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,								ownerId, DROP_CASCADE);			pfree(acl);			acl = new_acl;			goto cc_restart;		}	}	/* Now we can compute grantor's independently-derived privileges */	own_privs = aclmask(acl,						mod_aip->ai_grantor,						ownerId,						ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),						ACLMASK_ALL);	own_privs = ACL_OPTION_TO_PRIVS(own_privs);	if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)		ereport(ERROR,				(errcode(ERRCODE_INVALID_GRANT_OPERATION),		errmsg("grant options cannot be granted back to your own grantor")));	pfree(acl);}/* * Ensure that no privilege is "abandoned".  A privilege is abandoned * if the user that granted the privilege loses the grant option.  (So * the chain through which it was granted is broken.)  Either the * abandoned privileges are revoked as well, or an error message is * printed, depending on the drop behavior option. * *	acl: the input ACL list *	grantee: the user from whom some grant options have been revoked *	revoke_privs: the grant options being revoked *	ownerId: Oid of object owner *	behavior: RESTRICT or CASCADE behavior for recursive removal * * The input Acl object is pfree'd if replaced. */static Acl *recursive_revoke(Acl *acl,				 Oid grantee,				 AclMode revoke_privs,				 Oid ownerId,				 DropBehavior behavior){	AclMode		still_has;	AclItem    *aip;	int			i,				num;	/* The owner can never truly lose grant options, so short-circuit */	if (grantee == ownerId)		return acl;	/* The grantee might still have the privileges via another grantor */	still_has = aclmask(acl, grantee, ownerId,						ACL_GRANT_OPTION_FOR(revoke_privs),						ACLMASK_ALL);	revoke_privs &= ~still_has;	if (revoke_privs == ACL_NO_RIGHTS)		return acl;restart:	num = ACL_NUM(acl);	aip = ACL_DAT(acl);	for (i = 0; i < num; i++)	{		if (aip[i].ai_grantor == grantee			&& (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)		{			AclItem		mod_acl;			Acl		   *new_acl;			if (behavior == DROP_RESTRICT)				ereport(ERROR,						(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),						 errmsg("dependent privileges exist"),						 errhint("Use CASCADE to revoke them too.")));			mod_acl.ai_grantor = grantee;			mod_acl.ai_grantee = aip[i].ai_grantee;			ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,									   revoke_privs,									   revoke_privs);			new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,								ownerId, behavior);			pfree(acl);			acl = new_acl;			goto restart;		}	}	return acl;}/* * aclmask --- compute bitmask of all privileges held by roleid. * * When 'how' = ACLMASK_ALL, this simply returns the privilege bits * held by the given roleid according to the given ACL list, ANDed * with 'mask'.  (The point of passing 'mask' is to let the routine * exit early if all privileges of interest have been found.) * * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask * is known true.  (This lets us exit soonest in cases where the * caller is only going to test for zero or nonzero result.) * * Usage patterns: * * To see if any of a set of privileges are held: *		if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0) * * To see if all of a set of privileges are held: *		if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs) * * To determine exactly which of a set of privileges are held: *		heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL); */AclModeaclmask(const Acl *acl, Oid roleid, Oid ownerId,		AclMode mask, AclMaskHow how){	AclMode		result;	AclMode		remaining;	AclItem    *aidat;	int			i,				num;	/*	 * Null ACL should not happen, since caller should have inserted	 * appropriate default	 */	if (acl == NULL)		elog(ERROR, "null ACL");	/* Quick exit for mask == 0 */	if (mask == 0)		return 0;	result = 0;	/* Owner always implicitly has all grant options */	if ((mask & ACLITEM_ALL_GOPTION_BITS) &&		has_privs_of_role(roleid, ownerId))	{		result = mask & ACLITEM_ALL_GOPTION_BITS;		if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))			return result;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -