Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 35dd40d

Browse files
committed
Improve tracking of role dependencies of pg_init_privs entries.
Commit 5342874 invented SHARED_DEPENDENCY_INITACL entries in pg_shdepend, but installed them only for non-owner roles mentioned in a pg_init_privs entry. This turns out to be the wrong thing, because there is nothing to cue REASSIGN OWNED to go and update pg_init_privs entries when the object's ownership is reassigned. That leads to leaving dangling entries in pg_init_privs, as reported by Hannu Krosing. Instead, install INITACL entries for all roles mentioned in pg_init_privs entries (except pinned roles), and change ALTER OWNER to not touch them, just as it doesn't touch pg_init_privs entries. REASSIGN OWNED will now substitute the new owner OID for the old in pg_init_privs entries. This feels like perhaps not quite the right thing, since pg_init_privs ought to be a historical record of the state of affairs just after CREATE EXTENSION. However, it's hard to see what else to do, if we don't want to disallow dropping the object's original owner. In any case this is better than the previous do-nothing behavior, and we're unlikely to come up with a superior solution in time for v17. While here, tighten up some coding rules about how ACLs in pg_init_privs should never be null or empty. There's not any obvious reason to allow that, and perhaps asserting that it's not so will catch some bugs. (We were previously inconsistent on the point, with some code paths taking care not to store empty ACLs and others not.) This leaves recordExtensionInitPrivWorker not doing anything with its ownerId argument, but we'll deal with that separately. catversion bump forced because of change of expected contents of pg_shdepend when pg_init_privs entries exist. Discussion: https://postgr.es/m/CAMT0RQSVgv48G5GArUvOVhottWqZLrvC5wBzBa4HrUdXe9VRXw@mail.gmail.com
1 parent 653d396 commit 35dd40d

File tree

9 files changed

+666
-111
lines changed

9 files changed

+666
-111
lines changed

doc/src/sgml/catalogs.sgml

-3
Original file line numberDiff line numberDiff line change
@@ -7182,9 +7182,6 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
71827182
The referenced object (which must be a role) is mentioned in a
71837183
<link linkend="catalog-pg-init-privs"><structname>pg_init_privs</structname></link>
71847184
entry for the dependent object.
7185-
(A <symbol>SHARED_DEPENDENCY_INITACL</symbol> entry is not made for
7186-
the owner of the object, since the owner will have
7187-
a <symbol>SHARED_DEPENDENCY_OWNER</symbol> entry anyway.)
71887185
</para>
71897186
</listitem>
71907187
</varlistentry>

src/backend/catalog/aclchk.c

+116-14
Original file line numberDiff line numberDiff line change
@@ -4771,19 +4771,16 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
47714771
/* Update pg_shdepend for roles mentioned in the old/new ACLs. */
47724772
oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
47734773
RelationGetDescr(relation), &isNull);
4774-
if (!isNull)
4775-
old_acl = DatumGetAclP(oldAclDatum);
4776-
else
4777-
old_acl = NULL; /* this case shouldn't happen, probably */
4774+
Assert(!isNull);
4775+
old_acl = DatumGetAclP(oldAclDatum);
47784776
noldmembers = aclmembers(old_acl, &oldmembers);
47794777

47804778
updateInitAclDependencies(classoid, objoid, objsubid,
4781-
ownerId,
47824779
noldmembers, oldmembers,
47834780
nnewmembers, newmembers);
47844781

47854782
/* If we have a new ACL to set, then update the row with it. */
4786-
if (new_acl)
4783+
if (new_acl && ACL_NUM(new_acl) != 0)
47874784
{
47884785
values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
47894786
replace[Anum_pg_init_privs_initprivs - 1] = true;
@@ -4795,7 +4792,7 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
47954792
}
47964793
else
47974794
{
4798-
/* new_acl is NULL, so delete the entry we found. */
4795+
/* new_acl is NULL/empty, so delete the entry we found. */
47994796
CatalogTupleDelete(relation, &oldtuple->t_self);
48004797
}
48014798
}
@@ -4810,7 +4807,7 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
48104807
* If we are passed in a NULL ACL and no entry exists, we can just
48114808
* fall through and do nothing.
48124809
*/
4813-
if (new_acl)
4810+
if (new_acl && ACL_NUM(new_acl) != 0)
48144811
{
48154812
/* No entry found, so add it. */
48164813
values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
@@ -4832,7 +4829,6 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
48324829
oldmembers = NULL;
48334830

48344831
updateInitAclDependencies(classoid, objoid, objsubid,
4835-
ownerId,
48364832
noldmembers, oldmembers,
48374833
nnewmembers, newmembers);
48384834
}
@@ -4846,6 +4842,115 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
48464842
table_close(relation, RowExclusiveLock);
48474843
}
48484844

