PostgreSQL Source Code git master
Loading...
Searching...
No Matches
seclabel.c
Go to the documentation of this file.
1/* -------------------------------------------------------------------------
2 *
3 * seclabel.c
4 * routines to support security label feature.
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * -------------------------------------------------------------------------
10 */
11#include "postgres.h"
12
13#include "access/genam.h"
14#include "access/htup_details.h"
15#include "access/relation.h"
16#include "access/table.h"
17#include "catalog/catalog.h"
18#include "catalog/indexing.h"
19#include "catalog/pg_seclabel.h"
21#include "commands/seclabel.h"
22#include "miscadmin.h"
23#include "utils/builtins.h"
24#include "utils/fmgroids.h"
25#include "utils/memutils.h"
26#include "utils/rel.h"
27
33
35
36static bool
38{
39 switch (objtype)
40 {
42 case OBJECT_COLUMN:
43 case OBJECT_DATABASE:
44 case OBJECT_DOMAIN:
47 case OBJECT_FUNCTION:
48 case OBJECT_LANGUAGE:
50 case OBJECT_MATVIEW:
53 case OBJECT_ROLE:
54 case OBJECT_ROUTINE:
55 case OBJECT_SCHEMA:
56 case OBJECT_SEQUENCE:
58 case OBJECT_TABLE:
60 case OBJECT_TYPE:
61 case OBJECT_VIEW:
62 return true;
63
65 case OBJECT_AMOP:
66 case OBJECT_AMPROC:
68 case OBJECT_CAST:
71 case OBJECT_DEFAULT:
72 case OBJECT_DEFACL:
75 case OBJECT_FDW:
77 case OBJECT_INDEX:
78 case OBJECT_OPCLASS:
79 case OBJECT_OPERATOR:
80 case OBJECT_OPFAMILY:
82 case OBJECT_POLICY:
85 case OBJECT_RULE:
89 case OBJECT_TRIGGER:
92 case OBJECT_TSPARSER:
95 return false;
96
97 /*
98 * There's intentionally no default: case here; we want the
99 * compiler to warn if a new ObjectType hasn't been handled above.
100 */
101 }
102
103 /* Shouldn't get here, but if we do, say "no support" */
104 return false;
105}
106
107/*
108 * ExecSecLabelStmt --
109 *
110 * Apply a security label to a database object.
111 *
112 * Returns the ObjectAddress of the object to which the policy was applied.
113 */
116{
118 ObjectAddress address;
119 Relation relation;
120 ListCell *lc;
121 bool missing_ok;
122
123 /*
124 * Find the named label provider, or if none specified, check whether
125 * there's exactly one, and if so use it.
126 */
127 if (stmt->provider == NULL)
128 {
132 errmsg("no security label providers have been loaded")));
136 errmsg("must specify provider when multiple security label providers have been loaded")));
138 }
139 else
140 {
141 foreach(lc, label_provider_list)
142 {
144
145 if (strcmp(stmt->provider, lp->provider_name) == 0)
146 {
147 provider = lp;
148 break;
149 }
150 }
151 if (provider == NULL)
154 errmsg("security label provider \"%s\" is not loaded",
155 stmt->provider)));
156 }
157
158 if (!SecLabelSupportsObjectType(stmt->objtype))
161 errmsg("security labels are not supported for this type of object")));
162
163 /*
164 * During binary upgrade, allow nonexistent large objects so that we don't
165 * have to create them during schema restoration. pg_upgrade will
166 * transfer the contents of pg_largeobject_metadata via COPY or by
167 * copying/linking its files from the old cluster later on.
168 */
169 missing_ok = IsBinaryUpgrade && stmt->objtype == OBJECT_LARGEOBJECT;
170
171 /*
172 * Translate the parser representation which identifies this object into
173 * an ObjectAddress. get_object_address() will throw an error if the
174 * object does not exist, and will also acquire a lock on the target to
175 * guard against concurrent modifications.
176 */
177 address = get_object_address(stmt->objtype, stmt->object,
178 &relation, ShareUpdateExclusiveLock,
179 missing_ok);
180
181 /* Require ownership of the target object. */
182 check_object_ownership(GetUserId(), stmt->objtype, address,
183 stmt->object, relation);
184
185 /* Perform other integrity checks as needed. */
186 switch (stmt->objtype)
187 {
188 case OBJECT_COLUMN:
189
190 /*
191 * Allow security labels only on columns of tables, views,
192 * materialized views, composite types, and foreign tables (which
193 * are the only relkinds for which pg_dump will dump labels).
194 */
195 if (relation->rd_rel->relkind != RELKIND_RELATION &&
196 relation->rd_rel->relkind != RELKIND_VIEW &&
197 relation->rd_rel->relkind != RELKIND_MATVIEW &&
198 relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
199 relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
200 relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
203 errmsg("cannot set security label on relation \"%s\"",
204 RelationGetRelationName(relation)),
205 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
206 break;
207 default:
208 break;
209 }
210
211 /* Provider gets control here, may throw ERROR to veto new label. */
212 provider->hook(&address, stmt->label);
213
214 /* Apply new label. */
215 SetSecurityLabel(&address, provider->provider_name, stmt->label);
216
217 /*
218 * If get_object_address() opened the relation for us, we close it to keep
219 * the reference count correct - but we retain any locks acquired by
220 * get_object_address() until commit time, to guard against concurrent
221 * activity.
222 */
223 if (relation != NULL)
224 relation_close(relation, NoLock);
225
226 return address;
227}
228
229/*
230 * GetSharedSecurityLabel returns the security label for a shared object for
231 * a given provider, or NULL if there is no such label.
232 */
233static char *
235{
237 ScanKeyData keys[3];
238 SysScanDesc scan;
239 HeapTuple tuple;
240 Datum datum;
241 bool isnull;
242 char *seclabel = NULL;
243
244 ScanKeyInit(&keys[0],
247 ObjectIdGetDatum(object->objectId));
248 ScanKeyInit(&keys[1],
251 ObjectIdGetDatum(object->classId));
252 ScanKeyInit(&keys[2],
256
258
261
262 tuple = systable_getnext(scan);
263 if (HeapTupleIsValid(tuple))
264 {
267 if (!isnull)
269 }
270 systable_endscan(scan);
271
273
274 return seclabel;
275}
276
277/*
278 * GetSecurityLabel returns the security label for a shared or database object
279 * for a given provider, or NULL if there is no such label.
280 */
281char *
282GetSecurityLabel(const ObjectAddress *object, const char *provider)
283{
285 ScanKeyData keys[4];
286 SysScanDesc scan;
287 HeapTuple tuple;
288 Datum datum;
289 bool isnull;
290 char *seclabel = NULL;
291
292 /* Shared objects have their own security label catalog. */
293 if (IsSharedRelation(object->classId))
294 return GetSharedSecurityLabel(object, provider);
295
296 /* Must be an unshared object, so examine pg_seclabel. */
297 ScanKeyInit(&keys[0],
300 ObjectIdGetDatum(object->objectId));
301 ScanKeyInit(&keys[1],
304 ObjectIdGetDatum(object->classId));
305 ScanKeyInit(&keys[2],
308 Int32GetDatum(object->objectSubId));
309 ScanKeyInit(&keys[3],
313
315
317 NULL, 4, keys);
318
319 tuple = systable_getnext(scan);
320 if (HeapTupleIsValid(tuple))
321 {
323 RelationGetDescr(pg_seclabel), &isnull);
324 if (!isnull)
326 }
327 systable_endscan(scan);
328
330
331 return seclabel;
332}
333
334/*
335 * SetSharedSecurityLabel is a helper function of SetSecurityLabel to
336 * handle shared database objects.
337 */
338static void
340 const char *provider, const char *label)
341{
343 ScanKeyData keys[4];
344 SysScanDesc scan;
348 bool nulls[Natts_pg_shseclabel];
350
351 /* Prepare to form or update a tuple, if necessary. */
352 memset(nulls, false, sizeof(nulls));
353 memset(replaces, false, sizeof(replaces));
357 if (label != NULL)
359
360 /* Use the index to search for a matching old tuple */
361 ScanKeyInit(&keys[0],
364 ObjectIdGetDatum(object->objectId));
365 ScanKeyInit(&keys[1],
368 ObjectIdGetDatum(object->classId));
369 ScanKeyInit(&keys[2],
373
375
377 NULL, 3, keys);
378
379 oldtup = systable_getnext(scan);
381 {
382 if (label == NULL)
384 else
385 {
388 values, nulls, replaces);
390 }
391 }
392 systable_endscan(scan);
393
394 /* If we didn't find an old tuple, insert a new one */
395 if (newtup == NULL && label != NULL)
396 {
398 values, nulls);
400 }
401
402 if (newtup != NULL)
404
406}
407
408/*
409 * SetSecurityLabel attempts to set the security label for the specified
410 * provider on the specified object to the given value. NULL means that any
411 * existing label should be deleted.
412 */
413void
415 const char *provider, const char *label)
416{
418 ScanKeyData keys[4];
419 SysScanDesc scan;
423 bool nulls[Natts_pg_seclabel];
425
426 /* Shared objects have their own security label catalog. */
427 if (IsSharedRelation(object->classId))
428 {
430 return;
431 }
432
433 /* Prepare to form or update a tuple, if necessary. */
434 memset(nulls, false, sizeof(nulls));
435 memset(replaces, false, sizeof(replaces));
440 if (label != NULL)
442
443 /* Use the index to search for a matching old tuple */
444 ScanKeyInit(&keys[0],
447 ObjectIdGetDatum(object->objectId));
448 ScanKeyInit(&keys[1],
451 ObjectIdGetDatum(object->classId));
452 ScanKeyInit(&keys[2],
455 Int32GetDatum(object->objectSubId));
456 ScanKeyInit(&keys[3],
460
462
464 NULL, 4, keys);
465
466 oldtup = systable_getnext(scan);
468 {
469 if (label == NULL)
471 else
472 {
475 values, nulls, replaces);
477 }
478 }
479 systable_endscan(scan);
480
481 /* If we didn't find an old tuple, insert a new one */
482 if (newtup == NULL && label != NULL)
483 {
485 values, nulls);
487 }
488
489 /* Update indexes, if necessary */
490 if (newtup != NULL)
492
494}
495
496/*
497 * DeleteSharedSecurityLabel is a helper function of DeleteSecurityLabel
498 * to handle shared database objects.
499 */
500void
527
528/*
529 * DeleteSecurityLabel removes all security labels for an object (and any
530 * sub-objects, if applicable).
531 */
532void
534{
536 ScanKeyData skey[3];
537 SysScanDesc scan;
539 int nkeys;
540
541 /* Shared objects have their own security label catalog. */
542 if (IsSharedRelation(object->classId))
543 {
544 Assert(object->objectSubId == 0);
546 return;
547 }
548
549 ScanKeyInit(&skey[0],
552 ObjectIdGetDatum(object->objectId));
553 ScanKeyInit(&skey[1],
556 ObjectIdGetDatum(object->classId));
557 if (object->objectSubId != 0)
558 {
559 ScanKeyInit(&skey[2],
562 Int32GetDatum(object->objectSubId));
563 nkeys = 3;
564 }
565 else
566 nkeys = 2;
567
569
571 NULL, nkeys, skey);
574 systable_endscan(scan);
575
577}
578
579void
static Datum values[MAXATTR]
Definition bootstrap.c:155
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define TextDatumGetCString(d)
Definition builtins.h:99
#define Assert(condition)
Definition c.h:873
bool IsSharedRelation(Oid relationId)
Definition catalog.c:304
int errcode(int sqlerrcode)
Definition elog.c:864
int errmsg(const char *fmt,...)
Definition elog.c:1081
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
#define palloc_object(type)
Definition fe_memutils.h:74
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
bool IsBinaryUpgrade
Definition globals.c:121
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
#define stmt
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
List * lappend(List *list, void *datum)
Definition list.c:339
#define NoLock
Definition lockdefs.h:34
#define AccessShareLock
Definition lockdefs.h:36
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
#define RowExclusiveLock
Definition lockdefs.h:38
char * pstrdup(const char *in)
Definition mcxt.c:1781
MemoryContext TopMemoryContext
Definition mcxt.c:166
Oid GetUserId(void)
Definition miscinit.c:469
void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, Node *object, Relation relation)
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
ObjectType
@ OBJECT_EVENT_TRIGGER
@ OBJECT_FDW
@ OBJECT_TSPARSER
@ OBJECT_COLLATION
@ OBJECT_USER_MAPPING
@ OBJECT_ACCESS_METHOD
@ OBJECT_OPCLASS
@ OBJECT_DEFACL
@ OBJECT_AGGREGATE
@ OBJECT_MATVIEW
@ OBJECT_SCHEMA
@ OBJECT_POLICY
@ OBJECT_OPERATOR
@ OBJECT_FOREIGN_TABLE
@ OBJECT_TSCONFIGURATION
@ OBJECT_OPFAMILY
@ OBJECT_DOMAIN
@ OBJECT_COLUMN
@ OBJECT_TABLESPACE
@ OBJECT_ROLE
@ OBJECT_ROUTINE
@ OBJECT_LARGEOBJECT
@ OBJECT_PUBLICATION_NAMESPACE
@ OBJECT_PROCEDURE
@ OBJECT_EXTENSION
@ OBJECT_INDEX
@ OBJECT_DEFAULT
@ OBJECT_DATABASE
@ OBJECT_SEQUENCE
@ OBJECT_TSTEMPLATE
@ OBJECT_LANGUAGE
@ OBJECT_AMOP
@ OBJECT_PUBLICATION_REL
@ OBJECT_FOREIGN_SERVER
@ OBJECT_TSDICTIONARY
@ OBJECT_ATTRIBUTE
@ OBJECT_PUBLICATION
@ OBJECT_RULE
@ OBJECT_CONVERSION
@ OBJECT_AMPROC
@ OBJECT_TABLE
@ OBJECT_VIEW
@ OBJECT_PARAMETER_ACL
@ OBJECT_TYPE
@ OBJECT_FUNCTION
@ OBJECT_TABCONSTRAINT
@ OBJECT_DOMCONSTRAINT
@ OBJECT_SUBSCRIPTION
@ OBJECT_STATISTIC_EXT
@ OBJECT_CAST
@ OBJECT_TRIGGER
@ OBJECT_TRANSFORM
static char * label
int errdetail_relkind_not_supported(char relkind)
Definition pg_class.c:24
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
#define linitial(l)
Definition pg_list.h:178
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
uint64_t Datum
Definition postgres.h:70
static Datum Int32GetDatum(int32 X)
Definition postgres.h:222
unsigned int Oid
static int fb(int x)
#define RelationGetDescr(relation)
Definition rel.h:540
#define RelationGetRelationName(relation)
Definition rel.h:548
bool criticalSharedRelcachesBuilt
Definition relcache.c:146
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
static char * GetSharedSecurityLabel(const ObjectAddress *object, const char *provider)
Definition seclabel.c:234
void SetSecurityLabel(const ObjectAddress *object, const char *provider, const char *label)
Definition seclabel.c:414
ObjectAddress ExecSecLabelStmt(SecLabelStmt *stmt)
Definition seclabel.c:115
void register_label_provider(const char *provider_name, check_object_relabel_type hook)
Definition seclabel.c:580
static List * label_provider_list
Definition seclabel.c:34
static bool SecLabelSupportsObjectType(ObjectType objtype)
Definition seclabel.c:37
char * GetSecurityLabel(const ObjectAddress *object, const char *provider)
Definition seclabel.c:282
static void SetSharedSecurityLabel(const ObjectAddress *object, const char *provider, const char *label)
Definition seclabel.c:339
void DeleteSecurityLabel(const ObjectAddress *object)
Definition seclabel.c:533
void DeleteSharedSecurityLabel(Oid objectId, Oid classId)
Definition seclabel.c:501
void(* check_object_relabel_type)(const ObjectAddress *object, const char *seclabel)
Definition seclabel.h:29
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:205
#define BTEqualStrategyNumber
Definition stratnum.h:31
const char * provider_name
Definition seclabel.c:30
check_object_relabel_type hook
Definition seclabel.c:31
Definition pg_list.h:54
Form_pg_class rd_rel
Definition rel.h:111
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40