mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-15 08:20:16 +08:00
bdc4edbea6
Move the system catalog index declarations from catalog/indexing.h to the respective parent tables' catalog/pg_*.h files. The original reason for having it split was that the old genbki system produced the output in the order of the catalog files it read, so all the indexing stuff needed to come separately. But this is no longer the case, and keeping it together makes more sense. Reviewed-by: John Naylor <john.naylor@enterprisedb.com> Discussion: https://www.postgresql.org/message-id/flat/c7cc82d6-f976-75d6-2e3e-b03d2cab26bb@2ndquadrant.com
774 lines
19 KiB
C
774 lines
19 KiB
C
/* -------------------------------------------------------------------------
|
|
*
|
|
* contrib/sepgsql/relation.c
|
|
*
|
|
* Routines corresponding to relation/attribute objects
|
|
*
|
|
* Copyright (c) 2010-2020, PostgreSQL Global Development Group
|
|
*
|
|
* -------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "access/genam.h"
|
|
#include "access/htup_details.h"
|
|
#include "access/sysattr.h"
|
|
#include "access/table.h"
|
|
#include "catalog/dependency.h"
|
|
#include "catalog/pg_attribute.h"
|
|
#include "catalog/pg_class.h"
|
|
#include "catalog/pg_namespace.h"
|
|
#include "commands/seclabel.h"
|
|
#include "lib/stringinfo.h"
|
|
#include "sepgsql.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/catcache.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/lsyscache.h"
|
|
#include "utils/rel.h"
|
|
#include "utils/snapmgr.h"
|
|
#include "utils/syscache.h"
|
|
|
|
static void sepgsql_index_modify(Oid indexOid);
|
|
|
|
/*
|
|
* sepgsql_attribute_post_create
|
|
*
|
|
* This routine assigns a default security label on a newly defined
|
|
* column, using ALTER TABLE ... ADD COLUMN.
|
|
* Note that this routine is not invoked in the case of CREATE TABLE,
|
|
* although it also defines columns in addition to table.
|
|
*/
|
|
void
|
|
sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
|
|
{
|
|
Relation rel;
|
|
ScanKeyData skey[2];
|
|
SysScanDesc sscan;
|
|
HeapTuple tuple;
|
|
char *scontext;
|
|
char *tcontext;
|
|
char *ncontext;
|
|
ObjectAddress object;
|
|
Form_pg_attribute attForm;
|
|
StringInfoData audit_name;
|
|
char relkind = get_rel_relkind(relOid);
|
|
|
|
/*
|
|
* Only attributes within regular relations or partition relations have
|
|
* individual security labels.
|
|
*/
|
|
if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
|
|
return;
|
|
|
|
/*
|
|
* Compute a default security label of the new column underlying the
|
|
* specified relation, and check permission to create it.
|
|
*/
|
|
rel = table_open(AttributeRelationId, AccessShareLock);
|
|
|
|
ScanKeyInit(&skey[0],
|
|
Anum_pg_attribute_attrelid,
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
ObjectIdGetDatum(relOid));
|
|
ScanKeyInit(&skey[1],
|
|
Anum_pg_attribute_attnum,
|
|
BTEqualStrategyNumber, F_INT2EQ,
|
|
Int16GetDatum(attnum));
|
|
|
|
sscan = systable_beginscan(rel, AttributeRelidNumIndexId, true,
|
|
SnapshotSelf, 2, &skey[0]);
|
|
|
|
tuple = systable_getnext(sscan);
|
|
if (!HeapTupleIsValid(tuple))
|
|
elog(ERROR, "could not find tuple for column %d of relation %u",
|
|
attnum, relOid);
|
|
|
|
attForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
|
|
scontext = sepgsql_get_client_label();
|
|
tcontext = sepgsql_get_label(RelationRelationId, relOid, 0);
|
|
ncontext = sepgsql_compute_create(scontext, tcontext,
|
|
SEPG_CLASS_DB_COLUMN,
|
|
NameStr(attForm->attname));
|
|
|
|
/*
|
|
* check db_column:{create} permission
|
|
*/
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = 0;
|
|
|
|
initStringInfo(&audit_name);
|
|
appendStringInfo(&audit_name, "%s.%s",
|
|
getObjectIdentity(&object, false),
|
|
quote_identifier(NameStr(attForm->attname)));
|
|
sepgsql_avc_check_perms_label(ncontext,
|
|
SEPG_CLASS_DB_COLUMN,
|
|
SEPG_DB_COLUMN__CREATE,
|
|
audit_name.data,
|
|
true);
|
|
|
|
/*
|
|
* Assign the default security label on a new procedure
|
|
*/
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = attnum;
|
|
SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
|
|
|
|
systable_endscan(sscan);
|
|
table_close(rel, AccessShareLock);
|
|
|
|
pfree(tcontext);
|
|
pfree(ncontext);
|
|
}
|
|
|
|
/*
|
|
* sepgsql_attribute_drop
|
|
*
|
|
* It checks privileges to drop the supplied column.
|
|
*/
|
|
void
|
|
sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
|
|
{
|
|
ObjectAddress object;
|
|
char *audit_name;
|
|
char relkind = get_rel_relkind(relOid);
|
|
|
|
if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
|
|
return;
|
|
|
|
/*
|
|
* check db_column:{drop} permission
|
|
*/
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = attnum;
|
|
audit_name = getObjectIdentity(&object, false);
|
|
|
|
sepgsql_avc_check_perms(&object,
|
|
SEPG_CLASS_DB_COLUMN,
|
|
SEPG_DB_COLUMN__DROP,
|
|
audit_name,
|
|
true);
|
|
pfree(audit_name);
|
|
}
|
|
|
|
/*
|
|
* sepgsql_attribute_relabel
|
|
*
|
|
* It checks privileges to relabel the supplied column
|
|
* by the `seclabel'.
|
|
*/
|
|
void
|
|
sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
|
|
const char *seclabel)
|
|
{
|
|
ObjectAddress object;
|
|
char *audit_name;
|
|
char relkind = get_rel_relkind(relOid);
|
|
|
|
if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
errmsg("cannot set security label on non-regular columns")));
|
|
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = attnum;
|
|
audit_name = getObjectIdentity(&object, false);
|
|
|
|
/*
|
|
* check db_column:{setattr relabelfrom} permission
|
|
*/
|
|
sepgsql_avc_check_perms(&object,
|
|
SEPG_CLASS_DB_COLUMN,
|
|
SEPG_DB_COLUMN__SETATTR |
|
|
SEPG_DB_COLUMN__RELABELFROM,
|
|
audit_name,
|
|
true);
|
|
|
|
/*
|
|
* check db_column:{relabelto} permission
|
|
*/
|
|
sepgsql_avc_check_perms_label(seclabel,
|
|
SEPG_CLASS_DB_COLUMN,
|
|
SEPG_DB_PROCEDURE__RELABELTO,
|
|
audit_name,
|
|
true);
|
|
pfree(audit_name);
|
|
}
|
|
|
|
/*
|
|
* sepgsql_attribute_setattr
|
|
*
|
|
* It checks privileges to alter the supplied column.
|
|
*/
|
|
void
|
|
sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
|
|
{
|
|
ObjectAddress object;
|
|
char *audit_name;
|
|
char relkind = get_rel_relkind(relOid);
|
|
|
|
if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
|
|
return;
|
|
|
|
/*
|
|
* check db_column:{setattr} permission
|
|
*/
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = attnum;
|
|
audit_name = getObjectIdentity(&object, false);
|
|
|
|
sepgsql_avc_check_perms(&object,
|
|
SEPG_CLASS_DB_COLUMN,
|
|
SEPG_DB_COLUMN__SETATTR,
|
|
audit_name,
|
|
true);
|
|
pfree(audit_name);
|
|
}
|
|
|
|
/*
|
|
* sepgsql_relation_post_create
|
|
*
|
|
* The post creation hook of relation/attribute
|
|
*/
|
|
void
|
|
sepgsql_relation_post_create(Oid relOid)
|
|
{
|
|
Relation rel;
|
|
ScanKeyData skey;
|
|
SysScanDesc sscan;
|
|
HeapTuple tuple;
|
|
Form_pg_class classForm;
|
|
ObjectAddress object;
|
|
uint16_t tclass;
|
|
char *scontext; /* subject */
|
|
char *tcontext; /* schema */
|
|
char *rcontext; /* relation */
|
|
char *ccontext; /* column */
|
|
char *nsp_name;
|
|
StringInfoData audit_name;
|
|
|
|
/*
|
|
* Fetch catalog record of the new relation. Because pg_class entry is not
|
|
* visible right now, we need to scan the catalog using SnapshotSelf.
|
|
*/
|
|
rel = table_open(RelationRelationId, AccessShareLock);
|
|
|
|
ScanKeyInit(&skey,
|
|
Anum_pg_class_oid,
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
ObjectIdGetDatum(relOid));
|
|
|
|
sscan = systable_beginscan(rel, ClassOidIndexId, true,
|
|
SnapshotSelf, 1, &skey);
|
|
|
|
tuple = systable_getnext(sscan);
|
|
if (!HeapTupleIsValid(tuple))
|
|
elog(ERROR, "could not find tuple for relation %u", relOid);
|
|
|
|
classForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
|
|
/* ignore indexes on toast tables */
|
|
if (classForm->relkind == RELKIND_INDEX &&
|
|
classForm->relnamespace == PG_TOAST_NAMESPACE)
|
|
goto out;
|
|
|
|
/*
|
|
* check db_schema:{add_name} permission of the namespace
|
|
*/
|
|
object.classId = NamespaceRelationId;
|
|
object.objectId = classForm->relnamespace;
|
|
object.objectSubId = 0;
|
|
sepgsql_avc_check_perms(&object,
|
|
SEPG_CLASS_DB_SCHEMA,
|
|
SEPG_DB_SCHEMA__ADD_NAME,
|
|
getObjectIdentity(&object, false),
|
|
true);
|
|
|
|
switch (classForm->relkind)
|
|
{
|
|
case RELKIND_RELATION:
|
|
case RELKIND_PARTITIONED_TABLE:
|
|
tclass = SEPG_CLASS_DB_TABLE;
|
|
break;
|
|
case RELKIND_SEQUENCE:
|
|
tclass = SEPG_CLASS_DB_SEQUENCE;
|
|
break;
|
|
case RELKIND_VIEW:
|
|
tclass = SEPG_CLASS_DB_VIEW;
|
|
break;
|
|
case RELKIND_INDEX:
|
|
/* deal with indexes specially; no need for tclass */
|
|
sepgsql_index_modify(relOid);
|
|
goto out;
|
|
default:
|
|
/* ignore other relkinds */
|
|
goto out;
|
|
}
|
|
|
|
/*
|
|
* Compute a default security label when we create a new relation object
|
|
* under the specified namespace.
|
|
*/
|
|
scontext = sepgsql_get_client_label();
|
|
tcontext = sepgsql_get_label(NamespaceRelationId,
|
|
classForm->relnamespace, 0);
|
|
rcontext = sepgsql_compute_create(scontext, tcontext, tclass,
|
|
NameStr(classForm->relname));
|
|
|
|
/*
|
|
* check db_xxx:{create} permission
|
|
*/
|
|
nsp_name = get_namespace_name(classForm->relnamespace);
|
|
initStringInfo(&audit_name);
|
|
appendStringInfo(&audit_name, "%s.%s",
|
|
quote_identifier(nsp_name),
|
|
quote_identifier(NameStr(classForm->relname)));
|
|
sepgsql_avc_check_perms_label(rcontext,
|
|
tclass,
|
|
SEPG_DB_DATABASE__CREATE,
|
|
audit_name.data,
|
|
true);
|
|
|
|
/*
|
|
* Assign the default security label on the new regular or partitioned
|
|
* relation.
|
|
*/
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = 0;
|
|
SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext);
|
|
|
|
/*
|
|
* We also assign a default security label on columns of a new table.
|
|
*/
|
|
if (classForm->relkind == RELKIND_RELATION ||
|
|
classForm->relkind == RELKIND_PARTITIONED_TABLE)
|
|
{
|
|
Relation arel;
|
|
ScanKeyData akey;
|
|
SysScanDesc ascan;
|
|
HeapTuple atup;
|
|
Form_pg_attribute attForm;
|
|
|
|
arel = table_open(AttributeRelationId, AccessShareLock);
|
|
|
|
ScanKeyInit(&akey,
|
|
Anum_pg_attribute_attrelid,
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
ObjectIdGetDatum(relOid));
|
|
|
|
ascan = systable_beginscan(arel, AttributeRelidNumIndexId, true,
|
|
SnapshotSelf, 1, &akey);
|
|
|
|
while (HeapTupleIsValid(atup = systable_getnext(ascan)))
|
|
{
|
|
attForm = (Form_pg_attribute) GETSTRUCT(atup);
|
|
|
|
resetStringInfo(&audit_name);
|
|
appendStringInfo(&audit_name, "%s.%s.%s",
|
|
quote_identifier(nsp_name),
|
|
quote_identifier(NameStr(classForm->relname)),
|
|
quote_identifier(NameStr(attForm->attname)));
|
|
|
|
ccontext = sepgsql_compute_create(scontext,
|
|
rcontext,
|
|
SEPG_CLASS_DB_COLUMN,
|
|
NameStr(attForm->attname));
|
|
|
|
/*
|
|
* check db_column:{create} permission
|
|
*/
|
|
sepgsql_avc_check_perms_label(ccontext,
|
|
SEPG_CLASS_DB_COLUMN,
|
|
SEPG_DB_COLUMN__CREATE,
|
|
audit_name.data,
|
|
true);
|
|
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = attForm->attnum;
|
|
SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext);
|
|
|
|
pfree(ccontext);
|
|
}
|
|
systable_endscan(ascan);
|
|
table_close(arel, AccessShareLock);
|
|
}
|
|
pfree(rcontext);
|
|
|
|
out:
|
|
systable_endscan(sscan);
|
|
table_close(rel, AccessShareLock);
|
|
}
|
|
|
|
/*
|
|
* sepgsql_relation_drop
|
|
*
|
|
* It checks privileges to drop the supplied relation.
|
|
*/
|
|
void
|
|
sepgsql_relation_drop(Oid relOid)
|
|
{
|
|
ObjectAddress object;
|
|
char *audit_name;
|
|
uint16_t tclass = 0;
|
|
char relkind = get_rel_relkind(relOid);
|
|
|
|
switch (relkind)
|
|
{
|
|
case RELKIND_RELATION:
|
|
case RELKIND_PARTITIONED_TABLE:
|
|
tclass = SEPG_CLASS_DB_TABLE;
|
|
break;
|
|
case RELKIND_SEQUENCE:
|
|
tclass = SEPG_CLASS_DB_SEQUENCE;
|
|
break;
|
|
case RELKIND_VIEW:
|
|
tclass = SEPG_CLASS_DB_VIEW;
|
|
break;
|
|
case RELKIND_INDEX:
|
|
/* ignore indexes on toast tables */
|
|
if (get_rel_namespace(relOid) == PG_TOAST_NAMESPACE)
|
|
return;
|
|
/* other indexes are handled specially below; no need for tclass */
|
|
break;
|
|
default:
|
|
/* ignore other relkinds */
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* check db_schema:{remove_name} permission
|
|
*/
|
|
object.classId = NamespaceRelationId;
|
|
object.objectId = get_rel_namespace(relOid);
|
|
object.objectSubId = 0;
|
|
audit_name = getObjectIdentity(&object, false);
|
|
|
|
sepgsql_avc_check_perms(&object,
|
|
SEPG_CLASS_DB_SCHEMA,
|
|
SEPG_DB_SCHEMA__REMOVE_NAME,
|
|
audit_name,
|
|
true);
|
|
pfree(audit_name);
|
|
|
|
/* deal with indexes specially */
|
|
if (relkind == RELKIND_INDEX)
|
|
{
|
|
sepgsql_index_modify(relOid);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* check db_table/sequence/view:{drop} permission
|
|
*/
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = 0;
|
|
audit_name = getObjectIdentity(&object, false);
|
|
|
|
sepgsql_avc_check_perms(&object,
|
|
tclass,
|
|
SEPG_DB_TABLE__DROP,
|
|
audit_name,
|
|
true);
|
|
pfree(audit_name);
|
|
|
|
/*
|
|
* check db_column:{drop} permission
|
|
*/
|
|
if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
|
|
{
|
|
Form_pg_attribute attForm;
|
|
CatCList *attrList;
|
|
HeapTuple atttup;
|
|
int i;
|
|
|
|
attrList = SearchSysCacheList1(ATTNUM, ObjectIdGetDatum(relOid));
|
|
for (i = 0; i < attrList->n_members; i++)
|
|
{
|
|
atttup = &attrList->members[i]->tuple;
|
|
attForm = (Form_pg_attribute) GETSTRUCT(atttup);
|
|
|
|
if (attForm->attisdropped)
|
|
continue;
|
|
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = attForm->attnum;
|
|
audit_name = getObjectIdentity(&object, false);
|
|
|
|
sepgsql_avc_check_perms(&object,
|
|
SEPG_CLASS_DB_COLUMN,
|
|
SEPG_DB_COLUMN__DROP,
|
|
audit_name,
|
|
true);
|
|
pfree(audit_name);
|
|
}
|
|
ReleaseCatCacheList(attrList);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* sepgsql_relation_truncate
|
|
*
|
|
* Check privileges to TRUNCATE the supplied relation.
|
|
*/
|
|
void
|
|
sepgsql_relation_truncate(Oid relOid)
|
|
{
|
|
ObjectAddress object;
|
|
char *audit_name;
|
|
uint16_t tclass = 0;
|
|
char relkind = get_rel_relkind(relOid);
|
|
|
|
switch (relkind)
|
|
{
|
|
case RELKIND_RELATION:
|
|
case RELKIND_PARTITIONED_TABLE:
|
|
tclass = SEPG_CLASS_DB_TABLE;
|
|
break;
|
|
default:
|
|
/* ignore other relkinds */
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* check db_table:{truncate} permission
|
|
*/
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = 0;
|
|
audit_name = getObjectIdentity(&object, false);
|
|
|
|
sepgsql_avc_check_perms(&object,
|
|
tclass,
|
|
SEPG_DB_TABLE__TRUNCATE,
|
|
audit_name,
|
|
true);
|
|
pfree(audit_name);
|
|
}
|
|
|
|
/*
|
|
* sepgsql_relation_relabel
|
|
*
|
|
* It checks privileges to relabel the supplied relation by the `seclabel'.
|
|
*/
|
|
void
|
|
sepgsql_relation_relabel(Oid relOid, const char *seclabel)
|
|
{
|
|
ObjectAddress object;
|
|
char *audit_name;
|
|
char relkind = get_rel_relkind(relOid);
|
|
uint16_t tclass = 0;
|
|
|
|
if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
|
|
tclass = SEPG_CLASS_DB_TABLE;
|
|
else if (relkind == RELKIND_SEQUENCE)
|
|
tclass = SEPG_CLASS_DB_SEQUENCE;
|
|
else if (relkind == RELKIND_VIEW)
|
|
tclass = SEPG_CLASS_DB_VIEW;
|
|
else
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
errmsg("cannot set security labels on relations except "
|
|
"for tables, sequences or views")));
|
|
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = 0;
|
|
audit_name = getObjectIdentity(&object, false);
|
|
|
|
/*
|
|
* check db_xxx:{setattr relabelfrom} permission
|
|
*/
|
|
sepgsql_avc_check_perms(&object,
|
|
tclass,
|
|
SEPG_DB_TABLE__SETATTR |
|
|
SEPG_DB_TABLE__RELABELFROM,
|
|
audit_name,
|
|
true);
|
|
|
|
/*
|
|
* check db_xxx:{relabelto} permission
|
|
*/
|
|
sepgsql_avc_check_perms_label(seclabel,
|
|
tclass,
|
|
SEPG_DB_TABLE__RELABELTO,
|
|
audit_name,
|
|
true);
|
|
pfree(audit_name);
|
|
}
|
|
|
|
/*
|
|
* sepgsql_relation_setattr
|
|
*
|
|
* It checks privileges to set attribute of the supplied relation
|
|
*/
|
|
void
|
|
sepgsql_relation_setattr(Oid relOid)
|
|
{
|
|
Relation rel;
|
|
ScanKeyData skey;
|
|
SysScanDesc sscan;
|
|
HeapTuple oldtup;
|
|
HeapTuple newtup;
|
|
Form_pg_class oldform;
|
|
Form_pg_class newform;
|
|
ObjectAddress object;
|
|
char *audit_name;
|
|
uint16_t tclass;
|
|
|
|
switch (get_rel_relkind(relOid))
|
|
{
|
|
case RELKIND_RELATION:
|
|
case RELKIND_PARTITIONED_TABLE:
|
|
tclass = SEPG_CLASS_DB_TABLE;
|
|
break;
|
|
case RELKIND_SEQUENCE:
|
|
tclass = SEPG_CLASS_DB_SEQUENCE;
|
|
break;
|
|
case RELKIND_VIEW:
|
|
tclass = SEPG_CLASS_DB_VIEW;
|
|
break;
|
|
case RELKIND_INDEX:
|
|
/* deal with indexes specially */
|
|
sepgsql_index_modify(relOid);
|
|
return;
|
|
default:
|
|
/* other relkinds don't need additional work */
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Fetch newer catalog
|
|
*/
|
|
rel = table_open(RelationRelationId, AccessShareLock);
|
|
|
|
ScanKeyInit(&skey,
|
|
Anum_pg_class_oid,
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
ObjectIdGetDatum(relOid));
|
|
|
|
sscan = systable_beginscan(rel, ClassOidIndexId, true,
|
|
SnapshotSelf, 1, &skey);
|
|
|
|
newtup = systable_getnext(sscan);
|
|
if (!HeapTupleIsValid(newtup))
|
|
elog(ERROR, "could not find tuple for relation %u", relOid);
|
|
newform = (Form_pg_class) GETSTRUCT(newtup);
|
|
|
|
/*
|
|
* Fetch older catalog
|
|
*/
|
|
oldtup = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
|
|
if (!HeapTupleIsValid(oldtup))
|
|
elog(ERROR, "cache lookup failed for relation %u", relOid);
|
|
oldform = (Form_pg_class) GETSTRUCT(oldtup);
|
|
|
|
/*
|
|
* Does this ALTER command takes operation to namespace?
|
|
*/
|
|
if (newform->relnamespace != oldform->relnamespace)
|
|
{
|
|
sepgsql_schema_remove_name(oldform->relnamespace);
|
|
sepgsql_schema_add_name(newform->relnamespace);
|
|
}
|
|
if (strcmp(NameStr(newform->relname), NameStr(oldform->relname)) != 0)
|
|
sepgsql_schema_rename(oldform->relnamespace);
|
|
|
|
/*
|
|
* XXX - In the future version, db_tuple:{use} of system catalog entry
|
|
* shall be checked, if tablespace configuration is changed.
|
|
*/
|
|
|
|
/*
|
|
* check db_xxx:{setattr} permission
|
|
*/
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relOid;
|
|
object.objectSubId = 0;
|
|
audit_name = getObjectIdentity(&object, false);
|
|
|
|
sepgsql_avc_check_perms(&object,
|
|
tclass,
|
|
SEPG_DB_TABLE__SETATTR,
|
|
audit_name,
|
|
true);
|
|
pfree(audit_name);
|
|
|
|
ReleaseSysCache(oldtup);
|
|
systable_endscan(sscan);
|
|
table_close(rel, AccessShareLock);
|
|
}
|
|
|
|
/*
|
|
* sepgsql_relation_setattr_extra
|
|
*
|
|
* It checks permission of the relation being referenced by extra attributes,
|
|
* such as pg_index entries. Like core PostgreSQL, sepgsql also does not deal
|
|
* with such entries as individual "objects", thus, modification of these
|
|
* entries shall be considered as setting an attribute of the underlying
|
|
* relation.
|
|
*/
|
|
static void
|
|
sepgsql_relation_setattr_extra(Relation catalog,
|
|
Oid catindex_id,
|
|
Oid extra_oid,
|
|
AttrNumber anum_relation_id,
|
|
AttrNumber anum_extra_id)
|
|
{
|
|
ScanKeyData skey;
|
|
SysScanDesc sscan;
|
|
HeapTuple tuple;
|
|
Datum datum;
|
|
bool isnull;
|
|
|
|
ScanKeyInit(&skey, anum_extra_id,
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
ObjectIdGetDatum(extra_oid));
|
|
|
|
sscan = systable_beginscan(catalog, catindex_id, true,
|
|
SnapshotSelf, 1, &skey);
|
|
tuple = systable_getnext(sscan);
|
|
if (!HeapTupleIsValid(tuple))
|
|
elog(ERROR, "could not find tuple for object %u in catalog \"%s\"",
|
|
extra_oid, RelationGetRelationName(catalog));
|
|
|
|
datum = heap_getattr(tuple, anum_relation_id,
|
|
RelationGetDescr(catalog), &isnull);
|
|
Assert(!isnull);
|
|
|
|
sepgsql_relation_setattr(DatumGetObjectId(datum));
|
|
|
|
systable_endscan(sscan);
|
|
}
|
|
|
|
/*
|
|
* sepgsql_index_modify
|
|
* Handle index create, update, drop
|
|
*
|
|
* Unlike other relation kinds, indexes do not have their own security labels,
|
|
* so instead of doing checks directly, treat them as extra attributes of their
|
|
* owning tables; so check 'setattr' permissions on the table.
|
|
*/
|
|
static void
|
|
sepgsql_index_modify(Oid indexOid)
|
|
{
|
|
Relation catalog = table_open(IndexRelationId, AccessShareLock);
|
|
|
|
/* check db_table:{setattr} permission of the table being indexed */
|
|
sepgsql_relation_setattr_extra(catalog,
|
|
IndexRelidIndexId,
|
|
indexOid,
|
|
Anum_pg_index_indrelid,
|
|
Anum_pg_index_indexrelid);
|
|
table_close(catalog, AccessShareLock);
|
|
}
|