Fix updateAclDependencies() to not assume that ACL role dependencies can only

be added during GRANT and can only be removed during REVOKE; and fix its
callers to not lie to it about the existing set of dependencies when
instantiating a formerly-default ACL.  The previous coding accidentally failed
to malfunction so long as default ACLs contain only references to the object's
owning role, because that role is ignored by updateAclDependencies.  However
this is obviously pretty fragile, as well as being an undocumented assumption.
The new coding is a few lines longer but IMO much clearer.
This commit is contained in:
Tom Lane 2010-04-05 01:09:53 +00:00
parent 80390f493a
commit 9029df17c4
5 changed files with 248 additions and 153 deletions

View File

@ -8,7 +8,7 @@
*
*
* 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.
@ -1142,7 +1142,16 @@ SetDefaultACL(InternalDefaultACL *iacls)
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
@ -1154,14 +1163,11 @@ SetDefaultACL(InternalDefaultACL *iacls)
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
@ -1236,7 +1242,7 @@ SetDefaultACL(InternalDefaultACL *iacls)
nnewmembers = aclmembers(new_acl, &newmembers);
updateAclDependencies(DefaultAclRelationId, HeapTupleGetOid(newtuple), 0,
iacls->roleid, iacls->is_grant,
iacls->roleid,
noldmembers, oldmembers,
nnewmembers, newmembers);
@ -1526,9 +1532,18 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
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
@ -1563,18 +1578,17 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
/*
* 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 */
@ -1613,7 +1627,7 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid, attnum,
ownerId, istmt->is_grant,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
}
@ -1648,6 +1662,8 @@ ExecGrant_Relation(InternalGrant *istmt)
bool have_col_privileges;
Acl *old_acl;
Acl *old_rel_acl;
int noldmembers;
Oid *oldmembers;
Oid ownerId;
HeapTuple tuple;
ListCell *cell_colprivs;
@ -1770,11 +1786,20 @@ ExecGrant_Relation(InternalGrant *istmt)
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);
@ -1791,9 +1816,7 @@ ExecGrant_Relation(InternalGrant *istmt)
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 */
@ -1816,12 +1839,7 @@ ExecGrant_Relation(InternalGrant *istmt)
/*
* 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,
@ -1831,6 +1849,10 @@ ExecGrant_Relation(InternalGrant *istmt)
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 */
@ -1851,7 +1873,7 @@ ExecGrant_Relation(InternalGrant *istmt)
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid, 0,
ownerId, istmt->is_grant,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
@ -1980,9 +2002,18 @@ ExecGrant_Database(InternalGrant *istmt)
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,
@ -2002,17 +2033,16 @@ ExecGrant_Database(InternalGrant *istmt)
/*
* 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 */
@ -2033,7 +2063,7 @@ ExecGrant_Database(InternalGrant *istmt)
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
@ -2097,9 +2127,18 @@ ExecGrant_Fdw(InternalGrant *istmt)
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,
@ -2119,17 +2158,16 @@ ExecGrant_Fdw(InternalGrant *istmt)
/*
* 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 */
@ -2151,7 +2189,7 @@ ExecGrant_Fdw(InternalGrant *istmt)
/* Update the shared dependency ACL info */
updateAclDependencies(ForeignDataWrapperRelationId,
HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
@ -2214,9 +2252,18 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
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,
@ -2236,17 +2283,16 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
/*
* 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 */
@ -2268,7 +2314,7 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
/* Update the shared dependency ACL info */
updateAclDependencies(ForeignServerRelationId,
HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
@ -2330,9 +2376,18 @@ ExecGrant_Function(InternalGrant *istmt)
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,
@ -2352,17 +2407,16 @@ ExecGrant_Function(InternalGrant *istmt)
/*
* 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 */
@ -2383,7 +2437,7 @@ ExecGrant_Function(InternalGrant *istmt)
/* Update the shared dependency ACL info */
updateAclDependencies(ProcedureRelationId, funcId, 0,
ownerId, istmt->is_grant,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
@ -2452,9 +2506,18 @@ ExecGrant_Language(InternalGrant *istmt)
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,
@ -2474,17 +2537,16 @@ ExecGrant_Language(InternalGrant *istmt)
/*
* 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 */
@ -2505,7 +2567,7 @@ ExecGrant_Language(InternalGrant *istmt)
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
@ -2582,9 +2644,18 @@ ExecGrant_Largeobject(InternalGrant *istmt)
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,
@ -2604,17 +2675,16 @@ ExecGrant_Largeobject(InternalGrant *istmt)
/*
* 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 */
@ -2637,7 +2707,7 @@ ExecGrant_Largeobject(InternalGrant *istmt)
/* Update the shared dependency ACL info */
updateAclDependencies(LargeObjectRelationId,
HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
@ -2700,9 +2770,18 @@ ExecGrant_Namespace(InternalGrant *istmt)
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,
@ -2722,17 +2801,16 @@ ExecGrant_Namespace(InternalGrant *istmt)
/*
* 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 */
@ -2753,7 +2831,7 @@ ExecGrant_Namespace(InternalGrant *istmt)
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
@ -2816,9 +2894,18 @@ ExecGrant_Tablespace(InternalGrant *istmt)
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,
@ -2838,17 +2925,16 @@ ExecGrant_Tablespace(InternalGrant *istmt)
/*
* 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 */
@ -2869,7 +2955,7 @@ ExecGrant_Tablespace(InternalGrant *istmt)
/* Update the shared dependency ACL info */
updateAclDependencies(TableSpaceRelationId, tblId, 0,
ownerId, istmt->is_grant,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.372 2010/02/26 02:00:36 momjian Exp $
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.373 2010/04/05 01:09:52 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -1160,7 +1160,7 @@ heap_create_with_catalog(const char *relname,
nnewmembers = aclmembers(relacl, &newmembers);
updateAclDependencies(RelationRelationId, relid, 0,
ownerid, true,
ownerid,
0, NULL,
nnewmembers, newmembers);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.173 2010/03/19 22:54:40 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.174 2010/04/05 01:09:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -609,7 +609,7 @@ ProcedureCreate(const char *procedureName,
nnewmembers = aclmembers(proacl, &newmembers);
updateAclDependencies(ProcedureRelationId, retval, 0,
proowner, true,
proowner,
0, NULL,
nnewmembers, newmembers);
}

View File

@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -54,8 +54,7 @@ typedef enum
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,
@ -328,57 +327,53 @@ changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
* 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;
int in1,
in2,
out1,
out2;
AssertArg(nlist1 >= nlist2 && nlist2 >= 0);
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];
/* any remaining list1 entries are not in list2 */
while (in1 < *nlist1)
{
list1[out1++] = list1[in1++];
}
/* We should have copied the exact number of elements */
AssertState(k == (nlist1 - nlist2));
/* any remaining list2 entries are not in list1 */
while (in2 < *nlist2)
{
list2[out2++] = list2[in2++];
}
if (list1)
pfree(list1);
if (list2)
pfree(list2);
return k;
*nlist1 = out1;
*nlist2 = out2;
}
/*
@ -387,52 +382,50 @@ getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff)
*
* 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
@ -442,25 +435,41 @@ updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
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);
}
/*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.44 2010/01/02 16:58:01 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.45 2010/04/05 01:09:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -232,7 +232,7 @@ extern void changeDependencyOnOwner(Oid classId, Oid objectId,
Oid newOwnerId);
extern void updateAclDependencies(Oid classId, Oid objectId, int32 objectSubId,
Oid ownerId, bool isGrant,
Oid ownerId,
int noldmembers, Oid *oldmembers,
int nnewmembers, Oid *newmembers);