 contrib/sepgsql/expected/create.out |    4 +++
 contrib/sepgsql/hooks.c             |    7 ++++-
 contrib/sepgsql/schema.c            |   49 +++++++++++++++++++++++++---------
 contrib/sepgsql/sepgsql.h           |    3 +-
 contrib/sepgsql/sql/create.sql      |    6 ++++
 src/backend/catalog/namespace.c     |   17 +++++++++---
 src/backend/catalog/pg_namespace.c  |    7 +++--
 src/backend/commands/schemacmds.c   |    7 ++++-
 src/include/catalog/objectaccess.h  |   19 +++++++++++++
 src/include/catalog/pg_namespace.h  |    3 +-
 10 files changed, 98 insertions(+), 24 deletions(-)

diff --git a/contrib/sepgsql/expected/create.out b/contrib/sepgsql/expected/create.out
index 95fc4f1..3293a73 100644
--- a/contrib/sepgsql/expected/create.out
+++ b/contrib/sepgsql/expected/create.out
@@ -13,7 +13,11 @@ SET client_min_messages = LOG;
 CREATE DATABASE regtest_sepgsql_test_database;
 LOG:  SELinux: allowed { getattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database template1"
 LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database: regtest_sepgsql_test_database"
+CREATE SCHEMA regtest_schema;
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+SET search_path = regtest_schema, public;
 --
 -- clean-up 
 --
 DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
+DROP SCHEMA IF EXISTS regtest_schema CASCADE;
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index 886f1fa..2b62a75 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -141,6 +141,11 @@ sepgsql_object_prep_create(Oid classId, Oid objectId, int subId,
 											 args->pg_database.tablespaceId);
 			break;
 
+		case NamespaceRelationId:
+			cinfo->ncontext =
+				sepgsql_schema_prep_create(args->pg_namespace.nspname);
+			break;
+
 		default:
 			/* Ignore unsupported object classes */
 			break;
@@ -171,7 +176,7 @@ sepgsql_object_post_create(Oid classId, Oid objectId, int subId,
 			break;
 
 		case NamespaceRelationId:
-			sepgsql_schema_post_create(objectId);
+			sepgsql_schema_post_create(objectId, cinfo->ncontext);
 			break;
 
 		case RelationRelationId:
diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c
index a167be1..07dbf80 100644
--- a/contrib/sepgsql/schema.c
+++ b/contrib/sepgsql/schema.c
@@ -20,38 +20,61 @@
 #include "sepgsql.h"
 
 /*
- * sepgsql_schema_post_create
+ * sepgsql_schema_prep_create
  *
- * This routine assigns a default security label on a newly defined
- * schema.
+ * It computes a default security label of schema object, and checks
+ * permission to create a new schema object.
  */
-void
-sepgsql_schema_post_create(Oid namespaceId)
+const char *
+sepgsql_schema_prep_create(const char *nspname)
 {
-	char	   *scontext;
+	char	   *scontext = sepgsql_get_client_label();
 	char	   *tcontext;
 	char	   *ncontext;
-	ObjectAddress object;
+	char		audit_name[NAMEDATALEN + 16];
 
 	/*
 	 * Compute a default security label when we create a new schema object
 	 * under the working database.
 	 */
-	scontext = sepgsql_get_client_label();
 	tcontext = sepgsql_get_label(DatabaseRelationId, MyDatabaseId, 0);
 	ncontext = sepgsql_compute_create(scontext, tcontext,
 									  SEPG_CLASS_DB_SCHEMA);
 
 	/*
-	 * Assign the default security label on a new procedure
+	 * Check db_schema:{create} permission
 	 */
+	if (strncmp(nspname, "pg_temp_", 8) == 0)
+		snprintf(audit_name, sizeof(audit_name), "schema pg_temp");
+	else
+		snprintf(audit_name, sizeof(audit_name), "schema %s", nspname);
+
+	sepgsql_avc_check_perms_label(ncontext,
+								  SEPG_CLASS_DB_SCHEMA,
+								  SEPG_DB_SCHEMA__CREATE,
+								  audit_name,
+								  true);
+
+	pfree(tcontext);
+
+	return ncontext;
+}
+
+
+/*
+ * sepgsql_schema_post_create
+ *
+ * This routine assigns a default security label on a newly defined schema.
+ */
+void
+sepgsql_schema_post_create(Oid namespaceId, const char *seclabel)
+{
+	ObjectAddress	object;
+
 	object.classId = NamespaceRelationId;
 	object.objectId = namespaceId;
 	object.objectSubId = 0;
-	SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
-
-	pfree(ncontext);
-	pfree(tcontext);
+	SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, seclabel);
 }
 
 /*
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index 0d0eead..b4a3e4d 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -313,7 +313,8 @@ extern void sepgsql_database_relabel(Oid databaseId, const char *seclabel);
 /*
  * schema.c
  */
-extern void sepgsql_schema_post_create(Oid namespaceId);
+extern const char *sepgsql_schema_prep_create(const char *nspname);
+extern void sepgsql_schema_post_create(Oid namespaceId, const char *seclabel);
 extern void sepgsql_schema_relabel(Oid namespaceId, const char *seclabel);
 
 /*
diff --git a/contrib/sepgsql/sql/create.sql b/contrib/sepgsql/sql/create.sql
index e75d57b..9ce1db9 100644
--- a/contrib/sepgsql/sql/create.sql
+++ b/contrib/sepgsql/sql/create.sql
@@ -9,7 +9,13 @@ SET client_min_messages = LOG;
 
 CREATE DATABASE regtest_sepgsql_test_database;
 
+CREATE SCHEMA regtest_schema;
+
+SET search_path = regtest_schema, public;
+
 --
 -- clean-up 
 --
 DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
+
+DROP SCHEMA IF EXISTS regtest_schema CASCADE;
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index fcc90fe..3a0238f 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -21,6 +21,7 @@
 
 #include "access/xact.h"
 #include "catalog/dependency.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_conversion.h"
@@ -3384,9 +3385,12 @@ InitTempTableNamespace(void)
 	char		namespaceName[NAMEDATALEN];
 	Oid			namespaceId;
 	Oid			toastspaceId;
+	Datum		hook_private = 0;
 
 	Assert(!OidIsValid(myTempNamespace));
 
+	snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
+
 	/*
 	 * First, do permission check to see if we are authorized to make temp
 	 * tables.	We use a nonstandard error message here since "databasename:
@@ -3404,6 +3408,9 @@ InitTempTableNamespace(void)
 				 errmsg("permission denied to create temporary tables in database \"%s\"",
 						get_database_name(MyDatabaseId))));
 
+	/* Prep-creation hook for new temp-schema */
+	InvokePrepCreateSchemaHook(&hook_private, namespaceName);
+
 	/*
 	 * Do not allow a Hot Standby slave session to make temp tables.  Aside
 	 * from problems with modifying the system catalogs, there is a naming
@@ -3419,8 +3426,6 @@ InitTempTableNamespace(void)
 				(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
 				 errmsg("cannot create temporary tables during recovery")));
 
-	snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
-
 	namespaceId = get_namespace_oid(namespaceName, true);
 	if (!OidIsValid(namespaceId))
 	{
@@ -3432,7 +3437,9 @@ InitTempTableNamespace(void)
 		 * temp tables.  This works because the places that access the temp
 		 * namespace for my own backend skip permissions checks on it.
 		 */
-		namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID);
+		namespaceId = NamespaceCreate(namespaceName,
+									  BOOTSTRAP_SUPERUSERID,
+									  hook_private);
 		/* Advance command counter to make namespace visible */
 		CommandCounterIncrement();
 	}
