mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +03:00 
			
		
		
		
	The main change here is to call security_compute_create_name_raw() rather than security_compute_create_raw(). This ups the minimum requirement for libselinux from 2.0.99 to 2.1.10, but it looks like most distributions will have picked that up before 9.3 is out. KaiGai Kohei
		
			
				
	
	
		
			304 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			304 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* -------------------------------------------------------------------------
 | |
|  *
 | |
|  * contrib/sepgsql/proc.c
 | |
|  *
 | |
|  * Routines corresponding to procedure objects
 | |
|  *
 | |
|  * Copyright (c) 2010-2013, 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 "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	   *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,
 | |
| 							getObjectDescription(&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);
 | |
| 	appendStringInfo(&audit_name, "function %s(", NameStr(proForm->proname));
 | |
| 	for (i = 0; i < proForm->pronargs; i++)
 | |
| 	{
 | |
| 		Oid			typeoid = proForm->proargtypes.values[i];
 | |
| 
 | |
| 		if (i > 0)
 | |
| 			appendStringInfoChar(&audit_name, ',');
 | |
| 		appendStringInfoString(&audit_name, format_type_be(typeoid));
 | |
| 	}
 | |
| 	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 = getObjectDescription(&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 = getObjectDescription(&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 = getObjectDescription(&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 = getObjectDescription(&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);
 | |
| }
 |