pgsql-v9.2-drop-permissions.v3.patch

application/octet-stream

Filename: pgsql-v9.2-drop-permissions.v3.patch
Type: application/octet-stream
Part: 0
Message: Re: [v9.2] sepgsql's DROP Permission checks

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v9
File+
contrib/sepgsql/database.c 27 0
contrib/sepgsql/expected/create.out 0 80
contrib/sepgsql/expected/ddl.out 164 0
contrib/sepgsql/hooks.c 38 2
contrib/sepgsql/proc.c 42 0
contrib/sepgsql/relation.c 119 0
contrib/sepgsql/schema.c 27 0
contrib/sepgsql/sepgsql.h 5 0
contrib/sepgsql/sql/create.sql 0 46
contrib/sepgsql/sql/ddl.sql 81 0
contrib/sepgsql/test_sepgsql 1 1
doc/src/sgml/sepgsql.sgml 14 0
src/backend/catalog/dependency.c 46 8
src/backend/commands/cluster.c 2 2
src/backend/commands/dbcommands.c 3 0
src/backend/commands/tablecmds.c 3 3
src/backend/commands/tablespace.c 3 0
src/backend/commands/user.c 4 0
src/backend/postmaster/autovacuum.c 1 1
src/include/catalog/dependency.h 3 0
src/include/catalog/objectaccess.h 21 2
diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c
index be3a7be..0c395c4 100644
--- a/contrib/sepgsql/database.c
+++ b/contrib/sepgsql/database.c
@@ -119,6 +119,33 @@ sepgsql_database_post_create(Oid databaseId, const char *dtemplate)
 }
 
 /*
+ * sepgsql_database_drop
+ *
+ * It checks privileges to drop the supplied database
+ */
+void
+sepgsql_database_drop(Oid databaseId)
+{
+	ObjectAddress	object;
+	char		   *audit_name;
+
+	/*
+	 * check db_database:{drop} permission
+	 */
+	object.classId = DatabaseRelationId;
+	object.objectId = databaseId;
+	object.objectSubId = 0;
+	audit_name = getObjectDescription(&object);
+
+	sepgsql_avc_check_perms(&object,
+							SEPG_CLASS_DB_DATABASE,
+							SEPG_DB_DATABASE__DROP,
+							audit_name,
+							true);
+	pfree(audit_name);
+}
+
+/*
  * sepgsql_database_relabel
  *
  * It checks privileges to relabel the supplied database with the `seclabel'
diff --git a/contrib/sepgsql/expected/create.out b/contrib/sepgsql/expected/create.out
deleted file mode 100644
index 0f04a3e..0000000
--- a/contrib/sepgsql/expected/create.out
+++ /dev/null
@@ -1,80 +0,0 @@
---
--- Regression Test for Creation of Object Permission Checks
---
--- confirm required permissions using audit messages
-SELECT sepgsql_getcon();	-- confirm client privilege
-              sepgsql_getcon               
--------------------------------------------
- unconfined_u:unconfined_r:unconfined_t:s0
-(1 row)
-
-SET sepgsql.debug_audit = true;
-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;
-CREATE TABLE regtest_table (x serial primary key, y text);
-NOTICE:  CREATE TABLE will create implicit sequence "regtest_table_x_seq" for serial column "regtest_table.x"
-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_table_x_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_table_t:s0 tclass=db_table name="table regtest_table"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column tableoid"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmax"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column xmax"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmin"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column xmin"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column ctid"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column x"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column y"
-NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "regtest_table_pkey" for table "regtest_table"
-ALTER TABLE regtest_table ADD COLUMN z int;
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column z"
-CREATE TABLE regtest_table_2 (a int) WITH OIDS;
-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_table_t:s0 tclass=db_table name="table regtest_table_2"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column tableoid"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column cmax"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column xmax"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column cmin"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column xmin"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column oid"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column ctid"
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column a"
--- corresponding toast table should not have label and permission checks
-ALTER TABLE regtest_table_2 ADD COLUMN b text;
-LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column b"
--- VACUUM FULL internally create a new table and swap them later.
-VACUUM FULL regtest_table;
-CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100;
-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_view_t:s0 tclass=db_view name="view regtest_view"
-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 TYPE regtest_comptype AS (a int, b text);
-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 (
-           sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '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(integer)"
---
--- clean-up
---
-DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
-DROP SCHEMA IF EXISTS regtest_schema CASCADE;
-NOTICE:  drop cascades to 7 other objects
-DETAIL:  drop cascades to table regtest_table
-drop cascades to table regtest_table_2
-drop cascades to view regtest_view
-drop cascades to sequence regtest_seq
-drop cascades to type regtest_comptype
-drop cascades to function regtest_func(text,integer[])
-drop cascades to function regtest_agg(integer)
diff --git a/contrib/sepgsql/expected/ddl.out b/contrib/sepgsql/expected/ddl.out
new file mode 100644
index 0000000..1c7bcc5
--- /dev/null
+++ b/contrib/sepgsql/expected/ddl.out
@@ -0,0 +1,164 @@
+--
+-- Regression Test for DDL of Object Permission Checks
+--
+-- confirm required permissions using audit messages
+SELECT sepgsql_getcon();	-- confirm client privilege
+              sepgsql_getcon               
+-------------------------------------------
+ unconfined_u:unconfined_r:unconfined_t:s0
+(1 row)
+
+SET sepgsql.debug_audit = true;
+SET client_min_messages = LOG;
+--
+-- CREATE Permission checks
+--
+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 USER regtest_sepgsql_test_user;
+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"
+GRANT ALL ON SCHEMA regtest_schema TO regtest_sepgsql_test_user;
+SET search_path = regtest_schema, public;
+CREATE TABLE regtest_table (x serial primary key, y text);
+NOTICE:  CREATE TABLE will create implicit sequence "regtest_table_x_seq" for serial column "regtest_table.x"
+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_table_x_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_table_t:s0 tclass=db_table name="table regtest_table"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column tableoid"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmax"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column xmax"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmin"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column xmin"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column ctid"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column x"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column y"
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "regtest_table_pkey" for table "regtest_table"
+ALTER TABLE regtest_table ADD COLUMN z int;
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column z"
+CREATE TABLE regtest_table_2 (a int) WITH OIDS;
+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_table_t:s0 tclass=db_table name="table regtest_table_2"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column tableoid"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column cmax"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column xmax"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column cmin"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column xmin"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column oid"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column ctid"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column a"
+-- corresponding toast table should not have label and permission checks
+ALTER TABLE regtest_table_2 ADD COLUMN b text;
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column b"
+-- VACUUM FULL internally create a new table and swap them later.
+VACUUM FULL regtest_table;
+CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100;
+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_view_t:s0 tclass=db_view name="view regtest_view"
+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 TYPE regtest_comptype AS (a int, b text);
+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 (
+           sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '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(integer)"
+-- CREATE objects owned by others
+SET SESSION AUTHORIZATION regtest_sepgsql_test_user;
+SET search_path = regtest_schema, public;
+CREATE TABLE regtest_table_3 (x int, y serial);
+NOTICE:  CREATE TABLE will create implicit sequence "regtest_table_3_y_seq" for serial column "regtest_table_3.y"
+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_table_3_y_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_table_t:s0 tclass=db_table name="table regtest_table_3"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column tableoid"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column cmax"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column xmax"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column cmin"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column xmin"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column ctid"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column x"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column y"
+CREATE VIEW regtest_view_2 AS SELECT * FROM regtest_table_3 WHERE x < y;
+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_view_t:s0 tclass=db_view name="view regtest_view_2"
+CREATE FUNCTION regtest_func_2(int) RETURNS bool LANGUAGE plpgsql
+           AS 'BEGIN RETURN $1 * $1 < 100; 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_2(integer)"
+RESET SESSION AUTHORIZATION;
+--
+-- DROP Permission checks (with clean-up)
+--
+DROP FUNCTION regtest_func(text,int[]);
+LOG:  SELinux: allowed { remove_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 { drop } 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[])"
+DROP AGGREGATE regtest_agg(int);
+LOG:  SELinux: allowed { remove_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 { drop } 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(integer)"
+DROP SEQUENCE regtest_seq;
+LOG:  SELinux: allowed { remove_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 { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq"
+DROP VIEW regtest_view;
+LOG:  SELinux: allowed { remove_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 { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view"
+ALTER TABLE regtest_table DROP COLUMN y;
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column y"
+ALTER TABLE regtest_table_2 SET WITHOUT OIDS;
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column oid"
+DROP TABLE regtest_table;
+LOG:  SELinux: allowed { remove_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 { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_table_x_seq"
+LOG:  SELinux: allowed { remove_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 { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column tableoid"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmax"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column xmax"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmin"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column xmin"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column ctid"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column x"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column z"
+DROP OWNED BY regtest_sepgsql_test_user;
+LOG:  SELinux: allowed { remove_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 { drop } 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_2(integer)"
+LOG:  SELinux: allowed { remove_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 { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view_2"
+LOG:  SELinux: allowed { remove_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 { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_table_3_y_seq"
+LOG:  SELinux: allowed { remove_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 { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_3"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column tableoid"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column cmax"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column xmax"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column cmin"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column xmin"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column ctid"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column x"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column y"
+DROP DATABASE regtest_sepgsql_test_database;
+LOG:  SELinux: allowed { drop } 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"
+DROP USER regtest_sepgsql_test_user;
+DROP SCHEMA IF EXISTS regtest_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table regtest_table_2
+drop cascades to type regtest_comptype
+LOG:  SELinux: allowed { remove_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 { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_2"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column tableoid"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column cmax"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column xmax"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column cmin"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column xmin"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column ctid"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column a"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column b"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index 47437ba..cad031d 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -133,10 +133,11 @@ static void
 sepgsql_object_access(ObjectAccessType access,
 					  Oid classId,
 					  Oid objectId,
-					  int subId)
+					  int subId,
+					  Datum arg)
 {
 	if (next_object_access_hook)
-		(*next_object_access_hook) (access, classId, objectId, subId);
+		(*next_object_access_hook) (access, classId, objectId, subId, arg);
 
 	switch (access)
 	{
@@ -192,6 +193,41 @@ sepgsql_object_access(ObjectAccessType access,
 			}
 			break;
 
+		case OAT_DROP:
+			/*
+			 * SELinux does not apply permission checks on internal cleanup
+			 * of database objects.
+			 */
+			if (DatumGetInt32(arg) & OAT_DROP_FLAGS_INTERNAL)
+				break;
+
+			switch (classId)
+			{
+				case DatabaseRelationId:
+					sepgsql_database_drop(objectId);
+					break;
+
+				case NamespaceRelationId:
+					sepgsql_schema_drop(objectId);
+					break;
+
+				case RelationRelationId:
+					if (subId == 0)
+						sepgsql_relation_drop(objectId);
+					else
+						sepgsql_attribute_drop(objectId, subId);
+					break;
+
+				case ProcedureRelationId:
+					sepgsql_proc_drop(objectId);
+					break;
+
+				default:
+					/* Ignore unsupported object classes */
+					break;
+			}
+			break;
+
 		default:
 			elog(ERROR, "unexpected object access type: %d", (int) access);
 			break;
diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c
index b902797..1efbc90 100644
--- a/contrib/sepgsql/proc.c
+++ b/contrib/sepgsql/proc.c
@@ -131,6 +131,48 @@ sepgsql_proc_post_create(Oid functionId)
 }
 
 /*
+ * 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
diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c
index efce914..259be49 100644
--- a/contrib/sepgsql/relation.c
+++ b/contrib/sepgsql/relation.c
@@ -21,6 +21,7 @@
 #include "commands/seclabel.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
+#include "utils/syscache.h"
 #include "utils/tqual.h"
 
 #include "sepgsql.h"
@@ -110,6 +111,36 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
 }
 
 /*
+ * sepgsql_attribute_drop
+ *
+ * It checks privileges to drop the supplied column.
+ */
+void
+sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
+{
+	ObjectAddress	object;
+	char		   *audit_name;
+
+	if (get_rel_relkind(relOid) != RELKIND_RELATION)
+		return;
+
+	/*
+	 * check db_column:{drop} permission
+	 */
+	object.classId = RelationRelationId;
+	object.objectId = relOid;
+	object.objectSubId = attnum;
+	audit_name = getObjectDescription(&object);
+
+	sepgsql_avc_check_perms(&object,
+							SEPG_CLASS_DB_COLUMN,
+							SEPG_DB_COLUMN__DROP,
+							audit_name,
+							true);
+	pfree(audit_name);
+}
+
+/*
  * sepgsql_attribute_relabel
  *
  * It checks privileges to relabel the supplied column
@@ -310,6 +341,94 @@ out:
 }
 
 /*
+ * sepgsql_relation_drop
+ *
+ * It checks privileges to drop the supplied relation.
+ */
+void
+sepgsql_relation_drop(Oid relOid)
+{
+	ObjectAddress	object;
+	char		   *audit_name;
+	uint16_t		tclass = 0;
+	char			relkind;
+
+	relkind = get_rel_relkind(relOid);
+	if (relkind == RELKIND_RELATION)
+		tclass = SEPG_CLASS_DB_TABLE;
+	else if (relkind == RELKIND_SEQUENCE)
+		tclass = SEPG_CLASS_DB_SEQUENCE;
+	else if (relkind == RELKIND_VIEW)
+		tclass = SEPG_CLASS_DB_VIEW;
+	else
+		return;
+
+	/*
+	 * check db_schema:{remove_name} permission
+	 */
+	object.classId = NamespaceRelationId;
+	object.objectId = get_rel_namespace(relOid);
+	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_table/sequence/view:{drop} permission
+	 */
+	object.classId = RelationRelationId;
+	object.objectId = relOid;
+	object.objectSubId = 0;
+	audit_name = getObjectDescription(&object);
+
+	sepgsql_avc_check_perms(&object,
+							tclass,
+							SEPG_DB_TABLE__DROP,
+							audit_name,
+							true);
+	pfree(audit_name);
+
+	/*
+	 * check db_column:{drop} permission
+	 */
+	if (relkind == RELKIND_RELATION)
+	{
+		Form_pg_attribute	attForm;
+		CatCList   *attrList;
+		HeapTuple	atttup;
+		int			i;
+
+		attrList = SearchSysCacheList1(ATTNUM, ObjectIdGetDatum(relOid));
+		for (i=0; i < attrList->n_members; i++)
+		{
+			atttup = &attrList->members[i]->tuple;
+			attForm = (Form_pg_attribute) GETSTRUCT(atttup);
+
+			if (attForm->attisdropped)
+				continue;
+
+			object.classId = RelationRelationId;
+			object.objectId = relOid;
+			object.objectSubId = attForm->attnum;
+			audit_name = getObjectDescription(&object);
+
+			sepgsql_avc_check_perms(&object,
+									SEPG_CLASS_DB_COLUMN,
+									SEPG_DB_COLUMN__DROP,
+									audit_name,
+									true);
+			pfree(audit_name);
+		}
+		ReleaseCatCacheList(attrList);
+	}
+}
+
+/*
  * sepgsql_relation_relabel
  *
  * It checks privileges to relabel the supplied relation by the `seclabel'.
diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c
index 90dca1d..31d60ef 100644
--- a/contrib/sepgsql/schema.c
+++ b/contrib/sepgsql/schema.c
@@ -97,6 +97,33 @@ sepgsql_schema_post_create(Oid namespaceId)
 }
 
 /*
+ * sepgsql_schema_drop
+ *
+ * It checks privileges to drop the supplied schema object.
+ */
+void
+sepgsql_schema_drop(Oid namespaceId)
+{
+	ObjectAddress	object;
+	char		   *audit_name;
+
+	/*
+	 * check db_schema:{drop} permission
+	 */
+	object.classId = NamespaceRelationId;
+	object.objectId = namespaceId;
+	object.objectSubId = 0;
+	audit_name = getObjectDescription(&object);
+
+	sepgsql_avc_check_perms(&object,
+                            SEPG_CLASS_DB_SCHEMA,
+							SEPG_DB_SCHEMA__DROP,
+							audit_name,
+							true);
+	pfree(audit_name);
+}
+
+/*
  * sepgsql_schema_relabel
  *
  * It checks privileges to relabel the supplied schema
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index c93da7a..a7a4532 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -288,27 +288,32 @@ extern bool sepgsql_dml_privileges(List *rangeTabls, bool abort);
  */
 extern void sepgsql_database_post_create(Oid databaseId,
 										 const char *dtemplate);
