*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.164 2010/03/06 23:10:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.165 2010/04/05 01:09:52 tgl Exp $
*
* NOTES
* See acl.h.
isNew = true;
}
- if (old_acl == NULL)
+ if (old_acl != NULL)
+ {
+ /*
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information. Collect data before
+ * merge_acl_with_grant throws away old_acl.
+ */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
+ else
{
/*
* If we are creating a global entry, start with the hard-wired
old_acl = acldefault(iacls->objtype, iacls->roleid);
else
old_acl = make_empty_acl();
- }
- /*
- * We need the members of both old and new ACLs so we can correct the
- * shared dependency information. Collect data before
- * merge_acl_with_grant throws away old_acl.
- */
- noldmembers = aclmembers(old_acl, &oldmembers);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
/*
* Generate new ACL. Grantor of rights is always the same as the target
nnewmembers = aclmembers(new_acl, &newmembers);
updateAclDependencies(DefaultAclRelationId, HeapTupleGetOid(newtuple), 0,
- iacls->roleid, iacls->is_grant,
+ iacls->roleid,
noldmembers, oldmembers,
nnewmembers, newmembers);
aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
&isNull);
if (isNull)
+ {
old_acl = acldefault(ACL_OBJECT_COLUMN, ownerId);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
else
+ {
old_acl = DatumGetAclPCopy(aclDatum);
+ /* Get the roles mentioned in the existing ACL */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
/*
* In select_best_grantor we should consider existing table-level ACL bits
/*
* Generate new ACL.
- *
- * We need the members of both old and new ACLs so we can correct the
- * shared dependency information.
*/
- noldmembers = aclmembers(old_acl, &oldmembers);
-
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option,
istmt->behavior, istmt->grantees,
col_privileges, grantorId,
ownerId);
+ /*
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid, attnum,
- ownerId, istmt->is_grant,
+ ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
}
bool have_col_privileges;
Acl *old_acl;
Acl *old_rel_acl;
+ int noldmembers;
+ Oid *oldmembers;
Oid ownerId;
HeapTuple tuple;
ListCell *cell_colprivs;
aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
&isNull);
if (isNull)
+ {
old_acl = acldefault(pg_class_tuple->relkind == RELKIND_SEQUENCE ?
ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION,
ownerId);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
else
+ {
old_acl = DatumGetAclPCopy(aclDatum);
+ /* Get the roles mentioned in the existing ACL */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
/* Need an extra copy of original rel ACL for column handling */
old_rel_acl = aclcopy(old_acl);
Datum values[Natts_pg_class];
bool nulls[Natts_pg_class];
bool replaces[Natts_pg_class];
- int noldmembers;
int nnewmembers;
- Oid *oldmembers;
Oid *newmembers;
/* Determine ID to do the grant as, and available grant options */
/*
* Generate new ACL.
- *
- * We need the members of both old and new ACLs so we can correct
- * the shared dependency information.
*/
- noldmembers = aclmembers(old_acl, &oldmembers);
-
new_acl = merge_acl_with_grant(old_acl,
istmt->is_grant,
istmt->grant_option,
grantorId,
ownerId);
+ /*
+ * We need the members of both old and new ACLs so we can correct
+ * the shared dependency information.
+ */
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid, 0,
- ownerId, istmt->is_grant,
+ ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
RelationGetDescr(relation), &isNull);
if (isNull)
+ {
old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
else
+ {
old_acl = DatumGetAclPCopy(aclDatum);
+ /* Get the roles mentioned in the existing ACL */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
/* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges,
/*
* Generate new ACL.
- *
- * We need the members of both old and new ACLs so we can correct the
- * shared dependency information.
*/
- noldmembers = aclmembers(old_acl, &oldmembers);
-
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges,
grantorId, ownerId);
+ /*
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), 0,
- ownerId, istmt->is_grant,
+ ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
Anum_pg_foreign_data_wrapper_fdwacl,
&isNull);
if (isNull)
+ {
old_acl = acldefault(ACL_OBJECT_FDW, ownerId);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
else
+ {
old_acl = DatumGetAclPCopy(aclDatum);
+ /* Get the roles mentioned in the existing ACL */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
/* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges,
/*
* Generate new ACL.
- *
- * We need the members of both old and new ACLs so we can correct the
- * shared dependency information.
*/
- noldmembers = aclmembers(old_acl, &oldmembers);
-
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges,
grantorId, ownerId);
+ /*
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
/* Update the shared dependency ACL info */
updateAclDependencies(ForeignDataWrapperRelationId,
HeapTupleGetOid(tuple), 0,
- ownerId, istmt->is_grant,
+ ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
Anum_pg_foreign_server_srvacl,
&isNull);
if (isNull)
+ {
old_acl = acldefault(ACL_OBJECT_FOREIGN_SERVER, ownerId);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
else
+ {
old_acl = DatumGetAclPCopy(aclDatum);
+ /* Get the roles mentioned in the existing ACL */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
/* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges,
/*
* Generate new ACL.
- *
- * We need the members of both old and new ACLs so we can correct the
- * shared dependency information.
*/
- noldmembers = aclmembers(old_acl, &oldmembers);
-
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges,
grantorId, ownerId);
+ /*
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
/* Update the shared dependency ACL info */
updateAclDependencies(ForeignServerRelationId,
HeapTupleGetOid(tuple), 0,
- ownerId, istmt->is_grant,
+ ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
&isNull);
if (isNull)
+ {
old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
else
+ {
old_acl = DatumGetAclPCopy(aclDatum);
+ /* Get the roles mentioned in the existing ACL */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
/* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges,
/*
* Generate new ACL.
- *
- * We need the members of both old and new ACLs so we can correct the
- * shared dependency information.
*/
- noldmembers = aclmembers(old_acl, &oldmembers);
-
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges,
grantorId, ownerId);
+ /*
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
/* Update the shared dependency ACL info */
updateAclDependencies(ProcedureRelationId, funcId, 0,
- ownerId, istmt->is_grant,
+ ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
&isNull);
if (isNull)
+ {
old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
else
+ {
old_acl = DatumGetAclPCopy(aclDatum);
+ /* Get the roles mentioned in the existing ACL */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
/* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges,
/*
* Generate new ACL.
- *
- * We need the members of both old and new ACLs so we can correct the
- * shared dependency information.
*/
- noldmembers = aclmembers(old_acl, &oldmembers);
-
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges,
grantorId, ownerId);
+ /*
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0,
- ownerId, istmt->is_grant,
+ ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
Anum_pg_largeobject_metadata_lomacl,
RelationGetDescr(relation), &isNull);
if (isNull)
+ {
old_acl = acldefault(ACL_OBJECT_LARGEOBJECT, ownerId);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
else
+ {
old_acl = DatumGetAclPCopy(aclDatum);
+ /* Get the roles mentioned in the existing ACL */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
/* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges,
/*
* Generate new ACL.
- *
- * We need the members of both old and new ACLs so we can correct the
- * shared dependency information.
*/
- noldmembers = aclmembers(old_acl, &oldmembers);
-
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges,
grantorId, ownerId);
+ /*
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
/* Update the shared dependency ACL info */
updateAclDependencies(LargeObjectRelationId,
HeapTupleGetOid(tuple), 0,
- ownerId, istmt->is_grant,
+ ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
Anum_pg_namespace_nspacl,
&isNull);
if (isNull)
+ {
old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
else
+ {
old_acl = DatumGetAclPCopy(aclDatum);
+ /* Get the roles mentioned in the existing ACL */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
/* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges,
/*
* Generate new ACL.
- *
- * We need the members of both old and new ACLs so we can correct the
- * shared dependency information.
*/
- noldmembers = aclmembers(old_acl, &oldmembers);
-
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges,
grantorId, ownerId);
+ /*
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0,
- ownerId, istmt->is_grant,
+ ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
RelationGetDescr(relation), &isNull);
if (isNull)
+ {
old_acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
+ /* There are no old member roles according to the catalogs */
+ noldmembers = 0;
+ oldmembers = NULL;
+ }
else
+ {
old_acl = DatumGetAclPCopy(aclDatum);
+ /* Get the roles mentioned in the existing ACL */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+ }
/* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges,
/*
* Generate new ACL.
- *
- * We need the members of both old and new ACLs so we can correct the
- * shared dependency information.
*/
- noldmembers = aclmembers(old_acl, &oldmembers);
-
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges,
grantorId, ownerId);
+ /*
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */
/* Update the shared dependency ACL info */
updateAclDependencies(TableSpaceRelationId, tblId, 0,
- ownerId, istmt->is_grant,
+ ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.40 2010/02/26 02:00:37 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.41 2010/04/05 01:09:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
REMOTE_OBJECT
} objectType;
-static int getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2,
- Oid **diff);
+static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2);
static Oid classIdGetDbId(Oid classId);
static void shdepChangeDep(Relation sdepRel,
Oid classid, Oid objid, int32 objsubid,
* getOidListDiff
* Helper for updateAclDependencies.
*
- * Takes two Oid arrays and returns elements from the first not found in the
- * second. We assume both arrays are sorted and de-duped, and that the
- * second array does not contain any values not found in the first.
- *
- * NOTE: Both input arrays are pfreed.
+ * Takes two Oid arrays and removes elements that are common to both arrays,
+ * leaving just those that are in one input but not the other.
+ * We assume both arrays have been sorted and de-duped.
*/
-static int
-getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff)
+static void
+getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
{
- Oid *result;
- int i,
- j,
- k = 0;
-
- AssertArg(nlist1 >= nlist2 && nlist2 >= 0);
+ int in1,
+ in2,
+ out1,
+ out2;
- result = palloc(sizeof(Oid) * (nlist1 - nlist2));
- *diff = result;
-
- for (i = 0, j = 0; i < nlist1 && j < nlist2;)
+ in1 = in2 = out1 = out2 = 0;
+ while (in1 < *nlist1 && in2 < *nlist2)
{
- if (list1[i] == list2[j])
+ if (list1[in1] == list2[in2])
{
- i++;
- j++;
+ /* skip over duplicates */
+ in1++;
+ in2++;
}
- else if (list1[i] < list2[j])
+ else if (list1[in1] < list2[in2])
{
- result[k++] = list1[i];
- i++;
+ /* list1[in1] is not in list2 */
+ list1[out1++] = list1[in1++];
}
else
{
- /* can't happen */
- elog(WARNING, "invalid element %u in shorter list", list2[j]);
- j++;
+ /* list2[in2] is not in list1 */
+ list2[out2++] = list2[in2++];
}
}
- for (; i < nlist1; i++)
- result[k++] = list1[i];
-
- /* We should have copied the exact number of elements */
- AssertState(k == (nlist1 - nlist2));
+ /* any remaining list1 entries are not in list2 */
+ while (in1 < *nlist1)
+ {
+ list1[out1++] = list1[in1++];
+ }
- if (list1)
- pfree(list1);
- if (list2)
- pfree(list2);
+ /* any remaining list2 entries are not in list1 */
+ while (in2 < *nlist2)
+ {
+ list2[out2++] = list2[in2++];
+ }
- return k;
+ *nlist1 = out1;
+ *nlist2 = out2;
}
/*
*
* classId, objectId, objsubId: 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.
+ * We calculate the differences between the new and old lists of roles,
+ * and then insert or delete 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 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. They are pfreed
- * before return.
+ * 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, bool isGrant,
+ Oid ownerId,
int noldmembers, Oid *oldmembers,
int nnewmembers, Oid *newmembers)
{
Relation sdepRel;
- Oid *diff;
- int ndiff,
- i;
+ int i;
/*
- * Calculate the differences between the old and new lists.
+ * 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.
*/
- if (isGrant)
- ndiff = getOidListDiff(newmembers, nnewmembers,
- oldmembers, noldmembers, &diff);
- else
- ndiff = getOidListDiff(oldmembers, noldmembers,
- newmembers, nnewmembers, &diff);
+ getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers);
- if (ndiff > 0)
+ if (noldmembers > 0 || nnewmembers > 0)
{
sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
- /* Add or drop the respective dependency */
- for (i = 0; i < ndiff; i++)
+ /* Add new dependencies that weren't already present */
+ for (i = 0; i < nnewmembers; i++)
{
- Oid roleid = diff[i];
+ Oid roleid = newmembers[i];
/*
* Skip the owner: he has an OWNER shdep entry instead. (This is
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;
- if (isGrant)
- shdepAddDependency(sdepRel, classId, objectId, objsubId,
- AuthIdRelationId, roleid,
- SHARED_DEPENDENCY_ACL);
- else
- shdepDropDependency(sdepRel, classId, objectId, objsubId,
- false, /* exact match on objsubId */
- AuthIdRelationId, roleid,
- SHARED_DEPENDENCY_ACL);
+ shdepDropDependency(sdepRel, classId, objectId, objsubId,
+ false, /* exact match on objsubId */
+ AuthIdRelationId, roleid,
+ SHARED_DEPENDENCY_ACL);
}
heap_close(sdepRel, RowExclusiveLock);
}
- pfree(diff);
+ if (oldmembers)
+ pfree(oldmembers);
+ if (newmembers)
+ pfree(newmembers);
}
/*