Beispiel #1
0
/*
 * updateAclDependencies
 *		Update the pg_shdepend info for an object's ACL during GRANT/REVOKE.
 *
 * classId, objectId: identify the object whose ACL this is
 * ownerId: role owning the object
 * isGrant: are we adding or removing ACL entries?
 * noldmembers, oldmembers: array of roleids appearing in old ACL
 * nnewmembers, newmembers: array of roleids appearing in new ACL
 *
 * We calculate the difference between the new and old lists of roles,
 * and then insert (if it's a grant) or delete (if it's a revoke) from
 * pg_shdepend as appropiate.
 *
 * Note that we can't insert blindly at grant, because we would end up with
 * duplicate registered dependencies.  We could check for existence of the
 * tuple before inserting, but that seems to be more expensive than what we are
 * doing now.  On the other hand, we can't just delete the tuples blindly at
 * revoke, because the user may still have other privileges.
 *
 * NOTE: Both input arrays must be sorted and de-duped.  They are pfreed
 * before return.
 */
void
updateAclDependencies(Oid classId, Oid objectId, Oid ownerId, bool isGrant,
					  int noldmembers, Oid *oldmembers,
					  int nnewmembers, Oid *newmembers)
{
	Relation	sdepRel;
	Oid		   *diff;
	int			ndiff,
				i;

	/*
	 * Calculate the differences between the old and new lists.
	 */
	if (isGrant)
		ndiff = getOidListDiff(newmembers, nnewmembers,
							   oldmembers, noldmembers, &diff);
	else
		ndiff = getOidListDiff(oldmembers, noldmembers,
							   newmembers, nnewmembers, &diff);

	if (ndiff > 0)
	{
		sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);

		/* Add or drop the respective dependency */
		for (i = 0; i < ndiff; i++)
		{
			Oid			roleid = diff[i];

			/*
			 * Skip the owner: he has an OWNER shdep entry instead. (This is
			 * not just a space optimization; it makes ALTER OWNER easier. See
			 * notes in changeDependencyOnOwner.)
			 */
			if (roleid == ownerId)
				continue;

			/* Skip pinned roles */
			if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
				continue;

			if (isGrant)
				shdepAddDependency(sdepRel, classId, objectId,
								   AuthIdRelationId, roleid,
								   SHARED_DEPENDENCY_ACL);
			else
				shdepDropDependency(sdepRel, classId, objectId,
									AuthIdRelationId, roleid,
									SHARED_DEPENDENCY_ACL);
		}

		heap_close(sdepRel, RowExclusiveLock);
	}

	pfree(diff);
}
Beispiel #2
0
/*
 * updateAclDependencies
 *		Update the pg_shdepend info for an object's ACL during GRANT/REVOKE.
 *
 * classId, objectId, objsubId: identify the object whose ACL this is
 * ownerId: role owning the object
 * noldmembers, oldmembers: array of roleids appearing in old ACL
 * nnewmembers, newmembers: array of roleids appearing in new ACL
 *
 * We calculate the differences between the new and old lists of roles,
 * and then insert or delete from pg_shdepend as appropriate.
 *
 * Note that we can't just insert all referenced roles blindly during GRANT,
 * because we would end up with duplicate registered dependencies.  We could
 * check for existence of the tuples before inserting, but that seems to be
 * more expensive than what we are doing here.  Likewise we can't just delete
 * blindly during REVOKE, because the user may still have other privileges.
 * It is also possible that REVOKE actually adds dependencies, due to
 * instantiation of a formerly implicit default ACL (although at present,
 * all such dependencies should be for the owning role, which we ignore here).
 *
 * NOTE: Both input arrays must be sorted and de-duped.  (Typically they
 * are extracted from an ACL array by aclmembers(), which takes care of
 * both requirements.)	The arrays are pfreed before return.
 */
void
updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
					  Oid ownerId,
					  int noldmembers, Oid *oldmembers,
					  int nnewmembers, Oid *newmembers)
{
	Relation	sdepRel;
	int			i;

	/*
	 * Remove entries that are common to both lists; those represent existing
	 * dependencies we don't need to change.
	 *
	 * OK to overwrite the inputs since we'll pfree them anyway.
	 */
	getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers);

	if (noldmembers > 0 || nnewmembers > 0)
	{
		sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);

		/* Add new dependencies that weren't already present */
		for (i = 0; i < nnewmembers; i++)
		{
			Oid			roleid = newmembers[i];

			/*
			 * Skip the owner: he has an OWNER shdep entry instead. (This is
			 * not just a space optimization; it makes ALTER OWNER easier. See
			 * notes in changeDependencyOnOwner.)
			 */
			if (roleid == ownerId)
				continue;

			/* Skip pinned roles; they don't need dependency entries */
			if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
				continue;

			shdepAddDependency(sdepRel, classId, objectId, objsubId,
							   AuthIdRelationId, roleid,
							   SHARED_DEPENDENCY_ACL);
		}

		/* Drop no-longer-used old dependencies */
		for (i = 0; i < noldmembers; i++)
		{
			Oid			roleid = oldmembers[i];

			/* Skip the owner, same as above */
			if (roleid == ownerId)
				continue;

			/* Skip pinned roles */
			if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
				continue;

			shdepDropDependency(sdepRel, classId, objectId, objsubId,
								false,	/* exact match on objsubId */
								AuthIdRelationId, roleid,
								SHARED_DEPENDENCY_ACL);
		}

		heap_close(sdepRel, RowExclusiveLock);
	}

	if (oldmembers)
		pfree(oldmembers);
	if (newmembers)
		pfree(newmembers);
}