+extern void sepgsql_database_drop(Oid databaseId);
 extern void sepgsql_database_relabel(Oid databaseId, const char *seclabel);
 
 /*
  * schema.c
  */
 extern void sepgsql_schema_post_create(Oid namespaceId);
+extern void sepgsql_schema_drop(Oid namespaceId);
 extern void sepgsql_schema_relabel(Oid namespaceId, const char *seclabel);
 
 /*
  * relation.c
  */
 extern void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum);
+extern void sepgsql_attribute_drop(Oid relOid, AttrNumber attnum);
 extern void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
 						  const char *seclabel);
 extern void sepgsql_relation_post_create(Oid relOid);
+extern void sepgsql_relation_drop(Oid relOid);
 extern void sepgsql_relation_relabel(Oid relOid, const char *seclabel);
 
 /*
  * proc.c
  */
 extern void sepgsql_proc_post_create(Oid functionId);
+extern void sepgsql_proc_drop(Oid functionId);
 extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
 
 #endif   /* SEPGSQL_H */
diff --git a/contrib/sepgsql/sql/create.sql b/contrib/sepgsql/sql/create.sql
deleted file mode 100644
index b0695b4..0000000
--- a/contrib/sepgsql/sql/create.sql
+++ /dev/null
@@ -1,46 +0,0 @@
---
--- Regression Test for Creation of Object Permission Checks
---
-
--- confirm required permissions using audit messages
--- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0
-SET sepgsql.debug_audit = true;
-SET client_min_messages = LOG;
-
-CREATE DATABASE regtest_sepgsql_test_database;
-
-CREATE SCHEMA regtest_schema;
-
-SET search_path = regtest_schema, public;
-
-CREATE TABLE regtest_table (x serial primary key, y text);
-
-ALTER TABLE regtest_table ADD COLUMN z int;
-
-CREATE TABLE regtest_table_2 (a int) WITH OIDS;
-
--- corresponding toast table should not have label and permission checks
-ALTER TABLE regtest_table_2 ADD COLUMN b text;
-
--- VACUUM FULL internally create a new table and swap them later.
-VACUUM FULL regtest_table;
-
-CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100;
-
-CREATE SEQUENCE regtest_seq;
-
-CREATE TYPE regtest_comptype AS (a int, b text);
-
-CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql
-	   AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END';
-
-CREATE AGGREGATE regtest_agg (
-           sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '0'
-);
-
---
--- clean-up
---
-DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
-
-DROP SCHEMA IF EXISTS regtest_schema CASCADE;
diff --git a/contrib/sepgsql/sql/ddl.sql b/contrib/sepgsql/sql/ddl.sql
new file mode 100644
index 0000000..8dd57e0
--- /dev/null
+++ b/contrib/sepgsql/sql/ddl.sql
@@ -0,0 +1,81 @@
+--
+-- Regression Test for DDL of Object Permission Checks
+--
+
+-- confirm required permissions using audit messages
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0
+SET sepgsql.debug_audit = true;
+SET client_min_messages = LOG;
+
+--
+-- CREATE Permission checks
+--
+CREATE DATABASE regtest_sepgsql_test_database;
+
+CREATE USER regtest_sepgsql_test_user;
+
+CREATE SCHEMA regtest_schema;
+
+GRANT ALL ON SCHEMA regtest_schema TO regtest_sepgsql_test_user;
+
+SET search_path = regtest_schema, public;
+
+CREATE TABLE regtest_table (x serial primary key, y text);
+
+ALTER TABLE regtest_table ADD COLUMN z int;
+
+CREATE TABLE regtest_table_2 (a int) WITH OIDS;
+
+-- corresponding toast table should not have label and permission checks
+ALTER TABLE regtest_table_2 ADD COLUMN b text;
+
+-- VACUUM FULL internally create a new table and swap them later.
+VACUUM FULL regtest_table;
+
+CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100;
+
+CREATE SEQUENCE regtest_seq;
+
+CREATE TYPE regtest_comptype AS (a int, b text);
+
+CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql
+	   AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END';
+
+CREATE AGGREGATE regtest_agg (
+           sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '0'
+);
+
+-- CREATE objects owned by others
+SET SESSION AUTHORIZATION regtest_sepgsql_test_user;
+
+SET search_path = regtest_schema, public;
+
+CREATE TABLE regtest_table_3 (x int, y serial);
+
+CREATE VIEW regtest_view_2 AS SELECT * FROM regtest_table_3 WHERE x < y;
+
+CREATE FUNCTION regtest_func_2(int) RETURNS bool LANGUAGE plpgsql
+           AS 'BEGIN RETURN $1 * $1 < 100; END';
+
+RESET SESSION AUTHORIZATION;
+
+--
+-- DROP Permission checks (with clean-up)
+--
+
+DROP FUNCTION regtest_func(text,int[]);
+DROP AGGREGATE regtest_agg(int);
+
+DROP SEQUENCE regtest_seq;
+DROP VIEW regtest_view;
+
+ALTER TABLE regtest_table DROP COLUMN y;
+ALTER TABLE regtest_table_2 SET WITHOUT OIDS;
+
+DROP TABLE regtest_table;
+
+DROP OWNED BY regtest_sepgsql_test_user;
+
+DROP DATABASE regtest_sepgsql_test_database;
+DROP USER regtest_sepgsql_test_user;
+DROP SCHEMA IF EXISTS regtest_schema CASCADE;
diff --git a/contrib/sepgsql/test_sepgsql b/contrib/sepgsql/test_sepgsql
index 52237e6..473004f 100755
--- a/contrib/sepgsql/test_sepgsql
+++ b/contrib/sepgsql/test_sepgsql
@@ -259,6 +259,6 @@ echo "found ${NUM}"
 echo
 echo "============== running sepgsql regression tests       =============="
 
