Skip to content

Commit 6c268df

Browse files
committed
Add new catalog called pg_init_privs
This new catalog holds the privileges which the system was initialized with at initdb time, along with any permissions set by extensions at CREATE EXTENSION time. This allows pg_dump (and any other similar use-cases) to detect when the privileges set on initdb-created or extension-created objects have been changed from what they were set to at initdb/extension-creation time and handle those changes appropriately. Reviews by Alexander Korotkov, Jose Luis Tallon
1 parent 0b62fd0 commit 6c268df

File tree

8 files changed

+549
-4
lines changed

8 files changed

+549
-4
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@
178178
<entry>table inheritance hierarchy</entry>
179179
</row>
180180

181+
<row>
182+
<entry><link linkend="catalog-pg-init-privs"><structname>pg_init_privs</structname></link></entry>
183+
<entry>object initial privileges</entry>
184+
</row>
185+
181186
<row>
182187
<entry><link linkend="catalog-pg-language"><structname>pg_language</structname></link></entry>
183188
<entry>languages for writing functions</entry>
@@ -3785,6 +3790,109 @@
37853790

37863791
</sect1>
37873792

3793+
<sect1 id="catalog-pg-init-privs">
3794+
<title><structname>pg_init_privs</structname></title>
3795+
3796+
<indexterm zone="catalog-pg-init-privs">
3797+
<primary>pg_init_privs</primary>
3798+
</indexterm>
3799+
3800+
<para>
3801+
The catalog <structname>pg_init_privs</> records information about
3802+
the initial privileges of objects in the system. There is one entry
3803+
for each object in the database which has a non-default (non-NULL)
3804+
initial set of privileges.
3805+
</para>
3806+
3807+
<para>
3808+
Objects can have initial privileges either by having those privileges set
3809+
when the system is initialized (by <application>initdb</>) or when the
3810+
object is created during a <command>CREATE EXTENSION</command> and the
3811+
extension script sets initial privileges using the <command>GRANT</command>
3812+
system. Note that the system will automatically handle recording of the
3813+
privileges during the extension script and that extension authors need
3814+
only use the <command>GRANT</command> and <command>REVOKE</command>
3815+
statements in their script to have the privileges recorded. The
3816+
<literal>privtype</literal> column indicates if the initial privilege was
3817+
set by <application>initdb</> or during a
3818+
<command>CREATE EXTENSION</command> command.
3819+
</para>
3820+
3821+
<para>
3822+
Objects which have initial privileges set by <application>initdb</> will
3823+
have entries where <literal>privtype</literal> is
3824+
<literal>'i'</literal>, while objects which have initial privileges set
3825+
by <command>CREATE EXTENSION</command> will have entries where
3826+
<literal>privtype</literal> is <literal>'e'</literal>.
3827+
</para>
3828+
3829+
<table>
3830+
<title><structname>pg_inherits</> Columns</title>
3831+
3832+
<tgroup cols="4">
3833+
<thead>
3834+
<row>
3835+
<entry>Name</entry>
3836+
<entry>Type</entry>
3837+
<entry>References</entry>
3838+
<entry>Description</entry>
3839+
</row>
3840+
</thead>
3841+
3842+
<tbody>
3843+
<row>
3844+
<entry><structfield>objoid</structfield></entry>
3845+
<entry><type>oid</type></entry>
3846+
<entry>any OID column</entry>
3847+
<entry>The OID of the specific object</entry>
3848+
</row>
3849+
3850+
<row>
3851+
<entry><structfield>classoid</structfield></entry>
3852+
<entry><type>oid</type></entry>
3853+
<entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
3854+
<entry>The OID of the system catalog the object is in</entry>
3855+
</row>
3856+
3857+
<row>
3858+
<entry><structfield>objsubid</structfield></entry>
3859+
<entry><type>int4</type></entry>
3860+
<entry></entry>
3861+
<entry>
3862+
For a table column, this is the column number (the
3863+
<structfield>objoid</> and <structfield>classoid</> refer to the
3864+
table itself). For all other object types, this column is
3865+
zero.
3866+
</entry>
3867+
</row>
3868+
3869+
<row>
3870+
<entry><structfield>privtype</structfield></entry>
3871+
<entry><type>char</type></entry>
3872+
<entry></entry>
3873+
<entry>
3874+
A code defining the type of initial privilege of this object; see text
3875+
</entry>
3876+
</row>
3877+
3878+
<row>
3879+
<entry><structfield>initprivs</structfield></entry>
3880+
<entry><type>aclitem[]</type></entry>
3881+
<entry></entry>
3882+
<entry>
3883+
The initial access privileges; see
3884+
<xref linkend="sql-grant"> and
3885+
<xref linkend="sql-revoke">
3886+
for details
3887+
</entry>
3888+
</row>
3889+
3890+
</tbody>
3891+
</tgroup>
3892+
</table>
3893+
3894+
</sect1>
3895+
37883896

37893897
<sect1 id="catalog-pg-language">
37903898
<title><structname>pg_language</structname></title>

