mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-29 22:49:41 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			336 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* -------------------------------------------------------------------------
 | |
|  *
 | |
|  * contrib/sepgsql/proc.c
 | |
|  *
 | |
|  * Routines corresponding to procedure objects
 | |
|  *
 | |
|  * Copyright (c) 2010-2016, PostgreSQL Global Development Group
 | |
|  *
 | |
|  * -------------------------------------------------------------------------
 | |
|  */
 | |
| #include "postgres.h"
 | |
| 
 | |
| #include "access/genam.h"
 | |
| #include "access/heapam.h"
 | |
| #include "access/htup_details.h"
 | |
| #include "access/sysattr.h"
 | |
| #include "catalog/dependency.h"
 | |
| #include "catalog/indexing.h"
 | |
| #include "catalog/pg_namespace.h"
 | |
| #include "catalog/pg_proc.h"
 | |
| #include "catalog/pg_type.h"
 | |
| #include "commands/seclabel.h"
 | |
| #include "lib/stringinfo.h"
 | |
| #include "utils/builtins.h"
 | |
| #include "utils/fmgroids.h"
 | |
| #include "utils/lsyscache.h"
 | |
| #include "utils/syscache.h"
 | |
| #include "utils/tqual.h"
 | |
| 
 | |
| #include "sepgsql.h"
 | |
| 
 | |
| /*
 | |
|  * 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_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_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_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_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);
 | |
| }
 |