/* * sepgsql_proc_relabel * * It checks privileges to relabel the supplied function * by the `seclabel'. */ void sepgsql_proc_relabel(Oid functionId, const char *seclabel) { ObjectAddress object; char *audit_name; object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; audit_name = getObjectIdentity(&object); /* * check db_procedure:{setattr relabelfrom} permission */ sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_PROCEDURE, SEPG_DB_PROCEDURE__SETATTR | SEPG_DB_PROCEDURE__RELABELFROM, audit_name, true); /* * check db_procedure:{relabelto} permission */ sepgsql_avc_check_perms_label(seclabel, SEPG_CLASS_DB_PROCEDURE, 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); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_COLUMN, SEPG_DB_COLUMN__SETATTR, audit_name, true); pfree(audit_name); }
/* * sepgsql_schema_relabel * * It checks privileges to relabel the supplied schema * by the `seclabel'. */ void sepgsql_schema_relabel(Oid namespaceId, const char *seclabel) { ObjectAddress object; char *audit_name; object.classId = NamespaceRelationId; object.objectId = namespaceId; object.objectSubId = 0; audit_name = getObjectIdentity(&object); /* * check db_schema:{setattr relabelfrom} permission */ sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__SETATTR | SEPG_DB_SCHEMA__RELABELFROM, audit_name, true); /* * check db_schema:{relabelto} permission */ sepgsql_avc_check_perms_label(seclabel, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__RELABELTO, audit_name, true); pfree(audit_name); }
/* * sepgsql_database_relabel * * It checks privileges to relabel the supplied database with the `seclabel' */ void sepgsql_database_relabel(Oid databaseId, const char *seclabel) { ObjectAddress object; char *audit_name; object.classId = DatabaseRelationId; object.objectId = databaseId; object.objectSubId = 0; audit_name = getObjectIdentity(&object); /* * check db_database:{setattr relabelfrom} permission */ sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_DATABASE, SEPG_DB_DATABASE__SETATTR | SEPG_DB_DATABASE__RELABELFROM, audit_name, true); /* * check db_database:{relabelto} permission */ sepgsql_avc_check_perms_label(seclabel, SEPG_CLASS_DB_DATABASE, SEPG_DB_DATABASE__RELABELTO, audit_name, true); pfree(audit_name); }
/* * sepgsql_proc_drop * * It checks privileges to drop the supplied function. */ void sepgsql_proc_drop(Oid functionId) { ObjectAddress object; char *audit_name; /* * check db_schema:{remove_name} permission */ object.classId = NamespaceRelationId; object.objectId = get_func_namespace(functionId); object.objectSubId = 0; audit_name = getObjectIdentity(&object); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__REMOVE_NAME, audit_name, true); pfree(audit_name); /* * check db_procedure:{drop} permission */ object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; audit_name = getObjectIdentity(&object); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_PROCEDURE, SEPG_DB_PROCEDURE__DROP, 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; uint16_t tclass = 0; relkind = get_rel_relkind(relOid); if (relkind == RELKIND_RELATION) 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); /* * 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_proc_execute * * It checks privileges to execute the supplied function */ void sepgsql_proc_execute(Oid functionId) { ObjectAddress object; char *audit_name; /* * check db_procedure:{execute} permission */ object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; audit_name = getObjectIdentity(&object); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_PROCEDURE, SEPG_DB_PROCEDURE__EXECUTE, audit_name, true); pfree(audit_name); }
/* * sepgsql_database_post_alter * * It checks privileges to alter the supplied database */ void sepgsql_database_setattr(Oid databaseId) { ObjectAddress object; char *audit_name; /* * check db_database:{setattr} permission */ object.classId = DatabaseRelationId; object.objectId = databaseId; object.objectSubId = 0; audit_name = getObjectIdentity(&object); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_DATABASE, SEPG_DB_DATABASE__SETATTR, audit_name, true); pfree(audit_name); }
/* * sepgsql_schema_check_perms * * utility routine to check db_schema:{xxx} permissions */ static bool check_schema_perms(Oid namespaceId, uint32 required, bool abort_on_violation) { ObjectAddress object; char *audit_name; bool result; object.classId = NamespaceRelationId; object.objectId = namespaceId; object.objectSubId = 0; audit_name = getObjectIdentity(&object); result = sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, required, audit_name, abort_on_violation); pfree(audit_name); return result; }
/* * sepgsql_schema_drop * * It checks privileges to drop the supplied schema object. */ void sepgsql_schema_drop(Oid namespaceId) { ObjectAddress object; char *audit_name; /* * check db_schema:{drop} permission */ object.classId = NamespaceRelationId; object.objectId = namespaceId; object.objectSubId = 0; audit_name = getObjectIdentity(&object); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__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); /* * 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_drop * * It checks privileges to drop the supplied column. */ void sepgsql_attribute_drop(Oid relOid, AttrNumber attnum) { ObjectAddress object; char *audit_name; if (get_rel_relkind(relOid) != RELKIND_RELATION) return; /* * check db_column:{drop} permission */ object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attnum; audit_name = getObjectIdentity(&object); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_COLUMN, SEPG_DB_COLUMN__DROP, audit_name, true); pfree(audit_name); }
/* * check_relation_privileges * * It actually checks required permissions on a certain relation * and its columns. */ static bool check_relation_privileges(Oid relOid, Bitmapset *selected, Bitmapset *inserted, Bitmapset *updated, uint32 required, bool abort_on_violation) { ObjectAddress object; char *audit_name; Bitmapset *columns; int index; char relkind = get_rel_relkind(relOid); bool result = true; /* * Hardwired Policies: SE-PostgreSQL enforces - clients cannot modify * system catalogs using DMLs - clients cannot reference/modify toast * relations using DMLs */ if (sepgsql_getenforce() > 0) { Oid relnamespace = get_rel_namespace(relOid); if (IsSystemNamespace(relnamespace) && (required & (SEPG_DB_TABLE__UPDATE | SEPG_DB_TABLE__INSERT | SEPG_DB_TABLE__DELETE)) != 0) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("SELinux: hardwired security policy violation"))); if (relkind == RELKIND_TOASTVALUE) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("SELinux: hardwired security policy violation"))); } /* * Check permissions on the relation */ object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; audit_name = getObjectIdentity(&object); switch (relkind) { case RELKIND_RELATION: case RELKIND_PARTITIONED_TABLE: result = sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_TABLE, required, audit_name, abort_on_violation); break; case RELKIND_SEQUENCE: Assert((required & ~SEPG_DB_TABLE__SELECT) == 0); if (required & SEPG_DB_TABLE__SELECT) result = sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SEQUENCE, SEPG_DB_SEQUENCE__GET_VALUE, audit_name, abort_on_violation); break; case RELKIND_VIEW: result = sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_VIEW, SEPG_DB_VIEW__EXPAND, audit_name, abort_on_violation); break; default: /* nothing to be checked */ break; } pfree(audit_name); /* * Only columns owned by relations shall be checked */ if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE) return true; /* * Check permissions on the columns */ selected = fixup_whole_row_references(relOid, selected); inserted = fixup_whole_row_references(relOid, inserted); updated = fixup_whole_row_references(relOid, updated); columns = bms_union(selected, bms_union(inserted, updated)); while ((index = bms_first_member(columns)) >= 0) { AttrNumber attnum; uint32 column_perms = 0; if (bms_is_member(index, selected)) column_perms |= SEPG_DB_COLUMN__SELECT; if (bms_is_member(index, inserted)) { if (required & SEPG_DB_TABLE__INSERT) column_perms |= SEPG_DB_COLUMN__INSERT; } if (bms_is_member(index, updated)) { if (required & SEPG_DB_TABLE__UPDATE) column_perms |= SEPG_DB_COLUMN__UPDATE; } if (column_perms == 0) continue; /* obtain column's permission */ attnum = index + FirstLowInvalidHeapAttributeNumber; object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attnum; audit_name = getObjectDescription(&object); result = sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_COLUMN, column_perms, audit_name, abort_on_violation); pfree(audit_name); if (!result) return result; } return true; }
/* * sepgsql_proc_setattr * * It checks privileges to alter the supplied function. */ void sepgsql_proc_setattr(Oid functionId) { Relation rel; ScanKeyData skey; SysScanDesc sscan; HeapTuple oldtup; HeapTuple newtup; Form_pg_proc oldform; Form_pg_proc newform; uint32 required; ObjectAddress object; char *audit_name; /* * Fetch newer catalog */ rel = heap_open(ProcedureRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(functionId)); sscan = systable_beginscan(rel, ProcedureOidIndexId, true, SnapshotSelf, 1, &skey); newtup = systable_getnext(sscan); if (!HeapTupleIsValid(newtup)) elog(ERROR, "catalog lookup failed for function %u", functionId); newform = (Form_pg_proc) GETSTRUCT(newtup); /* * Fetch older catalog */ oldtup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId)); if (!HeapTupleIsValid(oldtup)) elog(ERROR, "cache lookup failed for function %u", functionId); oldform = (Form_pg_proc) GETSTRUCT(oldtup); /* * Does this ALTER command takes operation to namespace? */ if (newform->pronamespace != oldform->pronamespace) { sepgsql_schema_remove_name(oldform->pronamespace); sepgsql_schema_add_name(oldform->pronamespace); } if (strcmp(NameStr(newform->proname), NameStr(oldform->proname)) != 0) sepgsql_schema_rename(oldform->pronamespace); /* * check db_procedure:{setattr (install)} permission */ required = SEPG_DB_PROCEDURE__SETATTR; if (!oldform->proleakproof && newform->proleakproof) required |= SEPG_DB_PROCEDURE__INSTALL; object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; audit_name = getObjectIdentity(&object); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_PROCEDURE, required, audit_name, true); /* cleanups */ pfree(audit_name); ReleaseSysCache(oldtup); systable_endscan(sscan); heap_close(rel, AccessShareLock); }
/* * 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: 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 = heap_open(RelationRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relOid)); sscan = systable_beginscan(rel, ClassOidIndexId, true, SnapshotSelf, 1, &skey); newtup = systable_getnext(sscan); if (!HeapTupleIsValid(newtup)) elog(ERROR, "catalog lookup failed 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); sepgsql_avc_check_perms(&object, tclass, SEPG_DB_TABLE__SETATTR, audit_name, true); pfree(audit_name); ReleaseSysCache(oldtup); systable_endscan(sscan); heap_close(rel, AccessShareLock); }
/* * sepgsql_proc_post_create * * This routine assigns a default security label on a newly defined * procedure. */ void sepgsql_proc_post_create(Oid functionId) { Relation rel; ScanKeyData skey; SysScanDesc sscan; HeapTuple tuple; char *nsp_name; char *scontext; char *tcontext; char *ncontext; uint32 required; int i; StringInfoData audit_name; ObjectAddress object; Form_pg_proc proForm; /* * Fetch namespace of the new procedure. Because pg_proc entry is not * visible right now, we need to scan the catalog using SnapshotSelf. */ rel = heap_open(ProcedureRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(functionId)); sscan = systable_beginscan(rel, ProcedureOidIndexId, true, SnapshotSelf, 1, &skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed for proc %u", functionId); proForm = (Form_pg_proc) GETSTRUCT(tuple); /* * check db_schema:{add_name} permission of the namespace */ object.classId = NamespaceRelationId; object.objectId = proForm->pronamespace; object.objectSubId = 0; sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__ADD_NAME, getObjectIdentity(&object), true); /* * XXX - db_language:{implement} also should be checked here */ /* * Compute a default security label when we create a new procedure object * under the specified namespace. */ scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(NamespaceRelationId, proForm->pronamespace, 0); ncontext = sepgsql_compute_create(scontext, tcontext, SEPG_CLASS_DB_PROCEDURE, NameStr(proForm->proname)); /* * check db_procedure:{create (install)} permission */ initStringInfo(&audit_name); nsp_name = get_namespace_name(proForm->pronamespace); appendStringInfo(&audit_name, "%s(", quote_qualified_identifier(nsp_name, NameStr(proForm->proname))); for (i = 0; i < proForm->pronargs; i++) { if (i > 0) appendStringInfoChar(&audit_name, ','); object.classId = TypeRelationId; object.objectId = proForm->proargtypes.values[i]; object.objectSubId = 0; appendStringInfoString(&audit_name, getObjectIdentity(&object)); } appendStringInfoChar(&audit_name, ')'); required = SEPG_DB_PROCEDURE__CREATE; if (proForm->proleakproof) required |= SEPG_DB_PROCEDURE__INSTALL; sepgsql_avc_check_perms_label(ncontext, SEPG_CLASS_DB_PROCEDURE, required, audit_name.data, true); /* * Assign the default security label on a new procedure */ object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); /* * Cleanup */ systable_endscan(sscan); heap_close(rel, AccessShareLock); pfree(audit_name.data); pfree(tcontext); pfree(ncontext); }
/* * 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; /* * Only attributes within regular relation have individual security * labels. */ if (get_rel_relkind(relOid) != RELKIND_RELATION) return; /* * Compute a default security label of the new column underlying the * specified relation, and check permission to create it. */ rel = heap_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, "catalog lookup failed 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), 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); heap_close(rel, AccessShareLock); pfree(tcontext); pfree(ncontext); }
/* * 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; char relkind; relkind = get_rel_relkind(relOid); switch (relkind) { case RELKIND_RELATION: 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); 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); 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) { 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); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_COLUMN, SEPG_DB_COLUMN__DROP, audit_name, true); pfree(audit_name); } ReleaseCatCacheList(attrList); } }
/* * 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 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 = heap_open(RelationRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relOid)); sscan = systable_beginscan(rel, ClassOidIndexId, true, SnapshotSelf, 1, &skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed 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), true); switch (classForm->relkind) { case RELKIND_RELATION: 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 relation */ object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext); /* * We also assigns a default security label on columns of the new regular * tables. */ if (classForm->relkind == RELKIND_RELATION) { Relation arel; ScanKeyData akey; SysScanDesc ascan; HeapTuple atup; Form_pg_attribute attForm; arel = heap_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); heap_close(arel, AccessShareLock); } pfree(rcontext); out: systable_endscan(sscan); heap_close(rel, AccessShareLock); }