1/* -------------------------------------------------------------------------
3 * contrib/sepgsql/relation.c
5 * Routines corresponding to relation/attribute objects
7 * Copyright (c) 2010-2025, PostgreSQL Global Development Group
9 * -------------------------------------------------------------------------
26#include "utils/fmgroids.h"
35 * sepgsql_attribute_post_create
37 * This routine assigns a default security label on a newly defined
38 * column, using ALTER TABLE ... ADD COLUMN.
39 * Note that this routine is not invoked in the case of CREATE TABLE,
40 * although it also defines columns in addition to table.
58 * Only attributes within regular relations or partition relations have
59 * individual security labels.
61 if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
65 * Compute a default security label of the new column underlying the
66 * specified relation, and check permission to create it.
71 Anum_pg_attribute_attrelid,
75 Anum_pg_attribute_attnum,
84 elog(
ERROR,
"could not find tuple for column %d of relation %u",
96 * check db_column:{create} permission
98 object.classId = RelationRelationId;
99 object.objectId = relOid;
100 object.objectSubId = 0;
113 * Assign the default security label on a new procedure
115 object.classId = RelationRelationId;
116 object.objectId = relOid;
117 object.objectSubId =
attnum;
128 * sepgsql_attribute_drop
130 * It checks privileges to drop the supplied column.
139 if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
143 * check db_column:{drop} permission
145 object.classId = RelationRelationId;
146 object.objectId = relOid;
147 object.objectSubId =
attnum;
159 * sepgsql_attribute_relabel
161 * It checks privileges to relabel the supplied column
166 const char *seclabel)
172 if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
174 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
175 errmsg(
"cannot set security label on non-regular columns")));
177 object.classId = RelationRelationId;
178 object.objectId = relOid;
179 object.objectSubId =
attnum;
183 * check db_column:{setattr relabelfrom} permission
193 * check db_column:{relabelto} permission
204 * sepgsql_attribute_setattr
206 * It checks privileges to alter the supplied column.
215 if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
219 * check db_column:{setattr} permission
221 object.classId = RelationRelationId;
222 object.objectId = relOid;
223 object.objectSubId =
attnum;
235 * sepgsql_relation_post_create
237 * The post creation hook of relation/attribute
249 char *scontext;
/* subject */
250 char *tcontext;
/* schema */
251 char *rcontext;
/* relation */
252 char *ccontext;
/* column */
257 * Fetch catalog record of the new relation. Because pg_class entry is not
258 * visible right now, we need to scan the catalog using SnapshotSelf.
272 elog(
ERROR,
"could not find tuple for relation %u", relOid);
276 /* ignore indexes on toast tables */
277 if (classForm->relkind == RELKIND_INDEX &&
278 classForm->relnamespace == PG_TOAST_NAMESPACE)
282 * check db_schema:{add_name} permission of the namespace
284 object.classId = NamespaceRelationId;
285 object.objectId = classForm->relnamespace;
286 object.objectSubId = 0;
293 switch (classForm->relkind)
295 case RELKIND_RELATION:
296 case RELKIND_PARTITIONED_TABLE:
299 case RELKIND_SEQUENCE:
306 /* deal with indexes specially; no need for tclass */
310 /* ignore other relkinds */
315 * Compute a default security label when we create a new relation object
316 * under the specified namespace.
320 classForm->relnamespace, 0);
325 * check db_xxx:{create} permission
339 * Assign the default security label on the new regular or partitioned
342 object.classId = RelationRelationId;
343 object.objectId = relOid;
344 object.objectSubId = 0;
348 * We also assign a default security label on columns of a new table.
350 if (classForm->relkind == RELKIND_RELATION ||
351 classForm->relkind == RELKIND_PARTITIONED_TABLE)
362 Anum_pg_attribute_attrelid,
385 * check db_column:{create} permission
393 object.classId = RelationRelationId;
394 object.objectId = relOid;
395 object.objectSubId = attForm->attnum;
411 * sepgsql_relation_drop
413 * It checks privileges to drop the supplied relation.
425 case RELKIND_RELATION:
426 case RELKIND_PARTITIONED_TABLE:
429 case RELKIND_SEQUENCE:
436 /* ignore indexes on toast tables */
439 /* other indexes are handled specially below; no need for tclass */
442 /* ignore other relkinds */
447 * check db_schema:{remove_name} permission
449 object.classId = NamespaceRelationId;
451 object.objectSubId = 0;
461 /* deal with indexes specially */
462 if (relkind == RELKIND_INDEX)
469 * check db_table/sequence/view:{drop} permission
471 object.classId = RelationRelationId;
472 object.objectId = relOid;
473 object.objectSubId = 0;
484 * check db_column:{drop} permission
486 if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
499 if (attForm->attisdropped)
502 object.classId = RelationRelationId;
503 object.objectId = relOid;
504 object.objectSubId = attForm->attnum;
519 * sepgsql_relation_truncate
521 * Check privileges to TRUNCATE the supplied relation.
533 case RELKIND_RELATION:
534 case RELKIND_PARTITIONED_TABLE:
538 /* ignore other relkinds */
543 * check db_table:{truncate} permission
545 object.classId = RelationRelationId;
546 object.objectId = relOid;
547 object.objectSubId = 0;
559 * sepgsql_relation_relabel
561 * It checks privileges to relabel the supplied relation by the `seclabel'.
571 if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
573 else if (relkind == RELKIND_SEQUENCE)
575 else if (relkind == RELKIND_VIEW)
579 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
580 errmsg(
"cannot set security labels on relations except "
581 "for tables, sequences or views")));
583 object.classId = RelationRelationId;
584 object.objectId = relOid;
585 object.objectSubId = 0;
589 * check db_xxx:{setattr relabelfrom} permission
599 * check db_xxx:{relabelto} permission
610 * sepgsql_relation_setattr
612 * It checks privileges to set attribute of the supplied relation
630 case RELKIND_RELATION:
631 case RELKIND_PARTITIONED_TABLE:
634 case RELKIND_SEQUENCE:
641 /* deal with indexes specially */
645 /* other relkinds don't need additional work */
650 * Fetch newer catalog
664 elog(
ERROR,
"could not find tuple for relation %u", relOid);
668 * Fetch older catalog
672 elog(
ERROR,
"cache lookup failed for relation %u", relOid);
676 * Does this ALTER command takes operation to namespace?
678 if (newform->relnamespace != oldform->relnamespace)
683 if (strcmp(
NameStr(newform->relname),
NameStr(oldform->relname)) != 0)
687 * XXX - In the future version, db_tuple:{use} of system catalog entry
688 * shall be checked, if tablespace configuration is changed.
692 * check db_xxx:{setattr} permission
694 object.classId = RelationRelationId;
695 object.objectId = relOid;
696 object.objectSubId = 0;
712 * sepgsql_relation_setattr_extra
714 * It checks permission of the relation being referenced by extra attributes,
715 * such as pg_index entries. Like core PostgreSQL, sepgsql also does not deal
716 * with such entries as individual "objects", thus, modification of these
717 * entries shall be considered as setting an attribute of the underlying
741 elog(
ERROR,
"could not find tuple for object %u in catalog \"%s\"",
754 * sepgsql_index_modify
755 * Handle index create, update, drop
757 * Unlike other relation kinds, indexes do not have their own security labels,
758 * so instead of doing checks directly, treat them as extra attributes of their
759 * owning tables; so check 'setattr' permissions on the table.
766 /* check db_table:{setattr} permission of the table being indexed */
770 Anum_pg_index_indrelid,
771 Anum_pg_index_indexrelid);
void ReleaseCatCacheList(CatCList *list)
void sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
void sepgsql_relation_post_create(Oid relOid)
void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, const char *seclabel)
static void sepgsql_index_modify(Oid indexOid)
static void sepgsql_relation_setattr_extra(Relation catalog, Oid catindex_id, Oid extra_oid, AttrNumber anum_relation_id, AttrNumber anum_extra_id)
void sepgsql_relation_truncate(Oid relOid)
void sepgsql_relation_relabel(Oid relOid, const char *seclabel)
void sepgsql_relation_setattr(Oid relOid)
void sepgsql_relation_drop(Oid relOid)
void sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void systable_endscan(SysScanDesc sysscan)
HeapTuple systable_getnext(SysScanDesc sysscan)
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Assert(PointerIsAligned(start, uint64))
#define HeapTupleIsValid(tuple)
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static void * GETSTRUCT(const HeapTupleData *tuple)
char * sepgsql_get_label(Oid classId, Oid objectId, int32 subId)
char * sepgsql_get_client_label(void)
char get_rel_relkind(Oid relid)
Oid get_rel_namespace(Oid relid)
char * get_namespace_name(Oid nspid)
void pfree(void *pointer)
char * getObjectIdentity(const ObjectAddress *object, bool missing_ok)
FormData_pg_attribute * Form_pg_attribute
FormData_pg_class * Form_pg_class
static Oid DatumGetObjectId(Datum X)
static Datum Int16GetDatum(int16 X)
static Datum ObjectIdGetDatum(Oid X)
#define RelationGetDescr(relation)
#define RelationGetRelationName(relation)
const char * quote_identifier(const char *ident)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
void sepgsql_schema_rename(Oid namespaceId)
void sepgsql_schema_remove_name(Oid namespaceId)
void sepgsql_schema_add_name(Oid namespaceId)
void SetSecurityLabel(const ObjectAddress *object, const char *provider, const char *label)
char * sepgsql_compute_create(const char *scontext, const char *tcontext, uint16 tclass, const char *objname)
#define SEPG_DB_COLUMN__CREATE
#define SEPG_DB_COLUMN__SETATTR
#define SEPG_CLASS_DB_SCHEMA
#define SEPG_CLASS_DB_TABLE
#define SEPG_DB_DATABASE__CREATE
#define SEPG_DB_SCHEMA__REMOVE_NAME
bool sepgsql_avc_check_perms_label(const char *tcontext, uint16 tclass, uint32 required, const char *audit_name, bool abort_on_violation)
#define SEPG_DB_TABLE__SETATTR
#define SEPG_DB_TABLE__TRUNCATE
#define SEPG_DB_COLUMN__DROP
#define SEPG_DB_TABLE__RELABELFROM
#define SEPG_DB_SCHEMA__ADD_NAME
#define SEPG_DB_TABLE__RELABELTO
#define SEPG_DB_COLUMN__RELABELFROM
#define SEPG_DB_PROCEDURE__RELABELTO
#define SEPG_CLASS_DB_COLUMN
#define SEPG_DB_TABLE__DROP
#define SEPGSQL_LABEL_TAG
#define SEPG_CLASS_DB_VIEW
#define SEPG_CLASS_DB_SEQUENCE
bool sepgsql_avc_check_perms(const ObjectAddress *tobject, uint16 tclass, uint32 required, const char *audit_name, bool abort_on_violation)
#define BTEqualStrategyNumber
void resetStringInfo(StringInfo str)
void appendStringInfo(StringInfo str, const char *fmt,...)
void initStringInfo(StringInfo str)
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
#define SearchSysCacheList1(cacheId, key1)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)