4845+
/*
4846+
* ReplaceRoleInInitPriv
4847+
*
4848+
* Used by shdepReassignOwned to replace mentions of a role in pg_init_privs.
4849+
*/
4850+
void
4851+
ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid,
4852+
Oid classid, Oid objid, int32 objsubid)
4853+
{
4854+
Relation rel;
4855+
ScanKeyData key[3];
4856+
SysScanDesc scan;
4857+
HeapTuple oldtuple;
4858+
Datum oldAclDatum;
4859+
bool isNull;
4860+
Acl *old_acl;
4861+
Acl *new_acl;
4862+
HeapTuple newtuple;
4863+
int noldmembers;
4864+
int nnewmembers;
4865+
Oid *oldmembers;
4866+
Oid *newmembers;
4867+
4868+
/* Search for existing pg_init_privs entry for the target object. */
4869+
rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4870+
4871+
ScanKeyInit(&key[0],
4872+
Anum_pg_init_privs_objoid,
4873+
BTEqualStrategyNumber, F_OIDEQ,
4874+
ObjectIdGetDatum(objid));
4875+
ScanKeyInit(&key[1],
4876+
Anum_pg_init_privs_classoid,
4877+
BTEqualStrategyNumber, F_OIDEQ,
4878+
ObjectIdGetDatum(classid));
4879+
ScanKeyInit(&key[2],
4880+
Anum_pg_init_privs_objsubid,
4881+
BTEqualStrategyNumber, F_INT4EQ,
4882+
Int32GetDatum(objsubid));
4883+
4884+
scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4885+
NULL, 3, key);
4886+
4887+
/* There should exist only one entry or none. */
4888+
oldtuple = systable_getnext(scan);
4889+
4890+
if (!HeapTupleIsValid(oldtuple))
4891+
{
4892+
/*
4893+
* Hmm, why are we here if there's no entry? But pack up and go away
4894+
* quietly.
4895+
*/
4896+
systable_endscan(scan);
4897+
table_close(rel, RowExclusiveLock);
4898+
return;
4899+
}
4900+
4901+
/* Get a writable copy of the existing ACL. */
4902+
oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4903+
RelationGetDescr(rel), &isNull);
4904+
Assert(!isNull);
4905+
old_acl = DatumGetAclPCopy(oldAclDatum);
4906+
4907+
/*
4908+
* Generate new ACL. This usage of aclnewowner is a bit off-label when
4909+
* oldroleid isn't the owner; but it does the job fine.
4910+
*/
4911+
new_acl = aclnewowner(old_acl, oldroleid, newroleid);
4912+
4913+
/*
4914+
* If we end with an empty ACL, delete the pg_init_privs entry. (That
4915+
* probably can't happen here, but we may as well cover the case.)
4916+
*/
4917+
if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4918+
{
4919+
CatalogTupleDelete(rel, &oldtuple->t_self);
4920+
}
4921+
else
4922+
{
4923+
Datum values[Natts_pg_init_privs] = {0};
4924+
bool nulls[Natts_pg_init_privs] = {0};
4925+
bool replaces[Natts_pg_init_privs] = {0};
4926+
4927+
/* Update existing entry. */
4928+
values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4929+
replaces[Anum_pg_init_privs_initprivs - 1] = true;
4930+
4931+
newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4932+
values, nulls, replaces);
4933+
CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4934+
}
4935+
4936+
/*
4937+
* Update the shared dependency ACL info.
4938+
*/
4939+
noldmembers = aclmembers(old_acl, &oldmembers);
4940+
nnewmembers = aclmembers(new_acl, &newmembers);
4941+
4942+
updateInitAclDependencies(classid, objid, objsubid,
4943+
noldmembers, oldmembers,
4944+
nnewmembers, newmembers);
4945+
4946+
systable_endscan(scan);
4947+
4948+
/* prevent error when processing objects multiple times */
4949+
CommandCounterIncrement();
4950+
4951+
table_close(rel, RowExclusiveLock);
4952+
}
4953+
48494954
/*
48504955
* RemoveRoleFromInitPriv
48514956
*
@@ -4907,10 +5012,8 @@ RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
49075012
/* Get a writable copy of the existing ACL. */
49085013
oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
49095014
RelationGetDescr(rel), &isNull);
4910-
if (!isNull)
4911-
old_acl = DatumGetAclPCopy(oldAclDatum);
4912-
else
4913-
old_acl = NULL; /* this case shouldn't happen, probably */
5015+
Assert(!isNull);
5016+
old_acl = DatumGetAclPCopy(oldAclDatum);
49145017

49155018
/*
49165019
* We need the members of both old and new ACLs so we can correct the
@@ -4972,7 +5075,6 @@ RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
49725075
nnewmembers = aclmembers(new_acl, &newmembers);
49735076

49745077
updateInitAclDependencies(classid, objid, objsubid,
4975-
ownerId,
49765078
noldmembers, oldmembers,
49775079
nnewmembers, newmembers);
49785080

0 commit comments

Comments
 (0)