]> granicus.if.org Git - postgresql/commitdiff
Update per-column ACLs, not only per-table ACL, when changing table owner.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 21 Dec 2011 23:23:18 +0000 (18:23 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 21 Dec 2011 23:23:18 +0000 (18:23 -0500)
We forgot to modify column ACLs, so privileges were still shown as having
been granted by the old owner.  This meant that neither the new owner nor
a superuser could revoke the now-untraceable-to-table-owner permissions.
Per bug #6350 from Marc Balmer.

This has been wrong since column ACLs were added, so back-patch to 8.4.

src/backend/commands/tablecmds.c

index f679d619d7de2adbcbd573722f85f8379ac9aa4d..8f569ed0bd63dbba59dd6ef55e39631b0befc49c 100644 (file)
@@ -345,6 +345,8 @@ static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
                                          AlterTableCmd *cmd, LOCKMODE lockmode);
 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode);
 static void ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode);
+static void change_owner_fix_column_acls(Oid relationOid,
+                                                        Oid oldOwnerId, Oid newOwnerId);
 static void change_owner_recurse_to_sequences(Oid relationOid,
                                                                  Oid newOwnerId, LOCKMODE lockmode);
 static void ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode);
@@ -7530,6 +7532,14 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 
                heap_freetuple(newtuple);
 
+               /*
+                * We must similarly update any per-column ACLs to reflect the new
+                * owner; for neatness reasons that's split out as a subroutine.
+                */
+               change_owner_fix_column_acls(relationOid,
+                                                                        tuple_class->relowner,
+                                                                        newOwnerId);
+
                /*
                 * Update owner dependency reference, if any.  A composite type has
                 * none, because it's tracked for the pg_type entry instead of here;
@@ -7586,6 +7596,71 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
        relation_close(target_rel, NoLock);
 }
 
+/*
+ * change_owner_fix_column_acls
+ *
+ * Helper function for ATExecChangeOwner.  Scan the columns of the table
+ * and fix any non-null column ACLs to reflect the new owner.
+ */
+static void
+change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
+{
+       Relation        attRelation;
+       SysScanDesc scan;
+       ScanKeyData key[1];
+       HeapTuple       attributeTuple;
+
+       attRelation = heap_open(AttributeRelationId, RowExclusiveLock);
+       ScanKeyInit(&key[0],
+                               Anum_pg_attribute_attrelid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(relationOid));
+       scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
+                                                         true, SnapshotNow, 1, key);
+       while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
+       {
+               Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
+               Datum           repl_val[Natts_pg_attribute];
+               bool            repl_null[Natts_pg_attribute];
+               bool            repl_repl[Natts_pg_attribute];
+               Acl                *newAcl;
+               Datum           aclDatum;
+               bool            isNull;
+               HeapTuple       newtuple;
+
+               /* Ignore dropped columns */
+               if (att->attisdropped)
+                       continue;
+
+               aclDatum = heap_getattr(attributeTuple,
+                                                               Anum_pg_attribute_attacl,
+                                                               RelationGetDescr(attRelation),
+                                                               &isNull);
+               /* Null ACLs do not require changes */
+               if (isNull)
+                       continue;
+
+               memset(repl_null, false, sizeof(repl_null));
+               memset(repl_repl, false, sizeof(repl_repl));
+
+               newAcl = aclnewowner(DatumGetAclP(aclDatum),
+                                                        oldOwnerId, newOwnerId);
+               repl_repl[Anum_pg_attribute_attacl - 1] = true;
+               repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
+
+               newtuple = heap_modify_tuple(attributeTuple,
+                                                                        RelationGetDescr(attRelation),
+                                                                        repl_val, repl_null, repl_repl);
+
+               simple_heap_update(attRelation, &newtuple->t_self, newtuple);
+               CatalogUpdateIndexes(attRelation, newtuple);
+
+               heap_freetuple(newtuple);
+       }
+       systable_endscan(scan);
+       heap_close(attRelation, RowExclusiveLock);
+}
+
 /*
  * change_owner_recurse_to_sequences
  *