-make REGRESS="label dml create misc" REGRESS_OPTS="--launcher ./launcher" installcheck
+make REGRESS="label dml ddl misc" REGRESS_OPTS="--launcher ./launcher" installcheck
 
 # exit with the exit code provided by "make"
diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml
index e45c258..d9b1fed 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -448,6 +448,20 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
    </para>
 
    <para>
+    When <literal>DROP</> command is executed, <literal>drop</> will be
+    checked on the object being removed for each object types.
+    Please note that it shall not be checked on the objects removed by
+    cascaded deletion according to the standard manner in SQL.
+   </para>
+   <para>
+    A few additional checks are applied depending on object types.
+    On deletion of objects underlying a particula schema (tables, views,
+    sequences and procedures), <literal>remove_name</> shall be also checked
+    on the schema, not only <literal>drop</> on the object being removed
+    itself.
+   </para>
+
+   <para>
     When <xref linkend="sql-security-label"> is executed, <literal>setattr</>
     and <literal>relabelfrom</> will be checked on the object being relabeled
     with its old security label, then <literal>relabelto</> with the supplied
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 0b3d489..58855dd 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -20,6 +20,7 @@
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_amop.h"
 #include "catalog/pg_amproc.h"
 #include "catalog/pg_attrdef.h"
@@ -171,7 +172,8 @@ static void reportDependentObjects(const ObjectAddresses *targetObjects,
 					   DropBehavior behavior,
 					   int msglevel,
 					   const ObjectAddress *origObject);