src/backend/catalog/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
4040
pg_ts_parser.h pg_ts_template.h pg_extension.h \
4141
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
4242
pg_foreign_table.h pg_policy.h pg_replication_origin.h \
43-
pg_default_acl.h pg_seclabel.h pg_shseclabel.h \
43+
pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \
4444
pg_collation.h pg_range.h pg_transform.h \
4545
toasting.h indexing.h \
4646
)

src/backend/catalog/aclchk.c

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "catalog/pg_extension.h"
3636
#include "catalog/pg_foreign_data_wrapper.h"
3737
#include "catalog/pg_foreign_server.h"
38+
#include "catalog/pg_init_privs.h"
3839
#include "catalog/pg_language.h"
3940
#include "catalog/pg_largeobject.h"
4041
#include "catalog/pg_largeobject_metadata.h"
@@ -49,6 +50,7 @@
4950
#include "catalog/pg_ts_dict.h"
5051
#include "commands/dbcommands.h"
5152
#include "commands/event_trigger.h"
53+
#include "commands/extension.h"
5254
#include "commands/proclang.h"
5355
#include "commands/tablespace.h"
5456
#include "foreign/foreign.h"
@@ -119,6 +121,8 @@ static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
119121
AttrNumber att_number, const char *colname);
120122
static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum,
121123
Oid roleid, AclMode mask, AclMaskHow how);
124+
static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
125+
Acl *new_acl);
122126

123127

124128
#ifdef ACLDEBUG
@@ -1678,6 +1682,10 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
16781682
/* keep the catalog indexes up to date */
16791683
CatalogUpdateIndexes(attRelation, newtuple);
16801684

