diff options
| author | vvvv <[email protected]> | 2024-11-07 12:29:36 +0300 | 
|---|---|---|
| committer | vvvv <[email protected]> | 2024-11-07 13:49:47 +0300 | 
| commit | d4c258e9431675bab6745c8638df6e3dfd4dca6b (patch) | |
| tree | b5efcfa11351152a4c872fccaea35749141c0b11 /yql/essentials/parser/pg_wrapper/postgresql/src/backend/commands/seclabel.c | |
| parent | 13a4f274caef5cfdaf0263b24e4d6bdd5521472b (diff) | |
Moved other yql/essentials libs YQL-19206
init
commit_hash:7d4c435602078407bbf20dd3c32f9c90d2bbcbc0
Diffstat (limited to 'yql/essentials/parser/pg_wrapper/postgresql/src/backend/commands/seclabel.c')
| -rw-r--r-- | yql/essentials/parser/pg_wrapper/postgresql/src/backend/commands/seclabel.c | 581 | 
1 files changed, 581 insertions, 0 deletions
diff --git a/yql/essentials/parser/pg_wrapper/postgresql/src/backend/commands/seclabel.c b/yql/essentials/parser/pg_wrapper/postgresql/src/backend/commands/seclabel.c new file mode 100644 index 00000000000..2b14aaf5bc1 --- /dev/null +++ b/yql/essentials/parser/pg_wrapper/postgresql/src/backend/commands/seclabel.c @@ -0,0 +1,581 @@ +/* ------------------------------------------------------------------------- + * + * seclabel.c + *	  routines to support security label feature. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/relation.h" +#include "access/table.h" +#include "catalog/catalog.h" +#include "catalog/indexing.h" +#include "catalog/pg_seclabel.h" +#include "catalog/pg_shseclabel.h" +#include "commands/seclabel.h" +#include "miscadmin.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/memutils.h" +#include "utils/rel.h" + +typedef struct +{ +	const char *provider_name; +	check_object_relabel_type hook; +} LabelProvider; + +static __thread List *label_provider_list = NIL; + +static bool +SecLabelSupportsObjectType(ObjectType objtype) +{ +	switch (objtype) +	{ +		case OBJECT_AGGREGATE: +		case OBJECT_COLUMN: +		case OBJECT_DATABASE: +		case OBJECT_DOMAIN: +		case OBJECT_EVENT_TRIGGER: +		case OBJECT_FOREIGN_TABLE: +		case OBJECT_FUNCTION: +		case OBJECT_LANGUAGE: +		case OBJECT_LARGEOBJECT: +		case OBJECT_MATVIEW: +		case OBJECT_PROCEDURE: +		case OBJECT_PUBLICATION: +		case OBJECT_ROLE: +		case OBJECT_ROUTINE: +		case OBJECT_SCHEMA: +		case OBJECT_SEQUENCE: +		case OBJECT_SUBSCRIPTION: +		case OBJECT_TABLE: +		case OBJECT_TABLESPACE: +		case OBJECT_TYPE: +		case OBJECT_VIEW: +			return true; + +		case OBJECT_ACCESS_METHOD: +		case OBJECT_AMOP: +		case OBJECT_AMPROC: +		case OBJECT_ATTRIBUTE: +		case OBJECT_CAST: +		case OBJECT_COLLATION: +		case OBJECT_CONVERSION: +		case OBJECT_DEFAULT: +		case OBJECT_DEFACL: +		case OBJECT_DOMCONSTRAINT: +		case OBJECT_EXTENSION: +		case OBJECT_FDW: +		case OBJECT_FOREIGN_SERVER: +		case OBJECT_INDEX: +		case OBJECT_OPCLASS: +		case OBJECT_OPERATOR: +		case OBJECT_OPFAMILY: +		case OBJECT_PARAMETER_ACL: +		case OBJECT_POLICY: +		case OBJECT_PUBLICATION_NAMESPACE: +		case OBJECT_PUBLICATION_REL: +		case OBJECT_RULE: +		case OBJECT_STATISTIC_EXT: +		case OBJECT_TABCONSTRAINT: +		case OBJECT_TRANSFORM: +		case OBJECT_TRIGGER: +		case OBJECT_TSCONFIGURATION: +		case OBJECT_TSDICTIONARY: +		case OBJECT_TSPARSER: +		case OBJECT_TSTEMPLATE: +		case OBJECT_USER_MAPPING: +			return false; + +			/* +			 * There's intentionally no default: case here; we want the +			 * compiler to warn if a new ObjectType hasn't been handled above. +			 */ +	} + +	/* Shouldn't get here, but if we do, say "no support" */ +	return false; +} + +/* + * ExecSecLabelStmt -- + * + * Apply a security label to a database object. + * + * Returns the ObjectAddress of the object to which the policy was applied. + */ +ObjectAddress +ExecSecLabelStmt(SecLabelStmt *stmt) +{ +	LabelProvider *provider = NULL; +	ObjectAddress address; +	Relation	relation; +	ListCell   *lc; + +	/* +	 * Find the named label provider, or if none specified, check whether +	 * there's exactly one, and if so use it. +	 */ +	if (stmt->provider == NULL) +	{ +		if (label_provider_list == NIL) +			ereport(ERROR, +					(errcode(ERRCODE_INVALID_PARAMETER_VALUE), +					 errmsg("no security label providers have been loaded"))); +		if (list_length(label_provider_list) != 1) +			ereport(ERROR, +					(errcode(ERRCODE_INVALID_PARAMETER_VALUE), +					 errmsg("must specify provider when multiple security label providers have been loaded"))); +		provider = (LabelProvider *) linitial(label_provider_list); +	} +	else +	{ +		foreach(lc, label_provider_list) +		{ +			LabelProvider *lp = lfirst(lc); + +			if (strcmp(stmt->provider, lp->provider_name) == 0) +			{ +				provider = lp; +				break; +			} +		} +		if (provider == NULL) +			ereport(ERROR, +					(errcode(ERRCODE_INVALID_PARAMETER_VALUE), +					 errmsg("security label provider \"%s\" is not loaded", +							stmt->provider))); +	} + +	if (!SecLabelSupportsObjectType(stmt->objtype)) +		ereport(ERROR, +				(errcode(ERRCODE_WRONG_OBJECT_TYPE), +				 errmsg("security labels are not supported for this type of object"))); + +	/* +	 * Translate the parser representation which identifies this object into +	 * an ObjectAddress. get_object_address() will throw an error if the +	 * object does not exist, and will also acquire a lock on the target to +	 * guard against concurrent modifications. +	 */ +	address = get_object_address(stmt->objtype, stmt->object, +								 &relation, ShareUpdateExclusiveLock, false); + +	/* Require ownership of the target object. */ +	check_object_ownership(GetUserId(), stmt->objtype, address, +						   stmt->object, relation); + +	/* Perform other integrity checks as needed. */ +	switch (stmt->objtype) +	{ +		case OBJECT_COLUMN: + +			/* +			 * Allow security labels only on columns of tables, views, +			 * materialized views, composite types, and foreign tables (which +			 * are the only relkinds for which pg_dump will dump labels). +			 */ +			if (relation->rd_rel->relkind != RELKIND_RELATION && +				relation->rd_rel->relkind != RELKIND_VIEW && +				relation->rd_rel->relkind != RELKIND_MATVIEW && +				relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE && +				relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE && +				relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) +				ereport(ERROR, +						(errcode(ERRCODE_WRONG_OBJECT_TYPE), +						 errmsg("cannot set security label on relation \"%s\"", +								RelationGetRelationName(relation)), +						 errdetail_relkind_not_supported(relation->rd_rel->relkind))); +			break; +		default: +			break; +	} + +	/* Provider gets control here, may throw ERROR to veto new label. */ +	provider->hook(&address, stmt->label); + +	/* Apply new label. */ +	SetSecurityLabel(&address, provider->provider_name, stmt->label); + +	/* +	 * If get_object_address() opened the relation for us, we close it to keep +	 * the reference count correct - but we retain any locks acquired by +	 * get_object_address() until commit time, to guard against concurrent +	 * activity. +	 */ +	if (relation != NULL) +		relation_close(relation, NoLock); + +	return address; +} + +/* + * GetSharedSecurityLabel returns the security label for a shared object for + * a given provider, or NULL if there is no such label. + */ +static char * +GetSharedSecurityLabel(const ObjectAddress *object, const char *provider) +{ +	Relation	pg_shseclabel; +	ScanKeyData keys[3]; +	SysScanDesc scan; +	HeapTuple	tuple; +	Datum		datum; +	bool		isnull; +	char	   *seclabel = NULL; + +	ScanKeyInit(&keys[0], +				Anum_pg_shseclabel_objoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(object->objectId)); +	ScanKeyInit(&keys[1], +				Anum_pg_shseclabel_classoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(object->classId)); +	ScanKeyInit(&keys[2], +				Anum_pg_shseclabel_provider, +				BTEqualStrategyNumber, F_TEXTEQ, +				CStringGetTextDatum(provider)); + +	pg_shseclabel = table_open(SharedSecLabelRelationId, AccessShareLock); + +	scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, +							  criticalSharedRelcachesBuilt, NULL, 3, keys); + +	tuple = systable_getnext(scan); +	if (HeapTupleIsValid(tuple)) +	{ +		datum = heap_getattr(tuple, Anum_pg_shseclabel_label, +							 RelationGetDescr(pg_shseclabel), &isnull); +		if (!isnull) +			seclabel = TextDatumGetCString(datum); +	} +	systable_endscan(scan); + +	table_close(pg_shseclabel, AccessShareLock); + +	return seclabel; +} + +/* + * GetSecurityLabel returns the security label for a shared or database object + * for a given provider, or NULL if there is no such label. + */ +char * +GetSecurityLabel(const ObjectAddress *object, const char *provider) +{ +	Relation	pg_seclabel; +	ScanKeyData keys[4]; +	SysScanDesc scan; +	HeapTuple	tuple; +	Datum		datum; +	bool		isnull; +	char	   *seclabel = NULL; + +	/* Shared objects have their own security label catalog. */ +	if (IsSharedRelation(object->classId)) +		return GetSharedSecurityLabel(object, provider); + +	/* Must be an unshared object, so examine pg_seclabel. */ +	ScanKeyInit(&keys[0], +				Anum_pg_seclabel_objoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(object->objectId)); +	ScanKeyInit(&keys[1], +				Anum_pg_seclabel_classoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(object->classId)); +	ScanKeyInit(&keys[2], +				Anum_pg_seclabel_objsubid, +				BTEqualStrategyNumber, F_INT4EQ, +				Int32GetDatum(object->objectSubId)); +	ScanKeyInit(&keys[3], +				Anum_pg_seclabel_provider, +				BTEqualStrategyNumber, F_TEXTEQ, +				CStringGetTextDatum(provider)); + +	pg_seclabel = table_open(SecLabelRelationId, AccessShareLock); + +	scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true, +							  NULL, 4, keys); + +	tuple = systable_getnext(scan); +	if (HeapTupleIsValid(tuple)) +	{ +		datum = heap_getattr(tuple, Anum_pg_seclabel_label, +							 RelationGetDescr(pg_seclabel), &isnull); +		if (!isnull) +			seclabel = TextDatumGetCString(datum); +	} +	systable_endscan(scan); + +	table_close(pg_seclabel, AccessShareLock); + +	return seclabel; +} + +/* + * SetSharedSecurityLabel is a helper function of SetSecurityLabel to + * handle shared database objects. + */ +static void +SetSharedSecurityLabel(const ObjectAddress *object, +					   const char *provider, const char *label) +{ +	Relation	pg_shseclabel; +	ScanKeyData keys[4]; +	SysScanDesc scan; +	HeapTuple	oldtup; +	HeapTuple	newtup = NULL; +	Datum		values[Natts_pg_shseclabel]; +	bool		nulls[Natts_pg_shseclabel]; +	bool		replaces[Natts_pg_shseclabel]; + +	/* Prepare to form or update a tuple, if necessary. */ +	memset(nulls, false, sizeof(nulls)); +	memset(replaces, false, sizeof(replaces)); +	values[Anum_pg_shseclabel_objoid - 1] = ObjectIdGetDatum(object->objectId); +	values[Anum_pg_shseclabel_classoid - 1] = ObjectIdGetDatum(object->classId); +	values[Anum_pg_shseclabel_provider - 1] = CStringGetTextDatum(provider); +	if (label != NULL) +		values[Anum_pg_shseclabel_label - 1] = CStringGetTextDatum(label); + +	/* Use the index to search for a matching old tuple */ +	ScanKeyInit(&keys[0], +				Anum_pg_shseclabel_objoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(object->objectId)); +	ScanKeyInit(&keys[1], +				Anum_pg_shseclabel_classoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(object->classId)); +	ScanKeyInit(&keys[2], +				Anum_pg_shseclabel_provider, +				BTEqualStrategyNumber, F_TEXTEQ, +				CStringGetTextDatum(provider)); + +	pg_shseclabel = table_open(SharedSecLabelRelationId, RowExclusiveLock); + +	scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true, +							  NULL, 3, keys); + +	oldtup = systable_getnext(scan); +	if (HeapTupleIsValid(oldtup)) +	{ +		if (label == NULL) +			CatalogTupleDelete(pg_shseclabel, &oldtup->t_self); +		else +		{ +			replaces[Anum_pg_shseclabel_label - 1] = true; +			newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_shseclabel), +									   values, nulls, replaces); +			CatalogTupleUpdate(pg_shseclabel, &oldtup->t_self, newtup); +		} +	} +	systable_endscan(scan); + +	/* If we didn't find an old tuple, insert a new one */ +	if (newtup == NULL && label != NULL) +	{ +		newtup = heap_form_tuple(RelationGetDescr(pg_shseclabel), +								 values, nulls); +		CatalogTupleInsert(pg_shseclabel, newtup); +	} + +	if (newtup != NULL) +		heap_freetuple(newtup); + +	table_close(pg_shseclabel, RowExclusiveLock); +} + +/* + * SetSecurityLabel attempts to set the security label for the specified + * provider on the specified object to the given value.  NULL means that any + * existing label should be deleted. + */ +void +SetSecurityLabel(const ObjectAddress *object, +				 const char *provider, const char *label) +{ +	Relation	pg_seclabel; +	ScanKeyData keys[4]; +	SysScanDesc scan; +	HeapTuple	oldtup; +	HeapTuple	newtup = NULL; +	Datum		values[Natts_pg_seclabel]; +	bool		nulls[Natts_pg_seclabel]; +	bool		replaces[Natts_pg_seclabel]; + +	/* Shared objects have their own security label catalog. */ +	if (IsSharedRelation(object->classId)) +	{ +		SetSharedSecurityLabel(object, provider, label); +		return; +	} + +	/* Prepare to form or update a tuple, if necessary. */ +	memset(nulls, false, sizeof(nulls)); +	memset(replaces, false, sizeof(replaces)); +	values[Anum_pg_seclabel_objoid - 1] = ObjectIdGetDatum(object->objectId); +	values[Anum_pg_seclabel_classoid - 1] = ObjectIdGetDatum(object->classId); +	values[Anum_pg_seclabel_objsubid - 1] = Int32GetDatum(object->objectSubId); +	values[Anum_pg_seclabel_provider - 1] = CStringGetTextDatum(provider); +	if (label != NULL) +		values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(label); + +	/* Use the index to search for a matching old tuple */ +	ScanKeyInit(&keys[0], +				Anum_pg_seclabel_objoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(object->objectId)); +	ScanKeyInit(&keys[1], +				Anum_pg_seclabel_classoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(object->classId)); +	ScanKeyInit(&keys[2], +				Anum_pg_seclabel_objsubid, +				BTEqualStrategyNumber, F_INT4EQ, +				Int32GetDatum(object->objectSubId)); +	ScanKeyInit(&keys[3], +				Anum_pg_seclabel_provider, +				BTEqualStrategyNumber, F_TEXTEQ, +				CStringGetTextDatum(provider)); + +	pg_seclabel = table_open(SecLabelRelationId, RowExclusiveLock); + +	scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true, +							  NULL, 4, keys); + +	oldtup = systable_getnext(scan); +	if (HeapTupleIsValid(oldtup)) +	{ +		if (label == NULL) +			CatalogTupleDelete(pg_seclabel, &oldtup->t_self); +		else +		{ +			replaces[Anum_pg_seclabel_label - 1] = true; +			newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_seclabel), +									   values, nulls, replaces); +			CatalogTupleUpdate(pg_seclabel, &oldtup->t_self, newtup); +		} +	} +	systable_endscan(scan); + +	/* If we didn't find an old tuple, insert a new one */ +	if (newtup == NULL && label != NULL) +	{ +		newtup = heap_form_tuple(RelationGetDescr(pg_seclabel), +								 values, nulls); +		CatalogTupleInsert(pg_seclabel, newtup); +	} + +	/* Update indexes, if necessary */ +	if (newtup != NULL) +		heap_freetuple(newtup); + +	table_close(pg_seclabel, RowExclusiveLock); +} + +/* + * DeleteSharedSecurityLabel is a helper function of DeleteSecurityLabel + * to handle shared database objects. + */ +void +DeleteSharedSecurityLabel(Oid objectId, Oid classId) +{ +	Relation	pg_shseclabel; +	ScanKeyData skey[2]; +	SysScanDesc scan; +	HeapTuple	oldtup; + +	ScanKeyInit(&skey[0], +				Anum_pg_shseclabel_objoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(objectId)); +	ScanKeyInit(&skey[1], +				Anum_pg_shseclabel_classoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(classId)); + +	pg_shseclabel = table_open(SharedSecLabelRelationId, RowExclusiveLock); + +	scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true, +							  NULL, 2, skey); +	while (HeapTupleIsValid(oldtup = systable_getnext(scan))) +		CatalogTupleDelete(pg_shseclabel, &oldtup->t_self); +	systable_endscan(scan); + +	table_close(pg_shseclabel, RowExclusiveLock); +} + +/* + * DeleteSecurityLabel removes all security labels for an object (and any + * sub-objects, if applicable). + */ +void +DeleteSecurityLabel(const ObjectAddress *object) +{ +	Relation	pg_seclabel; +	ScanKeyData skey[3]; +	SysScanDesc scan; +	HeapTuple	oldtup; +	int			nkeys; + +	/* Shared objects have their own security label catalog. */ +	if (IsSharedRelation(object->classId)) +	{ +		Assert(object->objectSubId == 0); +		DeleteSharedSecurityLabel(object->objectId, object->classId); +		return; +	} + +	ScanKeyInit(&skey[0], +				Anum_pg_seclabel_objoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(object->objectId)); +	ScanKeyInit(&skey[1], +				Anum_pg_seclabel_classoid, +				BTEqualStrategyNumber, F_OIDEQ, +				ObjectIdGetDatum(object->classId)); +	if (object->objectSubId != 0) +	{ +		ScanKeyInit(&skey[2], +					Anum_pg_seclabel_objsubid, +					BTEqualStrategyNumber, F_INT4EQ, +					Int32GetDatum(object->objectSubId)); +		nkeys = 3; +	} +	else +		nkeys = 2; + +	pg_seclabel = table_open(SecLabelRelationId, RowExclusiveLock); + +	scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true, +							  NULL, nkeys, skey); +	while (HeapTupleIsValid(oldtup = systable_getnext(scan))) +		CatalogTupleDelete(pg_seclabel, &oldtup->t_self); +	systable_endscan(scan); + +	table_close(pg_seclabel, RowExclusiveLock); +} + +void +register_label_provider(const char *provider_name, check_object_relabel_type hook) +{ +	LabelProvider *provider; +	MemoryContext oldcxt; + +	oldcxt = MemoryContextSwitchTo(TopMemoryContext); +	provider = palloc(sizeof(LabelProvider)); +	provider->provider_name = pstrdup(provider_name); +	provider->hook = hook; +	label_provider_list = lappend(label_provider_list, provider); +	MemoryContextSwitchTo(oldcxt); +}  | 