@@ -3456,7 +3463,9 @@ InitTempTableNamespace(void)
 	toastspaceId = get_namespace_oid(namespaceName, true);
 	if (!OidIsValid(toastspaceId))
 	{
-		toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID);
+		toastspaceId = NamespaceCreate(namespaceName,
+									   BOOTSTRAP_SUPERUSERID,
+									   hook_private);
 		/* Advance command counter to make namespace visible */
 		CommandCounterIncrement();
 	}
diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c
index ceebac2..48b9fc9 100644
--- a/src/backend/catalog/pg_namespace.c
+++ b/src/backend/catalog/pg_namespace.c
@@ -29,7 +29,7 @@
  * ---------------
  */
 Oid
-NamespaceCreate(const char *nspName, Oid ownerId)
+NamespaceCreate(const char *nspName, Oid ownerId, Datum hook_private)
 {
 	Relation	nspdesc;
 	HeapTuple	tup;
@@ -86,7 +86,8 @@ NamespaceCreate(const char *nspName, Oid ownerId)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new schema */
-	InvokeObjectAccessHook(OAT_POST_CREATE, NamespaceRelationId, nspoid, 0);
-
+	InvokeObjectAccessHookArg(OAT_POST_CREATE,
+							  NamespaceRelationId, nspoid, 0,
+							  hook_private);
 	return nspoid;
 }
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 8daa9d0..d6f1927 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -19,6 +19,7 @@
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_namespace.h"
 #include "commands/dbcommands.h"
 #include "commands/schemacmds.h"
