 contrib/sepgsql/expected/create.out |   13 +++++++-
 contrib/sepgsql/proc.c              |   55 +++++++++++++++++++++++++++++++----
 contrib/sepgsql/sql/create.sql      |    7 ++++
 3 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/contrib/sepgsql/expected/create.out b/contrib/sepgsql/expected/create.out
index d2c30f0..ec52700 100644
--- a/contrib/sepgsql/expected/create.out
+++ b/contrib/sepgsql/expected/create.out
@@ -42,12 +42,23 @@ LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_
 CREATE SEQUENCE regtest_seq;
 LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
 LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq"
+CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql
+	   AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END';
+LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function regtest_func(text,integer[])"
+CREATE AGGREGATE regtest_agg (*) (
+	   sfunc = int8inc, stype = int8, initcond = '0'
+);
+LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function regtest_agg()"
 --
 -- clean-up
 --
 DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
 DROP SCHEMA IF EXISTS regtest_schema CASCADE;
-NOTICE:  drop cascades to 3 other objects
+NOTICE:  drop cascades to 5 other objects
 DETAIL:  drop cascades to table regtest_table
 drop cascades to view regtest_view
 drop cascades to sequence regtest_seq
+drop cascades to function regtest_func(text,integer[])
+drop cascades to function regtest_agg()
diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c
index 9630d45..14231c4 100644
--- a/contrib/sepgsql/proc.c
+++ b/contrib/sepgsql/proc.c
@@ -18,6 +18,7 @@
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_proc.h"
 #include "commands/seclabel.h"
+#include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/tqual.h"
@@ -37,11 +38,13 @@ sepgsql_proc_post_create(Oid functionId)
 	ScanKeyData skey;
 	SysScanDesc sscan;
 	HeapTuple	tuple;
-	Oid			namespaceId;
-	ObjectAddress object;
 	char	   *scontext;
 	char	   *tcontext;
 	char	   *ncontext;
+	int			i;
+	StringInfoData	audit_name;
+	ObjectAddress	object;
+	Form_pg_proc	proForm;
 
 	/*
 	 * Fetch namespace of the new procedure. Because pg_proc entry is not
@@ -61,21 +64,54 @@ sepgsql_proc_post_create(Oid functionId)
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "catalog lookup failed for proc %u", functionId);
 
-	namespaceId = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace;
+	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
+	 */
 
-	systable_endscan(sscan);
-	heap_close(rel, AccessShareLock);
 
 	/*
 	 * 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, namespaceId, 0);
+	tcontext = sepgsql_get_label(NamespaceRelationId,
+								 proForm->pronamespace, 0);
 	ncontext = sepgsql_compute_create(scontext, tcontext,
 									  SEPG_CLASS_DB_PROCEDURE);
 
 	/*
+	 * check db_procedure:{create} 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, ')');
+
+	sepgsql_avc_check_perms_label(ncontext,
+								  SEPG_CLASS_DB_PROCEDURE,
+								  SEPG_DB_PROCEDURE__CREATE,
+								  audit_name.data,
+								  true);
+	/*
 	 * Assign the default security label on a new procedure
 	 */
 	object.classId = ProcedureRelationId;
@@ -83,6 +119,13 @@ sepgsql_proc_post_create(Oid 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);
 }
diff --git a/contrib/sepgsql/sql/create.sql b/contrib/sepgsql/sql/create.sql
index 9cb2b60..512c114 100644
--- a/contrib/sepgsql/sql/create.sql
+++ b/contrib/sepgsql/sql/create.sql
@@ -25,6 +25,13 @@ CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100;
 
 CREATE SEQUENCE regtest_seq;
 
+CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql
+	   AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END';
+
+CREATE AGGREGATE regtest_agg (*) (
+	   sfunc = int8inc, stype = int8, initcond = '0'
+);
+
 --
 -- clean-up
 --