-static void deleteOneObject(const ObjectAddress *object, Relation depRel);
+static void deleteOneObject(const ObjectAddress *object,
+							Relation depRel, int32 flags);
 static void doDeletion(const ObjectAddress *object);
 static void AcquireDeletionLock(const ObjectAddress *object);
 static void ReleaseDeletionLock(const ObjectAddress *object);
@@ -201,14 +203,17 @@ static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
  * objects, except for those that should be implicitly dropped anyway
  * according to the dependency type.
  *
+ * performInternalDeletion: same as performDeletion except for a flag
+ * being informed to extension module via object-access-hook.
+ *
  * This is the outer control routine for all forms of DROP that drop objects
  * that can participate in dependencies.  Note that the next two routines
  * are variants on the same theme; if you change anything here you'll likely
  * need to fix them too.
  */
-void
-performDeletion(const ObjectAddress *object,
-				DropBehavior behavior)
+static void
+execPerformDeletion(const ObjectAddress *object,
+					DropBehavior behavior, bool is_internal)
 {
 	Relation	depRel;
 	ObjectAddresses *targetObjects;
@@ -253,8 +258,15 @@ performDeletion(const ObjectAddress *object,
 	for (i = 0; i < targetObjects->numrefs; i++)
 	{
 		ObjectAddress *thisobj = targetObjects->refs + i;
+		ObjectAddressExtra *thisextra = targetObjects->extras + i;
+		int32	flags = 0;
+
+		if ((thisextra->flags & DEPFLAG_ORIGINAL) == 0)
+			flags |= OAT_DROP_FLAGS_CASCADED;
+		if (is_internal)
+			flags |= OAT_DROP_FLAGS_INTERNAL;
 
-		deleteOneObject(thisobj, depRel);
+		deleteOneObject(thisobj, depRel, flags);
 	}
 
 	/* And clean up */
@@ -263,6 +275,18 @@ performDeletion(const ObjectAddress *object,
 	heap_close(depRel, RowExclusiveLock);
 }
 
+void
+performDeletion(const ObjectAddress *object, DropBehavior behavior)
+{
+	execPerformDeletion(object, behavior, false);
+}
+
+void
+performInternalDeletion(const ObjectAddress *object, DropBehavior behavior)
+{
+	execPerformDeletion(object, behavior, true);
+}
+
 /*
  * performMultipleDeletions: Similar to performDeletion, but act on multiple
  * objects at once.
@@ -335,8 +359,13 @@ performMultipleDeletions(const ObjectAddresses *objects,
 	for (i = 0; i < targetObjects->numrefs; i++)
 	{
 		ObjectAddress *thisobj = targetObjects->refs + i;
+		ObjectAddressExtra *thisextra = targetObjects->extras + i;
+		int32	flags = 0;
 
-		deleteOneObject(thisobj, depRel);
+		if ((thisextra->flags & DEPFLAG_ORIGINAL) == 0)
+			flags |= OAT_DROP_FLAGS_CASCADED;
+
+		deleteOneObject(thisobj, depRel, flags);
 	}
 
 	/* And clean up */
@@ -407,7 +436,8 @@ deleteWhatDependsOn(const ObjectAddress *object,
 		if (thisextra->flags & DEPFLAG_ORIGINAL)
 			continue;
 
-		deleteOneObject(thisobj, depRel);
+		deleteOneObject(thisobj, depRel,
+						OAT_DROP_FLAGS_CASCADED | OAT_DROP_FLAGS_INTERNAL);
 	}
 
 	/* And clean up */
@@ -948,9 +978,10 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
  * deleteOneObject: delete a single object for performDeletion.
  *
  * depRel is the already-open pg_depend relation.
+ * flags is or-masked OAT_DROP_FLAGS_* to be informed to extensions
  */
 static void
-deleteOneObject(const ObjectAddress *object, Relation depRel)
+deleteOneObject(const ObjectAddress *object, Relation depRel, int32 flags)
 {
 	ScanKeyData key[3];
 	int			nkeys;
@@ -958,6 +989,13 @@ deleteOneObject(const ObjectAddress *object, Relation depRel)
 	HeapTuple	tup;
 
 	/*
+	 * DROP hook for the objects being removed.
+	 */
+	InvokeObjectAccessHookArg(OAT_DROP, object->classId,
+							  object->objectId, object->objectSubId,
+							  Int32GetDatum(flags));
+
+	/*
 	 * First remove any pg_depend records that link from this object to
 	 * others.	(Any records linking to this object should be gone already.)
 	 *
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 9408f25..8f245c1 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -1443,9 +1443,9 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 	 * The new relation is local to our transaction and we know nothing
 	 * depends on it, so DROP_RESTRICT should be OK.
 	 */
-	performDeletion(&object, DROP_RESTRICT);
+	performInternalDeletion(&object, DROP_RESTRICT);
 
-	/* performDeletion does CommandCounterIncrement at end */
+	/* performInternalDeletion does CommandCounterIncrement at end */
 
 	/*
 	 * Now we must remove any relation mapping entries that we set up for the
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 42a8b31..ca12369 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -777,6 +777,9 @@ dropdb(const char *dbname, bool missing_ok)
 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
 					   dbname);
 
+	/* DROP hook for the database being removed */
+	InvokeObjectAccessHook(OAT_DROP, DatabaseRelationId, db_id, 0);
+
 	/*
 	 * Disallow dropping a DB that is marked istemplate.  This is just to
 	 * prevent people from accidentally dropping template0 or template1; they
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index cc210f0..ca7d8e6 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7581,7 +7581,7 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
 		obj.classId = ConstraintRelationId;
 		obj.objectId = lfirst_oid(oid_item);
 		obj.objectSubId = 0;
-		performDeletion(&obj, DROP_RESTRICT);
+		performInternalDeletion(&obj, DROP_RESTRICT);
 	}
 
 	foreach(oid_item, tab->changedIndexOids)
@@ -7589,7 +7589,7 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
 		obj.classId = RelationRelationId;
 		obj.objectId = lfirst_oid(oid_item);
 		obj.objectSubId = 0;
-		performDeletion(&obj, DROP_RESTRICT);
+		performInternalDeletion(&obj, DROP_RESTRICT);
 	}
 
 	/*
@@ -9738,7 +9738,7 @@ PreCommit_on_commit_actions(void)
 					object.classId = RelationRelationId;
 					object.objectId = oc->relid;
 					object.objectSubId = 0;
-					performDeletion(&object, DROP_CASCADE);
+					performInternalDeletion(&object, DROP_CASCADE);
 
 					/*
 					 * Note that table deletion will call
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index ff58490..bf9f362 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -434,6 +434,9 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 		aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
 					   tablespacename);
 
+	/* DROP hook for the tablespace being removed */
+	InvokeObjectAccessHook(OAT_DROP, TableSpaceRelationId, tablespaceoid, 0);
+
 	/*
 	 * Remove the pg_tablespace tuple (this will roll back if we fail below)
 	 */
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 9a88c90..99bf67c 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -947,6 +947,10 @@ DropRole(DropRoleStmt *stmt)
 							role),
 					 errdetail_internal("%s", detail),
 					 errdetail_log("%s", detail_log)));