1685+
/* Update initial privileges for extensions */
1686+
recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1687+
ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1688+
16811689
/* Update the shared dependency ACL info */
16821690
updateAclDependencies(RelationRelationId, relOid, attnum,
16831691
ownerId,
@@ -1939,6 +1947,9 @@ ExecGrant_Relation(InternalGrant *istmt)
19391947
/* keep the catalog indexes up to date */
19401948
CatalogUpdateIndexes(relation, newtuple);
19411949

1950+
/* Update initial privileges for extensions */
1951+
recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
1952+
19421953
/* Update the shared dependency ACL info */
19431954
updateAclDependencies(RelationRelationId, relOid, 0,
19441955
ownerId,
@@ -2254,6 +2265,10 @@ ExecGrant_Fdw(InternalGrant *istmt)
22542265
/* keep the catalog indexes up to date */
22552266
CatalogUpdateIndexes(relation, newtuple);
22562267

2268+
/* Update initial privileges for extensions */
2269+
recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0,
2270+
new_acl);
2271+
22572272
/* Update the shared dependency ACL info */
22582273
updateAclDependencies(ForeignDataWrapperRelationId,
22592274
HeapTupleGetOid(tuple), 0,
@@ -2379,6 +2394,9 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
23792394
/* keep the catalog indexes up to date */
23802395
CatalogUpdateIndexes(relation, newtuple);
23812396

2397+
/* Update initial privileges for extensions */
2398+
recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl);
2399+
23822400
/* Update the shared dependency ACL info */
23832401
updateAclDependencies(ForeignServerRelationId,
23842402
HeapTupleGetOid(tuple), 0,
@@ -2503,6 +2521,9 @@ ExecGrant_Function(InternalGrant *istmt)
25032521
/* keep the catalog indexes up to date */
25042522
CatalogUpdateIndexes(relation, newtuple);
25052523

2524+
/* Update initial privileges for extensions */
2525+
recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl);
2526+
25062527
/* Update the shared dependency ACL info */
25072528
updateAclDependencies(ProcedureRelationId, funcId, 0,
25082529
ownerId,
@@ -2633,6 +2654,9 @@ ExecGrant_Language(InternalGrant *istmt)
26332654
/* keep the catalog indexes up to date */
26342655
CatalogUpdateIndexes(relation, newtuple);
26352656

2657+
/* Update initial privileges for extensions */
2658+
recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl);
2659+
26362660
/* Update the shared dependency ACL info */
26372661
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0,
26382662
ownerId,
@@ -2772,6 +2796,9 @@ ExecGrant_Largeobject(InternalGrant *istmt)
27722796
/* keep the catalog indexes up to date */
27732797
CatalogUpdateIndexes(relation, newtuple);
27742798

2799+
/* Update initial privileges for extensions */
2800+
recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2801+
27752802
/* Update the shared dependency ACL info */
27762803
updateAclDependencies(LargeObjectRelationId,
27772804
HeapTupleGetOid(tuple), 0,
@@ -2897,6 +2924,9 @@ ExecGrant_Namespace(InternalGrant *istmt)
28972924
/* keep the catalog indexes up to date */
28982925
CatalogUpdateIndexes(relation, newtuple);
28992926

2927+
/* Update initial privileges for extensions */
2928+
recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl);
2929+
29002930
/* Update the shared dependency ACL info */
29012931
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0,
29022932
ownerId,
@@ -3158,6 +3188,9 @@ ExecGrant_Type(InternalGrant *istmt)
31583188
/* keep the catalog indexes up to date */
31593189
CatalogUpdateIndexes(relation, newtuple);
31603190

3191+
/* Update initial privileges for extensions */
3192+
recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl);
3193+
31613194
/* Update the shared dependency ACL info */
31623195
updateAclDependencies(TypeRelationId, typId, 0,
31633196
ownerId,
@@ -5174,3 +5207,119 @@ get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
51745207

51755208
return result;
51765209
}
5210+
5211+
/*
5212+
* Record initial ACL for an extension object
5213+
*
5214+
* This will perform a wholesale replacement of the entire ACL for the object
5215+
* passed in, therefore be sure to pass in the complete new ACL to use.
5216+
*
5217+
* Can be called at any time, we check if 'creating_extension' is set and, if
5218+
* not, exit immediately.
5219+
*
5220+
* Pass in the object OID, the OID of the class (the OID of the table which
5221+
* the object is defined in) and the 'sub' id of the object (objsubid), if
5222+
* any. If there is no 'sub' id (they are currently only used for columns of
5223+
* tables) then pass in '0'. Finally, pass in the complete ACL to store.
5224+
*
5225+
* If an ACL already exists for this object/sub-object then we will replace
5226+
* it with what is passed in.
5227+
*
5228+
* Passing in NULL for 'new_acl' will result in the entry for the object being
5229+
* removed, if one is found.
5230+
*/
5231+
static void
5232+
recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
5233+
{
5234+
Relation relation;
5235+
ScanKeyData key[3];
5236+
SysScanDesc scan;
5237+
HeapTuple tuple;
5238+
HeapTuple oldtuple;
5239+
5240+
if (!creating_extension)
5241+
return;
5242+
5243+
relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
5244+
5245+
ScanKeyInit(&key[0],
5246+
Anum_pg_init_privs_objoid,
5247+
BTEqualStrategyNumber, F_OIDEQ,
5248+
ObjectIdGetDatum(objoid));
5249+
ScanKeyInit(&key[1],
5250+
Anum_pg_init_privs_classoid,
5251+
BTEqualStrategyNumber, F_OIDEQ,
5252+
ObjectIdGetDatum(classoid));
5253+
ScanKeyInit(&key[2],
5254+
Anum_pg_init_privs_objsubid,
5255+
BTEqualStrategyNumber, F_INT4EQ,
5256+
Int32GetDatum(objsubid));
5257+
5258+
scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
5259+
NULL, 3, key);
5260+
5261+
/* There should exist only one entry or none. */
5262+
oldtuple = systable_getnext(scan);
5263+
5264+
systable_endscan(scan);
5265+
5266+
/* If we find an entry, update it with the latest ACL. */
5267+
if (HeapTupleIsValid(oldtuple))
5268+
{
5269+
Datum values[Natts_pg_init_privs];
5270+
bool nulls[Natts_pg_init_privs];
5271+
bool replace[Natts_pg_init_privs];
5272+
5273+
/* If we have a new ACL to set, then update the row with it. */
5274+
if (new_acl)
5275+
{
5276+
MemSet(values, 0, sizeof(values));
5277+
MemSet(nulls, false, sizeof(nulls));
5278+
MemSet(replace, false, sizeof(replace));
5279+
5280+
values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl);
5281+
replace[Anum_pg_init_privs_privs - 1] = true;
5282+
5283+
oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
5284+
values, nulls, replace);
5285+
5286+
simple_heap_update(relation, &oldtuple->t_self, oldtuple);
5287+
5288+
/* keep the catalog indexes up to date */
5289+
CatalogUpdateIndexes(relation, oldtuple);
5290+
}
5291+
else
5292+
/* new_acl is NULL, so delete the entry we found. */
5293+
simple_heap_delete(relation, &oldtuple->t_self);
5294+
}
5295+
else
5296+
{
5297+
/* No entry found, so add it. */
5298+
Datum values[Natts_pg_init_privs];
5299+
bool nulls[Natts_pg_init_privs];
5300+
5301+
MemSet(nulls, false, sizeof(nulls));
5302+
5303+
values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
5304+
values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
5305+
values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
5306+
5307+
/* This function only handles initial privileges of extensions */
5308+
values[Anum_pg_init_privs_privtype - 1] =
5309+
CharGetDatum(INITPRIVS_EXTENSION);
5310+
5311+
values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl);
5312+
5313+
tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
5314+
5315+
simple_heap_insert(relation, tuple);
5316+
5317+
/* keep the catalog indexes up to date */
5318+
CatalogUpdateIndexes(relation, tuple);
5319+
}
5320+
5321+
/* prevent error when processing objects multiple times */
5322+
CommandCounterIncrement();
5323+
5324+
heap_close(relation, RowExclusiveLock);
5325+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy