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 * 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 * NOTES
* See acl.h. * See acl.h.
@ -1142,7 +1142,16 @@ SetDefaultACL(InternalDefaultACL *iacls)
isNew = true; 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 * 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); old_acl = acldefault(iacls->objtype, iacls->roleid);
else else
old_acl = make_empty_acl(); old_acl = make_empty_acl();
}
/* /* There are no old member roles according to the catalogs */
* We need the members of both old and new ACLs so we can correct the noldmembers = 0;
* shared dependency information. Collect data before oldmembers = NULL;
* merge_acl_with_grant throws away old_acl. }
*/
noldmembers = aclmembers(old_acl, &oldmembers);
/* /*
* Generate new ACL. Grantor of rights is always the same as the target * 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); nnewmembers = aclmembers(new_acl, &newmembers);
updateAclDependencies(DefaultAclRelationId, HeapTupleGetOid(newtuple), 0, updateAclDependencies(DefaultAclRelationId, HeapTupleGetOid(newtuple), 0,
iacls->roleid, iacls->is_grant, iacls->roleid,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);
@ -1526,9 +1532,18 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl, aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
&isNull); &isNull);
if (isNull) if (isNull)
{
old_acl = acldefault(ACL_OBJECT_COLUMN, ownerId); old_acl = acldefault(ACL_OBJECT_COLUMN, ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else else
{
old_acl = DatumGetAclPCopy(aclDatum); 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 * 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. * 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, new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->grant_option,
istmt->behavior, istmt->grantees, istmt->behavior, istmt->grantees,
col_privileges, grantorId, col_privileges, grantorId,
ownerId); ownerId);
/*
* We need the members of both old and new ACLs so we can correct the
* shared dependency information.
*/
nnewmembers = aclmembers(new_acl, &newmembers); nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */ /* 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 */ /* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid, attnum, updateAclDependencies(RelationRelationId, relOid, attnum,
ownerId, istmt->is_grant, ownerId,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);
} }
@ -1648,6 +1662,8 @@ ExecGrant_Relation(InternalGrant *istmt)
bool have_col_privileges; bool have_col_privileges;
Acl *old_acl; Acl *old_acl;
Acl *old_rel_acl; Acl *old_rel_acl;
int noldmembers;
Oid *oldmembers;
Oid ownerId; Oid ownerId;
HeapTuple tuple; HeapTuple tuple;
ListCell *cell_colprivs; ListCell *cell_colprivs;
@ -1770,11 +1786,20 @@ ExecGrant_Relation(InternalGrant *istmt)
aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
&isNull); &isNull);
if (isNull) if (isNull)
{
old_acl = acldefault(pg_class_tuple->relkind == RELKIND_SEQUENCE ? old_acl = acldefault(pg_class_tuple->relkind == RELKIND_SEQUENCE ?
ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION, ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION,
ownerId); ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else else
{
old_acl = DatumGetAclPCopy(aclDatum); 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 */ /* Need an extra copy of original rel ACL for column handling */
old_rel_acl = aclcopy(old_acl); old_rel_acl = aclcopy(old_acl);
@ -1791,9 +1816,7 @@ ExecGrant_Relation(InternalGrant *istmt)
Datum values[Natts_pg_class]; Datum values[Natts_pg_class];
bool nulls[Natts_pg_class]; bool nulls[Natts_pg_class];
bool replaces[Natts_pg_class]; bool replaces[Natts_pg_class];
int noldmembers;
int nnewmembers; int nnewmembers;
Oid *oldmembers;
Oid *newmembers; Oid *newmembers;
/* Determine ID to do the grant as, and available grant options */ /* Determine ID to do the grant as, and available grant options */
@ -1816,12 +1839,7 @@ ExecGrant_Relation(InternalGrant *istmt)
/* /*
* Generate new ACL. * 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, new_acl = merge_acl_with_grant(old_acl,
istmt->is_grant, istmt->is_grant,
istmt->grant_option, istmt->grant_option,
@ -1831,6 +1849,10 @@ ExecGrant_Relation(InternalGrant *istmt)
grantorId, grantorId,
ownerId); ownerId);
/*
* We need the members of both old and new ACLs so we can correct
* the shared dependency information.
*/
nnewmembers = aclmembers(new_acl, &newmembers); nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
@ -1851,7 +1873,7 @@ ExecGrant_Relation(InternalGrant *istmt)
/* Update the shared dependency ACL info */ /* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid, 0, updateAclDependencies(RelationRelationId, relOid, 0,
ownerId, istmt->is_grant, ownerId,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);
@ -1980,9 +2002,18 @@ ExecGrant_Database(InternalGrant *istmt)
aclDatum = heap_getattr(tuple, Anum_pg_database_datacl, aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
RelationGetDescr(relation), &isNull); RelationGetDescr(relation), &isNull);
if (isNull) if (isNull)
{
old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId); old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else else
{
old_acl = DatumGetAclPCopy(aclDatum); 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 */ /* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges, select_best_grantor(GetUserId(), istmt->privileges,
@ -2002,17 +2033,16 @@ ExecGrant_Database(InternalGrant *istmt)
/* /*
* Generate new ACL. * 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, new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior, istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges, istmt->grantees, this_privileges,
grantorId, ownerId); 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); nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
@ -2033,7 +2063,7 @@ ExecGrant_Database(InternalGrant *istmt)
/* Update the shared dependency ACL info */ /* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), 0, updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant, ownerId,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);
@ -2097,9 +2127,18 @@ ExecGrant_Fdw(InternalGrant *istmt)
Anum_pg_foreign_data_wrapper_fdwacl, Anum_pg_foreign_data_wrapper_fdwacl,
&isNull); &isNull);
if (isNull) if (isNull)
{
old_acl = acldefault(ACL_OBJECT_FDW, ownerId); old_acl = acldefault(ACL_OBJECT_FDW, ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else else
{
old_acl = DatumGetAclPCopy(aclDatum); 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 */ /* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges, select_best_grantor(GetUserId(), istmt->privileges,
@ -2119,17 +2158,16 @@ ExecGrant_Fdw(InternalGrant *istmt)
/* /*
* Generate new ACL. * 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, new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior, istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges, istmt->grantees, this_privileges,
grantorId, ownerId); 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); nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
@ -2151,7 +2189,7 @@ ExecGrant_Fdw(InternalGrant *istmt)
/* Update the shared dependency ACL info */ /* Update the shared dependency ACL info */
updateAclDependencies(ForeignDataWrapperRelationId, updateAclDependencies(ForeignDataWrapperRelationId,
HeapTupleGetOid(tuple), 0, HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant, ownerId,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);
@ -2214,9 +2252,18 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
Anum_pg_foreign_server_srvacl, Anum_pg_foreign_server_srvacl,
&isNull); &isNull);
if (isNull) if (isNull)
{
old_acl = acldefault(ACL_OBJECT_FOREIGN_SERVER, ownerId); old_acl = acldefault(ACL_OBJECT_FOREIGN_SERVER, ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else else
{
old_acl = DatumGetAclPCopy(aclDatum); 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 */ /* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges, select_best_grantor(GetUserId(), istmt->privileges,
@ -2236,17 +2283,16 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
/* /*
* Generate new ACL. * 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, new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior, istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges, istmt->grantees, this_privileges,
grantorId, ownerId); 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); nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
@ -2268,7 +2314,7 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
/* Update the shared dependency ACL info */ /* Update the shared dependency ACL info */
updateAclDependencies(ForeignServerRelationId, updateAclDependencies(ForeignServerRelationId,
HeapTupleGetOid(tuple), 0, HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant, ownerId,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);
@ -2330,9 +2376,18 @@ ExecGrant_Function(InternalGrant *istmt)
aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
&isNull); &isNull);
if (isNull) if (isNull)
{
old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId); old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else else
{
old_acl = DatumGetAclPCopy(aclDatum); 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 */ /* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges, select_best_grantor(GetUserId(), istmt->privileges,
@ -2352,17 +2407,16 @@ ExecGrant_Function(InternalGrant *istmt)
/* /*
* Generate new ACL. * 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, new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior, istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges, istmt->grantees, this_privileges,
grantorId, ownerId); 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); nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
@ -2383,7 +2437,7 @@ ExecGrant_Function(InternalGrant *istmt)
/* Update the shared dependency ACL info */ /* Update the shared dependency ACL info */
updateAclDependencies(ProcedureRelationId, funcId, 0, updateAclDependencies(ProcedureRelationId, funcId, 0,
ownerId, istmt->is_grant, ownerId,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);
@ -2452,9 +2506,18 @@ ExecGrant_Language(InternalGrant *istmt)
aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl, aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
&isNull); &isNull);
if (isNull) if (isNull)
{
old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId); old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else else
{
old_acl = DatumGetAclPCopy(aclDatum); 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 */ /* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges, select_best_grantor(GetUserId(), istmt->privileges,
@ -2474,17 +2537,16 @@ ExecGrant_Language(InternalGrant *istmt)
/* /*
* Generate new ACL. * 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, new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior, istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges, istmt->grantees, this_privileges,
grantorId, ownerId); 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); nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
@ -2505,7 +2567,7 @@ ExecGrant_Language(InternalGrant *istmt)
/* Update the shared dependency ACL info */ /* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0, updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant, ownerId,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);
@ -2582,9 +2644,18 @@ ExecGrant_Largeobject(InternalGrant *istmt)
Anum_pg_largeobject_metadata_lomacl, Anum_pg_largeobject_metadata_lomacl,
RelationGetDescr(relation), &isNull); RelationGetDescr(relation), &isNull);
if (isNull) if (isNull)
{
old_acl = acldefault(ACL_OBJECT_LARGEOBJECT, ownerId); old_acl = acldefault(ACL_OBJECT_LARGEOBJECT, ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else else
{
old_acl = DatumGetAclPCopy(aclDatum); 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 */ /* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges, select_best_grantor(GetUserId(), istmt->privileges,
@ -2604,17 +2675,16 @@ ExecGrant_Largeobject(InternalGrant *istmt)
/* /*
* Generate new ACL. * 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, new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior, istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges, istmt->grantees, this_privileges,
grantorId, ownerId); 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); nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
@ -2637,7 +2707,7 @@ ExecGrant_Largeobject(InternalGrant *istmt)
/* Update the shared dependency ACL info */ /* Update the shared dependency ACL info */
updateAclDependencies(LargeObjectRelationId, updateAclDependencies(LargeObjectRelationId,
HeapTupleGetOid(tuple), 0, HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant, ownerId,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);
@ -2700,9 +2770,18 @@ ExecGrant_Namespace(InternalGrant *istmt)
Anum_pg_namespace_nspacl, Anum_pg_namespace_nspacl,
&isNull); &isNull);
if (isNull) if (isNull)
{
old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId); old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else else
{
old_acl = DatumGetAclPCopy(aclDatum); 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 */ /* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges, select_best_grantor(GetUserId(), istmt->privileges,
@ -2722,17 +2801,16 @@ ExecGrant_Namespace(InternalGrant *istmt)
/* /*
* Generate new ACL. * 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, new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior, istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges, istmt->grantees, this_privileges,
grantorId, ownerId); 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); nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
@ -2753,7 +2831,7 @@ ExecGrant_Namespace(InternalGrant *istmt)
/* Update the shared dependency ACL info */ /* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0, updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0,
ownerId, istmt->is_grant, ownerId,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);
@ -2816,9 +2894,18 @@ ExecGrant_Tablespace(InternalGrant *istmt)
aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl, aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
RelationGetDescr(relation), &isNull); RelationGetDescr(relation), &isNull);
if (isNull) if (isNull)
{
old_acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId); old_acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else else
{
old_acl = DatumGetAclPCopy(aclDatum); 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 */ /* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges, select_best_grantor(GetUserId(), istmt->privileges,
@ -2838,17 +2925,16 @@ ExecGrant_Tablespace(InternalGrant *istmt)
/* /*
* Generate new ACL. * 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, new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior, istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges, istmt->grantees, this_privileges,
grantorId, ownerId); 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); nnewmembers = aclmembers(new_acl, &newmembers);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
@ -2869,7 +2955,7 @@ ExecGrant_Tablespace(InternalGrant *istmt)
/* Update the shared dependency ACL info */ /* Update the shared dependency ACL info */
updateAclDependencies(TableSpaceRelationId, tblId, 0, updateAclDependencies(TableSpaceRelationId, tblId, 0,
ownerId, istmt->is_grant, ownerId,
noldmembers, oldmembers, noldmembers, oldmembers,
nnewmembers, newmembers); nnewmembers, newmembers);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
@ -1160,7 +1160,7 @@ heap_create_with_catalog(const char *relname,
nnewmembers = aclmembers(relacl, &newmembers); nnewmembers = aclmembers(relacl, &newmembers);
updateAclDependencies(RelationRelationId, relid, 0, updateAclDependencies(RelationRelationId, relid, 0,
ownerid, true, ownerid,
0, NULL, 0, NULL,
nnewmembers, newmembers); nnewmembers, newmembers);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); nnewmembers = aclmembers(proacl, &newmembers);
updateAclDependencies(ProcedureRelationId, retval, 0, updateAclDependencies(ProcedureRelationId, retval, 0,
proowner, true, proowner,
0, NULL, 0, NULL,
nnewmembers, newmembers); nnewmembers, newmembers);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 REMOTE_OBJECT
} objectType; } objectType;
static int getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2);
Oid **diff);
static Oid classIdGetDbId(Oid classId); static Oid classIdGetDbId(Oid classId);
static void shdepChangeDep(Relation sdepRel, static void shdepChangeDep(Relation sdepRel,
Oid classid, Oid objid, int32 objsubid, Oid classid, Oid objid, int32 objsubid,
@ -328,57 +327,53 @@ changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
* getOidListDiff * getOidListDiff
* Helper for updateAclDependencies. * Helper for updateAclDependencies.
* *
* Takes two Oid arrays and returns elements from the first not found in the * Takes two Oid arrays and removes elements that are common to both arrays,
* second. We assume both arrays are sorted and de-duped, and that the * leaving just those that are in one input but not the other.
* second array does not contain any values not found in the first. * We assume both arrays have been sorted and de-duped.
*
* NOTE: Both input arrays are pfreed.
*/ */
static int static void
getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff) getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
{ {
Oid *result; int in1,
int i, in2,
j, out1,
k = 0; out2;
AssertArg(nlist1 >= nlist2 && nlist2 >= 0); in1 = in2 = out1 = out2 = 0;
while (in1 < *nlist1 && in2 < *nlist2)
result = palloc(sizeof(Oid) * (nlist1 - nlist2));
*diff = result;
for (i = 0, j = 0; i < nlist1 && j < nlist2;)
{ {
if (list1[i] == list2[j]) if (list1[in1] == list2[in2])
{ {
i++; /* skip over duplicates */
j++; in1++;
in2++;
} }
else if (list1[i] < list2[j]) else if (list1[in1] < list2[in2])
{ {
result[k++] = list1[i]; /* list1[in1] is not in list2 */
i++; list1[out1++] = list1[in1++];
} }
else else
{ {
/* can't happen */ /* list2[in2] is not in list1 */
elog(WARNING, "invalid element %u in shorter list", list2[j]); list2[out2++] = list2[in2++];
j++;
} }
} }
for (; i < nlist1; i++) /* any remaining list1 entries are not in list2 */
result[k++] = list1[i]; while (in1 < *nlist1)
{
list1[out1++] = list1[in1++];
}
/* We should have copied the exact number of elements */ /* any remaining list2 entries are not in list1 */
AssertState(k == (nlist1 - nlist2)); while (in2 < *nlist2)
{
list2[out2++] = list2[in2++];
}
if (list1) *nlist1 = out1;
pfree(list1); *nlist2 = out2;
if (list2)
pfree(list2);
return k;
} }
/* /*
@ -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 * classId, objectId, objsubId: identify the object whose ACL this is
* ownerId: role owning the object * ownerId: role owning the object
* isGrant: are we adding or removing ACL entries?
* noldmembers, oldmembers: array of roleids appearing in old ACL * noldmembers, oldmembers: array of roleids appearing in old ACL
* nnewmembers, newmembers: array of roleids appearing in new ACL * nnewmembers, newmembers: array of roleids appearing in new ACL
* *
* We calculate the difference between the new and old lists of roles, * We calculate the differences between the new and old lists of roles,
* and then insert (if it's a grant) or delete (if it's a revoke) from * and then insert or delete from pg_shdepend as appropiate.
* pg_shdepend as appropiate.
* *
* Note that we can't insert blindly at grant, because we would end up with * Note that we can't just insert all referenced roles blindly during GRANT,
* duplicate registered dependencies. We could check for existence of the * because we would end up with duplicate registered dependencies. We could
* tuple before inserting, but that seems to be more expensive than what we are * check for existence of the tuples before inserting, but that seems to be
* doing now. On the other hand, we can't just delete the tuples blindly at * more expensive than what we are doing here. Likewise we can't just delete
* revoke, because the user may still have other privileges. * 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 * NOTE: Both input arrays must be sorted and de-duped. (Typically they
* before return. * are extracted from an ACL array by aclmembers(), which takes care of
* both requirements.) The arrays are pfreed before return.
*/ */
void void
updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
Oid ownerId, bool isGrant, Oid ownerId,
int noldmembers, Oid *oldmembers, int noldmembers, Oid *oldmembers,
int nnewmembers, Oid *newmembers) int nnewmembers, Oid *newmembers)
{ {
Relation sdepRel; Relation sdepRel;
Oid *diff; int i;
int ndiff,
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) getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers);
ndiff = getOidListDiff(newmembers, nnewmembers,
oldmembers, noldmembers, &diff);
else
ndiff = getOidListDiff(oldmembers, noldmembers,
newmembers, nnewmembers, &diff);
if (ndiff > 0) if (noldmembers > 0 || nnewmembers > 0)
{ {
sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
/* Add or drop the respective dependency */ /* Add new dependencies that weren't already present */
for (i = 0; i < ndiff; i++) 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 * Skip the owner: he has an OWNER shdep entry instead. (This is
@ -442,15 +435,28 @@ updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
if (roleid == ownerId) if (roleid == ownerId)
continue; 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 */ /* Skip pinned roles */
if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
continue; continue;
if (isGrant)
shdepAddDependency(sdepRel, classId, objectId, objsubId,
AuthIdRelationId, roleid,
SHARED_DEPENDENCY_ACL);
else
shdepDropDependency(sdepRel, classId, objectId, objsubId, shdepDropDependency(sdepRel, classId, objectId, objsubId,
false, /* exact match on objsubId */ false, /* exact match on objsubId */
AuthIdRelationId, roleid, AuthIdRelationId, roleid,
@ -460,7 +466,10 @@ updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
heap_close(sdepRel, RowExclusiveLock); 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) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); Oid newOwnerId);
extern void updateAclDependencies(Oid classId, Oid objectId, int32 objectSubId, extern void updateAclDependencies(Oid classId, Oid objectId, int32 objectSubId,
Oid ownerId, bool isGrant, Oid ownerId,
int noldmembers, Oid *oldmembers, int noldmembers, Oid *oldmembers,
int nnewmembers, Oid *newmembers); int nnewmembers, Oid *newmembers);