+		/*
+		 * DROP hook for the role being removed
+		 */
+		InvokeObjectAccessHook(OAT_DROP, AuthIdRelationId, roleid, 0);
 
 		/*
 		 * Remove the role from the pg_authid table
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index e84e21c..e13d857 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2044,7 +2044,7 @@ do_autovacuum(void)
 					object.classId = RelationRelationId;
 					object.objectId = relid;
 					object.objectSubId = 0;
-					performDeletion(&object, DROP_CASCADE);
+					performInternalDeletion(&object, DROP_CASCADE);
 				}
 				else
 				{
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index 087341e..5c44803 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -155,6 +155,9 @@ typedef enum ObjectClass
 extern void performDeletion(const ObjectAddress *object,
 				DropBehavior behavior);
 
+extern void performInternalDeletion(const ObjectAddress *object,
+				DropBehavior behavior);
+
 extern void performMultipleDeletions(const ObjectAddresses *objects,
 						 DropBehavior behavior);
 
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index 5c7a40a..dfbff44 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -19,13 +19,24 @@
  * Typically, this is done after inserting the primary catalog records and
  * associated dependencies.
  *
+ * OAT_DROP should be invoked just before deletion of objects. It takes an
+ * argument to inform extensions contexts of objects being removed.
+ * Also see the comment of OAT_DROP_FLAGS_*.
+ *
  * Other types may be added in the future.
  */
 typedef enum ObjectAccessType
 {
 	OAT_POST_CREATE,
+	OAT_DROP,
 } ObjectAccessType;
 