@@ -48,6 +49,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
 	Oid			owner_uid;
 	Oid			saved_uid;
 	int			save_sec_context;
+	Datum		hook_private = 0;
 	AclResult	aclresult;
 
 	GetUserIdAndSecContext(&saved_uid, &save_sec_context);
@@ -74,6 +76,9 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
 
 	check_is_member_of_role(saved_uid, owner_uid);
 
+	/* Prep-creation hook for new schema */
+	InvokePrepCreateSchemaHook(&hook_private, schemaName);
+
 	/* Additional check to protect reserved schema names */
 	if (!allowSystemTableMods && IsReservedName(schemaName))
 		ereport(ERROR,
@@ -94,7 +99,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
 							save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
 
 	/* Create the schema's namespace */
-	namespaceId = NamespaceCreate(schemaName, owner_uid);
+	namespaceId = NamespaceCreate(schemaName, owner_uid, hook_private);
 
 	/* Advance cmd counter to make the namespace visible */
 	CommandCounterIncrement();
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index 0531327..cb5c396 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -51,6 +51,10 @@ typedef union
 		Oid			datsourceId;	/* oid of source database */
 		Oid			tablespaceId;	/* oid of default tablespace */
 	} pg_database;
+	struct {
+		Datum	   *private;	/* common */
+		const char *nspname;	/* name of new schema */
+	} pg_namespace;
 } ObjectAccessCreateObjectArgs;
 
 /*
@@ -102,4 +106,19 @@ extern PGDLLIMPORT object_access_hook_type object_access_hook;
 		}																\
 	} while(0)
 
+#define InvokePrepCreateSchemaHook(_private,_nspname)					\
+	do {																\
+		if (object_access_hook)											\
+		{																\
+			ObjectAccessCreateObjectArgs	__args;						\
+																		\
+			__args.pg_namespace.private = (_private);					\
+			__args.pg_namespace.nspname = (_nspname);					\
+																		\
+			(*object_access_hook)(OAT_PREP_CREATE,						\
+								  NamespaceRelationId, InvalidOid, 0,	\
+								  PointerGetDatum(&__args));			\
+		}																\
+	} while(0)
+
 #endif   /* OBJECTACCESS_H */
diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h
index 680802d7..eedcf1b 100644
--- a/src/include/catalog/pg_namespace.h
+++ b/src/include/catalog/pg_namespace.h
@@ -77,6 +77,7 @@ DESCR("standard public schema");
 /*
  * prototypes for functions in pg_namespace.c
  */
-extern Oid	NamespaceCreate(const char *nspName, Oid ownerId);
+extern Oid	NamespaceCreate(const char *nspName, Oid ownerId,
+							Datum hook_private);
 
 #endif   /* PG_NAMESPACE_H */