+#define OAT_DROP_FLAGS_INTERNAL		0x01	/* this object shall be removed
+											 * because of internal clean-up,
+											 * not user's activities. */
+#define OAT_DROP_FLAGS_CASCADED		0x02	/* this object shall be removed
+											 * because of DROP_CASCADE */
+
 /*
  * Hook, and a macro to invoke it.
  */
@@ -33,14 +44,22 @@ typedef enum ObjectAccessType
 typedef void (*object_access_hook_type) (ObjectAccessType access,
 													 Oid classId,
 													 Oid objectId,
-													 int subId);
+													 int subId,
+													 Datum arg);
 
 extern PGDLLIMPORT object_access_hook_type object_access_hook;
 
 #define InvokeObjectAccessHook(access,classId,objectId,subId)			\
 	do {																\
 		if (object_access_hook)											\
-			(*object_access_hook)((access),(classId),(objectId),(subId)); \
+			(*object_access_hook)((access),(classId),(objectId),(subId),0); \
 	} while(0)
 
+#define InvokeObjectAccessHookArg(access,classId,objectId,subId,arg)	\
+	do {																\
+		if (object_access_hook)											\
+			(*object_access_hook)((access),(classId),					\
+								  (objectId),(subId),(arg));			\
+	} while(0);
+
 #endif   /* OBJECTACCESS_H */