From d85584c15f4c77f392223bf4e8d06bc25afb87fa Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Tue, 17 Apr 2012 19:05:50 +0200 Subject: [PATCH] SE-PostgreSQL was merged into mainstream as contrib/sepgsql extension --- .gitignore | 4 - dead.package | 1 + sepostgresql-9.0-fullset.patch | 19467 ----------------------------- sepostgresql-fedora-prefix.patch | 105 - sepostgresql.8 | 137 - sepostgresql.init | 205 - sepostgresql.logrotate | 11 - sepostgresql.spec | 482 - sources | 1 - 9 files changed, 1 insertion(+), 20412 deletions(-) delete mode 100644 .gitignore create mode 100644 dead.package delete mode 100644 sepostgresql-9.0-fullset.patch delete mode 100644 sepostgresql-fedora-prefix.patch delete mode 100644 sepostgresql.8 delete mode 100644 sepostgresql.init delete mode 100644 sepostgresql.logrotate delete mode 100644 sepostgresql.spec delete mode 100644 sources diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 81ff717..0000000 --- a/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -postgresql-9.0beta1.tar.gz -/postgresql-9.0.0.tar.gz -/postgresql-9.0.1.tar.gz -/postgresql-9.0.3.tar.gz diff --git a/dead.package b/dead.package new file mode 100644 index 0000000..e1c0fac --- /dev/null +++ b/dead.package @@ -0,0 +1 @@ +SE-PostgreSQL was merged into mainstream as contrib/sepgsql extension diff --git a/sepostgresql-9.0-fullset.patch b/sepostgresql-9.0-fullset.patch deleted file mode 100644 index e4b3c26..0000000 --- a/sepostgresql-9.0-fullset.patch +++ /dev/null @@ -1,19467 +0,0 @@ - configure | 198 ++++++ - configure.in | 13 + - contrib/adminpack/adminpack.c | 28 +- - src/Makefile.global.in | 1 + - src/backend/Makefile | 7 +- - src/backend/access/common/heaptuple.c | 14 + - src/backend/access/common/tupdesc.c | 20 +- - src/backend/access/gin/ginutil.c | 2 +- - src/backend/access/heap/heapam.c | 35 + - src/backend/access/heap/tuptoaster.c | 6 + - src/backend/access/transam/twophase.c | 2 +- - src/backend/access/transam/xact.c | 19 + - src/backend/access/transam/xlog.c | 2 +- - src/backend/bootstrap/bootparse.y | 7 +- - src/backend/bootstrap/bootstrap.c | 14 + - src/backend/catalog/Makefile | 4 +- - src/backend/catalog/aclchk.c | 20 + - src/backend/catalog/catalog.c | 6 + - src/backend/catalog/genbki.pl | 3 +- - src/backend/catalog/heap.c | 120 +++- - src/backend/catalog/index.c | 28 +- - src/backend/catalog/namespace.c | 26 +- - src/backend/catalog/pg_aggregate.c | 9 +- - src/backend/catalog/pg_conversion.c | 4 +- - src/backend/catalog/pg_largeobject.c | 65 ++- - src/backend/catalog/pg_namespace.c | 4 +- - src/backend/catalog/pg_operator.c | 21 + - src/backend/catalog/pg_proc.c | 8 +- - src/backend/catalog/pg_seclabel.c | 646 +++++++++++++++++++ - src/backend/catalog/pg_type.c | 17 +- - src/backend/catalog/toasting.c | 12 +- - src/backend/commands/aggregatecmds.c | 4 + - src/backend/commands/alter.c | 61 ++ - src/backend/commands/cluster.c | 23 +- - src/backend/commands/comment.c | 60 ++ - src/backend/commands/conversioncmds.c | 16 +- - src/backend/commands/copy.c | 265 +++++++-- - src/backend/commands/dbcommands.c | 87 +++ - src/backend/commands/explain.c | 2 +- - src/backend/commands/foreigncmds.c | 39 ++ - src/backend/commands/functioncmds.c | 82 +++- - src/backend/commands/indexcmds.c | 18 +- - src/backend/commands/lockcmds.c | 4 + - src/backend/commands/opclasscmds.c | 48 ++- - src/backend/commands/operatorcmds.c | 6 + - src/backend/commands/prepare.c | 2 +- - src/backend/commands/proclang.c | 10 +- - src/backend/commands/schemacmds.c | 57 ++- - src/backend/commands/sequence.c | 16 + - src/backend/commands/tablecmds.c | 509 +++++++++++++++- - src/backend/commands/tablespace.c | 64 ++ - src/backend/commands/trigger.c | 11 + - src/backend/commands/tsearchcmds.c | 64 ++- - src/backend/commands/typecmds.c | 159 +++++- - src/backend/commands/user.c | 20 + - src/backend/commands/vacuum.c | 3 + - src/backend/commands/view.c | 4 + - src/backend/executor/execJunk.c | 5 +- - src/backend/executor/execMain.c | 63 ++- - src/backend/executor/execQual.c | 11 +- - src/backend/executor/execScan.c | 23 +- - src/backend/executor/execTuples.c | 17 +- - src/backend/executor/execUtils.c | 6 +- - src/backend/executor/functions.c | 6 +- - src/backend/executor/nodeAgg.c | 5 +- - src/backend/executor/nodeFunctionscan.c | 2 +- - src/backend/executor/nodeMergejoin.c | 4 + - src/backend/executor/nodeModifyTable.c | 76 +++- - src/backend/executor/nodeSubplan.c | 4 +- - src/backend/executor/nodeWindowAgg.c | 7 + - src/backend/executor/spi.c | 13 +- - src/backend/libpq/be-fsstubs.c | 40 +- - src/backend/nodes/copyfuncs.c | 19 + - src/backend/nodes/equalfuncs.c | 17 + - src/backend/nodes/outfuncs.c | 1 + - src/backend/nodes/readfuncs.c | 1 + - src/backend/optimizer/plan/planner.c | 11 + - src/backend/optimizer/util/clauses.c | 8 +- - src/backend/parser/analyze.c | 4 +- - src/backend/parser/gram.y | 120 ++++- - src/backend/parser/parse_relation.c | 12 +- - src/backend/parser/parse_target.c | 75 ++- - src/backend/parser/parse_utilcmd.c | 10 +- - src/backend/postmaster/postmaster.c | 45 ++- - src/backend/rewrite/rewriteDefine.c | 4 + - src/backend/rewrite/rewriteRemove.c | 4 + - src/backend/sepgsql/Makefile | 21 + - src/backend/sepgsql/attribute.c | 260 ++++++++ - src/backend/sepgsql/avc.c | 503 +++++++++++++++ - src/backend/sepgsql/blob.c | 245 ++++++++ - src/backend/sepgsql/conversion.c | 147 +++++ - src/backend/sepgsql/database.c | 201 ++++++ - src/backend/sepgsql/fdw.c | 296 +++++++++ - src/backend/sepgsql/file.c | 287 +++++++++ - src/backend/sepgsql/label.c | 588 ++++++++++++++++++ - src/backend/sepgsql/misc.c | 147 +++++ - src/backend/sepgsql/operator.c | 454 ++++++++++++++ - src/backend/sepgsql/proc.c | 366 +++++++++++ - src/backend/sepgsql/relation.c | 819 +++++++++++++++++++++++++ - src/backend/sepgsql/role.c | 142 +++++ - src/backend/sepgsql/rowlv.c | 346 +++++++++++ - src/backend/sepgsql/schema.c | 173 ++++++ - src/backend/sepgsql/selinux.c | 690 +++++++++++++++++++++ - src/backend/sepgsql/tablespace.c | 157 +++++ - src/backend/sepgsql/tsearch.c | 524 ++++++++++++++++ - src/backend/sepgsql/type.c | 314 ++++++++++ - src/backend/storage/large_object/inv_api.c | 4 +- - src/backend/tcop/fastpath.c | 5 + - src/backend/tcop/pquery.c | 2 +- - src/backend/tcop/utility.c | 49 ++ - src/backend/tsearch/wparser.c | 4 +- - src/backend/utils/adt/acl.c | 2 +- - src/backend/utils/adt/datetime.c | 4 +- - src/backend/utils/adt/dbsize.c | 6 + - src/backend/utils/adt/genfile.c | 9 +- - src/backend/utils/adt/lockfuncs.c | 2 +- - src/backend/utils/adt/misc.c | 2 +- - src/backend/utils/adt/pgstatfuncs.c | 2 +- - src/backend/utils/adt/ri_triggers.c | 24 + - src/backend/utils/adt/tid.c | 5 + - src/backend/utils/adt/trigfuncs.c | 4 + - src/backend/utils/adt/tsvector_op.c | 2 +- - src/backend/utils/cache/plancache.c | 8 +- - src/backend/utils/cache/relcache.c | 38 +- - src/backend/utils/cache/syscache.c | 24 + - src/backend/utils/fmgr/fmgr.c | 32 +- - src/backend/utils/fmgr/funcapi.c | 4 +- - src/backend/utils/init/postinit.c | 7 + - src/backend/utils/misc/guc.c | 74 ++- - src/backend/utils/misc/postgresql.conf.sample | 2 + - src/backend/utils/mmgr/portalmem.c | 2 +- - src/bin/initdb/initdb.c | 13 + - src/bin/pg_dump/pg_backup.h | 3 +- - src/bin/pg_dump/pg_backup_archiver.c | 81 +++- - src/bin/pg_dump/pg_backup_archiver.h | 9 +- - src/bin/pg_dump/pg_dump.c | 400 ++++++++++-- - src/bin/pg_dump/pg_dump.h | 7 + - src/bin/pg_dump/pg_dumpall.c | 60 ++- - src/bin/pg_dump/pg_restore.c | 6 + - src/include/access/htup.h | 35 +- - src/include/access/sysattr.h | 3 +- - src/include/access/tupdesc.h | 5 +- - src/include/bootstrap/bootstrap.h | 1 + - src/include/catalog/heap.h | 16 +- - src/include/catalog/indexing.h | 5 + - src/include/catalog/pg_class.h | 28 +- - src/include/catalog/pg_conversion_fn.h | 2 +- - src/include/catalog/pg_largeobject.h | 3 +- - src/include/catalog/pg_namespace.h | 2 +- - src/include/catalog/pg_proc.h | 4 + - src/include/catalog/pg_proc_fn.h | 3 +- - src/include/catalog/pg_seclabel.h | 79 +++ - src/include/catalog/pg_type_fn.h | 3 +- - src/include/catalog/toasting.h | 3 + - src/include/commands/alter.h | 1 + - src/include/commands/dbcommands.h | 1 + - src/include/commands/defrem.h | 2 + - src/include/commands/schemacmds.h | 1 + - src/include/commands/tablecmds.h | 7 + - src/include/commands/tablespace.h | 1 + - src/include/commands/typecmds.h | 2 + - src/include/executor/executor.h | 9 +- - src/include/fmgr.h | 1 + - src/include/nodes/nodes.h | 1 + - src/include/nodes/parsenodes.h | 17 + - src/include/parser/kwlist.h | 1 + - src/include/pg_config.h.in | 3 + - src/include/sepgsql/hooks.h | 293 +++++++++ - src/include/sepgsql/sepgsql.h | 318 ++++++++++ - src/include/storage/large_object.h | 2 +- - src/include/storage/lwlock.h | 1 + - src/include/utils/guc.h | 1 + - src/include/utils/syscache.h | 11 + - src/pl/plpgsql/src/pl_comp.c | 2 +- - src/test/regress/expected/sanity_check.out | 3 +- - 175 files changed, 11679 insertions(+), 375 deletions(-) - -diff --git a/configure b/configure -index a4f4c9e..e8e71c1 100755 ---- a/configure -+++ b/configure -@@ -708,6 +708,7 @@ LDFLAGS_EX - ELF_SYS - EGREP - GREP -+enable_selinux - with_zlib - with_system_tzdata - with_libxslt -@@ -843,6 +844,7 @@ with_libxml - with_libxslt - with_system_tzdata - with_zlib -+enable_selinux - with_gnu_ld - enable_largefile - enable_float4_byval -@@ -1500,6 +1502,7 @@ Optional Features: - --enable-depend turn on automatic dependency tracking - --enable-cassert enable assertion checks (for debugging) - --disable-thread-safety disable thread-safety in client libraries -+ --enable-selinux build with SELinux support - --disable-largefile omit support for large files - --disable-float4-byval disable float4 passed by value - --disable-float8-byval disable float8 passed by value -@@ -5611,6 +5614,201 @@ fi - - - # -+# SELinux support -+# -+ -+ -+# Check whether --enable-selinux was given. -+if test "${enable_selinux+set}" = set; then -+ enableval=$enable_selinux; -+ case $enableval in -+ yes) -+ : -+ ;; -+ no) -+ : -+ ;; -+ *) -+ { { $as_echo "$as_me:$LINENO: error: no argument expected for --enable-selinux option" >&5 -+$as_echo "$as_me: error: no argument expected for --enable-selinux option" >&2;} -+ { (exit 1); exit 1; }; } -+ ;; -+ esac -+ -+else -+ enable_selinux=no -+ -+fi -+ -+ -+if test "$enable_selinux" = yes; then -+ -+{ $as_echo "$as_me:$LINENO: checking for avc_open in -lselinux" >&5 -+$as_echo_n "checking for avc_open in -lselinux... " >&6; } -+if test "${ac_cv_lib_selinux_avc_open+set}" = set; then -+ $as_echo_n "(cached) " >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-lselinux $LIBS" -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char avc_open (); -+int -+main () -+{ -+return avc_open (); -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext conftest$ac_exeext -+if { (ac_try="$ac_link" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -+$as_echo "$ac_try_echo") >&5 -+ (eval "$ac_link") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest$ac_exeext && { -+ test "$cross_compiling" = yes || -+ $as_test_x conftest$ac_exeext -+ }; then -+ ac_cv_lib_selinux_avc_open=yes -+else -+ $as_echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_cv_lib_selinux_avc_open=no -+fi -+ -+rm -rf conftest.dSYM -+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_avc_open" >&5 -+$as_echo "$ac_cv_lib_selinux_avc_open" >&6; } -+if test "x$ac_cv_lib_selinux_avc_open" = x""yes; then -+ cat >>confdefs.h <<_ACEOF -+#define HAVE_LIBSELINUX 1 -+_ACEOF -+ -+ LIBS="-lselinux $LIBS" -+ -+else -+ { { $as_echo "$as_me:$LINENO: error: \"SELinux support requires libselinux.\"" >&5 -+$as_echo "$as_me: error: \"SELinux support requires libselinux.\"" >&2;} -+ { (exit 1); exit 1; }; } -+fi -+ -+ -+{ $as_echo "$as_me:$LINENO: checking for audit_open in -laudit" >&5 -+$as_echo_n "checking for audit_open in -laudit... " >&6; } -+if test "${ac_cv_lib_audit_audit_open+set}" = set; then -+ $as_echo_n "(cached) " >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-laudit $LIBS" -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char audit_open (); -+int -+main () -+{ -+return audit_open (); -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext conftest$ac_exeext -+if { (ac_try="$ac_link" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -+$as_echo "$ac_try_echo") >&5 -+ (eval "$ac_link") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest$ac_exeext && { -+ test "$cross_compiling" = yes || -+ $as_test_x conftest$ac_exeext -+ }; then -+ ac_cv_lib_audit_audit_open=yes -+else -+ $as_echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_cv_lib_audit_audit_open=no -+fi -+ -+rm -rf conftest.dSYM -+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_audit_audit_open" >&5 -+$as_echo "$ac_cv_lib_audit_audit_open" >&6; } -+if test "x$ac_cv_lib_audit_audit_open" = x""yes; then -+ cat >>confdefs.h <<_ACEOF -+#define HAVE_LIBAUDIT 1 -+_ACEOF -+ -+ LIBS="-laudit $LIBS" -+ -+else -+ { { $as_echo "$as_me:$LINENO: error: \"SELinux support requires libaudit.\"" >&5 -+$as_echo "$as_me: error: \"SELinux support requires libaudit.\"" >&2;} -+ { (exit 1); exit 1; }; } -+fi -+ -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_SELINUX 1 -+_ACEOF -+ -+ -+fi -+ -+# - # Elf - # - -diff --git a/configure.in b/configure.in -index 26166d0..0a58c40 100644 ---- a/configure.in -+++ b/configure.in -@@ -755,6 +755,19 @@ PGAC_ARG_BOOL(with, zlib, yes, - AC_SUBST(with_zlib) - - # -+# SELinux support -+# -+PGAC_ARG_BOOL(enable, selinux, no, [build with SELinux support]) -+if test "$enable_selinux" = yes; then -+ AC_CHECK_LIB(selinux, avc_open,, -+ AC_MSG_ERROR("SELinux support requires libselinux.")) -+ AC_CHECK_LIB(audit, audit_open,, -+ AC_MSG_ERROR("SELinux support requires libaudit.")) -+ AC_DEFINE_UNQUOTED(HAVE_SELINUX, 1, [SE-PostgreSQL feature is enabled]) -+ AC_SUBST(enable_selinux) -+fi -+ -+# - # Elf - # - -diff --git a/contrib/adminpack/adminpack.c b/contrib/adminpack/adminpack.c -index 5271ef6..397786d 100644 ---- a/contrib/adminpack/adminpack.c -+++ b/contrib/adminpack/adminpack.c -@@ -22,6 +22,7 @@ - #include "funcapi.h" - #include "miscadmin.h" - #include "postmaster/syslogger.h" -+#include "sepgsql/hooks.h" - #include "storage/fd.h" - #include "utils/builtins.h" - #include "utils/datetime.h" -@@ -142,10 +143,16 @@ pg_file_write(PG_FUNCTION_ARGS) - (ERRCODE_DUPLICATE_FILE, - errmsg("file \"%s\" exists", filename))); - -+ sepgsql_file_write(filename, true); -+ - f = fopen(filename, "wb"); - } - else -+ { -+ sepgsql_file_append(filename); -+ - f = fopen(filename, "ab"); -+ } - - if (!f) - ereport(ERROR, -@@ -217,6 +224,7 @@ pg_file_rename(PG_FUNCTION_ARGS) - - if (fn3) - { -+ sepgsql_file_rename(fn2, fn3); - if (rename(fn2, fn3) != 0) - { - ereport(ERROR, -@@ -224,6 +232,7 @@ pg_file_rename(PG_FUNCTION_ARGS) - errmsg("could not rename \"%s\" to \"%s\": %m", - fn2, fn3))); - } -+ sepgsql_file_rename(fn1, fn2); - if (rename(fn1, fn2) != 0) - { - ereport(WARNING, -@@ -247,11 +256,15 @@ pg_file_rename(PG_FUNCTION_ARGS) - } - } - } -- else if (rename(fn1, fn2) != 0) -+ else - { -- ereport(ERROR, -- (errcode_for_file_access(), -- errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2))); -+ sepgsql_file_rename(fn1, fn2); -+ if (rename(fn1, fn2) != 0) -+ { -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2))); -+ } - } - - PG_RETURN_BOOL(true); -@@ -277,6 +290,8 @@ pg_file_unlink(PG_FUNCTION_ARGS) - errmsg("file \"%s\" is not accessible: %m", filename))); - } - -+ sepgsql_file_unlink(filename); -+ - if (unlink(filename) < 0) - { - ereport(WARNING, -@@ -312,11 +327,14 @@ pg_logdir_ls(PG_FUNCTION_ARGS) - TupleDesc tupdesc; - - funcctx = SRF_FIRSTCALL_INIT(); -+ -+ sepgsql_dir_list(Log_directory); -+ - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - - fctx = palloc(sizeof(directory_fctx)); - -- tupdesc = CreateTemplateTupleDesc(2, false); -+ tupdesc = CreateTemplateTupleDesc(2, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime", - TIMESTAMPOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename", -diff --git a/src/Makefile.global.in b/src/Makefile.global.in -index 280578a..6495097 100644 ---- a/src/Makefile.global.in -+++ b/src/Makefile.global.in -@@ -166,6 +166,7 @@ enable_nls = @enable_nls@ - enable_debug = @enable_debug@ - enable_dtrace = @enable_dtrace@ - enable_coverage = @enable_coverage@ -+enable_selinux = @enable_selinux@ - enable_thread_safety = @enable_thread_safety@ - - python_includespec = @python_includespec@ -diff --git a/src/backend/Makefile b/src/backend/Makefile -index a11b2b5..25198fd 100644 ---- a/src/backend/Makefile -+++ b/src/backend/Makefile -@@ -19,7 +19,7 @@ include $(top_builddir)/src/Makefile.global - - SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \ - main nodes optimizer port postmaster regex replication rewrite \ -- storage tcop tsearch utils $(top_builddir)/src/timezone -+ sepgsql storage tcop tsearch utils $(top_builddir)/src/timezone - - include $(srcdir)/common.mk - -@@ -43,6 +43,11 @@ LIBS := $(filter-out -lpgport, $(LIBS)) $(LDAP_LIBS_BE) - # The backend doesn't need everything that's in LIBS, however - LIBS := $(filter-out -lz -lreadline -ledit -ltermcap -lncurses -lcurses, $(LIBS)) - -+# SELinux needs libselinux and libaudit -+ifeq ($(enable_selinux), yes) -+LIBS := $(filter-out -lselinux -laudit, $(LIBS)) -lselinux -laudit -+endif -+ - ########################################################################## - - all: submake-libpgport submake-schemapg postgres $(POSTGRES_IMP) -diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c -index 8d770a3..a3b1474 100644 ---- a/src/backend/access/common/heaptuple.c -+++ b/src/backend/access/common/heaptuple.c -@@ -60,6 +60,7 @@ - #include "access/heapam.h" - #include "access/sysattr.h" - #include "access/tuptoaster.h" -+#include "catalog/pg_seclabel.h" - #include "executor/tuptable.h" - - -@@ -559,6 +560,9 @@ heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull) - case TableOidAttributeNumber: - result = ObjectIdGetDatum(tup->t_tableOid); - break; -+ case SecurityLabelAttributeNumber: -+ result = seclabelSysattOutput(tup->t_tableOid, tup); -+ break; - default: - elog(ERROR, "invalid attnum: %d", attnum); - result = 0; /* keep compiler quiet */ -@@ -682,6 +686,8 @@ heap_form_tuple(TupleDesc tupleDescriptor, - - if (tupleDescriptor->tdhasoid) - len += sizeof(Oid); -+ if (tupleDescriptor->tdhassecid) -+ len += sizeof(Oid)+1; - - hoff = len = MAXALIGN(len); /* align user data safely */ - -@@ -713,6 +719,8 @@ heap_form_tuple(TupleDesc tupleDescriptor, - - if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ - td->t_infomask = HEAP_HASOID; -+ if (tupleDescriptor->tdhassecid) -+ td->t_infomask |= HEAP_HASSECID; - - heap_fill_tuple(tupleDescriptor, - values, -@@ -824,6 +832,8 @@ heap_modify_tuple(HeapTuple tuple, - newTuple->t_tableOid = tuple->t_tableOid; - if (tupleDesc->tdhasoid) - HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple)); -+ if (tupleDesc->tdhassecid) -+ HeapTupleSetSecid(newTuple, HeapTupleGetSecid(tuple)); - - return newTuple; - } -@@ -1434,6 +1444,8 @@ heap_form_minimal_tuple(TupleDesc tupleDescriptor, - - if (tupleDescriptor->tdhasoid) - len += sizeof(Oid); -+ if (tupleDescriptor->tdhassecid) -+ len += sizeof(Oid)+1; - - hoff = len = MAXALIGN(len); /* align user data safely */ - -@@ -1455,6 +1467,8 @@ heap_form_minimal_tuple(TupleDesc tupleDescriptor, - - if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ - tuple->t_infomask = HEAP_HASOID; -+ if (tupleDescriptor->tdhassecid) -+ tuple->t_infomask |= HEAP_HASSECID; - - heap_fill_tuple(tupleDescriptor, - values, -diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c -index 2125fdf..5880ec7 100644 ---- a/src/backend/access/common/tupdesc.c -+++ b/src/backend/access/common/tupdesc.c -@@ -34,7 +34,7 @@ - * caller can overwrite this if needed. - */ - TupleDesc --CreateTemplateTupleDesc(int natts, bool hasoid) -+CreateTemplateTupleDesc(int natts, bool hasoid, bool hassecid) - { - TupleDesc desc; - char *stg; -@@ -88,6 +88,7 @@ CreateTemplateTupleDesc(int natts, bool hasoid) - desc->tdtypeid = RECORDOID; - desc->tdtypmod = -1; - desc->tdhasoid = hasoid; -+ desc->tdhassecid = hassecid; - desc->tdrefcount = -1; /* assume not reference-counted */ - - return desc; -@@ -105,7 +106,8 @@ CreateTemplateTupleDesc(int natts, bool hasoid) - * caller can overwrite this if needed. - */ - TupleDesc --CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs) -+CreateTupleDesc(int natts, bool hasoid, bool hassecid, -+ Form_pg_attribute *attrs) - { - TupleDesc desc; - -@@ -121,6 +123,7 @@ CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs) - desc->tdtypeid = RECORDOID; - desc->tdtypmod = -1; - desc->tdhasoid = hasoid; -+ desc->tdhassecid = hassecid; - desc->tdrefcount = -1; /* assume not reference-counted */ - - return desc; -@@ -139,7 +142,8 @@ CreateTupleDescCopy(TupleDesc tupdesc) - TupleDesc desc; - int i; - -- desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid); -+ desc = CreateTemplateTupleDesc(tupdesc->natts, -+ tupdesc->tdhasoid, tupdesc->tdhassecid); - - for (i = 0; i < desc->natts; i++) - { -@@ -150,6 +154,7 @@ CreateTupleDescCopy(TupleDesc tupdesc) - - desc->tdtypeid = tupdesc->tdtypeid; - desc->tdtypmod = tupdesc->tdtypmod; -+ desc->tdhassecid = tupdesc->tdhassecid; - - return desc; - } -@@ -166,7 +171,8 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) - TupleConstr *constr = tupdesc->constr; - int i; - -- desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid); -+ desc = CreateTemplateTupleDesc(tupdesc->natts, -+ tupdesc->tdhasoid, tupdesc->tdhassecid); - - for (i = 0; i < desc->natts; i++) - { -@@ -314,6 +320,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) - return false; - if (tupdesc1->tdhasoid != tupdesc2->tdhasoid) - return false; -+ if (tupdesc1->tdhassecid != tupdesc2->tdhassecid) -+ return false; - - for (i = 0; i < tupdesc1->natts; i++) - { -@@ -519,7 +527,7 @@ BuildDescForRelation(List *schema) - * allocate a new tuple descriptor - */ - natts = list_length(schema); -- desc = CreateTemplateTupleDesc(natts, false); -+ desc = CreateTemplateTupleDesc(natts, false, false); - has_not_null = false; - - attnum = 0; -@@ -604,7 +612,7 @@ BuildDescFromLists(List *names, List *types, List *typmods) - /* - * allocate a new tuple descriptor - */ -- desc = CreateTemplateTupleDesc(natts, false); -+ desc = CreateTemplateTupleDesc(natts, false, false); - - attnum = 0; - -diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c -index 2a75820..065ba1a 100644 ---- a/src/backend/access/gin/ginutil.c -+++ b/src/backend/access/gin/ginutil.c -@@ -33,7 +33,7 @@ initGinState(GinState *state, Relation index) - - for (i = 0; i < index->rd_att->natts; i++) - { -- state->tupdesc[i] = CreateTemplateTupleDesc(2, false); -+ state->tupdesc[i] = CreateTemplateTupleDesc(2, false, false); - - TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 1, NULL, - INT2OID, -1, 0); -diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c -index 1c93400..1236873 100644 ---- a/src/backend/access/heap/heapam.c -+++ b/src/backend/access/heap/heapam.c -@@ -52,6 +52,7 @@ - #include "access/xlogutils.h" - #include "catalog/catalog.h" - #include "catalog/namespace.h" -+#include "catalog/pg_seclabel.h" - #include "miscadmin.h" - #include "pgstat.h" - #include "storage/bufmgr.h" -@@ -1862,6 +1863,22 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, - Assert(!(tup->t_data->t_infomask & HEAP_HASOID)); - } - -+ /* -+ * If this tuple has a capability to store its security id, but it has -+ * not been assigned yet, the default security id should be assigned. -+ * Note that this step does not apply any permission checks. All the -+ * caller of heap_insert() is trusted. -+ */ -+ if (relation->rd_rel->relhassecids) -+ { -+ if (!OidIsValid(HeapTupleGetSecid(tup))) -+ HeapTupleSetSecid(tup, seclabelGetNewSecid(relation, tup)); -+ } -+ else -+ { -+ Assert(!HeapTupleHasSecid(tup)); -+ } -+ - tup->t_data->t_infomask &= ~(HEAP_XACT_MASK); - tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK); - tup->t_data->t_infomask |= HEAP_XMAX_INVALID; -@@ -2560,6 +2577,20 @@ l2: - Assert(!(newtup->t_data->t_infomask & HEAP_HASOID)); - } - -+ /* -+ * Preserve security-id, if not changed -+ */ -+ if (relation->rd_rel->relhassecids) -+ { -+ if (!OidIsValid(HeapTupleGetSecid(newtup))) -+ HeapTupleSetSecid(newtup, HeapTupleGetSecid(&oldtup)); -+ } -+ else -+ { -+ /* check there is not space for a security-id */ -+ Assert(!HeapTupleHasSecid(newtup)); -+ } -+ - newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK); - newtup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK); - newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED); -@@ -3501,6 +3532,10 @@ heap_inplace_update(Relation relation, HeapTuple tuple) - memcpy((char *) htup + htup->t_hoff, - (char *) tuple->t_data + tuple->t_data->t_hoff, - newlen); -+ if (HeapTupleHeaderHasOid(htup)) -+ HeapTupleHeaderSetOid(htup, HeapTupleGetOid(tuple)); -+ if (HeapTupleHeaderHasSecid(htup)) -+ HeapTupleHeaderSetSecid(htup, HeapTupleGetSecid(tuple)); - - MarkBufferDirty(buffer); - -diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c -index 7518db1..fb78993 100644 ---- a/src/backend/access/heap/tuptoaster.c -+++ b/src/backend/access/heap/tuptoaster.c -@@ -591,6 +591,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, - hoff += BITMAPLEN(numAttrs); - if (newtup->t_data->t_infomask & HEAP_HASOID) - hoff += sizeof(Oid); -+ if (HeapTupleHasSecid(newtup)) -+ hoff += sizeof(Oid); - hoff = MAXALIGN(hoff); - Assert(hoff == newtup->t_data->t_hoff); - /* now convert to a limit on the tuple data size */ -@@ -868,6 +870,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, - new_len += BITMAPLEN(numAttrs); - if (olddata->t_infomask & HEAP_HASOID) - new_len += sizeof(Oid); -+ if (HeapTupleHeaderHasSecid(olddata)) -+ new_len += sizeof(Oid); - new_len = MAXALIGN(new_len); - Assert(new_len == olddata->t_hoff); - new_data_len = heap_compute_data_size(tupleDesc, -@@ -1019,6 +1023,8 @@ toast_flatten_tuple_attribute(Datum value, - new_len += BITMAPLEN(numAttrs); - if (olddata->t_infomask & HEAP_HASOID) - new_len += sizeof(Oid); -+ if (HeapTupleHeaderHasSecid(olddata)) -+ new_len += sizeof(Oid)+1; - new_len = MAXALIGN(new_len); - Assert(new_len == olddata->t_hoff); - new_data_len = heap_compute_data_size(tupleDesc, -diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c -index d6dca97..710b891 100644 ---- a/src/backend/access/transam/twophase.c -+++ b/src/backend/access/transam/twophase.c -@@ -605,7 +605,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS) - - /* build tupdesc for result tuples */ - /* this had better match pg_prepared_xacts view in system_views.sql */ -- tupdesc = CreateTemplateTupleDesc(5, false); -+ tupdesc = CreateTemplateTupleDesc(5, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "transaction", - XIDOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "gid", -diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c -index 8436dea..d9de0e4 100644 ---- a/src/backend/access/transam/xact.c -+++ b/src/backend/access/transam/xact.c -@@ -36,6 +36,7 @@ - #include "libpq/be-fsstubs.h" - #include "miscadmin.h" - #include "pgstat.h" -+#include "sepgsql/hooks.h" - #include "storage/bufmgr.h" - #include "storage/fd.h" - #include "storage/lmgr.h" -@@ -140,6 +141,8 @@ typedef struct TransactionStateData - int maxChildXids; /* allocated size of childXids[] */ - Oid prevUser; /* previous CurrentUserId setting */ - int prevSecContext; /* previous SecurityRestrictionContext */ -+ char *prevSecLabel; /* previous security label of client */ -+ int prevRowlvMode; /* previous row-level access control mode */ - bool prevXactReadOnly; /* entry-time xact r/o state */ - bool startedInRecovery; /* did we start in recovery? */ - struct TransactionStateData *parent; /* back link to parent */ -@@ -169,6 +172,8 @@ static TransactionStateData TopTransactionStateData = { - 0, /* allocated size of childXids[] */ - InvalidOid, /* previous CurrentUserId setting */ - 0, /* previous SecurityRestrictionContext */ -+ NULL, /* previous security label of the client */ -+ 0, /* previous row-level access control mode */ - false, /* entry-time xact r/o state */ - false, /* startedInRecovery */ - NULL /* link to parent state block */ -@@ -1698,6 +1703,10 @@ StartTransaction(void) - /* SecurityRestrictionContext should never be set outside a transaction */ - Assert(s->prevSecContext == 0); - -+ /* Save status of SELinux */ -+ s->prevSecLabel = sepgsql_get_client_label(); -+ s->prevRowlvMode = sepgsql_rowlv_get_mode(); -+ - /* - * initialize other subsystems for new transaction - */ -@@ -2202,6 +2211,10 @@ AbortTransaction(void) - */ - SetUserIdAndSecContext(s->prevUser, s->prevSecContext); - -+ /* Reset SELinux status */ -+ sepgsql_set_client_label(s->prevSecLabel); -+ sepgsql_rowlv_set_mode(s->prevRowlvMode); -+ - /* - * do abort processing - */ -@@ -4046,6 +4059,10 @@ AbortSubTransaction(void) - */ - SetUserIdAndSecContext(s->prevUser, s->prevSecContext); - -+ /* Reset SELinux status */ -+ sepgsql_set_client_label(s->prevSecLabel); -+ sepgsql_rowlv_set_mode(s->prevRowlvMode); -+ - /* - * We can skip all this stuff if the subxact failed before creating a - * ResourceOwner... -@@ -4185,6 +4202,8 @@ PushTransaction(void) - s->state = TRANS_DEFAULT; - s->blockState = TBLOCK_SUBBEGIN; - GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext); -+ s->prevSecLabel = sepgsql_get_client_label(); -+ s->prevRowlvMode = sepgsql_rowlv_get_mode(); - s->prevXactReadOnly = XactReadOnly; - - CurrentTransactionState = s; -diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c -index bb06a2e..77feebf 100644 ---- a/src/backend/access/transam/xlog.c -+++ b/src/backend/access/transam/xlog.c -@@ -8916,7 +8916,7 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS) - * Construct a tuple descriptor for the result row. This must match this - * function's pg_proc entry! - */ -- resultTupleDesc = CreateTemplateTupleDesc(2, false); -+ resultTupleDesc = CreateTemplateTupleDesc(2, false, false); - TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "file_name", - TEXTOID, -1, 0); - TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "file_offset", -diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y -index 9cc6850..7537984 100644 ---- a/src/backend/bootstrap/bootparse.y -+++ b/src/backend/bootstrap/bootparse.y -@@ -32,6 +32,7 @@ - #include "catalog/pg_authid.h" - #include "catalog/pg_class.h" - #include "catalog/pg_namespace.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/pg_tablespace.h" - #include "catalog/toasting.h" - #include "commands/defrem.h" -@@ -187,10 +188,11 @@ Boot_CreateStmt: - TupleDesc tupdesc; - bool shared_relation; - bool mapped_relation; -+ bool hassecid = seclabelCatalogHasSysAttr($3); - - do_start(); - -- tupdesc = CreateTupleDesc(numattr, !($6), attrtypes); -+ tupdesc = CreateTupleDesc(numattr, !($6), hassecid, attrtypes); - - shared_relation = $5; - -@@ -245,7 +247,8 @@ Boot_CreateStmt: - ONCOMMIT_NOOP, - (Datum) 0, - false, -- true); -+ true, -+ NULL); - elog(DEBUG4, "relation created with oid %u", id); - } - do_end(); -diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c -index 080d80e..a870b31 100644 ---- a/src/backend/bootstrap/bootstrap.c -+++ b/src/backend/bootstrap/bootstrap.c -@@ -33,6 +33,7 @@ - #include "postmaster/bgwriter.h" - #include "postmaster/walwriter.h" - #include "replication/walreceiver.h" -+#include "sepgsql/hooks.h" - #include "storage/bufmgr.h" - #include "storage/ipc.h" - #include "storage/proc.h" -@@ -319,6 +320,9 @@ AuxiliaryProcessMain(int argc, char *argv[]) - case WalReceiverProcess: - statmsg = "wal receiver process"; - break; -+ case SecurityWorkerProcess: -+ statmsg = "security worker process"; -+ break; - default: - statmsg = "??? process"; - break; -@@ -428,6 +432,10 @@ AuxiliaryProcessMain(int argc, char *argv[]) - WalReceiverMain(); - proc_exit(1); /* should never return */ - -+ case SecurityWorkerProcess: -+ sepgsql_worker_main(); -+ proc_exit(1); /* should never return */ -+ - default: - elog(PANIC, "unrecognized process type: %d", auxType); - proc_exit(1); -@@ -482,6 +490,11 @@ BootstrapModeMain(void) - boot_yyparse(); - - /* -+ * Initial security labeling -+ */ -+ sepgsql_post_bootstraping(); -+ -+ /* - * We should now know about all mapped relations, so it's okay to write - * out the initial relation mapping files. - */ -@@ -779,6 +792,7 @@ InsertOneTuple(Oid objectid) - - tupDesc = CreateTupleDesc(numattr, - RelationGetForm(boot_reldesc)->relhasoids, -+ RelationGetForm(boot_reldesc)->relhassecids, - attrtypes); - tuple = heap_form_tuple(tupDesc, values, Nulls); - if (objectid != (Oid) 0) -diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile -index a970039..0381d6b 100644 ---- a/src/backend/catalog/Makefile -+++ b/src/backend/catalog/Makefile -@@ -13,7 +13,7 @@ include $(top_builddir)/src/Makefile.global - OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \ - pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \ - pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \ -- pg_db_role_setting.o pg_shdepend.o pg_type.o storage.o toasting.o -+ pg_db_role_setting.o pg_seclabel.o pg_shdepend.o pg_type.o storage.o toasting.o - - BKIFILES = postgres.bki postgres.description postgres.shdescription - -@@ -34,7 +34,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ - pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \ - pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \ - pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \ -- pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ -+ pg_seclabel.h pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ - pg_ts_parser.h pg_ts_template.h \ - pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ - pg_default_acl.h \ -diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c -index 9b5602e..80be522 100644 ---- a/src/backend/catalog/aclchk.c -+++ b/src/backend/catalog/aclchk.c -@@ -38,6 +38,7 @@ - #include "catalog/pg_operator.h" - #include "catalog/pg_opfamily.h" - #include "catalog/pg_proc.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/pg_tablespace.h" - #include "catalog/pg_type.h" - #include "catalog/pg_ts_config.h" -@@ -46,6 +47,7 @@ - #include "foreign/foreign.h" - #include "miscadmin.h" - #include "parser/parse_func.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -@@ -1506,6 +1508,10 @@ expand_all_col_privileges(Oid table_oid, Form_pg_class classForm, - if (curr_att == ObjectIdAttributeNumber && !classForm->relhasoids) - continue; - -+ /* Skip security label column, if it doesn't exist */ -+ if (curr_att == SecurityLabelAttributeNumber && !classForm->relhassecids) -+ continue; -+ - /* Views don't have any system columns at all */ - if (classForm->relkind == RELKIND_VIEW && curr_att < 0) - continue; -@@ -1615,6 +1621,8 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, - relOid, grantorId, ACL_KIND_COLUMN, - relname, attnum, - NameStr(pg_attribute_tuple->attname)); -+ /* SELinux checks */ -+ sepgsql_attribute_grant(relOid, attnum); - - /* - * Generate new ACL. -@@ -1876,6 +1884,8 @@ ExecGrant_Relation(InternalGrant *istmt) - ? ACL_KIND_SEQUENCE : ACL_KIND_CLASS, - NameStr(pg_class_tuple->relname), - 0, NULL); -+ /* SELinux checks */ -+ sepgsql_relation_grant(relOid); - - /* - * Generate new ACL. -@@ -2070,6 +2080,8 @@ ExecGrant_Database(InternalGrant *istmt) - datId, grantorId, ACL_KIND_DATABASE, - NameStr(pg_database_tuple->datname), - 0, NULL); -+ /* SELinux checks */ -+ sepgsql_database_grant(datId); - - /* - * Generate new ACL. -@@ -2195,6 +2207,8 @@ ExecGrant_Fdw(InternalGrant *istmt) - fdwid, grantorId, ACL_KIND_FDW, - NameStr(pg_fdw_tuple->fdwname), - 0, NULL); -+ /* SELinux checks */ -+ sepgsql_fdw_grant(fdwid); - - /* - * Generate new ACL. -@@ -2320,6 +2334,8 @@ ExecGrant_ForeignServer(InternalGrant *istmt) - srvid, grantorId, ACL_KIND_FOREIGN_SERVER, - NameStr(pg_server_tuple->srvname), - 0, NULL); -+ /* SELinux checks */ -+ sepgsql_fserver_grant(srvid); - - /* - * Generate new ACL. -@@ -2838,6 +2854,8 @@ ExecGrant_Namespace(InternalGrant *istmt) - nspid, grantorId, ACL_KIND_NAMESPACE, - NameStr(pg_namespace_tuple->nspname), - 0, NULL); -+ /* SELinux checks */ -+ sepgsql_schema_grant(nspid); - - /* - * Generate new ACL. -@@ -2962,6 +2980,8 @@ ExecGrant_Tablespace(InternalGrant *istmt) - tblId, grantorId, ACL_KIND_TABLESPACE, - NameStr(pg_tablespace_tuple->spcname), - 0, NULL); -+ /* SELinux checks */ -+ sepgsql_tablespace_grant(tblId); - - /* - * Generate new ACL. -diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c -index 1739085..36d4852 100644 ---- a/src/backend/catalog/catalog.c -+++ b/src/backend/catalog/catalog.c -@@ -32,6 +32,7 @@ - #include "catalog/pg_namespace.h" - #include "catalog/pg_pltemplate.h" - #include "catalog/pg_db_role_setting.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/pg_shdepend.h" - #include "catalog/pg_shdescription.h" - #include "catalog/pg_tablespace.h" -@@ -306,6 +307,7 @@ IsSharedRelation(Oid relationId) - relationId == AuthMemRelationId || - relationId == DatabaseRelationId || - relationId == PLTemplateRelationId || -+ relationId == SecLabelRelationId || - relationId == SharedDescriptionRelationId || - relationId == SharedDependRelationId || - relationId == TableSpaceRelationId || -@@ -319,6 +321,8 @@ IsSharedRelation(Oid relationId) - relationId == DatabaseNameIndexId || - relationId == DatabaseOidIndexId || - relationId == PLTemplateNameIndexId || -+ relationId == SecLabelSecidIndexId || -+ relationId == SecLabelLabelIndexId || - relationId == SharedDescriptionObjIndexId || - relationId == SharedDependDependerIndexId || - relationId == SharedDependReferenceIndexId || -@@ -329,6 +333,8 @@ IsSharedRelation(Oid relationId) - /* These are their toast tables and toast indexes (see toasting.h) */ - if (relationId == PgDatabaseToastTable || - relationId == PgDatabaseToastIndex || -+ relationId == PgSecLabelToastTable || -+ relationId == PgSecLabelToastIndex || - relationId == PgShdescriptionToastTable || - relationId == PgShdescriptionToastIndex || - relationId == PgDbRoleSettingToastTable || -diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl -index 85d1d71..853074e 100644 ---- a/src/backend/catalog/genbki.pl -+++ b/src/backend/catalog/genbki.pl -@@ -218,7 +218,8 @@ foreach my $catname ( @{ $catalogs->{names} } ) - {cmin => 'cid'}, - {xmax => 'xid'}, - {cmax => 'cid'}, -- {tableoid => 'oid'} -+ {tableoid => 'oid'}, -+ {security_label => 'text'} - ); - foreach my $attr (@SYS_ATTRS) - { -diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c -index 47e0c9b..73cbfcf 100644 ---- a/src/backend/catalog/heap.c -+++ b/src/backend/catalog/heap.c -@@ -43,6 +43,7 @@ - #include "catalog/pg_constraint.h" - #include "catalog/pg_inherits.h" - #include "catalog/pg_namespace.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/pg_statistic.h" - #include "catalog/pg_tablespace.h" - #include "catalog/pg_type.h" -@@ -82,14 +83,16 @@ static void AddNewRelationTuple(Relation pg_class_desc, - Oid relowner, - char relkind, - Datum relacl, -- Datum reloptions); -+ Datum reloptions, -+ Oid *secLabels); - static Oid AddNewRelationType(const char *typeName, - Oid typeNamespace, - Oid new_rel_oid, - char new_rel_kind, - Oid ownerid, - Oid new_row_type, -- Oid new_array_type); -+ Oid new_array_type, -+ Oid securityId); - static void RelationRemoveInheritance(Oid relid); - static void StoreRelCheck(Relation rel, char *ccname, Node *expr, - bool is_local, int inhcount); -@@ -173,7 +176,16 @@ static FormData_pg_attribute a7 = { - true, 'p', 'i', true, false, false, true, 0 - }; - --static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; -+/* -+ * Security Label system column -+ */ -+static FormData_pg_attribute a8 = { -+ 0, {"security_label"}, TEXTOID, 0, -1, -+ SecurityLabelAttributeNumber, 0, -1, -1, -+ false, 'x', 'i', true, false, false, true, 0 -+}; -+ -+static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8}; - - /* - * This function returns a Form_pg_attribute pointer for a system attribute. -@@ -181,12 +193,14 @@ static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; - * happen if there's a problem upstream. - */ - Form_pg_attribute --SystemAttributeDefinition(AttrNumber attno, bool relhasoids) -+SystemAttributeDefinition(AttrNumber attno, bool relhasoids, bool relhassecids) - { - if (attno >= 0 || attno < -(int) lengthof(SysAtt)) - elog(ERROR, "invalid system attribute number %d", attno); - if (attno == ObjectIdAttributeNumber && !relhasoids) - elog(ERROR, "invalid system attribute number %d", attno); -+ if (attno == SecurityLabelAttributeNumber && !relhassecids) -+ elog(ERROR, "invalid system attribute number %d", attno); - return SysAtt[-attno - 1]; - } - -@@ -195,7 +209,7 @@ SystemAttributeDefinition(AttrNumber attno, bool relhasoids) - * pointer for a prototype definition. If not, return NULL. - */ - Form_pg_attribute --SystemAttributeByName(const char *attname, bool relhasoids) -+SystemAttributeByName(const char *attname, bool relhasoids, bool relhassecids) - { - int j; - -@@ -203,16 +217,29 @@ SystemAttributeByName(const char *attname, bool relhasoids) - { - Form_pg_attribute att = SysAtt[j]; - -- if (relhasoids || att->attnum != ObjectIdAttributeNumber) -- { -- if (strcmp(NameStr(att->attname), attname) == 0) -- return att; -- } -+ if (!relhasoids && att->attnum == ObjectIdAttributeNumber) -+ continue; -+ if (!relhassecids && att->attnum == SecurityLabelAttributeNumber) -+ continue; -+ -+ if (strcmp(NameStr(att->attname), attname) == 0) -+ return att; - } - - return NULL; - } - -+/* -+ * If the given attribute is writable system attribute, it returns true. -+ */ -+bool -+SystemAttributeWritable(AttrNumber attnum, bool hasoids, bool hassecids) -+{ -+ if (hassecids && attnum == SecurityLabelAttributeNumber) -+ return true; -+ -+ return false; -+} - - /* ---------------------------------------------------------------- - * XXX END OF UGLY HARD CODED BADNESS XXX -@@ -391,7 +418,8 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, - for (i = 0; i < natts; i++) - { - if (SystemAttributeByName(NameStr(tupdesc->attrs[i]->attname), -- tupdesc->tdhasoid) != NULL) -+ tupdesc->tdhasoid, -+ tupdesc->tdhassecid) != NULL) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_COLUMN), - errmsg("column name \"%s\" conflicts with a system column name", -@@ -509,7 +537,8 @@ CheckAttributeType(const char *attname, Oid atttypid, - void - InsertPgAttributeTuple(Relation pg_attribute_rel, - Form_pg_attribute new_attribute, -- CatalogIndexState indstate) -+ CatalogIndexState indstate, -+ Oid securityId) - { - Datum values[Natts_pg_attribute]; - bool nulls[Natts_pg_attribute]; -@@ -542,6 +571,8 @@ InsertPgAttributeTuple(Relation pg_attribute_rel, - nulls[Anum_pg_attribute_attoptions - 1] = true; - - tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, securityId); - - /* finally insert the new tuple, update the indexes, and clean up */ - simple_heap_insert(pg_attribute_rel, tup); -@@ -566,13 +597,15 @@ AddNewAttributeTuples(Oid new_rel_oid, - TupleDesc tupdesc, - char relkind, - bool oidislocal, -- int oidinhcount) -+ int oidinhcount, -+ Oid *secLabels) - { - Form_pg_attribute attr; - int i; - Relation rel; - CatalogIndexState indstate; - int natts = tupdesc->natts; -+ Oid secid; - ObjectAddress myself, - referenced; - -@@ -596,7 +629,10 @@ AddNewAttributeTuples(Oid new_rel_oid, - attr->attstattarget = -1; - attr->attcacheoff = -1; - -- InsertPgAttributeTuple(rel, attr, indstate); -+ secid = (!secLabels ? InvalidOid : -+ secLabels[i - FirstLowInvalidHeapAttributeNumber]); -+ -+ InsertPgAttributeTuple(rel, attr, indstate, secid); - - /* Add dependency info */ - myself.classId = RelationRelationId; -@@ -624,6 +660,11 @@ AddNewAttributeTuples(Oid new_rel_oid, - SysAtt[i]->attnum == ObjectIdAttributeNumber) - continue; - -+ /* skip security label where appropriate */ -+ if (!tupdesc->tdhassecid && -+ SysAtt[i]->attnum == SecurityLabelAttributeNumber) -+ continue; -+ - memcpy(&attStruct, (char *) SysAtt[i], sizeof(FormData_pg_attribute)); - - /* Fill in the correct relation OID in the copied tuple */ -@@ -636,7 +677,10 @@ AddNewAttributeTuples(Oid new_rel_oid, - attStruct.attinhcount = oidinhcount; - } - -- InsertPgAttributeTuple(rel, &attStruct, indstate); -+ secid = (!secLabels ? InvalidOid -+ : secLabels[SysAtt[i]->attnum - FirstLowInvalidHeapAttributeNumber]); -+ -+ InsertPgAttributeTuple(rel, &attStruct, indstate, secid); - } - } - -@@ -666,7 +710,8 @@ InsertPgClassTuple(Relation pg_class_desc, - Relation new_rel_desc, - Oid new_rel_oid, - Datum relacl, -- Datum reloptions) -+ Datum reloptions, -+ Oid securityId) - { - Form_pg_class rd_rel = new_rel_desc->rd_rel; - Datum values[Natts_pg_class]; -@@ -696,6 +741,7 @@ InsertPgClassTuple(Relation pg_class_desc, - values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts); - values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks); - values[Anum_pg_class_relhasoids - 1] = BoolGetDatum(rd_rel->relhasoids); -+ values[Anum_pg_class_relhassecids - 1] = BoolGetDatum(rd_rel->relhassecids); - values[Anum_pg_class_relhaspkey - 1] = BoolGetDatum(rd_rel->relhaspkey); - values[Anum_pg_class_relhasexclusion - 1] = BoolGetDatum(rd_rel->relhasexclusion); - values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules); -@@ -719,6 +765,9 @@ InsertPgClassTuple(Relation pg_class_desc, - */ - HeapTupleSetOid(tup, new_rel_oid); - -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, securityId); -+ - /* finally insert the new tuple, update the indexes, and clean up */ - simple_heap_insert(pg_class_desc, tup); - -@@ -743,9 +792,11 @@ AddNewRelationTuple(Relation pg_class_desc, - Oid relowner, - char relkind, - Datum relacl, -- Datum reloptions) -+ Datum reloptions, -+ Oid *secLabels) - { - Form_pg_class new_rel_reltup; -+ Oid secid; - - /* - * first we update some of the information in our uncataloged relation's -@@ -803,9 +854,11 @@ AddNewRelationTuple(Relation pg_class_desc, - - new_rel_desc->rd_att->tdtypeid = new_type_oid; - -+ secid = (!secLabels ? InvalidOid : secLabels[0]); -+ - /* Now build and insert the tuple */ - InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, -- relacl, reloptions); -+ relacl, reloptions, secid); - } - - -@@ -822,7 +875,8 @@ AddNewRelationType(const char *typeName, - char new_rel_kind, - Oid ownerid, - Oid new_row_type, -- Oid new_array_type) -+ Oid new_array_type, -+ Oid securityId) - { - return - TypeCreate(new_row_type, /* optional predetermined OID */ -@@ -854,7 +908,8 @@ AddNewRelationType(const char *typeName, - 'x', /* fully TOASTable */ - -1, /* typmod */ - 0, /* array dimensions for typBaseType */ -- false); /* Type NOT NULL */ -+ false, /* Type NOT NULL */ -+ securityId); /* security-id of the type */ - } - - /* -------------------------------- -@@ -903,7 +958,8 @@ heap_create_with_catalog(const char *relname, - OnCommitAction oncommit, - Datum reloptions, - bool use_user_acl, -- bool allow_system_table_mods) -+ bool allow_system_table_mods, -+ Oid *secLabels) - { - Relation pg_class_desc; - Relation new_rel_desc; -@@ -911,6 +967,7 @@ heap_create_with_catalog(const char *relname, - Oid old_type_oid; - Oid new_type_oid; - Oid new_array_oid = InvalidOid; -+ Oid type_secid = InvalidOid; - - pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock); - -@@ -1030,6 +1087,11 @@ heap_create_with_catalog(const char *relname, - relkind == RELKIND_COMPOSITE_TYPE)) - new_array_oid = AssignTypeArrayOid(); - -+ /* security context of the relation type */ -+ if (secLabels) -+ type_secid = seclabelMoveSecid(TypeRelationId, -+ RelationRelationId, secLabels[0]); -+ - /* - * Since defining a relation also defines a complex type, we add a new - * system type corresponding to the new relation. The OID of the type can -@@ -1046,7 +1108,8 @@ heap_create_with_catalog(const char *relname, - relkind, - ownerid, - reltypeid, -- new_array_oid); -+ new_array_oid, -+ type_secid); - - /* - * Now make the array type if wanted. -@@ -1086,7 +1149,8 @@ heap_create_with_catalog(const char *relname, - 'x', /* fully TOASTable */ - -1, /* typmod */ - 0, /* array dimensions for typBaseType */ -- false); /* Type NOT NULL */ -+ false, /* Type NOT NULL */ -+ type_secid); /* security-id of the type */ - - pfree(relarrayname); - } -@@ -1106,13 +1170,14 @@ heap_create_with_catalog(const char *relname, - ownerid, - relkind, - PointerGetDatum(relacl), -- reloptions); -+ reloptions, -+ secLabels); - - /* - * now add tuples to pg_attribute for the attributes in our new relation. - */ - AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind, -- oidislocal, oidinhcount); -+ oidislocal, oidinhcount, secLabels); - - /* - * Make a dependency link to force the relation to be deleted if its -@@ -1590,6 +1655,11 @@ heap_drop_with_catalog(Oid relid) - * delete relation tuple - */ - DeleteRelationTuple(relid); -+ -+ /* -+ * delete orphan pg_seclabel entries -+ */ -+ seclabelOnDropTable(relid); - } - - -diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c -index 8af382b..01f53fd 100644 ---- a/src/backend/catalog/index.c -+++ b/src/backend/catalog/index.c -@@ -39,6 +39,7 @@ - #include "catalog/pg_constraint.h" - #include "catalog/pg_operator.h" - #include "catalog/pg_opclass.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/pg_tablespace.h" - #include "catalog/pg_trigger.h" - #include "catalog/pg_type.h" -@@ -89,7 +90,8 @@ static TupleDesc ConstructTupleDescriptor(Relation heapRelation, - Oid *classObjectId); - static void InitializeAttributeOids(Relation indexRelation, - int numatts, Oid indexoid); --static void AppendAttributeTuples(Relation indexRelation, int numatts); -+static void AppendAttributeTuples(Relation indexRelation, -+ int numatts, Oid securityId); - static void UpdateIndexRelation(Oid indexoid, Oid heapoid, - IndexInfo *indexInfo, - Oid *classOids, -@@ -154,7 +156,7 @@ ConstructTupleDescriptor(Relation heapRelation, - /* - * allocate the new tuple descriptor - */ -- indexTupDesc = CreateTemplateTupleDesc(numatts, false); -+ indexTupDesc = CreateTemplateTupleDesc(numatts, false, false); - - /* - * For simple index columns, we copy the pg_attribute row from the parent -@@ -181,7 +183,8 @@ ConstructTupleDescriptor(Relation heapRelation, - * here we are indexing on a system attribute (-1...-n) - */ - from = SystemAttributeDefinition(atnum, -- heapRelation->rd_rel->relhasoids); -+ heapRelation->rd_rel->relhasoids, -+ heapRelation->rd_rel->relhassecids); - } - else - { -@@ -338,13 +341,16 @@ InitializeAttributeOids(Relation indexRelation, - * ---------------------------------------------------------------- - */ - static void --AppendAttributeTuples(Relation indexRelation, int numatts) -+AppendAttributeTuples(Relation indexRelation, int numatts, Oid securityId) - { - Relation pg_attribute; - CatalogIndexState indstate; - TupleDesc indexTupDesc; - int i; - -+ /* copy security id */ -+ securityId = seclabelMoveSecid(AttributeRelationId, -+ RelationRelationId, securityId); - /* - * open the attribute relation and its indexes - */ -@@ -366,7 +372,8 @@ AppendAttributeTuples(Relation indexRelation, int numatts) - Assert(indexTupDesc->attrs[i]->attnum == i + 1); - Assert(indexTupDesc->attrs[i]->attcacheoff == -1); - -- InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], indstate); -+ InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], -+ indstate, securityId); - } - - CatalogCloseIndexes(indstate); -@@ -544,6 +551,7 @@ index_create(Oid heapRelationId, - bool mapped_relation; - bool is_exclusion; - Oid namespaceId; -+ Oid securityId; - int i; - - is_exclusion = (indexInfo->ii_ExclusionOps != NULL); -@@ -681,15 +689,21 @@ index_create(Oid heapRelationId, - indexRelation->rd_rel->relam = accessMethodObjectId; - indexRelation->rd_rel->relkind = RELKIND_INDEX; - indexRelation->rd_rel->relhasoids = false; -+ indexRelation->rd_rel->relhassecids = false; - indexRelation->rd_rel->relhasexclusion = is_exclusion; - - /* -+ * Index always has same security id of the relation to be indexed on. -+ */ -+ securityId = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(heapRelationId)); -+ -+ /* - * store index's pg_class entry - */ - InsertPgClassTuple(pg_class, indexRelation, - RelationGetRelid(indexRelation), - (Datum) 0, -- reloptions); -+ reloptions, securityId); - - /* done with pg_class */ - heap_close(pg_class, RowExclusiveLock); -@@ -705,7 +719,7 @@ index_create(Oid heapRelationId, - /* - * append ATTRIBUTE tuples for the index - */ -- AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs); -+ AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs, securityId); - - /* ---------------- - * update pg_index -diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c -index 2e5bb27..e730904 100644 ---- a/src/backend/catalog/namespace.c -+++ b/src/backend/catalog/namespace.c -@@ -40,6 +40,7 @@ - #include "miscadmin.h" - #include "nodes/makefuncs.h" - #include "parser/parse_func.h" -+#include "sepgsql/hooks.h" - #include "storage/backendid.h" - #include "storage/ipc.h" - #include "utils/acl.h" -@@ -2311,6 +2312,9 @@ LookupExplicitNamespace(const char *nspname) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - nspname); - -+ /* SELinux checks */ -+ sepgsql_schema_search(namespaceId, true); -+ - return namespaceId; - } - -@@ -2911,7 +2915,8 @@ recomputeNamespacePath(void) - if (OidIsValid(namespaceId) && - !list_member_oid(oidlist, namespaceId) && - pg_namespace_aclcheck(namespaceId, roleid, -- ACL_USAGE) == ACLCHECK_OK) -+ ACL_USAGE) == ACLCHECK_OK && -+ sepgsql_schema_search(namespaceId, false)) - oidlist = lappend_oid(oidlist, namespaceId); - } - } -@@ -2938,7 +2943,8 @@ recomputeNamespacePath(void) - if (OidIsValid(namespaceId) && - !list_member_oid(oidlist, namespaceId) && - pg_namespace_aclcheck(namespaceId, roleid, -- ACL_USAGE) == ACLCHECK_OK) -+ ACL_USAGE) == ACLCHECK_OK && -+ sepgsql_schema_search(namespaceId, false)) - oidlist = lappend_oid(oidlist, namespaceId); - } - } -@@ -3004,9 +3010,12 @@ InitTempTableNamespace(void) - char namespaceName[NAMEDATALEN]; - Oid namespaceId; - Oid toastspaceId; -+ Oid secid; - - 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: -@@ -3024,6 +3033,9 @@ InitTempTableNamespace(void) - errmsg("permission denied to create temporary tables in database \"%s\"", - get_database_name(MyDatabaseId)))); - -+ /* SELinux checks */ -+ secid = sepgsql_schema_create(namespaceName, true); -+ - /* - * Do not allow a Hot Standby slave session to make temp tables. Aside - * from problems with modifying the system catalogs, there is a naming -@@ -3039,8 +3051,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 = GetSysCacheOid1(NAMESPACENAME, - CStringGetDatum(namespaceName)); - if (!OidIsValid(namespaceId)) -@@ -3053,7 +3063,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, -+ secid); - /* Advance command counter to make namespace visible */ - CommandCounterIncrement(); - } -@@ -3078,7 +3090,9 @@ InitTempTableNamespace(void) - CStringGetDatum(namespaceName)); - if (!OidIsValid(toastspaceId)) - { -- toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID); -+ toastspaceId = NamespaceCreate(namespaceName, -+ BOOTSTRAP_SUPERUSERID, -+ secid); - /* Advance command counter to make namespace visible */ - CommandCounterIncrement(); - } -diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c -index 9672ecf..b28a314 100644 ---- a/src/backend/catalog/pg_aggregate.c -+++ b/src/backend/catalog/pg_aggregate.c -@@ -27,6 +27,7 @@ - #include "parser/parse_coerce.h" - #include "parser/parse_func.h" - #include "parser/parse_oper.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -@@ -67,6 +68,7 @@ AggregateCreate(const char *aggName, - Oid *fnArgs; - int nargs_transfn; - Oid procOid; -+ Oid procSecid; - TupleDesc tupDesc; - int i; - ObjectAddress myself, -@@ -161,6 +163,10 @@ AggregateCreate(const char *aggName, - } - Assert(OidIsValid(finaltype)); - -+ /* SELinux checks */ -+ procSecid = sepgsql_aggregate_create(aggName, aggNamespace, -+ transfn, finalfn); -+ - /* - * If finaltype (i.e. aggregate return type) is polymorphic, inputs must - * be polymorphic also, else parser will fail to deduce result type. -@@ -229,7 +235,8 @@ AggregateCreate(const char *aggName, - NIL, /* parameterDefaults */ - PointerGetDatum(NULL), /* proconfig */ - 1, /* procost */ -- 0); /* prorows */ -+ 0, /* prorows */ -+ procSecid); /* security-id */ - - /* - * Okay to create the pg_aggregate entry. -diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c -index 574eef5..2a46cdb 100644 ---- a/src/backend/catalog/pg_conversion.c -+++ b/src/backend/catalog/pg_conversion.c -@@ -40,7 +40,7 @@ Oid - ConversionCreate(const char *conname, Oid connamespace, - Oid conowner, - int32 conforencoding, int32 contoencoding, -- Oid conproc, bool def) -+ Oid conproc, bool def, Oid securityId) - { - int i; - Relation rel; -@@ -104,6 +104,8 @@ ConversionCreate(const char *conname, Oid connamespace, - - tup = heap_form_tuple(tupDesc, values, nulls); - -+ HeapTupleSetSecid(tup, securityId); -+ - /* insert a new tuple */ - oid = simple_heap_insert(rel, tup); - Assert(OidIsValid(oid)); -diff --git a/src/backend/catalog/pg_largeobject.c b/src/backend/catalog/pg_largeobject.c -index 7c5f56f..fb8bf22 100644 ---- a/src/backend/catalog/pg_largeobject.c -+++ b/src/backend/catalog/pg_largeobject.c -@@ -21,10 +21,13 @@ - #include "catalog/dependency.h" - #include "catalog/indexing.h" - #include "catalog/pg_authid.h" -+#include "catalog/pg_description.h" - #include "catalog/pg_largeobject.h" - #include "catalog/pg_largeobject_metadata.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/toasting.h" - #include "miscadmin.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/bytea.h" - #include "utils/fmgroids.h" -@@ -40,7 +43,7 @@ - * will appear to exist with size 0. - */ - Oid --LargeObjectCreate(Oid loid) -+LargeObjectCreate(Oid loid, Oid securityId) - { - Relation pg_lo_meta; - HeapTuple ntup; -@@ -66,6 +69,8 @@ LargeObjectCreate(Oid loid) - if (OidIsValid(loid)) - HeapTupleSetOid(ntup, loid); - -+ HeapTupleSetSecid(ntup, securityId); -+ - loid_new = simple_heap_insert(pg_lo_meta, ntup); - Assert(!OidIsValid(loid) || loid == loid_new); - -@@ -245,6 +250,64 @@ LargeObjectAlterOwner(Oid loid, Oid newOwnerId) - } - - /* -+ * LargeObjectAlterSecLabel -+ * -+ * Implementation of ALTER LARGE OBJECT xxx SECURITY LABEL -+ */ -+void -+LargeObjectAlterSecLabel(Oid loid, char *new_label) -+{ -+ Relation pg_lo_meta; -+ ScanKeyData skey; -+ SysScanDesc scan; -+ HeapTuple oldtup; -+ HeapTuple newtup; -+ Oid securityId; -+ -+ pg_lo_meta = heap_open(LargeObjectMetadataRelationId, -+ RowExclusiveLock); -+ -+ ScanKeyInit(&skey, -+ ObjectIdAttributeNumber, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(loid)); -+ -+ scan = systable_beginscan(pg_lo_meta, -+ LargeObjectMetadataOidIndexId, true, -+ SnapshotNow, 1, &skey); -+ -+ oldtup = systable_getnext(scan); -+ if (!HeapTupleIsValid(oldtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_OBJECT), -+ errmsg("large object %u does not exist", loid))); -+ -+ /* Must be owner of the large object */ -+ if (!pg_largeobject_ownercheck(loid, GetUserId())) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("must be owner of large object %u", loid))); -+ -+ /* SELinux checks */ -+ securityId = sepgsql_largeobject_relabel(loid, new_label); -+ -+ /* update the tuple */ -+ newtup = heap_copytuple(oldtup); -+ -+ HeapTupleSetSecid(newtup, securityId); -+ -+ simple_heap_update(pg_lo_meta, &newtup->t_self, newtup); -+ -+ CatalogUpdateIndexes(pg_lo_meta, newtup); -+ -+ heap_freetuple(newtup); -+ -+ systable_endscan(scan); -+ -+ heap_close(pg_lo_meta, RowExclusiveLock); -+} -+ -+/* - * LargeObjectExists - * - * We don't use the system cache for large object metadata, for fear of -diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c -index 79d03b3..4357a9e 100644 ---- a/src/backend/catalog/pg_namespace.c -+++ b/src/backend/catalog/pg_namespace.c -@@ -28,7 +28,7 @@ - * --------------- - */ - Oid --NamespaceCreate(const char *nspName, Oid ownerId) -+NamespaceCreate(const char *nspName, Oid ownerId, Oid secid) - { - Relation nspdesc; - HeapTuple tup; -@@ -64,6 +64,8 @@ NamespaceCreate(const char *nspName, Oid ownerId) - tupDesc = nspdesc->rd_att; - - tup = heap_form_tuple(tupDesc, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, secid); - - nspoid = simple_heap_insert(nspdesc, tup); - Assert(OidIsValid(nspoid)); -diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c -index 8eebb1d..71be3c5 100644 ---- a/src/backend/catalog/pg_operator.c -+++ b/src/backend/catalog/pg_operator.c -@@ -28,6 +28,7 @@ - #include "catalog/pg_type.h" - #include "miscadmin.h" - #include "parser/parse_oper.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -@@ -204,6 +205,7 @@ OperatorShellMake(const char *operatorName, - { - Relation pg_operator_desc; - Oid operatorObjectId; -+ Oid securityId; - int i; - HeapTuple tup; - Datum values[Natts_pg_operator]; -@@ -220,6 +222,12 @@ OperatorShellMake(const char *operatorName, - errmsg("\"%s\" is not a valid operator name", - operatorName))); - -+ /* SELinux checks */ -+ securityId = sepgsql_operator_create(operatorName, InvalidOid, -+ operatorNamespace, -+ InvalidOid, InvalidOid, InvalidOid, -+ InvalidOid, InvalidOid); -+ - /* - * initialize our *nulls and *values arrays - */ -@@ -261,6 +269,8 @@ OperatorShellMake(const char *operatorName, - */ - tup = heap_form_tuple(tupDesc, values, nulls); - -+ HeapTupleSetSecid(tup, securityId); -+ - /* - * insert our "shell" operator tuple - */ -@@ -340,6 +350,7 @@ OperatorCreate(const char *operatorName, - bool replaces[Natts_pg_operator]; - Datum values[Natts_pg_operator]; - Oid operatorObjectId; -+ Oid securityId; - bool operatorAlreadyDefined; - Oid operResultType; - Oid commutatorId, -@@ -476,6 +487,12 @@ OperatorCreate(const char *operatorName, - else - negatorId = InvalidOid; - -+ /* SELinux checks */ -+ securityId = sepgsql_operator_create(operatorName, operatorObjectId, -+ operatorNamespace, -+ procedureId, restrictionId, joinId, -+ commutatorId, negatorId); -+ - /* - * set up values in the operator tuple - */ -@@ -516,6 +533,8 @@ OperatorCreate(const char *operatorName, - if (!HeapTupleIsValid(tup)) - elog(ERROR, "cache lookup failed for operator %u", - operatorObjectId); -+ if (securityId != HeapTupleHasSecid(tup)) -+ elog(ERROR, "Bug? security-id was mismatched."); - - tup = heap_modify_tuple(tup, - RelationGetDescr(pg_operator_desc), -@@ -530,6 +549,8 @@ OperatorCreate(const char *operatorName, - tupDesc = pg_operator_desc->rd_att; - tup = heap_form_tuple(tupDesc, values, nulls); - -+ HeapTupleSetSecid(tup, securityId); -+ - operatorObjectId = simple_heap_insert(pg_operator_desc, tup); - } - -diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c -index f60cc61..a2ccc76 100644 ---- a/src/backend/catalog/pg_proc.c -+++ b/src/backend/catalog/pg_proc.c -@@ -84,7 +84,8 @@ ProcedureCreate(const char *procedureName, - List *parameterDefaults, - Datum proconfig, - float4 procost, -- float4 prorows) -+ float4 prorows, -+ Oid prosecid) - { - Oid retval; - int parameterCount; -@@ -364,6 +365,8 @@ ProcedureCreate(const char *procedureName, - if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner)) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - procedureName); -+ if (prosecid != HeapTupleGetSecid(oldtup)) -+ elog(ERROR, "Bug? security-id was tried to be changed."); - - /* - * Not okay to change the return type of the existing proc, since -@@ -548,6 +551,9 @@ ProcedureCreate(const char *procedureName, - nulls[Anum_pg_proc_proacl - 1] = true; - - tup = heap_form_tuple(tupDesc, values, nulls); -+ -+ HeapTupleSetSecid(tup, prosecid); -+ - simple_heap_insert(rel, tup); - is_update = false; - } -diff --git a/src/backend/catalog/pg_seclabel.c b/src/backend/catalog/pg_seclabel.c -new file mode 100644 -index 0000000..4816635 ---- /dev/null -+++ b/src/backend/catalog/pg_seclabel.c -@@ -0,0 +1,646 @@ -+/* -+ * pg_seclabel.c -+ * -+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#include "postgres.h" -+ -+#include "access/genam.h" -+#include "access/heapam.h" -+#include "access/sysattr.h" -+#include "access/tupdesc.h" -+#include "catalog/catalog.h" -+#include "catalog/indexing.h" -+#include "catalog/pg_aggregate.h" -+#include "catalog/pg_amop.h" -+#include "catalog/pg_amproc.h" -+#include "catalog/pg_attrdef.h" -+#include "catalog/pg_auth_members.h" -+#include "catalog/pg_constraint.h" -+#include "catalog/pg_db_role_setting.h" -+#include "catalog/pg_depend.h" -+#include "catalog/pg_description.h" -+#include "catalog/pg_enum.h" -+#include "catalog/pg_index.h" -+#include "catalog/pg_inherits.h" -+#include "catalog/pg_largeobject.h" -+#include "catalog/pg_namespace.h" -+#include "catalog/pg_rewrite.h" -+#include "catalog/pg_seclabel.h" -+#include "catalog/pg_shdepend.h" -+#include "catalog/pg_shdescription.h" -+#include "catalog/pg_trigger.h" -+#include "catalog/pg_ts_config_map.h" -+#include "executor/spi.h" -+#include "miscadmin.h" -+#include "sepgsql/sepgsql.h" -+#include "sepgsql/hooks.h" -+#include "utils/builtins.h" -+#include "utils/fmgroids.h" -+#include "utils/lsyscache.h" -+#include "utils/rel.h" -+#include "utils/syscache.h" -+#include "utils/tqual.h" -+ -+bool ignore_security_label_input; -+ -+void -+seclabelOnCreateDatabase(Oid src_datid, Oid dst_datid) -+{ -+ Relation rel; -+ ScanKeyData keys[1]; -+ SysScanDesc scan; -+ HeapTuple oldtup, newtup; -+ Datum values[Natts_pg_seclabel]; -+ bool nulls[Natts_pg_seclabel]; -+ bool replaces[Natts_pg_seclabel]; -+ -+ /* Scan all entries with pg_seclabel.datid = src_datid */ -+ ScanKeyInit(&keys[0], -+ Anum_pg_seclabel_datid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(src_datid)); -+ -+ rel = heap_open(SecLabelRelationId, RowExclusiveLock); -+ -+ scan = systable_beginscan(rel, SecLabelSecidIndexId, true, -+ SnapshotNow, 1, keys); -+ -+ /* corresponding entries will be inserted with new datid */ -+ memset(values, 0, sizeof(values)); -+ memset(nulls, false, sizeof(nulls)); -+ memset(replaces, false, sizeof(replaces)); -+ -+ values[Anum_pg_seclabel_datid - 1] = ObjectIdGetDatum(dst_datid); -+ replaces[Anum_pg_seclabel_datid - 1] = true; -+ while (HeapTupleIsValid(oldtup = systable_getnext(scan))) -+ { -+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), -+ values, nulls, replaces); -+ simple_heap_insert(rel, newtup); -+ -+ CatalogUpdateIndexes(rel, newtup); -+ -+ heap_freetuple(newtup); -+ } -+ systable_endscan(scan); -+ -+ heap_close(rel, RowExclusiveLock); -+} -+ -+void -+seclabelOnDropDatabase(Oid datid) -+{ -+ Relation rel; -+ ScanKeyData keys[1]; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ -+ /* Scan all entries with pg_seclabel.datid = datid */ -+ ScanKeyInit(&keys[0], -+ Anum_pg_seclabel_datid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(datid)); -+ -+ rel = heap_open(SecLabelRelationId, RowExclusiveLock); -+ -+ scan = systable_beginscan(rel, SecLabelSecidIndexId, true, -+ SnapshotNow, 1, keys); -+ -+ while (HeapTupleIsValid(tuple = systable_getnext(scan))) -+ { -+ simple_heap_delete(rel, &tuple->t_self); -+ } -+ -+ systable_endscan(scan); -+ -+ heap_close(rel, RowExclusiveLock); -+} -+ -+void -+seclabelOnDropTable(Oid relid) -+{ -+ Relation rel; -+ SysScanDesc scan; -+ ScanKeyData key[2]; -+ HeapTuple tuple; -+ Oid database_oid; -+ -+ database_oid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId); -+ ScanKeyInit(&key[0], -+ Anum_pg_seclabel_datid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(database_oid)); -+ ScanKeyInit(&key[1], -+ Anum_pg_seclabel_relid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(relid)); -+ -+ rel = heap_open(SecLabelRelationId, RowExclusiveLock); -+ scan = systable_beginscan(rel, SecLabelLabelIndexId, true, -+ SnapshotNow, 2, key); -+ -+ while (HeapTupleIsValid(tuple = systable_getnext(scan))) -+ simple_heap_delete(rel, &tuple->t_self); -+ -+ systable_endscan(scan); -+ -+ heap_close(rel, RowExclusiveLock); -+} -+ -+/* -+ * XXX - it should be replaced by BKI scripts -+ */ -+bool -+seclabelCatalogHasSysAttr(Oid relOid) -+{ -+ switch (relOid) -+ { -+ case AggregateRelationId: -+ /* pg_aggregate is property of pg_proc */ -+ case AccessMethodOperatorRelationId: -+ /* pg_amop is property of pg_opfamily */ -+ case AccessMethodProcedureRelationId: -+ /* pg_amproc is property of pg_opfamily */ -+ case AttrDefaultRelationId: -+ /* pg_attrdef is property of pg_attribute */ -+ case AuthMemRelationId: -+ /* pg_auth_members is property of pg_auth */ -+ case ConstraintRelationId: -+ /* -+ * CHECK constraint is property of pg_class -+ * DOMAIN constraint is property of pg_type -+ * Global assertion is property of pg_database -+ */ -+ case DbRoleSettingRelationId: -+ /* pg_db_role_setting is property of pg_auth or pg_database */ -+ case DependRelationId: -+ /* property of the depending object */ -+ case DescriptionRelationId: -+ /* property of the object commented on */ -+ case EnumRelationId: -+ /* pg_enum is property of pg_type */ -+ case IndexRelationId: -+ /* pg_index is property of pg_class with RELKIND_INDEX */ -+ case InheritsRelationId: -+ /* pg_inherits is property of the child relation */ -+ case LargeObjectRelationId: -+ /* pg_largeobject is data chunk of pg_largeobject_metadata */ -+ case RewriteRelationId: -+ /* pg_rewrite is property of pg_class */ -+ case SecLabelRelationId: -+ /* No security attribute has no security label */ -+ case SharedDependRelationId: -+ /* property of the depending shared object */ -+ case SharedDescriptionRelationId: -+ /* property of the shared object commented on */ -+ case TriggerRelationId: -+ /* pg_trigger is property of pg_class */ -+ case TSConfigMapRelationId: -+ /* pg_ts_config_map is property of pg_ts_config */ -+ return false; -+ -+ default: -+ return true; -+ } -+} -+ -+Oid * -+seclabelMakeRelationDefaults(TupleDesc tupdesc, List *supOids) -+{ -+ ListCell *l; -+ Oid *secLabels; -+ Oid securityId; -+ int index, attno, nitems; -+ -+ nitems = tupdesc->natts - FirstLowInvalidHeapAttributeNumber; -+ secLabels = palloc0(sizeof(Oid) * nitems); -+ -+ foreach (l, supOids) -+ { -+ Oid relOid = lfirst_oid(l); -+ -+ securityId = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(relOid)); -+ -+ if (!OidIsValid(secLabels[0])) -+ secLabels[0] = securityId; -+ else if (!seclabelCompareSecid(RelationRelationId, secLabels[0], -+ RelationRelationId, securityId)) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("cannot inherit relations with different label"))); -+ -+ for (index = 1; index < nitems; index++) -+ { -+ attno = index + FirstLowInvalidHeapAttributeNumber; -+ -+ if (attno < 0) -+ securityId = GetSysCacheSecid2(ATTNUM, -+ ObjectIdGetDatum(relOid), -+ Int16GetDatum(attno)); -+ else -+ { -+ const char *attname = NameStr(tupdesc->attrs[attno]->attname); -+ securityId = GetSysCacheSecid2(ATTNAME, -+ ObjectIdGetDatum(relOid), -+ PointerGetDatum(attname)); -+ } -+ -+ if (!OidIsValid(securityId)) -+ continue; -+ -+ if (!OidIsValid(secLabels[index])) -+ secLabels[index] = securityId; -+ else if (!seclabelCompareSecid(AttributeRelationId, secLabels[index], -+ AttributeRelationId, securityId)) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("cannot inherit attribute with different label"))); -+ } -+ } -+ return secLabels; -+} -+ -+Oid * -+seclabelMakeToastDefaults(TupleDesc tupdesc, Oid relOid) -+{ -+ Oid *secLabels; -+ Oid securityId; -+ int index, nitems; -+ -+ nitems = tupdesc->natts + 1 - FirstLowInvalidHeapAttributeNumber; -+ secLabels = palloc0(sizeof(Oid) * nitems); -+ -+ securityId = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(relOid)); -+ secLabels[0] = securityId; -+ -+ securityId = seclabelMoveSecid(AttributeRelationId, -+ RelationRelationId, -+ securityId); -+ for (index = 1; index < nitems; index++) -+ secLabels[index] = securityId; -+ -+ return secLabels; -+} -+ -+Oid -+seclabelGetNewSecid(Relation rel, HeapTuple tuple) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled() && -+ !IsBootstrapProcessingMode()) -+ { -+ return sepgsql_get_default_secid(rel, tuple); -+ } -+#endif -+ return InvalidOid; -+} -+ -+static Oid -+inputSecurityLabel(Oid relid, const char *seclabel) -+{ -+ LOCKMODE lockmode = AccessShareLock; -+ Relation rel; -+ ScanKeyData skey[3]; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ Oid datid; -+ Oid secid; -+ Datum values[Natts_pg_seclabel]; -+ bool nulls[Natts_pg_seclabel]; -+ -+ datid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId); -+ -+retry: -+ /* -+ * Lookup pg_seclabel first, then insert a new entry if not found. -+ * An exclusive lock is not necessary for the first read-only path, -+ * and we assume most of trials are read-only. -+ */ -+ rel = heap_open(SecLabelRelationId, lockmode); -+ -+ ScanKeyInit(&skey[0], -+ Anum_pg_seclabel_datid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(datid)); -+ ScanKeyInit(&skey[1], -+ Anum_pg_seclabel_relid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(relid)); -+ ScanKeyInit(&skey[2], -+ Anum_pg_seclabel_label, -+ BTEqualStrategyNumber, F_TEXTEQ, -+ CStringGetTextDatum(seclabel)); -+ -+ scan = systable_beginscan(rel, SecLabelLabelIndexId, true, -+ SnapshotToast, 3, skey); -+ -+ tuple = systable_getnext(scan); -+ if (HeapTupleIsValid(tuple)) -+ { -+ secid = ((Form_pg_seclabel) GETSTRUCT(tuple))->secid; -+ systable_endscan(scan); -+ heap_close(rel, lockmode); -+ return secid; -+ } -+ -+ /* -+ * If not exist, try to insert a new entry. -+ */ -+ if (lockmode == AccessShareLock) -+ { -+ systable_endscan(scan); -+ heap_close(rel, lockmode); -+ lockmode = RowExclusiveLock; -+ goto retry; -+ } -+ -+ memset(nulls, false, sizeof(nulls)); -+ secid = GetNewOidWithIndex(rel, SecLabelSecidIndexId, -+ Anum_pg_seclabel_secid); -+ values[Anum_pg_seclabel_secid - 1] = ObjectIdGetDatum(secid); -+ values[Anum_pg_seclabel_datid - 1] = ObjectIdGetDatum(datid); -+ values[Anum_pg_seclabel_relid - 1] = ObjectIdGetDatum(relid); -+ values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(seclabel); -+ -+ tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); -+ -+ simple_heap_insert(rel, tuple); -+ -+ CatalogUpdateIndexes(rel, tuple); -+ -+ systable_endscan(scan); -+ -+ heap_close(rel, lockmode); -+ -+ return secid; -+} -+ -+static char * -+outputSecurityLabel(Oid relid, Oid secid) -+{ -+ Relation rel; -+ ScanKeyData skey[3]; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ Oid datid; -+ char *result = NULL; -+ -+ datid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId); -+ -+ /* -+ * Lookup pg_seclabel for the given datid/relid/secid -+ */ -+ rel = heap_open(SecLabelRelationId, AccessShareLock); -+ -+ ScanKeyInit(&skey[0], -+ Anum_pg_seclabel_secid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(secid)); -+ ScanKeyInit(&skey[1], -+ Anum_pg_seclabel_datid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(datid)); -+ ScanKeyInit(&skey[2], -+ Anum_pg_seclabel_relid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(relid)); -+ -+ scan = systable_beginscan(rel, SecLabelSecidIndexId, true, -+ SnapshotToast, 3, skey); -+ tuple = systable_getnext(scan); -+ if (HeapTupleIsValid(tuple)) -+ { -+ Datum datum; -+ bool isnull; -+ -+ datum = heap_getattr(tuple, -+ Anum_pg_seclabel_label, -+ RelationGetDescr(rel), &isnull); -+ if (!isnull) -+ result = TextDatumGetCString(datum); -+ } -+ systable_endscan(scan); -+ -+ heap_close(rel, AccessShareLock); -+ -+ return result; -+} -+ -+Oid -+seclabelRawInput(Oid relid, char *seclabel) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ seclabel = sepgsql_rawlabel_in(seclabel); -+#endif -+ return inputSecurityLabel(relid, seclabel); -+} -+ -+char * -+seclabelRawOutput(Oid relid, Oid secid) -+{ -+ char *seclabel = outputSecurityLabel(relid, secid); -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ seclabel = sepgsql_rawlabel_out(seclabel); -+#endif -+ return seclabel; -+} -+ -+Oid -+seclabelTransInput(Oid relid, char *seclabel) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ seclabel = sepgsql_mcstrans_in(seclabel); -+#endif -+ return seclabelRawInput(relid, seclabel); -+} -+ -+char * -+seclabelTransOutput(Oid relid, Oid secid) -+{ -+ char *seclabel = seclabelRawOutput(relid, secid); -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ seclabel = sepgsql_mcstrans_out(seclabel); -+#endif -+ return seclabel; -+} -+ -+Oid -+seclabelMoveSecid(Oid dst_relid, Oid src_relid, Oid secid) -+{ -+ char *label = seclabelRawOutput(src_relid, secid); -+ -+ if (!label) -+ return InvalidOid; -+ -+ secid = seclabelRawInput(dst_relid, label); -+ -+ pfree(label); -+ -+ return secid; -+} -+ -+bool -+seclabelCompareSecid(Oid relid1, Oid secid1, Oid relid2, Oid secid2) -+{ -+ char *label1 = seclabelRawOutput(relid1, secid1); -+ char *label2 = seclabelRawOutput(relid2, secid2); -+ bool retval = false; -+ -+ if (label1 && label2 && strcmp(label1, label2) == 0) -+ retval = true; -+ else if (!label1 && !label2) -+ retval = false; -+ -+ if (label1) -+ pfree(label1); -+ if (label2) -+ pfree(label2); -+ -+ return retval; -+} -+ -+Datum -+seclabelSysattOutput(Oid relid, HeapTuple tuple) -+{ -+ Oid secid; -+ char *seclabel; -+ -+ secid = HeapTupleGetSecid(tuple); -+ -+ seclabel = seclabelTransOutput(relid, secid); -+ if (!seclabel) -+ seclabel = "unlabeled"; -+ -+ return CStringGetTextDatum(seclabel); -+} -+ -+/* -+ * seclabelRelationReclaim -+ * -+ * It reclaims security labels already referenced to. -+ * It has to be called under the VACUUM FULL context that means the relation -+ * to be reclaimed is already locked exclusively. -+ */ -+void -+seclabelRelationReclaim(Oid relOid) -+{ -+ StringInfoData query; -+ const char *nspname_reclaimed; -+ const char *relname_reclaimed; -+ const char *nspname_pg_seclabel; -+ const char *relname_pg_seclabel; -+ const char *attname_secid; -+ const char *attname_datid; -+ const char *attname_relid; -+ const char *attname_label; -+ const char *nspname_to_secid; -+ const char *proname_to_secid; -+ Oid databaseId; -+ Oid namespaceId; -+ int index; -+ int save_sepgsql_mode; -+ -+ if (SPI_connect() != SPI_OK_CONNECT) -+ elog(ERROR, "SPI_connect() failed"); -+ -+ /* -+ * DELETE orphan entries -+ */ -+ databaseId = (IsSharedRelation(relOid) ? InvalidOid : MyDatabaseId); -+ -+ namespaceId = get_rel_namespace(relOid); -+ nspname_reclaimed = get_namespace_name(namespaceId); -+ relname_reclaimed = get_rel_name(relOid); -+ -+ namespaceId = get_rel_namespace(SecLabelRelationId); -+ nspname_pg_seclabel = get_namespace_name(namespaceId); -+ relname_pg_seclabel = get_rel_name(SecLabelRelationId); -+ -+ attname_secid = get_attname(SecLabelRelationId, Anum_pg_seclabel_secid); -+ attname_datid = get_attname(SecLabelRelationId, Anum_pg_seclabel_datid); -+ attname_relid = get_attname(SecLabelRelationId, Anum_pg_seclabel_relid); -+ attname_label = get_attname(SecLabelRelationId, Anum_pg_seclabel_label); -+ -+ namespaceId = get_func_namespace(F_SECLABEL_TO_SECID); -+ nspname_to_secid = get_namespace_name(namespaceId); -+ proname_to_secid = get_func_name(F_SECLABEL_TO_SECID); -+ -+ initStringInfo(&query); -+ appendStringInfo(&query, -+ "DELETE FROM %s.%s " -+ "WHERE %s = %u AND %s = %u AND %s NOT IN " -+ "(SELECT %s.%s(%s) FROM ONLY %s.%s) " -+ "RETURNING %s,%s", -+ quote_identifier(nspname_pg_seclabel), -+ quote_identifier(relname_pg_seclabel), -+ quote_identifier(attname_datid), -+ databaseId, -+ quote_identifier(attname_relid), -+ relOid, -+ quote_identifier(attname_secid), -+ quote_identifier(nspname_to_secid), -+ quote_identifier(proname_to_secid), -+ quote_identifier(relname_reclaimed), -+ quote_identifier(nspname_reclaimed), -+ quote_identifier(relname_reclaimed), -+ quote_identifier(attname_secid), -+ quote_identifier(attname_label)); -+ /* -+ * Run the query -+ */ -+ elog(DEBUG1, "query: %s", query.data); -+ -+ save_sepgsql_mode = sepostgresql_mode; -+ -+ PG_TRY(); -+ { -+ sepostgresql_mode = SEPGSQL_MODE_INTERNAL; -+ -+ if (SPI_execute(query.data, false, 0) != SPI_OK_DELETE_RETURNING) -+ elog(ERROR, "Failed to run: %s", query.data); -+ } -+ PG_CATCH(); -+ { -+ sepostgresql_mode = save_sepgsql_mode; -+ -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ -+ sepostgresql_mode = save_sepgsql_mode; -+ -+ for (index = 0; index < SPI_processed; index++) -+ { -+ HeapTuple tuple = SPI_tuptable->vals[index]; -+ char *label; -+ Oid secid; -+ Datum datum; -+ bool isnull; -+ -+ datum = heap_getattr(tuple, 1, SPI_tuptable->tupdesc, &isnull); -+ secid = (isnull ? InvalidOid : DatumGetObjectId(datum)); -+ -+ datum = heap_getattr(tuple, 2, SPI_tuptable->tupdesc, &isnull); -+ label = (isnull ? NULL : TextDatumGetCString(datum)); -+ -+ elog(DEBUG1, "seclabel: \"%s\"was reclaimed (secid=%u)", -+ label, secid); -+ } -+ -+ if (SPI_finish() != SPI_OK_FINISH) -+ elog(ERROR, "SPI_finish() failed"); -+} -+ -+Datum -+seclabel_to_secid(PG_FUNCTION_ARGS) -+{ -+ HeapTupleHeader htup = PG_GETARG_HEAPTUPLEHEADER(0); -+ -+ PG_RETURN_OID(HeapTupleHeaderGetSecid(htup)); -+} -diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c -index d4fdea9..a1220ea 100644 ---- a/src/backend/catalog/pg_type.c -+++ b/src/backend/catalog/pg_type.c -@@ -25,6 +25,7 @@ - #include "commands/typecmds.h" - #include "miscadmin.h" - #include "parser/scansup.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -@@ -57,10 +58,17 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) - Datum values[Natts_pg_type]; - bool nulls[Natts_pg_type]; - Oid typoid; -+ Oid secid; - NameData name; - - Assert(PointerIsValid(typeName)); - -+ /* SELinux checks */ -+ secid = sepgsql_type_create(typeName, InvalidOid, -+ typeNamespace, TYPTYPE_PSEUDO, -+ F_SHELL_IN, F_SHELL_OUT, -+ InvalidOid, InvalidOid, -+ InvalidOid, InvalidOid, InvalidOid); - /* - * open pg_type - */ -@@ -126,6 +134,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) - binary_upgrade_next_pg_type_oid = InvalidOid; - } - -+ HeapTupleSetSecid(tup, secid); -+ - /* - * insert the tuple in the relation and get the tuple's oid. - */ -@@ -204,7 +214,8 @@ TypeCreate(Oid newTypeOid, - char storage, - int32 typeMod, - int32 typNDims, /* Array dimensions for baseType */ -- bool typeNotNull) -+ bool typeNotNull, -+ Oid securityId) - { - Relation pg_type_desc; - Oid typeObjectId; -@@ -389,6 +400,8 @@ TypeCreate(Oid newTypeOid, - */ - if (((Form_pg_type) GETSTRUCT(tup))->typowner != ownerId) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName); -+ if (HeapTupleGetSecid(tup) != securityId) -+ elog(ERROR, "Bug? security-id was mismatched"); - - /* trouble if caller wanted to force the OID */ - if (OidIsValid(newTypeOid)) -@@ -425,6 +438,8 @@ TypeCreate(Oid newTypeOid, - } - /* else allow system to assign oid */ - -+ HeapTupleSetSecid(tup, securityId); -+ - typeObjectId = simple_heap_insert(pg_type_desc, tup); - } - -diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c -index 86e7daa..82cf587 100644 ---- a/src/backend/catalog/toasting.c -+++ b/src/backend/catalog/toasting.c -@@ -24,6 +24,7 @@ - #include "catalog/namespace.h" - #include "catalog/pg_namespace.h" - #include "catalog/pg_opclass.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/pg_type.h" - #include "catalog/toasting.h" - #include "miscadmin.h" -@@ -127,6 +128,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio - int16 coloptions[2]; - ObjectAddress baseobject, - toastobject; -+ Oid *secLabels; - - /* - * Toast table is shared if and only if its parent is. -@@ -168,7 +170,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio - "pg_toast_%u_index", relOid); - - /* this is pretty painful... need a tuple descriptor */ -- tupdesc = CreateTemplateTupleDesc(3, false); -+ tupdesc = CreateTemplateTupleDesc(3, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, - "chunk_id", - OIDOID, -@@ -206,6 +208,11 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio - binary_upgrade_next_pg_type_toast_oid = InvalidOid; - } - -+ /* -+ * Toast inherits security-id from the heap relation -+ */ -+ secLabels = seclabelMakeToastDefaults(tupdesc, relOid); -+ - toast_relid = heap_create_with_catalog(toast_relname, - namespaceid, - rel->rd_rel->reltablespace, -@@ -223,7 +230,8 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio - ONCOMMIT_NOOP, - reloptions, - false, -- true); -+ true, -+ secLabels); - - /* make the toast relation visible, else index creation will fail */ - CommandCounterIncrement(); -diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c -index 2c6ce59..312d59f 100644 ---- a/src/backend/commands/aggregatecmds.c -+++ b/src/backend/commands/aggregatecmds.c -@@ -32,6 +32,7 @@ - #include "miscadmin.h" - #include "parser/parse_func.h" - #include "parser/parse_type.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -@@ -307,6 +308,9 @@ RenameAggregate(List *name, List *args, const char *newname) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux checks */ -+ sepgsql_proc_alter_rename(procOid, newname); -+ - /* rename */ - namestrcpy(&(((Form_pg_proc) GETSTRUCT(tup))->proname), newname); - simple_heap_update(rel, &tup->t_self, tup); -diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c -index cecdfa5..5b51f68 100644 ---- a/src/backend/commands/alter.c -+++ b/src/backend/commands/alter.c -@@ -290,3 +290,64 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt) - (int) stmt->objectType); - } - } -+ -+/* -+ * ExecAlterSecLabelStmt -+ * -+ * Execute ALTER xxx SECURITY LABEL TO statement -+ */ -+void -+ExecAlterSecLabelStmt(AlterSecLabelStmt *stmt) -+{ -+ const char *name; -+ char *seclabel; -+ -+ Assert(IsA(stmt->secLabel, String)); -+ seclabel = strVal(stmt->secLabel); -+ -+ switch (stmt->objectType) -+ { -+ case OBJECT_DATABASE: -+ name = strVal(linitial(stmt->object)); -+ AlterDatabaseSecLabel(name, seclabel); -+ break; -+ -+ case OBJECT_SCHEMA: -+ name = strVal(linitial(stmt->object)); -+ AlterSchemaSecLabel(name, seclabel); -+ break; -+ -+ case OBJECT_TABLE: -+ case OBJECT_SEQUENCE: -+ case OBJECT_VIEW: -+ case OBJECT_COLUMN: -+ AlterRelationSecLabel(stmt->relation, stmt->addname, -+ stmt->objectType, seclabel); -+ break; -+ -+ case OBJECT_AGGREGATE: -+ AlterFunctionSecLabel(stmt->object, stmt->objarg, true, seclabel); -+ break; -+ -+ case OBJECT_FUNCTION: -+ AlterFunctionSecLabel(stmt->object, stmt->objarg, false, seclabel); -+ break; -+ -+ case OBJECT_LARGEOBJECT: -+ LargeObjectAlterSecLabel(intVal(linitial(stmt->object)), seclabel); -+ break; -+ -+ case OBJECT_TYPE: -+ case OBJECT_DOMAIN: -+ AlterTypeSecLabel(stmt->object, seclabel); -+ break; -+ -+ case OBJECT_TABLESPACE: -+ AlterTableSpaceSecLabel(strVal(linitial(stmt->object)), seclabel); -+ break; -+ -+ default: -+ elog(ERROR, "unrecognized AlterSecLabelStmt type: %d", -+ (int) stmt->objectType); -+ } -+} -diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c -index 61020dc..f8408b4 100644 ---- a/src/backend/commands/cluster.c -+++ b/src/backend/commands/cluster.c -@@ -30,12 +30,14 @@ - #include "catalog/indexing.h" - #include "catalog/namespace.h" - #include "catalog/pg_namespace.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/toasting.h" - #include "commands/cluster.h" - #include "commands/tablecmds.h" - #include "commands/trigger.h" - #include "commands/vacuum.h" - #include "miscadmin.h" -+#include "sepgsql/hooks.h" - #include "storage/bufmgr.h" - #include "storage/procarray.h" - #include "storage/smgr.h" -@@ -116,6 +118,9 @@ cluster(ClusterStmt *stmt, bool isTopLevel) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(rel)); - -+ /* SELinux checks */ -+ sepgsql_relation_cluster(tableOid, true); -+ - /* - * Reject clustering a remote temp table ... their local buffer - * manager is not going to cope. -@@ -290,7 +295,8 @@ cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose, - Form_pg_index indexForm; - - /* Check that the user still owns the relation */ -- if (!pg_class_ownercheck(tableOid, GetUserId())) -+ if (!pg_class_ownercheck(tableOid, GetUserId()) || -+ !sepgsql_relation_cluster(tableOid, false)) - { - relation_close(OldHeap, AccessExclusiveLock); - return; -@@ -632,6 +638,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace) - HeapTuple tuple; - Datum reloptions; - bool isNull; -+ Oid *secLabels; - - OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock); - OldHeapDesc = RelationGetDescr(OldHeap); -@@ -657,6 +664,11 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace) - reloptions = (Datum) 0; - - /* -+ * The new heap copies all the security-id from the original -+ */ -+ secLabels = seclabelMakeRelationDefaults(tupdesc, -+ list_make1_oid(OIDOldHeap)); -+ /* - * Create the new heap, using a temporary name in the same namespace as - * the existing table. NOTE: there is some risk of collision with user - * relnames. Working around this seems more trouble than it's worth; in -@@ -687,7 +699,8 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace) - ONCOMMIT_NOOP, - reloptions, - false, -- true); -+ true, -+ secLabels); - - ReleaseSysCache(tuple); - -@@ -977,6 +990,9 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, - /* Preserve OID, if any */ - if (NewHeap->rd_rel->relhasoids) - HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple)); -+ /* Preserve security-id, if any */ -+ if (NewHeap->rd_rel->relhassecids) -+ HeapTupleSetSecid(copiedTuple, HeapTupleGetSecid(tuple)); - - /* The heap rewrite module does the rest */ - rewrite_heap_tuple(rwstate, tuple, copiedTuple); -@@ -1469,7 +1485,8 @@ get_tables_to_cluster(MemoryContext cluster_context) - { - index = (Form_pg_index) GETSTRUCT(indexTuple); - -- if (!pg_class_ownercheck(index->indrelid, GetUserId())) -+ if (!pg_class_ownercheck(index->indrelid, GetUserId()) || -+ !sepgsql_relation_cluster(index->indrelid, false)) - continue; - - /* -diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c -index 7fa09c8..2deb171 100644 ---- a/src/backend/commands/comment.c -+++ b/src/backend/commands/comment.c -@@ -49,6 +49,7 @@ - #include "parser/parse_func.h" - #include "parser/parse_oper.h" - #include "parser/parse_type.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -@@ -548,6 +549,9 @@ CommentRelation(int objtype, List *relname, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(relation)); - -+ /* SELinux checks */ -+ sepgsql_relation_comment(RelationGetRelid(relation)); -+ - /* Next, verify that the relation type matches the intent */ - - switch (objtype) -@@ -651,6 +655,9 @@ CommentAttribute(List *qualname, char *comment) - errmsg("column \"%s\" of relation \"%s\" does not exist", - attrname, RelationGetRelationName(relation)))); - -+ /* SELinux checks */ -+ sepgsql_attribute_comment(RelationGetRelid(relation), attnum); -+ - /* Create the comment using the relation's oid */ - CreateComments(RelationGetRelid(relation), RelationRelationId, - (int32) attnum, comment); -@@ -704,6 +711,9 @@ CommentDatabase(List *qualname, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - database); - -+ /* SELinux checks */ -+ sepgsql_database_comment(oid); -+ - /* Call CreateSharedComments() to create/drop the comments */ - CreateSharedComments(oid, DatabaseRelationId, comment); - } -@@ -742,6 +752,9 @@ CommentTablespace(List *qualname, char *comment) - if (!pg_tablespace_ownercheck(oid, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, tablespace); - -+ /* SELinux checks */ -+ sepgsql_tablespace_comment(oid); -+ - /* Call CreateSharedComments() to create/drop the comments */ - CreateSharedComments(oid, TableSpaceRelationId, comment); - } -@@ -774,6 +787,9 @@ CommentRole(List *qualname, char *comment) - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be member of role \"%s\" to comment upon it", role))); - -+ /* SELinux checks */ -+ sepgsql_role_comment(oid); -+ - /* Call CreateSharedComments() to create/drop the comments */ - CreateSharedComments(oid, AuthIdRelationId, comment); - } -@@ -810,6 +826,9 @@ CommentNamespace(List *qualname, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, - namespace); - -+ /* SELinux checks */ -+ sepgsql_schema_comment(oid); -+ - /* Call CreateComments() to create/drop the comments */ - CreateComments(oid, NamespaceRelationId, 0, comment); - } -@@ -919,6 +938,9 @@ CommentRule(List *qualname, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - get_rel_name(reloid)); - -+ /* SELinux checks */ -+ sepgsql_rule_comment(reloid, rulename); -+ - /* Call CreateComments() to create/drop the comments */ - CreateComments(ruleoid, RewriteRelationId, 0, comment); - -@@ -953,6 +975,9 @@ CommentType(List *typename, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, - format_type_be(oid)); - -+ /* SELinux checks */ -+ sepgsql_type_comment(oid); -+ - /* Call CreateComments() to create/drop the comments */ - CreateComments(oid, TypeRelationId, 0, comment); - } -@@ -977,6 +1002,9 @@ CommentAggregate(List *aggregate, List *arguments, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - NameListToString(aggregate)); - -+ /* SELinux checks */ -+ sepgsql_proc_comment(oid); -+ - /* Call CreateComments() to create/drop the comments */ - CreateComments(oid, ProcedureRelationId, 0, comment); - } -@@ -1005,6 +1033,9 @@ CommentProc(List *function, List *arguments, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - NameListToString(function)); - -+ /* SELinux checks */ -+ sepgsql_proc_comment(oid); -+ - /* Call CreateComments() to create/drop the comments */ - CreateComments(oid, ProcedureRelationId, 0, comment); - } -@@ -1036,6 +1067,9 @@ CommentOperator(List *opername, List *arguments, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER, - NameListToString(opername)); - -+ /* SELinux checks */ -+ sepgsql_operator_comment(oid); -+ - /* Call CreateComments() to create/drop the comments */ - CreateComments(oid, OperatorRelationId, 0, comment); - } -@@ -1080,6 +1114,9 @@ CommentTrigger(List *qualname, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(relation)); - -+ /* SELinux checks */ -+ sepgsql_trigger_comment(RelationGetRelid(relation), trigname); -+ - /* - * Fetch the trigger tuple from pg_trigger. There can be only one because - * of the unique index. -@@ -1153,6 +1190,9 @@ CommentConstraint(List *qualname, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(relation)); - -+ /* SELinux checks */ -+ sepgsql_constraint_comment(RelationGetRelid(relation), conName); -+ - conOid = GetConstraintByName(RelationGetRelid(relation), conName); - - /* Call CreateComments() to create/drop the comments */ -@@ -1188,6 +1228,9 @@ CommentConversion(List *qualname, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, - NameListToString(qualname)); - -+ /* SELinux checks */ -+ sepgsql_conversion_comment(conversionOid); -+ - /* Call CreateComments() to create/drop the comments */ - CreateComments(conversionOid, ConversionRelationId, 0, comment); - } -@@ -1304,6 +1347,9 @@ CommentOpClass(List *qualname, List *arguments, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, - NameListToString(qualname)); - -+ /* SELinux checks */ -+ sepgsql_opclass_comment(opcID); -+ - ReleaseSysCache(tuple); - - /* Call CreateComments() to create/drop the comments */ -@@ -1385,6 +1431,9 @@ CommentOpFamily(List *qualname, List *arguments, char *comment) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY, - NameListToString(qualname)); - -+ /* SELinux checks */ -+ sepgsql_opfamily_comment(opfID); -+ - ReleaseSysCache(tuple); - - /* Call CreateComments() to create/drop the comments */ -@@ -1482,6 +1531,9 @@ CommentCast(List *qualname, List *arguments, char *comment) - format_type_be(sourcetypeid), - format_type_be(targettypeid)))); - -+ /* SELinux checks */ -+ sepgsql_cast_comment(sourcetypeid, targettypeid); -+ - ReleaseSysCache(tuple); - - /* Call CreateComments() to create/drop the comments */ -@@ -1499,6 +1551,8 @@ CommentTSParser(List *qualname, char *comment) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to comment on text search parser"))); -+ /* SELinux checks */ -+ sepgsql_ts_parser_comment(prsId); - - CreateComments(prsId, TSParserRelationId, 0, comment); - } -@@ -1513,6 +1567,8 @@ CommentTSDictionary(List *qualname, char *comment) - if (!pg_ts_dict_ownercheck(dictId, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY, - NameListToString(qualname)); -+ /* SELinux checks */ -+ sepgsql_ts_dict_comment(dictId); - - CreateComments(dictId, TSDictionaryRelationId, 0, comment); - } -@@ -1528,6 +1584,8 @@ CommentTSTemplate(List *qualname, char *comment) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to comment on text search template"))); -+ /* SELinux checks */ -+ sepgsql_ts_template_comment(tmplId); - - CreateComments(tmplId, TSTemplateRelationId, 0, comment); - } -@@ -1542,6 +1600,8 @@ CommentTSConfiguration(List *qualname, char *comment) - if (!pg_ts_config_ownercheck(cfgId, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, - NameListToString(qualname)); -+ /* SELinux checks */ -+ sepgsql_ts_config_comment(cfgId); - - CreateComments(cfgId, TSConfigRelationId, 0, comment); - } -diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c -index 2e5a7df..9647622 100644 ---- a/src/backend/commands/conversioncmds.c -+++ b/src/backend/commands/conversioncmds.c -@@ -24,6 +24,7 @@ - #include "mb/pg_wchar.h" - #include "miscadmin.h" - #include "parser/parse_func.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -@@ -45,6 +46,7 @@ CreateConversionCommand(CreateConversionStmt *stmt) - int from_encoding; - int to_encoding; - Oid funcoid; -+ Oid secid; - const char *from_encoding_name = stmt->for_encoding_name; - const char *to_encoding_name = stmt->to_encoding_name; - List *func_name = stmt->func_name; -@@ -96,6 +98,10 @@ CreateConversionCommand(CreateConversionStmt *stmt) - aclcheck_error(aclresult, ACL_KIND_PROC, - NameListToString(func_name)); - -+ /* SELinux checks */ -+ secid = sepgsql_conversion_create(conversion_name, -+ namespaceId, funcoid); -+ - /* - * Check that the conversion function is suitable for the requested source - * and target encodings. We do that by calling the function with an empty -@@ -114,7 +120,7 @@ CreateConversionCommand(CreateConversionStmt *stmt) - * name) - */ - ConversionCreate(conversion_name, namespaceId, GetUserId(), -- from_encoding, to_encoding, funcoid, stmt->def); -+ from_encoding, to_encoding, funcoid, stmt->def, secid); - } - - /* -@@ -174,6 +180,9 @@ DropConversionsCommand(DropStmt *drop) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, - NameStr(con->conname)); - -+ /* SELinux checks */ -+ sepgsql_conversion_drop(conversionOid, false); -+ - object.classId = ConversionRelationId; - object.objectId = conversionOid; - object.objectSubId = 0; -@@ -235,6 +244,9 @@ RenameConversion(List *name, const char *newname) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux checks */ -+ sepgsql_conversion_alter_rename(conversionOid, newname); -+ - /* rename */ - namestrcpy(&(((Form_pg_conversion) GETSTRUCT(tup))->conname), newname); - simple_heap_update(rel, &tup->t_self, tup); -@@ -329,6 +341,8 @@ AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(convForm->connamespace)); - } -+ /* SELinux checks */ -+ sepgsql_conversion_alter(HeapTupleGetOid(tup)); - - /* - * Modify the owner --- okay to scribble on tup because it's a copy -diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c -index a6e1d35..50921ec 100644 ---- a/src/backend/commands/copy.c -+++ b/src/backend/commands/copy.c -@@ -22,7 +22,10 @@ - - #include "access/heapam.h" - #include "access/xact.h" -+#include "access/sysattr.h" -+#include "catalog/heap.h" - #include "catalog/namespace.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/pg_type.h" - #include "commands/copy.h" - #include "commands/defrem.h" -@@ -35,6 +38,7 @@ - #include "optimizer/planner.h" - #include "parser/parse_relation.h" - #include "rewrite/rewriteHandler.h" -+#include "sepgsql/hooks.h" - #include "storage/fd.h" - #include "tcop/tcopprot.h" - #include "utils/acl.h" -@@ -161,6 +165,12 @@ typedef struct CopyStateData - char *raw_buf; - int raw_buf_index; /* next byte to process */ - int raw_buf_len; /* total # of bytes stored */ -+ -+ /* -+ * Dump/Restore support for security_label -+ */ -+ FmgrInfo seclabel_out_function; -+ bool seclabel_force_quot; - } CopyStateData; - - typedef CopyStateData *CopyState; -@@ -244,7 +254,7 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0"; - /* non-export function prototypes */ - static void DoCopyTo(CopyState cstate); - static void CopyTo(CopyState cstate); --static void CopyOneRowTo(CopyState cstate, Oid tupleOid, -+static void CopyOneRowTo(CopyState cstate, HeapTuple tuple, - Datum *values, bool *nulls); - static void CopyFrom(CopyState cstate); - static bool CopyReadLine(CopyState cstate); -@@ -986,8 +996,21 @@ DoCopy(const CopyStmt *stmt, const char *queryString) - errhint("Anyone can COPY to stdout or from stdin. " - "psql's \\copy command also works for anyone."))); - -+ /* SELinux checks on file COPY */ -+ if (stmt->filename) -+ { -+ if (is_from) -+ sepgsql_file_read(stmt->filename); -+ else -+ sepgsql_file_write(stmt->filename, true); -+ } -+ - if (stmt->relation) - { -+ Bitmapset *columnsSet = NULL; -+ List *attnums; -+ ListCell *cur; -+ - Assert(!stmt->query); - cstate->queryDesc = NULL; - -@@ -998,16 +1021,20 @@ DoCopy(const CopyStmt *stmt, const char *queryString) - tupDesc = RelationGetDescr(cstate->rel); - - /* Check relation permissions. */ -+ attnums = CopyGetAttnums(tupDesc, cstate->rel, attnamelist); -+ foreach(cur, attnums) -+ { -+ int index = lfirst_int(cur) -+ - FirstLowInvalidHeapAttributeNumber; -+ columnsSet = bms_add_member(columnsSet, index); -+ } -+ - relPerms = pg_class_aclmask(RelationGetRelid(cstate->rel), GetUserId(), - required_access, ACLMASK_ALL); - remainingPerms = required_access & ~relPerms; - if (remainingPerms != 0) - { - /* We don't have table permissions, check per-column permissions */ -- List *attnums; -- ListCell *cur; -- -- attnums = CopyGetAttnums(tupDesc, cstate->rel, attnamelist); - foreach(cur, attnums) - { - int attnum = lfirst_int(cur); -@@ -1021,6 +1048,13 @@ DoCopy(const CopyStmt *stmt, const char *queryString) - } - } - -+ if (is_from) -+ sepgsql_relation_perms(RelationGetRelid(cstate->rel), -+ ACL_INSERT, NULL, columnsSet, true); -+ else -+ sepgsql_relation_perms(RelationGetRelid(cstate->rel), -+ ACL_SELECT, columnsSet, NULL, true); -+ - /* check read-only transaction */ - if (XactReadOnly && is_from && !cstate->rel->rd_islocaltemp) - PreventCommandIfReadOnly("COPY FROM"); -@@ -1130,11 +1164,24 @@ DoCopy(const CopyStmt *stmt, const char *queryString) - int attnum = lfirst_int(cur); - - if (!list_member_int(cstate->attnumlist, attnum)) -+ { -+ Form_pg_attribute attForm; -+ -+ if (attnum > 0) -+ attForm = tupDesc->attrs[attnum - 1]; -+ else -+ attForm = SystemAttributeDefinition(attnum, true, true); -+ - ereport(ERROR, - (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), - errmsg("FORCE QUOTE column \"%s\" not referenced by COPY", -- NameStr(tupDesc->attrs[attnum - 1]->attname)))); -- cstate->force_quote_flags[attnum - 1] = true; -+ NameStr(attForm->attname)))); -+ } -+ -+ if (attnum == SecurityLabelAttributeNumber) -+ cstate->seclabel_force_quot = true; -+ else -+ cstate->force_quote_flags[attnum - 1] = true; - } - } - -@@ -1152,10 +1199,24 @@ DoCopy(const CopyStmt *stmt, const char *queryString) - int attnum = lfirst_int(cur); - - if (!list_member_int(cstate->attnumlist, attnum)) -+ { -+ Form_pg_attribute attForm; -+ -+ if (attnum > 0) -+ attForm = tupDesc->attrs[attnum - 1]; -+ else -+ attForm = SystemAttributeDefinition(attnum, -+ tupDesc->tdhasoid, -+ tupDesc->tdhassecid); -+ - ereport(ERROR, - (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), - errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY", -- NameStr(tupDesc->attrs[attnum - 1]->attname)))); -+ NameStr(attForm->attname)))); -+ } -+ /* ignore system columns, if specified */ -+ if (attnum <= 0) -+ continue; - cstate->force_notnull_flags[attnum - 1] = true; - } - } -@@ -1347,16 +1408,29 @@ CopyTo(CopyState cstate) - int attnum = lfirst_int(cur); - Oid out_func_oid; - bool isvarlena; -+ FmgrInfo *out_fmgr; -+ Form_pg_attribute attForm; -+ -+ if (attnum == SecurityLabelAttributeNumber) -+ { -+ attForm = SystemAttributeDefinition(attnum, true, true); -+ out_fmgr = &cstate->seclabel_out_function; -+ } -+ else -+ { -+ attForm = attr[attnum - 1]; -+ out_fmgr = &cstate->out_functions[attnum - 1]; -+ } - - if (cstate->binary) -- getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid, -+ getTypeBinaryOutputInfo(attForm->atttypid, - &out_func_oid, - &isvarlena); - else -- getTypeOutputInfo(attr[attnum - 1]->atttypid, -+ getTypeOutputInfo(attForm->atttypid, - &out_func_oid, - &isvarlena); -- fmgr_info(out_func_oid, &cstate->out_functions[attnum - 1]); -+ fmgr_info(out_func_oid, out_fmgr); - } - - /* -@@ -1411,7 +1485,17 @@ CopyTo(CopyState cstate) - CopySendChar(cstate, cstate->delim[0]); - hdr_delim = true; - -- colname = NameStr(attr[attnum - 1]->attname); -+ if (SystemAttributeWritable(attnum, -+ tupDesc->tdhasoid, -+ tupDesc->tdhassecid)) -+ { -+ Form_pg_attribute attForm -+ = SystemAttributeDefinition(attnum, true, true); -+ -+ colname = NameStr(attForm->attname); -+ } -+ else -+ colname = NameStr(attr[attnum - 1]->attname); - - CopyAttributeOutCSV(cstate, colname, false, - list_length(cstate->attnumlist) == 1); -@@ -1437,11 +1521,15 @@ CopyTo(CopyState cstate) - { - CHECK_FOR_INTERRUPTS(); - -+ /* Row-level access control policy */ -+ if (!sepgsql_rowlv_copyto(cstate->rel, tuple)) -+ continue; -+ - /* Deconstruct the tuple ... faster than repeated heap_getattr */ - heap_deform_tuple(tuple, tupDesc, values, nulls); - - /* Format and send the data */ -- CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls); -+ CopyOneRowTo(cstate, tuple, values, nulls); - } - - heap_endscan(scandesc); -@@ -1467,13 +1555,17 @@ CopyTo(CopyState cstate) - * Emit one row during CopyTo(). - */ - static void --CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) -+CopyOneRowTo(CopyState cstate, HeapTuple tuple, Datum *values, bool *nulls) - { - bool need_delim = false; - FmgrInfo *out_functions = cstate->out_functions; - MemoryContext oldcontext; - ListCell *cur; - char *string; -+ Oid tupleOid = InvalidOid; -+ -+ if (HeapTupleIsValid(tuple)) -+ tupleOid = HeapTupleGetOid(tuple); - - MemoryContextReset(cstate->rowcontext); - oldcontext = MemoryContextSwitchTo(cstate->rowcontext); -@@ -1506,8 +1598,10 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) - foreach(cur, cstate->attnumlist) - { - int attnum = lfirst_int(cur); -- Datum value = values[attnum - 1]; -- bool isnull = nulls[attnum - 1]; -+ Datum value; -+ bool isnull; -+ bool force_quot; -+ FmgrInfo *out_fmgr; - - if (!cstate->binary) - { -@@ -1516,6 +1610,21 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) - need_delim = true; - } - -+ if (attnum == SecurityLabelAttributeNumber) -+ { -+ value = seclabelSysattOutput(RelationGetRelid(cstate->rel), tuple); -+ isnull = false; -+ force_quot = cstate->seclabel_force_quot; -+ out_fmgr = &cstate->seclabel_out_function; -+ } -+ else -+ { -+ value = values[attnum - 1]; -+ isnull = nulls[attnum - 1]; -+ force_quot = cstate->force_quote_flags[attnum - 1]; -+ out_fmgr = &out_functions[attnum - 1]; -+ } -+ - if (isnull) - { - if (!cstate->binary) -@@ -1527,11 +1636,9 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) - { - if (!cstate->binary) - { -- string = OutputFunctionCall(&out_functions[attnum - 1], -- value); -+ string = OutputFunctionCall(out_fmgr, value); - if (cstate->csv_mode) -- CopyAttributeOutCSV(cstate, string, -- cstate->force_quote_flags[attnum - 1], -+ CopyAttributeOutCSV(cstate, string, force_quot, - list_length(cstate->attnumlist) == 1); - else - CopyAttributeOutText(cstate, string); -@@ -1540,8 +1647,7 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) - { - bytea *outputbytes; - -- outputbytes = SendFunctionCall(&out_functions[attnum - 1], -- value); -+ outputbytes = SendFunctionCall(out_fmgr, value); - CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ); - CopySendData(cstate, VARDATA(outputbytes), - VARSIZE(outputbytes) - VARHDRSZ); -@@ -1675,8 +1781,10 @@ CopyFrom(CopyState cstate) - num_defaults; - FmgrInfo *in_functions; - FmgrInfo oid_in_function; -+ FmgrInfo seclabel_in_function; - Oid *typioparams; - Oid oid_typioparam; -+ Oid seclabel_typioparam; - int attnum; - int i; - Oid in_func_oid; -@@ -1919,6 +2027,19 @@ CopyFrom(CopyState cstate) - fmgr_info(in_func_oid, &oid_in_function); - } - -+ if (list_member_int(cstate->attnumlist, SecurityLabelAttributeNumber)) -+ { -+ if (!cstate->binary) -+ getTypeInputInfo(TEXTOID, &in_func_oid, &seclabel_typioparam); -+ else -+ getTypeBinaryInputInfo(TEXTOID, &in_func_oid, &seclabel_typioparam); -+ -+ fmgr_info(in_func_oid, &seclabel_in_function); -+ } -+ -+ -+ -+ - values = (Datum *) palloc(num_phys_attrs * sizeof(Datum)); - nulls = (bool *) palloc(num_phys_attrs * sizeof(bool)); - -@@ -1953,6 +2074,7 @@ CopyFrom(CopyState cstate) - { - bool skip_tuple; - Oid loaded_oid = InvalidOid; -+ Oid loaded_secid = InvalidOid; - - CHECK_FOR_INTERRUPTS(); - -@@ -2024,14 +2146,20 @@ CopyFrom(CopyState cstate) - /* Loop to read the user attributes on the line. */ - foreach(cur, cstate->attnumlist) - { -+ Form_pg_attribute attForm; - int attnum = lfirst_int(cur); - int m = attnum - 1; - -+ if (attnum == SecurityLabelAttributeNumber) -+ attForm = SystemAttributeDefinition(attnum, true, true); -+ else -+ attForm = attr[m]; -+ - if (fieldno >= fldct) - ereport(ERROR, - (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), - errmsg("missing data for column \"%s\"", -- NameStr(attr[m]->attname)))); -+ NameStr(attForm->attname)))); - string = field_strings[fieldno++]; - - if (cstate->csv_mode && string == NULL && -@@ -2041,14 +2169,38 @@ CopyFrom(CopyState cstate) - string = cstate->null_print; - } - -- cstate->cur_attname = NameStr(attr[m]->attname); -+ cstate->cur_attname = NameStr(attForm->attname); - cstate->cur_attval = string; -- values[m] = InputFunctionCall(&in_functions[m], -- string, -- typioparams[m], -- attr[m]->atttypmod); -- if (string != NULL) -- nulls[m] = false; -+ -+ if (attnum == SecurityLabelAttributeNumber) -+ { -+ if (string && !ignore_security_label_input) -+ { -+ Datum datum = InputFunctionCall(&seclabel_in_function, -+ string, -+ seclabel_typioparam, -+ attForm->atttypmod); -+ loaded_secid -+ = seclabelTransInput(RelationGetRelid(cstate->rel), -+ TextDatumGetCString(datum)); -+ } -+ } -+ else -+ { -+ if (cstate->csv_mode && string == NULL && -+ cstate->force_notnull_flags[m]) -+ { -+ /* Go ahead and read the NULL string */ -+ string = cstate->null_print; -+ } -+ -+ values[m] = InputFunctionCall(&in_functions[m], -+ string, -+ typioparams[m], -+ attForm->atttypmod); -+ if (string != NULL) -+ nulls[m] = false; -+ } - cstate->cur_attname = NULL; - cstate->cur_attval = NULL; - } -@@ -2094,17 +2246,38 @@ CopyFrom(CopyState cstate) - i = 0; - foreach(cur, cstate->attnumlist) - { -+ Form_pg_attribute attForm; - int attnum = lfirst_int(cur); - int m = attnum - 1; - -- cstate->cur_attname = NameStr(attr[m]->attname); -+ if (attnum == SecurityLabelAttributeNumber) -+ attForm = SystemAttributeDefinition(attnum, true, true); -+ else -+ attForm = attr[m]; -+ -+ cstate->cur_attname = NameStr(attForm->attname); - i++; -- values[m] = CopyReadBinaryAttribute(cstate, -- i, -- &in_functions[m], -- typioparams[m], -- attr[m]->atttypmod, -- &nulls[m]); -+ -+ if (attnum == SecurityLabelAttributeNumber) -+ { -+ Datum datum = CopyReadBinaryAttribute(cstate, i, -+ &seclabel_in_function, -+ seclabel_typioparam, -+ attForm->atttypmod, -+ &isnull); -+ if (!isnull && !ignore_security_label_input) -+ loaded_secid -+ = seclabelTransInput(RelationGetRelid(cstate->rel), -+ TextDatumGetCString(datum)); -+ } -+ else -+ { -+ values[m] = CopyReadBinaryAttribute(cstate, i, -+ &in_functions[m], -+ typioparams[m], -+ attr[m]->atttypmod, -+ &nulls[m]); -+ } - cstate->cur_attname = NULL; - } - } -@@ -2125,6 +2298,8 @@ CopyFrom(CopyState cstate) - - if (cstate->oids && file_has_oids) - HeapTupleSetOid(tuple, loaded_oid); -+ if (HeapTupleHasSecid(tuple)) -+ HeapTupleSetSecid(tuple, loaded_secid); - - /* Triggers and stuff need to be invoked in query context. */ - MemoryContextSwitchTo(oldcontext); -@@ -2149,6 +2324,9 @@ CopyFrom(CopyState cstate) - } - - if (!skip_tuple) -+ sepgsql_tuple_insert(cstate->rel, tuple); -+ -+ if (!skip_tuple) - { - List *recheckIndexes = NIL; - -@@ -3435,6 +3613,17 @@ CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist) - } - if (attnum == InvalidAttrNumber) - { -+ Form_pg_attribute attForm; -+ bool hasoid = tupDesc->tdhasoid; -+ bool hassecid = tupDesc->tdhassecid; -+ -+ attForm = SystemAttributeByName(name, hasoid, hassecid); -+ if (attForm && -+ SystemAttributeWritable(attForm->attnum, hasoid, hassecid)) -+ attnum = attForm->attnum; -+ } -+ if (attnum == InvalidAttrNumber) -+ { - if (rel != NULL) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), -@@ -3482,7 +3671,7 @@ copy_dest_receive(TupleTableSlot *slot, DestReceiver *self) - slot_getallattrs(slot); - - /* And send the data */ -- CopyOneRowTo(cstate, InvalidOid, slot->tts_values, slot->tts_isnull); -+ CopyOneRowTo(cstate, slot->tts_tuple, slot->tts_values, slot->tts_isnull); - } - - /* -diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c -index 3d54324..3687922 100644 ---- a/src/backend/commands/dbcommands.c -+++ b/src/backend/commands/dbcommands.c -@@ -35,6 +35,8 @@ - #include "catalog/pg_authid.h" - #include "catalog/pg_database.h" - #include "catalog/pg_db_role_setting.h" -+#include "catalog/pg_seclabel.h" -+#include "catalog/pg_shdescription.h" - #include "catalog/pg_tablespace.h" - #include "commands/comment.h" - #include "commands/dbcommands.h" -@@ -43,6 +45,7 @@ - #include "miscadmin.h" - #include "pgstat.h" - #include "postmaster/bgwriter.h" -+#include "sepgsql/hooks.h" - #include "storage/bufmgr.h" - #include "storage/fd.h" - #include "storage/lmgr.h" -@@ -111,6 +114,7 @@ createdb(const CreatedbStmt *stmt) - Datum new_record[Natts_pg_database]; - bool new_record_nulls[Natts_pg_database]; - Oid dboid; -+ Oid dbsecid; - Oid datdba; - ListCell *option; - DefElem *dtablespacename = NULL; -@@ -486,6 +490,9 @@ createdb(const CreatedbStmt *stmt) - /* Note there is no additional permission check in this path */ - } - -+ /* SELinux permission checks */ -+ dbsecid = sepgsql_database_create(dbname, src_dboid); -+ - /* - * Check for db name conflict. This is just to give a more friendly error - * message than "unique index violation". There's a race condition but -@@ -560,6 +567,8 @@ createdb(const CreatedbStmt *stmt) - new_record, new_record_nulls); - - HeapTupleSetOid(tuple, dboid); -+ if (HeapTupleHasSecid(tuple)) -+ HeapTupleSetSecid(tuple, dbsecid); - - simple_heap_insert(pg_database_rel, tuple); - -@@ -576,6 +585,9 @@ createdb(const CreatedbStmt *stmt) - /* Create pg_shdepend entries for objects within database */ - copyTemplateDependencies(src_dboid, dboid); - -+ /* Create pg_seclabel entries for objects within database */ -+ seclabelOnCreateDatabase(src_dboid, dboid); -+ - /* - * Force a checkpoint before starting the copy. This will force dirty - * buffers out to disk, to ensure source database is up-to-date on disk -@@ -777,6 +789,9 @@ dropdb(const char *dbname, bool missing_ok) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - dbname); - -+ /* SELinux checks */ -+ sepgsql_database_drop(db_id, false); -+ - /* - * Disallow dropping a DB that is marked istemplate. This is just to - * prevent people from accidentally dropping template0 or template1; they -@@ -833,6 +848,11 @@ dropdb(const char *dbname, bool missing_ok) - dropDatabaseDependencies(db_id); - - /* -+ * Remove pg_seclabel entries for the database -+ */ -+ seclabelOnDropDatabase(db_id); -+ -+ /* - * Drop pages for this database that are in the shared buffer cache. This - * is important to ensure that no remaining backend tries to write out a - * dirty buffer to the dead database later... -@@ -915,6 +935,9 @@ RenameDatabase(const char *oldname, const char *newname) - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied to rename database"))); - -+ /* SELinux checks */ -+ sepgsql_database_alter(db_id); -+ - /* - * Make sure the new name doesn't exist. See notes for same error in - * CREATE DATABASE. -@@ -1053,6 +1076,9 @@ movedb(const char *dbname, const char *tblspcname) - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("pg_global cannot be used as default tablespace"))); - -+ /* SELinux checks */ -+ sepgsql_database_alter(db_id); -+ - /* - * No-op if same tablespace - */ -@@ -1369,6 +1395,9 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - stmt->dbname); - -+ /* SELinux checks */ -+ sepgsql_database_alter(HeapTupleGetOid(tuple)); -+ - /* - * Build an updated tuple, perusing the information just obtained - */ -@@ -1419,6 +1448,9 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - stmt->dbname); - -+ /* SELinux checks */ -+ sepgsql_database_alter(datid); -+ - AlterSetting(datid, InvalidOid, stmt->setstmt); - - UnlockSharedObject(DatabaseRelationId, datid, 0, AccessShareLock); -@@ -1494,6 +1526,9 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId) - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied to change owner of database"))); - -+ /* SELinux checks */ -+ sepgsql_database_alter(HeapTupleGetOid(tuple)); -+ - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - -@@ -1533,6 +1568,58 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId) - heap_close(rel, NoLock); - } - -+/* -+ * ALTER DATABASE SECURITY LABEL TO -+ */ -+void -+AlterDatabaseSecLabel(const char *dbname, char *new_label) -+{ -+ Relation rel; -+ HeapTuple oldtup; -+ HeapTuple newtup; -+ ScanKeyData skey; -+ SysScanDesc scan; -+ Oid databaseId; -+ Oid securityId; -+ -+ /* Fetch the old tuple */ -+ rel = heap_open(DatabaseRelationId, RowExclusiveLock); -+ ScanKeyInit(&skey, -+ Anum_pg_database_datname, -+ BTEqualStrategyNumber, F_NAMEEQ, -+ NameGetDatum(dbname)); -+ scan = systable_beginscan(rel, DatabaseNameIndexId, true, -+ SnapshotNow, 1, &skey); -+ oldtup = systable_getnext(scan); -+ if (!HeapTupleIsValid(oldtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_DATABASE), -+ errmsg("database \"%s\" does not exist", dbname))); -+ -+ newtup = heap_copytuple(oldtup); -+ -+ systable_endscan(scan); -+ -+ databaseId = HeapTupleGetOid(newtup); -+ -+ /* DAC permission checks */ -+ if (!pg_database_ownercheck(databaseId, GetUserId())) -+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname); -+ -+ /* SELinux checks */ -+ securityId = sepgsql_database_relabel(databaseId, new_label); -+ -+ /* Update it */ -+ HeapTupleSetSecid(newtup, securityId); -+ -+ simple_heap_update(rel, &newtup->t_self, newtup); -+ -+ CatalogUpdateIndexes(rel, newtup); -+ -+ heap_freetuple(newtup); -+ -+ heap_close(rel, RowExclusiveLock); -+} - - /* - * Helper functions -diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c -index e8dba94..4c4fc36 100644 ---- a/src/backend/commands/explain.c -+++ b/src/backend/commands/explain.c -@@ -257,7 +257,7 @@ ExplainResultDesc(ExplainStmt *stmt) - } - - /* Need a tuple descriptor representing a single TEXT or XML column */ -- tupdesc = CreateTemplateTupleDesc(1, false); -+ tupdesc = CreateTemplateTupleDesc(1, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN", - xml ? XMLOID : TEXTOID, -1, 0); - return tupdesc; -diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c -index abbe731..b36c928 100644 ---- a/src/backend/commands/foreigncmds.c -+++ b/src/backend/commands/foreigncmds.c -@@ -27,6 +27,7 @@ - #include "foreign/foreign.h" - #include "miscadmin.h" - #include "parser/parse_func.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -@@ -230,6 +231,9 @@ AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId) - fdwId = HeapTupleGetOid(tup); - form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup); - -+ /* SELinux checks */ -+ sepgsql_fdw_alter(fdwId, InvalidOid); -+ - if (form->fdwowner != newOwnerId) - { - form->fdwowner = newOwnerId; -@@ -294,6 +298,8 @@ AlterForeignServerOwner(const char *name, Oid newOwnerId) - aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname); - } - } -+ /* SELinux checks */ -+ sepgsql_fserver_alter(srvId); - - form->srvowner = newOwnerId; - -@@ -339,6 +345,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) - Oid fdwvalidator; - Datum fdwoptions; - Oid ownerId; -+ Oid securityId; - - /* Must be super user */ - if (!superuser()) -@@ -391,8 +398,13 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) - else - nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true; - -+ /* SELinux checks */ -+ securityId = sepgsql_fdw_create(stmt->fdwname, fdwvalidator); -+ - tuple = heap_form_tuple(rel->rd_att, values, nulls); - -+ HeapTupleSetSecid(tuple, securityId); -+ - fdwId = simple_heap_insert(rel, tuple); - CatalogUpdateIndexes(rel, tuple); - -@@ -511,6 +523,8 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) - - repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true; - } -+ /* SELinux checks */ -+ sepgsql_fdw_alter(fdwId, fdwvalidator); - - /* Everything looks good - update the tuple */ - -@@ -559,6 +573,8 @@ RemoveForeignDataWrapper(DropFdwStmt *stmt) - stmt->fdwname))); - return; - } -+ /* SELinux checks */ -+ sepgsql_fdw_drop(fdwId, false); - - /* - * Do the deletion -@@ -608,6 +624,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt) - HeapTuple tuple; - Oid srvId; - Oid ownerId; -+ Oid securityId; - AclResult aclresult; - ObjectAddress myself; - ObjectAddress referenced; -@@ -635,6 +652,9 @@ CreateForeignServer(CreateForeignServerStmt *stmt) - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname); - -+ /* SELinux checks */ -+ securityId = sepgsql_fserver_create(stmt->servername, fdw->fdwid); -+ - /* - * Insert tuple into pg_foreign_server. - */ -@@ -678,6 +698,8 @@ CreateForeignServer(CreateForeignServerStmt *stmt) - - tuple = heap_form_tuple(rel->rd_att, values, nulls); - -+ HeapTupleSetSecid(tuple, securityId); -+ - srvId = simple_heap_insert(rel, tuple); - - CatalogUpdateIndexes(rel, tuple); -@@ -732,6 +754,9 @@ AlterForeignServer(AlterForeignServerStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER, - stmt->servername); - -+ /* SELinux checks */ -+ sepgsql_fserver_alter(srvId); -+ - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); -@@ -823,6 +848,8 @@ RemoveForeignServer(DropForeignServerStmt *stmt) - if (!pg_foreign_server_ownercheck(srvId, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER, - stmt->servername); -+ /* SELinux checks */ -+ sepgsql_fserver_drop(srvId, false); - - object.classId = ForeignServerRelationId; - object.objectId = srvId; -@@ -896,6 +923,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt) - HeapTuple tuple; - Oid useId; - Oid umId; -+ Oid securityId; - ObjectAddress myself; - ObjectAddress referenced; - ForeignServer *srv; -@@ -908,6 +936,9 @@ CreateUserMapping(CreateUserMappingStmt *stmt) - - user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername); - -+ /* SELinux checks */ -+ securityId = sepgsql_user_mapping_create(useId, srv->serverid); -+ - /* - * Check that the user mapping is unique within server. - */ -@@ -947,6 +978,8 @@ CreateUserMapping(CreateUserMappingStmt *stmt) - - tuple = heap_form_tuple(rel->rd_att, values, nulls); - -+ HeapTupleSetSecid(tuple, securityId); -+ - umId = simple_heap_insert(rel, tuple); - - CatalogUpdateIndexes(rel, tuple); -@@ -1000,6 +1033,9 @@ AlterUserMapping(AlterUserMappingStmt *stmt) - - user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername); - -+ /* SELinux checks */ -+ sepgsql_user_mapping_alter(umId); -+ - tp = SearchSysCacheCopy1(USERMAPPINGOID, ObjectIdGetDatum(umId)); - - if (!HeapTupleIsValid(tp)) -@@ -1114,6 +1150,9 @@ RemoveUserMapping(DropUserMappingStmt *stmt) - - user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername); - -+ /* SELinux checks */ -+ sepgsql_user_mapping_drop(umId, false); -+ - /* - * Do the deletion - */ -diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c -index 26a3a52..e2b8683 100644 ---- a/src/backend/commands/functioncmds.c -+++ b/src/backend/commands/functioncmds.c -@@ -43,6 +43,7 @@ - #include "catalog/pg_namespace.h" - #include "catalog/pg_proc.h" - #include "catalog/pg_proc_fn.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/pg_type.h" - #include "catalog/pg_type_fn.h" - #include "commands/defrem.h" -@@ -53,6 +54,7 @@ - #include "parser/parse_expr.h" - #include "parser/parse_func.h" - #include "parser/parse_type.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -@@ -788,6 +790,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) - ArrayType *parameterNames; - List *parameterDefaults; - Oid requiredResultType; -+ Oid replacedFunc = InvalidOid; -+ Oid prosecid; - bool isWindowFunc, - isStrict, - security; -@@ -933,6 +937,18 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) - errmsg("ROWS is not applicable when function does not return a set"))); - - /* -+ * SELinux checks -+ */ -+ if (stmt->replace) -+ replacedFunc = GetSysCacheOid3(PROCNAMEARGSNSP, -+ PointerGetDatum(funcname), -+ PointerGetDatum(parameterTypes), -+ ObjectIdGetDatum(namespaceId)); -+ -+ prosecid = sepgsql_proc_create(funcname, replacedFunc, -+ namespaceId, languageOid); -+ -+ /* - * And now that we have all the parameters, and know we're permitted to do - * so, go ahead and create the function. - */ -@@ -957,7 +973,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) - parameterDefaults, - PointerGetDatum(proconfig), - procost, -- prorows); -+ prorows, -+ prosecid); - } - - -@@ -999,6 +1016,9 @@ RemoveFunction(RemoveFuncStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - NameListToString(functionName)); - -+ /* SELinux checks */ -+ sepgsql_proc_drop(funcOid, false); -+ - if (((Form_pg_proc) GETSTRUCT(tup))->proisagg) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), -@@ -1135,6 +1155,9 @@ RenameFunction(List *name, List *argtypes, const char *newname) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux checks */ -+ sepgsql_proc_alter_rename(procOid, newname); -+ - /* rename */ - namestrcpy(&(procForm->proname), newname); - simple_heap_update(rel, &tup->t_self, tup); -@@ -1239,6 +1262,8 @@ AlterFunctionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(procForm->pronamespace)); - } -+ /* SELinux checks */ -+ sepgsql_proc_alter(procOid); - - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); -@@ -1277,6 +1302,49 @@ AlterFunctionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) - } - - /* -+ * ALTER FUNCTION f(...) SECURITY LABEL TO -+ */ -+void -+AlterFunctionSecLabel(List *name, List *argtypes, bool isagg, char *new_label) -+{ -+ Relation rel; -+ HeapTuple tuple; -+ Oid procOid; -+ Oid securityId; -+ -+ /* open pg_proc system catalog */ -+ rel = heap_open(ProcedureRelationId, RowExclusiveLock); -+ -+ /* get function OID */ -+ if (isagg) -+ procOid = LookupAggNameTypeNames(name, argtypes, false); -+ else -+ procOid = LookupFuncNameTypeNames(name, argtypes, false); -+ -+ tuple = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for function %u", procOid); -+ -+ /* Must be owner */ -+ if (!pg_proc_ownercheck(procOid, GetUserId())) -+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, -+ get_func_name(procOid)); -+ -+ /* SELinux checks */ -+ securityId = sepgsql_proc_relabel(procOid, new_label); -+ -+ /* Update it */ -+ HeapTupleSetSecid(tuple, securityId); -+ -+ simple_heap_update(rel, &tuple->t_self, tuple); -+ CatalogUpdateIndexes(rel, tuple); -+ -+ heap_freetuple(tuple); -+ -+ heap_close(rel, RowExclusiveLock); -+} -+ -+/* - * Implements the ALTER FUNCTION utility command (except for the - * RENAME and OWNER clauses, which are handled as part of the generic - * ALTER framework). -@@ -1313,6 +1381,9 @@ AlterFunction(AlterFunctionStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - NameListToString(stmt->func->funcname)); - -+ /* SELinux checks */ -+ sepgsql_proc_alter(funcOid); -+ - if (procForm->proisagg) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), -@@ -1659,6 +1730,9 @@ CreateCast(CreateCastStmt *stmt) - errmsg("array data types are not binary-compatible"))); - } - -+ /* SELinux checks */ -+ sepgsql_cast_create(sourcetypeid, targettypeid, castmethod, funcid); -+ - /* - * Allow source and target types to be same only for length coercion - * functions. We assume a multi-arg function does length coercion. -@@ -1795,6 +1869,9 @@ DropCast(DropCastStmt *stmt) - format_type_be(sourcetypeid), - format_type_be(targettypeid)))); - -+ /* SELinux checks */ -+ sepgsql_cast_drop(sourcetypeid, targettypeid, false); -+ - /* - * Do the deletion - */ -@@ -1873,6 +1950,9 @@ AlterFunctionNamespace(List *name, List *argtypes, bool isagg, - /* get schema OID and check its permissions */ - nspOid = LookupCreationNamespace(newschema); - -+ /* SELinux checks */ -+ sepgsql_proc_alter_schema(procOid, nspOid); -+ - if (oldNspOid == nspOid) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_FUNCTION), -diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c -index a129511..6c2dbc4 100644 ---- a/src/backend/commands/indexcmds.c -+++ b/src/backend/commands/indexcmds.c -@@ -40,6 +40,7 @@ - #include "parser/parse_func.h" - #include "parser/parse_oper.h" - #include "parser/parsetree.h" -+#include "sepgsql/hooks.h" - #include "storage/lmgr.h" - #include "storage/proc.h" - #include "storage/procarray.h" -@@ -243,6 +244,10 @@ DefineIndex(RangeVar *heapRelation, - get_tablespace_name(tablespaceId)); - } - -+ /* SELinux checks */ -+ if (check_rights) -+ sepgsql_index_create(relationId, namespaceId); -+ - /* - * Force shared indexes into the pg_global tablespace. This is a bit of a - * hack but seems simpler than marking them in the BKI commands. On the -@@ -364,7 +369,9 @@ DefineIndex(RangeVar *heapRelation, - errmsg("primary keys cannot be expressions"))); - - /* System attributes are never null, so no problem */ -- if (SystemAttributeByName(key->name, rel->rd_rel->relhasoids)) -+ if (SystemAttributeByName(key->name, -+ rel->rd_rel->relhasoids, -+ rel->rd_rel->relhassecids)) - continue; - - atttuple = SearchSysCacheAttName(relationId, key->name); -@@ -1600,6 +1607,9 @@ ReindexIndex(RangeVar *indexRelation) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - indexRelation->relname); - -+ /* SELinux checks */ -+ sepgsql_index_reindex(indOid); -+ - ReleaseSysCache(tuple); - - reindex_index(indOid, false); -@@ -1632,6 +1642,9 @@ ReindexTable(RangeVar *relation) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - relation->relname); - -+ /* SELinux checks */ -+ sepgsql_relation_reindex(heapOid); -+ - ReleaseSysCache(tuple); - - if (!reindex_relation(heapOid, true, 0)) -@@ -1670,6 +1683,9 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - databaseName); - -+ /* SELinux checks */ -+ sepgsql_database_reindex(MyDatabaseId); -+ - /* - * Create a memory context that will survive forced transaction commits we - * do below. Since it is a child of PortalContext, it will go away -diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c -index 34d657c..d3c69a3 100644 ---- a/src/backend/commands/lockcmds.c -+++ b/src/backend/commands/lockcmds.c -@@ -20,6 +20,7 @@ - #include "commands/lockcmds.h" - #include "miscadmin.h" - #include "parser/parse_clause.h" -+#include "sepgsql/hooks.h" - #include "storage/lmgr.h" - #include "utils/acl.h" - #include "utils/lsyscache.h" -@@ -149,6 +150,9 @@ LockTableRecurse(Oid reloid, RangeVar *rv, - errmsg("\"%s\" is not a table", - RelationGetRelationName(rel)))); - -+ /* SELinux checks */ -+ sepgsql_relation_lock(rel); -+ - /* - * If requested, recurse to children. We use find_inheritance_children - * not find_all_inheritors to avoid taking locks far in advance of -diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c -index cae1a31..c946c5c 100644 ---- a/src/backend/commands/opclasscmds.c -+++ b/src/backend/commands/opclasscmds.c -@@ -35,6 +35,7 @@ - #include "parser/parse_func.h" - #include "parser/parse_oper.h" - #include "parser/parse_type.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -@@ -164,7 +165,8 @@ OpClassCacheLookup(Oid amID, List *opclassname) - * Caller must have done permissions checks etc. already. - */ - static Oid --CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid) -+CreateOpFamily(char *amname, char *opfname, -+ Oid namespaceoid, Oid amoid, Oid securityId) - { - Oid opfamilyoid; - Relation rel; -@@ -204,6 +206,8 @@ CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid) - - tup = heap_form_tuple(rel->rd_att, values, nulls); - -+ HeapTupleSetSecid(tup, securityId); -+ - opfamilyoid = simple_heap_insert(rel, tup); - - CatalogUpdateIndexes(rel, tup); -@@ -369,11 +373,16 @@ DefineOpClass(CreateOpClassStmt *stmt) - } - else - { -+ Oid securityId; -+ -+ /* SELinux checks */ -+ securityId = sepgsql_opfamily_create(opcname, namespaceoid, amoid); -+ - /* - * Create it ... again no need for more permissions ... - */ - opfamilyoid = CreateOpFamily(stmt->amname, opcname, -- namespaceoid, amoid); -+ namespaceoid, amoid, securityId); - } - } - -@@ -505,6 +514,12 @@ DefineOpClass(CreateOpClassStmt *stmt) - stmt->amname))); - } - -+ /* SELinux checks */ -+ sepgsql_opfamily_alter(opfamilyoid, false, amoid, -+ operators, procedures); -+ sepgsql_opclass_create(opcname, namespaceoid, -+ typeoid, opfamilyoid, storageoid); -+ - rel = heap_open(OperatorClassRelationId, RowExclusiveLock); - - /* -@@ -650,6 +665,7 @@ DefineOpFamily(CreateOpFamilyStmt *stmt) - NameData opfName; - ObjectAddress myself, - referenced; -+ Oid securityId; - - /* Convert list of names to a name and namespace */ - namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname, -@@ -701,6 +717,9 @@ DefineOpFamily(CreateOpFamilyStmt *stmt) - errmsg("operator family \"%s\" for access method \"%s\" already exists", - opfname, stmt->amname))); - -+ /* SELinux checks */ -+ securityId = sepgsql_opfamily_create(opfname, namespaceoid, amoid); -+ - /* - * Okay, let's create the pg_opfamily entry. - */ -@@ -715,6 +734,8 @@ DefineOpFamily(CreateOpFamilyStmt *stmt) - - tup = heap_form_tuple(rel->rd_att, values, nulls); - -+ HeapTupleSetSecid(tup, securityId); -+ - opfamilyoid = simple_heap_insert(rel, tup); - - CatalogUpdateIndexes(rel, tup); -@@ -925,6 +946,9 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid, - break; - } - } -+ /* SELinux checks */ -+ sepgsql_opfamily_alter(opfamilyoid, false, amoid, -+ operators, procedures); - - /* - * Add tuples to pg_amop and pg_amproc tying in the operators and -@@ -1002,6 +1026,9 @@ AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid, - } - } - -+ /* SELinux checks */ -+ sepgsql_opfamily_alter(opfamilyoid, true, amoid, operators, procedures); -+ - /* - * Remove tuples from pg_amop and pg_amproc. - */ -@@ -1522,6 +1549,9 @@ RemoveOpClass(RemoveOpClassStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, - NameListToString(stmt->opclassname)); - -+ /* SELinux checks */ -+ sepgsql_opclass_drop(opcID, false); -+ - ReleaseSysCache(tuple); - - /* -@@ -1583,6 +1613,9 @@ RemoveOpFamily(RemoveOpFamilyStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY, - NameListToString(stmt->opfamilyname)); - -+ /* SELinux checks */ -+ sepgsql_opfamily_drop(opfID, false); -+ - ReleaseSysCache(tuple); - - /* -@@ -1781,6 +1814,9 @@ RenameOpClass(List *name, const char *access_method, const char *newname) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux checks */ -+ sepgsql_opclass_alter_rename(opcOid, newname); -+ - /* rename */ - namestrcpy(&(((Form_pg_opclass) GETSTRUCT(tup))->opcname), newname); - simple_heap_update(rel, &tup->t_self, tup); -@@ -1875,6 +1911,9 @@ RenameOpFamily(List *name, const char *access_method, const char *newname) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux checks */ -+ sepgsql_opfamily_alter_rename(opfOid, newname); -+ - /* rename */ - namestrcpy(&(((Form_pg_opfamily) GETSTRUCT(tup))->opfname), newname); - simple_heap_update(rel, &tup->t_self, tup); -@@ -2011,6 +2050,8 @@ AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - } -+ /* SELinux checks */ -+ sepgsql_opclass_alter(HeapTupleGetOid(tup)); - - /* - * Modify the owner --- okay to scribble on tup because it's a copy -@@ -2154,7 +2195,8 @@ AlterOpFamilyOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - } -- -+ /* SELinux checks */ -+ sepgsql_opfamily_alter_owner(HeapTupleGetOid(tup), newOwnerId); - /* - * Modify the owner --- okay to scribble on tup because it's a copy - */ -diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c -index fa84a9b..36a4ac7 100644 ---- a/src/backend/commands/operatorcmds.c -+++ b/src/backend/commands/operatorcmds.c -@@ -45,6 +45,7 @@ - #include "parser/parse_func.h" - #include "parser/parse_oper.h" - #include "parser/parse_type.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/lsyscache.h" - #include "utils/rel.h" -@@ -329,6 +330,9 @@ RemoveOperator(RemoveFuncStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER, - NameListToString(operatorName)); - -+ /* SELinux checks */ -+ sepgsql_operator_drop(operOid, false); -+ - ReleaseSysCache(tup); - - /* -@@ -436,6 +440,8 @@ AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(oprForm->oprnamespace)); - } -+ /* SELinux checks */ -+ sepgsql_operator_alter(operOid); - - /* - * Modify the owner --- okay to scribble on tup because it's a copy -diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c -index 7fa8278..9b3662d 100644 ---- a/src/backend/commands/prepare.c -+++ b/src/backend/commands/prepare.c -@@ -759,7 +759,7 @@ pg_prepared_statement(PG_FUNCTION_ARGS) - * build tupdesc for result tuples. This must match the definition of the - * pg_prepared_statements view in system_views.sql - */ -- tupdesc = CreateTemplateTupleDesc(5, false); -+ tupdesc = CreateTemplateTupleDesc(5, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement", -diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c -index 8292ae1..0ce601a 100644 ---- a/src/backend/commands/proclang.c -+++ b/src/backend/commands/proclang.c -@@ -29,6 +29,7 @@ - #include "miscadmin.h" - #include "parser/parse_func.h" - #include "parser/parser.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -@@ -145,7 +146,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) - NIL, - PointerGetDatum(NULL), - 1, -- 0); -+ 0, -+ InvalidOid); - } - - /* -@@ -180,7 +182,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) - NIL, - PointerGetDatum(NULL), - 1, -- 0); -+ 0, -+ InvalidOid); - } - } - else -@@ -218,7 +221,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) - NIL, - PointerGetDatum(NULL), - 1, -- 0); -+ 0, -+ InvalidOid); - } - } - else -diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c -index b30fdce..8430e3e 100644 ---- a/src/backend/commands/schemacmds.c -+++ b/src/backend/commands/schemacmds.c -@@ -21,10 +21,12 @@ - #include "catalog/indexing.h" - #include "catalog/namespace.h" - #include "catalog/pg_namespace.h" -+#include "catalog/pg_seclabel.h" - #include "commands/dbcommands.h" - #include "commands/schemacmds.h" - #include "miscadmin.h" - #include "parser/parse_utilcmd.h" -+#include "sepgsql/hooks.h" - #include "tcop/utility.h" - #include "utils/acl.h" - #include "utils/builtins.h" -@@ -49,6 +51,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) - Oid owner_uid; - Oid saved_uid; - int save_sec_context; -+ Oid secid; - AclResult aclresult; - - GetUserIdAndSecContext(&saved_uid, &save_sec_context); -@@ -75,6 +78,9 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) - - check_is_member_of_role(saved_uid, owner_uid); - -+ /* SELinux checks */ -+ secid = sepgsql_schema_create(schemaName, false); -+ - /* Additional check to protect reserved schema names */ - if (!allowSystemTableMods && IsReservedName(schemaName)) - ereport(ERROR, -@@ -95,7 +101,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, secid); - - /* Advance cmd counter to make the namespace visible */ - CommandCounterIncrement(); -@@ -204,6 +210,9 @@ RemoveSchemas(DropStmt *drop) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, - namespaceName); - -+ /* SELinux checks */ -+ sepgsql_schema_drop(namespaceId, false); -+ - object.classId = NamespaceRelationId; - object.objectId = namespaceId; - object.objectSubId = 0; -@@ -288,6 +297,9 @@ RenameSchema(const char *oldname, const char *newname) - errmsg("unacceptable schema name \"%s\"", newname), - errdetail("The prefix \"pg_\" is reserved for system schemas."))); - -+ /* SELinux checks */ -+ sepgsql_schema_alter(HeapTupleGetOid(tup)); -+ - /* rename */ - namestrcpy(&(((Form_pg_namespace) GETSTRUCT(tup))->nspname), newname); - simple_heap_update(rel, &tup->t_self, tup); -@@ -389,6 +401,9 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId) - aclcheck_error(aclresult, ACL_KIND_DATABASE, - get_database_name(MyDatabaseId)); - -+ /* SELinux checks */ -+ sepgsql_schema_alter(HeapTupleGetOid(tup)); -+ - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - -@@ -423,3 +438,43 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId) - } - - } -+ -+/* -+ * ALTER SCHEMA SECURITY LABEL TO -+ */ -+void -+AlterSchemaSecLabel(const char *name, char *new_label) -+{ -+ Relation rel; -+ HeapTuple tuple; -+ Oid namespaceId; -+ Oid securityId; -+ -+ /* open pg_namespace relation */ -+ rel = heap_open(NamespaceRelationId, RowExclusiveLock); -+ tuple = SearchSysCacheCopy1(NAMESPACENAME, -+ CStringGetDatum(name)); -+ if (!HeapTupleIsValid(tuple)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_SCHEMA), -+ errmsg("schema \"%s\" does not exist", name))); -+ namespaceId = HeapTupleGetOid(tuple); -+ -+ /* DAC permission check */ -+ if (!pg_namespace_ownercheck(namespaceId, GetUserId())) -+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, name); -+ -+ /* SELinux checks */ -+ securityId = sepgsql_schema_relabel(namespaceId, new_label); -+ -+ /* Update it */ -+ HeapTupleSetSecid(tuple, securityId); -+ -+ simple_heap_update(rel, &tuple->t_self, tuple); -+ -+ CatalogUpdateIndexes(rel, tuple); -+ -+ heap_freetuple(tuple); -+ -+ heap_close(rel, RowExclusiveLock); -+} -diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c -index 292a427..3c8a36f 100644 ---- a/src/backend/commands/sequence.c -+++ b/src/backend/commands/sequence.c -@@ -26,6 +26,7 @@ - #include "commands/tablecmds.h" - #include "miscadmin.h" - #include "nodes/makefuncs.h" -+#include "sepgsql/hooks.h" - #include "storage/bufmgr.h" - #include "storage/lmgr.h" - #include "storage/proc.h" -@@ -331,6 +332,9 @@ AlterSequence(AlterSeqStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - stmt->sequence->relname); - -+ /* SELinux checks */ -+ sepgsql_relation_alter(relid); -+ - /* do the work */ - AlterSequenceInternal(relid, stmt->options); - } -@@ -469,6 +473,9 @@ nextval_internal(Oid relid) - errmsg("permission denied for sequence %s", - RelationGetRelationName(seqrel)))); - -+ /* SELinux checks */ -+ sepgsql_sequence_next_value(elm->relid); -+ - /* read-only transactions may only modify temp sequences */ - if (!seqrel->rd_islocaltemp) - PreventCommandIfReadOnly("nextval()"); -@@ -668,6 +675,9 @@ currval_oid(PG_FUNCTION_ARGS) - errmsg("permission denied for sequence %s", - RelationGetRelationName(seqrel)))); - -+ /* SELinux checks */ -+ sepgsql_sequence_get_value(elm->relid); -+ - if (!elm->last_valid) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), -@@ -710,6 +720,9 @@ lastval(PG_FUNCTION_ARGS) - errmsg("permission denied for sequence %s", - RelationGetRelationName(seqrel)))); - -+ /* SELinux checks */ -+ sepgsql_sequence_get_value(last_used_seq->relid); -+ - result = last_used_seq->last; - relation_close(seqrel, NoLock); - -@@ -746,6 +759,9 @@ do_setval(Oid relid, int64 next, bool iscalled) - errmsg("permission denied for sequence %s", - RelationGetRelationName(seqrel)))); - -+ /* SELinux checks */ -+ sepgsql_sequence_set_value(elm->relid); -+ - /* read-only transactions may only modify temp sequences */ - if (!seqrel->rd_islocaltemp) - PreventCommandIfReadOnly("setval()"); -diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c -index 6a1804b..2453fcf 100644 ---- a/src/backend/commands/tablecmds.c -+++ b/src/backend/commands/tablecmds.c -@@ -32,6 +32,7 @@ - #include "catalog/pg_inherits_fn.h" - #include "catalog/pg_namespace.h" - #include "catalog/pg_opclass.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/pg_tablespace.h" - #include "catalog/pg_trigger.h" - #include "catalog/pg_type.h" -@@ -62,12 +63,14 @@ - #include "parser/parser.h" - #include "rewrite/rewriteDefine.h" - #include "rewrite/rewriteHandler.h" -+#include "sepgsql/hooks.h" - #include "storage/bufmgr.h" - #include "storage/lmgr.h" - #include "storage/smgr.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -+#include "utils/guc.h" - #include "utils/inval.h" - #include "utils/lsyscache.h" - #include "utils/memutils.h" -@@ -223,7 +226,7 @@ static const struct dropmsgstrings dropmsgstringarray[] = { - - static void truncate_check_rel(Relation rel); - static List *MergeAttributes(List *schema, List *supers, bool istemp, -- List **supOids, List **supconstr, int *supOidCount); -+ List **supOids, List **supconstr, int *supOidCount, int *supSecidCount); - static bool MergeCheckConstraint(List *constraints, char *name, Node *expr); - static bool change_varattnos_walker(Node *node, const AttrNumber *newattno); - static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel); -@@ -271,10 +274,12 @@ static void ATOneLevelRecursion(List **wqueue, Relation rel, - static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, - AlterTableCmd *cmd); - static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel, -- ColumnDef *colDef, bool isOid); -+ ColumnDef *colDef, bool isOid, bool isSecid); - static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid); - static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse, - AlterTableCmd *cmd); -+static void ATPrepAddSecLabel(List **wqueue, Relation rel, bool recurse, -+ AlterTableCmd *cmd); - static void ATExecDropNotNull(Relation rel, const char *colName); - static void ATExecSetNotNull(AlteredTableInfo *tab, Relation rel, - const char *colName); -@@ -367,6 +372,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId) - List *old_constraints; - bool localHasOids; - int parentOidCount; -+ int parentSecidCount; - List *rawDefaults; - List *cookedDefaults; - Datum reloptions; -@@ -374,6 +380,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId) - AttrNumber attnum; - static char *validnsps[] = HEAP_RELOPT_NAMESPACES; - Oid ofTypeId; -+ Oid *secLabels; - - /* - * Truncate relname to appropriate length (probably a waste of time, as -@@ -477,7 +484,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId) - */ - schema = MergeAttributes(schema, stmt->inhRelations, - stmt->relation->istemp, -- &inheritOids, &old_constraints, &parentOidCount); -+ &inheritOids, &old_constraints, -+ &parentOidCount, &parentSecidCount); - - /* - * Create a tuple descriptor from the relation schema. Note that this -@@ -489,6 +497,16 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId) - localHasOids = interpretOidsOption(stmt->options); - descriptor->tdhasoid = (localHasOids || parentOidCount > 0); - -+ if ((relkind == RELKIND_RELATION && default_with_secids) || parentSecidCount > 0) -+ descriptor->tdhassecid = true; -+ -+ /* SELinux permission checks */ -+ secLabels = sepgsql_relation_create(relname, -+ relkind, -+ descriptor, -+ namespaceId, -+ inheritOids, -+ false); - /* - * Find columns with default values and prepare for insertion of the - * defaults. Pre-cooked (that is, inherited) defaults go into a list of -@@ -562,7 +580,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId) - stmt->oncommit, - reloptions, - true, -- allowSystemTableMods); -+ allowSystemTableMods, -+ secLabels); - - StoreCatalogInheritance(relationId, inheritOids); - -@@ -771,6 +790,9 @@ RemoveRelations(DropStmt *drop) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - rel->relname); - -+ /* SELinux checks */ -+ sepgsql_relation_drop(relOid, false); -+ - if (!allowSystemTableMods && IsSystemClass(classform)) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -@@ -934,6 +956,9 @@ ExecuteTruncate(TruncateStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(seq_rel)); - -+ /* SELinux checks */ -+ sepgsql_relation_alter(seq_relid); -+ - seq_relids = lappend_oid(seq_relids, seq_relid); - - relation_close(seq_rel, NoLock); -@@ -1102,6 +1127,8 @@ truncate_check_rel(Relation rel) - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_CLASS, - RelationGetRelationName(rel)); -+ /* SELinux checks */ -+ sepgsql_relation_truncate(rel); - - if (!allowSystemTableMods && IsSystemRelation(rel)) - ereport(ERROR, -@@ -1162,6 +1189,7 @@ storage_name(char c) - * 'supconstr' receives a list of constraints belonging to the parents, - * updated as necessary to be valid for the child. - * 'supOidCount' is set to the number of parents that have OID columns. -+ * 'supSecidCount' is set to the number of parents that have SID columns. - * - * Return value: - * Completed schema list. -@@ -1207,13 +1235,15 @@ storage_name(char c) - */ - static List * - MergeAttributes(List *schema, List *supers, bool istemp, -- List **supOids, List **supconstr, int *supOidCount) -+ List **supOids, List **supconstr, -+ int *supOidCount, int *supSecidCount) - { - ListCell *entry; - List *inhSchema = NIL; - List *parentOids = NIL; - List *constraints = NIL; - int parentsWithOids = 0; -+ int parentsWithSecids = 0; - bool have_bogus_defaults = false; - int child_attno; - static Node bogus_marker = {0}; /* marks conflicting defaults */ -@@ -1341,6 +1371,8 @@ MergeAttributes(List *schema, List *supers, bool istemp, - - if (relation->rd_rel->relhasoids) - parentsWithOids++; -+ if (relation->rd_rel->relhassecids) -+ parentsWithSecids++; - - tupleDesc = RelationGetDescr(relation); - constr = tupleDesc->constr; -@@ -1642,6 +1674,7 @@ MergeAttributes(List *schema, List *supers, bool istemp, - *supOids = parentOids; - *supconstr = constraints; - *supOidCount = parentsWithOids; -+ *supSecidCount = parentsWithSecids; - return schema; - } - -@@ -2001,6 +2034,9 @@ renameatt(Oid myrelid, - errmsg("permission denied: \"%s\" is a system catalog", - RelationGetRelationName(targetrelation)))); - -+ /* SELinux checks */ -+ sepgsql_attribute_alter(myrelid, oldattname); -+ - /* - * if the 'recurse' flag is set then we are supposed to rename this - * attribute in all classes that inherit from 'relname' (as well as in -@@ -2152,6 +2188,9 @@ RenameRelation(Oid myrelid, const char *newrelname, ObjectType reltype) - errmsg("\"%s\" is not a view", - RelationGetRelationName(targetrelation)))); - -+ /* SELinux checks */ -+ sepgsql_relation_alter_rename(myrelid, newrelname); -+ - /* - * Don't allow ALTER TABLE on composite types. We want people to use ALTER - * TYPE for that. -@@ -2580,6 +2619,27 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, - } - pass = AT_PASS_DROP; - break; -+ case AT_AddSecLabel: -+ ATSimplePermissions(rel, false); -+ /* Performs own recursion */ -+ if (!rel->rd_rel->relhassecids || recursing) -+ ATPrepAddSecLabel(wqueue, rel, recurse, cmd); -+ pass = AT_PASS_ADD_COL; -+ break; -+ case AT_DropSecLabel: -+ ATSimplePermissions(rel, false); -+ /* Performs own recursion */ -+ if (rel->rd_rel->relhassecids) -+ { -+ AlterTableCmd *dropCmd = makeNode(AlterTableCmd); -+ -+ dropCmd->subtype = AT_DropColumn; -+ dropCmd->name = pstrdup("security_label"); -+ dropCmd->behavior = cmd->behavior; -+ ATPrepCmd(wqueue, rel, dropCmd, recurse, false); -+ } -+ pass = AT_PASS_DROP; -+ break; - case AT_SetTableSpace: /* SET TABLESPACE */ - ATSimplePermissionsRelationOrIndex(rel); - /* This command never recurses */ -@@ -2709,7 +2769,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, - case AT_AddColumn: /* ADD COLUMN */ - case AT_AddColumnToView: /* add column via CREATE OR REPLACE - * VIEW */ -- ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, false); -+ ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, false, false); - break; - case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */ - ATExecColumnDefault(rel, cmd->name, cmd->def); -@@ -2781,17 +2841,22 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, - case AT_AddOids: /* SET WITH OIDS */ - /* Use the ADD COLUMN code, unless prep decided to do nothing */ - if (cmd->def != NULL) -- ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, true); -+ ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, true, false); -+ break; -+ case AT_AddSecLabel: /* SET WITH SECURITY LABEL */ -+ /* Use the ADD COLUMN code, unless prep decided to do nothing */ -+ if (cmd->def != NULL) -+ ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, false, true); - break; - case AT_DropOids: /* SET WITHOUT OIDS */ -- -+ case AT_DropSecLabel: /* SET WITHOUT SECURITY LABEL */ - /* - * Nothing to do here; we'll have generated a DropColumn - * subcommand to do the real work - */ - break; - case AT_SetTableSpace: /* SET TABLESPACE */ -- -+ sepgsql_relation_alter(RelationGetRelid(rel)); - /* - * Nothing to do here; Phase 3 does the work - */ -@@ -3146,6 +3211,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) - MemoryContext oldCxt; - List *dropped_attrs = NIL; - ListCell *lc; -+ Oid tupSecidInherit = InvalidOid; - - econtext = GetPerTupleExprContext(estate); - -@@ -3176,6 +3242,19 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) - } - - /* -+ * If this routine is called due to ALTER TABLE SET WITH SECURITY LABEL, -+ * security label of the relation shall be assigned tuples. -+ */ -+ if (!oldTupDesc->tdhassecid && newTupDesc->tdhassecid) -+ { -+ Oid relSecid = GetSysCacheSecid1(RELOID, -+ ObjectIdGetDatum(tab->relid)); -+ -+ tupSecidInherit = seclabelMoveSecid(RelationGetRelid(oldrel), -+ RelationRelationId, relSecid); -+ } -+ -+ /* - * Scan through the rows, generating a new row if needed and then - * checking all the constraints. - */ -@@ -3192,11 +3271,16 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) - if (newrel) - { - Oid tupOid = InvalidOid; -+ Oid tupSecid = InvalidOid; - - /* Extract data from old tuple */ - heap_deform_tuple(tuple, oldTupDesc, values, isnull); - if (oldTupDesc->tdhasoid) - tupOid = HeapTupleGetOid(tuple); -+ if (oldTupDesc->tdhassecid) -+ tupSecid = HeapTupleGetSecid(tuple); -+ else -+ tupSecid = tupSecidInherit; - - /* Set dropped attributes to null in new tuple */ - foreach(lc, dropped_attrs) -@@ -3228,6 +3312,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) - /* Preserve OID, if any */ - if (newTupDesc->tdhasoid) - HeapTupleSetOid(tuple, tupOid); -+ /* Preserve security-id, if any */ -+ if (newTupDesc->tdhassecid) -+ HeapTupleSetSecid(tuple, tupSecid); - } - - /* Now check any constraints on the possibly-changed tuple */ -@@ -3626,7 +3713,7 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, - - static void - ATExecAddColumn(AlteredTableInfo *tab, Relation rel, -- ColumnDef *colDef, bool isOid) -+ ColumnDef *colDef, bool isOid, bool isSecid) - { - Oid myrelid = RelationGetRelid(rel); - Relation pgclass, -@@ -3640,6 +3727,10 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, - int32 typmod; - Form_pg_type tform; - Expr *defval; -+ Oid securityId; -+ -+ /* SELinux permission check */ -+ securityId = sepgsql_attribute_create(myrelid, colDef->colname); - - attrdesc = heap_open(AttributeRelationId, RowExclusiveLock); - -@@ -3668,6 +3759,13 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, - errmsg("child table \"%s\" has different type for column \"%s\"", - RelationGetRelationName(rel), colDef->colname))); - -+ if (!seclabelCompareSecid(AttributeRelationId, securityId, -+ AttributeRelationId, HeapTupleGetSecid(tuple))) -+ ereport(ERROR, -+ (errcode(ERRCODE_DATATYPE_MISMATCH), -+ errmsg("child table \"%s\" has different label for column \"%s\"", -+ RelationGetRelationName(rel), colDef->colname))); -+ - /* If it's OID, child column must actually be OID */ - if (isOid && childatt->attnum != ObjectIdAttributeNumber) - ereport(ERROR, -@@ -3675,6 +3773,13 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, - errmsg("child table \"%s\" has a conflicting \"%s\" column", - RelationGetRelationName(rel), colDef->colname))); - -+ /* If it's SecID, child column must actually be SecID */ -+ if (isSecid && childatt->attnum != SecurityLabelAttributeNumber) -+ ereport(ERROR, -+ (errcode(ERRCODE_DATATYPE_MISMATCH), -+ errmsg("child table \"%s\" has a conflicting \"%s\" column", -+ RelationGetRelationName(rel), colDef->colname))); -+ - /* Bump the existing child att's inhcount */ - childatt->attinhcount++; - simple_heap_update(attrdesc, &tuple->t_self, tuple); -@@ -3714,6 +3819,8 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, - /* Determine the new attribute's number */ - if (isOid) - newattnum = ObjectIdAttributeNumber; -+ else if (isSecid) -+ newattnum = SecurityLabelAttributeNumber; - else - { - newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1; -@@ -3753,7 +3860,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, - - ReleaseSysCache(typeTuple); - -- InsertPgAttributeTuple(attrdesc, &attribute, NULL); -+ InsertPgAttributeTuple(attrdesc, &attribute, NULL, securityId); - - heap_close(attrdesc, RowExclusiveLock); - -@@ -3762,6 +3869,8 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, - */ - if (isOid) - ((Form_pg_class) GETSTRUCT(reltup))->relhasoids = true; -+ else if (isSecid) -+ ((Form_pg_class) GETSTRUCT(reltup))->relhassecids = true; - else - ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum; - -@@ -3873,7 +3982,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, - * If we are adding an OID column, we have to tell Phase 3 to rewrite the - * table to fix that. - */ -- if (isOid) -+ if (isOid || isSecid) - tab->new_changeoids = true; - - /* -@@ -3926,6 +4035,31 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd) - } - - /* -+ * ALTER TABLE SET WITH SECURITY LABEL -+ * -+ * Basically this is an ADD COLUMN for the special SecLabel column. -+ * We have to cons up a ColumnDef node because the ADD COLUMN code needs one. -+ */ -+static void -+ATPrepAddSecLabel(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd) -+{ -+ /* If we're recursing to a child table, the ColumnDef is already set up */ -+ if (cmd->def == NULL) -+ { -+ ColumnDef *cdef = makeNode(ColumnDef); -+ -+ cdef->colname = pstrdup("security_label"); -+ cdef->typeName = makeTypeNameFromOid(TEXTOID, -1); -+ cdef->inhcount = 0; -+ cdef->is_local = true; -+ cdef->is_not_null = true; -+ cdef->storage = 0; -+ cmd->def = (Node *) cdef; -+ } -+ ATPrepAddColumn(wqueue, rel, recurse, cmd); -+} -+ -+/* - * ALTER TABLE ALTER COLUMN DROP NOT NULL - */ - static void -@@ -3937,6 +4071,9 @@ ATExecDropNotNull(Relation rel, const char *colName) - List *indexoidlist; - ListCell *indexoidscan; - -+ /* SELinux checks */ -+ sepgsql_attribute_alter(RelationGetRelid(rel), colName); -+ - /* - * lookup the attribute - */ -@@ -4027,6 +4164,9 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel, - AttrNumber attnum; - Relation attr_rel; - -+ /* SELinux checks */ -+ sepgsql_attribute_alter(RelationGetRelid(rel), colName); -+ - /* - * lookup the attribute - */ -@@ -4077,6 +4217,9 @@ ATExecColumnDefault(Relation rel, const char *colName, - { - AttrNumber attnum; - -+ /* SELinux checks */ -+ sepgsql_attribute_alter(RelationGetRelid(rel), colName); -+ - /* - * get the number of the attribute - */ -@@ -4151,6 +4294,9 @@ ATExecSetStatistics(Relation rel, const char *colName, Node *newValue) - HeapTuple tuple; - Form_pg_attribute attrtuple; - -+ /* SELinux checks */ -+ sepgsql_attribute_alter(RelationGetRelid(rel), colName); -+ - Assert(IsA(newValue, Integer)); - newtarget = intVal(newValue); - -@@ -4217,6 +4363,9 @@ ATExecSetOptions(Relation rel, const char *colName, Node *options, - bool repl_null[Natts_pg_attribute]; - bool repl_repl[Natts_pg_attribute]; - -+ /* SELinux checks */ -+ sepgsql_attribute_alter(RelationGetRelid(rel), colName); -+ - attrelation = heap_open(AttributeRelationId, RowExclusiveLock); - - tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName); -@@ -4276,6 +4425,9 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue) - HeapTuple tuple; - Form_pg_attribute attrtuple; - -+ /* SELinux checks */ -+ sepgsql_attribute_alter(RelationGetRelid(rel), colName); -+ - Assert(IsA(newValue, String)); - storagemode = strVal(newValue); - -@@ -4374,6 +4526,9 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, - if (recursing) - ATSimplePermissions(rel, false); - -+ /* SELinux checks */ -+ sepgsql_attribute_drop(RelationGetRelid(rel), colName, false); -+ - /* - * get the number of the attribute - */ -@@ -4399,8 +4554,10 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, - - attnum = targetatt->attnum; - -- /* Can't drop a system attribute, except OID */ -- if (attnum <= 0 && attnum != ObjectIdAttributeNumber) -+ /* Can't drop a system attribute, except OID/SecID */ -+ if (attnum <= 0 && -+ attnum != ObjectIdAttributeNumber && -+ attnum != SecurityLabelAttributeNumber) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot drop system column \"%s\"", -@@ -4516,7 +4673,8 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, - * If we dropped the OID column, must adjust pg_class.relhasoids and tell - * Phase 3 to physically get rid of the column. - */ -- if (attnum == ObjectIdAttributeNumber) -+ if (attnum == ObjectIdAttributeNumber || -+ attnum == SecurityLabelAttributeNumber) - { - Relation class_rel; - Form_pg_class tuple_class; -@@ -4531,7 +4689,11 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, - RelationGetRelid(rel)); - tuple_class = (Form_pg_class) GETSTRUCT(tuple); - -- tuple_class->relhasoids = false; -+ if (attnum == ObjectIdAttributeNumber) -+ tuple_class->relhasoids = false; -+ if (attnum == SecurityLabelAttributeNumber) -+ tuple_class->relhassecids = false; -+ - simple_heap_update(class_rel, &tuple->t_self, tuple); - - /* Keep the catalog indexes up to date */ -@@ -4678,6 +4840,9 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, - if (recursing) - ATSimplePermissions(rel, false); - -+ /* SELinux checks */ -+ sepgsql_relation_alter(RelationGetRelid(rel)); -+ - /* - * Call AddRelationNewConstraints to do the work, making sure it works on - * a copy of the Constraint so transformExpr can't modify the original. It -@@ -4884,6 +5049,9 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, - checkFkeyPermissions(pkrel, pkattnum, numpks); - checkFkeyPermissions(rel, fkattnum, numfks); - -+ /* SELinux checks */ -+ sepgsql_relation_alter(RelationGetRelid(rel)); -+ - /* - * Look up the equality operators to use in the constraint. - * -@@ -5629,6 +5797,9 @@ ATExecDropConstraint(Relation rel, const char *constrName, - if (recursing) - ATSimplePermissions(rel, false); - -+ /* SELinux checks */ -+ sepgsql_relation_alter(RelationGetRelid(rel)); -+ - conrel = heap_open(ConstraintRelationId, RowExclusiveLock); - - /* -@@ -5966,6 +6137,9 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, - SysScanDesc scan; - HeapTuple depTup; - -+ /* SELinux checks */ -+ sepgsql_attribute_alter(RelationGetRelid(rel), colName); -+ - attrelation = heap_open(AttributeRelationId, RowExclusiveLock); - - /* Look up the target column */ -@@ -6596,6 +6770,8 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - } -+ /* SELinux checks */ -+ sepgsql_relation_alter(relationOid); - } - - memset(repl_null, false, sizeof(repl_null)); -@@ -6761,6 +6937,9 @@ ATExecClusterOn(Relation rel, const char *indexName) - { - Oid indexOid; - -+ /* SELinux checks */ -+ sepgsql_relation_alter(RelationGetRelid(rel)); -+ - indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace); - - if (!OidIsValid(indexOid)) -@@ -6785,6 +6964,9 @@ ATExecClusterOn(Relation rel, const char *indexName) - static void - ATExecDropCluster(Relation rel) - { -+ /* SELinux checks */ -+ sepgsql_relation_alter(RelationGetRelid(rel)); -+ - mark_index_clustered(rel, InvalidOid); - } - -@@ -6835,6 +7017,9 @@ ATExecSetRelOptions(Relation rel, List *defList, bool isReset) - bool repl_repl[Natts_pg_class]; - static char *validnsps[] = HEAP_RELOPT_NAMESPACES; - -+ /* SELinux checks */ -+ sepgsql_relation_alter(RelationGetRelid(rel)); -+ - if (defList == NIL) - return; /* nothing to do */ - -@@ -7163,6 +7348,9 @@ static void - ATExecEnableDisableTrigger(Relation rel, char *trigname, - char fires_when, bool skip_system) - { -+ /* SELinux checks */ -+ sepgsql_relation_alter(RelationGetRelid(rel)); -+ - EnableDisableTrigger(rel, trigname, fires_when, skip_system); - } - -@@ -7175,6 +7363,9 @@ static void - ATExecEnableDisableRule(Relation rel, char *trigname, - char fires_when) - { -+ /* SELinux checks */ -+ sepgsql_relation_alter(RelationGetRelid(rel)); -+ - EnableDisableRule(rel, trigname, fires_when); - } - -@@ -7217,6 +7408,10 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent) - */ - ATSimplePermissions(parent_rel, false); - -+ /* SELinux checks */ -+ sepgsql_relation_alter_inherit(RelationGetRelid(child_rel), -+ RelationGetRelid(parent_rel)); -+ - /* Permanent rels cannot inherit from temporary ones */ - if (parent_rel->rd_istemp && !child_rel->rd_istemp) - ereport(ERROR, -@@ -7569,6 +7764,9 @@ ATExecDropInherit(Relation rel, RangeVar *parent) - List *connames; - bool found = false; - -+ /* SELinux checks */ -+ sepgsql_relation_alter(RelationGetRelid(rel)); -+ - /* - * AccessShareLock on the parent is probably enough, seeing that DROP - * TABLE doesn't lock parent tables at all. We need some lock since we'll -@@ -7866,6 +8064,9 @@ AlterTableNamespace(RangeVar *relation, const char *newschema, - /* get schema OID and check its permissions */ - nspOid = LookupCreationNamespace(newschema); - -+ /* SELinux checks */ -+ sepgsql_relation_alter_schema(RelationGetRelid(rel), nspOid); -+ - if (oldNspOid == nspOid) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_TABLE), -@@ -8063,6 +8264,282 @@ AlterSeqNamespaces(Relation classRel, Relation rel, - relation_close(depRel, AccessShareLock); - } - -+/* -+ * ALTER TABLE/SEQUENCE/VIEW SECURITY LABEL TO -+ */ -+void -+AlterRelationSecLabelInternal(Oid relOid, Oid securityId, int expected_parents) -+{ -+ Form_pg_class classForm; -+ Relation targetRel; -+ Relation inhRel; -+ Relation classRel; -+ SysScanDesc scan; -+ ScanKeyData skey; -+ HeapTuple tuple; -+ List *indexList; -+ ListCell *cell; -+ int inhcount = 0; -+ -+ /* -+ * Grab an exclusive lock on the target table -+ */ -+ targetRel = relation_open(relOid, AccessExclusiveLock); -+ -+ /* -+ * Check num of inheritors -+ */ -+ inhRel = heap_open(InheritsRelationId, AccessShareLock); -+ -+ ScanKeyInit(&skey, -+ Anum_pg_inherits_inhrelid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(relOid)); -+ -+ scan = systable_beginscan(inhRel, InheritsRelidSeqnoIndexId, -+ true, SnapshotNow, 1, &skey); -+ while (HeapTupleIsValid(systable_getnext(scan))) -+ inhcount++; -+ -+ systable_endscan(scan); -+ -+ heap_close(inhRel, AccessShareLock); -+ -+ if (inhcount != expected_parents) -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION), -+ errmsg("cannot relabel inherited relation"))); -+ -+ /* -+ * Update pg_class relation -+ */ -+ classRel = heap_open(RelationRelationId, RowExclusiveLock); -+ -+ tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for relation %u", relOid); -+ -+ classForm = (Form_pg_class) GETSTRUCT(tuple); -+ -+ HeapTupleSetSecid(tuple, securityId); -+ -+ simple_heap_update(classRel, &tuple->t_self, tuple); -+ -+ CatalogUpdateIndexes(classRel, tuple); -+ -+ heap_close(classRel, RowExclusiveLock); -+ -+ /* -+ * Also update TOAST and INDEX -+ */ -+ if (OidIsValid(classForm->reltoastrelid)) -+ AlterRelationSecLabelInternal(classForm->reltoastrelid, -+ securityId, 0); -+ -+ indexList = RelationGetIndexList(targetRel); -+ foreach (cell, indexList) -+ AlterRelationSecLabelInternal(lfirst_oid(cell), securityId, 0); -+ -+ /* -+ * Also update pg_attribute, if not RELKIND_RELATION -+ */ -+ if (classForm->relkind != RELKIND_RELATION) -+ { -+ Relation attRel; -+ HeapTuple oldtup, newtup; -+ Oid attsecid; -+ -+ /* move security-id to pg_attribtue catalog */ -+ attsecid = seclabelMoveSecid(AttributeRelationId, -+ RelationRelationId, -+ securityId); -+ -+ attRel = heap_open(AttributeRelationId, RowExclusiveLock); -+ -+ ScanKeyInit(&skey, -+ Anum_pg_attribute_attrelid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(RelationGetRelid(targetRel))); -+ -+ scan = systable_beginscan(attRel, AttributeRelidNumIndexId, true, -+ SnapshotNow, 1, &skey); -+ while (HeapTupleIsValid(oldtup = systable_getnext(scan))) -+ { -+ Form_pg_attribute attForm -+ = (Form_pg_attribute) GETSTRUCT(oldtup); -+ -+ if (attForm->attinhcount > 0) -+ elog(ERROR, "Bug? attinhcount is %d at %s of %s", -+ attForm->attinhcount, NameStr(attForm->attname), -+ RelationGetRelationName(targetRel)); -+ -+ newtup = heap_copytuple(oldtup); -+ -+ HeapTupleSetSecid(newtup, attsecid); -+ -+ simple_heap_update(attRel, &newtup->t_self, newtup); -+ -+ CatalogUpdateIndexes(attRel, newtup); -+ } -+ systable_endscan(scan); -+ -+ heap_close(attRel, RowExclusiveLock); -+ } -+ -+ heap_close(targetRel, NoLock); /* close rel but keep lock */ -+} -+ -+void -+AlterAttributeSecLabelInternal(Oid relOid, const char *attname, -+ Oid securityId, int expected_parents) -+{ -+ Form_pg_attribute attForm; -+ Relation targetRel; -+ Relation attRel; -+ HeapTuple tuple; -+ -+ /* -+ * Grab an exclusive lock on the target table, which we will NOT -+ * release until end of transaction. -+ */ -+ targetRel = heap_open(relOid, AccessExclusiveLock); -+ -+ attRel = heap_open(AttributeRelationId, RowExclusiveLock); -+ -+ tuple = SearchSysCacheCopyAttName(relOid, attname); -+ if (!HeapTupleIsValid(tuple)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_COLUMN), -+ errmsg("column \"%s\" does not exist", attname))); -+ -+ attForm = (Form_pg_attribute) GETSTRUCT(tuple); -+#if 0 -+ /* -+ * XXX - here is no active reason why we forbid to relabel -+ * system columns. -+ */ -+ if (attForm->attnum <= 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("cannot relabel system column \"%s\"", attname))); -+#endif -+ if (attForm->attinhcount > expected_parents) -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION), -+ errmsg("cannot relabel inherited column \"%s\"", attname))); -+ -+ /* update pg_attribute */ -+ HeapTupleSetSecid(tuple, securityId); -+ -+ simple_heap_update(attRel, &tuple->t_self, tuple); -+ -+ CatalogUpdateIndexes(attRel, tuple); -+ -+ heap_close(attRel, RowExclusiveLock); -+ -+ heap_close(targetRel, NoLock); /* close rel but keep lock */ -+} -+ -+void -+AlterRelationSecLabel(RangeVar *relation, const char *attname, -+ ObjectType objtype, char *new_label) -+{ -+ Oid relOid = RangeVarGetRelid(relation, false); -+ Oid securityId; -+ char relkind; -+ List *child_oids, *child_numparents; -+ ListCell *lo, *li; -+ -+ /* -+ * Sanity checks for relation types -+ */ -+ relkind = get_rel_relkind(relOid); -+ switch (objtype) -+ { -+ case OBJECT_TABLE: -+ Assert(attname == NULL); -+ if (relkind != RELKIND_RELATION && -+ relkind != RELKIND_SEQUENCE && -+ relkind != RELKIND_VIEW) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not a table, sequence or view", -+ get_rel_name(relOid)))); -+ break; -+ -+ case OBJECT_SEQUENCE: -+ Assert(attname == NULL); -+ if (relkind != RELKIND_SEQUENCE) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not a sequence", -+ get_rel_name(relOid)))); -+ break; -+ -+ case OBJECT_VIEW: -+ Assert(attname == NULL); -+ if (relkind != RELKIND_VIEW) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not a view", -+ get_rel_name(relOid)))); -+ break; -+ -+ case OBJECT_COLUMN: -+ Assert(attname != NULL); -+ if (relkind != RELKIND_RELATION) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not a table", -+ get_rel_name(relOid)))); -+ break; -+ -+ default: -+ elog(ERROR, "Bug? unexpected object type %d", objtype); -+ break; -+ } -+ -+ /* -+ * Recursive calls to child relations including myself -+ */ -+ child_oids = find_all_inheritors(relOid, -+ AccessExclusiveLock, -+ &child_numparents); -+ forboth (lo, child_oids, li, child_numparents) -+ { -+ Oid childOid = lfirst_oid(lo); -+ int numParents = lfirst_int(li); -+ Oid relnsp = get_rel_namespace(childOid); -+ -+ /* Permission checks */ -+ if (!pg_class_ownercheck(childOid, GetUserId())) -+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, -+ get_rel_name(childOid)); -+ -+ if (!allowSystemTableMods && -+ (IsSystemNamespace(relnsp) || IsToastNamespace(relnsp))) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("permission denied: \"%s\" is a system catalog", -+ get_rel_name(childOid)))); -+ -+ /* SELinux checks */ -+ if (objtype != OBJECT_COLUMN) -+ securityId = sepgsql_relation_relabel(childOid, -+ new_label); -+ else -+ securityId = sepgsql_attribute_relabel(childOid, attname, -+ new_label); -+ -+ /* Do work */ -+ if (objtype != OBJECT_COLUMN) -+ AlterRelationSecLabelInternal(childOid, -+ securityId, numParents); -+ else -+ AlterAttributeSecLabelInternal(childOid, attname, -+ securityId, numParents); -+ } -+} - - /* - * This code supports -diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c -index 4c57a73..ce0bb99 100644 ---- a/src/backend/commands/tablespace.c -+++ b/src/backend/commands/tablespace.c -@@ -65,6 +65,7 @@ - #include "commands/tablespace.h" - #include "miscadmin.h" - #include "postmaster/bgwriter.h" -+#include "sepgsql/hooks.h" - #include "storage/fd.h" - #include "storage/procarray.h" - #include "storage/standby.h" -@@ -235,6 +236,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) - Oid tablespaceoid; - char *location; - Oid ownerId; -+ Oid securityId; - - /* Must be super user */ - if (!superuser()) -@@ -244,6 +246,9 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) - stmt->tablespacename), - errhint("Must be superuser to create a tablespace."))); - -+ /* SELinux check */ -+ securityId = sepgsql_tablespace_create(stmt->tablespacename); -+ - /* However, the eventual owner of the tablespace need not be */ - if (stmt->owner) - ownerId = get_roleid_checked(stmt->owner); -@@ -324,6 +329,8 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) - - tuple = heap_form_tuple(rel->rd_att, values, nulls); - -+ HeapTupleSetSecid(tuple, securityId); -+ - tablespaceoid = simple_heap_insert(rel, tuple); - - CatalogUpdateIndexes(rel, tuple); -@@ -429,6 +436,9 @@ DropTableSpace(DropTableSpaceStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, - tablespacename); - -+ /* SELinux checks */ -+ sepgsql_tablespace_drop(tablespaceoid, false); -+ - /* Disallow drop of the standard tablespaces, even by superuser */ - if (tablespaceoid == GLOBALTABLESPACE_OID || - tablespaceoid == DEFAULTTABLESPACE_OID) -@@ -817,6 +827,9 @@ RenameTableSpace(const char *oldname, const char *newname) - if (!pg_tablespace_ownercheck(HeapTupleGetOid(newtuple), GetUserId())) - aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, oldname); - -+ /* SELinux checks */ -+ sepgsql_tablespace_alter(HeapTupleGetOid(newtuple)); -+ - /* Validate new name */ - if (!allowSystemTableMods && IsReservedName(newname)) - ereport(ERROR, -@@ -898,6 +911,9 @@ AlterTableSpaceOwner(const char *name, Oid newOwnerId) - /* Must be able to become new owner */ - check_is_member_of_role(GetUserId(), newOwnerId); - -+ /* SELinux checks */ -+ sepgsql_tablespace_alter(HeapTupleGetOid(tup)); -+ - /* - * Normally we would also check for create permissions here, but there - * are none for tablespaces so we follow what rename tablespace does -@@ -1015,6 +1031,54 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) - } - - /* -+ * ALTER TABLESPACE xxx SECURITY LABEL TO ... -+ */ -+void -+AlterTableSpaceSecLabel(const char *tspaceName, char *newLabel) -+{ -+ Relation rel; -+ ScanKeyData skey; -+ HeapScanDesc scan; -+ HeapTuple oldtup; -+ HeapTuple newtup; -+ Oid securityId; -+ -+ rel = heap_open(TableSpaceRelationId, RowExclusiveLock); -+ -+ /* scan pg_tablespace catalog */ -+ ScanKeyInit(&skey, -+ Anum_pg_tablespace_spcname, -+ BTEqualStrategyNumber, F_NAMEEQ, -+ CStringGetDatum(tspaceName)); -+ scan = heap_beginscan(rel, SnapshotNow, 1, &skey); -+ oldtup = heap_getnext(scan, ForwardScanDirection); -+ if (!HeapTupleIsValid(oldtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_OBJECT), -+ errmsg("tablespace \"%s\" does not exist", tspaceName))); -+ -+ /* Must be owner */ -+ if (!pg_tablespace_ownercheck(HeapTupleGetOid(oldtup), GetUserId())) -+ aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, tspaceName); -+ -+ /* SELinux checks */ -+ securityId = sepgsql_tablespace_relabel(HeapTupleGetSecid(oldtup), newLabel); -+ -+ /* update it */ -+ newtup = heap_copytuple(oldtup); -+ -+ HeapTupleSetSecid(newtup, securityId); -+ -+ simple_heap_update(rel, &newtup->t_self, newtup); -+ -+ CatalogUpdateIndexes(rel, newtup); -+ -+ heap_endscan(scan); -+ -+ heap_close(rel, RowExclusiveLock); -+} -+ -+/* - * Routines for handling the GUC variable 'default_tablespace'. - */ - -diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c -index 251c3e8..2f7d3d5 100644 ---- a/src/backend/commands/trigger.c -+++ b/src/backend/commands/trigger.c -@@ -40,6 +40,7 @@ - #include "parser/parsetree.h" - #include "pgstat.h" - #include "rewrite/rewriteManip.h" -+#include "sepgsql/hooks.h" - #include "storage/bufmgr.h" - #include "tcop/utility.h" - #include "utils/acl.h" -@@ -330,6 +331,10 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, - NameListToString(stmt->funcname)))); - } - -+ /* SELinux checks */ -+ sepgsql_trigger_create(RelationGetRelid(rel), stmt->trigname, -+ constrrelid, funcoid); -+ - /* - * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that - * references one of the built-in RI_FKey trigger functions, assume it is -@@ -1007,6 +1012,9 @@ DropTrigger(Oid relid, const char *trigname, DropBehavior behavior, - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - get_rel_name(relid)); - -+ /* SELinux checks */ -+ sepgsql_trigger_drop(relid, trigname, false); -+ - object.classId = TriggerRelationId; - object.objectId = HeapTupleGetOid(tup); - object.objectSubId = 0; -@@ -1116,6 +1124,9 @@ renametrig(Oid relid, - SysScanDesc tgscan; - ScanKeyData key[2]; - -+ /* SELinux checks */ -+ sepgsql_trigger_alter(relid, oldname); -+ - /* - * Grab an exclusive lock on the target table, which we will NOT release - * until end of transaction. -diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c -index 522ea6e..8c6e0d3 100644 ---- a/src/backend/commands/tsearchcmds.c -+++ b/src/backend/commands/tsearchcmds.c -@@ -35,6 +35,7 @@ - #include "miscadmin.h" - #include "nodes/makefuncs.h" - #include "parser/parse_func.h" -+#include "sepgsql/hooks.h" - #include "tsearch/ts_cache.h" - #include "tsearch/ts_public.h" - #include "tsearch/ts_utils.h" -@@ -171,6 +172,7 @@ DefineTSParser(List *names, List *parameters) - NameData pname; - Oid prsOid; - Oid namespaceoid; -+ Oid securityId; - - if (!superuser()) - ereport(ERROR, -@@ -250,6 +252,14 @@ DefineTSParser(List *names, List *parameters) - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("text search parser lextypes method is required"))); - -+ /* SELinux checks */ -+ securityId = sepgsql_ts_parser_create(prsname, namespaceoid, -+ DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1]), -+ DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1]), -+ DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1]), -+ DatumGetObjectId(values[Anum_pg_ts_parser_prsheadline - 1]), -+ DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1])); -+ - /* - * Looks good, insert - */ -@@ -257,6 +267,8 @@ DefineTSParser(List *names, List *parameters) - - tup = heap_form_tuple(prsRel->rd_att, values, nulls); - -+ HeapTupleSetSecid(tup, securityId); -+ - prsOid = simple_heap_insert(prsRel, tup); - - CatalogUpdateIndexes(prsRel, tup); -@@ -314,6 +326,8 @@ RemoveTSParsers(DropStmt *drop) - } - continue; - } -+ /* SELinux checks */ -+ sepgsql_ts_parser_drop(prsOid, false); - - object.classId = TSParserRelationId; - object.objectId = prsOid; -@@ -366,10 +380,13 @@ RenameTSParser(List *oldname, const char *newname) - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to rename text search parsers"))); - -- rel = heap_open(TSParserRelationId, RowExclusiveLock); -- - prsId = TSParserGetPrsid(oldname, false); - -+ /* SELinux checks */ -+ sepgsql_ts_parser_alter_rename(prsId, newname); -+ -+ rel = heap_open(TSParserRelationId, RowExclusiveLock); -+ - tup = SearchSysCacheCopy1(TSPARSEROID, ObjectIdGetDatum(prsId)); - - if (!HeapTupleIsValid(tup)) /* should not happen */ -@@ -496,6 +513,7 @@ DefineTSDictionary(List *names, List *parameters) - List *dictoptions = NIL; - Oid dictOid; - Oid namespaceoid; -+ Oid securityId; - AclResult aclresult; - char *dictname; - -@@ -508,6 +526,9 @@ DefineTSDictionary(List *names, List *parameters) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceoid)); - -+ /* SELinux checks */ -+ securityId = sepgsql_ts_dict_create(dictname, namespaceoid); -+ - /* - * loop over the definition list and extract the information we need. - */ -@@ -557,6 +578,8 @@ DefineTSDictionary(List *names, List *parameters) - - tup = heap_form_tuple(dictRel->rd_att, values, nulls); - -+ HeapTupleSetSecid(tup, securityId); -+ - dictOid = simple_heap_insert(dictRel, tup); - - CatalogUpdateIndexes(dictRel, tup); -@@ -610,6 +633,8 @@ RenameTSDictionary(List *oldname, const char *newname) - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); -+ /* SELinux checks */ -+ sepgsql_ts_dict_alter_rename(dictId, newname); - - namestrcpy(&(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname), newname); - simple_heap_update(rel, &tup->t_self, tup); -@@ -674,6 +699,8 @@ RemoveTSDictionaries(DropStmt *drop) - !pg_namespace_ownercheck(namespaceId, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY, - NameListToString(names)); -+ /* SELinux checks */ -+ sepgsql_ts_dict_drop(dictOid, false); - - object.classId = TSDictionaryRelationId; - object.objectId = dictOid; -@@ -745,6 +772,8 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt) - if (!pg_ts_dict_ownercheck(dictId, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY, - NameListToString(stmt->dictname)); -+ /* SELinux checks */ -+ sepgsql_ts_dict_alter(dictId); - - /* deserialize the existing set of options */ - opt = SysCacheGetAttr(TSDICTOID, tup, -@@ -871,6 +900,8 @@ AlterTSDictionaryOwner(List *name, Oid newOwnerId) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - } -+ /* SELinux checks */ -+ sepgsql_ts_dict_alter(dictId); - - form->dictowner = newOwnerId; - -@@ -982,6 +1013,7 @@ DefineTSTemplate(List *names, List *parameters) - int i; - Oid dictOid; - Oid namespaceoid; -+ Oid securityId; - char *tmplname; - - if (!superuser()) -@@ -1036,6 +1068,10 @@ DefineTSTemplate(List *names, List *parameters) - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("text search template lexize method is required"))); - -+ /* SELinux checks */ -+ securityId = sepgsql_ts_template_create(tmplname, namespaceoid, -+ DatumGetObjectId(values[Anum_pg_ts_template_tmplinit - 1]), -+ DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1])); - /* - * Looks good, insert - */ -@@ -1044,6 +1080,8 @@ DefineTSTemplate(List *names, List *parameters) - - tup = heap_form_tuple(tmplRel->rd_att, values, nulls); - -+ HeapTupleSetSecid(tup, securityId); -+ - dictOid = simple_heap_insert(tmplRel, tup); - - CatalogUpdateIndexes(tmplRel, tup); -@@ -1075,6 +1113,9 @@ RenameTSTemplate(List *oldname, const char *newname) - - tmplId = TSTemplateGetTmplid(oldname, false); - -+ /* SELinux checks */ -+ sepgsql_ts_template_alter_rename(tmplId, newname); -+ - tup = SearchSysCacheCopy1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId)); - - if (!HeapTupleIsValid(tup)) /* should not happen */ -@@ -1145,6 +1186,8 @@ RemoveTSTemplates(DropStmt *drop) - } - continue; - } -+ /* SELinux checks */ -+ sepgsql_ts_template_drop(tmplOid, false); - - object.classId = TSTemplateRelationId; - object.objectId = tmplOid; -@@ -1305,6 +1348,7 @@ DefineTSConfiguration(List *names, List *parameters) - bool nulls[Natts_pg_ts_config]; - AclResult aclresult; - Oid namespaceoid; -+ Oid securityId; - char *cfgname; - NameData cname; - Oid sourceOid = InvalidOid; -@@ -1321,6 +1365,9 @@ DefineTSConfiguration(List *names, List *parameters) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceoid)); - -+ /* SELinux checks */ -+ securityId = sepgsql_ts_config_create(cfgname, namespaceoid); -+ - /* - * loop over the definition list and extract the information we need. - */ -@@ -1388,6 +1435,8 @@ DefineTSConfiguration(List *names, List *parameters) - - tup = heap_form_tuple(cfgRel->rd_att, values, nulls); - -+ HeapTupleSetSecid(tup, securityId); -+ - cfgOid = simple_heap_insert(cfgRel, tup); - - CatalogUpdateIndexes(cfgRel, tup); -@@ -1489,6 +1538,9 @@ RenameTSConfiguration(List *oldname, const char *newname) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux checks */ -+ sepgsql_ts_config_alter_rename(cfgId, newname); -+ - namestrcpy(&(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname), newname); - simple_heap_update(rel, &tup->t_self, tup); - CatalogUpdateIndexes(rel, tup); -@@ -1549,6 +1601,9 @@ RemoveTSConfigurations(DropStmt *drop) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, - NameListToString(names)); - -+ /* SELinux checks */ -+ sepgsql_ts_config_drop(cfgOid, false); -+ - object.classId = TSConfigRelationId; - object.objectId = cfgOid; - object.objectSubId = 0; -@@ -1656,6 +1711,8 @@ AlterTSConfigurationOwner(List *name, Oid newOwnerId) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - } -+ /* SELinux checks */ -+ sepgsql_ts_config_alter(cfgId); - - form->cfgowner = newOwnerId; - -@@ -1693,6 +1750,9 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, - NameListToString(stmt->cfgname)); - -+ /* SELinux checks */ -+ sepgsql_ts_config_alter(HeapTupleGetOid(tup)); -+ - relMap = heap_open(TSConfigMapRelationId, RowExclusiveLock); - - /* Add or drop mappings */ -diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c -index abde562..a5cf445 100644 ---- a/src/backend/commands/typecmds.c -+++ b/src/backend/commands/typecmds.c -@@ -56,6 +56,7 @@ - #include "parser/parse_expr.h" - #include "parser/parse_func.h" - #include "parser/parse_type.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -@@ -143,6 +144,8 @@ DefineType(List *names, List *parameters) - char *array_type; - Oid array_oid; - Oid typoid; -+ Oid type_replaced; -+ Oid securityId; - Oid resulttype; - ListCell *pl; - -@@ -520,6 +523,15 @@ DefineType(List *names, List *parameters) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - NameListToString(analyzeName)); - #endif -+ /* SELinux checks */ -+ type_replaced = GetSysCacheOid2(TYPENAMENSP, -+ CStringGetDatum(typeName), -+ ObjectIdGetDatum(typeNamespace)); -+ securityId = sepgsql_type_create(typeName, type_replaced, -+ typeNamespace, TYPTYPE_BASE, -+ inputOid, outputOid, -+ receiveOid, sendOid, -+ typmodinOid, typmodoutOid, analyzeOid); - - array_oid = AssignTypeArrayOid(); - -@@ -562,7 +574,8 @@ DefineType(List *names, List *parameters) - storage, /* TOAST strategy */ - -1, /* typMod (Domains only) */ - 0, /* Array Dimensions of typbasetype */ -- false); /* Type NOT NULL */ -+ false, /* Type NOT NULL */ -+ securityId); /* security-id of the type */ - - /* - * Create the array type that goes with it. -@@ -601,7 +614,8 @@ DefineType(List *names, List *parameters) - 'x', /* ARRAY is always toastable */ - -1, /* typMod (Domains only) */ - 0, /* Array dimensions of typbasetype */ -- false); /* Type NOT NULL */ -+ false, /* Type NOT NULL */ -+ securityId); /* security-id of the type */ - - pfree(array_type); - } -@@ -668,6 +682,9 @@ RemoveTypes(DropStmt *drop) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, - format_type_be(typeoid)); - -+ /* SELinux checks */ -+ sepgsql_type_drop(typeoid, false); -+ - if (drop->removeType == OBJECT_DOMAIN) - { - /* Check that this is actually a domain */ -@@ -766,6 +783,7 @@ DefineDomain(CreateDomainStmt *stmt) - Oid basetypeoid; - Oid domainoid; - Oid old_type_oid; -+ Oid securityId; - Form_pg_type baseType; - int32 basetypeMod; - -@@ -1011,6 +1029,13 @@ DefineDomain(CreateDomainStmt *stmt) - } - } - -+ /* SELinux checks */ -+ securityId = sepgsql_type_create(domainName, InvalidOid, -+ domainNamespace, TYPTYPE_DOMAIN, -+ inputProcedure, outputProcedure, -+ receiveProcedure, sendProcedure, -+ InvalidOid, InvalidOid, analyzeProcedure); -+ - /* - * Have TypeCreate do all the real work. - */ -@@ -1044,7 +1069,8 @@ DefineDomain(CreateDomainStmt *stmt) - storage, /* TOAST strategy */ - basetypeMod, /* typeMod value */ - typNDims, /* Array dimensions for base type */ -- typNotNull); /* Type NOT NULL */ -+ typNotNull, /* Type NOT NULL */ -+ securityId); /* security-id of the type */ - - /* - * Process constraints which refer to the domain ID returned by TypeCreate -@@ -1094,6 +1120,7 @@ DefineEnum(CreateEnumStmt *stmt) - AclResult aclresult; - Oid old_type_oid; - Oid enumArrayOid; -+ Oid securityId; - - /* Convert list of names to a name and namespace */ - enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName, -@@ -1120,6 +1147,13 @@ DefineEnum(CreateEnumStmt *stmt) - errmsg("type \"%s\" already exists", enumName))); - } - -+ /* SELinux checks */ -+ securityId = sepgsql_type_create(enumName, old_type_oid, -+ enumNamespace, TYPTYPE_ENUM, -+ F_ENUM_IN, F_ENUM_OUT, -+ F_ENUM_RECV, F_ENUM_SEND, -+ InvalidOid, InvalidOid, InvalidOid); -+ - enumArrayOid = AssignTypeArrayOid(); - - /* Create the pg_type entry */ -@@ -1153,7 +1187,8 @@ DefineEnum(CreateEnumStmt *stmt) - 'p', /* TOAST strategy always plain */ - -1, /* typMod (Domains only) */ - 0, /* Array dimensions of typbasetype */ -- false); /* Type NOT NULL */ -+ false, /* Type NOT NULL */ -+ securityId); /* security-id of the type */ - - /* Enter the enum's values into pg_enum */ - EnumValuesCreate(enumTypeOid, stmt->vals, InvalidOid); -@@ -1192,7 +1227,8 @@ DefineEnum(CreateEnumStmt *stmt) - 'x', /* ARRAY is always toastable */ - -1, /* typMod (Domains only) */ - 0, /* Array dimensions of typbasetype */ -- false); /* Type NOT NULL */ -+ false, /* Type NOT NULL */ -+ securityId); /* security-id of the type */ - - pfree(enumArrayName); - } -@@ -1585,6 +1621,8 @@ AlterDomainDefault(List *names, Node *defaultRaw) - /* Check it's a domain and check user has permission for ALTER DOMAIN */ - checkDomainOwner(tup, typename); - -+ sepgsql_type_alter(domainoid); -+ - /* Setup new tuple */ - MemSet(new_record, (Datum) 0, sizeof(new_record)); - MemSet(new_record_nulls, false, sizeof(new_record_nulls)); -@@ -1711,6 +1749,8 @@ AlterDomainNotNull(List *names, bool notNull) - /* Check it's a domain and check user has permission for ALTER DOMAIN */ - checkDomainOwner(tup, typename); - -+ sepgsql_type_alter(domainoid); -+ - /* Is the domain already set to the desired constraint? */ - if (typTup->typnotnull == notNull) - { -@@ -1810,6 +1850,8 @@ AlterDomainDropConstraint(List *names, const char *constrName, - /* Check it's a domain and check user has permission for ALTER DOMAIN */ - checkDomainOwner(tup, typename); - -+ sepgsql_type_alter(domainoid); -+ - /* Grab an appropriate lock on the pg_constraint relation */ - conrel = heap_open(ConstraintRelationId, RowExclusiveLock); - -@@ -1884,6 +1926,8 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) - /* Check it's a domain and check user has permission for ALTER DOMAIN */ - checkDomainOwner(tup, typename); - -+ sepgsql_type_alter(domainoid); -+ - if (!IsA(newConstraint, Constraint)) - elog(ERROR, "unrecognized node type: %d", - (int) nodeTag(newConstraint)); -@@ -2507,6 +2551,9 @@ RenameType(List *names, const char *newTypeName) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, - format_type_be(typeOid)); - -+ /* SELinux checks */ -+ sepgsql_type_alter_rename(typeOid, newTypeName); -+ - /* - * If it's a composite type, we need to check that it really is a - * free-standing composite type, and not a table's rowtype. We want people -@@ -2627,6 +2674,8 @@ AlterTypeOwner(List *names, Oid newOwnerId) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(typTup->typnamespace)); - } -+ /* SELinux checks */ -+ sepgsql_type_alter(HeapTupleGetOid(tup)); - - /* - * If it's a composite type, invoke ATExecChangeOwner so that we fix -@@ -2731,6 +2780,9 @@ AlterTypeNamespace(List *names, const char *newschema) - /* get schema OID and check its permissions */ - nspOid = LookupCreationNamespace(newschema); - -+ /* SELinux checks */ -+ sepgsql_type_alter_schema(typeOid, nspOid); -+ - /* don't allow direct alteration of array types */ - elemOid = get_element_type(typeOid); - if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid) -@@ -2882,3 +2934,100 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, - if (OidIsValid(arrayOid)) - AlterTypeNamespaceInternal(arrayOid, nspOid, true, true); - } -+ -+/* -+ * ALTER TYPE xxx SECURITY LABEL TO ... -+ */ -+void -+AlterTypeSecLabelInternal(Oid typeOid, Oid securityId) -+{ -+ Relation typeRel; -+ Form_pg_type typeForm; -+ HeapTuple tuple; -+ -+ typeRel = heap_open(TypeRelationId, RowExclusiveLock); -+ -+ tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for type %u", typeOid); -+ typeForm = (Form_pg_type) GETSTRUCT(tuple); -+ -+ /* update it */ -+ HeapTupleSetSecid(tuple, securityId); -+ -+ simple_heap_update(typeRel, &tuple->t_self, tuple); -+ -+ CatalogUpdateIndexes(typeRel, tuple); -+ -+ /* if it is a composit type, update pg_class too */ -+ if (OidIsValid(typeForm->typrelid)) -+ { -+ Oid classSecId = seclabelMoveSecid(RelationRelationId, -+ TypeRelationId, -+ securityId); -+ AlterRelationSecLabelInternal(typeForm->typrelid, classSecId, 0); -+ } -+ -+ /* if it has an array type, update that too */ -+ if (OidIsValid(typeForm->typarray)) -+ AlterTypeSecLabelInternal(typeForm->typarray, securityId); -+ -+ heap_freetuple(tuple); -+ -+ heap_close(typeRel, RowExclusiveLock); -+} -+ -+void -+AlterTypeSecLabel(List *names, char *new_label) -+{ -+ Form_pg_type typeForm; -+ HeapTuple typtup; -+ TypeName *typename; -+ Oid typeOid; -+ Oid securityId; -+ -+ /* resolve type name */ -+ typename = makeTypeNameFromNameList(names); -+ typtup = LookupTypeName(NULL, typename, NULL); -+ if (!HeapTupleIsValid(typtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_OBJECT), -+ errmsg("type \"%s\" does not exist", -+ TypeNameToString(typename)))); -+ -+ typeForm = (Form_pg_type) GETSTRUCT(typtup); -+ typeOid = HeapTupleGetOid(typtup); -+ -+ /* -+ * If it's a composite type, we need to check that it really is a -+ * free-standing composite type, and not a table's rowtype. We want people -+ * to use ALTER TABLE not ALTER TYPE for that case. -+ */ -+ if (typeForm->typtype == TYPTYPE_COMPOSITE && -+ get_rel_relkind(typeForm->typrelid) != RELKIND_COMPOSITE_TYPE) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("%s is a table's row type", -+ format_type_be(typeOid)), -+ errhint("Use ALTER TABLE instead."))); -+ -+ /* don't allow direct alteration of array types, either */ -+ if (OidIsValid(typeForm->typelem) && -+ get_array_type(typeForm->typelem) == typeOid) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("cannot alter array type %s", -+ format_type_be(typeOid)))); -+ -+ /* DAC permission checks */ -+ if (!pg_type_ownercheck(typeOid, GetUserId())) -+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, -+ format_type_be(typeOid)); -+ -+ /* SELinux checks */ -+ securityId = sepgsql_type_relabel(typeOid, new_label); -+ -+ AlterTypeSecLabelInternal(typeOid, securityId); -+ -+ ReleaseSysCache(typtup); -+} -diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c -index cdf7dc5..f6aee43 100644 ---- a/src/backend/commands/user.c -+++ b/src/backend/commands/user.c -@@ -21,11 +21,13 @@ - #include "catalog/pg_authid.h" - #include "catalog/pg_database.h" - #include "catalog/pg_db_role_setting.h" -+#include "catalog/pg_seclabel.h" - #include "commands/comment.h" - #include "commands/dbcommands.h" - #include "commands/user.h" - #include "libpq/md5.h" - #include "miscadmin.h" -+#include "sepgsql/hooks.h" - #include "storage/lmgr.h" - #include "utils/acl.h" - #include "utils/builtins.h" -@@ -111,6 +113,7 @@ CreateRole(CreateRoleStmt *stmt) - DefElem *drolemembers = NULL; - DefElem *dadminmembers = NULL; - DefElem *dvalidUntil = NULL; -+ Oid securityId; - - /* The defaults can vary depending on the original statement type */ - switch (stmt->stmt_type) -@@ -279,6 +282,9 @@ CreateRole(CreateRoleStmt *stmt) - errmsg("permission denied to create role"))); - } - -+ /* SELinux checks */ -+ securityId = sepgsql_role_create(stmt->role); -+ - if (strcmp(stmt->role, "public") == 0 || - strcmp(stmt->role, "none") == 0) - ereport(ERROR, -@@ -365,6 +371,8 @@ CreateRole(CreateRoleStmt *stmt) - - tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls); - -+ HeapTupleSetSecid(tuple, securityId); -+ - /* - * Insert new record in the pg_authid table - */ -@@ -606,6 +614,8 @@ AlterRole(AlterRoleStmt *stmt) - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied"))); - } -+ /* SELinux checks */ -+ sepgsql_role_alter(roleid); - - /* Convert validuntil to internal form */ - if (validUntil) -@@ -791,6 +801,8 @@ AlterRoleSet(AlterRoleSetStmt *stmt) - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied"))); - } -+ /* SELinux checks */ -+ sepgsql_role_alter(HeapTupleGetOid(roletuple)); - - /* look up and lock the database, if specified */ - if (stmt->database != NULL) -@@ -886,6 +898,9 @@ DropRole(DropRoleStmt *stmt) - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to drop superusers"))); - -+ /* SELinux checks */ -+ sepgsql_role_drop(roleid, false); -+ - /* - * Lock the role, so nobody can add dependencies to her while we drop - * her. We keep the lock until the end of transaction. -@@ -1282,6 +1297,9 @@ AddRoleMems(const char *rolename, Oid roleid, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to set grantor"))); - -+ /* SELinux checks */ -+ sepgsql_role_grant(roleid, true, memberIds); -+ - pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock); - pg_authmem_dsc = RelationGetDescr(pg_authmem_rel); - -@@ -1412,6 +1430,8 @@ DelRoleMems(const char *rolename, Oid roleid, - errmsg("must have admin option on role \"%s\"", - rolename))); - } -+ /* SELinux checks */ -+ sepgsql_role_grant(roleid, false, memberIds); - - pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock); - pg_authmem_dsc = RelationGetDescr(pg_authmem_rel); -diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c -index e77430e..3dfc7d4 100644 ---- a/src/backend/commands/vacuum.c -+++ b/src/backend/commands/vacuum.c -@@ -957,6 +957,9 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound, - */ - if (vacstmt->options & VACOPT_FULL) - { -+ /* Also reclaim unreferenced security labels */ -+ seclabelRelationReclaim(relid); -+ - /* close relation before vacuuming, but hold lock until commit */ - relation_close(onerel, NoLock); - onerel = NULL; -diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c -index c291529..dd0b12a 100644 ---- a/src/backend/commands/view.c -+++ b/src/backend/commands/view.c -@@ -28,6 +28,7 @@ - #include "rewrite/rewriteDefine.h" - #include "rewrite/rewriteManip.h" - #include "rewrite/rewriteSupport.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -@@ -167,6 +168,9 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(rel)); - -+ /* SELinux checks */ -+ sepgsql_view_replace(viewOid); -+ - /* Also check it's not in use already */ - CheckTableNotInUse(rel, "CREATE OR REPLACE VIEW"); - -diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c -index da22709..cbd4932 100644 ---- a/src/backend/executor/execJunk.c -+++ b/src/backend/executor/execJunk.c -@@ -58,7 +58,8 @@ - * An optional resultSlot can be passed as well. - */ - JunkFilter * --ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot) -+ExecInitJunkFilter(List *targetList, bool hasoid, bool hassecid, -+ TupleTableSlot *slot) - { - JunkFilter *junkfilter; - TupleDesc cleanTupType; -@@ -70,7 +71,7 @@ ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot) - /* - * Compute the tuple descriptor for the cleaned tuple. - */ -- cleanTupType = ExecCleanTypeFromTL(targetList, hasoid); -+ cleanTupType = ExecCleanTypeFromTL(targetList, hasoid, hassecid); - - /* - * Use the given slot, or make a new slot if we weren't given one. -diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c -index 6d4a773..a8ad9a3 100644 ---- a/src/backend/executor/execMain.c -+++ b/src/backend/executor/execMain.c -@@ -38,6 +38,7 @@ - #include "access/xact.h" - #include "catalog/heap.h" - #include "catalog/namespace.h" -+#include "catalog/pg_seclabel.h" - #include "catalog/toasting.h" - #include "commands/tablespace.h" - #include "commands/trigger.h" -@@ -47,11 +48,13 @@ - #include "optimizer/clauses.h" - #include "parser/parse_clause.h" - #include "parser/parsetree.h" -+#include "sepgsql/hooks.h" - #include "storage/bufmgr.h" - #include "storage/lmgr.h" - #include "storage/smgr.h" - #include "tcop/utility.h" - #include "utils/acl.h" -+#include "utils/guc.h" - #include "utils/lsyscache.h" - #include "utils/memutils.h" - #include "utils/snapmgr.h" -@@ -414,7 +417,16 @@ ExecCheckRTPerms(List *rangeTable) - - foreach(l, rangeTable) - { -- ExecCheckRTEPerms((RangeTblEntry *) lfirst(l)); -+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); -+ -+ ExecCheckRTEPerms(rte); -+ -+ if (rte->rtekind == RTE_RELATION) -+ sepgsql_relation_perms(rte->relid, -+ rte->requiredPerms, -+ rte->selectedCols, -+ rte->modifiedCols, -+ true); - } - } - -@@ -826,6 +838,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) - - j = ExecInitJunkFilter(planstate->plan->targetlist, - tupType->tdhasoid, -+ tupType->tdhassecid, - ExecInitExtraTupleSlot(estate)); - estate->es_junkFilter = j; - -@@ -1062,6 +1075,37 @@ ExecContextForcesOids(PlanState *planstate, bool *hasoids) - return false; - } - -+/* -+ * ExecContextForcesSecids -+ * -+ * It is same with ExecContextForcesOids, except for it checks space -+ * for security id of the tuples. -+ */ -+bool -+ExecContextForcesSecids(PlanState *planstate, bool *hassecid) -+{ -+ ResultRelInfo *ri = planstate->state->es_result_relation_info; -+ -+ if (ri != NULL) -+ { -+ Relation rel = ri->ri_RelationDesc; -+ -+ if (rel != NULL) -+ { -+ *hassecid = RelationGetForm(rel)->relhassecids; -+ return true; -+ } -+ } -+ -+ if (planstate->state->es_select_into) -+ { -+ *hassecid = default_with_secids; -+ return true; -+ } -+ -+ return false; -+} -+ - /* ---------------------------------------------------------------- - * ExecEndPlan - * -@@ -2130,6 +2174,7 @@ OpenIntoRel(QueryDesc *queryDesc) - Oid intoRelationId; - TupleDesc tupdesc; - DR_intorel *myState; -+ Oid *secLabels; - static char *validnsps[] = HEAP_RELOPT_NAMESPACES; - - Assert(into); -@@ -2201,6 +2246,14 @@ OpenIntoRel(QueryDesc *queryDesc) - get_tablespace_name(tablespaceId)); - } - -+ /* SELinux checks */ -+ secLabels = sepgsql_relation_create(intoName, -+ RELKIND_RELATION, -+ queryDesc->tupDesc, -+ namespaceId, -+ NIL, -+ true); -+ - /* Parse and validate any reloptions */ - reloptions = transformRelOptions((Datum) 0, - into->options, -@@ -2231,7 +2284,8 @@ OpenIntoRel(QueryDesc *queryDesc) - into->onCommit, - reloptions, - true, -- allowSystemTableMods); -+ allowSystemTableMods, -+ secLabels); - - FreeTupleDesc(tupdesc); - -@@ -2355,6 +2409,11 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self) - */ - if (myState->rel->rd_rel->relhasoids) - HeapTupleSetOid(tuple, InvalidOid); -+ if (myState->rel->rd_rel->relhassecids) -+ HeapTupleSetSecid(tuple, InvalidOid); -+ -+ /* SELinux checks */ -+ sepgsql_tuple_insert(myState->rel, tuple); - - heap_insert(myState->rel, - tuple, -diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c -index bfcce0f..a07b314 100644 ---- a/src/backend/executor/execQual.c -+++ b/src/backend/executor/execQual.c -@@ -49,6 +49,7 @@ - #include "optimizer/planner.h" - #include "parser/parse_coerce.h" - #include "pgstat.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -@@ -1177,6 +1178,9 @@ init_fcache(Oid foid, FuncExprState *fcache, - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid)); - -+ /* SELinux checks */ -+ sepgsql_proc_execute(foid); -+ - /* - * Safety check on nargs. Under normal circumstances this should never - * fail, as parser should check sooner. But possibly it might fail if -@@ -1221,7 +1225,7 @@ init_fcache(Oid foid, FuncExprState *fcache, - else if (functypclass == TYPEFUNC_SCALAR) - { - /* Base data type, i.e. scalar */ -- tupdesc = CreateTemplateTupleDesc(1, false); -+ tupdesc = CreateTemplateTupleDesc(1, false, false); - TupleDescInitEntry(tupdesc, - (AttrNumber) 1, - NULL, -@@ -2111,7 +2115,7 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, - /* - * Scalar type, so make a single-column descriptor - */ -- tupdesc = CreateTemplateTupleDesc(1, false); -+ tupdesc = CreateTemplateTupleDesc(1, false, false); - TupleDescInitEntry(tupdesc, - (AttrNumber) 1, - "column", -@@ -4118,6 +4122,9 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(acoerce->elemfuncid)); - -+ /* SELinux checks */ -+ sepgsql_proc_execute(acoerce->elemfuncid); -+ - /* Set up the primary fmgr lookup information */ - fmgr_info_cxt(acoerce->elemfuncid, &(astate->elemfunc), - econtext->ecxt_per_query_memory); -diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c -index fa5ff2d..fb9093c 100644 ---- a/src/backend/executor/execScan.c -+++ b/src/backend/executor/execScan.c -@@ -20,6 +20,7 @@ - - #include "executor/executor.h" - #include "miscadmin.h" -+#include "parser/parsetree.h" - #include "utils/memutils.h" - - -@@ -114,6 +115,9 @@ ExecScan(ScanState *node, - ProjectionInfo *projInfo; - ExprDoneCond isDone; - TupleTableSlot *resultSlot; -+ Scan *scan = (Scan *)node->ps.plan; -+ EState *estate = node->ps.state; -+ RangeTblEntry *rte = rt_fetch(scan->scanrelid, estate->es_range_table); - - /* - * Fetch data from node -@@ -125,7 +129,7 @@ ExecScan(ScanState *node, - * If we have neither a qual to check nor a projection to do, just skip - * all the overhead and return the raw scan tuple. - */ -- if (!qual && !projInfo) -+ if (!qual && !projInfo && !rte->rowlvPerms) - return ExecScanFetch(node, accessMtd, recheckMtd); - - /* -@@ -189,9 +193,20 @@ ExecScan(ScanState *node, - * when the qual is nil ... saves only a few cycles, but they add up - * ... - */ -- if (!qual || ExecQual(qual, econtext, false)) -+ if (sepgsql_rowlv_quals(node->ss_currentRelation, -+ rte->rowlvPerms, slot, false) && -+ (!qual || ExecQual(qual, econtext, false))) - { - /* -+ * NOTE: When FK checks, the Row-level features needs to raise -+ * an error after evaluation of all the given quals, to avoid -+ * incorrect error reports about unrelated tuples. -+ * We assume FK does not use malicious functions in the quals. -+ */ -+ sepgsql_rowlv_quals(node->ss_currentRelation, -+ rte->rowlvPerms, slot, true); -+ -+ /* - * Found a satisfactory scan tuple. - */ - if (projInfo) -@@ -258,6 +273,7 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc - int numattrs = tupdesc->natts; - int attrno; - bool hasoid; -+ bool hassecid; - ListCell *tlist_item = list_head(tlist); - - /* Check the tlist attributes */ -@@ -307,6 +323,9 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc - if (ExecContextForcesOids(ps, &hasoid) && - hasoid != tupdesc->tdhasoid) - return false; -+ if (ExecContextForcesSecids(ps, &hassecid) && -+ hassecid != tupdesc->tdhassecid) -+ return false; - - return true; - } -diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c -index e2ee706..d4d216b 100644 ---- a/src/backend/executor/execTuples.c -+++ b/src/backend/executor/execTuples.c -@@ -98,7 +98,7 @@ - - - static TupleDesc ExecTypeFromTLInternal(List *targetList, -- bool hasoid, bool skipjunk); -+ bool hasoid, bool hassecid, bool skipjunk); - - - /* ---------------------------------------------------------------- -@@ -899,9 +899,9 @@ ExecInitNullTupleSlot(EState *estate, TupleDesc tupType) - * ---------------------------------------------------------------- - */ - TupleDesc --ExecTypeFromTL(List *targetList, bool hasoid) -+ExecTypeFromTL(List *targetList, bool hasoid, bool hassecid) - { -- return ExecTypeFromTLInternal(targetList, hasoid, false); -+ return ExecTypeFromTLInternal(targetList, hasoid, hassecid, false); - } - - /* ---------------------------------------------------------------- -@@ -911,13 +911,14 @@ ExecTypeFromTL(List *targetList, bool hasoid) - * ---------------------------------------------------------------- - */ - TupleDesc --ExecCleanTypeFromTL(List *targetList, bool hasoid) -+ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hassecid) - { -- return ExecTypeFromTLInternal(targetList, hasoid, true); -+ return ExecTypeFromTLInternal(targetList, hasoid, hassecid, true); - } - - static TupleDesc --ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk) -+ExecTypeFromTLInternal(List *targetList, -+ bool hasoid, bool hassecid, bool skipjunk) - { - TupleDesc typeInfo; - ListCell *l; -@@ -928,7 +929,7 @@ ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk) - len = ExecCleanTargetListLength(targetList); - else - len = ExecTargetListLength(targetList); -- typeInfo = CreateTemplateTupleDesc(len, hasoid); -+ typeInfo = CreateTemplateTupleDesc(len, hasoid, hassecid); - - foreach(l, targetList) - { -@@ -960,7 +961,7 @@ ExecTypeFromExprList(List *exprList) - int cur_resno = 1; - char fldname[NAMEDATALEN]; - -- typeInfo = CreateTemplateTupleDesc(list_length(exprList), false); -+ typeInfo = CreateTemplateTupleDesc(list_length(exprList), false, false); - - foreach(l, exprList) - { -diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c -index 5886c1b..50f91f5 100644 ---- a/src/backend/executor/execUtils.c -+++ b/src/backend/executor/execUtils.c -@@ -444,6 +444,7 @@ void - ExecAssignResultTypeFromTL(PlanState *planstate) - { - bool hasoid; -+ bool hassecid; - TupleDesc tupDesc; - - if (ExecContextForcesOids(planstate, &hasoid)) -@@ -456,12 +457,15 @@ ExecAssignResultTypeFromTL(PlanState *planstate) - hasoid = false; - } - -+ if (!ExecContextForcesSecids(planstate, &hassecid)) -+ hassecid = false; -+ - /* - * ExecTypeFromTL needs the parse-time representation of the tlist, not a - * list of ExprStates. This is good because some plan nodes don't bother - * to set up planstate->targetlist ... - */ -- tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid); -+ tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid, hassecid); - ExecAssignResultType(planstate, tupDesc); - } - -diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c -index 75fc173..99cb650 100644 ---- a/src/backend/executor/functions.c -+++ b/src/backend/executor/functions.c -@@ -1153,7 +1153,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList, - - /* Set up junk filter if needed */ - if (junkFilter) -- *junkFilter = ExecInitJunkFilter(tlist, false, NULL); -+ *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL); - } - else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID) - { -@@ -1197,7 +1197,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList, - } - /* Set up junk filter if needed */ - if (junkFilter) -- *junkFilter = ExecInitJunkFilter(tlist, false, NULL); -+ *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL); - return false; /* NOT returning whole tuple */ - } - } -@@ -1210,7 +1210,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList, - * what the caller expects will happen at runtime. - */ - if (junkFilter) -- *junkFilter = ExecInitJunkFilter(tlist, false, NULL); -+ *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL); - return true; - } - Assert(tupdesc); -diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c -index 74fc87a..4b222b1 100644 ---- a/src/backend/executor/nodeAgg.c -+++ b/src/backend/executor/nodeAgg.c -@@ -89,6 +89,7 @@ - #include "optimizer/tlist.h" - #include "parser/parse_agg.h" - #include "parser/parse_coerce.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -@@ -1641,6 +1642,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) - get_func_name(finalfn_oid)); - } - } -+ /* SELinux checks */ -+ sepgsql_aggregate_execute(aggref->aggfnoid); - - /* resolve actual type of transition state, if polymorphic */ - aggtranstype = aggform->aggtranstype; -@@ -1722,7 +1725,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) - * Get a tupledesc corresponding to the inputs (including sort - * expressions) of the agg. - */ -- peraggstate->evaldesc = ExecTypeFromTL(aggref->args, false); -+ peraggstate->evaldesc = ExecTypeFromTL(aggref->args, false, false); - - /* Create slot we're going to do argument evaluation in */ - peraggstate->evalslot = ExecInitExtraTupleSlot(estate); -diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c -index 6989961..471653f 100644 ---- a/src/backend/executor/nodeFunctionscan.c -+++ b/src/backend/executor/nodeFunctionscan.c -@@ -178,7 +178,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) - /* Base data type, i.e. scalar */ - char *attname = strVal(linitial(node->funccolnames)); - -- tupdesc = CreateTemplateTupleDesc(1, false); -+ tupdesc = CreateTemplateTupleDesc(1, false, false); - TupleDescInitEntry(tupdesc, - (AttrNumber) 1, - attname, -diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c -index 948f580..7d9f4f4 100644 ---- a/src/backend/executor/nodeMergejoin.c -+++ b/src/backend/executor/nodeMergejoin.c -@@ -98,6 +98,7 @@ - #include "executor/execdefs.h" - #include "executor/nodeMergejoin.h" - #include "miscadmin.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/lsyscache.h" - #include "utils/memutils.h" -@@ -224,6 +225,9 @@ MJExamineQuals(List *mergeclauses, - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(cmpproc)); - -+ /* SELinux permissions */ -+ sepgsql_proc_execute(cmpproc); -+ - /* Set up the fmgr lookup information */ - fmgr_info(cmpproc, &(clause->cmpfinfo)); - -diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c -index f4b2b16..62c76b5 100644 ---- a/src/backend/executor/nodeModifyTable.c -+++ b/src/backend/executor/nodeModifyTable.c -@@ -38,11 +38,13 @@ - #include "postgres.h" - - #include "access/xact.h" -+#include "catalog/pg_seclabel.h" - #include "commands/trigger.h" - #include "executor/executor.h" - #include "executor/nodeModifyTable.h" - #include "miscadmin.h" - #include "nodes/nodeFuncs.h" -+#include "sepgsql/hooks.h" - #include "storage/bufmgr.h" - #include "utils/builtins.h" - #include "utils/memutils.h" -@@ -160,7 +162,8 @@ ExecProcessReturning(ProjectionInfo *projectReturning, - static TupleTableSlot * - ExecInsert(TupleTableSlot *slot, - TupleTableSlot *planSlot, -- EState *estate) -+ EState *estate, -+ Oid securityId) - { - HeapTuple tuple; - ResultRelInfo *resultRelInfo; -@@ -194,6 +197,8 @@ ExecInsert(TupleTableSlot *slot, - */ - if (resultRelationDesc->rd_rel->relhasoids) - HeapTupleSetOid(tuple, InvalidOid); -+ if (resultRelationDesc->rd_rel->relhassecids) -+ HeapTupleSetSecid(tuple, securityId); - - /* BEFORE ROW INSERT Triggers */ - if (resultRelInfo->ri_TrigDesc && -@@ -224,6 +229,8 @@ ExecInsert(TupleTableSlot *slot, - tuple = newtuple; - } - } -+ /* SELinux checks */ -+ sepgsql_tuple_insert(resultRelationDesc, tuple); - - /* - * Check the constraints of the tuple -@@ -421,7 +428,8 @@ ExecUpdate(ItemPointer tupleid, - TupleTableSlot *slot, - TupleTableSlot *planSlot, - EPQState *epqstate, -- EState *estate) -+ EState *estate, -+ Oid securityId) - { - HeapTuple tuple; - ResultRelInfo *resultRelInfo; -@@ -449,6 +457,13 @@ ExecUpdate(ItemPointer tupleid, - resultRelInfo = estate->es_result_relation_info; - resultRelationDesc = resultRelInfo->ri_RelationDesc; - -+ /* -+ * If the result relation has writable system attributes, -+ * we store user given value (or InvalidOid) on the tuple. -+ */ -+ if (resultRelationDesc->rd_rel->relhassecids) -+ HeapTupleSetSecid(tuple, securityId); -+ - /* BEFORE ROW UPDATE Triggers */ - if (resultRelInfo->ri_TrigDesc && - resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0) -@@ -479,6 +494,8 @@ ExecUpdate(ItemPointer tupleid, - tuple = newtuple; - } - } -+ /* SELinux checks */ -+ sepgsql_tuple_update(resultRelationDesc, tupleid, tuple); - - /* - * Check the constraints of the tuple -@@ -635,6 +652,42 @@ fireASTriggers(ModifyTableState *node) - } - } - -+/* -+ * FetchWritableSecLabel -+ * -+ * It moves user given security label into slot-> -+ */ -+static Oid -+FetchWritableSecLabel(Relation relation, -+ JunkFilter *junkfilter, -+ TupleTableSlot *slot) -+{ -+ Oid securityId = InvalidOid; -+ AttrNumber attno; -+ Datum datum; -+ bool isnull; -+ char *label; -+ -+ /* -+ * If no explicit label was given, set a default label later -+ */ -+ attno = ExecFindJunkAttribute(junkfilter, "security_label"); -+ if (attno != InvalidAttrNumber && !ignore_security_label_input) -+ { -+ datum = ExecGetJunkAttribute(slot, attno, &isnull); -+ if (isnull) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("Unable to set NULL on \"security_label\""))); -+ -+ label = TextDatumGetCString(datum); -+ -+ securityId = seclabelTransInput(RelationGetRelid(relation), label); -+ -+ pfree(label); -+ } -+ return securityId; -+} - - /* ---------------------------------------------------------------- - * ExecModifyTable -@@ -682,6 +735,8 @@ ExecModifyTable(ModifyTableState *node) - */ - for (;;) - { -+ Oid securityId = InvalidOid; -+ - /* - * Reset the per-output-tuple exprcontext. This is needed because - * triggers expect to use that context as workspace. It's a bit ugly -@@ -714,6 +769,14 @@ ExecModifyTable(ModifyTableState *node) - - if (junkfilter != NULL) - { -+ Relation targetRel -+ = estate->es_result_relation_info->ri_RelationDesc; -+ -+ /* -+ * extract writable system column -+ */ -+ securityId = FetchWritableSecLabel(targetRel, junkfilter, slot); -+ - /* - * extract the 'ctid' junk attribute. - */ -@@ -743,11 +806,11 @@ ExecModifyTable(ModifyTableState *node) - switch (operation) - { - case CMD_INSERT: -- slot = ExecInsert(slot, planSlot, estate); -+ slot = ExecInsert(slot, planSlot, estate, securityId); - break; - case CMD_UPDATE: - slot = ExecUpdate(tupleid, slot, planSlot, -- &node->mt_epqstate, estate); -+ &node->mt_epqstate, estate, securityId); - break; - case CMD_DELETE: - slot = ExecDelete(tupleid, planSlot, -@@ -855,7 +918,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) - * RETURNING list. We assume the rest will look the same. - */ - tupDesc = ExecTypeFromTL((List *) linitial(node->returningLists), -- false); -+ false, false); - - /* Set up a slot for the output of the RETURNING projection(s) */ - ExecInitResultTupleSlot(estate, &mtstate->ps); -@@ -889,7 +952,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) - * We still must construct a dummy result tuple type, because InitPlan - * expects one (maybe should change that?). - */ -- tupDesc = ExecTypeFromTL(NIL, false); -+ tupDesc = ExecTypeFromTL(NIL, false, false); - ExecInitResultTupleSlot(estate, &mtstate->ps); - ExecAssignResultType(&mtstate->ps, tupDesc); - -@@ -986,6 +1049,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) - - j = ExecInitJunkFilter(subplan->targetlist, - resultRelInfo->ri_RelationDesc->rd_att->tdhasoid, -+ resultRelInfo->ri_RelationDesc->rd_att->tdhassecid, - ExecInitExtraTupleSlot(estate)); - - if (operation == CMD_UPDATE || operation == CMD_DELETE) -diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c -index d397b13..90e2e65 100644 ---- a/src/backend/executor/nodeSubplan.c -+++ b/src/backend/executor/nodeSubplan.c -@@ -859,7 +859,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) - * (hack alert!). The righthand expressions will be evaluated in our - * own innerecontext. - */ -- tupDesc = ExecTypeFromTL(leftptlist, false); -+ tupDesc = ExecTypeFromTL(leftptlist, false, false); - slot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(slot, tupDesc); - sstate->projLeft = ExecBuildProjectionInfo(lefttlist, -@@ -867,7 +867,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) - slot, - NULL); - -- tupDesc = ExecTypeFromTL(rightptlist, false); -+ tupDesc = ExecTypeFromTL(rightptlist, false, false); - slot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(slot, tupDesc); - sstate->projRight = ExecBuildProjectionInfo(righttlist, -diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c -index de6d038..2ee0a8f 100644 ---- a/src/backend/executor/nodeWindowAgg.c -+++ b/src/backend/executor/nodeWindowAgg.c -@@ -43,6 +43,7 @@ - #include "optimizer/clauses.h" - #include "parser/parse_agg.h" - #include "parser/parse_coerce.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/datum.h" -@@ -1554,6 +1555,12 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(wfunc->winfnoid)); - -+ /* SELinux checks */ -+ if (wfunc->winagg) -+ sepgsql_aggregate_execute(wfunc->winfnoid); -+ else -+ sepgsql_proc_execute(wfunc->winfnoid); -+ - /* Fill in the perfuncstate data */ - perfuncstate->wfuncstate = wfuncstate; - perfuncstate->wfunc = wfunc; -diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c -index 1ffb1b2..623b2dd 100644 ---- a/src/backend/executor/spi.c -+++ b/src/backend/executor/spi.c -@@ -767,6 +767,8 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, - mtuple->t_tableOid = tuple->t_tableOid; - if (rel->rd_att->tdhasoid) - HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple)); -+ if (rel->rd_att->tdhassecid) -+ HeapTupleSetSecid(mtuple, HeapTupleGetSecid(tuple)); - } - else - { -@@ -795,7 +797,8 @@ SPI_fnumber(TupleDesc tupdesc, const char *fname) - return res + 1; - } - -- sysatt = SystemAttributeByName(fname, true /* "oid" will be accepted */ ); -+ /* "oid" and "security_label" will be accepted */ -+ sysatt = SystemAttributeByName(fname, true, true); - if (sysatt != NULL) - return sysatt->attnum; - -@@ -820,7 +823,7 @@ SPI_fname(TupleDesc tupdesc, int fnumber) - if (fnumber > 0) - att = tupdesc->attrs[fnumber - 1]; - else -- att = SystemAttributeDefinition(fnumber, true); -+ att = SystemAttributeDefinition(fnumber, true, true); - - return pstrdup(NameStr(att->attname)); - } -@@ -852,7 +855,7 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber) - if (fnumber > 0) - typoid = tupdesc->attrs[fnumber - 1]->atttypid; - else -- typoid = (SystemAttributeDefinition(fnumber, true))->atttypid; -+ typoid = (SystemAttributeDefinition(fnumber, true, true))->atttypid; - - getTypeOutputInfo(typoid, &foutoid, &typisvarlena); - -@@ -909,7 +912,7 @@ SPI_gettype(TupleDesc tupdesc, int fnumber) - if (fnumber > 0) - typoid = tupdesc->attrs[fnumber - 1]->atttypid; - else -- typoid = (SystemAttributeDefinition(fnumber, true))->atttypid; -+ typoid = (SystemAttributeDefinition(fnumber, true, true))->atttypid; - - typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid)); - -@@ -939,7 +942,7 @@ SPI_gettypeid(TupleDesc tupdesc, int fnumber) - if (fnumber > 0) - return tupdesc->attrs[fnumber - 1]->atttypid; - else -- return (SystemAttributeDefinition(fnumber, true))->atttypid; -+ return (SystemAttributeDefinition(fnumber, true, true))->atttypid; - } - - char * -diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c -index 464183d..67d0316 100644 ---- a/src/backend/libpq/be-fsstubs.c -+++ b/src/backend/libpq/be-fsstubs.c -@@ -46,6 +46,7 @@ - #include "libpq/be-fsstubs.h" - #include "libpq/libpq-fs.h" - #include "miscadmin.h" -+#include "sepgsql/hooks.h" - #include "storage/fd.h" - #include "storage/large_object.h" - #include "utils/acl.h" -@@ -172,6 +173,8 @@ lo_read(int fd, char *buf, int len) - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied for large object %u", - cookies[fd]->id))); -+ /* SELinux checks */ -+ sepgsql_largeobject_read(cookies[fd]->id, cookies[fd]->snapshot); - - status = inv_read(cookies[fd], buf, len); - -@@ -204,6 +207,8 @@ lo_write(int fd, const char *buf, int len) - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied for large object %u", - cookies[fd]->id))); -+ /* SELinux checks */ -+ sepgsql_largeobject_write(cookies[fd]->id, cookies[fd]->snapshot); - - status = inv_write(cookies[fd], buf, len); - -@@ -233,6 +238,7 @@ Datum - lo_creat(PG_FUNCTION_ARGS) - { - Oid lobjId; -+ Oid securityId; - - /* - * We don't actually need to store into fscxt, but create it anyway to -@@ -240,7 +246,10 @@ lo_creat(PG_FUNCTION_ARGS) - */ - CreateFSContext(); - -- lobjId = inv_create(InvalidOid); -+ /* SELinux checks */ -+ securityId = sepgsql_largeobject_create(InvalidOid); -+ -+ lobjId = inv_create(InvalidOid, securityId); - - PG_RETURN_OID(lobjId); - } -@@ -249,6 +258,7 @@ Datum - lo_create(PG_FUNCTION_ARGS) - { - Oid lobjId = PG_GETARG_OID(0); -+ Oid securityId; - - /* - * We don't actually need to store into fscxt, but create it anyway to -@@ -256,7 +266,10 @@ lo_create(PG_FUNCTION_ARGS) - */ - CreateFSContext(); - -- lobjId = inv_create(lobjId); -+ /* SELinux checks */ -+ securityId = sepgsql_largeobject_create(lobjId); -+ -+ lobjId = inv_create(lobjId, securityId); - - PG_RETURN_OID(lobjId); - } -@@ -286,6 +299,9 @@ lo_unlink(PG_FUNCTION_ARGS) - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be owner of large object %u", lobjId))); - -+ /* SELinux checks */ -+ sepgsql_largeobject_drop(lobjId, false); -+ - /* - * If there are any open LO FDs referencing that ID, close 'em. - */ -@@ -381,9 +397,10 @@ lo_import_internal(text *filename, Oid lobjOid) - int nbytes, - tmp; - char buf[BUFSIZE]; -- char fnamebuf[MAXPGPATH]; -+ char *fnamebuf = text_to_cstring(filename); - LargeObjectDesc *lobj; - Oid oid; -+ Oid securityId; - - #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS - if (!superuser()) -@@ -392,13 +409,14 @@ lo_import_internal(text *filename, Oid lobjOid) - errmsg("must be superuser to use server-side lo_import()"), - errhint("Anyone can use the client-side lo_import() provided by libpq."))); - #endif -- - CreateFSContext(); - -+ /* SELinux checks */ -+ securityId = sepgsql_largeobject_import(lobjOid, fnamebuf); -+ - /* - * open the file to be read in - */ -- text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); - fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666); - if (fd < 0) - ereport(ERROR, -@@ -409,7 +427,7 @@ lo_import_internal(text *filename, Oid lobjOid) - /* - * create an inversion object - */ -- oid = inv_create(lobjOid); -+ oid = inv_create(lobjOid, securityId); - - /* - * read in from the filesystem and write to the inversion object -@@ -447,7 +465,7 @@ lo_export(PG_FUNCTION_ARGS) - int nbytes, - tmp; - char buf[BUFSIZE]; -- char fnamebuf[MAXPGPATH]; -+ char *fnamebuf = text_to_cstring(filename); - LargeObjectDesc *lobj; - mode_t oumask; - -@@ -458,7 +476,6 @@ lo_export(PG_FUNCTION_ARGS) - errmsg("must be superuser to use server-side lo_export()"), - errhint("Anyone can use the client-side lo_export() provided by libpq."))); - #endif -- - CreateFSContext(); - - /* -@@ -466,6 +483,9 @@ lo_export(PG_FUNCTION_ARGS) - */ - lobj = inv_open(lobjId, INV_READ, fscxt); - -+ /* SELinux checks */ -+ sepgsql_largeobject_export(lobj->id, lobj->snapshot, fnamebuf); -+ - /* - * open the file to be written to - * -@@ -473,7 +493,6 @@ lo_export(PG_FUNCTION_ARGS) - * 022. This code used to drop it all the way to 0, but creating - * world-writable export files doesn't seem wise. - */ -- text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); - oumask = umask((mode_t) 0022); - fd = PathNameOpenFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666); - umask(oumask); -@@ -528,6 +547,9 @@ lo_truncate(PG_FUNCTION_ARGS) - errmsg("permission denied for large object %u", - cookies[fd]->id))); - -+ /* SELinux checks */ -+ sepgsql_largeobject_write(cookies[fd]->id, cookies[fd]->snapshot); -+ - inv_truncate(cookies[fd], len); - - PG_RETURN_INT32(0); -diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c -index 0b2aa3d..90bb7d4 100644 ---- a/src/backend/nodes/copyfuncs.c -+++ b/src/backend/nodes/copyfuncs.c -@@ -1823,6 +1823,7 @@ _copyRangeTblEntry(RangeTblEntry *from) - COPY_SCALAR_FIELD(checkAsUser); - COPY_BITMAPSET_FIELD(selectedCols); - COPY_BITMAPSET_FIELD(modifiedCols); -+ COPY_SCALAR_FIELD(rowlvPerms); - - return newnode; - } -@@ -2755,6 +2756,21 @@ _copyAlterOwnerStmt(AlterOwnerStmt *from) - return newnode; - } - -+static AlterSecLabelStmt * -+_copyAlterSecLabelStmt(AlterSecLabelStmt *from) -+{ -+ AlterSecLabelStmt *newnode = makeNode(AlterSecLabelStmt); -+ -+ COPY_SCALAR_FIELD(objectType); -+ COPY_NODE_FIELD(relation); -+ COPY_NODE_FIELD(object); -+ COPY_NODE_FIELD(objarg); -+ COPY_STRING_FIELD(addname); -+ COPY_NODE_FIELD(secLabel); -+ -+ return newnode; -+} -+ - static RuleStmt * - _copyRuleStmt(RuleStmt *from) - { -@@ -3972,6 +3988,9 @@ copyObject(void *from) - case T_AlterOwnerStmt: - retval = _copyAlterOwnerStmt(from); - break; -+ case T_AlterSecLabelStmt: -+ retval = _copyAlterSecLabelStmt(from); -+ break; - case T_RuleStmt: - retval = _copyRuleStmt(from); - break; -diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c -index 6e00584..2adfa91 100644 ---- a/src/backend/nodes/equalfuncs.c -+++ b/src/backend/nodes/equalfuncs.c -@@ -1309,6 +1309,19 @@ _equalAlterOwnerStmt(AlterOwnerStmt *a, AlterOwnerStmt *b) - } - - static bool -+_equalAlterSecLabelStmt(AlterSecLabelStmt *a, AlterSecLabelStmt *b) -+{ -+ COMPARE_SCALAR_FIELD(objectType); -+ COMPARE_NODE_FIELD(relation); -+ COMPARE_NODE_FIELD(object); -+ COMPARE_NODE_FIELD(objarg); -+ COMPARE_STRING_FIELD(addname); -+ COMPARE_NODE_FIELD(secLabel); -+ -+ return true; -+} -+ -+static bool - _equalRuleStmt(RuleStmt *a, RuleStmt *b) - { - COMPARE_NODE_FIELD(relation); -@@ -2188,6 +2201,7 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b) - COMPARE_SCALAR_FIELD(checkAsUser); - COMPARE_BITMAPSET_FIELD(selectedCols); - COMPARE_BITMAPSET_FIELD(modifiedCols); -+ COMPARE_SCALAR_FIELD(rowlvPerms); - - return true; - } -@@ -2659,6 +2673,9 @@ equal(void *a, void *b) - case T_AlterOwnerStmt: - retval = _equalAlterOwnerStmt(a, b); - break; -+ case T_AlterSecLabelStmt: -+ retval = _equalAlterSecLabelStmt(a, b); -+ break; - case T_RuleStmt: - retval = _equalRuleStmt(a, b); - break; -diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c -index 032150e..63f6b77 100644 ---- a/src/backend/nodes/outfuncs.c -+++ b/src/backend/nodes/outfuncs.c -@@ -2143,6 +2143,7 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node) - WRITE_OID_FIELD(checkAsUser); - WRITE_BITMAPSET_FIELD(selectedCols); - WRITE_BITMAPSET_FIELD(modifiedCols); -+ WRITE_UINT_FIELD(rowlvPerms); - } - - static void -diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c -index f28191d..f6f31e5 100644 ---- a/src/backend/nodes/readfuncs.c -+++ b/src/backend/nodes/readfuncs.c -@@ -1171,6 +1171,7 @@ _readRangeTblEntry(void) - READ_OID_FIELD(checkAsUser); - READ_BITMAPSET_FIELD(selectedCols); - READ_BITMAPSET_FIELD(modifiedCols); -+ READ_UINT_FIELD(rowlvPerms); - - READ_DONE(); - } -diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c -index 45ba902..be917ec 100644 ---- a/src/backend/optimizer/plan/planner.c -+++ b/src/backend/optimizer/plan/planner.c -@@ -39,6 +39,7 @@ - #include "parser/parse_expr.h" - #include "parser/parse_oper.h" - #include "parser/parsetree.h" -+#include "sepgsql/hooks.h" - #include "utils/lsyscache.h" - #include "utils/syscache.h" - -@@ -371,6 +372,16 @@ subquery_planner(PlannerGlobal *glob, Query *parse, - } - - /* -+ * We set up rowlvPerms before expanding inherited tables. -+ */ -+ foreach(l, parse->rtable) -+ { -+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); -+ -+ rte->rowlvPerms = sepgsql_rowlv_permissions(rte); -+ } -+ -+ /* - * Preprocess RowMark information. We need to do this after subquery - * pullup (so that all non-inherited RTEs are present) and before - * inheritance expansion (so that the info is available for -diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c -index 8902b5b..321bba9 100644 ---- a/src/backend/optimizer/util/clauses.c -+++ b/src/backend/optimizer/util/clauses.c -@@ -38,6 +38,7 @@ - #include "parser/parse_coerce.h" - #include "parser/parse_func.h" - #include "rewrite/rewriteManip.h" -+#include "sepgsql/hooks.h" - #include "tcop/tcopprot.h" - #include "utils/acl.h" - #include "utils/builtins.h" -@@ -3752,6 +3753,10 @@ inline_function(Oid funcid, Oid result_type, List *args, - if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK) - return NULL; - -+ /* SELinux checks */ -+ if (!sepgsql_proc_be_inlined(func_tuple)) -+ return NULL; -+ - /* - * Make a temporary memory context, so that we don't leak all the stuff - * that parsing might create. -@@ -4205,7 +4210,8 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) - funcform->provolatile == PROVOLATILE_VOLATILE || - funcform->prosecdef || - !funcform->proretset || -- !heap_attisnull(func_tuple, Anum_pg_proc_proconfig)) -+ !heap_attisnull(func_tuple, Anum_pg_proc_proconfig) || -+ !sepgsql_proc_be_inlined(func_tuple)) - { - ReleaseSysCache(func_tuple); - return NULL; -diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c -index 70cdb59..1a88724 100644 ---- a/src/backend/parser/analyze.c -+++ b/src/backend/parser/analyze.c -@@ -25,6 +25,7 @@ - #include "postgres.h" - - #include "access/sysattr.h" -+#include "catalog/heap.h" - #include "catalog/pg_type.h" - #include "nodes/makefuncs.h" - #include "nodes/nodeFuncs.h" -@@ -40,6 +41,7 @@ - #include "parser/parse_target.h" - #include "parser/parsetree.h" - #include "rewrite/rewriteManip.h" -+#include "utils/guc.h" - #include "utils/rel.h" - - -@@ -660,7 +662,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) - tle = makeTargetEntry(expr, - attr_num, - col->name, -- false); -+ attr_num < 0 ? true : false); - qry->targetList = lappend(qry->targetList, tle); - - rte->modifiedCols = bms_add_member(rte->modifiedCols, -diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y -index 05ff082..acb1799 100644 ---- a/src/backend/parser/gram.y -+++ b/src/backend/parser/gram.y -@@ -183,8 +183,8 @@ static TypeName *TableFuncTypeName(List *columns); - %type stmt schema_stmt - AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterFdwStmt - AlterForeignServerStmt AlterGroupStmt -- AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt -- AlterUserStmt AlterUserMappingStmt AlterUserSetStmt -+ AlterObjectSchemaStmt AlterOwnerStmt AlterSecLabelStmt AlterSeqStmt -+ AlterTableStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt - AlterRoleStmt AlterRoleSetStmt - AlterDefaultPrivilegesStmt DefACLAction - AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt -@@ -422,6 +422,8 @@ static TypeName *TableFuncTypeName(List *columns); - %type OptTableSpace OptConsTableSpace OptTableSpaceOwner - %type opt_check_option - -+%type SecLabelItem -+ - %type xml_attribute_el - %type xml_attribute_list xml_attributes - %type xml_root_version opt_xml_root_standalone -@@ -498,7 +500,7 @@ static TypeName *TableFuncTypeName(List *columns); - - KEY - -- LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING -+ LABEL LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING - LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP - LOCATION LOCK_P LOGIN_P - -@@ -654,6 +656,7 @@ stmt : - | AlterGroupStmt - | AlterObjectSchemaStmt - | AlterOwnerStmt -+ | AlterSecLabelStmt - | AlterSeqStmt - | AlterTableStmt - | AlterRoleSetStmt -@@ -1761,6 +1764,20 @@ alter_table_cmd: - n->subtype = AT_DropOids; - $$ = (Node *)n; - } -+ /* ALTER TABLE SET WITH SECURITY LABEL */ -+ | SET WITH SECURITY LABEL -+ { -+ AlterTableCmd *n = makeNode(AlterTableCmd); -+ n->subtype = AT_AddSecLabel; -+ $$ = (Node *)n; -+ } -+ /* ALTER TABLE SET WITHOUT SECURITY LABEL */ -+ | SET WITHOUT SECURITY LABEL -+ { -+ AlterTableCmd *n = makeNode(AlterTableCmd); -+ n->subtype = AT_DropSecLabel; -+ $$ = (Node *)n; -+ } - /* ALTER TABLE CLUSTER ON */ - | CLUSTER ON name - { -@@ -6028,6 +6045,102 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId - } - ; - -+/***************************************************************************** -+ * -+ * ALTER THING name SECURITY LABEL TO new_label -+ * -+ *****************************************************************************/ -+ -+AlterSecLabelStmt: ALTER DATABASE database_name SecLabelItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_DATABASE; -+ n->object = list_make1(makeString($3)); -+ n->secLabel = $4; -+ $$ = (Node *)n; -+ } -+ | ALTER SCHEMA name SecLabelItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_SCHEMA; -+ n->object = list_make1(makeString($3)); -+ n->secLabel = $4; -+ $$ = (Node *)n; -+ } -+ | ALTER TABLE relation_expr SecLabelItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_TABLE; -+ n->relation = $3; -+ n->secLabel = $4; -+ $$ = (Node *)n; -+ } -+ | ALTER TABLE relation_expr ALTER opt_column ColId SecLabelItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_COLUMN; -+ n->relation = $3; -+ n->addname = $6; -+ n->secLabel = $7; -+ $$ = (Node *)n; -+ } -+ | ALTER SEQUENCE qualified_name SecLabelItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_SEQUENCE; -+ n->relation = $3; -+ n->secLabel = $4; -+ $$ = (Node *)n; -+ } -+ | ALTER VIEW qualified_name SecLabelItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_VIEW; -+ n->relation = $3; -+ n->secLabel = $4; -+ $$ = (Node *)n; -+ } -+ | ALTER FUNCTION function_with_argtypes SecLabelItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_FUNCTION; -+ n->object = $3->funcname; -+ n->objarg = $3->funcargs; -+ n->secLabel = $4; -+ $$ = (Node *)n; -+ } -+ | ALTER AGGREGATE func_name aggr_args SecLabelItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_AGGREGATE; -+ n->object = $3; -+ n->objarg = $4; -+ n->secLabel = $5; -+ $$ = (Node *)n; -+ } -+ | ALTER LARGE_P OBJECT_P Iconst SecLabelItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_LARGEOBJECT; -+ n->object = list_make1(makeInteger($4)); -+ n->secLabel = $5; -+ $$ = (Node *)n; -+ } -+ | ALTER TYPE_P any_name SecLabelItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_TYPE; -+ n->object = $3; -+ n->secLabel = $4; -+ $$ = (Node *)n; -+ } -+ ; -+ -+SecLabelItem: SECURITY LABEL TO Sconst -+ { -+ $$ = makeString($4); -+ } -+ ; - - /***************************************************************************** - * -@@ -10922,6 +11035,7 @@ unreserved_keyword: - | INVOKER - | ISOLATION - | KEY -+ | LABEL - | LANGUAGE - | LARGE_P - | LAST_P -diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c -index 1d0fc82..7ad1eeb 100644 ---- a/src/backend/parser/parse_relation.c -+++ b/src/backend/parser/parse_relation.c -@@ -2302,8 +2302,8 @@ specialAttNum(const char *attname) - { - Form_pg_attribute sysatt; - -- sysatt = SystemAttributeByName(attname, -- true /* "oid" will be accepted */ ); -+ /* "oid" and "security_label" will be accepted */ -+ sysatt = SystemAttributeByName(attname, true, true); - if (sysatt != NULL) - return sysatt->attnum; - return InvalidAttrNumber; -@@ -2324,7 +2324,9 @@ attnumAttName(Relation rd, int attid) - { - Form_pg_attribute sysatt; - -- sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids); -+ sysatt = SystemAttributeDefinition(attid, -+ rd->rd_rel->relhasoids, -+ rd->rd_rel->relhassecids); - return &sysatt->attname; - } - if (attid > rd->rd_att->natts) -@@ -2346,7 +2348,9 @@ attnumTypeId(Relation rd, int attid) - { - Form_pg_attribute sysatt; - -- sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids); -+ sysatt = SystemAttributeDefinition(attid, -+ rd->rd_rel->relhasoids, -+ rd->rd_rel->relhassecids); - return sysatt->atttypid; - } - if (attid > rd->rd_att->natts) -diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c -index 7e04a94..da10dc7 100644 ---- a/src/backend/parser/parse_target.c -+++ b/src/backend/parser/parse_target.c -@@ -14,6 +14,7 @@ - */ - #include "postgres.h" - -+#include "catalog/heap.h" - #include "catalog/pg_type.h" - #include "commands/dbcommands.h" - #include "funcapi.h" -@@ -365,16 +366,34 @@ transformAssignedExpr(ParseState *pstate, - Oid attrtype; /* type of target column */ - int32 attrtypmod; - Relation rd = pstate->p_target_relation; -+ bool relhasoids = RelationGetForm(rd)->relhasoids; -+ bool relhassecids = RelationGetForm(rd)->relhassecids; - - Assert(rd != NULL); -- if (attrno <= 0) -- ereport(ERROR, -- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -- errmsg("cannot assign to system column \"%s\"", -- colname), -- parser_errposition(pstate, location))); -- attrtype = attnumTypeId(rd, attrno); -- attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod; -+ if (attrno > 0) -+ { -+ attrtype = attnumTypeId(rd, attrno); -+ attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod; -+ } -+ else -+ { -+ Form_pg_attribute attr; -+ -+ attr = SystemAttributeDefinition(attrno, relhasoids, relhassecids); -+ if (attr && SystemAttributeWritable(attrno, relhasoids, relhassecids)) -+ { -+ attrtype = attr->atttypid; -+ attrtypmod = attr->atttypmod; -+ } -+ else -+ { -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("cannot assign to system column \"%s\"", colname), -+ parser_errposition(pstate, location))); -+ return NULL; -+ } -+ } - - /* - * If the expression is a DEFAULT placeholder, insert the attribute's -@@ -503,6 +522,10 @@ updateTargetListEntry(ParseState *pstate, - List *indirection, - int location) - { -+ Relation rel = pstate->p_target_relation; -+ bool relhasoids = RelationGetForm(rel)->relhasoids; -+ bool relhassecids = RelationGetForm(rel)->relhassecids; -+ - /* Fix up expression as needed */ - tle->expr = transformAssignedExpr(pstate, - tle->expr, -@@ -519,6 +542,9 @@ updateTargetListEntry(ParseState *pstate, - */ - tle->resno = (AttrNumber) attrno; - tle->resname = colname; -+ -+ if (SystemAttributeWritable(attrno, relhasoids, relhassecids)) -+ tle->resjunk = true; - } - - -@@ -793,6 +819,7 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos) - Bitmapset *wholecols = NULL; - Bitmapset *partialcols = NULL; - ListCell *tl; -+ uint32 system_attrs = 0UL; - - foreach(tl, cols) - { -@@ -801,14 +828,42 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos) - int attrno; - - /* Lookup column name, ereport on failure */ -- attrno = attnameAttNum(pstate->p_target_relation, name, false); -+ attrno = attnameAttNum(pstate->p_target_relation, name, true); - if (attrno == InvalidAttrNumber) -+ { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - name, - RelationGetRelationName(pstate->p_target_relation)), - parser_errposition(pstate, col->location))); -+ } -+ else if (attrno < 0) -+ { -+ Relation rel = pstate->p_target_relation; -+ bool relhasoids = RelationGetForm(rel)->relhasoids; -+ bool relhassecids = RelationGetForm(rel)->relhassecids; -+ -+ if (SystemAttributeWritable(attrno, relhasoids, relhassecids)) -+ { -+ uint32 mask = (1<<(-attrno)); -+ -+ if ((system_attrs & mask) != 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_DUPLICATE_COLUMN), -+ errmsg("column \"%s\" specified more than once", -+ name), -+ parser_errposition(pstate, col->location))); -+ system_attrs |= mask; -+ *attrnos = lappend_int(*attrnos, attrno); -+ continue; -+ } -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), -+ errmsg("column \"%s\" of relation \"%s\" is system column", -+ name, RelationGetRelationName(rel)), -+ parser_errposition(pstate, col->location))); -+ } - - /* - * Check for duplicates, but only of whole columns --- we allow -@@ -1263,7 +1318,7 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup) - expandRTE(rte, var->varno, 0, var->location, false, - &names, &vars); - -- tupleDesc = CreateTemplateTupleDesc(list_length(vars), false); -+ tupleDesc = CreateTemplateTupleDesc(list_length(vars), false, false); - i = 1; - forboth(lname, names, lvar, vars) - { -diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c -index d1e1dac..8e994da 100644 ---- a/src/backend/parser/parse_utilcmd.c -+++ b/src/backend/parser/parse_utilcmd.c -@@ -53,8 +53,10 @@ - #include "parser/parse_utilcmd.h" - #include "parser/parser.h" - #include "rewrite/rewriteManip.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" -+#include "utils/guc.h" - #include "utils/lsyscache.h" - #include "utils/relcache.h" - #include "utils/syscache.h" -@@ -70,6 +72,7 @@ typedef struct - List *inhRelations; /* relations to inherit from */ - bool isalter; /* true if altering existing table */ - bool hasoids; /* does relation have an OID column? */ -+ bool hassecids; /* does relation have an security label? */ - List *columns; /* ColumnDef items */ - List *ckconstraints; /* CHECK constraints */ - List *fkconstraints; /* FOREIGN KEY constraints */ -@@ -185,6 +188,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) - cxt.alist = NIL; - cxt.pkey = NULL; - cxt.hasoids = interpretOidsOption(stmt->options); -+ cxt.hassecids = default_with_secids; - - Assert(!stmt->ofTypename || !stmt->inhRelations); /* grammar enforces */ - -@@ -599,6 +603,9 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, - aclcheck_error(aclresult, ACL_KIND_CLASS, - RelationGetRelationName(relation)); - -+ /* SELinux checks */ -+ sepgsql_relation_getattr(RelationGetRelid(relation)); -+ - tupleDesc = RelationGetDescr(relation); - constr = tupleDesc->constr; - -@@ -1380,7 +1387,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) - if (constraint->contype == CONSTR_PRIMARY) - column->is_not_null = TRUE; - } -- else if (SystemAttributeByName(key, cxt->hasoids) != NULL) -+ else if (SystemAttributeByName(key, cxt->hasoids, cxt->hassecids) != NULL) - { - /* - * column will be a system column in the new table, so accept it. -@@ -1957,6 +1964,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) - cxt.inhRelations = NIL; - cxt.isalter = true; - cxt.hasoids = false; /* need not be right */ -+ cxt.hassecids = false; /* need not be right */ - cxt.columns = NIL; - cxt.ckconstraints = NIL; - cxt.fkconstraints = NIL; -diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c -index 279f0f0..f91f746 100644 ---- a/src/backend/postmaster/postmaster.c -+++ b/src/backend/postmaster/postmaster.c -@@ -109,6 +109,7 @@ - #include "postmaster/postmaster.h" - #include "postmaster/syslogger.h" - #include "replication/walsender.h" -+#include "sepgsql/hooks.h" - #include "storage/fd.h" - #include "storage/ipc.h" - #include "storage/pg_shmem.h" -@@ -212,7 +213,8 @@ static pid_t StartupPID = 0, - AutoVacPID = 0, - PgArchPID = 0, - PgStatPID = 0, -- SysLoggerPID = 0; -+ SysLoggerPID = 0, -+ SecWorkerPID = 0; - - /* Startup/shutdown state */ - #define NoShutdown 0 -@@ -467,6 +469,7 @@ static void ShmemBackendArrayRemove(Backend *bn); - #define StartBackgroundWriter() StartChildProcess(BgWriterProcess) - #define StartWalWriter() StartChildProcess(WalWriterProcess) - #define StartWalReceiver() StartChildProcess(WalReceiverProcess) -+#define StartSecurityWorker() StartChildProcess(SecurityWorkerProcess) - - /* Macros to check exit status of a child process */ - #define EXIT_STATUS_0(st) ((st) == 0) -@@ -1480,6 +1483,11 @@ ServerLoop(void) - if (PgStatPID == 0 && pmState == PM_RUN) - PgStatPID = pgstat_start(); - -+ /* If we have lost security worker, try to start a new one */ -+ if (SecWorkerPID == 0 && pmState == PM_RUN && -+ sepgsql_worker_needed()) -+ SecWorkerPID = StartSecurityWorker(); -+ - /* If we need to signal the autovacuum launcher, do so now */ - if (avlauncher_needs_signal) - { -@@ -2125,6 +2133,8 @@ SIGHUP_handler(SIGNAL_ARGS) - signal_child(SysLoggerPID, SIGHUP); - if (PgStatPID != 0) - signal_child(PgStatPID, SIGHUP); -+ if (SecWorkerPID != 0) -+ signal_child(SecWorkerPID, SIGHUP); - - /* Reload authentication config files too */ - if (!load_hba()) -@@ -2185,6 +2195,9 @@ pmdie(SIGNAL_ARGS) - /* and the walwriter too */ - if (WalWriterPID != 0) - signal_child(WalWriterPID, SIGTERM); -+ /* and the security worker too */ -+ if (SecWorkerPID != 0) -+ signal_child(SecWorkerPID, SIGTERM); - - /* - * If we're in recovery, we can't kill the startup process -@@ -2247,6 +2260,9 @@ pmdie(SIGNAL_ARGS) - /* and the walwriter too */ - if (WalWriterPID != 0) - signal_child(WalWriterPID, SIGTERM); -+ /* and the security worker too */ -+ if (SecWorkerPID != 0) -+ signal_child(SecWorkerPID, SIGTERM); - pmState = PM_WAIT_BACKENDS; - } - -@@ -2282,6 +2298,8 @@ pmdie(SIGNAL_ARGS) - signal_child(PgArchPID, SIGQUIT); - if (PgStatPID != 0) - signal_child(PgStatPID, SIGQUIT); -+ if (SecWorkerPID != 0) -+ signal_child(SecWorkerPID, SIGQUIT); - ExitPostmaster(0); - break; - } -@@ -2554,6 +2572,16 @@ reaper(SIGNAL_ARGS) - continue; - } - -+ /* Was it the security worker process? */ -+ if (pid == SecWorkerPID) -+ { -+ SecWorkerPID = 0; -+ if (!EXIT_STATUS_0(exitstatus)) -+ LogChildExit(LOG, _("security worker process"), -+ pid, exitstatus); -+ continue; -+ } -+ - /* - * Else do standard backend child cleanup. - */ -@@ -2770,6 +2798,18 @@ HandleChildCrash(int pid, int exitstatus, const char *procname) - signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT)); - } - -+ /* Take care of the security worker process too */ -+ if (pid == SecWorkerPID) -+ SecWorkerPID = 0; -+ else if (SecWorkerPID != 0 && !FatalError) -+ { -+ ereport(DEBUG2, -+ (errmsg_internal("sending %s to process %d", -+ (SendStop ? "SIGSTOP" : "SIGQUIT"), -+ (int) SecWorkerPID))); -+ signal_child(SecWorkerPID, (SendStop ? SIGSTOP : SIGQUIT)); -+ } -+ - /* - * Force a power-cycle of the pgarch process too. (This isn't absolutely - * necessary, but it seems like a good idea for robustness, and it -@@ -2926,7 +2966,8 @@ PostmasterStateMachine(void) - WalReceiverPID == 0 && - (BgWriterPID == 0 || !FatalError) && - WalWriterPID == 0 && -- AutoVacPID == 0) -+ AutoVacPID == 0 && -+ SecWorkerPID == 0) - { - if (FatalError) - { -diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c -index 06469b3..34f8cbe 100644 ---- a/src/backend/rewrite/rewriteDefine.c -+++ b/src/backend/rewrite/rewriteDefine.c -@@ -27,6 +27,7 @@ - #include "rewrite/rewriteDefine.h" - #include "rewrite/rewriteManip.h" - #include "rewrite/rewriteSupport.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/inval.h" -@@ -265,6 +266,9 @@ DefineQueryRewrite(char *rulename, - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(event_relation)); - -+ /* SELinux checks */ -+ sepgsql_rule_create(event_relid, rulename); -+ - /* - * No rule actions that modify OLD or NEW - */ -diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c -index 2bbfc1f..b412ee9 100644 ---- a/src/backend/rewrite/rewriteRemove.c -+++ b/src/backend/rewrite/rewriteRemove.c -@@ -22,6 +22,7 @@ - #include "catalog/pg_rewrite.h" - #include "miscadmin.h" - #include "rewrite/rewriteRemove.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/fmgroids.h" - #include "utils/inval.h" -@@ -77,6 +78,9 @@ RemoveRewriteRule(Oid owningRel, const char *ruleName, DropBehavior behavior, - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - get_rel_name(eventRelationOid)); - -+ /* SELinux checks */ -+ sepgsql_rule_drop(eventRelationOid, ruleName, false); -+ - /* - * Do the deletion - */ -diff --git a/src/backend/sepgsql/Makefile b/src/backend/sepgsql/Makefile -new file mode 100644 -index 0000000..c8fb740 ---- /dev/null -+++ b/src/backend/sepgsql/Makefile -@@ -0,0 +1,21 @@ -+# -+# Makefile for security subsystem -+# -+ -+subdir = src/backend/sepgsql -+top_builddir = ../../.. -+include $(top_builddir)/src/Makefile.global -+ -+ifeq ($(enable_selinux), yes) -+OBJS = selinux.o avc.o label.o -+else -+OBJS = dummy.o -+endif -+ -+OBJS += rowlv.o -+ -+OBJS += misc.o database.o schema.o relation.o attribute.o proc.o \ -+ type.o tablespace.o operator.o role.o blob.o conversion.o \ -+ tsearch.o fdw.o file.o -+ -+include $(top_srcdir)/src/backend/common.mk -diff --git a/src/backend/sepgsql/attribute.c b/src/backend/sepgsql/attribute.c -new file mode 100644 -index 0000000..3b9c916 ---- /dev/null -+++ b/src/backend/sepgsql/attribute.c -@@ -0,0 +1,260 @@ -+/* -+ * attribute.c -+ * -+ * SELinux hooks related to attribute -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "access/heapam.h" -+#include "access/sysattr.h" -+#include "catalog/pg_attribute.h" -+#include "catalog/pg_class.h" -+#include "catalog/pg_seclabel.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/lsyscache.h" -+#include "utils/syscache.h" -+#include "utils/tqual.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_attribute_common(Oid relOid, AttrNumber attno, -+ uint32 required, bool abort) -+{ -+ Form_pg_attribute attForm; -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ char auname[NAMEDATALEN * 2 + 10]; -+ bool retval; -+ -+ Assert(get_rel_relkind(relOid) == RELKIND_RELATION); -+ -+ tuple = SearchSysCache2(ATTNUM, -+ ObjectIdGetDatum(relOid), -+ Int16GetDatum(attno)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for attribute %d of relation %u", -+ attno, relOid); -+ attForm = (Form_pg_attribute) GETSTRUCT(tuple); -+ -+ tsid.relid = AttributeRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ snprintf(auname, sizeof(auname), "%s.%s", -+ get_rel_name(relOid), NameStr(attForm->attname)); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_COLUMN, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+#endif -+ -+Oid -+sepgsql_attribute_create(Oid relOid, const char *attName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ char auname[NAMEDATALEN * 2 + 10]; -+ -+ if (get_rel_relkind(relOid) != RELKIND_RELATION) -+ { -+ sepgsql_relation_common(relOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ nsid.relid = RelationRelationId; -+ nsid.secid = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(relOid)); -+ -+ nsid = sepgsql_move_secid(AttributeRelationId, nsid); -+ -+ return nsid.secid; -+ } -+ -+ nsid = sepgsql_get_default_column_secid(relOid); -+ snprintf(auname, sizeof(auname), "%s.%s", -+ get_rel_name(relOid), attName); -+ -+ /* db_column:{create} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_COLUMN, -+ SEPG_DB_COLUMN__CREATE, -+ auname, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_attribute_alter(Oid relOid, const char *attName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ AttrNumber attnum = get_attnum(relOid, attName); -+ -+ if (attnum == InvalidAttrNumber) -+ return; /* to be failed later */ -+ -+ if (get_rel_relkind(relOid) == RELKIND_RELATION) -+ sepgsql_attribute_common(relOid, attnum, -+ SEPG_DB_COLUMN__SETATTR, true); -+ else -+ sepgsql_relation_common(relOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_attribute_relabel(Oid relOid, const char *attName, char *new_label) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ AttrNumber attnum = get_attnum(relOid, attName); -+ sepgsql_sid_t nsid; -+ char auname[NAMEDATALEN * 2 + 10]; -+ -+ Assert(get_rel_relkind(relOid) == RELKIND_RELATION); -+ if (attnum == InvalidAttrNumber) -+ return InvalidOid; /* to be failed later */ -+ -+ nsid.relid = AttributeRelationId; -+ nsid.secid = seclabelTransInput(nsid.relid, new_label); -+ -+ snprintf(auname, sizeof(auname), "%s.%s", -+ get_rel_name(relOid), get_attname(relOid, attnum)); -+ -+ /* db_column:{setattr relabelfrom} */ -+ sepgsql_attribute_common(relOid, attnum, -+ SEPG_DB_COLUMN__SETATTR | -+ SEPG_DB_COLUMN__RELABELFROM, -+ true); -+ -+ /* db_column:{relabelto} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_COLUMN, -+ SEPG_DB_COLUMN__RELABELTO, -+ auname, -+ true); -+ return nsid.secid; -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ return InvalidOid; -+} -+ -+void -+sepgsql_attribute_drop(Oid relOid, const char *attName, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ AttrNumber attnum = get_attnum(relOid, attName); -+ -+ /* -+ * If not found, the caller raises an error with an appropriate -+ * error message. -+ */ -+ if (attnum == InvalidAttrNumber) -+ return; -+ -+ if (get_rel_relkind(relOid) == RELKIND_RELATION) -+ { -+ sepgsql_attribute_common(relOid, attnum, -+ SEPG_DB_COLUMN__DROP, true); -+ /* -+ * ALTER TABLE SET WITHOUT SECURITY LABEL is equivalent to -+ * relabel all the tuples within the target relation. -+ * In this case, we need to check {relabelfrom relabelto} -+ */ -+ if (!cascade && -+ attnum == SecurityLabelAttributeNumber) -+ { -+ Relation rel; -+ HeapScanDesc scan; -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ -+ rel = heap_open(relOid, AccessShareLock); -+ -+ scan = heap_beginscan(rel, SnapshotNow, 0, NULL); -+ -+ while (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection))) -+ { -+ /* db_tuple:{update relabelfrom} */ -+ tsid.relid = relOid; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__UPDATE | -+ SEPG_DB_TUPLE__RELABELFROM, -+ NULL, -+ true); -+ } -+ heap_endscan(scan); -+ -+ heap_close(rel, AccessShareLock); -+ -+ /* db_tuple:{relabelto} */ -+ tsid.relid = RelationRelationId; -+ tsid.secid = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(relOid)); -+ -+ sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__RELABELTO, -+ NULL, -+ true); -+ } -+ } -+ else if (!cascade) -+ sepgsql_relation_common(relOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_attribute_grant(Oid relOid, AttrNumber attnum) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ if (get_rel_relkind(relOid) == RELKIND_RELATION) -+ sepgsql_attribute_common(relOid, attnum, -+ SEPG_DB_COLUMN__SETATTR, true); -+ else -+ sepgsql_relation_common(relOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_attribute_comment(Oid relOid, AttrNumber attnum) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ if (get_rel_relkind(relOid) == RELKIND_RELATION) -+ sepgsql_attribute_common(relOid, attnum, -+ SEPG_DB_COLUMN__SETATTR, true); -+ else -+ sepgsql_relation_common(relOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/avc.c b/src/backend/sepgsql/avc.c -new file mode 100644 -index 0000000..5f58974 ---- /dev/null -+++ b/src/backend/sepgsql/avc.c -@@ -0,0 +1,503 @@ -+/* -+ * avc.c -+ * userspace access vector cache -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "access/hash.h" -+#include "access/xact.h" -+#include "catalog/pg_seclabel.h" -+#include "libpq/libpq-be.h" -+#include "libpq/pqsignal.h" -+#include "miscadmin.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "storage/shmem.h" -+#include "storage/lock.h" -+#include "utils/memutils.h" -+ -+#include -+#include -+#include -+ -+/* ------------------------------------------------------------ -+ * -+ * Userspace Access Vector Cache -+ * -+ * ------------------------------------------------------------ -+ */ -+static MemoryContext AvcMemCtx = NULL; -+ -+#define AVC_HASH_NUM_SLOTS 256 -+#define AVC_HASH_NUM_NODES 180 -+ -+#define avc_hash_key(trelid, tsecid, tclass, nrelid) \ -+ (hash_uint32((trelid) ^ (tsecid) ^ ((tclass) << 3) ^ (nrelid))) -+ -+typedef struct _avc_datum -+{ -+ uint32 hash_key; -+ -+ uint16 tclass; -+ sepgsql_sid_t tsid; -+ sepgsql_sid_t nsid; -+ char *tcontext; -+ char *ncontext; -+ -+ uint32 allowed; -+ uint32 auditallow; -+ uint32 auditdeny; -+ bool permissive; -+ -+ bool hot_cache; -+} avc_datum; -+ -+typedef struct _avc_page -+{ -+ struct _avc_page *next; -+ -+ List *slot[AVC_HASH_NUM_SLOTS]; -+ -+ uint32 avc_count; -+ uint32 lru_hint; -+ -+ char scontext[1]; -+} avc_page; -+ -+static avc_page *current_page = NULL; -+ -+static int avc_version = -1; -+ -+/* -+ * selinux_state -+ * -+ * It is deployed on the shared memory region, to show the system -+ * state of SELinux and its security policy. -+ */ -+struct -+{ -+ int version; -+ -+ bool enforcing; -+} *selinux_state = NULL; -+ -+Size -+sepgsql_shmem_size(void) -+{ -+ return sizeof(*selinux_state); -+} -+ -+static void -+sepgsql_shmem_init(void) -+{ -+ bool found; -+ -+ selinux_state = ShmemInitStruct("SELinux system state", -+ sepgsql_shmem_size(), &found); -+ if (!found) -+ { -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ -+ selinux_state->version = 0; -+ selinux_state->enforcing = (security_getenforce() > 0); -+ -+ LWLockRelease(SepgsqlAvcLock); -+ } -+} -+ -+void -+sepgsql_avc_switch(const char *scontext) -+{ -+ avc_page *new_page; -+ int i, length; -+ -+ if (current_page) -+ { -+ new_page = current_page; -+ do { -+ if (strcmp(new_page->scontext, scontext) == 0) -+ { -+ current_page = new_page; -+ return; -+ } -+ new_page = new_page->next; -+ } while (new_page != current_page); -+ } -+ -+ /* -+ * Not found, so create a new avc_page -+ */ -+ length = sizeof(avc_page) + strlen(scontext); -+ new_page = MemoryContextAllocZero(AvcMemCtx, length); -+ -+ strcpy(new_page->scontext, scontext); -+ for (i = 0; i < AVC_HASH_NUM_SLOTS; i++) -+ new_page->slot[i] = NIL; -+ -+ if (!current_page) -+ new_page->next = new_page; -+ else -+ { -+ new_page->next = current_page->next; -+ current_page->next = new_page; -+ } -+ current_page = new_page; -+} -+ -+ -+static void -+sepgsql_avc_reset(void) -+{ -+ Assert(AvcMemCtx != NULL); -+ -+ MemoryContextReset(AvcMemCtx); -+ -+ current_page = NULL; -+ -+ sepgsql_avc_switch(sepgsql_get_client_label()); -+} -+ -+static bool -+sepgsql_avc_is_valid(void) -+{ -+ bool result = true; -+ -+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED); -+ if (avc_version != selinux_state->version) -+ { -+ sepgsql_avc_reset(); -+ -+ /* copy current version to local variable */ -+ avc_version = selinux_state->version; -+ -+ result = false; -+ } -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return result; -+} -+ -+ -+static void -+sepgsql_avc_reclaim(avc_page *page) -+{ -+ ListCell *l; -+ -+ while (page->avc_count > AVC_HASH_NUM_NODES - 10) -+ { -+ foreach (l, page->slot[page->lru_hint]) -+ { -+ avc_datum *cache = lfirst(l); -+ -+ if (cache->hot_cache) -+ cache->hot_cache = false; -+ { -+ list_delete_ptr(page->slot[page->lru_hint], cache); -+ pfree(cache); -+ page->avc_count--; -+ } -+ } -+ page->lru_hint = (page->lru_hint + 1) % AVC_HASH_NUM_SLOTS; -+ } -+} -+ -+static avc_datum * -+sepgsql_avc_make_entry(avc_page *page, -+ sepgsql_sid_t tsid, uint16 tclass, Oid nrelid) -+{ -+ struct av_decision avd; -+ MemoryContext oldctx; -+ char *scontext; -+ char *tcontext; -+ char *ncontext; -+ avc_datum *cache; -+ uint32 hash_key, index; -+ -+ hash_key = avc_hash_key(tsid.relid, tsid.secid, tclass, nrelid); -+ index = hash_key % AVC_HASH_NUM_SLOTS; -+ -+ oldctx = MemoryContextSwitchTo(AvcMemCtx); -+ -+ scontext = page->scontext; -+ tcontext = seclabelRawOutput(tsid.relid, tsid.secid); -+ ncontext = sepgsql_compute_create(scontext, tcontext, tclass); -+ -+ sepgsql_compute_avd(scontext, tcontext, tclass, &avd); -+ -+ cache = palloc0(sizeof(avc_datum)); -+ -+ cache->hash_key = hash_key; -+ -+ cache->tclass = tclass; -+ -+ cache->hot_cache = true; -+ cache->tcontext = tcontext; -+ cache->ncontext = ncontext; -+ -+ cache->tsid.relid = tsid.relid; -+ cache->tsid.secid = tsid.secid; -+ -+ if (OidIsValid(nrelid)) -+ { -+ cache->nsid.relid = nrelid; -+ cache->nsid.secid = seclabelRawInput(nrelid, ncontext); -+ } -+ -+ cache->allowed = avd.allowed; -+ cache->auditallow = avd.auditallow; -+ cache->auditdeny = avd.auditdeny; -+ if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) -+ cache->permissive = true; -+ -+ if (page->avc_count > AVC_HASH_NUM_NODES) -+ sepgsql_avc_reclaim(page); -+ -+ page->slot[index] = lcons(cache, page->slot[index]); -+ page->avc_count++; -+ -+ MemoryContextSwitchTo(oldctx); -+ -+ return cache; -+} -+ -+static avc_datum * -+sepgsql_avc_lookup(avc_page *page, -+ sepgsql_sid_t tsid, uint16 tclass, Oid nrelid) -+{ -+ avc_datum *cache = NULL; -+ uint32 hash_key, index; -+ ListCell *l; -+ -+ hash_key = avc_hash_key(tsid.relid, tsid.secid, tclass, nrelid); -+ index = hash_key % AVC_HASH_NUM_SLOTS; -+ -+ foreach (l, page->slot[index]) -+ { -+ cache = lfirst(l); -+ if (cache->hash_key == hash_key && -+ cache->tclass == tclass && -+ cache->tsid.relid == tsid.relid && -+ cache->tsid.secid == tsid.secid && -+ cache->nsid.relid == nrelid) -+ { -+ cache->hot_cache = true; -+ return cache; -+ } -+ } -+ return NULL; -+} -+ -+bool -+sepgsql_client_perms(sepgsql_sid_t tsid, -+ uint16 tclass, uint32 required, -+ const char *audit_name, bool abort) -+{ -+ avc_datum *cache; -+ uint32 denied, audited; -+ bool result = true; -+ -+ do { -+ cache = sepgsql_avc_lookup(current_page, -+ tsid, tclass, InvalidOid); -+ if (!cache) -+ cache = sepgsql_avc_make_entry(current_page, -+ tsid, tclass, InvalidOid); -+ } while (!sepgsql_avc_is_valid()); -+ -+ denied = required & ~cache->allowed; -+ if (sepgsql_debug_audit && tclass != SEPG_CLASS_DB_TUPLE) -+ audited = (denied ? (denied & ~0) : (required & ~0)); -+ else -+ audited = (denied ? (denied & cache->auditdeny) -+ : (required & cache->auditallow)); -+ -+ if (audited) -+ { -+ sepgsql_audit_log(!!denied, -+ current_page->scontext, -+ seclabelRawOutput(tsid.relid, tsid.secid), -+ tclass, audited, audit_name); -+ } -+ -+ if (denied) -+ { -+ if (!sepgsql_get_enforce() || cache->permissive) -+ cache->allowed |= required; /* prevent flood of audit log */ -+ else -+ { -+ if (abort) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("SELinux: security policy violation"))); -+ result = false; -+ } -+ } -+ -+ return result; -+} -+ -+sepgsql_sid_t -+sepgsql_client_create_secid(sepgsql_sid_t tsid, uint16 tclass, Oid nrelid) -+{ -+ avc_datum *cache; -+ -+ do { -+ cache = sepgsql_avc_lookup(current_page, tsid, tclass, nrelid); -+ -+ if (!cache) -+ cache = sepgsql_avc_make_entry(current_page, -+ tsid, tclass, nrelid); -+ } while (!sepgsql_avc_is_valid()); -+ -+ return cache->nsid; -+} -+ -+char * -+sepgsql_client_create_label(sepgsql_sid_t tsid, uint16 tclass) -+{ -+ avc_datum *cache; -+ -+ do { -+ cache = sepgsql_avc_lookup(current_page, tsid, tclass, InvalidOid); -+ -+ if (!cache) -+ cache = sepgsql_avc_make_entry(current_page, -+ tsid, tclass, InvalidOid); -+ } while (!sepgsql_avc_is_valid()); -+ -+ return cache->ncontext; -+} -+ -+static void -+sepgsql_avc_xact_callback(XactEvent event, void *arg) -+{ -+ if (event == XACT_EVENT_ABORT) -+ sepgsql_avc_reset(); -+} -+ -+static void -+sepgsql_avc_sub_xact_callback(SubXactEvent event, SubTransactionId mySubid, -+ SubTransactionId parentSubid, void *arg) -+{ -+ if (event == SUBXACT_EVENT_ABORT_SUB) -+ sepgsql_avc_reset(); -+} -+ -+void -+sepgsql_avc_init(void) -+{ -+ sepgsql_shmem_init(); -+ -+ AvcMemCtx = AllocSetContextCreate(TopMemoryContext, -+ "Userspace AVC", -+ ALLOCSET_DEFAULT_MINSIZE, -+ ALLOCSET_DEFAULT_INITSIZE, -+ ALLOCSET_DEFAULT_MAXSIZE); -+ /* -+ * userspace avc should be invalidate when the current transaction -+ * is aborted on errors, because sid to be created shall be rollbacked. -+ */ -+ RegisterXactCallback(sepgsql_avc_xact_callback, NULL); -+ RegisterSubXactCallback(sepgsql_avc_sub_xact_callback, NULL); -+} -+ -+/* ------------------------------------------------------------ -+ * -+ * SELinux state monitor process -+ * -+ * ------------------------------------------------------------ -+ */ -+static int -+sepgsql_cb_log(int type, const char *fmt, ...) -+{ -+ char *c, buffer[1024]; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ vsnprintf(buffer, sizeof(buffer), fmt, ap); -+ va_end(ap); -+ -+ c = strrchr(buffer, '\n'); -+ if (c) -+ *c = '\0'; -+ -+ ereport(LOG,(errmsg("%s", buffer))); -+ -+ return 0; -+} -+ -+static int -+sepgsql_cb_setenforce(int enforce) -+{ -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ selinux_state->enforcing = (enforce ? true : false); -+ selinux_state->version++; -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return 0; -+} -+ -+static int -+sepgsql_cb_policyload(int seqno) -+{ -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ selinux_state->version++; -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return 0; -+} -+ -+void -+sepgsql_avc_worker_main(void) -+{ -+ union selinux_callback cb; -+ -+ Assert(sepgsql_is_enabled()); -+ -+#ifdef HAVE_SETSID -+ if (setsid() < 0) -+ elog(FATAL, "setsid() failed: %m"); -+#endif -+ -+ /* -+ * setup the signal handler -+ */ -+ pqinitmask(); -+ pqsignal(SIGHUP, SIG_IGN); -+ pqsignal(SIGINT, SIG_IGN); -+ pqsignal(SIGTERM, exit); -+ pqsignal(SIGQUIT, exit); -+ pqsignal(SIGUSR1, SIG_IGN); -+ pqsignal(SIGUSR2, SIG_IGN); -+ pqsignal(SIGCHLD, SIG_DFL); -+ PG_SETMASK(&UnBlockSig); -+ -+ /* -+ * map shared memory segment -+ */ -+ sepgsql_shmem_init(); -+ -+ ereport(LOG, (errmsg("SELinux: netlink receiver (pid=%u)", getpid()))); -+ -+ /* -+ * setup callback functions from avc_netlink_loop() -+ */ -+ cb.func_log = sepgsql_cb_log; -+ selinux_set_callback(SELINUX_CB_LOG, cb); -+ cb.func_setenforce = sepgsql_cb_setenforce; -+ selinux_set_callback(SELINUX_CB_SETENFORCE, cb); -+ cb.func_policyload = sepgsql_cb_policyload; -+ selinux_set_callback(SELINUX_CB_POLICYLOAD, cb); -+ -+ /* -+ * open netlink socket and wait for messages -+ */ -+ avc_netlink_open(1); -+ -+ avc_netlink_loop(); -+ -+ exit(0); -+} -diff --git a/src/backend/sepgsql/blob.c b/src/backend/sepgsql/blob.c -new file mode 100644 -index 0000000..e60e9cc ---- /dev/null -+++ b/src/backend/sepgsql/blob.c -@@ -0,0 +1,245 @@ -+/* -+ * blob.c -+ * -+ * SELinux hooks related to large objects -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "access/genam.h" -+#include "access/heapam.h" -+#include "access/sysattr.h" -+#include "catalog/indexing.h" -+#include "catalog/pg_largeobject.h" -+#include "catalog/pg_largeobject_metadata.h" -+#include "catalog/pg_seclabel.h" -+#include "miscadmin.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/fmgroids.h" -+#include "utils/tqual.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_largeobject_common(Oid loid, Snapshot snapshot, -+ uint32 required, bool abort) -+{ -+ Relation pg_lo_meta; -+ ScanKeyData skey; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ char auname[NAMEDATALEN]; -+ bool retval; -+ -+ snprintf(auname, sizeof(auname), "blob_%u", loid); -+ -+ pg_lo_meta = heap_open(LargeObjectMetadataRelationId, -+ AccessShareLock); -+ -+ ScanKeyInit(&skey, -+ ObjectIdAttributeNumber, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(loid)); -+ -+ scan = systable_beginscan(pg_lo_meta, -+ LargeObjectMetadataOidIndexId, true, -+ snapshot, 1, &skey); -+ -+ tuple = systable_getnext(scan); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "large object %u does not exist", loid); -+ -+ tsid.relid = LargeObjectMetadataRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_BLOB, -+ required, -+ auname, -+ abort); -+ systable_endscan(scan); -+ -+ heap_close(pg_lo_meta, AccessShareLock); -+ -+ return retval; -+} -+#endif -+ -+Oid -+sepgsql_largeobject_create(Oid loid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ char auname[NAMEDATALEN]; -+ -+ nsid = sepgsql_get_default_blob_secid(MyDatabaseId); -+ snprintf(auname, sizeof(auname), "blob_%u", loid); -+ -+ /* db_blob:{create} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__CREATE, -+ auname, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_largeobject_alter(Oid loid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_largeobject_common(loid, SnapshotNow, -+ SEPG_DB_BLOB__SETATTR, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_largeobject_relabel(Oid loid, char *newLabel) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ char auname[NAMEDATALEN]; -+ -+ nsid.relid = LargeObjectMetadataRelationId; -+ nsid.secid = seclabelTransInput(nsid.relid, newLabel); -+ -+ snprintf(auname, sizeof(auname), "blob_%u", loid); -+ -+ /* db_blob:{setattr relabelfrom} */ -+ sepgsql_largeobject_common(loid, -+ SnapshotNow, -+ SEPG_DB_BLOB__SETATTR | -+ SEPG_DB_BLOB__RELABELFROM, -+ true); -+ /* db_blob:{relabelto} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__RELABELTO, -+ auname, -+ true); -+ return nsid.secid; -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ return InvalidOid; -+} -+ -+void -+sepgsql_largeobject_drop(Oid loid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_largeobject_common(loid, SnapshotNow, -+ SEPG_DB_BLOB__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_largeobject_read(Oid loid, Snapshot snapshot) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_largeobject_common(loid, snapshot, -+ SEPG_DB_BLOB__READ, true); -+ } -+#endif -+} -+ -+void -+sepgsql_largeobject_write(Oid loid, Snapshot snapshot) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_largeobject_common(loid, snapshot, -+ SEPG_DB_BLOB__WRITE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_largeobject_import(Oid loid, const char *filename) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ char auname[NAMEDATALEN]; -+ -+ nsid = sepgsql_get_default_blob_secid(MyDatabaseId); -+ snprintf(auname, sizeof(auname), "blob_%u", loid); -+ -+ /* db_blob:{create} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__CREATE | -+ SEPG_DB_BLOB__WRITE | -+ SEPG_DB_BLOB__IMPORT, -+ auname, -+ true); -+ /* db_file:{read} */ -+ // XXX - todo: add file read checks -+ -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_largeobject_export(Oid loid, Snapshot snapshot, const char *filename) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_blob:{read export} */ -+ sepgsql_largeobject_common(loid, snapshot, -+ SEPG_DB_BLOB__READ | -+ SEPG_DB_BLOB__EXPORT, true); -+ /* file:{write} */ -+ // TODO: add security checks -+ } -+#endif -+} -+ -+void -+sepgsql_largeobject_grant(Oid loid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_largeobject_common(loid, SnapshotNow, -+ SEPG_DB_BLOB__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_largeobject_comment(Oid loid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_largeobject_common(loid, SnapshotNow, -+ SEPG_DB_BLOB__SETATTR, true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/conversion.c b/src/backend/sepgsql/conversion.c -new file mode 100644 -index 0000000..6a60284 ---- /dev/null -+++ b/src/backend/sepgsql/conversion.c -@@ -0,0 +1,147 @@ -+/* -+ * conversion.c -+ * -+ * SELinux hooks related to conversion -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_conversion.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/syscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_conversion_common(Oid convOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ HeapTuple tuple; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(convOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for conversion %u", convOid); -+ -+ tsid.relid = ConversionRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_conversion) GETSTRUCT(tuple))->conname); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+static Oid -+get_conversion_namespace(Oid convOid) -+{ -+ HeapTuple tuple; -+ Oid namespaceId = InvalidOid; -+ -+ tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(convOid)); -+ if (HeapTupleIsValid(tuple)) -+ { -+ namespaceId = ((Form_pg_conversion) GETSTRUCT(tuple))->connamespace; -+ -+ ReleaseSysCache(tuple); -+ } -+ return namespaceId; -+} -+#endif -+ -+Oid -+sepgsql_conversion_create(const char *convName, -+ Oid namespaceId, Oid conversionFunc) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ -+ nsid = sepgsql_get_default_tuple_secid(ConversionRelationId); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, -+ SEPG_DB_SCHEMA__ADD_NAME, true); -+ /* db_procedure:{install} */ -+ sepgsql_proc_common(conversionFunc, -+ SEPG_DB_PROCEDURE__INSTALL, true); -+ /* db_tuple:{insert} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ convName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_conversion_alter(Oid convOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_conversion_common(convOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_conversion_alter_rename(Oid convOid, const char *newName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_conversion_namespace(convOid); -+ -+ /* db_schema:{add_name remove_name} */ -+ sepgsql_schema_common(namespaceId, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{update} */ -+ sepgsql_conversion_common(convOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_conversion_drop(Oid convOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_conversion_namespace(convOid); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{delete} */ -+ sepgsql_conversion_common(convOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_conversion_comment(Oid convOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_conversion_common(convOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/database.c b/src/backend/sepgsql/database.c -new file mode 100644 -index 0000000..bee9d36 ---- /dev/null -+++ b/src/backend/sepgsql/database.c -@@ -0,0 +1,201 @@ -+/* -+ * database.c -+ * -+ * SELinux hooks related to database -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_database.h" -+#include "catalog/pg_seclabel.h" -+#include "commands/dbcommands.h" -+#include "miscadmin.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/syscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_database_common(Oid datOid, uint32 required, bool abort) -+{ -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(DATABASEOID, -+ ObjectIdGetDatum(datOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for database %u", datOid); -+ -+ tsid.relid = DatabaseRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname); -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_DATABASE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+#endif -+ -+Oid -+sepgsql_database_create(const char *datName, Oid templateOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ -+ /* compute a default security context */ -+ nsid = sepgsql_get_default_database_secid(templateOid); -+ -+ /* db_database:{create} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_DATABASE, -+ SEPG_DB_DATABASE__CREATE, -+ datName, true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_database_alter(Oid databaseOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_database_common(databaseOid, -+ SEPG_DB_DATABASE__SETATTR, -+ true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_database_relabel(Oid databaseOid, char *new_label) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ char *auname; -+ -+ nsid.relid = DatabaseRelationId; -+ nsid.secid = seclabelTransInput(nsid.relid, new_label); -+ -+ auname = get_database_name(databaseOid); -+ -+ /* db_database:{setattr relabelfrom} */ -+ sepgsql_database_common(databaseOid, -+ SEPG_DB_DATABASE__SETATTR | -+ SEPG_DB_DATABASE__RELABELFROM, -+ true); -+ -+ /* db_database:{relabelto} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_DATABASE, -+ SEPG_DB_DATABASE__RELABELTO, -+ auname, -+ true); -+ pfree(auname); -+ -+ return nsid.secid; -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ return InvalidOid; -+} -+ -+void -+sepgsql_database_drop(Oid databaseOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_database_common(databaseOid, -+ SEPG_DB_DATABASE__DROP, -+ true); -+ } -+#endif -+} -+ -+void -+sepgsql_database_grant(Oid databaseOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_database_common(databaseOid, -+ SEPG_DB_DATABASE__SETATTR, -+ true); -+ } -+#endif -+} -+ -+void -+sepgsql_database_comment(Oid databaseOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_database_common(databaseOid, -+ SEPG_DB_DATABASE__SETATTR, -+ true); -+ } -+#endif -+} -+ -+void -+sepgsql_database_connect(Oid databaseOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ if (!sepgsql_database_common(databaseOid, -+ SEPG_DB_DATABASE__ACCESS, -+ false)) -+ ereport(FATAL, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("permission denied for database \"%s\"", -+ get_database_name(databaseOid)))); -+ } -+#endif -+} -+ -+void -+sepgsql_database_reindex(Oid databaseOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ // TODO: check db_table:{indexon} for each -+ -+ -+ -+ } -+#endif -+} -+ -+void -+sepgsql_database_getattr(Oid databaseOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_database_common(databaseOid, -+ SEPG_DB_DATABASE__GETATTR, -+ true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/fdw.c b/src/backend/sepgsql/fdw.c -new file mode 100644 -index 0000000..be4a34b ---- /dev/null -+++ b/src/backend/sepgsql/fdw.c -@@ -0,0 +1,296 @@ -+/* -+ * fdw.c -+ * -+ * SELinux hooks related to foreign data wrapper -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_foreign_data_wrapper.h" -+#include "catalog/pg_foreign_server.h" -+#include "catalog/pg_user_mapping.h" -+#include "miscadmin.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/syscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_fdw_common(Oid fdwOid, uint32 required, bool abort) -+{ -+ Form_pg_foreign_data_wrapper fdwForm; -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ bool retval; -+ -+ tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for foreign-data-wrapper %u", fdwOid); -+ fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple); -+ -+ tsid.relid = ForeignDataWrapperRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ NameStr(fdwForm->fdwname), -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+bool -+sepgsql_fserver_common(Oid fservOid, uint32 required, bool abort) -+{ -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(fservOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for foreign-server %u", fservOid); -+ -+ tsid.relid = ForeignServerRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_foreign_server) GETSTRUCT(tuple))->srvname); -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+static char * -+get_fserver_name(Oid fservOid) -+{ -+ Form_pg_foreign_server servForm; -+ HeapTuple tuple; -+ char *srvname = NULL; -+ -+ tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(fservOid)); -+ if (HeapTupleIsValid(tuple)) -+ { -+ servForm = (Form_pg_foreign_server) GETSTRUCT(tuple); -+ -+ srvname = pstrdup(NameStr(servForm->srvname)); -+ -+ ReleaseSysCache(tuple); -+ } -+ return srvname; -+} -+ -+bool -+sepgsql_user_mapping_common(Oid umapOid, uint32 required, bool abort) -+{ -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ Oid umuser; -+ Oid umserver; -+ char auname[NAMEDATALEN * 2 + 10]; -+ bool retval; -+ -+ tuple = SearchSysCache1(USERMAPPINGOID, ObjectIdGetDatum(umapOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for user mapping %u", umapOid); -+ -+ tsid.relid = UserMappingRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ umuser = ((Form_pg_user_mapping) GETSTRUCT(tuple))->umuser; -+ umserver = ((Form_pg_user_mapping) GETSTRUCT(tuple))->umserver; -+ -+ snprintf(auname, sizeof(auname), "%s@%s", -+ OidIsValid(umuser) ? GetUserNameFromId(umuser) : "public", -+ get_fserver_name(umserver)); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+#endif -+ -+Oid -+sepgsql_fdw_create(const char *fdwName, Oid validatorFunc) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid -+ = sepgsql_get_default_tuple_secid(ForeignDataWrapperRelationId); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(validatorFunc)) -+ sepgsql_proc_common(validatorFunc, -+ SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* db_tuple:{insert} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ fdwName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_fdw_alter(Oid fdwOid, Oid newValidator) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_procedure:{install} */ -+ if (OidIsValid(newValidator)) -+ sepgsql_proc_common(newValidator, -+ SEPG_DB_PROCEDURE__INSTALL, true); -+ /* db_tuple:{update} */ -+ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_fdw_drop(Oid fdwOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{delete} */ -+ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_fdw_grant(Oid fdwOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_fserver_create(const char *fservName, Oid fdwOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid -+ = sepgsql_get_default_tuple_secid(ForeignServerRelationId); -+ -+ /* db_tuple:{insert} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ fservName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_fserver_alter(Oid fservOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_fserver_common(fservOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_fserver_drop(Oid fservOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_fserver_common(fservOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_fserver_grant(Oid fservOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_fserver_common(fservOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_user_mapping_create(Oid umuserId, Oid fservOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ char auname[NAMEDATALEN * 2 + 10]; -+ sepgsql_sid_t nsid -+ = sepgsql_get_default_tuple_secid(UserMappingRelationId); -+ -+ snprintf(auname, sizeof(auname), "%s@%s", -+ OidIsValid(umuserId) ? GetUserNameFromId(umuserId) : "public", -+ get_fserver_name(fservOid)); -+ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ auname, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_user_mapping_alter(Oid umapOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_user_mapping_common(umapOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_user_mapping_drop(Oid umapOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{delete} */ -+ sepgsql_user_mapping_common(umapOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/file.c b/src/backend/sepgsql/file.c -new file mode 100644 -index 0000000..9a9e8a3 ---- /dev/null -+++ b/src/backend/sepgsql/file.c -@@ -0,0 +1,287 @@ -+/* -+ * file.c -+ * -+ * SELinux hooks related to filesystem -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+ -+#include -+#ifdef HAVE_SELINUX -+#include -+#endif -+#include -+#include -+#include -+ -+#ifdef HAVE_SELINUX -+static uint16 -+sepgsql_file_class(const char *filename, bool abort) -+{ -+ struct stat stbuf; -+ uint16 tclass; -+ -+ if (stat(filename, &stbuf) < 0) -+ { -+ if (abort) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not stat file \"%s\": %m", filename))); -+ return 0; -+ } -+ -+ /* decide object class to be applied */ -+ if (S_ISDIR(stbuf.st_mode)) -+ tclass = SEPG_CLASS_DIR; -+ else if (S_ISCHR(stbuf.st_mode)) -+ tclass = SEPG_CLASS_CHR_FILE; -+ else if (S_ISBLK(stbuf.st_mode)) -+ tclass = SEPG_CLASS_BLK_FILE; -+ else if (S_ISFIFO(stbuf.st_mode)) -+ tclass = SEPG_CLASS_FIFO_FILE; -+ else if (S_ISLNK(stbuf.st_mode)) -+ tclass = SEPG_CLASS_LNK_FILE; -+ else if (S_ISSOCK(stbuf.st_mode)) -+ tclass = SEPG_CLASS_SOCK_FILE; -+ else -+ tclass = SEPG_CLASS_FILE; -+ -+ return tclass; -+} -+ -+static bool -+sepgsql_file_common(const char *filename, uint16 tclass, uint32 required, bool abort) -+{ -+ struct stat stbuf; -+ char *scontext = sepgsql_get_client_label(); -+ char *tcontext; -+ char *temp; -+ bool retval; -+ -+ if (stat(filename, &stbuf) < 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not stat file \"%s\"", filename))); -+ -+ if (getfilecon_raw(filename, &temp) < 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not get security context \"%s\"", filename))); -+ -+ PG_TRY(); -+ { -+ tcontext = pstrdup(temp); -+ } -+ PG_CATCH(); -+ { -+ freecon(temp); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(temp); -+ -+ retval = sepgsql_compute_perms(scontext, tcontext, -+ tclass, required, -+ filename, abort); -+ pfree(tcontext); -+ -+ return retval; -+} -+#endif -+ -+void -+sepgsql_file_getattr(const char *filename) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ uint16 tclass = sepgsql_file_class(filename, true); -+ -+ sepgsql_file_common(filename, tclass, -+ SEPG_FILE__GETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_file_read(const char *filename) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ uint16 tclass = sepgsql_file_class(filename, true); -+ -+ sepgsql_file_common(filename, tclass, -+ SEPG_FILE__READ, true); -+ } -+#endif -+} -+ -+void -+sepgsql_file_write(const char *filename, bool may_create) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ uint16 tclass = sepgsql_file_class(filename, !may_create); -+ char *dir_name; -+ char *tcontext; -+ char *ncontext; -+ char *temp; -+ -+ /* write an existing file */ -+ if (tclass != 0) -+ { -+ sepgsql_file_common(filename, tclass, -+ SEPG_FILE__WRITE, true); -+ return; -+ } -+ -+ /* create a new file, and write it */ -+ dir_name = dirname(pstrdup(filename)); -+ -+ if (sepgsql_file_class(dir_name, true) != SEPG_CLASS_DIR) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not a directory", dir_name))); -+ -+ if (getfilecon(dir_name, &temp) < 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not get security context \"%s\"", dir_name))); -+ PG_TRY(); -+ { -+ tcontext = pstrdup(temp); -+ } -+ PG_CATCH(); -+ { -+ freecon(temp); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(temp); -+ -+ /* dir:{add_name} */ -+ sepgsql_file_common(dir_name, SEPG_CLASS_DIR, -+ SEPG_DIR__ADD_NAME, true); -+ -+ /* file:{create write} */ -+ ncontext = sepgsql_compute_create(sepgsql_get_client_label(), -+ tcontext, SEPG_CLASS_FILE); -+ sepgsql_compute_perms(sepgsql_get_client_label(), -+ ncontext, -+ SEPG_CLASS_FILE, -+ SEPG_FILE__CREATE | -+ SEPG_FILE__WRITE, -+ filename, true); -+ } -+#endif -+} -+ -+void -+sepgsql_file_append(const char *filename) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ if (sepgsql_file_class(filename, true) != SEPG_CLASS_FILE) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not a regular file", filename))); -+ -+ sepgsql_file_common(filename, SEPG_CLASS_FILE, -+ SEPG_FILE__APPEND, true); -+ } -+#endif -+} -+ -+void -+sepgsql_file_unlink(const char *filename) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ uint16 tclass = sepgsql_file_class(filename, true); -+ -+ sepgsql_file_common(filename, tclass, SEPG_FILE__UNLINK, true); -+ } -+#endif -+} -+ -+void -+sepgsql_file_rename(const char *oldpath, const char *newpath) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ char *olddir = dirname(pstrdup(oldpath)); -+ char *newdir = dirname(pstrdup(newpath)); -+ uint16 tclass; -+ uint32 required; -+ -+ /* file:{setattr} on oldpath */ -+ tclass = sepgsql_file_class(oldpath, true); -+ sepgsql_file_common(oldpath, tclass, -+ SEPG_FILE__RENAME, true); -+ -+ if (sepgsql_file_class(olddir, true) != SEPG_CLASS_DIR) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not a directory", olddir))); -+ -+ required = SEPG_DIR__SEARCH | SEPG_DIR__REMOVE_NAME; -+ if (strcmp(olddir, newdir) == 0) -+ { -+ /* dir:{search remove_name add_name} */ -+ required |= SEPG_DIR__ADD_NAME; -+ sepgsql_file_common(olddir, SEPG_CLASS_DIR, required, true); -+ } -+ else -+ { -+ /* dir:{search remove_name (reparent)} */ -+ if (tclass == SEPG_CLASS_DIR) -+ required |= SEPG_DIR__REPARENT; -+ sepgsql_file_common(olddir, SEPG_CLASS_DIR, required, true); -+ -+ if (sepgsql_file_class(newdir, true) != SEPG_CLASS_DIR) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not a directory", newdir))); -+ -+ /* dir:{add_name} */ -+ sepgsql_file_common(newdir, SEPG_CLASS_DIR, -+ SEPG_DIR__ADD_NAME, true); -+ } -+ -+ /* file:{unlink} or dir:{DIR__RMDIR}, if necessary */ -+ tclass = sepgsql_file_class(newpath, false); -+ if (tclass == SEPG_CLASS_DIR) -+ sepgsql_file_common(newpath, tclass, SEPG_DIR__RMDIR, true); -+ else if (tclass > 0) -+ sepgsql_file_common(newpath, tclass, SEPG_FILE__UNLINK, true); -+ } -+#endif -+} -+ -+void -+sepgsql_dir_list(const char *dirname) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ uint16 tclass = sepgsql_file_class(dirname, true); -+ -+ if (tclass != SEPG_CLASS_DIR) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not directory", dirname))); -+ -+ sepgsql_file_common(dirname, tclass, SEPG_DIR__READ, true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/label.c b/src/backend/sepgsql/label.c -new file mode 100644 -index 0000000..ec8244d ---- /dev/null -+++ b/src/backend/sepgsql/label.c -@@ -0,0 +1,588 @@ -+/* -+ * label.c -+ * SE-PostgreSQL security label management -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "access/relscan.h" -+#include "access/xact.h" -+#include "catalog/pg_attribute.h" -+#include "catalog/pg_class.h" -+#include "catalog/pg_database.h" -+#include "catalog/pg_largeobject_metadata.h" -+#include "catalog/pg_namespace.h" -+#include "catalog/pg_proc.h" -+#include "catalog/pg_seclabel.h" -+#include "catalog/pg_type.h" -+#include "commands/dbcommands.h" -+#include "miscadmin.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/fmgroids.h" -+#include "utils/lsyscache.h" -+#include "utils/rel.h" -+#include "utils/syscache.h" -+#include "utils/tqual.h" -+#include // for workaround hack -+#include -+#include -+ -+/* -+ * guc parameter to turn on/off mcstrans -+ */ -+bool sepgsql_mcstrans; -+ -+sepgsql_sid_t -+sepgsql_move_secid(Oid dst_relid, sepgsql_sid_t ssid) -+{ -+ char *label; -+ sepgsql_sid_t dsid = { .relid = dst_relid, -+ .secid = InvalidOid }; -+ -+ label = seclabelRawOutput(ssid.relid, ssid.secid); -+ if (label) -+ { -+ dsid.secid = seclabelRawInput(dsid.relid, label); -+ -+ pfree(label); -+ } -+ return dsid; -+} -+ -+static sepgsql_sid_t -+get_default_secid_with_database(Oid relOid, Oid databaseOid, uint16 tclass) -+{ -+ HeapTuple tuple; -+ sepgsql_sid_t datsid; -+ -+ tuple = SearchSysCache1(DATABASEOID, -+ ObjectIdGetDatum(databaseOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for database: %u", databaseOid); -+ -+ datsid.relid = DatabaseRelationId; -+ datsid.secid = HeapTupleGetSecid(tuple); -+ -+ ReleaseSysCache(tuple); -+ -+ return sepgsql_client_create_secid(datsid, tclass, relOid); -+} -+ -+static sepgsql_sid_t -+get_default_secid_with_schema(Oid relOid, Oid namespaceOid, uint16 tclass) -+{ -+ HeapTuple tuple; -+ sepgsql_sid_t nspsid; -+ -+ tuple = SearchSysCache1(NAMESPACEOID, -+ ObjectIdGetDatum(namespaceOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for namespace: %u", namespaceOid); -+ -+ nspsid.relid = NamespaceRelationId; -+ nspsid.secid = HeapTupleGetSecid(tuple); -+ -+ ReleaseSysCache(tuple); -+ -+ return sepgsql_client_create_secid(nspsid, tclass, relOid); -+} -+ -+static sepgsql_sid_t -+get_default_secid_with_table(Oid relOid, Oid tableOid, uint16 tclass) -+{ -+ HeapTuple tuple; -+ sepgsql_sid_t tblsid; -+ -+ tuple = SearchSysCache1(RELOID, -+ ObjectIdGetDatum(tableOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for relation: %u", tableOid); -+ -+ tblsid.relid = RelationRelationId; -+ tblsid.secid = HeapTupleGetSecid(tuple); -+ -+ ReleaseSysCache(tuple); -+ -+ return sepgsql_client_create_secid(tblsid, tclass, relOid); -+} -+ -+sepgsql_sid_t -+sepgsql_get_default_database_secid(Oid templateOid) -+{ -+ return get_default_secid_with_database(DatabaseRelationId, -+ templateOid, -+ SEPG_CLASS_DB_DATABASE); -+} -+ -+sepgsql_sid_t -+sepgsql_get_default_schema_secid(Oid databaseOid) -+{ -+ return get_default_secid_with_database(NamespaceRelationId, -+ databaseOid, -+ SEPG_CLASS_DB_SCHEMA); -+} -+ -+sepgsql_sid_t -+sepgsql_get_default_table_secid(Oid namespaceOid) -+{ -+ return get_default_secid_with_schema(RelationRelationId, -+ namespaceOid, -+ SEPG_CLASS_DB_TABLE); -+} -+ -+sepgsql_sid_t -+sepgsql_get_default_sequence_secid(Oid namespaceOid) -+{ -+ return get_default_secid_with_schema(RelationRelationId, -+ namespaceOid, -+ SEPG_CLASS_DB_SEQUENCE); -+} -+ -+sepgsql_sid_t -+sepgsql_get_default_view_secid(Oid namespaceOid) -+{ -+ return get_default_secid_with_schema(RelationRelationId, -+ namespaceOid, -+ SEPG_CLASS_DB_VIEW); -+} -+ -+sepgsql_sid_t -+sepgsql_get_default_proc_secid(Oid namespaceOid) -+{ -+ return get_default_secid_with_schema(ProcedureRelationId, -+ namespaceOid, -+ SEPG_CLASS_DB_PROCEDURE); -+} -+ -+sepgsql_sid_t -+sepgsql_get_default_column_secid(Oid tableOid) -+{ -+ return get_default_secid_with_table(AttributeRelationId, -+ tableOid, -+ SEPG_CLASS_DB_COLUMN); -+} -+ -+sepgsql_sid_t -+sepgsql_get_default_tuple_secid(Oid tableOid) -+{ -+ return get_default_secid_with_table(tableOid, -+ tableOid, -+ SEPG_CLASS_DB_TUPLE); -+} -+ -+sepgsql_sid_t -+sepgsql_get_default_blob_secid(Oid databaseOid) -+{ -+ return get_default_secid_with_database(LargeObjectMetadataRelationId, -+ databaseOid, -+ SEPG_CLASS_DB_BLOB); -+} -+ -+Oid -+sepgsql_get_default_secid(Relation rel, HeapTuple tuple) -+{ -+ Oid namespaceId; -+ sepgsql_sid_t nsid -+ = { .relid = RelationGetRelid(rel), .secid = InvalidOid }; -+ -+ switch (RelationGetRelid(rel)) -+ { -+ case DatabaseRelationId: -+ case RelationRelationId: -+ case AttributeRelationId: -+ elog(WARNING, "Bug? a new tuple without security id on \"%s\"", -+ RelationGetRelationName(rel)); -+ break; -+ -+ case NamespaceRelationId: -+ nsid = sepgsql_get_default_schema_secid(MyDatabaseId); -+ break; -+ -+ case ProcedureRelationId: -+ namespaceId = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace; -+ nsid = sepgsql_get_default_proc_secid(namespaceId); -+ break; -+ -+ case LargeObjectMetadataRelationId: -+ nsid = sepgsql_get_default_blob_secid(MyDatabaseId); -+ break; -+ -+ default: -+ nsid = sepgsql_get_default_tuple_secid(RelationGetRelid(rel)); -+ break; -+ } -+ return nsid.secid; -+} -+ -+static Oid -+sepgsql_initial_labeling_lookup(struct selabel_handle *sehnd, -+ Oid relationId, HeapTuple tuple) -+{ -+ Form_pg_database datForm; -+ Form_pg_namespace nspForm; -+ Form_pg_class clsForm; -+ Form_pg_attribute attForm; -+ Form_pg_proc proForm; -+ char namebuf[NAMEDATALEN * 3 + 10]; -+ Oid namespaceId; -+ Oid securityId = InvalidOid; -+ int type = 0; -+ security_context_t context; -+ -+ switch (relationId) -+ { -+ case DatabaseRelationId: -+ datForm = (Form_pg_database) GETSTRUCT(tuple); -+ snprintf(namebuf, sizeof(namebuf), "%s", -+ NameStr(datForm->datname)); -+ type = SELABEL_DB_DATABASE; -+ break; -+ -+ case NamespaceRelationId: -+ nspForm = (Form_pg_namespace) GETSTRUCT(tuple); -+ snprintf(namebuf, sizeof(namebuf), "%s.%s", -+ get_database_name(MyDatabaseId), -+ NameStr(nspForm->nspname)); -+ type = SELABEL_DB_SCHEMA; -+ break; -+ -+ case RelationRelationId: -+ clsForm = (Form_pg_class) GETSTRUCT(tuple); -+ namespaceId = clsForm->relnamespace; -+ switch (clsForm->relkind) -+ { -+ case RELKIND_RELATION: -+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s", -+ get_database_name(MyDatabaseId), -+ get_namespace_name(namespaceId), -+ NameStr(clsForm->relname)); -+ type = SELABEL_DB_TABLE; -+ break; -+ -+ case RELKIND_SEQUENCE: -+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s", -+ get_database_name(MyDatabaseId), -+ get_namespace_name(namespaceId), -+ NameStr(clsForm->relname)); -+ type = SELABEL_DB_SEQUENCE; -+ break; -+ -+ case RELKIND_VIEW: -+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s", -+ get_database_name(MyDatabaseId), -+ get_namespace_name(namespaceId), -+ NameStr(clsForm->relname)); -+ type = SELABEL_DB_VIEW; -+ break; -+ -+ case RELKIND_INDEX: { -+ HeapTuple tbltup; -+ HeapTuple indtup; -+ Oid tableId; -+ -+ indtup = SearchSysCache1(INDEXRELID, -+ ObjectIdGetDatum(HeapTupleGetOid(tuple))); -+ if (!HeapTupleIsValid(indtup)) -+ elog(ERROR, "cache lookup failed for index %u", -+ HeapTupleGetOid(tuple)); -+ -+ tableId = ((Form_pg_index) GETSTRUCT(indtup))->indrelid; -+ tbltup = SearchSysCache1(RELOID, ObjectIdGetDatum(tableId)); -+ if (!HeapTupleIsValid(tbltup)) -+ elog(ERROR, "cache lookup failed for relation %u", tableId); -+ -+ securityId = sepgsql_initial_labeling_lookup(sehnd, RelationRelationId, tbltup); -+ -+ ReleaseSysCache(tbltup); -+ ReleaseSysCache(indtup); -+ -+ return securityId; -+ } -+ case RELKIND_TOASTVALUE: { -+ HeapTuple tbltup; -+ Oid tableId; -+ -+ /* -+ * XXX - we assume all the toast relation's name is -+ * "pg_toast_%u", and the "%u" shall be replaced by OID -+ * of the relation which owns the toast relation -+ */ -+ tableId = strtoul(NameStr(clsForm->relname) + 9, NULL, 10); -+ -+ tbltup = SearchSysCache1(RELOID, -+ ObjectIdGetDatum(tableId)); -+ if (!HeapTupleIsValid(tbltup)) -+ elog(ERROR, "cache lookup failed for relation %u", tableId); -+ -+ securityId = sepgsql_initial_labeling_lookup(sehnd, RelationRelationId, tbltup); -+ -+ ReleaseSysCache(tbltup); -+ -+ return securityId; -+ } -+ case RELKIND_COMPOSITE_TYPE: { -+ HeapTuple typtup; -+ -+ typtup = SearchSysCache1(TYPEOID, -+ ObjectIdGetDatum(clsForm->reltype)); -+ if (!HeapTupleIsValid(typtup)) -+ elog(ERROR, "cache lookup failed for type %u", clsForm->reltype); -+ -+ securityId = sepgsql_initial_labeling_lookup(sehnd, TypeRelationId, typtup); -+ -+ ReleaseSysCache(typtup); -+ -+ return securityId; -+ } -+ default: -+ elog(ERROR, "unexpected relkind %c of \"%s\"", -+ clsForm->relkind, NameStr(clsForm->relname)); -+ break; -+ } -+ break; -+ -+ case AttributeRelationId: -+ attForm = (Form_pg_attribute) GETSTRUCT(tuple); -+ if (get_rel_relkind(attForm->attrelid) == RELKIND_RELATION) -+ { -+ namespaceId = get_rel_namespace(attForm->attrelid); -+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s.%s", -+ get_database_name(MyDatabaseId), -+ get_namespace_name(namespaceId), -+ get_rel_name(attForm->attrelid), -+ NameStr(attForm->attname)); -+ type = SELABEL_DB_COLUMN; -+ } -+ else -+ { -+ HeapTuple classTup; -+ -+ classTup = SearchSysCache1(RELOID, ObjectIdGetDatum(attForm->attrelid)); -+ if (!HeapTupleIsValid(classTup)) -+ elog(ERROR, "cache lookup failed for relation %u", attForm->attrelid); -+ -+ securityId = sepgsql_initial_labeling_lookup(sehnd, RelationRelationId, classTup); -+ -+ ReleaseSysCache(classTup); -+ -+ return securityId; -+ } -+ break; -+ -+ case ProcedureRelationId: -+ proForm = (Form_pg_proc) GETSTRUCT(tuple); -+ namespaceId = proForm->pronamespace; -+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s", -+ get_database_name(MyDatabaseId), -+ get_namespace_name(namespaceId), -+ NameStr(proForm->proname)); -+ type = SELABEL_DB_PROCEDURE; -+ break; -+ -+ case LargeObjectMetadataRelationId: -+ snprintf(namebuf, sizeof(namebuf), "%s.%u", -+ get_database_name(MyDatabaseId), -+ HeapTupleGetOid(tuple)); -+ type = SELABEL_DB_BLOB; -+ break; -+ -+ default: -+ namespaceId = get_rel_namespace(relationId); -+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s", -+ get_database_name(MyDatabaseId), -+ get_namespace_name(namespaceId), -+ get_rel_name(relationId)); -+ type = SELABEL_DB_TUPLE; -+ break; -+ } -+ -+ if (selabel_lookup_raw(sehnd, &context, namebuf, type) == 0) -+ { -+ PG_TRY(); -+ { -+ securityId = seclabelTransInput(relationId, context); -+ } -+ PG_CATCH(); -+ { -+ freecon(context); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(context); -+ } -+ else if (errno == ENOENT) -+ elog(WARNING, -+ "SELinux: no initial label assigned for %s (type=%d), skipping", -+ namebuf, type); -+ else -+ elog(ERROR, -+ "SELinux: could not determine initial security label for %s (type=%d): %m", -+ namebuf, type); -+ -+ return securityId; -+} -+ -+void -+sepgsql_initial_labeling(void) -+{ -+ Relation classRel; -+ SysScanDesc classScan; -+ ScanKeyData classSkey; -+ HeapTuple classTup; -+ struct selabel_handle *sehnd; -+ -+ Assert(IsBootstrapProcessingMode()); -+ -+ StartTransactionCommand(); -+ -+ sehnd = selabel_open(SELABEL_CTX_DB, NULL, 0); -+ if (!sehnd) -+ elog(ERROR, "failed to open initial selinux label"); -+ -+ classRel = heap_open(RelationRelationId, AccessShareLock); -+ -+ ScanKeyInit(&classSkey, -+ Anum_pg_class_relhassecids, -+ BTEqualStrategyNumber, F_BOOLEQ, -+ BoolGetDatum(true)); -+ -+ classScan = systable_beginscan(classRel, InvalidOid, false, -+ SnapshotNow, 1, &classSkey); -+ -+ while (HeapTupleIsValid(classTup = systable_getnext(classScan))) -+ { -+ Relation rel; -+ HeapScanDesc scan; -+ HeapTuple oldtup; -+ HeapTuple newtup; -+ Oid relOid = HeapTupleGetOid(classTup); -+ -+ Assert(((Form_pg_class) GETSTRUCT(classTup))->relhassecids); -+ -+ rel = heap_open(relOid, RowExclusiveLock); -+ -+ scan = heap_beginscan(rel, SnapshotNow, 0, NULL); -+ -+ while (HeapTupleIsValid(oldtup = heap_getnext(scan, ForwardScanDirection))) -+ { -+ Oid securityId = sepgsql_initial_labeling_lookup(sehnd, relOid, oldtup); -+ -+ /* -+ * inplace-updating -+ */ -+ newtup = heap_copytuple(oldtup); -+ -+ HeapTupleSetSecid(newtup, securityId); -+ -+ heap_inplace_update(rel, newtup); -+ -+ heap_freetuple(newtup); -+ } -+ -+ heap_endscan(scan); -+ -+ heap_close(rel, RowExclusiveLock); -+ } -+ systable_endscan(classScan); -+ -+ heap_close(classRel, AccessShareLock); -+ -+ selabel_close(sehnd); -+ -+ CommitTransactionCommand(); -+} -+ -+char * -+sepgsql_mcstrans_in(char *trans_label) -+{ -+ security_context_t raw_label; -+ security_context_t result; -+ -+ if (!sepgsql_mcstrans) -+ return trans_label; -+ -+ if (selinux_trans_to_raw_context(trans_label, &raw_label) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("SELinux: unable to translate \"%s\"", trans_label))); -+ PG_TRY(); -+ { -+ result = pstrdup(raw_label); -+ } -+ PG_CATCH(); -+ { -+ freecon(raw_label); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(raw_label); -+ -+ return result; -+} -+ -+char * -+sepgsql_mcstrans_out(char *raw_label) -+{ -+ security_context_t trans_label; -+ security_context_t result; -+ -+ if (!sepgsql_mcstrans) -+ return raw_label; -+ -+ if (selinux_raw_to_trans_context(raw_label, &trans_label) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("SELinux: unable to translate \"%s\"", raw_label))); -+ PG_TRY(); -+ { -+ result = pstrdup(trans_label); -+ } -+ PG_CATCH(); -+ { -+ freecon(trans_label); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(trans_label); -+ -+ return result; -+} -+ -+char * -+sepgsql_rawlabel_in(char *label) -+{ -+ if (!label || security_check_context_raw(label) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_NAME), -+ errmsg("invalid security context \"%s\"", label))); -+ return label; -+} -+ -+char * -+sepgsql_rawlabel_out(char *label) -+{ -+ if (!label || security_check_context_raw(label) < 0) -+ { -+ security_context_t unlabeled_label; -+ -+ if (security_get_initial_context_raw("unlabeled", -+ &unlabeled_label) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("unable to get unlabeled security context"))); -+ PG_TRY(); -+ { -+ label = pstrdup(unlabeled_label); -+ } -+ PG_CATCH(); -+ { -+ freecon(unlabeled_label); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(unlabeled_label); -+ } -+ return label; -+} -diff --git a/src/backend/sepgsql/misc.c b/src/backend/sepgsql/misc.c -new file mode 100644 -index 0000000..377a72b ---- /dev/null -+++ b/src/backend/sepgsql/misc.c -@@ -0,0 +1,147 @@ -+/* -+ * misc.c -+ * -+ * SELinux hooks related to misc features -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "libpq/libpq-be.h" -+#include "miscadmin.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/builtins.h" -+#include "utils/fmgroids.h" -+#include "utils/guc.h" -+ -+#include -+ -+/* -+ * sepgsql_client_label -+ * -+ * security context of the peer process -+ */ -+static char *sepgsql_client_label = NULL; -+ -+char * -+sepgsql_get_client_label(void) -+{ -+ return sepgsql_client_label; -+} -+ -+char * -+sepgsql_set_client_label(char *new_label) -+{ -+ char *old_label = sepgsql_client_label; -+ -+ sepgsql_client_label = new_label; -+ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* -+ * NOTE: When an error happened prior to initialization of -+ * SE-PostgreSQL, NULL maight be delivered. In this case, -+ * we don't need to reset avc. -+ */ -+ if (new_label != NULL) -+ sepgsql_avc_switch(new_label); -+ } -+#endif -+ return old_label; -+} -+ -+void -+sepgsql_post_bootstraping(void) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ sepgsql_initial_labeling(); -+#endif -+} -+ -+void -+sepgsql_initialize(void) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ security_context_t context; -+ -+ /* init userspace avc */ -+ sepgsql_avc_init(); -+ -+ /* init privilege of the client */ -+ if (!MyProcPort) -+ { -+ /* -+ * SE-PgSQL does not prevent anything in single-user mode. -+ */ -+ sepostgresql_mode = SEPGSQL_MODE_INTERNAL; -+ -+ if (getprevcon_raw(&context) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("SELinux: could not get server context"))); -+ } -+ else -+ { -+ if (getpeercon_raw(MyProcPort->sock, &context) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("SELinux: could not get client context"))); -+ } -+ sepgsql_set_client_label(context); -+ -+ return; -+ } -+#endif -+ if (default_with_secids) -+ { -+ default_with_secids = false; -+ elog(LOG, "guc: default_with_secid was turned off " -+ "because no label based access control is availabel now"); -+ } -+} -+ -+bool -+sepgsql_worker_needed(void) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ return true; -+#endif -+ return false; -+} -+ -+void -+sepgsql_worker_main(void) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_avc_worker_main(); -+ return; -+ } -+#endif -+ elog(FATAL, "Bug? try to launch worker process without security provider"); -+} -+ -+Datum -+sepgsql_getcon(PG_FUNCTION_ARGS) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ char *label = sepgsql_get_client_label(); -+ -+ PG_RETURN_TEXT_P(cstring_to_text(label)); -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ PG_RETURN_NULL(); -+} -diff --git a/src/backend/sepgsql/operator.c b/src/backend/sepgsql/operator.c -new file mode 100644 -index 0000000..7960525 ---- /dev/null -+++ b/src/backend/sepgsql/operator.c -@@ -0,0 +1,454 @@ -+/* -+ * operator.c -+ * -+ * SELinux hooks related to operators -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_operator.h" -+#include "catalog/pg_opclass.h" -+#include "catalog/pg_opfamily.h" -+#include "catalog/pg_seclabel.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/builtins.h" -+#include "utils/lsyscache.h" -+#include "utils/syscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_operator_common(Oid operOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ char *auname; -+ bool retval; -+ -+ tsid.relid = OperatorRelationId; -+ tsid.secid = GetSysCacheSecid1(OPEROID, ObjectIdGetDatum(operOid)); -+ -+ auname = format_operator(operOid); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ pfree(auname); -+ -+ return retval; -+} -+ -+bool -+sepgsql_opclass_common(Oid opcOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ HeapTuple tuple; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for operator class %u", opcOid); -+ -+ tsid.relid = OperatorClassRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+bool -+sepgsql_opfamily_common(Oid opfOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ HeapTuple tuple; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for operator family %u", opfOid); -+ -+ tsid.relid = OperatorFamilyRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_opfamily) GETSTRUCT(tuple))->opfname); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+static Oid -+get_operator_namespace(Oid operOid) -+{ -+ HeapTuple tuple; -+ Oid namespaceId; -+ -+ tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); -+ if (HeapTupleIsValid(tuple)) -+ { -+ namespaceId = ((Form_pg_operator) GETSTRUCT(tuple))->oprnamespace; -+ -+ ReleaseSysCache(tuple); -+ } -+ return namespaceId; -+} -+ -+static Oid -+get_opclass_namespace(Oid opcOid) -+{ -+ HeapTuple tuple; -+ Oid namespaceId = InvalidOid; -+ -+ tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcOid)); -+ if (HeapTupleIsValid(tuple)) -+ { -+ namespaceId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcnamespace; -+ -+ ReleaseSysCache(tuple); -+ } -+ return namespaceId; -+} -+ -+static Oid -+get_opfamily_namespace(Oid opfOid) -+{ -+ HeapTuple tuple; -+ Oid namespaceId = InvalidOid; -+ -+ tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfOid)); -+ if (HeapTupleIsValid(tuple)) -+ { -+ namespaceId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfnamespace; -+ -+ ReleaseSysCache(tuple); -+ } -+ return namespaceId; -+} -+ -+#endif -+ -+Oid -+sepgsql_operator_create(const char *operName, Oid replaced, Oid namespaceId, -+ Oid codeFunc, Oid restrictFunc, Oid joinFunc, -+ Oid commutatorOp, Oid negatorOp) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ uint32 required; -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_tuple:{insert} */ -+ if (OidIsValid(replaced)) -+ { -+ nsid.relid = OperatorRelationId; -+ nsid.secid = GetSysCacheSecid1(OPEROID, -+ ObjectIdGetDatum(replaced)); -+ required = SEPG_DB_TUPLE__UPDATE; -+ } -+ else -+ { -+ nsid = sepgsql_get_default_tuple_secid(OperatorRelationId); -+ required = SEPG_DB_TUPLE__INSERT; -+ } -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ operName, -+ true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(codeFunc)) -+ sepgsql_proc_common(codeFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(restrictFunc)) -+ sepgsql_proc_common(restrictFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(joinFunc)) -+ sepgsql_proc_common(joinFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* -+ * XXX - we should check anything on he commutatorOp/negatorOp -+ */ -+ -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_operator_alter(Oid operOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_operator_common(operOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_operator_relabel(Oid operOid, char *newLabel) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ -+ nsid.relid = OperatorRelationId; -+ nsid.secid = seclabelTransInput(OperatorRelationId, newLabel); -+ -+ /* db_tuple:{update relabelfrom} */ -+ sepgsql_operator_common(operOid, -+ SEPG_DB_TUPLE__UPDATE | -+ SEPG_DB_TUPLE__RELABELFROM, -+ true); -+ -+ /* db_tuple:{relabelto} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__RELABELTO, -+ format_operator(operOid), -+ true); -+ return nsid.secid; -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ return InvalidOid; -+} -+ -+void -+sepgsql_operator_drop(Oid operOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_operator_namespace(operOid); -+ -+ /* db_namespace:{remove_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{delete} */ -+ sepgsql_operator_common(operOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_operator_comment(Oid operOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_operator_common(operOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_opclass_create(const char *opcName, Oid namespaceId, -+ Oid typeOid, Oid opfamilyOid, Oid storageOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_TUPLE__UPDATE, true); -+ -+ /* db_tuple:{insert} */ -+ nsid = sepgsql_get_default_tuple_secid(OperatorRelationId); -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ opcName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_opclass_alter(Oid opcOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_opclass_common(opcOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_opclass_alter_rename(Oid opcOid, const char *newName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_opclass_namespace(opcOid); -+ -+ /* db_schema:{add_name remove_name} */ -+ sepgsql_schema_common(namespaceId, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{update} */ -+ sepgsql_opclass_common(opcOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_opclass_drop(Oid opcOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_opclass_namespace(opcOid); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{drop} */ -+ sepgsql_opclass_common(opcOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_opclass_comment(Oid opcOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_opclass_common(opcOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_opfamily_create(const char *opfName, Oid namespaceId, Oid amOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_tuple:{insert} */ -+ nsid = sepgsql_get_default_tuple_secid(OperatorFamilyRelationId); -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ opfName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_opfamily_alter(Oid opfOid, bool isDrop, Oid amOid, -+ List *operators, List *procedures) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_opfamily_common(opfOid, SEPG_DB_TUPLE__UPDATE, true); -+ -+ /* XXX - to do we should install checks? */ -+ } -+#endif -+} -+ -+void -+sepgsql_opfamily_alter_rename(Oid opfOid, const char *newName) -+{ -+ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_opfamily_namespace(opfOid); -+ -+ /* db_schema:{add_name remove_name} */ -+ sepgsql_schema_common(namespaceId, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{update} */ -+ sepgsql_opfamily_common(opfOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_opfamily_alter_owner(Oid opfOid, Oid newOwner) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_opfamily_common(opfOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_opfamily_drop(Oid opfOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_opfamily_namespace(opfOid); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{delete} */ -+ sepgsql_opfamily_common(opfOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_opfamily_comment(Oid opfOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_opfamily_common(opfOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/proc.c b/src/backend/sepgsql/proc.c -new file mode 100644 -index 0000000..1149571 ---- /dev/null -+++ b/src/backend/sepgsql/proc.c -@@ -0,0 +1,366 @@ -+/* -+ * proc.c -+ * -+ * SELinux hooks related to procedures -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_aggregate.h" -+#include "catalog/pg_language.h" -+#include "catalog/pg_namespace.h" -+#include "catalog/pg_proc.h" -+#include "catalog/pg_seclabel.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/builtins.h" -+#include "utils/syscache.h" -+#include "utils/lsyscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_proc_common(Oid procOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ char *auname; -+ bool retval; -+ -+ tsid.relid = ProcedureRelationId; -+ tsid.secid = GetSysCacheSecid1(PROCOID, -+ ObjectIdGetDatum(procOid)); -+ -+ auname = format_procedure(procOid); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_PROCEDURE, -+ required, -+ auname, -+ abort); -+ pfree(auname); -+ -+ return retval; -+} -+#endif -+ -+Oid -+sepgsql_proc_create(const char *proName, Oid replaced, -+ Oid namespaceId, Oid languageId) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ HeapTuple tuple; -+ sepgsql_sid_t nsid; -+ char *scontext; -+ char *tcontext; -+ uint32 required; -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_procedure:{create or setattr} */ -+ if (OidIsValid(replaced)) -+ { -+ nsid.relid = ProcedureRelationId; -+ nsid.secid = GetSysCacheSecid1(PROCOID, -+ ObjectIdGetDatum(replaced)); -+ required = SEPG_DB_PROCEDURE__SETATTR; -+ } -+ else -+ { -+ nsid = sepgsql_get_default_proc_secid(namespaceId); -+ required = SEPG_DB_PROCEDURE__CREATE; -+ } -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_PROCEDURE, -+ required, -+ proName, -+ true); -+ -+ /* db_language:{implemente} */ -+ tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(languageId)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for language %u", languageId); -+ -+ scontext = seclabelRawOutput(LanguageRelationId, -+ HeapTupleGetSecid(tuple)); -+ tcontext = seclabelRawOutput(nsid.relid, nsid.secid); -+ -+ sepgsql_compute_perms(scontext, tcontext, -+ SEPG_CLASS_DB_LANGUAGE, -+ SEPG_DB_LANGUAGE__IMPLEMENTE, -+ proName, true); -+ -+ ReleaseSysCache(tuple); -+ -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_proc_alter(Oid procOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_proc_alter_rename(Oid procOid, const char *newName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_func_namespace(procOid); -+ -+ /* db_schema:{remove_name add_name} */ -+ sepgsql_schema_common(namespaceId, -+ SEPG_DB_SCHEMA__REMOVE_NAME | -+ SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_procedure:{setattr} */ -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_proc_alter_schema(Oid procOid, Oid newSchema) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_func_namespace(procOid); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(newSchema, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_procedure:{setattr} */ -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_proc_relabel(Oid procOid, char *new_label) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t tsid; -+ -+ tsid.relid = ProcedureRelationId; -+ tsid.secid = seclabelTransInput(tsid.relid, new_label); -+ -+ /* db_procedure:{setattr relabelfrom} */ -+ sepgsql_proc_common(procOid, -+ SEPG_DB_PROCEDURE__SETATTR | -+ SEPG_DB_PROCEDURE__RELABELFROM, true); -+ -+ /* db_procedure:{relabelto} */ -+ sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_DB_PROCEDURE__RELABELTO, -+ format_procedure(procOid), -+ true); -+ return tsid.secid; -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ return InvalidOid; -+} -+ -+void -+sepgsql_proc_drop(Oid procOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_func_namespace(procOid); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_procedure:{proc} */ -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__DROP, true); -+ } -+#endif -+} -+ -+void -+sepgsql_proc_grant(Oid procOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_proc_comment(Oid procOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_proc_execute(Oid procOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__EXECUTE, true); -+ } -+#endif -+} -+ -+bool -+sepgsql_proc_be_inlined(HeapTuple protup) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t tsid; -+ char *old_label; -+ char *new_label; -+ const char *auname -+ = NameStr(((Form_pg_proc) GETSTRUCT(protup))->proname); -+ -+ tsid.relid = ProcedureRelationId; -+ tsid.secid = HeapTupleGetSecid(protup); -+ -+ if (!sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_DB_PROCEDURE__EXECUTE, -+ auname, false)) -+ return false; -+ -+ old_label = sepgsql_get_client_label(); -+ new_label = sepgsql_client_create_label(tsid, SEPG_CLASS_PROCESS); -+ if (strcmp(old_label, new_label) != 0) -+ return false; -+ -+ return true; -+ } -+#endif -+ return true; -+} -+ -+char * -+sepgsql_proc_domtrans(HeapTuple protup, MemoryContext mcxt) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t tsid; -+ char *old_label = sepgsql_get_client_label(); -+ char *new_label; -+ char *auname -+ = NameStr(((Form_pg_proc) GETSTRUCT(protup))->proname); -+ -+ tsid.relid = ProcedureRelationId; -+ tsid.secid = HeapTupleGetSecid(protup); -+ -+ new_label = sepgsql_client_create_label(tsid, SEPG_CLASS_PROCESS); -+ -+ if (strcmp(old_label, new_label) == 0) -+ return NULL; -+ -+ /* db_procedure:{entrypoint} */ -+ sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_DB_PROCEDURE__ENTRYPOINT, -+ auname, -+ true); -+ -+ /* db_process:{transition} */ -+ sepgsql_compute_perms(old_label, -+ new_label, -+ SEPG_CLASS_PROCESS, -+ SEPG_PROCESS__TRANSITION, -+ NULL, -+ true); -+ -+ return MemoryContextStrdup(mcxt, new_label); -+ } -+#endif -+ return NULL; -+} -+ -+Oid -+sepgsql_aggregate_create(const char *aggName, Oid namespaceId, -+ Oid transFunc, Oid finalFunc) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid securityId; -+ -+ /* check normal creation permission */ -+ securityId = sepgsql_proc_create(aggName, InvalidOid, -+ namespaceId, INTERNALlanguageId); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(transFunc)) -+ sepgsql_proc_common(transFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(finalFunc)) -+ sepgsql_proc_common(finalFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return securityId; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_aggregate_execute(Oid aggOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Form_pg_aggregate aggForm; -+ HeapTuple tuple; -+ -+ tuple = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(aggOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for aggregate %u", aggOid); -+ -+ aggForm = (Form_pg_aggregate) GETSTRUCT(tuple); -+ -+ /* pg_proc:{execute} */ -+ sepgsql_proc_common(aggOid, SEPG_DB_PROCEDURE__EXECUTE, true); -+ -+ /* pg_proc:{execute} */ -+ if (OidIsValid(aggForm->aggtransfn)) -+ sepgsql_proc_common(aggForm->aggtransfn, -+ SEPG_DB_PROCEDURE__EXECUTE, true); -+ -+ /* pg_proc:{execute} */ -+ if (OidIsValid(aggForm->aggfinalfn)) -+ sepgsql_proc_common(aggForm->aggfinalfn, -+ SEPG_DB_PROCEDURE__EXECUTE, true); -+ -+ ReleaseSysCache(tuple); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/relation.c b/src/backend/sepgsql/relation.c -new file mode 100644 -index 0000000..2604749 ---- /dev/null -+++ b/src/backend/sepgsql/relation.c -@@ -0,0 +1,819 @@ -+/* -+ * relation.c -+ * -+ * SELinux hooks related to relation -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "access/sysattr.h" -+#include "catalog/catalog.h" -+#include "catalog/heap.h" -+#include "catalog/pg_attribute.h" -+#include "catalog/pg_class.h" -+#include "catalog/pg_seclabel.h" -+#include "catalog/pg_type.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/lsyscache.h" -+#include "utils/syscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_relation_common(Oid relOid, uint32 required, bool abort) -+{ -+ Form_pg_class classForm; -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ uint16 tclass; -+ bool retval; -+ -+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for relation %u", relOid); -+ classForm = (Form_pg_class) GETSTRUCT(tuple); -+ -+ tsid.relid = RelationRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ switch (classForm->relkind) -+ { -+ case RELKIND_SEQUENCE: -+ tclass = SEPG_CLASS_DB_SEQUENCE; -+ break; -+ -+ case RELKIND_VIEW: -+ tclass = SEPG_CLASS_DB_VIEW; -+ break; -+ -+ case RELKIND_COMPOSITE_TYPE: -+ tclass = SEPG_CLASS_DB_TUPLE; -+ break; -+ -+ default: -+ tclass = SEPG_CLASS_DB_TABLE; -+ break; -+ } -+ -+ retval = sepgsql_client_perms(tsid, -+ tclass, -+ required, -+ NameStr(classForm->relname), -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+static Bitmapset * -+fixup_whole_row_reference(Oid relOid, int natts, Bitmapset *columns) -+{ -+ Bitmapset *result; -+ AttrNumber attno; -+ -+ attno = InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber; -+ if (!bms_is_member(attno, columns)) -+ return columns; /* no need to fixup */ -+ -+ result = bms_copy(columns); -+ result = bms_del_member(result, attno); -+ -+ for (attno=1; attno <= natts; attno++) -+ { -+ Form_pg_attribute attForm; -+ HeapTuple atttup; -+ -+ atttup = SearchSysCache2(ATTNUM, -+ ObjectIdGetDatum(relOid), -+ Int16GetDatum(attno)); -+ if (!HeapTupleIsValid(atttup)) -+ continue; -+ -+ attForm = (Form_pg_attribute) GETSTRUCT(atttup); -+ if (!attForm->attisdropped) -+ { -+ int cindex = attno - FirstLowInvalidHeapAttributeNumber; -+ result = bms_add_member(result, cindex); -+ } -+ ReleaseSysCache(atttup); -+ } -+ -+ return result; -+} -+#endif -+ -+bool -+sepgsql_relation_perms(Oid relOid, AclMode aclmask, -+ Bitmapset *selectedCols, -+ Bitmapset *modifiedCols, bool abort) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Form_pg_class relForm; -+ HeapTuple tuple; -+ sepgsql_sid_t rsid; -+ Bitmapset *selColsEx; -+ Bitmapset *modColsEx; -+ Bitmapset *columns; -+ AttrNumber nattrs; -+ AttrNumber attno; -+ const char *auname; -+ char relkind; -+ uint16 tclass = 0; -+ uint32 required = 0; -+ bool rc = true; -+ -+ /* -+ * Hardwired policy: -+ * SE-PostgreSQL enforces clients cannot modify system catalogs -+ * and access toast values using DML statements in enforcing mode. -+ * Note that it performs in permissive mode during initdb phase. -+ */ -+ if (sepgsql_get_enforce()) -+ { -+ if (IsSystemNamespace(get_rel_namespace(relOid)) && -+ (aclmask & (ACL_UPDATE | ACL_INSERT | ACL_DELETE)) != 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("not allowed to modify system catalog \"%s\"", -+ get_rel_name(relOid)))); -+ -+ if (get_rel_relkind(relOid) == RELKIND_TOASTVALUE) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("not allowed to access toast values \"%s\"", -+ get_rel_name(relOid)))); -+ } -+ -+ /* -+ * check relation's permissions -+ */ -+ tuple = SearchSysCache1(RELOID, -+ ObjectIdGetDatum(relOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for relation %u", relOid); -+ -+ rsid.relid = RelationRelationId; -+ rsid.secid = HeapTupleGetSecid(tuple); -+ -+ relForm = (Form_pg_class) GETSTRUCT(tuple); -+ auname = NameStr(relForm->relname); -+ relkind = relForm->relkind; -+ nattrs = relForm->relnatts; -+ -+ switch (relkind) -+ { -+ case RELKIND_RELATION: -+ tclass = SEPG_CLASS_DB_TABLE; -+ -+ if (aclmask & ACL_SELECT) -+ required |= SEPG_DB_TABLE__SELECT; -+ if (aclmask & ACL_INSERT) -+ required |= SEPG_DB_TABLE__INSERT; -+ if (aclmask & ACL_UPDATE) -+ required |= (!modifiedCols -+ ? SEPG_DB_TABLE__LOCK -+ : SEPG_DB_TABLE__UPDATE); -+ if (aclmask & ACL_DELETE) -+ required |= SEPG_DB_TABLE__DELETE; -+ break; -+ -+ case RELKIND_SEQUENCE: -+ tclass = SEPG_CLASS_DB_SEQUENCE; -+ if (aclmask & ACL_SELECT) -+ required |= SEPG_DB_SEQUENCE__GET_VALUE; -+ break; -+ -+ case RELKIND_VIEW: -+ tclass = SEPG_CLASS_DB_VIEW; -+ if (aclmask != 0) -+ required |= SEPG_DB_VIEW__EXPAND; -+ break; -+ -+ default: -+ elog(ERROR, "Bug? unexpected relkind %c", relkind); -+ return false; -+ } -+ -+ if (required != 0) -+ rc = sepgsql_client_perms(rsid, tclass, required, auname, abort); -+ -+ ReleaseSysCache(tuple); -+ -+ if (!rc || relkind != RELKIND_RELATION) -+ return rc; -+ -+ /* -+ * Check column's permissions -+ */ -+ selColsEx = fixup_whole_row_reference(relOid, nattrs, -+ selectedCols); -+ modColsEx = fixup_whole_row_reference(relOid, nattrs, -+ modifiedCols); -+ columns = bms_union(selColsEx, modColsEx); -+ -+ while ((attno = bms_first_member(columns)) >= 0) -+ { -+ required = 0; -+ -+ if (bms_is_member(attno, selColsEx)) -+ required |= SEPG_DB_COLUMN__SELECT; -+ if (bms_is_member(attno, modColsEx)) -+ { -+ if (aclmask & ACL_UPDATE) -+ required |= SEPG_DB_COLUMN__UPDATE; -+ if (aclmask & ACL_INSERT) -+ required |= SEPG_DB_COLUMN__INSERT; -+ } -+ if (required == 0) -+ continue; -+ -+ attno += FirstLowInvalidHeapAttributeNumber; -+ rc = sepgsql_attribute_common(relOid, attno, required, abort); -+ if (!rc) -+ break; -+ } -+ -+ if (selColsEx != selectedCols) -+ bms_free(selColsEx); -+ if (modColsEx != modifiedCols) -+ bms_free(modColsEx); -+ bms_free(columns); -+ -+ return rc; -+ } -+#endif -+ return true; -+} -+ -+Oid * -+sepgsql_relation_create(const char *relName, -+ char relkind, -+ TupleDesc tupDesc, -+ Oid namespaceId, -+ List *supOids, -+ bool createAs) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t tsid; -+ sepgsql_sid_t csid; -+ Oid *secLabels; -+ uint16 tclass; -+ uint32 perms; -+ AttrNumber index, attno, nitems; -+ -+ /* -+ * The secLabeld array stores security identifiers to be -+ * assigned on the new table and columns. -+ * -+ * secLabels[0] is security-id of the relation. -+ * secLabels[attnum - FirstLowInvalidHeapAttributeNumber] -+ * is security-id of the columns. -+ */ -+ secLabels = seclabelMakeRelationDefaults(tupDesc, supOids); -+ nitems = tupDesc->natts - FirstLowInvalidHeapAttributeNumber; -+ -+ switch (relkind) -+ { -+ case RELKIND_RELATION: -+ if (!OidIsValid(secLabels[0])) -+ { -+ tsid = sepgsql_get_default_table_secid(namespaceId); -+ secLabels[0] = tsid.secid; -+ } -+ tclass = SEPG_CLASS_DB_TABLE; -+ perms = SEPG_DB_TABLE__CREATE; -+ if (createAs) -+ perms |= SEPG_DB_TABLE__INSERT; -+ break; -+ -+ case RELKIND_SEQUENCE: -+ if (!OidIsValid(secLabels[0])) -+ { -+ tsid = sepgsql_get_default_sequence_secid(namespaceId); -+ secLabels[0] = tsid.secid; -+ } -+ tclass = SEPG_CLASS_DB_SEQUENCE; -+ perms = SEPG_DB_SEQUENCE__CREATE; -+ break; -+ -+ case RELKIND_VIEW: -+ if (!OidIsValid(secLabels[0])) -+ { -+ tsid = sepgsql_get_default_view_secid(namespaceId); -+ secLabels[0] = tsid.secid; -+ } -+ tclass = SEPG_CLASS_DB_VIEW; -+ perms = SEPG_DB_VIEW__CREATE; -+ break; -+ -+ case RELKIND_COMPOSITE_TYPE: -+ if (!OidIsValid(secLabels[0])) -+ { -+ tsid = sepgsql_get_default_tuple_secid(TypeRelationId); -+ secLabels[0] = seclabelMoveSecid(RelationRelationId, -+ TypeRelationId, tsid.secid); -+ } -+ tclass = SEPG_CLASS_DB_TUPLE; -+ perms = SEPG_DB_TUPLE__INSERT; -+ break; -+ -+ default: -+ elog(ERROR, "Bug? unexpected relkind %c", relkind); -+ return NULL; -+ } -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_table:{create} or others */ -+ tsid.relid = RelationRelationId; -+ tsid.secid = secLabels[0]; -+ sepgsql_client_perms(tsid, tclass, perms, relName, true); -+ -+ /* no individual security-id except for RELKIND_RELATION */ -+ if (relkind != RELKIND_RELATION) -+ { -+ Oid securityId = seclabelMoveSecid(AttributeRelationId, -+ RelationRelationId, secLabels[0]); -+ -+ for (index = 1; index < nitems; index++) -+ secLabels[index] = securityId; -+ -+ return secLabels; -+ } -+ -+ /* -+ * security context of the columns -+ */ -+ for (index = 1; index < nitems; index++) -+ { -+ Form_pg_attribute attForm; -+ char auname[NAMEDATALEN * 2 + 10]; -+ -+ attno = index + FirstLowInvalidHeapAttributeNumber; -+ -+ /* skip unnecessary system columns */ -+ if ((attno == ObjectIdAttributeNumber && !tupDesc->tdhasoid) || -+ (attno == SecurityLabelAttributeNumber && !tupDesc->tdhassecid)) -+ continue; -+ -+ if (!OidIsValid(secLabels[index])) -+ { -+ csid = sepgsql_client_create_secid(tsid, -+ SEPG_CLASS_DB_COLUMN, -+ AttributeRelationId); -+ secLabels[index] = csid.secid; -+ } -+ -+ if (attno < 0) -+ attForm = SystemAttributeDefinition(attno, -+ tupDesc->tdhasoid, -+ tupDesc->tdhassecid); -+ else -+ attForm = tupDesc->attrs[attno]; -+ -+ /* db_column:{create (insert)} permission */ -+ csid.relid = AttributeRelationId; -+ csid.secid = secLabels[index]; -+ -+ perms = SEPG_DB_COLUMN__CREATE; -+ if (createAs && attno >= 0) -+ perms |= SEPG_DB_COLUMN__INSERT; -+ -+ snprintf(auname, sizeof(auname), "%s.%s", -+ relName, NameStr(attForm->attname)); -+ -+ sepgsql_client_perms(csid, -+ SEPG_CLASS_DB_COLUMN, -+ perms, -+ auname, -+ true); -+ } -+ return secLabels; -+ } -+#endif -+ return NULL; -+} -+ -+void -+sepgsql_relation_alter(Oid relationOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_relation_alter_schema(Oid relationOid, Oid newSchema) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_relation_alter_rename(Oid relationOid, const char *newName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_relation_alter_inherit(Oid childOid, Oid parentOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_relation_common(childOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_relation_relabel(Oid relationOid, char *new_label) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ char *auname; -+ char relkind; -+ uint16 tclass = 0; -+ -+ nsid.relid = RelationRelationId; -+ nsid.secid = seclabelTransInput(nsid.relid, new_label); -+ -+ auname = get_rel_name(relationOid); -+ relkind = get_rel_relkind(relationOid); -+ -+ switch (relkind) -+ { -+ case RELKIND_RELATION: -+ tclass = SEPG_CLASS_DB_TABLE; -+ break; -+ -+ case RELKIND_SEQUENCE: -+ tclass = SEPG_CLASS_DB_SEQUENCE; -+ break; -+ -+ case RELKIND_VIEW: -+ tclass = SEPG_CLASS_DB_VIEW; -+ break; -+ -+ case RELKIND_COMPOSITE_TYPE: -+ tclass = SEPG_CLASS_DB_TUPLE; -+ break; -+ -+ default: -+ elog(ERROR, "unexpected relkind %c", relkind); -+ break;; -+ } -+ /* db_xxx:{setattr relabelfrom} */ -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR | -+ SEPG_DB_TABLE__RELABELFROM, true); -+ -+ /* db_xxx:{relabelto} */ -+ sepgsql_client_perms(nsid, -+ tclass, -+ SEPG_DB_TABLE__RELABELTO, -+ auname, true); -+ pfree(auname); -+ -+ return nsid.secid; -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ return InvalidOid; -+} -+ -+void -+sepgsql_relation_drop(Oid relationOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__DROP, true); -+ } -+#endif -+} -+ -+void -+sepgsql_relation_getattr(Oid relationOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__GETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_relation_grant(Oid relationOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_relation_comment(Oid relationOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+bool -+sepgsql_relation_cluster(Oid relationOid, bool abort) -+{ -+#ifdef HAVE_SELINUX -+ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); -+ -+ if (sepgsql_is_enabled()) -+ { -+ bool retval = -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__INDEXON, true); -+ return retval; -+ } -+#endif -+ return true; -+} -+ -+void -+sepgsql_relation_truncate(Relation rel) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(RelationGetForm(rel)->relkind == RELKIND_RELATION); -+ -+ /* db_table:{delete} */ -+ sepgsql_relation_common(RelationGetRelid(rel), -+ SEPG_DB_TABLE__DELETE, true); -+ /* db_tuple:{delete} */ -+ } -+#endif -+} -+ -+void -+sepgsql_relation_lock(Relation rel) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(RelationGetForm(rel)->relkind == RELKIND_RELATION); -+ -+ /* db_table:{lock} */ -+ sepgsql_relation_common(RelationGetRelid(rel), -+ SEPG_DB_TABLE__LOCK, true); -+ } -+#endif -+} -+ -+void -+sepgsql_relation_reindex(Oid relationOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); -+ -+ /* db_table:{indexon} */ -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__INDEXON, true); -+ } -+#endif -+} -+ -+void -+sepgsql_view_replace(Oid viewOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(get_rel_relkind(viewOid) == RELKIND_VIEW); -+ /* db_view:{setattr} */ -+ sepgsql_relation_common(viewOid, -+ SEPG_DB_VIEW__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_index_create(Oid relationOid, Oid namespaceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceOid, -+ SEPG_DB_SCHEMA__ADD_NAME, true); -+ /* db_table:{setattr indexon} */ -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR | -+ SEPG_DB_TABLE__INDEXON, true); -+ } -+#endif -+} -+ -+void -+sepgsql_index_reindex(Oid indexOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ HeapTuple tuple; -+ Oid relationOid; -+ -+ tuple = SearchSysCache1(INDEXRELID, indexOid); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for index %u", indexOid); -+ relationOid = ((Form_pg_index) GETSTRUCT(tuple))->indrelid; -+ ReleaseSysCache(tuple); -+ -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__INDEXON, true); -+ } -+#endif -+} -+ -+void -+sepgsql_sequence_get_value(Oid sequenceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(get_rel_relkind(sequenceOid) == RELKIND_SEQUENCE); -+ sepgsql_relation_common(sequenceOid, -+ SEPG_DB_SEQUENCE__GET_VALUE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_sequence_next_value(Oid sequenceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(get_rel_relkind(sequenceOid) == RELKIND_SEQUENCE); -+ sepgsql_relation_common(sequenceOid, -+ SEPG_DB_SEQUENCE__NEXT_VALUE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_sequence_set_value(Oid sequenceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(get_rel_relkind(sequenceOid) == RELKIND_SEQUENCE); -+ sepgsql_relation_common(sequenceOid, -+ SEPG_DB_SEQUENCE__SET_VALUE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_rule_create(Oid relationOid, const char *ruleName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_rule_drop(Oid relationOid, const char *ruleName, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled() && !cascade) -+ { -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_rule_comment(Oid relationOid, const char *ruleName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_trigger_create(Oid relationOid, const char *triggerName, -+ Oid constrrelid, Oid funcOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); -+ -+ /* db_table:{setattr} */ -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ /* db_procedure:{install} */ -+ // sepgsql_procedure_common... -+ } -+#endif -+} -+ -+void -+sepgsql_trigger_alter(Oid relationOid, const char *triggerName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_trigger_drop(Oid relationOid, const char *triggerName, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled() && !cascade) -+ { -+ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_trigger_comment(Oid relationOid, const char *triggerName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -+ -+void -+sepgsql_constraint_comment(Oid relationOid, const char *constName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); -+ sepgsql_relation_common(relationOid, -+ SEPG_DB_TABLE__SETATTR, true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/role.c b/src/backend/sepgsql/role.c -new file mode 100644 -index 0000000..3c4891c ---- /dev/null -+++ b/src/backend/sepgsql/role.c -@@ -0,0 +1,142 @@ -+/* -+ * role.c -+ * -+ * SELinux hooks related to roles -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_authid.h" -+#include "catalog/pg_seclabel.h" -+#include "miscadmin.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/lsyscache.h" -+#include "utils/syscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_role_common(Oid roleOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ HeapTuple tuple; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for role %u", roleOid); -+ -+ tsid.relid = AuthIdRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+#endif -+ -+Oid -+sepgsql_role_create(const char *roleName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ -+ nsid = sepgsql_get_default_tuple_secid(AuthIdRelationId); -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ roleName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_role_alter(Oid roleOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_role_common(roleOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_role_relabel(Oid roleOid, char *newLabel) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t tsid; -+ -+ tsid.relid = AuthIdRelationId; -+ tsid.secid = seclabelTransInput(tsid.relid, newLabel); -+ -+ /* db_tuple:{update relabelfrom} */ -+ sepgsql_role_common(roleOid, -+ SEPG_DB_TUPLE__UPDATE | -+ SEPG_DB_TUPLE__RELABELFROM, -+ true); -+ -+ /* db_tuple:{relabelto} */ -+ sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__RELABELTO, -+ GetUserNameFromId(roleOid), -+ true); -+ return tsid.secid; -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ return InvalidOid; -+} -+ -+void -+sepgsql_role_drop(Oid roleOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_role_common(roleOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_role_grant(Oid roleOid, bool is_grant, List *memberIds) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_role_common(roleOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_role_comment(Oid roleOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_role_common(roleOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/rowlv.c b/src/backend/sepgsql/rowlv.c -new file mode 100644 -index 0000000..892daf9 ---- /dev/null -+++ b/src/backend/sepgsql/rowlv.c -@@ -0,0 +1,346 @@ -+/* -+ * rowlv.c -+ * -+ * Row-level access control facilities -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "access/heapam.h" -+#include "access/sysattr.h" -+#include "catalog/pg_attribute.h" -+#include "catalog/pg_class.h" -+#include "catalog/pg_database.h" -+#include "catalog/pg_language.h" -+#include "catalog/pg_largeobject_metadata.h" -+#include "catalog/pg_namespace.h" -+#include "catalog/pg_proc.h" -+#include "catalog/pg_seclabel.h" -+#include "catalog/pg_type.h" -+#include "nodes/makefuncs.h" -+#include "parser/parsetree.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "storage/bufmgr.h" -+#include "utils/fmgroids.h" -+#include "utils/lsyscache.h" -+#include "utils/syscache.h" -+#include "utils/tqual.h" -+ -+static int sepgsql_rowlv_mode = SEPGSQL_ROWLV_FILTER; -+ -+int -+sepgsql_rowlv_get_mode(void) -+{ -+ return sepgsql_rowlv_mode; -+} -+ -+int -+sepgsql_rowlv_set_mode(int new_mode) -+{ -+ int old_mode = sepgsql_rowlv_mode; -+ -+ Assert(new_mode == SEPGSQL_ROWLV_FILTER || -+ new_mode == SEPGSQL_ROWLV_ABORT || -+ new_mode == SEPGSQL_ROWLV_BYPASS); -+ -+ sepgsql_rowlv_mode = new_mode; -+ -+ return old_mode; -+} -+ -+uint32 -+sepgsql_rowlv_permissions(RangeTblEntry *rte) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid relOid = rte->relid; -+ HeapTuple reltup; -+ bool relhassecids; -+ uint32 required = 0; -+ -+ if (!OidIsValid(relOid)) -+ return 0; -+ -+ if (get_rel_relkind(relOid) != RELKIND_RELATION) -+ return 0; -+ -+ reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid)); -+ if (!HeapTupleIsValid(reltup)) -+ elog(ERROR, "cache lookup failed for relation %u", relOid); -+ relhassecids = ((Form_pg_class) GETSTRUCT(reltup))->relhassecids; -+ ReleaseSysCache(reltup); -+ -+ if (!relhassecids) -+ return 0; -+ -+ if (rte->requiredPerms & ACL_SELECT) -+ required |= SEPG_DB_TUPLE__SELECT; -+ -+ if (rte->requiredPerms & ACL_UPDATE && -+ !bms_is_empty(rte->modifiedCols)) -+ required |= SEPG_DB_TUPLE__UPDATE; -+ -+ if (rte->requiredPerms & ACL_DELETE) -+ required |= SEPG_DB_TUPLE__DELETE; -+ -+ return required; -+ } -+#endif -+ return 0; -+} -+ -+#ifdef HAVE_SELINUX -+static bool -+sepgsql_tuple_perms(Relation rel, HeapTuple tuple, uint32 required, bool abort) -+{ -+ Form_pg_class relForm; -+ Form_pg_attribute attForm; -+ Form_pg_type typForm; -+ sepgsql_sid_t tsid; -+ uint16 tclass; -+ -+ /* object class? */ -+ switch (RelationGetRelid(rel)) -+ { -+ case DatabaseRelationId: -+ tclass = SEPG_CLASS_DB_DATABASE; -+ break; -+ -+ case NamespaceRelationId: -+ tclass = SEPG_CLASS_DB_SCHEMA; -+ break; -+ -+ case RelationRelationId: -+ relForm = (Form_pg_class) GETSTRUCT(tuple); -+ switch (relForm->relkind) -+ { -+ case RELKIND_RELATION: -+ tclass = SEPG_CLASS_DB_TABLE; -+ break; -+ case RELKIND_SEQUENCE: -+ tclass = SEPG_CLASS_DB_SEQUENCE; -+ break; -+ case RELKIND_VIEW: -+ tclass = SEPG_CLASS_DB_VIEW; -+ break; -+ case RELKIND_COMPOSITE_TYPE: -+ tclass = SEPG_CLASS_DB_TUPLE; -+ break; -+ default: /* index, toast */ -+ tclass = SEPG_CLASS_DB_TABLE; -+ break; -+ } -+ break; -+ -+ case AttributeRelationId: -+ attForm = (Form_pg_attribute) GETSTRUCT(tuple); -+ switch (get_rel_relkind(attForm->attrelid)) -+ { -+ case RELKIND_RELATION: -+ tclass = SEPG_CLASS_DB_COLUMN; -+ break; -+ case RELKIND_SEQUENCE: -+ tclass = SEPG_CLASS_DB_SEQUENCE; -+ break; -+ case RELKIND_VIEW: -+ tclass = SEPG_CLASS_DB_VIEW; -+ break; -+ case RELKIND_COMPOSITE_TYPE: -+ tclass = SEPG_CLASS_DB_TUPLE; -+ break; -+ case RELKIND_INDEX: -+ case RELKIND_TOASTVALUE: -+ tclass = SEPG_CLASS_DB_TABLE; -+ break; -+ default: -+ /* orphan attribute? */ -+ return !sepgsql_get_enforce(); -+ } -+ break; -+ -+ case ProcedureRelationId: -+ tclass = SEPG_CLASS_DB_PROCEDURE; -+ break; -+ -+ case LanguageRelationId: -+ tclass = SEPG_CLASS_DB_LANGUAGE; -+ break; -+ -+ case LargeObjectMetadataRelationId: -+ tclass = SEPG_CLASS_DB_BLOB; -+ break; -+ -+ case TypeRelationId: -+ typForm = (Form_pg_type) GETSTRUCT(tuple); -+ if (!OidIsValid(typForm->typrelid)) -+ tclass = SEPG_CLASS_DB_TUPLE; -+ else -+ { -+ switch (get_rel_relkind(typForm->typrelid)) -+ { -+ case RELKIND_RELATION: -+ case RELKIND_INDEX: -+ case RELKIND_TOASTVALUE: -+ tclass = SEPG_CLASS_DB_TABLE; -+ break; -+ case RELKIND_SEQUENCE: -+ tclass = SEPG_CLASS_DB_SEQUENCE; -+ break; -+ case RELKIND_VIEW: -+ tclass = SEPG_CLASS_DB_VIEW; -+ break; -+ case RELKIND_COMPOSITE_TYPE: -+ tclass = SEPG_CLASS_DB_TUPLE; -+ break; -+ default: -+ /* orphan type? */ -+ return !sepgsql_get_enforce(); -+ } -+ } -+ break; -+ -+ default: -+ tclass = SEPG_CLASS_DB_TUPLE; -+ break; -+ } -+ -+ /* do permission check */ -+ tsid.relid = RelationGetRelid(rel); -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ return sepgsql_client_perms(tsid, tclass, required, NULL, abort); -+} -+#endif -+ -+bool -+sepgsql_rowlv_quals(Relation rel, uint32 required, -+ TupleTableSlot *slot, bool abort) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ HeapTuple tuple; -+ -+ /* no permission to be checked */ -+ if (!required) -+ return true; -+ -+ /* mismatch invocation for the current rowlv mode */ -+ if ((!abort && sepgsql_rowlv_mode != SEPGSQL_ROWLV_FILTER) || -+ (abort && sepgsql_rowlv_mode != SEPGSQL_ROWLV_ABORT)) -+ return true; -+ -+ Assert(OidIsValid(RelationGetRelid(rel))); -+ -+ tuple = ExecMaterializeSlot(slot); -+ -+ return sepgsql_tuple_perms(rel, tuple, required, abort); -+ } -+#endif -+ return true; -+} -+ -+bool -+sepgsql_rowlv_copyto(Relation rel, HeapTuple tuple) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ return sepgsql_tuple_perms(rel, tuple, SEPG_DB_TUPLE__SELECT, false); -+ } -+#endif -+ return true; -+} -+ -+void -+sepgsql_tuple_insert(Relation rel, HeapTuple tuple) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ Oid relOid = RelationGetRelid(rel); -+ -+ if (!RelationGetForm(rel)->relhassecids) -+ { -+ nsid.relid = RelationRelationId; -+ nsid.secid = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(relOid)); -+ } -+ else if (OidIsValid(HeapTupleGetSecid(tuple))) -+ { -+ nsid.relid = relOid; -+ nsid.secid = HeapTupleGetSecid(tuple); -+ } -+ else -+ { -+ nsid = sepgsql_get_default_tuple_secid(relOid); -+ HeapTupleSetSecid(tuple, nsid.secid); -+ } -+ /* db_tuple:{insert} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ NULL, -+ true); -+ } -+#endif -+} -+ -+void -+sepgsql_tuple_update(Relation rel, ItemPointer otid, HeapTuple newtup) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t tsid; -+ HeapTupleData oldtup; -+ Buffer oldbuf; -+ Oid newSecId = HeapTupleGetSecid(newtup); -+ Oid oldSecId; -+ -+ /* -+ * heap_update() preserves security id of the original tuple, -+ * if no explicit security label was given, so we don't need -+ * to check anything. -+ * At this point, db_tuple:{update} is already checked. -+ */ -+ if (!OidIsValid(newSecId)) -+ return; -+ -+ /* -+ * User gave an explicit security label -+ */ -+ ItemPointerCopy(otid, &oldtup.t_self); -+ if (!heap_fetch(rel, SnapshotAny, &oldtup, &oldbuf, false, NULL)) -+ elog(ERROR, "failed to fetch old version of the tuple"); -+ -+ tsid.relid = RelationGetRelid(rel); -+ oldSecId = HeapTupleGetSecid(&oldtup); -+ -+ if (!seclabelCompareSecid(tsid.relid, oldSecId, -+ tsid.relid, newSecId)) -+ { -+ /* db_tuple:{relabelfrom} */ -+ tsid.secid = oldSecId; -+ sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__RELABELFROM, -+ NULL, -+ true); -+ -+ /* db_tuple:{relabelto} */ -+ tsid.secid = newSecId; -+ sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__RELABELTO, -+ NULL, -+ true); -+ } -+ ReleaseBuffer(oldbuf); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/schema.c b/src/backend/sepgsql/schema.c -new file mode 100644 -index 0000000..24878f9 ---- /dev/null -+++ b/src/backend/sepgsql/schema.c -@@ -0,0 +1,173 @@ -+/* -+ * schema.c -+ * -+ * SELinux hooks related to schema -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_namespace.h" -+#include "catalog/pg_seclabel.h" -+#include "miscadmin.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/lsyscache.h" -+#include "utils/syscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_schema_common(Oid namespaceOid, uint32 required, bool abort) -+{ -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(NAMESPACEOID, -+ ObjectIdGetDatum(namespaceOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for namespace %u", namespaceOid); -+ -+ tsid.relid = NamespaceRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname); -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_SCHEMA, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+#endif -+ -+Oid -+sepgsql_schema_create(const char *nspName, bool is_temp) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ -+ /* compute default security context */ -+ nsid = sepgsql_get_default_schema_secid(MyDatabaseId); -+ -+ /* db_schema:{create} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_SCHEMA, -+ SEPG_DB_SCHEMA__CREATE, -+ nspName, true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_schema_alter(Oid namespaceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_schema_common(namespaceOid, -+ SEPG_DB_SCHEMA__SETATTR, -+ true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_schema_relabel(Oid namespaceOid, char *new_label) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ char *auname; -+ -+ nsid.relid = NamespaceRelationId; -+ nsid.secid = seclabelTransInput(nsid.relid, new_label); -+ -+ auname = get_namespace_name(namespaceOid); -+ -+ /* db_schema:{setattr relabelfrom} */ -+ sepgsql_schema_common(namespaceOid, -+ SEPG_DB_SCHEMA__SETATTR | -+ SEPG_DB_SCHEMA__RELABELFROM, -+ true); -+ -+ /* db_schema:{relabelto} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_SCHEMA, -+ SEPG_DB_SCHEMA__RELABELTO, -+ auname, -+ true); -+ pfree(auname); -+ -+ return nsid.secid; -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ return InvalidOid; -+} -+ -+void -+sepgsql_schema_drop(Oid namespaceOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_schema_common(namespaceOid, -+ SEPG_DB_SCHEMA__DROP, -+ true); -+ } -+#endif -+} -+ -+void -+sepgsql_schema_grant(Oid namespaceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_schema_common(namespaceOid, -+ SEPG_DB_SCHEMA__SETATTR, -+ true); -+ } -+#endif -+} -+ -+bool -+sepgsql_schema_search(Oid namespaceOid, bool abort) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ bool retval = -+ sepgsql_schema_common(namespaceOid, -+ SEPG_DB_SCHEMA__SEARCH, -+ abort); -+ return retval; -+ } -+#endif -+ return true; -+} -+ -+void -+sepgsql_schema_comment(Oid namespaceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_schema_common(namespaceOid, -+ SEPG_DB_SCHEMA__SETATTR, -+ true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/selinux.c b/src/backend/sepgsql/selinux.c -new file mode 100644 -index 0000000..5e40cf9 ---- /dev/null -+++ b/src/backend/sepgsql/selinux.c -@@ -0,0 +1,690 @@ -+/* -+ * src/backend/security/sepgsql/selinux.c -+ * Routines to communicate with SELinux. -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_seclabel.h" -+#include "libpq/libpq.h" -+#include "miscadmin.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/guc.h" -+#include "utils/memutils.h" -+ -+#include -+ -+/* -+ * selinux_catalog -+ * -+ * This static translation lookup table enables to associate a certain -+ * object class/permission name with its internal code, such as -+ * SEPG_CLASS_DB_SCHEMA. -+ * -+ * SELinux requires applications to represent object class and a set of -+ * permissions in code, instead of its name, when we ask SELinux's decision. -+ * -+ * See the definition of security_compute_av(3) API in libselinux. -+ * We need to gives a code of object class, and interpret what permissions -+ * are allowed on the object class from av_decision structure. -+ * Actual values of the code depend on the security policy. In other words, -+ * we cannot know what number is assigned on a certain object class and -+ * permissions. -+ * The string_to_security_class(3) and string_to_av_perm(3) APIs takes -+ * arguments with the name of object class/permission, and returns the -+ * code for the given object class/permissions. -+ * For example, we can know what code is assigned on the "db_table" class -+ * using these functions as follows: -+ * -+ * uint16 tclass_ex = string_to_security_class("db_table"); -+ * -+ * On the other hand, we use an alternative code internally to simplify -+ * the implementation, such as SEPG_CLASS_* for object class. -+ * The following selinux_catalog is used to translate the 'internal' -+ * code and the 'external' code. -+ * -+ * It allows to lookup name of the object class or permission corresponding -+ * to a certain 'internal' code. Then, we can give the name to SELinux's -+ * API to obtain 'external' code which can be used to ask in-kernel SELinux. -+ */ -+static struct -+{ -+ const char *class_name; -+ uint16 class_code; -+ struct -+ { -+ const char *perm_name; -+ uint32 perm_code; -+ } perms[32]; -+} selinux_catalog[] = { -+ { -+ "process", SEPG_CLASS_PROCESS, -+ { -+ { "translation", SEPG_PROCESS__TRANSITION }, -+ { NULL, 0UL } -+ } -+ }, -+ { -+ "file", SEPG_CLASS_FILE, -+ { -+ { "read", SEPG_FILE__READ }, -+ { "write", SEPG_FILE__WRITE }, -+ { "create", SEPG_FILE__CREATE }, -+ { "getattr", SEPG_FILE__GETATTR }, -+ { "unlink", SEPG_FILE__UNLINK }, -+ { "rename", SEPG_FILE__RENAME }, -+ { "append", SEPG_FILE__APPEND }, -+ { NULL, 0UL } -+ } -+ }, -+ { -+ "dir", SEPG_CLASS_DIR, -+ { -+ { "read", SEPG_DIR__READ }, -+ { "write", SEPG_DIR__WRITE }, -+ { "create", SEPG_DIR__CREATE }, -+ { "getattr", SEPG_DIR__GETATTR }, -+ { "unlink", SEPG_DIR__UNLINK }, -+ { "rename", SEPG_DIR__RENAME }, -+ { "search", SEPG_DIR__SEARCH }, -+ { "add_name", SEPG_DIR__ADD_NAME }, -+ { "remove_name", SEPG_DIR__REMOVE_NAME }, -+ { "rmdir", SEPG_DIR__RMDIR }, -+ { "reparent", SEPG_DIR__REPARENT }, -+ { NULL, 0UL } -+ } -+ }, -+ { -+ "lnk_file", SEPG_CLASS_LNK_FILE, -+ { -+ { "read", SEPG_LNK_FILE__READ }, -+ { "write", SEPG_LNK_FILE__WRITE }, -+ { "create", SEPG_LNK_FILE__CREATE }, -+ { "getattr", SEPG_LNK_FILE__GETATTR }, -+ { "unlink", SEPG_LNK_FILE__UNLINK }, -+ { "rename", SEPG_LNK_FILE__RENAME }, -+ { NULL, 0UL } -+ } -+ }, -+ { -+ "chr_file", SEPG_CLASS_CHR_FILE, -+ { -+ { "read", SEPG_CHR_FILE__READ }, -+ { "write", SEPG_CHR_FILE__WRITE }, -+ { "create", SEPG_CHR_FILE__CREATE }, -+ { "getattr", SEPG_CHR_FILE__GETATTR }, -+ { "unlink", SEPG_CHR_FILE__UNLINK }, -+ { "rename", SEPG_CHR_FILE__RENAME }, -+ { NULL, 0UL } -+ } -+ }, -+ { -+ "blk_file", SEPG_CLASS_BLK_FILE, -+ { -+ { "read", SEPG_BLK_FILE__READ }, -+ { "write", SEPG_BLK_FILE__WRITE }, -+ { "create", SEPG_BLK_FILE__CREATE }, -+ { "getattr", SEPG_BLK_FILE__GETATTR }, -+ { "unlink", SEPG_BLK_FILE__UNLINK }, -+ { "rename", SEPG_BLK_FILE__RENAME }, -+ { NULL, 0UL } -+ } -+ }, -+ { -+ "sock_file", SEPG_CLASS_SOCK_FILE, -+ { -+ { "read", SEPG_SOCK_FILE__READ }, -+ { "write", SEPG_SOCK_FILE__WRITE }, -+ { "create", SEPG_SOCK_FILE__CREATE }, -+ { "getattr", SEPG_SOCK_FILE__GETATTR }, -+ { "unlink", SEPG_SOCK_FILE__UNLINK }, -+ { "rename", SEPG_SOCK_FILE__RENAME }, -+ { NULL, 0UL } -+ } -+ }, -+ { -+ "fifo_file", SEPG_CLASS_FIFO_FILE, -+ { -+ { "read", SEPG_FIFO_FILE__READ }, -+ { "write", SEPG_FIFO_FILE__WRITE }, -+ { "create", SEPG_FIFO_FILE__CREATE }, -+ { "getattr", SEPG_FIFO_FILE__GETATTR }, -+ { "unlink", SEPG_FIFO_FILE__UNLINK }, -+ { "rename", SEPG_FIFO_FILE__RENAME }, -+ { NULL, 0UL } -+ } -+ }, -+ { -+ "db_database", SEPG_CLASS_DB_DATABASE, -+ { -+ { "create", SEPG_DB_DATABASE__CREATE }, -+ { "drop", SEPG_DB_DATABASE__DROP }, -+ { "getattr", SEPG_DB_DATABASE__GETATTR }, -+ { "setattr", SEPG_DB_DATABASE__SETATTR }, -+ { "relabelfrom", SEPG_DB_DATABASE__RELABELFROM }, -+ { "relabelto", SEPG_DB_DATABASE__RELABELTO }, -+ { "access", SEPG_DB_DATABASE__ACCESS }, -+ { "load_module", SEPG_DB_DATABASE__LOAD_MODULE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_schema", SEPG_CLASS_DB_SCHEMA, -+ { -+ { "create", SEPG_DB_SCHEMA__CREATE }, -+ { "drop", SEPG_DB_SCHEMA__DROP }, -+ { "getattr", SEPG_DB_SCHEMA__GETATTR }, -+ { "setattr", SEPG_DB_SCHEMA__SETATTR }, -+ { "relabelfrom", SEPG_DB_SCHEMA__RELABELFROM }, -+ { "relabelto", SEPG_DB_SCHEMA__RELABELTO }, -+ { "search", SEPG_DB_SCHEMA__SEARCH }, -+ { "add_name", SEPG_DB_SCHEMA__ADD_NAME }, -+ { "remove_name", SEPG_DB_SCHEMA__REMOVE_NAME }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_table", SEPG_CLASS_DB_TABLE, -+ { -+ { "create", SEPG_DB_TABLE__CREATE }, -+ { "drop", SEPG_DB_TABLE__DROP }, -+ { "getattr", SEPG_DB_TABLE__GETATTR }, -+ { "setattr", SEPG_DB_TABLE__SETATTR }, -+ { "relabelfrom", SEPG_DB_TABLE__RELABELFROM }, -+ { "relabelto", SEPG_DB_TABLE__RELABELTO }, -+ { "select", SEPG_DB_TABLE__SELECT }, -+ { "update", SEPG_DB_TABLE__UPDATE }, -+ { "insert", SEPG_DB_TABLE__INSERT }, -+ { "delete", SEPG_DB_TABLE__DELETE }, -+ { "lock", SEPG_DB_TABLE__LOCK }, -+ { "indexon", SEPG_DB_TABLE__INDEXON }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_view", SEPG_CLASS_DB_VIEW, -+ { -+ { "create", SEPG_DB_VIEW__CREATE }, -+ { "drop", SEPG_DB_VIEW__DROP }, -+ { "getattr", SEPG_DB_VIEW__GETATTR }, -+ { "setattr", SEPG_DB_VIEW__SETATTR }, -+ { "relabelfrom", SEPG_DB_VIEW__RELABELFROM }, -+ { "relabelto", SEPG_DB_VIEW__RELABELTO }, -+ { "expand", SEPG_DB_VIEW__EXPAND }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_sequence", SEPG_CLASS_DB_SEQUENCE, -+ { -+ { "create", SEPG_DB_SEQUENCE__CREATE }, -+ { "drop", SEPG_DB_SEQUENCE__DROP }, -+ { "getattr", SEPG_DB_SEQUENCE__GETATTR }, -+ { "setattr", SEPG_DB_SEQUENCE__SETATTR }, -+ { "relabelfrom", SEPG_DB_SEQUENCE__RELABELFROM }, -+ { "relabelto", SEPG_DB_SEQUENCE__RELABELTO }, -+ { "get_value", SEPG_DB_SEQUENCE__GET_VALUE }, -+ { "next_value", SEPG_DB_SEQUENCE__NEXT_VALUE }, -+ { "set_value", SEPG_DB_SEQUENCE__SET_VALUE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_procedure", SEPG_CLASS_DB_PROCEDURE, -+ { -+ { "create", SEPG_DB_PROCEDURE__CREATE }, -+ { "drop", SEPG_DB_PROCEDURE__DROP }, -+ { "getattr", SEPG_DB_PROCEDURE__GETATTR }, -+ { "setattr", SEPG_DB_PROCEDURE__SETATTR }, -+ { "relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM }, -+ { "relabelto", SEPG_DB_PROCEDURE__RELABELTO }, -+ { "execute", SEPG_DB_PROCEDURE__EXECUTE }, -+ { "entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT }, -+ { "install", SEPG_DB_PROCEDURE__INSTALL }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_column", SEPG_CLASS_DB_COLUMN, -+ { -+ { "create", SEPG_DB_COLUMN__CREATE }, -+ { "drop", SEPG_DB_COLUMN__DROP }, -+ { "getattr", SEPG_DB_COLUMN__GETATTR }, -+ { "setattr", SEPG_DB_COLUMN__SETATTR }, -+ { "relabelfrom", SEPG_DB_COLUMN__RELABELFROM }, -+ { "relabelto", SEPG_DB_COLUMN__RELABELTO }, -+ { "select", SEPG_DB_COLUMN__SELECT }, -+ { "update", SEPG_DB_COLUMN__UPDATE }, -+ { "insert", SEPG_DB_COLUMN__INSERT }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_tuple", SEPG_CLASS_DB_TUPLE, -+ { -+ { "relabelfrom", SEPG_DB_TUPLE__RELABELFROM }, -+ { "relabelto", SEPG_DB_TUPLE__RELABELTO }, -+ { "select", SEPG_DB_TUPLE__SELECT }, -+ { "update", SEPG_DB_TUPLE__UPDATE }, -+ { "insert", SEPG_DB_TUPLE__INSERT }, -+ { "delete", SEPG_DB_TUPLE__DELETE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_blob", SEPG_CLASS_DB_BLOB, -+ { -+ { "create", SEPG_DB_BLOB__CREATE }, -+ { "drop", SEPG_DB_BLOB__DROP }, -+ { "getattr", SEPG_DB_BLOB__GETATTR }, -+ { "setattr", SEPG_DB_BLOB__SETATTR }, -+ { "relabelfrom", SEPG_DB_BLOB__RELABELFROM }, -+ { "relabelto", SEPG_DB_BLOB__RELABELTO }, -+ { "read", SEPG_DB_BLOB__READ }, -+ { "write", SEPG_DB_BLOB__WRITE }, -+ { "import", SEPG_DB_BLOB__IMPORT }, -+ { "export", SEPG_DB_BLOB__EXPORT }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_language", SEPG_CLASS_DB_LANGUAGE, -+ { -+ { "create", SEPG_DB_LANGUAGE__CREATE }, -+ { "drop", SEPG_DB_LANGUAGE__DROP }, -+ { "getattr", SEPG_DB_LANGUAGE__GETATTR }, -+ { "setattr", SEPG_DB_LANGUAGE__SETATTR }, -+ { "relabelfrom", SEPG_DB_LANGUAGE__RELABELFROM }, -+ { "relabelto", SEPG_DB_LANGUAGE__RELABELTO }, -+ { "implement", SEPG_DB_LANGUAGE__IMPLEMENTE }, -+ { "execute", SEPG_DB_LANGUAGE__EXECUTE }, -+ { NULL, 0UL }, -+ } -+ }, -+}; -+ -+/* -+ * GUC option: sepostgresql = [default|enforcing|permissive|disabled] -+ * -+ * SEPGSQL_MODE_DEFAULT : It follows system setting -+ * SEPGSQL_MODE_ENFORCING : Use enforcing mode always -+ * SEPGSQL_MODE_PERMISSIVE : Use permissive mode always -+ * SEPGSQL_MODE_INTERNAL : Internally used mode. Same as permissive mode -+ * except for silence in audit logs -+ * SEPGSQL_MODE_DISABLED : It always disables SE-PgSQL configuration -+ */ -+int sepostgresql_mode; -+ -+/* -+ * sepgsql_is_enabled -+ * -+ * If it returns true, SE-PgSQL is enabled. Otherwise, it is disabled. -+ */ -+bool -+sepgsql_is_enabled(void) -+{ -+ static int enabled = -1; -+ -+ /* -+ * If sepostgresql = disabled, it always returns FALSE -+ * independently from the system status. -+ */ -+ if (sepostgresql_mode == SEPGSQL_MODE_DISABLED) -+ return false; -+ -+ /* -+ * SE-PgSQL needs SELinux is enabled on the operating system. -+ * If it is disabled, SE-PgSQL has to be also disabled, even if -+ * 'enforcing' or 'permissive' are specified. -+ */ -+ if (enabled < 0) -+ enabled = is_selinux_enabled(); -+ -+ return enabled > 0 ? true : false; -+} -+ -+/* -+ * sepgsql_get_enforce -+ * -+ * It returns true, if SE-PgSQL performs in enforcing mode. -+ * -+ * In enforcing mode, SE-PgSQL performs as expected. It checks permissions -+ * on the required action, and it prevents them if violated. -+ * In permissive mode, SE-PgSQL also checks permissions, but it does not -+ * prevent anything, even if violated. It generates audit logs for access -+ * violations, so we can use this mode to debug security policy itself. -+ */ -+bool -+sepgsql_get_enforce(void) -+{ -+ if (sepostgresql_mode == SEPGSQL_MODE_DEFAULT) -+ { -+ if (security_getenforce() == 1) -+ return true; -+ } -+ else if (sepostgresql_mode == SEPGSQL_MODE_ENFORCING) -+ return true; -+ -+ return false; -+} -+ -+/* -+ * sepgsql_show_mode -+ * -+ * It returns the current performing mode ('selinux_support') -+ * in human readable form. -+ */ -+const char * -+sepgsql_show_mode(void) -+{ -+ if (!sepgsql_is_enabled()) -+ return "disabled"; -+ -+ if (!sepgsql_get_enforce()) -+ return "permissive"; -+ -+ return "enforcing"; -+} -+ -+/* -+ * GUC parameter to turn on/off debuging audit generation -+ */ -+bool sepgsql_debug_audit; -+ -+/* -+ * sepgsql_audit_log -+ * -+ * It generates a security audit record. In the default, it writes out -+ * audit records into standard PG's logfile. It also allows to set up -+ * external audit log receiver, such as auditd in Linux, using the -+ * sepgsql_audit_hook. -+ * -+ * SELinux can control what should be audited and should not using -+ * "auditdeny" and "auditallow" rules in the security policy. In the -+ * default, all the access violations are audited, and all the access -+ * allowed are not audited. But we can set up the security policy, so -+ * we can have exceptions. So, it is necessary to follow the suggestion -+ * come from the security policy. (av_decision.auditallow and auditdeny) -+ * -+ * Security audit is an important feature, because it enables us to check -+ * what was happen if we have a security incident. In fact, ISO/IEC15408 -+ * defines several security functionalities for audit features. -+ */ -+void -+sepgsql_audit_log(bool denied, char *scontext, char *tcontext, -+ uint16 tclass, uint32 audited, const char *audit_name) -+{ -+ StringInfoData buf; -+ const char *tclass_name; -+ const char *perm_name; -+ int level = LOG; -+ int i; -+ -+ /* -+ * translation of security contexts to human readable format, -+ * if sepgsql_mcstrans is turned on. -+ */ -+ scontext = sepgsql_mcstrans_out(scontext); -+ tcontext = sepgsql_mcstrans_out(tcontext); -+ -+ /* lookup name of the object class */ -+ tclass_name = selinux_catalog[tclass].class_name; -+ -+ /* lookup name of the permissions */ -+ initStringInfo(&buf); -+ appendStringInfo(&buf, "{"); -+ -+ for (i=0; selinux_catalog[tclass].perms[i].perm_name; i++) -+ { -+ if (audited & (1UL << i)) -+ { -+ perm_name = selinux_catalog[tclass].perms[i].perm_name; -+ appendStringInfo(&buf, " %s", perm_name); -+ } -+ } -+ appendStringInfo(&buf, " }"); -+ -+ /* -+ * Call external audit module, if loaded -+ */ -+ appendStringInfo(&buf, " scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, tclass_name); -+ if (audit_name) -+ appendStringInfo(&buf, " name=%s", audit_name); -+ -+ if (sepgsql_debug_audit) -+ level = client_min_messages; -+ -+ ereport(level, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("SELinux: %s %s", -+ (denied ? "denied" : "allowed"), buf.data))); -+} -+ -+/* -+ * sepgsql_compute_avd -+ * -+ * It actually asks SELinux what permissions are allowed on a pair of -+ * the security contexts and object class. It also returns what permissions -+ * should be audited on access violation or allowed. -+ * In most cases, subject's security context (scontext) is a client, and -+ * target security context (tcontext) is a database object. -+ * -+ * The access control decision shall be set on the given av_decision. -+ * The av_decision.allowed has a bitmask of SEPG___ -+ * to suggest a set of allowed actions in this object class. -+ */ -+void -+sepgsql_compute_avd(char *scontext, char *tcontext, -+ uint16 tclass, struct av_decision *avd) -+{ -+ const char *tclass_name; -+ security_class_t tclass_ex; -+ struct av_decision avd_ex; -+ int i, deny_unknown = security_deny_unknown(); -+ -+ /* Get external code of the object class*/ -+ Assert(tclass < SEPG_CLASS_MAX); -+ -+ tclass_name = selinux_catalog[tclass].class_name; -+ tclass_ex = string_to_security_class(tclass_name); -+ -+ if (tclass_ex == 0) -+ { -+ /* -+ * If the current security policy does not support permissions -+ * corresponding to database objects, we fill up them with dummy -+ * data. -+ * If security_deny_unknown() returns positive value, undefined -+ * permissions should be denied. Otherwise, allowed -+ */ -+ avd->allowed = (deny_unknown > 0 ? 0 : ~0U); -+ avd->auditallow = 0U; -+ avd->auditdeny = ~0U; -+ avd->flags = 0; -+ -+ return; -+ } -+ -+ /* -+ * Ask SELinux what is allowed set of permissions on a pair of the -+ * security contexts and the given object class. -+ */ -+ if (security_compute_av_flags_raw(scontext, tcontext, -+ tclass_ex, 0, &avd_ex) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("SELinux could not compute av_decision: " -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, tclass_name))); -+ -+ /* -+ * SELinux returns its access control decision as a set of permissions -+ * represented in external code which depends on run-time environment. -+ * So, we need to translate it to the internal representation before -+ * returning results for the caller. -+ */ -+ memset(avd, 0, sizeof(struct av_decision)); -+ -+ for (i=0; selinux_catalog[tclass].perms[i].perm_name; i++) -+ { -+ access_vector_t perm_code_ex; -+ const char *perm_name = selinux_catalog[tclass].perms[i].perm_name; -+ uint32 perm_code = selinux_catalog[tclass].perms[i].perm_code; -+ -+ perm_code_ex = string_to_av_perm(tclass_ex, perm_name); -+ if (perm_code_ex == 0) -+ { -+ /* fill up undefined permissions */ -+ if (!deny_unknown) -+ avd->allowed |= perm_code; -+ avd->auditdeny |= perm_code; -+ -+ continue; -+ } -+ -+ if (avd_ex.allowed & perm_code_ex) -+ avd->allowed |= perm_code; -+ if (avd_ex.auditallow & perm_code_ex) -+ avd->auditallow |= perm_code; -+ if (avd_ex.auditdeny & perm_code_ex) -+ avd->auditdeny |= perm_code; -+ } -+ -+ return; -+} -+ -+/* -+ * sepgsql_compute_perms -+ * -+ * It makes access control decision communicating with SELinux. -+ * If SELinux does not allow required permissions on a pair of the security -+ * contexts, it raises an error or returns false. -+ * -+ * scontext : The security context of subject. In most cases, it is client. -+ * tcontext : The security context of target database object. -+ * tclass : One of the object class code (SEPG_CLASS_*) declared in the -+ * header file. -+ * required : A bitmap of the required permissions (SEPG___) -+ * declared in the header file. -+ * audit_name : A human readable name of the database object for auditing. -+ * abort : True, if caller want to raise an error on access violation. -+ */ -+bool -+sepgsql_compute_perms(char *scontext, char *tcontext, -+ uint16 tclass, uint32 required, -+ const char *audit_name, bool abort) -+{ -+ struct av_decision avd; -+ uint32 denied; -+ uint32 audited; -+ -+ sepgsql_compute_avd(scontext, tcontext, tclass, &avd); -+ -+ /* -+ * It logs a security audit record for the given request, if necessary. -+ * When SE-PgSQL performs 'internal' mode, it needs to keep silent. -+ */ -+ denied = required & ~avd.allowed; -+ if (sepgsql_debug_audit && tclass != SEPG_CLASS_DB_TUPLE) -+ audited = (denied ? (denied & ~0) : (required & ~0)); -+ else -+ audited = (denied ? (denied & avd.auditdeny) -+ : (required & avd.auditallow)); -+ -+ if (audited && sepostgresql_mode != SEPGSQL_MODE_INTERNAL) -+ { -+ sepgsql_audit_log(!!denied, scontext, tcontext, -+ tclass, audited, audit_name); -+ } -+ -+ /* -+ * If here is no policy violations, or SE-PgSQL performs in permissive -+ * mode, or the client process peforms in permissive domain, it returns -+ * normally with 'true'. -+ */ -+ if (!denied || -+ !sepgsql_get_enforce() || -+ (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) != 0) -+ return true; -+ -+ /* -+ * Otherwise, it raises an error or returns 'false', depending on the -+ * caller's indication by 'abort'. -+ */ -+ if (abort) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("SELinux: security policy violation"))); -+ -+ return false; -+} -+ -+/* -+ * sepgsql_compute_create -+ * -+ * It returns a default security context to be assigned on a new database -+ * object. SELinux compute it based on a combination of client, upper object -+ * which owns the new object and object class. -+ * -+ * For example, when a client (staff_u:staff_r:staff_t:s0) tries to create -+ * a new table within a schema (system_u:object_r:sepgsql_schema_t:s0), -+ * SELinux looks-up its security policy. If it has a special rule on the -+ * combination of these security contexts and object class (db_table), -+ * it returns the security context suggested by the special rule. -+ * Otherwise, it returns the security context of schema, as is. -+ * -+ * We expect the caller already applies sanity/validation checks on the -+ * given security context. -+ * -+ * scontext : The security context of subject. In most cases, it is client. -+ * tcontext : The security context of the parent database object.. -+ * tclass : One of the object class code (SEPG_CLASS_*) declared in the -+ * header file. -+ */ -+char * -+sepgsql_compute_create(char *scontext, char *tcontext, uint16 tclass) -+{ -+ security_context_t ncontext; -+ security_class_t tclass_ex; -+ const char *tclass_name; -+ char *result; -+ -+ /* Get external code of the object class*/ -+ Assert(tclass < SEPG_CLASS_MAX); -+ -+ tclass_name = selinux_catalog[tclass].class_name; -+ tclass_ex = string_to_security_class(tclass_name); -+ -+ /* -+ * Ask SELinux what is the default context for the given object class -+ * on a pair of security contexts -+ */ -+ if (security_compute_create_raw(scontext, tcontext, -+ tclass_ex, &ncontext)) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("SELinux could not compute a new context: " -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, tclass_name))); -+ -+ /* -+ * libselinux returns malloc()'ed string, so we need to copy it -+ * on the palloc()'ed region. -+ */ -+ PG_TRY(); -+ { -+ result = pstrdup(ncontext); -+ } -+ PG_CATCH(); -+ { -+ freecon(ncontext); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(ncontext); -+ -+ return result; -+} -diff --git a/src/backend/sepgsql/tablespace.c b/src/backend/sepgsql/tablespace.c -new file mode 100644 -index 0000000..1d3a35e ---- /dev/null -+++ b/src/backend/sepgsql/tablespace.c -@@ -0,0 +1,157 @@ -+/* -+ * tablespace.c -+ * -+ * SELinux hooks related to tablespaces -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_tablespace.h" -+#include "catalog/pg_seclabel.h" -+#include "commands/tablespace.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/syscache.h" -+#include "utils/lsyscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_tablespace_common(Oid tablespaceOid, uint32 required, bool abort) -+{ -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ bool retval; -+ const char *auname; -+ -+ tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tablespaceOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for tablespace %u", tablespaceOid); -+ -+ tsid.relid = TableSpaceRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname); -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+#endif -+ -+Oid -+sepgsql_tablespace_create(const char *tablespaceName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ -+ nsid = sepgsql_get_default_tuple_secid(TableSpaceRelationId); -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ tablespaceName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_tablespace_alter(Oid tablespaceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_tablespace_common(tablespaceOid, -+ SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_tablespace_relabel(Oid tablespaceOid, char *newLabel) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t tsid; -+ -+ tsid.relid = TableSpaceRelationId; -+ tsid.secid = seclabelTransInput(tsid.relid, newLabel); -+ -+ /* db_tuple:{update relabelfrom} */ -+ sepgsql_tablespace_common(tablespaceOid, -+ SEPG_DB_TUPLE__UPDATE | -+ SEPG_DB_TUPLE__RELABELFROM, true); -+ -+ /* db_procedure:{relabelto} */ -+ sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__RELABELTO, -+ get_tablespace_name(tablespaceOid), -+ true); -+ return tsid.secid; -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ return InvalidOid; -+} -+ -+void -+sepgsql_tablespace_drop(Oid tablespaceOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_tablespace_common(tablespaceOid, -+ SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_tablespace_grant(Oid tablespaceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_tablespace_common(tablespaceOid, -+ SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_tablespace_getattr(Oid tablespaceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_tablespace_common(tablespaceOid, -+ SEPG_DB_TUPLE__SELECT, true); -+ } -+#endif -+} -+ -+void -+sepgsql_tablespace_comment(Oid tablespaceOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_tablespace_common(tablespaceOid, -+ SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/tsearch.c b/src/backend/sepgsql/tsearch.c -new file mode 100644 -index 0000000..3d4180d ---- /dev/null -+++ b/src/backend/sepgsql/tsearch.c -@@ -0,0 +1,524 @@ -+/* -+ * tsearch.c -+ * -+ * SELinux hooks related to text searches -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_ts_config.h" -+#include "catalog/pg_ts_dict.h" -+#include "catalog/pg_ts_parser.h" -+#include "catalog/pg_ts_template.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/syscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_ts_config_common(Oid confOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ HeapTuple tuple; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(confOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search configuration %u", confOid); -+ -+ tsid.relid = TSConfigRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_ts_config) GETSTRUCT(tuple))->cfgname); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+static Oid -+get_ts_config_namespace(Oid confOid) -+{ -+ HeapTuple tuple; -+ Oid namespaceId = InvalidOid; -+ -+ tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(confOid)); -+ if (HeapTupleIsValid(tuple)) -+ { -+ namespaceId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgnamespace; -+ -+ ReleaseSysCache(tuple); -+ } -+ return namespaceId; -+} -+ -+bool -+sepgsql_ts_dict_common(Oid dictOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ HeapTuple tuple; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search dictionary %u", dictOid); -+ -+ tsid.relid = TSDictionaryRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_ts_dict) GETSTRUCT(tuple))->dictname); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+static Oid -+get_ts_dict_namespace(Oid dictOid) -+{ -+ HeapTuple tuple; -+ Oid namespaceId = InvalidOid; -+ -+ tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictOid)); -+ if (HeapTupleIsValid(tuple)) -+ { -+ namespaceId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictnamespace; -+ -+ ReleaseSysCache(tuple); -+ } -+ return namespaceId; -+} -+ -+bool -+sepgsql_ts_parser_common(Oid parseOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ HeapTuple tuple; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(parseOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search parser %u", parseOid); -+ -+ tsid.relid = TSParserRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_ts_parser) GETSTRUCT(tuple))->prsname); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+static Oid -+get_ts_parser_namespace(Oid parseOid) -+{ -+ HeapTuple tuple; -+ Oid namespaceId = InvalidOid; -+ -+ tuple = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(parseOid)); -+ if (HeapTupleIsValid(tuple)) -+ { -+ namespaceId = ((Form_pg_ts_parser) GETSTRUCT(tuple))->prsnamespace; -+ -+ ReleaseSysCache(tuple); -+ } -+ return namespaceId; -+} -+ -+bool -+sepgsql_ts_template_common(Oid templateOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ HeapTuple tuple; -+ const char *auname; -+ bool retval; -+ -+ tuple = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(templateOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search template %u", templateOid); -+ -+ tsid.relid = TSDictionaryRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ auname = NameStr(((Form_pg_ts_dict) GETSTRUCT(tuple))->dictname); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+static Oid -+get_ts_template_namespace(Oid templateOid) -+{ -+ HeapTuple tuple; -+ Oid namespaceId = InvalidOid; -+ -+ tuple = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(templateOid)); -+ if (HeapTupleIsValid(tuple)) -+ { -+ namespaceId = ((Form_pg_ts_template) GETSTRUCT(tuple))->tmplnamespace; -+ -+ ReleaseSysCache(tuple); -+ } -+ return namespaceId; -+} -+ -+#endif -+ -+Oid -+sepgsql_ts_config_create(const char *confName, Oid namespaceId) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid -+ = sepgsql_get_default_tuple_secid(TSConfigRelationId); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_tuple:{insert} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ confName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_ts_config_alter(Oid confOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_ts_config_common(confOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_ts_config_alter_rename(Oid confOid, const char *newName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_ts_config_namespace(confOid); -+ -+ /* db_schema:{add_name remove_name} */ -+ sepgsql_schema_common(namespaceId, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{update} */ -+ sepgsql_ts_config_common(confOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_ts_config_drop(Oid confOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_ts_config_namespace(confOid); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{delete} */ -+ sepgsql_ts_config_common(confOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_ts_config_comment(Oid confOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_ts_config_common(confOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_ts_dict_create(const char *dictName, Oid namespaceId) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid -+ = sepgsql_get_default_tuple_secid(TSDictionaryRelationId); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_tuple:{insert} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ dictName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_ts_dict_alter(Oid dictOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_ts_dict_common(dictOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_ts_dict_alter_rename(Oid dictOid, const char *newName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_ts_dict_namespace(dictOid); -+ -+ /* db_schema:{add_name remove_name} */ -+ sepgsql_schema_common(namespaceId, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{update} */ -+ sepgsql_ts_dict_common(dictOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_ts_dict_drop(Oid dictOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_ts_dict_namespace(dictOid); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{delete} */ -+ sepgsql_ts_dict_common(dictOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_ts_dict_comment(Oid dictOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_ts_dict_common(dictOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_ts_parser_create(const char *parseName, Oid namespaceId, -+ Oid startFunc, Oid tokenFunc, Oid endFunc, -+ Oid headlineFunc, Oid lextypeFunc) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid -+ = sepgsql_get_default_tuple_secid(TSParserRelationId); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(startFunc)) -+ sepgsql_proc_common(startFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(tokenFunc)) -+ sepgsql_proc_common(tokenFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(endFunc)) -+ sepgsql_proc_common(endFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(headlineFunc)) -+ sepgsql_proc_common(headlineFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(lextypeFunc)) -+ sepgsql_proc_common(lextypeFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* db_tuple:{insert} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ parseName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_ts_parser_alter_rename(Oid parseOid, const char *newName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_ts_parser_namespace(parseOid); -+ -+ /* db_schema:{add_name remove_name} */ -+ sepgsql_schema_common(namespaceId, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{update} */ -+ sepgsql_ts_parser_common(parseOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_ts_parser_drop(Oid parseOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_ts_parser_namespace(parseOid); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{delete} */ -+ sepgsql_ts_parser_common(parseOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_ts_parser_comment(Oid parseOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_ts_parser_common(parseOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_ts_template_create(const char *templateName, Oid namespaceId, -+ Oid initFunc, Oid lexizeFunc) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid -+ = sepgsql_get_default_tuple_secid(TSTemplateRelationId); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(initFunc)) -+ sepgsql_proc_common(initFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(lexizeFunc)) -+ sepgsql_proc_common(lexizeFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* db_tuple:{insert} */ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ templateName, -+ true); -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_ts_template_alter_rename(Oid templateOid, const char *newName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_ts_template_namespace(templateOid); -+ -+ /* db_schema:{add_name remove_name} */ -+ sepgsql_schema_common(namespaceId, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{update} */ -+ sepgsql_ts_template_common(templateOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_ts_template_drop(Oid templateOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_ts_template_namespace(templateOid); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{delete} */ -+ sepgsql_ts_template_common(templateOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_ts_template_comment(Oid templateOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_ts_template_common(templateOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -diff --git a/src/backend/sepgsql/type.c b/src/backend/sepgsql/type.c -new file mode 100644 -index 0000000..8cd65ae ---- /dev/null -+++ b/src/backend/sepgsql/type.c -@@ -0,0 +1,314 @@ -+/* -+ * type.c -+ * -+ * SELinux hooks related to types -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#include "postgres.h" -+ -+#include "catalog/pg_cast.h" -+#include "catalog/pg_seclabel.h" -+#include "catalog/pg_type.h" -+#include "sepgsql/hooks.h" -+#include "sepgsql/sepgsql.h" -+#include "utils/builtins.h" -+#include "utils/lsyscache.h" -+#include "utils/syscache.h" -+ -+#ifdef HAVE_SELINUX -+bool -+sepgsql_type_common(Oid typeOid, uint32 required, bool abort) -+{ -+ sepgsql_sid_t tsid; -+ char *auname; -+ bool retval; -+ -+ tsid.relid = TypeRelationId; -+ tsid.secid = GetSysCacheSecid1(TYPEOID, -+ ObjectIdGetDatum(typeOid)); -+ -+ auname = format_type_be(typeOid); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ auname, -+ abort); -+ pfree(auname); -+ -+ return retval; -+} -+ -+bool -+sepgsql_cast_common(Oid srcTypeOid, Oid dstTypeOid, -+ uint32 required, bool abort) -+{ -+ HeapTuple tuple; -+ sepgsql_sid_t tsid; -+ bool retval; -+ -+ tuple = SearchSysCache2(CASTSOURCETARGET, -+ ObjectIdGetDatum(srcTypeOid), -+ ObjectIdGetDatum(dstTypeOid)); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for cast (%u,%u)", -+ srcTypeOid, dstTypeOid); -+ -+ tsid.relid = CastRelationId; -+ tsid.secid = HeapTupleGetSecid(tuple); -+ -+ retval = sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ NULL, -+ abort); -+ ReleaseSysCache(tuple); -+ -+ return retval; -+} -+ -+static Oid -+get_type_namespace(Oid typeOid) -+{ -+ HeapTuple tuple; -+ Oid namespaceId; -+ -+ tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid)); -+ if (!HeapTupleIsValid(tuple)) -+ return InvalidOid; -+ -+ namespaceId = ((Form_pg_type) GETSTRUCT(tuple))->typnamespace; -+ -+ ReleaseSysCache(tuple); -+ -+ return namespaceId; -+} -+#endif -+ -+Oid -+sepgsql_type_create(const char *typeName, Oid replaced, -+ Oid namespaceId, char typeType, -+ Oid inputFunc, Oid outputFunc, -+ Oid recvFunc, Oid sendFunc, -+ Oid modinFunc, Oid modoutFunc, Oid analyzeFunc) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ uint32 required; -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_tuple:{insert or update} */ -+ if (!OidIsValid(replaced)) -+ { -+ nsid = sepgsql_get_default_tuple_secid(TypeRelationId); -+ required = SEPG_DB_TUPLE__INSERT; -+ } -+ else -+ { -+ nsid.relid = TypeRelationId; -+ nsid.secid = GetSysCacheSecid1(TYPEOID, -+ ObjectIdGetDatum(replaced)); -+ required = SEPG_DB_TUPLE__UPDATE; -+ } -+ -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ required, -+ typeName, -+ true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(inputFunc)) -+ sepgsql_proc_common(inputFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(outputFunc)) -+ sepgsql_proc_common(outputFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(recvFunc)) -+ sepgsql_proc_common(recvFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(sendFunc)) -+ sepgsql_proc_common(sendFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(modinFunc)) -+ sepgsql_proc_common(modinFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(modoutFunc)) -+ sepgsql_proc_common(modoutFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(analyzeFunc)) -+ sepgsql_proc_common(analyzeFunc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_type_alter(Oid typeOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_type_common(typeOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_type_alter_rename(Oid typeOid, const char *newName) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_type_namespace(typeOid); -+ -+ /* db_schema:{add_name remove_name} */ -+ sepgsql_schema_common(namespaceId, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_tuple:{update} */ -+ sepgsql_type_common(typeOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_type_alter_schema(Oid typeOid, Oid newSchema) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ Oid namespaceId = get_type_namespace(typeOid); -+ -+ /* db_schema:{ remove_name } */ -+ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ /* db_schema:{ add_name } */ -+ sepgsql_schema_common(newSchema, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_tuple:{update} */ -+ sepgsql_type_common(typeOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_type_relabel(Oid typeOid, char *newLabel) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t tsid; -+ -+ tsid.relid = TypeRelationId; -+ tsid.secid = seclabelTransInput(tsid.relid, newLabel); -+ -+ /* db_tuple:{update relabelfrom} */ -+ sepgsql_type_common(typeOid, -+ SEPG_DB_TUPLE__UPDATE | -+ SEPG_DB_TUPLE__RELABELFROM, true); -+ -+ /* db_procedure:{relabelto} */ -+ sepgsql_client_perms(tsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__RELABELTO, -+ format_type_be(typeOid), -+ true); -+ return tsid.secid; -+ } -+#endif -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL is not available"))); -+ return InvalidOid; -+} -+ -+void -+sepgsql_type_drop(Oid typeOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{delete} */ -+ sepgsql_type_common(typeOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_type_comment(Oid typeOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ /* db_tuple:{update} */ -+ sepgsql_type_common(typeOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -+ -+Oid -+sepgsql_cast_create(Oid sourceTypeOid, Oid targetTypeOid, -+ char castMethod, Oid castFuncOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_sid_t nsid; -+ -+ /* db_tuple:{insert} */ -+ nsid = sepgsql_get_default_tuple_secid(CastRelationId); -+ sepgsql_client_perms(nsid, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ NULL, -+ true); -+ /* db_procedure:{install} */ -+ if (OidIsValid(castFuncOid)) -+ sepgsql_proc_common(castFuncOid, -+ SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return nsid.secid; -+ } -+#endif -+ return InvalidOid; -+} -+ -+void -+sepgsql_cast_drop(Oid sourceTypeOid, Oid targetTypeOid, bool cascade) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_cast_common(sourceTypeOid, targetTypeOid, -+ SEPG_DB_TUPLE__DELETE, true); -+ } -+#endif -+} -+ -+void -+sepgsql_cast_comment(Oid sourceTypeOid, Oid targetTypeOid) -+{ -+#ifdef HAVE_SELINUX -+ if (sepgsql_is_enabled()) -+ { -+ sepgsql_cast_common(sourceTypeOid, targetTypeOid, -+ SEPG_DB_TUPLE__UPDATE, true); -+ } -+#endif -+} -diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c -index 36da56d..6240a62 100644 ---- a/src/backend/storage/large_object/inv_api.c -+++ b/src/backend/storage/large_object/inv_api.c -@@ -197,14 +197,14 @@ getbytealen(bytea *data) - * in use. - */ - Oid --inv_create(Oid lobjId) -+inv_create(Oid lobjId, Oid securityId) - { - Oid lobjId_new; - - /* - * Create a new largeobject with empty data pages - */ -- lobjId_new = LargeObjectCreate(lobjId); -+ lobjId_new = LargeObjectCreate(lobjId, securityId); - - /* - * dependency on the owner of largeobject -diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c -index 5870081..7ae10b3 100644 ---- a/src/backend/tcop/fastpath.c -+++ b/src/backend/tcop/fastpath.c -@@ -26,6 +26,7 @@ - #include "libpq/pqformat.h" - #include "mb/pg_wchar.h" - #include "miscadmin.h" -+#include "sepgsql/hooks.h" - #include "tcop/fastpath.h" - #include "tcop/tcopprot.h" - #include "utils/acl.h" -@@ -348,6 +349,10 @@ HandleFunctionRequest(StringInfo msgBuf) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(fid)); - -+ /* SELinux checks */ -+ sepgsql_schema_search(fip->namespace, true); -+ sepgsql_proc_execute(fid); -+ - /* - * Restrict access to pg_get_expr(). This reflects the hack in - * transformFuncCall() in parse_expr.c, see comments there for an -diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c -index d60dc49..0ef21eb 100644 ---- a/src/backend/tcop/pquery.c -+++ b/src/backend/tcop/pquery.c -@@ -575,7 +575,7 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot) - Assert(pstmt->hasReturning); - portal->tupDesc = - ExecCleanTypeFromTL(pstmt->planTree->targetlist, -- false); -+ false, false); - } - - /* -diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c -index ec36644..a25bd00 100644 ---- a/src/backend/tcop/utility.c -+++ b/src/backend/tcop/utility.c -@@ -165,6 +165,7 @@ check_xact_readonly(Node *parsetree) - case T_AlterRoleSetStmt: - case T_AlterObjectSchemaStmt: - case T_AlterOwnerStmt: -+ case T_AlterSecLabelStmt: - case T_AlterSeqStmt: - case T_AlterTableStmt: - case T_RenameStmt: -@@ -697,6 +698,10 @@ standard_ProcessUtility(Node *parsetree, - ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree); - break; - -+ case T_AlterSecLabelStmt: -+ ExecAlterSecLabelStmt((AlterSecLabelStmt *) parsetree); -+ break; -+ - case T_AlterTableStmt: - { - List *stmts; -@@ -1761,6 +1766,46 @@ CreateCommandTag(Node *parsetree) - } - break; - -+ case T_AlterSecLabelStmt: -+ switch (((AlterSecLabelStmt *) parsetree)->objectType) -+ { -+ case OBJECT_DATABASE: -+ tag = "ALTER DATABASE"; -+ break; -+ case OBJECT_SCHEMA: -+ tag = "ALTER SCHEMA"; -+ break; -+ case OBJECT_TABLE: -+ case OBJECT_COLUMN: -+ tag = "ALTER TABLE"; -+ break; -+ case OBJECT_SEQUENCE: -+ tag = "ALTER SEQUENCE"; -+ break; -+ case OBJECT_VIEW: -+ tag = "ALTER VIEW"; -+ break; -+ case OBJECT_FUNCTION: -+ tag = "ALTER FUNCTION"; -+ break; -+ case OBJECT_AGGREGATE: -+ tag = "ALTER AGGREGATE"; -+ break; -+ case OBJECT_LARGEOBJECT: -+ tag = "ALTER LARGE OBJECT"; -+ break; -+ case OBJECT_TYPE: -+ tag = "ALTER TYPE"; -+ break; -+ case OBJECT_DOMAIN: -+ tag = "ALTER DOMAIN"; -+ break; -+ default: -+ tag = "???"; -+ break; -+ } -+ break; -+ - case T_AlterTableStmt: - switch (((AlterTableStmt *) parsetree)->relkind) - { -@@ -2353,6 +2398,10 @@ GetCommandLogLevel(Node *parsetree) - lev = LOGSTMT_DDL; - break; - -+ case T_AlterSecLabelStmt: -+ lev = LOGSTMT_DDL; -+ break; -+ - case T_AlterTableStmt: - lev = LOGSTMT_DDL; - break; -diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c -index d74256f..f876951 100644 ---- a/src/backend/tsearch/wparser.c -+++ b/src/backend/tsearch/wparser.c -@@ -59,7 +59,7 @@ tt_setup_firstcall(FuncCallContext *funcctx, Oid prsid) - (Datum) 0)); - funcctx->user_fctx = (void *) st; - -- tupdesc = CreateTemplateTupleDesc(3, false); -+ tupdesc = CreateTemplateTupleDesc(3, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid", - INT4OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "alias", -@@ -205,7 +205,7 @@ prs_setup_firstcall(FuncCallContext *funcctx, Oid prsid, text *txt) - st->cur = 0; - - funcctx->user_fctx = (void *) st; -- tupdesc = CreateTemplateTupleDesc(2, false); -+ tupdesc = CreateTemplateTupleDesc(2, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid", - INT4OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "token", -diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c -index 79ca6c1..70fc9fb 100644 ---- a/src/backend/utils/adt/acl.c -+++ b/src/backend/utils/adt/acl.c -@@ -1695,7 +1695,7 @@ aclexplode(PG_FUNCTION_ARGS) - * build tupdesc for result tuples (matches out parameters in pg_proc - * entry) - */ -- tupdesc = CreateTemplateTupleDesc(4, false); -+ tupdesc = CreateTemplateTupleDesc(4, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor", - OIDOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee", -diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c -index 705fcf1..e897f55 100644 ---- a/src/backend/utils/adt/datetime.c -+++ b/src/backend/utils/adt/datetime.c -@@ -4213,7 +4213,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS) - * build tupdesc for result tuples. This must match this function's - * pg_proc entry! - */ -- tupdesc = CreateTemplateTupleDesc(3, false); -+ tupdesc = CreateTemplateTupleDesc(3, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "abbrev", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "utc_offset", -@@ -4306,7 +4306,7 @@ pg_timezone_names(PG_FUNCTION_ARGS) - * build tupdesc for result tuples. This must match this function's - * pg_proc entry! - */ -- tupdesc = CreateTemplateTupleDesc(4, false); -+ tupdesc = CreateTemplateTupleDesc(4, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "abbrev", -diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c -index 8b5def4..9f79a5c 100644 ---- a/src/backend/utils/adt/dbsize.c -+++ b/src/backend/utils/adt/dbsize.c -@@ -21,6 +21,7 @@ - #include "commands/dbcommands.h" - #include "commands/tablespace.h" - #include "miscadmin.h" -+#include "sepgsql/hooks.h" - #include "storage/fd.h" - #include "utils/acl.h" - #include "utils/builtins.h" -@@ -90,6 +91,9 @@ calculate_database_size(Oid dbOid) - aclcheck_error(aclresult, ACL_KIND_DATABASE, - get_database_name(dbOid)); - -+ /* SELinux checks */ -+ sepgsql_database_getattr(dbOid); -+ - /* Shared storage in pg_global is not counted */ - - /* Include pg_default storage */ -@@ -178,6 +182,8 @@ calculate_tablespace_size(Oid tblspcOid) - aclcheck_error(aclresult, ACL_KIND_TABLESPACE, - get_tablespace_name(tblspcOid)); - } -+ /* SELinux checks */ -+ sepgsql_tablespace_getattr(tblspcOid); - - if (tblspcOid == DEFAULTTABLESPACE_OID) - snprintf(tblspcPath, MAXPGPATH, "base"); -diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c -index 863727d..d4a5220 100644 ---- a/src/backend/utils/adt/genfile.c -+++ b/src/backend/utils/adt/genfile.c -@@ -25,6 +25,7 @@ - #include "mb/pg_wchar.h" - #include "miscadmin.h" - #include "postmaster/syslogger.h" -+#include "sepgsql/hooks.h" - #include "storage/fd.h" - #include "utils/builtins.h" - #include "utils/memutils.h" -@@ -100,6 +101,8 @@ pg_read_file(PG_FUNCTION_ARGS) - - filename = convert_and_check_filename(filename_t); - -+ sepgsql_file_read(filename); -+ - if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL) - ereport(ERROR, - (errcode_for_file_access(), -@@ -164,6 +167,8 @@ pg_stat_file(PG_FUNCTION_ARGS) - - filename = convert_and_check_filename(filename_t); - -+ sepgsql_file_getattr(filename); -+ - if (stat(filename, &fst) < 0) - ereport(ERROR, - (errcode_for_file_access(), -@@ -173,7 +178,7 @@ pg_stat_file(PG_FUNCTION_ARGS) - * This record type had better match the output parameters declared for me - * in pg_proc.h. - */ -- tupdesc = CreateTemplateTupleDesc(6, false); -+ tupdesc = CreateTemplateTupleDesc(6, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, - "size", INT8OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, -@@ -236,6 +241,8 @@ pg_ls_dir(PG_FUNCTION_ARGS) - fctx = palloc(sizeof(directory_fctx)); - fctx->location = convert_and_check_filename(PG_GETARG_TEXT_P(0)); - -+ sepgsql_dir_list(fctx->location); -+ - fctx->dirdesc = AllocateDir(fctx->location); - - if (!fctx->dirdesc) -diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c -index c72c4c1..0d23605 100644 ---- a/src/backend/utils/adt/lockfuncs.c -+++ b/src/backend/utils/adt/lockfuncs.c -@@ -85,7 +85,7 @@ pg_lock_status(PG_FUNCTION_ARGS) - - /* build tupdesc for result tuples */ - /* this had better match pg_locks view in system_views.sql */ -- tupdesc = CreateTemplateTupleDesc(14, false); -+ tupdesc = CreateTemplateTupleDesc(14, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database", -diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c -index 66c8598..c532dea 100644 ---- a/src/backend/utils/adt/misc.c -+++ b/src/backend/utils/adt/misc.c -@@ -322,7 +322,7 @@ pg_get_keywords(PG_FUNCTION_ARGS) - funcctx = SRF_FIRSTCALL_INIT(); - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - -- tupdesc = CreateTemplateTupleDesc(3, false); -+ tupdesc = CreateTemplateTupleDesc(3, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode", -diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c -index 8b13c8a..09bb38e 100644 ---- a/src/backend/utils/adt/pgstatfuncs.c -+++ b/src/backend/utils/adt/pgstatfuncs.c -@@ -419,7 +419,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) - - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - -- tupdesc = CreateTemplateTupleDesc(11, false); -+ tupdesc = CreateTemplateTupleDesc(11, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid", OIDOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "procpid", INT4OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "usesysid", OIDOID, -1, 0); -diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c -index 2d0ab44..87eb953 100644 ---- a/src/backend/utils/adt/ri_triggers.c -+++ b/src/backend/utils/adt/ri_triggers.c -@@ -30,6 +30,7 @@ - - #include "postgres.h" - -+#include "access/sysattr.h" - #include "access/xact.h" - #include "catalog/pg_constraint.h" - #include "catalog/pg_operator.h" -@@ -39,6 +40,7 @@ - #include "parser/parse_coerce.h" - #include "parser/parse_relation.h" - #include "miscadmin.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -@@ -2624,6 +2626,8 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) - char fkrelname[MAX_QUOTED_REL_NAME_LEN]; - char pkattname[MAX_QUOTED_NAME_LEN + 3]; - char fkattname[MAX_QUOTED_NAME_LEN + 3]; -+ Bitmapset *pkColumns = NULL; -+ Bitmapset *fkColumns = NULL; - const char *sep; - int i; - int old_work_mem; -@@ -2645,6 +2649,18 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) - - ri_FetchConstraintInfo(&riinfo, trigger, fk_rel, false); - -+ for (i = 0; i < riinfo.nkeys; i++) -+ { -+ fkColumns = bms_add_member(fkColumns, riinfo.fk_attnums[i] -+ - FirstLowInvalidHeapAttributeNumber); -+ pkColumns = bms_add_member(pkColumns, riinfo.pk_attnums[i] -+ - FirstLowInvalidHeapAttributeNumber); -+ } -+ -+ if (!sepgsql_relation_perms(RelationGetRelid(pk_rel), -+ ACL_SELECT, pkColumns, NULL, false)) -+ return false; -+ - /*---------- - * The query string built is: - * SELECT fk.keycols FROM ONLY relname fk -@@ -3259,6 +3275,7 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPlanPtr qplan, - int spi_result; - Oid save_userid; - int save_sec_context; -+ int save_rowlv, temp_rowlv; - Datum vals[RI_MAX_NUMKEYS * 2]; - char nulls[RI_MAX_NUMKEYS * 2]; - -@@ -3342,6 +3359,10 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPlanPtr qplan, - SetUserIdAndSecContext(RelationGetForm(query_rel)->relowner, - save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - -+ /* Switch rowlv control mode */ -+ temp_rowlv = (detectNewRows ? SEPGSQL_ROWLV_ABORT : SEPGSQL_ROWLV_FILTER); -+ save_rowlv = sepgsql_rowlv_set_mode(temp_rowlv); -+ - /* Finally we can run the query. */ - spi_result = SPI_execute_snapshot(qplan, - vals, nulls, -@@ -3351,6 +3372,9 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPlanPtr qplan, - /* Restore UID and security context */ - SetUserIdAndSecContext(save_userid, save_sec_context); - -+ /* Restore Rowlv control mode */ -+ sepgsql_rowlv_set_mode(save_rowlv); -+ - /* Check result */ - if (spi_result < 0) - elog(ERROR, "SPI_execute_snapshot returned %d", spi_result); -diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c -index 8c18a26..843d702 100644 ---- a/src/backend/utils/adt/tid.c -+++ b/src/backend/utils/adt/tid.c -@@ -27,6 +27,7 @@ - #include "libpq/pqformat.h" - #include "miscadmin.h" - #include "parser/parsetree.h" -+#include "sepgsql/hooks.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/rel.h" -@@ -347,6 +348,8 @@ currtid_byreloid(PG_FUNCTION_ARGS) - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_CLASS, - RelationGetRelationName(rel)); -+ /* SELinux checks */ -+ sepgsql_relation_getattr(RelationGetRelid(rel)); - - if (rel->rd_rel->relkind == RELKIND_VIEW) - return currtid_for_view(rel, tid); -@@ -377,6 +380,8 @@ currtid_byrelname(PG_FUNCTION_ARGS) - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_CLASS, - RelationGetRelationName(rel)); -+ /* SELinux checks */ -+ sepgsql_relation_getattr(RelationGetRelid(rel)); - - if (rel->rd_rel->relkind == RELKIND_VIEW) - return currtid_for_view(rel, tid); -diff --git a/src/backend/utils/adt/trigfuncs.c b/src/backend/utils/adt/trigfuncs.c -index d831b60..badc1f5 100644 ---- a/src/backend/utils/adt/trigfuncs.c -+++ b/src/backend/utils/adt/trigfuncs.c -@@ -76,6 +76,10 @@ suppress_redundant_updates_trigger(PG_FUNCTION_ARGS) - !OidIsValid(HeapTupleHeaderGetOid(newheader))) - HeapTupleHeaderSetOid(newheader, HeapTupleHeaderGetOid(oldheader)); - -+ if (trigdata->tg_relation->rd_rel->relhassecids && -+ !OidIsValid(HeapTupleHeaderGetSecid(newheader))) -+ HeapTupleHeaderSetSecid(newheader, HeapTupleHeaderGetSecid(oldheader)); -+ - /* if the tuple payload is the same ... */ - if (newtuple->t_len == oldtuple->t_len && - newheader->t_hoff == oldheader->t_hoff && -diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c -index 94c242d..b44cb63 100644 ---- a/src/backend/utils/adt/tsvector_op.c -+++ b/src/backend/utils/adt/tsvector_op.c -@@ -975,7 +975,7 @@ ts_setup_firstcall(FunctionCallInfo fcinfo, FuncCallContext *funcctx, - } - Assert(stat->stackpos <= stat->maxdepth); - -- tupdesc = CreateTemplateTupleDesc(3, false); -+ tupdesc = CreateTemplateTupleDesc(3, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "ndoc", -diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c -index 06e2549..56c5df9 100644 ---- a/src/backend/utils/cache/plancache.c -+++ b/src/backend/utils/cache/plancache.c -@@ -926,12 +926,12 @@ PlanCacheComputeResultDesc(List *stmt_list) - if (IsA(node, Query)) - { - query = (Query *) node; -- return ExecCleanTypeFromTL(query->targetList, false); -+ return ExecCleanTypeFromTL(query->targetList, false, false); - } - if (IsA(node, PlannedStmt)) - { - pstmt = (PlannedStmt *) node; -- return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false); -+ return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false, false); - } - /* other cases shouldn't happen, but return NULL */ - break; -@@ -942,13 +942,13 @@ PlanCacheComputeResultDesc(List *stmt_list) - { - query = (Query *) node; - Assert(query->returningList); -- return ExecCleanTypeFromTL(query->returningList, false); -+ return ExecCleanTypeFromTL(query->returningList, false, false); - } - if (IsA(node, PlannedStmt)) - { - pstmt = (PlannedStmt *) node; - Assert(pstmt->hasReturning); -- return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false); -+ return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false, false); - } - /* other cases shouldn't happen, but return NULL */ - break; -diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c -index 510f077..430d89e 100644 ---- a/src/backend/utils/cache/relcache.c -+++ b/src/backend/utils/cache/relcache.c -@@ -215,7 +215,7 @@ static void write_relcache_init_file(bool shared); - static void write_item(const void *data, Size len, FILE *fp); - - static void formrdesc(const char *relationName, Oid relationReltype, -- bool isshared, bool hasoids, -+ bool isshared, bool hasoids, bool hassecids, - int natts, const FormData_pg_attribute *attrs); - - static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK); -@@ -354,7 +354,8 @@ AllocateRelationDesc(Form_pg_class relp) - - /* and allocate attribute tuple form storage */ - relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts, -- relationForm->relhasoids); -+ relationForm->relhasoids, -+ relationForm->relhassecids); - /* which we mark as a reference-counted tupdesc */ - relation->rd_att->tdrefcount = 1; - -@@ -436,6 +437,7 @@ RelationBuildTupleDesc(Relation relation) - relation->rd_att->tdtypeid = relation->rd_rel->reltype; - relation->rd_att->tdtypmod = -1; /* unnecessary, but... */ - relation->rd_att->tdhasoid = relation->rd_rel->relhasoids; -+ relation->rd_att->tdhassecid = relation->rd_rel->relhassecids; - - constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext, - sizeof(TupleConstr)); -@@ -1395,7 +1397,7 @@ LookupOpclassInfo(Oid operatorClassOid, - */ - static void - formrdesc(const char *relationName, Oid relationReltype, -- bool isshared, bool hasoids, -+ bool isshared, bool hasoids, bool hassecids, - int natts, const FormData_pg_attribute *attrs) - { - Relation relation; -@@ -1458,6 +1460,7 @@ formrdesc(const char *relationName, Oid relationReltype, - relation->rd_rel->reltuples = 1; - relation->rd_rel->relkind = RELKIND_RELATION; - relation->rd_rel->relhasoids = hasoids; -+ relation->rd_rel->relhassecids = hassecids; - relation->rd_rel->relnatts = (int16) natts; - - /* -@@ -1467,7 +1470,7 @@ formrdesc(const char *relationName, Oid relationReltype, - * because it will never be replaced. The data comes from - * src/include/catalog/ headers via genbki.pl. - */ -- relation->rd_att = CreateTemplateTupleDesc(natts, hasoids); -+ relation->rd_att = CreateTemplateTupleDesc(natts, hasoids, hassecids); - relation->rd_att->tdrefcount = 1; /* mark as refcounted */ - - relation->rd_att->tdtypeid = relationReltype; -@@ -2542,6 +2545,7 @@ RelationBuildLocalRelation(const char *relname, - - rel->rd_rel->relkind = RELKIND_UNCATALOGED; - rel->rd_rel->relhasoids = rel->rd_att->tdhasoid; -+ rel->rd_rel->relhassecids = rel->rd_att->tdhassecid; - rel->rd_rel->relnatts = natts; - rel->rd_rel->reltype = InvalidOid; - /* needed when bootstrapping: */ -@@ -2784,11 +2788,11 @@ RelationCacheInitializePhase2(void) - if (!load_relcache_init_file(true)) - { - formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true, -- true, Natts_pg_database, Desc_pg_database); -+ true, true, Natts_pg_database, Desc_pg_database); - formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true, -- true, Natts_pg_authid, Desc_pg_authid); -+ true, true, Natts_pg_authid, Desc_pg_authid); - formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true, -- false, Natts_pg_auth_members, Desc_pg_auth_members); -+ false, false, Natts_pg_auth_members, Desc_pg_auth_members); - - #define NUM_CRITICAL_SHARED_RELS 3 /* fix if you change list above */ - } -@@ -2839,13 +2843,13 @@ RelationCacheInitializePhase3(void) - needNewCacheFile = true; - - formrdesc("pg_class", RelationRelation_Rowtype_Id, false, -- true, Natts_pg_class, Desc_pg_class); -+ true, true, Natts_pg_class, Desc_pg_class); - formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false, -- false, Natts_pg_attribute, Desc_pg_attribute); -+ false, true, Natts_pg_attribute, Desc_pg_attribute); - formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false, -- true, Natts_pg_proc, Desc_pg_proc); -+ true, true, Natts_pg_proc, Desc_pg_proc); - formrdesc("pg_type", TypeRelation_Rowtype_Id, false, -- true, Natts_pg_type, Desc_pg_type); -+ true, true, Natts_pg_type, Desc_pg_type); - - #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */ - } -@@ -2998,6 +3002,7 @@ RelationCacheInitializePhase3(void) - Assert(relation->rd_att->tdtypeid == relp->reltype); - Assert(relation->rd_att->tdtypmod == -1); - Assert(relation->rd_att->tdhasoid == relp->relhasoids); -+ Assert(relation->rd_att->tdhassecid == relp->relhassecids); - - ReleaseSysCache(htup); - -@@ -3108,7 +3113,7 @@ load_critical_index(Oid indexoid, Oid heapoid) - */ - static TupleDesc - BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs, -- bool hasoids) -+ bool hasoids, bool hassecids) - { - TupleDesc result; - MemoryContext oldcxt; -@@ -3116,7 +3121,7 @@ BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs, - - oldcxt = MemoryContextSwitchTo(CacheMemoryContext); - -- result = CreateTemplateTupleDesc(natts, hasoids); -+ result = CreateTemplateTupleDesc(natts, hasoids, hassecids); - result->tdtypeid = RECORDOID; /* not right, but we don't care */ - result->tdtypmod = -1; - -@@ -3146,7 +3151,7 @@ GetPgClassDescriptor(void) - if (pgclassdesc == NULL) - pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class, - Desc_pg_class, -- true); -+ true, true); - - return pgclassdesc; - } -@@ -3160,7 +3165,7 @@ GetPgIndexDescriptor(void) - if (pgindexdesc == NULL) - pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index, - Desc_pg_index, -- false); -+ false, false); - - return pgindexdesc; - } -@@ -3976,7 +3981,8 @@ load_relcache_init_file(bool shared) - - /* initialize attribute tuple forms */ - rel->rd_att = CreateTemplateTupleDesc(relform->relnatts, -- relform->relhasoids); -+ relform->relhasoids, -+ relform->relhassecids); - rel->rd_att->tdrefcount = 1; /* mark as refcounted */ - - rel->rd_att->tdtypeid = relform->reltype; -diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c -index 0224cfb..3137199 100644 ---- a/src/backend/utils/cache/syscache.c -+++ b/src/backend/utils/cache/syscache.c -@@ -895,6 +895,30 @@ GetSysCacheOid(int cacheId, - return result; - } - -+/* -+ * GetSysCacheSecid -+ * -+ * A convenience routine that does SearchSysCache and returns the -+ * security-id of the found tuple, or InvalidOid if no tuple could -+ * be found. No lock is retained on the syscache entry. -+ */ -+Oid -+GetSysCacheSecid(int cacheId, -+ Datum key1, -+ Datum key2, -+ Datum key3, -+ Datum key4) -+{ -+ HeapTuple tuple; -+ Oid result; -+ -+ tuple = SearchSysCache(cacheId, key1, key2, key3, key4); -+ if (!HeapTupleIsValid(tuple)) -+ return InvalidOid; -+ result = HeapTupleGetSecid(tuple); -+ ReleaseSysCache(tuple); -+ return result; -+} - - /* - * SearchSysCacheAttName -diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c -index 04f91f1..6f82199 100644 ---- a/src/backend/utils/fmgr/fmgr.c -+++ b/src/backend/utils/fmgr/fmgr.c -@@ -24,6 +24,7 @@ - #include "miscadmin.h" - #include "nodes/nodeFuncs.h" - #include "pgstat.h" -+#include "sepgsql/hooks.h" - #include "utils/builtins.h" - #include "utils/fmgrtab.h" - #include "utils/guc.h" -@@ -190,6 +191,7 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt, - finfo->fn_extra = NULL; - finfo->fn_mcxt = mcxt; - finfo->fn_expr = NULL; /* caller may set this later */ -+ finfo->fn_seclabel = NULL; - - if ((fbp = fmgr_isbuiltin(functionId)) != NULL) - { -@@ -228,15 +230,22 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt, - * ability to set the track_functions GUC as a local GUC parameter of an - * interesting function and have the right things happen. - */ -- if (!ignore_security && -- (procedureStruct->prosecdef || -- !heap_attisnull(procedureTuple, Anum_pg_proc_proconfig))) -+ if (!ignore_security) - { -- finfo->fn_addr = fmgr_security_definer; -- finfo->fn_stats = TRACK_FUNC_ALL; /* ie, never track */ -- finfo->fn_oid = functionId; -- ReleaseSysCache(procedureTuple); -- return; -+ char *seclabel -+ = sepgsql_proc_domtrans(procedureTuple, mcxt); -+ -+ if (procedureStruct->prosecdef || -+ !heap_attisnull(procedureTuple, Anum_pg_proc_proconfig) || -+ seclabel != NULL) -+ { -+ finfo->fn_addr = fmgr_security_definer; -+ finfo->fn_stats = TRACK_FUNC_ALL; /* ie, never track */ -+ finfo->fn_oid = functionId; -+ finfo->fn_seclabel = seclabel; -+ ReleaseSysCache(procedureTuple); -+ return; -+ } - } - - switch (procedureStruct->prolang) -@@ -877,6 +886,7 @@ fmgr_security_definer(PG_FUNCTION_ARGS) - FmgrInfo *save_flinfo; - Oid save_userid; - int save_sec_context; -+ char *save_seclabel; - volatile int save_nestlevel; - PgStat_FunctionCallUsage fcusage; - -@@ -939,6 +949,10 @@ fmgr_security_definer(PG_FUNCTION_ARGS) - PGC_S_SESSION, - GUC_ACTION_SAVE); - } -+ if (fcinfo->flinfo->fn_seclabel) -+ save_seclabel = sepgsql_set_client_label(fcinfo->flinfo->fn_seclabel); -+ else -+ save_seclabel = NULL; - - /* - * We don't need to restore GUC or userid settings on error, because the -@@ -978,6 +992,8 @@ fmgr_security_definer(PG_FUNCTION_ARGS) - AtEOXact_GUC(true, save_nestlevel); - if (OidIsValid(fcache->userid)) - SetUserIdAndSecContext(save_userid, save_sec_context); -+ if (fcinfo->flinfo->fn_seclabel) -+ sepgsql_set_client_label(save_seclabel); - - return result; - } -diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c -index d946aab..f7581a7 100644 ---- a/src/backend/utils/fmgr/funcapi.c -+++ b/src/backend/utils/fmgr/funcapi.c -@@ -1105,7 +1105,7 @@ build_function_result_tupdesc_d(Datum proallargtypes, - if (numoutargs < 2) - return NULL; - -- desc = CreateTemplateTupleDesc(numoutargs, false); -+ desc = CreateTemplateTupleDesc(numoutargs, false, false); - for (i = 0; i < numoutargs; i++) - { - TupleDescInitEntry(desc, i + 1, -@@ -1220,7 +1220,7 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases) - /* OK, get the column alias */ - attname = strVal(linitial(colaliases)); - -- tupdesc = CreateTemplateTupleDesc(1, false); -+ tupdesc = CreateTemplateTupleDesc(1, false, false); - TupleDescInitEntry(tupdesc, - (AttrNumber) 1, - attname, -diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c -index fc97683..1fcb33f 100644 ---- a/src/backend/utils/init/postinit.c -+++ b/src/backend/utils/init/postinit.c -@@ -37,6 +37,7 @@ - #include "postmaster/autovacuum.h" - #include "postmaster/postmaster.h" - #include "replication/walsender.h" -+#include "sepgsql/hooks.h" - #include "storage/bufmgr.h" - #include "storage/fd.h" - #include "storage/ipc.h" -@@ -306,6 +307,9 @@ CheckMyDatabase(const char *name, bool am_superuser) - errmsg("permission denied for database \"%s\"", name), - errdetail("User does not have CONNECT privilege."))); - -+ /* SELinux checks */ -+ sepgsql_database_connect(MyDatabaseId); -+ - /* - * Check connection limit for this database. - * -@@ -817,6 +821,9 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, - /* set up ACL framework (so CheckMyDatabase can check permissions) */ - initialize_acl(); - -+ /* set up enhanced security feature */ -+ sepgsql_initialize(); -+ - /* - * Re-read the pg_database row for our database, check permissions and set - * up database-specific GUC settings. We can't do this until all the -diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c -index 4e55b16..a9f9f7e 100644 ---- a/src/backend/utils/misc/guc.c -+++ b/src/backend/utils/misc/guc.c -@@ -31,6 +31,7 @@ - #include "access/twophase.h" - #include "access/xact.h" - #include "catalog/namespace.h" -+#include "catalog/pg_seclabel.h" - #include "commands/async.h" - #include "commands/prepare.h" - #include "commands/vacuum.h" -@@ -56,6 +57,7 @@ - #include "postmaster/syslogger.h" - #include "postmaster/walwriter.h" - #include "replication/walsender.h" -+#include "sepgsql/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/standby.h" - #include "storage/fd.h" -@@ -335,6 +337,18 @@ static const struct config_enum_entry constraint_exclusion_options[] = { - {NULL, 0, false} - }; - -+#ifdef HAVE_SELINUX -+static const struct config_enum_entry sepostgresql_options[] = { -+ {"default", SEPGSQL_MODE_DEFAULT, false}, -+ {"enforcing", SEPGSQL_MODE_ENFORCING, false}, -+ {"permissive", SEPGSQL_MODE_PERMISSIVE, false}, -+ {"disabled", SEPGSQL_MODE_DISABLED, false}, -+ {"on", SEPGSQL_MODE_DEFAULT, true}, -+ {"off", SEPGSQL_MODE_DISABLED, true}, -+ {NULL, 0, false}, -+}; -+#endif -+ - /* - * Options for enum values stored in other modules - */ -@@ -364,6 +378,7 @@ bool log_btree_build_stats = false; - - bool check_function_bodies = true; - bool default_with_oids = false; -+bool default_with_secids = true; - bool SQL_inheritance = true; - - bool Password_encryption = true; -@@ -1103,6 +1118,14 @@ static struct config_bool ConfigureNamesBool[] = - false, NULL, NULL - }, - { -+ {"default_with_secids", PGC_USERSET, CONN_AUTH_SETTINGS, -+ gettext_noop("Create new tables with security-ids by default."), -+ NULL -+ }, -+ &default_with_secids, -+ true, NULL, NULL -+ }, -+ { - {"logging_collector", PGC_POSTMASTER, LOGGING_WHERE, - gettext_noop("Start a subprocess to capture stderr output and/or csvlogs into log files."), - NULL -@@ -1270,6 +1293,36 @@ static struct config_bool ConfigureNamesBool[] = - false, NULL, NULL - }, - -+ { -+ {"ignore_security_label_input", PGC_USERSET, CONN_AUTH_SECURITY, -+ gettext_noop("Disables to assign used provided security label"), -+ NULL, -+ GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE -+ }, -+ &ignore_security_label_input, -+ false, NULL, NULL -+ }, -+#ifdef HAVE_SELINUX -+ { -+ {"sepostgresql_mcstrans", PGC_USERSET, CONN_AUTH_SECURITY, -+ gettext_noop("Enables to show security context in human-readable form"), -+ NULL, -+ GUC_NOT_IN_SAMPLE -+ }, -+ &sepgsql_mcstrans, -+ true, NULL, NULL -+ }, -+ { -+ {"sepostgresql_debug_audit", PGC_USERSET, CONN_AUTH_SECURITY, -+ gettext_noop("Enables to show audit logs for debugging"), -+ NULL, -+ GUC_NOT_IN_SAMPLE -+ }, -+ &sepgsql_debug_audit, -+ false, NULL, NULL -+ }, -+#endif -+ - /* End-of-list marker */ - { - {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL -@@ -2844,7 +2897,16 @@ static struct config_enum ConfigureNamesEnum[] = - &xmloption, - XMLOPTION_CONTENT, xmloption_options, NULL, NULL - }, -- -+#ifdef HAVE_SELINUX -+ { -+ {"sepostgresql", PGC_POSTMASTER, CONN_AUTH_SECURITY, -+ gettext_noop("Enables to set SE-PostgreSQL's mode"), -+ NULL -+ }, -+ &sepostgresql_mode, -+ SEPGSQL_MODE_DEFAULT, sepostgresql_options, NULL, sepgsql_show_mode -+ }, -+#endif - - /* End-of-list marker */ - { -@@ -6139,7 +6201,7 @@ GetPGVariableResultDesc(const char *name) - if (guc_name_compare(name, "all") == 0) - { - /* need a tuple descriptor representing three TEXT columns */ -- tupdesc = CreateTemplateTupleDesc(3, false); -+ tupdesc = CreateTemplateTupleDesc(3, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting", -@@ -6155,7 +6217,7 @@ GetPGVariableResultDesc(const char *name) - (void) GetConfigOptionByName(name, &varname); - - /* need a tuple descriptor representing a single TEXT column */ -- tupdesc = CreateTemplateTupleDesc(1, false); -+ tupdesc = CreateTemplateTupleDesc(1, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, - TEXTOID, -1, 0); - } -@@ -6178,7 +6240,7 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest) - value = GetConfigOptionByName(name, &varname); - - /* need a tuple descriptor representing a single TEXT column */ -- tupdesc = CreateTemplateTupleDesc(1, false); -+ tupdesc = CreateTemplateTupleDesc(1, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, - TEXTOID, -1, 0); - -@@ -6205,7 +6267,7 @@ ShowAllGUCConfig(DestReceiver *dest) - bool isnull[3] = {false, false, false}; - - /* need a tuple descriptor representing three TEXT columns */ -- tupdesc = CreateTemplateTupleDesc(3, false); -+ tupdesc = CreateTemplateTupleDesc(3, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting", -@@ -6600,7 +6662,7 @@ show_all_settings(PG_FUNCTION_ARGS) - * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns - * of the appropriate types - */ -- tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS, false); -+ tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting", -diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample -index a3880da..7537ac8 100644 ---- a/src/backend/utils/misc/postgresql.conf.sample -+++ b/src/backend/utils/misc/postgresql.conf.sample -@@ -76,6 +76,8 @@ - - # - Security and Authentication - - -+#sepostgresql = disabled # default|enforcing|permissive|disabled -+ - #authentication_timeout = 1min # 1s-600s - #ssl = off # (change requires restart) - #ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers -diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c -index 19c594d..b80b6ac 100644 ---- a/src/backend/utils/mmgr/portalmem.c -+++ b/src/backend/utils/mmgr/portalmem.c -@@ -949,7 +949,7 @@ pg_cursor(PG_FUNCTION_ARGS) - * build tupdesc for result tuples. This must match the definition of the - * pg_cursors view in system_views.sql - */ -- tupdesc = CreateTemplateTupleDesc(6, false); -+ tupdesc = CreateTemplateTupleDesc(6, false, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement", -diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c -index 0aee70d..ceb9a87 100644 ---- a/src/bin/initdb/initdb.c -+++ b/src/bin/initdb/initdb.c -@@ -87,6 +87,7 @@ static bool debug = false; - static bool noclean = false; - static bool show_setting = false; - static char *xlog_dir = ""; -+static bool enable_selinux = false; - - - /* internal vars */ -@@ -1163,6 +1164,13 @@ setup_config(void) - "#default_text_search_config = 'pg_catalog.simple'", - repltok); - -+ if (enable_selinux) -+ { -+ strcpy(repltok, "sepostgresql = default"); -+ conflines = replace_token(conflines, -+ "#sepostgresql = disabled", repltok); -+ } -+ - snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); - - writefile(path, conflines); -@@ -2394,6 +2402,7 @@ usage(const char *progname) - printf(_(" -U, --username=NAME database superuser name\n")); - printf(_(" -W, --pwprompt prompt for a password for the new superuser\n")); - printf(_(" -X, --xlogdir=XLOGDIR location for the transaction log directory\n")); -+ printf(_(" --enable-selinux enables SELinux support\n")); - printf(_("\nLess commonly used options:\n")); - printf(_(" -d, --debug generate lots of debugging output\n")); - printf(_(" -L DIRECTORY where to find the input files\n")); -@@ -2436,6 +2445,7 @@ main(int argc, char *argv[]) - {"show", no_argument, NULL, 's'}, - {"noclean", no_argument, NULL, 'n'}, - {"xlogdir", required_argument, NULL, 'X'}, -+ {"enable-selinux", no_argument, NULL, 10}, - {NULL, 0, NULL, 0} - }; - -@@ -2545,6 +2555,9 @@ main(int argc, char *argv[]) - case 9: - pwfilename = xstrdup(optarg); - break; -+ case 10: -+ enable_selinux = true; -+ break; - case 's': - show_setting = true; - break; -diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h -index 5a73779..67fce14 100644 ---- a/src/bin/pg_dump/pg_backup.h -+++ b/src/bin/pg_dump/pg_backup.h -@@ -103,6 +103,7 @@ typedef struct _restoreOptions - * restore */ - int use_setsessauth;/* Use SET SESSION AUTHORIZATION commands - * instead of OWNER TO */ -+ int noSecLabel; /* Don't try to restore security labels */ - char *superuser; /* Username to use as superuser */ - char *use_role; /* Issue SET ROLE to this */ - int dataOnly; -@@ -167,7 +168,7 @@ extern void ArchiveEntry(Archive *AHX, - CatalogId catalogId, DumpId dumpId, - const char *tag, - const char *namespace, const char *tablespace, -- const char *owner, bool withOids, -+ const char *owner, bool withOids, bool withSecids, - const char *desc, teSection section, - const char *defn, - const char *dropStmt, const char *copyStmt, -diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c -index 6528f4d..e482bde 100644 ---- a/src/bin/pg_dump/pg_backup_archiver.c -+++ b/src/bin/pg_dump/pg_backup_archiver.c -@@ -542,6 +542,8 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, - } - else - { -+ bool need_reset = false; -+ - _disableTriggersIfNecessary(AH, te, ropt); - - /* Select owner and schema as necessary */ -@@ -577,6 +579,16 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, - "ONLY " : ""), - fmtId(te->tag)); - } -+ /* -+ * If data section has security_label, but pg_restore works -+ * with --no-security-label, we set server flag to ignore -+ * the security label input. -+ */ -+ if (ropt->noSecLabel && te->withSecids) -+ { -+ ahprintf(AH, "SET ignore_security_label_input = on;\n\n"); -+ need_reset = true; -+ } - - /* - * If we have a copy statement, use it. As of V1.3, these -@@ -597,6 +609,9 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, - - AH->writingCopyData = false; - -+ if (need_reset) -+ ahprintf(AH, "RESET ignore_security_label_input;\n\n"); -+ - /* close out the transaction started above */ - if (is_parallel && te->created) - CommitTransaction(AH); -@@ -714,7 +729,7 @@ ArchiveEntry(Archive *AHX, - const char *tag, - const char *namespace, - const char *tablespace, -- const char *owner, bool withOids, -+ const char *owner, bool withOids, bool withSecids, - const char *desc, teSection section, - const char *defn, - const char *dropStmt, const char *copyStmt, -@@ -746,6 +761,7 @@ ArchiveEntry(Archive *AHX, - newToc->tablespace = tablespace ? strdup(tablespace) : NULL; - newToc->owner = strdup(owner); - newToc->withOids = withOids; -+ newToc->withSecids = withSecids; - newToc->desc = strdup(desc); - newToc->defn = strdup(defn); - newToc->dropStmt = strdup(dropStmt); -@@ -2048,6 +2064,7 @@ WriteToc(ArchiveHandle *AH) - WriteStr(AH, te->tablespace); - WriteStr(AH, te->owner); - WriteStr(AH, te->withOids ? "true" : "false"); -+ WriteStr(AH, te->withSecids ? "true" : "false"); - - /* Dump list of dependencies */ - for (i = 0; i < te->nDeps; i++) -@@ -2159,6 +2176,16 @@ ReadToc(ArchiveHandle *AH) - else - te->withOids = true; - -+ if (AH->version >= K_VERS_1_13) -+ { -+ if (strcmp(ReadStr(AH), "true") == 0) -+ te->withSecids = true; -+ else -+ te->withSecids = false; -+ } -+ else -+ te->withSecids = false; -+ - /* Read TOC entry dependencies */ - if (AH->version >= K_VERS_1_5) - { -@@ -2277,6 +2304,9 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls) - if ((!include_acls || ropt->aclsSkip) && _tocEntryIsACL(te)) - return 0; - -+ if (ropt->noSecLabel && strcmp(te->desc, "LABEL") == 0) -+ return 0; -+ - /* Ignore DATABASE entry unless we should create it */ - if (!ropt->createDB && strcmp(te->desc, "DATABASE") == 0) - return 0; -@@ -2343,6 +2373,8 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls) - (strcmp(te->desc, "ACL") == 0 && - strncmp(te->tag, "LARGE OBJECT ", 13) == 0) || - (strcmp(te->desc, "COMMENT") == 0 && -+ strncmp(te->tag, "LARGE OBJECT ", 13) == 0) || -+ (strcmp(te->desc, "LABEL") == 0 && - strncmp(te->tag, "LARGE OBJECT ", 13) == 0)) - res = res & REQ_DATA; - else -@@ -2494,6 +2526,36 @@ _doSetWithOids(ArchiveHandle *AH, const bool withOids) - destroyPQExpBuffer(cmd); - } - -+/* -+ * Issue a SET default_with_secids command. Caller is responsible -+ * for updating state if appropriate. -+ */ -+static void -+_doSetWithSecids(ArchiveHandle *AH, const bool withSecids) -+{ -+ PQExpBuffer cmd = createPQExpBuffer(); -+ -+ appendPQExpBuffer(cmd, "SET default_with_secids = %s;", withSecids ? -+ "true" : "false"); -+ -+ if (RestoringToDB(AH)) -+ { -+ PGresult *res; -+ -+ res = PQexec(AH->connection, cmd->data); -+ -+ if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) -+ warn_or_die_horribly(AH, modulename, -+ "could not set default_with_secids: %s", -+ PQerrorMessage(AH->connection)); -+ -+ PQclear(res); -+ } -+ else -+ ahprintf(AH, "%s\n\n", cmd->data); -+ -+ destroyPQExpBuffer(cmd); -+} - - /* - * Issue the commands to connect to the specified database. -@@ -2592,6 +2654,18 @@ _setWithOids(ArchiveHandle *AH, TocEntry *te) - } - } - -+/* -+ * Set the proper default_with_secids value for the table. -+ */ -+static void -+_setWithSecids(ArchiveHandle *AH, TocEntry *te) -+{ -+ if (AH->currWithSecids != te->withSecids) -+ { -+ _doSetWithSecids(AH, te->withSecids); -+ AH->currWithSecids = te->withSecids; -+ } -+} - - /* - * Issue the commands to select the specified schema as the current schema -@@ -2829,9 +2903,12 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat - _selectOutputSchema(AH, te->namespace); - _selectTablespace(AH, te->tablespace); - -- /* Set up OID mode too */ -+ /* Set up OID/SECID mode too */ - if (strcmp(te->desc, "TABLE") == 0) -+ { - _setWithOids(AH, te); -+ _setWithSecids(AH, te); -+ } - - /* Emit header comment for item */ - if (!AH->noTocComments) -diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h -index 9f826b6..a46be6b 100644 ---- a/src/bin/pg_dump/pg_backup_archiver.h -+++ b/src/bin/pg_dump/pg_backup_archiver.h -@@ -63,7 +63,7 @@ typedef z_stream *z_streamp; - - /* Current archive version number (the format we can output) */ - #define K_VERS_MAJOR 1 --#define K_VERS_MINOR 12 -+#define K_VERS_MINOR 13 - #define K_VERS_REV 0 - - /* Data block types */ -@@ -89,9 +89,10 @@ typedef z_stream *z_streamp; - * indicator */ - #define K_VERS_1_12 (( (1 * 256 + 12) * 256 + 0) * 256 + 0) /* add separate BLOB - * entries */ -- -+#define K_VERS_1_13 (( (1 * 256 + 13) * 256 + 0) * 256 + 0) /* add security label -+ * support */ - /* Newest format we can read */ --#define K_VERS_MAX (( (1 * 256 + 12) * 256 + 255) * 256 + 0) -+#define K_VERS_MAX (( (1 * 256 + 13) * 256 + 255) * 256 + 0) - - - /* Flags to indicate disposition of offsets stored in files */ -@@ -278,6 +279,7 @@ typedef struct _archiveHandle - char *currSchema; /* current schema, or NULL */ - char *currTablespace; /* current tablespace, or NULL */ - bool currWithOids; /* current default_with_oids setting */ -+ bool currWithSecids; /* current default_with_secids setting */ - - void *lo_buf; - size_t lo_buf_used; -@@ -305,6 +307,7 @@ typedef struct _tocEntry - * means use database default */ - char *owner; - bool withOids; /* Used only by "TABLE" tags */ -+ bool withSecids; /* Used only by "TABLE" tags */ - char *desc; - char *defn; - char *dropStmt; -diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c -index f93affd..0a89cf2 100644 ---- a/src/bin/pg_dump/pg_dump.c -+++ b/src/bin/pg_dump/pg_dump.c -@@ -125,7 +125,7 @@ static int binary_upgrade = 0; - static int disable_dollar_quoting = 0; - static int dump_inserts = 0; - static int column_inserts = 0; -- -+static int security_label = 0; - - static void help(const char *progname); - static void expand_schema_name_patterns(SimpleStringList *patterns, -@@ -183,6 +183,11 @@ static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId, - const char *tag, const char *nspname, const char *owner, - const char *acls); - -+static void dumpSecLabel(Archive *fout, DumpId objDumpId, -+ const char *target, -+ const char *namespace, -+ const char *seclabel); -+ - static void getDependencies(void); - static void getDomainConstraints(TypeInfo *tyinfo); - static void getTableData(TableInfo *tblinfo, int numTables, bool oids); -@@ -215,7 +220,7 @@ static bool binary_upgrade_set_type_oids_by_rel_oid( - static void binary_upgrade_set_relfilenodes(PQExpBuffer upgrade_buffer, - Oid pg_class_oid, bool is_index); - static const char *getAttrName(int attrnum, TableInfo *tblInfo); --static const char *fmtCopyColumnList(const TableInfo *ti); -+static const char *fmtCopyColumnList(const TableInfo *ti, bool secids); - static void do_sql_command(PGconn *conn, const char *query); - static void check_sql_result(PGresult *res, PGconn *conn, const char *query, - ExecStatusType expected); -@@ -299,6 +304,7 @@ main(int argc, char **argv) - {"no-tablespaces", no_argument, &outputNoTablespaces, 1}, - {"role", required_argument, NULL, 3}, - {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, -+ {"security-label", no_argument, &security_label, 1}, - - {NULL, 0, NULL, 0} - }; -@@ -447,6 +453,8 @@ main(int argc, char **argv) - outputNoTablespaces = 1; - else if (strcmp(optarg, "use-set-session-authorization") == 0) - use_setsessauth = 1; -+ else if (strcmp(optarg, "security-label") == 0) -+ security_label = 1; - else - { - fprintf(stderr, -@@ -516,6 +524,10 @@ main(int argc, char **argv) - exit(1); - } - -+ /* Force column insertion mode, when --security-label mode is given. */ -+ if (security_label && dump_inserts) -+ column_inserts = 1; -+ - /* open the output file */ - if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0) - { -@@ -834,6 +846,7 @@ help(const char *progname) - printf(_(" --use-set-session-authorization\n" - " use SET SESSION AUTHORIZATION commands instead of\n" - " ALTER OWNER commands to set ownership\n")); -+ printf(_(" --security-label dump schema/data with security label\n")); - - printf(_("\nConnection options:\n")); - printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); -@@ -1128,7 +1141,7 @@ dumpTableData_copy(Archive *fout, void *dcontext) - * cases involving ADD COLUMN and inheritance.) - */ - if (g_fout->remoteVersion >= 70300) -- column_list = fmtCopyColumnList(tbinfo); -+ column_list = fmtCopyColumnList(tbinfo, tdinfo->secids); - else - column_list = ""; /* can't select columns in COPY */ - -@@ -1252,14 +1265,16 @@ dumpTableData_insert(Archive *fout, void *dcontext) - if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " -- "SELECT * FROM ONLY %s", -+ "SELECT %s* FROM ONLY %s", -+ (tdinfo->secids ? "security_label," : ""), - fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, - classname)); - } - else - { - appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " -- "SELECT * FROM %s", -+ "SELECT %s* FROM %s", -+ (tdinfo->secids ? "security_label," : ""), - fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, - classname)); - } -@@ -1399,7 +1414,7 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo) - appendPQExpBuffer(copyBuf, "COPY %s ", - fmtId(tbinfo->dobj.name)); - appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n", -- fmtCopyColumnList(tbinfo), -+ fmtCopyColumnList(tbinfo, tdinfo->secids), - (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : ""); - copyStmt = copyBuf->data; - } -@@ -1413,7 +1428,7 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo) - ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId, - tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name, - NULL, tbinfo->rolname, -- false, "TABLE DATA", SECTION_DATA, -+ false, tdinfo->secids, "TABLE DATA", SECTION_DATA, - "", "", copyStmt, - tdinfo->dobj.dependencies, tdinfo->dobj.nDeps, - dumpFn, tdinfo); -@@ -1458,6 +1473,7 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids) - tdinfo->dobj.namespace = tblinfo[i].dobj.namespace; - tdinfo->tdtable = &(tblinfo[i]); - tdinfo->oids = oids; -+ tdinfo->secids = (security_label && tblinfo[i].hassecids) ? true : false; - addObjectDependency(&tdinfo->dobj, tblinfo[i].dobj.dumpId); - - tblinfo[i].dataObj = tdinfo; -@@ -1781,6 +1797,7 @@ dumpDatabase(Archive *AH) - NULL, /* Tablespace */ - dba, /* Owner */ - false, /* with oids */ -+ false, /* with secids */ - "DATABASE", /* Desc */ - SECTION_PRE_DATA, /* Section */ - creaQry->data, /* Create */ -@@ -1826,7 +1843,7 @@ dumpDatabase(Archive *AH) - LargeObjectRelationId); - ArchiveEntry(AH, nilCatalogId, createDumpId(), - "pg_largeobject", NULL, NULL, "", -- false, "pg_largeobject", SECTION_PRE_DATA, -+ false, false, "pg_largeobject", SECTION_PRE_DATA, - loOutQry->data, "", NULL, - NULL, 0, - NULL, NULL); -@@ -1858,7 +1875,7 @@ dumpDatabase(Archive *AH) - appendPQExpBuffer(dbQry, ";\n"); - - ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL, -- dba, false, "COMMENT", SECTION_NONE, -+ dba, false, false, "COMMENT", SECTION_NONE, - dbQry->data, "", NULL, - &dbDumpId, 1, NULL, NULL); - } -@@ -1897,7 +1914,7 @@ dumpEncoding(Archive *AH) - - ArchiveEntry(AH, nilCatalogId, createDumpId(), - "ENCODING", NULL, NULL, "", -- false, "ENCODING", SECTION_PRE_DATA, -+ false, false, "ENCODING", SECTION_PRE_DATA, - qry->data, "", NULL, - NULL, 0, - NULL, NULL); -@@ -1924,7 +1941,7 @@ dumpStdStrings(Archive *AH) - - ArchiveEntry(AH, nilCatalogId, createDumpId(), - "STDSTRINGS", NULL, NULL, "", -- false, "STDSTRINGS", SECTION_PRE_DATA, -+ false, false, "STDSTRINGS", SECTION_PRE_DATA, - qry->data, "", NULL, - NULL, 0, - NULL, NULL); -@@ -1957,16 +1974,17 @@ getBlobs(Archive *AH) - /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */ - if (AH->remoteVersion >= 90000) - appendPQExpBuffer(blobQry, -- "SELECT oid, (%s lomowner) AS rolname, lomacl" -+ "SELECT oid, (%s lomowner) AS rolname, lomacl, %s" - " FROM pg_largeobject_metadata", -- username_subquery); -+ username_subquery, -+ security_label ? "security_label" : "NULL"); - else if (AH->remoteVersion >= 70100) - appendPQExpBuffer(blobQry, -- "SELECT DISTINCT loid, NULL::oid, NULL::oid" -+ "SELECT DISTINCT loid, NULL::oid, NULL::oid, NULL::text" - " FROM pg_largeobject"); - else - appendPQExpBuffer(blobQry, -- "SELECT oid, NULL::oid, NULL::oid" -+ "SELECT oid, NULL::oid, NULL::oid, NULL::text" - " FROM pg_class WHERE relkind = 'l'"); - - res = PQexec(g_conn, blobQry->data); -@@ -1996,6 +2014,11 @@ getBlobs(Archive *AH) - binfo[i].blobacl = strdup(PQgetvalue(res, i, 2)); - else - binfo[i].blobacl = NULL; -+ -+ if (!PQgetisnull(res, i, 3)) -+ binfo[i].seclabel = strdup(PQgetvalue(res, i, 3)); -+ else -+ binfo[i].seclabel = NULL; - } - - /* -@@ -2035,7 +2058,7 @@ dumpBlob(Archive *AH, BlobInfo *binfo) - ArchiveEntry(AH, binfo->dobj.catId, binfo->dobj.dumpId, - binfo->dobj.name, - NULL, NULL, -- binfo->rolname, false, -+ binfo->rolname, false, false, - "BLOB", SECTION_PRE_DATA, - cquery->data, dquery->data, NULL, - binfo->dobj.dependencies, binfo->dobj.nDeps, -@@ -2050,6 +2073,10 @@ dumpBlob(Archive *AH, BlobInfo *binfo) - NULL, binfo->rolname, - binfo->dobj.catId, 0, binfo->dobj.dumpId); - -+ /* Dump security label if any */ -+ dumpSecLabel(AH, binfo->dobj.dumpId, -+ cquery->data, NULL, binfo->seclabel); -+ - /* Dump ACL if any */ - if (binfo->blobacl) - dumpACL(AH, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT", -@@ -2357,6 +2384,7 @@ getNamespaces(int *numNamespaces) - int i_nspname; - int i_rolname; - int i_nspacl; -+ int i_seclabel; - - /* - * Before 7.3, there are no real namespaces; create two dummy entries, one -@@ -2373,6 +2401,7 @@ getNamespaces(int *numNamespaces) - nsinfo[0].dobj.name = strdup("public"); - nsinfo[0].rolname = strdup(""); - nsinfo[0].nspacl = strdup(""); -+ nsinfo[0].seclabel = strdup(""); - - selectDumpableNamespace(&nsinfo[0]); - -@@ -2383,6 +2412,7 @@ getNamespaces(int *numNamespaces) - nsinfo[1].dobj.name = strdup("pg_catalog"); - nsinfo[1].rolname = strdup(""); - nsinfo[1].nspacl = strdup(""); -+ nsinfo[1].seclabel = strdup(""); - - selectDumpableNamespace(&nsinfo[1]); - -@@ -2403,8 +2433,8 @@ getNamespaces(int *numNamespaces) - */ - appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, " - "(%s nspowner) AS rolname, " -- "nspacl FROM pg_namespace", -- username_subquery); -+ "nspacl, %s AS seclabel FROM pg_namespace", -+ username_subquery, security_label ? "security_label" : "NULL"); - - res = PQexec(g_conn, query->data); - check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK); -@@ -2418,6 +2448,7 @@ getNamespaces(int *numNamespaces) - i_nspname = PQfnumber(res, "nspname"); - i_rolname = PQfnumber(res, "rolname"); - i_nspacl = PQfnumber(res, "nspacl"); -+ i_seclabel = PQfnumber(res, "seclabel"); - - for (i = 0; i < ntups; i++) - { -@@ -2428,6 +2459,7 @@ getNamespaces(int *numNamespaces) - nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname)); - nsinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); - nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl)); -+ nsinfo[i].seclabel = strdup(PQgetvalue(res, i, i_seclabel)); - - /* Decide whether to dump this namespace */ - selectDumpableNamespace(&nsinfo[i]); -@@ -2516,6 +2548,7 @@ getTypes(int *numTypes) - int i_typtype; - int i_typisdefined; - int i_isarray; -+ int i_seclabel; - - /* - * we include even the built-in types because those may be used as array -@@ -2548,8 +2581,10 @@ getTypes(int *numTypes) - "typtype, typisdefined, " - "typname[0] = '_' AND typelem != 0 AND " - "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray " -+ ",%s AS seclabel " - "FROM pg_type", -- username_subquery); -+ username_subquery, -+ security_label ? "security_label" : "NULL"); - } - else if (g_fout->remoteVersion >= 70300) - { -@@ -2562,6 +2597,7 @@ getTypes(int *numTypes) - "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " - "typtype, typisdefined, " - "typname[0] = '_' AND typelem != 0 AS isarray " -+ ",NULL AS seclabel " - "FROM pg_type", - username_subquery); - } -@@ -2576,6 +2612,7 @@ getTypes(int *numTypes) - "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " - "typtype, typisdefined, " - "typname[0] = '_' AND typelem != 0 AS isarray " -+ ",NULL AS seclabel " - "FROM pg_type", - username_subquery); - } -@@ -2592,6 +2629,7 @@ getTypes(int *numTypes) - "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " - "typtype, typisdefined, " - "typname[0] = '_' AND typelem != 0 AS isarray " -+ ",NULL AS seclabel " - "FROM pg_type", - username_subquery); - } -@@ -2616,6 +2654,7 @@ getTypes(int *numTypes) - i_typtype = PQfnumber(res, "typtype"); - i_typisdefined = PQfnumber(res, "typisdefined"); - i_isarray = PQfnumber(res, "isarray"); -+ i_seclabel = PQfnumber(res, "seclabel"); - - for (i = 0; i < ntups; i++) - { -@@ -2643,6 +2682,8 @@ getTypes(int *numTypes) - else - tyinfo[i].isArray = false; - -+ tyinfo[i].seclabel = strdup(PQgetvalue(res, i, i_seclabel)); -+ - /* Decide whether we want to dump it */ - selectDumpableType(&tyinfo[i]); - -@@ -3408,6 +3449,7 @@ getTables(int *numTables) - int i_relhasindex; - int i_relhasrules; - int i_relhasoids; -+ int i_relhassecids; - int i_relfrozenxid; - int i_owning_tab; - int i_owning_col; -@@ -3415,6 +3457,7 @@ getTables(int *numTables) - int i_reloptions; - int i_toastreloptions; - int i_reloftype; -+ int i_seclabel; - - /* Make sure we are in proper schema */ - selectSourceSchema("pg_catalog"); -@@ -3451,6 +3494,7 @@ getTables(int *numTables) - "(%s c.relowner) AS rolname, " - "c.relchecks, c.relhastriggers, " - "c.relhasindex, c.relhasrules, c.relhasoids, " -+ "c.relhassecids, " - "c.relfrozenxid, " - "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, " - "d.refobjid AS owning_tab, " -@@ -3458,6 +3502,7 @@ getTables(int *numTables) - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "array_to_string(c.reloptions, ', ') AS reloptions, " - "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions " -+ ",%s AS seclabel " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " -@@ -3468,6 +3513,7 @@ getTables(int *numTables) - "WHERE c.relkind in ('%c', '%c', '%c', '%c') " - "ORDER BY c.oid", - username_subquery, -+ security_label ? "c.security_label" : "NULL", - RELKIND_SEQUENCE, - RELKIND_RELATION, RELKIND_SEQUENCE, - RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); -@@ -3484,6 +3530,7 @@ getTables(int *numTables) - "(%s c.relowner) AS rolname, " - "c.relchecks, c.relhastriggers, " - "c.relhasindex, c.relhasrules, c.relhasoids, " -+ "false AS relhasecids, " - "c.relfrozenxid, " - "NULL AS reloftype, " - "d.refobjid AS owning_tab, " -@@ -3491,6 +3538,7 @@ getTables(int *numTables) - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "array_to_string(c.reloptions, ', ') AS reloptions, " - "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions " -+ ",%s AS seclabel " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " -@@ -3501,6 +3549,7 @@ getTables(int *numTables) - "WHERE c.relkind in ('%c', '%c', '%c', '%c') " - "ORDER BY c.oid", - username_subquery, -+ security_label ? "security_label" : "NULL", - RELKIND_SEQUENCE, - RELKIND_RELATION, RELKIND_SEQUENCE, - RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); -@@ -3517,6 +3566,7 @@ getTables(int *numTables) - "(%s relowner) AS rolname, " - "relchecks, (reltriggers <> 0) AS relhastriggers, " - "relhasindex, relhasrules, relhasoids, " -+ "false AS relhassecids, " - "relfrozenxid, " - "NULL AS reloftype, " - "d.refobjid AS owning_tab, " -@@ -3524,6 +3574,7 @@ getTables(int *numTables) - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "array_to_string(c.reloptions, ', ') AS reloptions, " - "NULL AS toast_reloptions " -+ ",NULL AS seclabel " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " -@@ -3549,6 +3600,7 @@ getTables(int *numTables) - "(%s relowner) AS rolname, " - "relchecks, (reltriggers <> 0) AS relhastriggers, " - "relhasindex, relhasrules, relhasoids, " -+ "false AS relhassecids, " - "0 AS relfrozenxid, " - "NULL AS reloftype, " - "d.refobjid AS owning_tab, " -@@ -3556,6 +3608,7 @@ getTables(int *numTables) - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "NULL AS reloptions, " - "NULL AS toast_reloptions " -+ ",NULL AS seclabel " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " -@@ -3581,6 +3634,7 @@ getTables(int *numTables) - "(%s relowner) AS rolname, " - "relchecks, (reltriggers <> 0) AS relhastriggers, " - "relhasindex, relhasrules, relhasoids, " -+ "false AS relhassecids, " - "0 AS relfrozenxid, " - "NULL AS reloftype, " - "d.refobjid AS owning_tab, " -@@ -3588,6 +3642,7 @@ getTables(int *numTables) - "NULL AS reltablespace, " - "NULL AS reloptions, " - "NULL AS toast_reloptions " -+ ",NULL AS seclabel " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " -@@ -3609,6 +3664,7 @@ getTables(int *numTables) - "(%s relowner) AS rolname, " - "relchecks, (reltriggers <> 0) AS relhastriggers, " - "relhasindex, relhasrules, relhasoids, " -+ "false AS relhassecids, " - "0 AS relfrozenxid, " - "NULL AS reloftype, " - "NULL::oid AS owning_tab, " -@@ -3616,6 +3672,7 @@ getTables(int *numTables) - "NULL AS reltablespace, " - "NULL AS reloptions, " - "NULL AS toast_reloptions " -+ ",NULL AS seclabel " - "FROM pg_class " - "WHERE relkind IN ('%c', '%c', '%c') " - "ORDER BY oid", -@@ -3632,6 +3689,7 @@ getTables(int *numTables) - "relchecks, (reltriggers <> 0) AS relhastriggers, " - "relhasindex, relhasrules, " - "'t'::bool AS relhasoids, " -+ "'f'::bool AS relhassecids, " - "0 AS relfrozenxid, " - "NULL AS reloftype, " - "NULL::oid AS owning_tab, " -@@ -3639,6 +3697,7 @@ getTables(int *numTables) - "NULL AS reltablespace, " - "NULL AS reloptions, " - "NULL AS toast_reloptions " -+ ",NULL AS seclabel " - "FROM pg_class " - "WHERE relkind IN ('%c', '%c', '%c') " - "ORDER BY oid", -@@ -3672,6 +3731,7 @@ getTables(int *numTables) - "NULL AS reltablespace, " - "NULL AS reloptions, " - "NULL AS toast_reloptions " -+ ",NULL AS seclabel " - "FROM pg_class c " - "WHERE relkind IN ('%c', '%c') " - "ORDER BY oid", -@@ -3710,6 +3770,7 @@ getTables(int *numTables) - i_relhasindex = PQfnumber(res, "relhasindex"); - i_relhasrules = PQfnumber(res, "relhasrules"); - i_relhasoids = PQfnumber(res, "relhasoids"); -+ i_relhassecids = PQfnumber(res, "relhassecids"); - i_relfrozenxid = PQfnumber(res, "relfrozenxid"); - i_owning_tab = PQfnumber(res, "owning_tab"); - i_owning_col = PQfnumber(res, "owning_col"); -@@ -3717,6 +3778,7 @@ getTables(int *numTables) - i_reloptions = PQfnumber(res, "reloptions"); - i_toastreloptions = PQfnumber(res, "toast_reloptions"); - i_reloftype = PQfnumber(res, "reloftype"); -+ i_seclabel = PQfnumber(res, "seclabel"); - - if (lockWaitTimeout && g_fout->remoteVersion >= 70300) - { -@@ -3749,6 +3811,7 @@ getTables(int *numTables) - tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0); - tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0); - tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0); -+ tblinfo[i].hassecids = (strcmp(PQgetvalue(res, i, i_relhassecids), "t")==0); - tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid)); - if (PQgetisnull(res, i, i_reloftype)) - tblinfo[i].reloftype = NULL; -@@ -3768,6 +3831,7 @@ getTables(int *numTables) - tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace)); - tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions)); - tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions)); -+ tblinfo[i].rellabel = strdup(PQgetvalue(res, i, i_seclabel)); - - /* other fields were zeroed above */ - -@@ -5083,6 +5147,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) - int i_attalign; - int i_attislocal; - int i_attoptions; -+ int i_seclabel; - PGresult *res; - int ntups; - bool hasdefaults; -@@ -5129,11 +5194,13 @@ getTableAttrs(TableInfo *tblinfo, int numTables) - "a.attlen, a.attalign, a.attislocal, " - "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, " - "array_to_string(attoptions, ', ') AS attoptions " -+ ",%s AS seclabel " - "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t " - "ON a.atttypid = t.oid " - "WHERE a.attrelid = '%u'::pg_catalog.oid " - "AND a.attnum > 0::pg_catalog.int2 " - "ORDER BY a.attrelid, a.attnum", -+ security_label ? "a.security_label" : "NULL", - tbinfo->dobj.catId.oid); - } - else if (g_fout->remoteVersion >= 70300) -@@ -5145,6 +5212,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) - "a.attlen, a.attalign, a.attislocal, " - "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, " - "'' AS attoptions " -+ ",NULL AS seclabel " - "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t " - "ON a.atttypid = t.oid " - "WHERE a.attrelid = '%u'::pg_catalog.oid " -@@ -5166,6 +5234,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) - "a.attalign, false AS attislocal, " - "format_type(t.oid,a.atttypmod) AS atttypname, " - "'' AS attoptions " -+ ",NULL AS seclabel " - "FROM pg_attribute a LEFT JOIN pg_type t " - "ON a.atttypid = t.oid " - "WHERE a.attrelid = '%u'::oid " -@@ -5184,6 +5253,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) - "false AS attislocal, " - "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, " - "'' AS attoptions " -+ ",NULL AS seclabel " - "FROM pg_attribute a " - "WHERE attrelid = '%u'::oid " - "AND attnum > 0::int2 " -@@ -5210,6 +5280,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) - i_attalign = PQfnumber(res, "attalign"); - i_attislocal = PQfnumber(res, "attislocal"); - i_attoptions = PQfnumber(res, "attoptions"); -+ i_seclabel = PQfnumber(res, "seclabel"); - - tbinfo->numatts = ntups; - tbinfo->attnames = (char **) malloc(ntups * sizeof(char *)); -@@ -5228,6 +5299,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) - tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool)); - tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool)); - tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool)); -+ tbinfo->attlabels = (char **) malloc(ntups * sizeof(char *)); - hasdefaults = false; - - for (j = 0; j < ntups; j++) -@@ -5257,6 +5329,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) - tbinfo->inhAttrs[j] = false; - tbinfo->inhAttrDef[j] = false; - tbinfo->inhNotNull[j] = false; -+ tbinfo->attlabels[j] = strdup(PQgetvalue(res, j, i_seclabel)); - } - - PQclear(res); -@@ -6153,7 +6226,7 @@ dumpComment(Archive *fout, const char *target, - */ - ArchiveEntry(fout, nilCatalogId, createDumpId(), - target, namespace, NULL, owner, -- false, "COMMENT", SECTION_NONE, -+ false, false, "COMMENT", SECTION_NONE, - query->data, "", NULL, - &(dumpId), 1, - NULL, NULL); -@@ -6214,7 +6287,7 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo, - target->data, - tbinfo->dobj.namespace->dobj.name, - NULL, tbinfo->rolname, -- false, "COMMENT", SECTION_NONE, -+ false, false, "COMMENT", SECTION_NONE, - query->data, "", NULL, - &(tbinfo->dobj.dumpId), 1, - NULL, NULL); -@@ -6236,7 +6309,7 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo, - target->data, - tbinfo->dobj.namespace->dobj.name, - NULL, tbinfo->rolname, -- false, "COMMENT", SECTION_NONE, -+ false, false, "COMMENT", SECTION_NONE, - query->data, "", NULL, - &(tbinfo->dobj.dumpId), 1, - NULL, NULL); -@@ -6516,7 +6589,7 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj) - case DO_BLOB_DATA: - ArchiveEntry(fout, dobj->catId, dobj->dumpId, - dobj->name, NULL, NULL, "", -- false, "BLOBS", SECTION_DATA, -+ false, false, "BLOBS", SECTION_DATA, - "", "", NULL, - dobj->dependencies, dobj->nDeps, - dumpBlobs, NULL); -@@ -6556,7 +6629,7 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo) - nspinfo->dobj.name, - NULL, NULL, - nspinfo->rolname, -- false, "SCHEMA", SECTION_PRE_DATA, -+ false, false, "SCHEMA", SECTION_PRE_DATA, - q->data, delq->data, NULL, - nspinfo->dobj.dependencies, nspinfo->dobj.nDeps, - NULL, NULL); -@@ -6568,6 +6641,9 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo) - NULL, nspinfo->rolname, - nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId); - -+ dumpSecLabel(fout, nspinfo->dobj.dumpId, -+ q->data, NULL, nspinfo->seclabel); -+ - dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA", - qnspname, NULL, nspinfo->dobj.name, NULL, - nspinfo->rolname, nspinfo->nspacl); -@@ -6685,7 +6761,7 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo) - tyinfo->dobj.name, - tyinfo->dobj.namespace->dobj.name, - NULL, -- tyinfo->rolname, false, -+ tyinfo->rolname, false, false, - "TYPE", SECTION_PRE_DATA, - q->data, delq->data, NULL, - tyinfo->dobj.dependencies, tyinfo->dobj.nDeps, -@@ -6699,6 +6775,12 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo) - tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, - tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId); - -+ /* Dump type security label */ -+ dumpSecLabel(fout, tyinfo->dobj.dumpId, -+ q->data, -+ tyinfo->dobj.namespace->dobj.name, -+ tyinfo->seclabel); -+ - PQclear(res); - destroyPQExpBuffer(q); - destroyPQExpBuffer(delq); -@@ -7061,7 +7143,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) - tyinfo->dobj.name, - tyinfo->dobj.namespace->dobj.name, - NULL, -- tyinfo->rolname, false, -+ tyinfo->rolname, false, false, - "TYPE", SECTION_PRE_DATA, - q->data, delq->data, NULL, - tyinfo->dobj.dependencies, tyinfo->dobj.nDeps, -@@ -7075,6 +7157,12 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) - tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, - tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId); - -+ /* Dump type security label */ -+ dumpSecLabel(fout, tyinfo->dobj.dumpId, -+ q->data, -+ tyinfo->dobj.namespace->dobj.name, -+ tyinfo->seclabel); -+ - PQclear(res); - destroyPQExpBuffer(q); - destroyPQExpBuffer(delq); -@@ -7185,7 +7273,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) - tyinfo->dobj.name, - tyinfo->dobj.namespace->dobj.name, - NULL, -- tyinfo->rolname, false, -+ tyinfo->rolname, false, false, - "DOMAIN", SECTION_PRE_DATA, - q->data, delq->data, NULL, - tyinfo->dobj.dependencies, tyinfo->dobj.nDeps, -@@ -7199,6 +7287,12 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) - tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, - tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId); - -+ /* Dump domain security label */ -+ dumpSecLabel(fout, tyinfo->dobj.dumpId, -+ q->data, -+ tyinfo->dobj.namespace->dobj.name, -+ tyinfo->seclabel); -+ - destroyPQExpBuffer(q); - destroyPQExpBuffer(delq); - destroyPQExpBuffer(query); -@@ -7290,7 +7384,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) - tyinfo->dobj.name, - tyinfo->dobj.namespace->dobj.name, - NULL, -- tyinfo->rolname, false, -+ tyinfo->rolname, false, false, - "TYPE", SECTION_PRE_DATA, - q->data, delq->data, NULL, - tyinfo->dobj.dependencies, tyinfo->dobj.nDeps, -@@ -7305,6 +7399,12 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) - tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, - tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId); - -+ /* Dump type security label */ -+ dumpSecLabel(fout, tyinfo->dobj.dumpId, -+ q->data, -+ tyinfo->dobj.namespace->dobj.name, -+ tyinfo->seclabel); -+ - PQclear(res); - destroyPQExpBuffer(q); - destroyPQExpBuffer(delq); -@@ -7409,7 +7509,7 @@ dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo) - target->data, - tyinfo->dobj.namespace->dobj.name, - NULL, tyinfo->rolname, -- false, "COMMENT", SECTION_NONE, -+ false, false, "COMMENT", SECTION_NONE, - query->data, "", NULL, - &(tyinfo->dobj.dumpId), 1, - NULL, NULL); -@@ -7461,7 +7561,7 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo) - stinfo->dobj.name, - stinfo->dobj.namespace->dobj.name, - NULL, -- stinfo->baseType->rolname, false, -+ stinfo->baseType->rolname, false, false, - "SHELL TYPE", SECTION_PRE_DATA, - q->data, "", NULL, - stinfo->dobj.dependencies, stinfo->dobj.nDeps, -@@ -7616,7 +7716,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) - ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId, - plang->dobj.name, - lanschema, NULL, plang->lanowner, -- false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA, -+ false, false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA, - defqry->data, delqry->data, NULL, - plang->dobj.dependencies, plang->dobj.nDeps, - NULL, NULL); -@@ -7802,6 +7902,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - char **argmodes = NULL; - char **argnames = NULL; - char **configitems = NULL; -+ char *proseclabel; - int nconfigitems = 0; - int i; - -@@ -7832,8 +7933,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "proiswindow, provolatile, proisstrict, prosecdef, " - "proconfig, procost, prorows, " - "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " -+ ",%s AS seclabel " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", -+ security_label ? "security_label" : "NULL", - finfo->dobj.catId.oid); - } - else if (g_fout->remoteVersion >= 80300) -@@ -7845,6 +7948,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "provolatile, proisstrict, prosecdef, " - "proconfig, procost, prorows, " - "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " -+ ",NULL AS seclabel " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -@@ -7858,6 +7962,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "provolatile, proisstrict, prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " - "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " -+ ",NULL AS seclabel " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -@@ -7873,6 +7978,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "provolatile, proisstrict, prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " - "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " -+ ",NULL AS seclabel " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -@@ -7888,6 +7994,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "provolatile, proisstrict, prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " - "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " -+ ",NULL AS seclabel " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -@@ -7905,6 +8012,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "false AS prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " - "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname " -+ ",NULL AS seclabel " - "FROM pg_proc " - "WHERE oid = '%u'::oid", - finfo->dobj.catId.oid); -@@ -7922,6 +8030,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "false AS prosecdef, " - "NULL AS proconfig, 0 AS procost, 0 AS prorows, " - "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname " -+ ",NULL AS seclabel " - "FROM pg_proc " - "WHERE oid = '%u'::oid", - finfo->dobj.catId.oid); -@@ -7966,6 +8075,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - procost = PQgetvalue(res, 0, PQfnumber(res, "procost")); - prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows")); - lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname")); -+ proseclabel = PQgetvalue(res, 0, PQfnumber(res, "seclabel")); - - /* - * See backend/commands/functioncmds.c for details of how the 'AS' clause -@@ -8176,7 +8286,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - funcsig_tag, - finfo->dobj.namespace->dobj.name, - NULL, -- finfo->rolname, false, -+ finfo->rolname, false, false, - "FUNCTION", SECTION_PRE_DATA, - q->data, delqry->data, NULL, - finfo->dobj.dependencies, finfo->dobj.nDeps, -@@ -8189,6 +8299,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - finfo->dobj.namespace->dobj.name, finfo->rolname, - finfo->dobj.catId, 0, finfo->dobj.dumpId); - -+ /* Dump Function security label */ -+ dumpSecLabel(fout, finfo->dobj.dumpId, -+ q->data, -+ finfo->dobj.namespace->dobj.name, -+ proseclabel); -+ - dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION", - funcsig, NULL, funcsig_tag, - finfo->dobj.namespace->dobj.name, -@@ -8330,7 +8446,7 @@ dumpCast(Archive *fout, CastInfo *cast) - ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId, - castsig->data, - "pg_catalog", NULL, "", -- false, "CAST", SECTION_PRE_DATA, -+ false, false, "CAST", SECTION_PRE_DATA, - defqry->data, delqry->data, NULL, - cast->dobj.dependencies, cast->dobj.nDeps, - NULL, NULL); -@@ -8574,7 +8690,7 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) - oprinfo->dobj.namespace->dobj.name, - NULL, - oprinfo->rolname, -- false, "OPERATOR", SECTION_PRE_DATA, -+ false, false, "OPERATOR", SECTION_PRE_DATA, - q->data, delq->data, NULL, - oprinfo->dobj.dependencies, oprinfo->dobj.nDeps, - NULL, NULL); -@@ -9033,7 +9149,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) - opcinfo->dobj.namespace->dobj.name, - NULL, - opcinfo->rolname, -- false, "OPERATOR CLASS", SECTION_PRE_DATA, -+ false, false, "OPERATOR CLASS", SECTION_PRE_DATA, - q->data, delq->data, NULL, - opcinfo->dobj.dependencies, opcinfo->dobj.nDeps, - NULL, NULL); -@@ -9314,7 +9430,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo) - opfinfo->dobj.namespace->dobj.name, - NULL, - opfinfo->rolname, -- false, "OPERATOR FAMILY", SECTION_PRE_DATA, -+ false, false, "OPERATOR FAMILY", SECTION_PRE_DATA, - q->data, delq->data, NULL, - opfinfo->dobj.dependencies, opfinfo->dobj.nDeps, - NULL, NULL); -@@ -9430,7 +9546,7 @@ dumpConversion(Archive *fout, ConvInfo *convinfo) - convinfo->dobj.namespace->dobj.name, - NULL, - convinfo->rolname, -- false, "CONVERSION", SECTION_PRE_DATA, -+ false, false, "CONVERSION", SECTION_PRE_DATA, - q->data, delq->data, NULL, - convinfo->dobj.dependencies, convinfo->dobj.nDeps, - NULL, NULL); -@@ -9511,11 +9627,13 @@ dumpAgg(Archive *fout, AggInfo *agginfo) - int i_aggtranstype; - int i_agginitval; - int i_convertok; -+ int i_seclabel; - const char *aggtransfn; - const char *aggfinalfn; - const char *aggsortop; - const char *aggtranstype; - const char *agginitval; -+ const char *seclabel; - bool convertok; - - /* Skip if not to be dumped */ -@@ -9538,9 +9656,11 @@ dumpAgg(Archive *fout, AggInfo *agginfo) - "aggsortop::pg_catalog.regoperator, " - "agginitval, " - "'t'::boolean AS convertok " -+ ",%s AS seclabel " - "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " - "WHERE a.aggfnoid = p.oid " - "AND p.oid = '%u'::pg_catalog.oid", -+ security_label ? "p.security_label" : "NULL", - agginfo->aggfn.dobj.catId.oid); - } - else if (g_fout->remoteVersion >= 70300) -@@ -9550,6 +9670,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) - "0 AS aggsortop, " - "agginitval, " - "'t'::boolean AS convertok " -+ ",NULL AS seclabel " - "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " - "WHERE a.aggfnoid = p.oid " - "AND p.oid = '%u'::pg_catalog.oid", -@@ -9562,6 +9683,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) - "0 AS aggsortop, " - "agginitval, " - "'t'::boolean AS convertok " -+ ",NULL AS seclabel " - "FROM pg_aggregate " - "WHERE oid = '%u'::oid", - agginfo->aggfn.dobj.catId.oid); -@@ -9574,6 +9696,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) - "0 AS aggsortop, " - "agginitval1 AS agginitval, " - "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok " -+ ",NULL AS seclabel " - "FROM pg_aggregate " - "WHERE oid = '%u'::oid", - agginfo->aggfn.dobj.catId.oid); -@@ -9599,6 +9722,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) - i_aggtranstype = PQfnumber(res, "aggtranstype"); - i_agginitval = PQfnumber(res, "agginitval"); - i_convertok = PQfnumber(res, "convertok"); -+ i_seclabel = PQfnumber(res, "seclabel"); - - aggtransfn = PQgetvalue(res, 0, i_aggtransfn); - aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn); -@@ -9606,6 +9730,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) - aggtranstype = PQgetvalue(res, 0, i_aggtranstype); - agginitval = PQgetvalue(res, 0, i_agginitval); - convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't'); -+ seclabel = PQgetvalue(res, 0, i_seclabel); - - aggsig = format_aggregate_signature(agginfo, fout, true); - aggsig_tag = format_aggregate_signature(agginfo, fout, false); -@@ -9674,7 +9799,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) - agginfo->aggfn.dobj.namespace->dobj.name, - NULL, - agginfo->aggfn.rolname, -- false, "AGGREGATE", SECTION_PRE_DATA, -+ false, false, "AGGREGATE", SECTION_PRE_DATA, - q->data, delq->data, NULL, - agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps, - NULL, NULL); -@@ -9686,6 +9811,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo) - agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname, - agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId); - -+ /* Dump Aggregate security label */ -+ dumpSecLabel(fout, agginfo->aggfn.dobj.dumpId, -+ q->data, -+ agginfo->aggfn.dobj.namespace->dobj.name, -+ seclabel); -+ - /* - * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL - * command look like a function's GRANT; in particular this affects the -@@ -9762,7 +9893,7 @@ dumpTSParser(Archive *fout, TSParserInfo *prsinfo) - prsinfo->dobj.namespace->dobj.name, - NULL, - "", -- false, "TEXT SEARCH PARSER", SECTION_PRE_DATA, -+ false, false, "TEXT SEARCH PARSER", SECTION_PRE_DATA, - q->data, delq->data, NULL, - prsinfo->dobj.dependencies, prsinfo->dobj.nDeps, - NULL, NULL); -@@ -9854,7 +9985,7 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo) - dictinfo->dobj.namespace->dobj.name, - NULL, - dictinfo->rolname, -- false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA, -+ false, false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA, - q->data, delq->data, NULL, - dictinfo->dobj.dependencies, dictinfo->dobj.nDeps, - NULL, NULL); -@@ -9914,7 +10045,7 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo) - tmplinfo->dobj.namespace->dobj.name, - NULL, - "", -- false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA, -+ false, false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA, - q->data, delq->data, NULL, - tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps, - NULL, NULL); -@@ -10047,7 +10178,7 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo) - cfginfo->dobj.namespace->dobj.name, - NULL, - cfginfo->rolname, -- false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA, -+ false, false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA, - q->data, delq->data, NULL, - cfginfo->dobj.dependencies, cfginfo->dobj.nDeps, - NULL, NULL); -@@ -10103,7 +10234,7 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo) - NULL, - NULL, - fdwinfo->rolname, -- false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA, -+ false, false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA, - q->data, delq->data, NULL, - fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps, - NULL, NULL); -@@ -10191,7 +10322,7 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo) - NULL, - NULL, - srvinfo->rolname, -- false, "SERVER", SECTION_PRE_DATA, -+ false, false, "SERVER", SECTION_PRE_DATA, - q->data, delq->data, NULL, - srvinfo->dobj.dependencies, srvinfo->dobj.nDeps, - NULL, NULL); -@@ -10296,7 +10427,7 @@ dumpUserMappings(Archive *fout, - tag->data, - namespace, - NULL, -- owner, false, -+ owner, false, false, - "USER MAPPING", SECTION_PRE_DATA, - q->data, delq->data, NULL, - &dumpId, 1, -@@ -10367,7 +10498,7 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo) - daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL, - NULL, - daclinfo->defaclrole, -- false, "DEFAULT ACL", SECTION_NONE, -+ false, false, "DEFAULT ACL", SECTION_NONE, - q->data, "", NULL, - daclinfo->dobj.dependencies, daclinfo->dobj.nDeps, - NULL, NULL); -@@ -10424,7 +10555,7 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId, - tag, nspname, - NULL, - owner ? owner : "", -- false, "ACL", SECTION_NONE, -+ false, false, "ACL", SECTION_NONE, - sql->data, "", NULL, - &(objDumpId), 1, - NULL, NULL); -@@ -10433,6 +10564,123 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId, - } - - /* -+ * dumpSecLabel -+ * -+ * write out security label of the objects -+ */ -+static void -+dumpSecLabel(Archive *fout, DumpId objDumpId, -+ const char *target, const char *namespace, -+ const char *seclabel) -+{ -+ PQExpBuffer qry; -+ -+ /* Do nothing, if security label dump is not given */ -+ if (!security_label || strlen(seclabel) == 0) -+ return; -+ -+ /* Do nothing, if --data-only for schemas, or --schema-only for blobs */ -+ if (strncmp(target, "LARGE OBJECT", 13) == 0) -+ { -+ if (schemaOnly) -+ return; -+ } -+ else -+ { -+ if (dataOnly) -+ return; -+ } -+ -+ /* Make ALTER xxx SECURITY LABEL TO command */ -+ qry = createPQExpBuffer(); -+ -+ appendPQExpBuffer(qry, "ALTER %s SECURITY LABEL TO '%s';", -+ target, seclabel); -+ -+ ArchiveEntry(fout, -+ nilCatalogId, /* catalog ID */ -+ createDumpId(), /* dump ID */ -+ target, /* name */ -+ namespace, /* namespace */ -+ NULL, /* tablespace */ -+ "", /* owner */ -+ false, /* with oids */ -+ false, /* with secids */ -+ "LABEL", /* desc */ -+ SECTION_NONE, /* section */ -+ qry->data, /* create */ -+ "", /* delete*/ -+ NULL, /* copy */ -+ &(objDumpId), /* dependency */ -+ 1, /* # deps */ -+ NULL, /* dumper Func */ -+ NULL); /* dumper Arg */ -+ -+ destroyPQExpBuffer(qry); -+} -+ -+/* -+ * dumpTableSecLabel -+ * -+ * write out security label of the table -+ */ -+static void -+dumpTableSecLabel(Archive *fout, DumpId objDumpId, -+ const char *namespace, -+ const char *table_name, -+ const char **column_names, int ncolumns, -+ const char *table_label, const char **column_labels) -+{ -+ PQExpBuffer qry; -+ PQExpBuffer tag; -+ int i; -+ -+ if (!security_label || dataOnly) -+ return; -+ -+ /* Make ALTER xxx SECURITY LABEL TO command */ -+ qry = createPQExpBuffer(); -+ tag = createPQExpBuffer(); -+ -+ appendPQExpBuffer(tag, "TABLE %s", table_name); -+ -+ if (strlen(table_label) > 0) -+ appendPQExpBuffer(qry, "ALTER TABLE %s SECURITY LABEL TO '%s';\n", -+ table_name, table_label); -+ for (i = 0; i < ncolumns; i++) -+ { -+ if (strlen(column_labels[i]) > 0) -+ appendPQExpBuffer(qry, "ALTER TABLE %s ALTER %s SECURITY LABEL TO '%s';\n", -+ table_name, -+ column_names[i], -+ column_labels[i]); -+ } -+ -+ if (qry->len > 0) -+ ArchiveEntry(fout, -+ nilCatalogId, /* catalog ID */ -+ createDumpId(), /* dump ID */ -+ tag->data, /* name */ -+ namespace, /* namespace */ -+ NULL, /* tablespace */ -+ "", /* owner */ -+ false, /* with oids */ -+ false, /* with secids */ -+ "LABEL", /* desc */ -+ SECTION_NONE, /* section */ -+ qry->data, /* create */ -+ "", /* delete*/ -+ NULL, /* copy */ -+ &(objDumpId), /* dependency */ -+ 1, /* # deps */ -+ NULL, /* dumper Func */ -+ NULL); /* dumper Arg */ -+ -+ destroyPQExpBuffer(qry); -+ destroyPQExpBuffer(tag); -+} -+ -+/* - * dumpTable - * write out to fout the declarations (not data) of a user-defined table - */ -@@ -10588,7 +10836,6 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) - - appendPQExpBuffer(q, "CREATE VIEW %s AS\n %s\n", - fmtId(tbinfo->dobj.name), viewdef); -- - PQclear(res); - } - else -@@ -10939,6 +11186,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) - (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace, - tbinfo->rolname, - (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false, -+ (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hassecids : false, - reltypename, SECTION_PRE_DATA, - q->data, delq->data, NULL, - tbinfo->dobj.dependencies, tbinfo->dobj.nDeps, -@@ -10959,6 +11207,27 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) - dumpTableConstraintComment(fout, constr); - } - -+ /* Dump relation/attribute's security labels */ -+ if (tbinfo->relkind == RELKIND_RELATION) -+ { -+ dumpTableSecLabel(fout, tbinfo->dobj.dumpId, -+ tbinfo->dobj.namespace->dobj.name, -+ tbinfo->dobj.name, -+ tbinfo->attnames, tbinfo->numatts, -+ tbinfo->rellabel, tbinfo->attlabels); -+ } -+ else -+ { -+ PQExpBuffer target = createPQExpBuffer(); -+ -+ appendPQExpBuffer(target, "%s %s", reltypename, fmtId(tbinfo->dobj.name)); -+ dumpSecLabel(fout, tbinfo->dobj.dumpId, -+ target->data, -+ tbinfo->dobj.namespace->dobj.name, -+ tbinfo->rellabel); -+ destroyPQExpBuffer(target); -+ } -+ - destroyPQExpBuffer(query); - destroyPQExpBuffer(q); - destroyPQExpBuffer(delq); -@@ -11007,7 +11276,7 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo) - tbinfo->dobj.namespace->dobj.name, - NULL, - tbinfo->rolname, -- false, "DEFAULT", SECTION_PRE_DATA, -+ false, false, "DEFAULT", SECTION_PRE_DATA, - q->data, delq->data, NULL, - adinfo->dobj.dependencies, adinfo->dobj.nDeps, - NULL, NULL); -@@ -11103,7 +11372,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) - indxinfo->dobj.name, - tbinfo->dobj.namespace->dobj.name, - indxinfo->tablespace, -- tbinfo->rolname, false, -+ tbinfo->rolname, false, false, - "INDEX", SECTION_POST_DATA, - q->data, delq->data, NULL, - indxinfo->dobj.dependencies, indxinfo->dobj.nDeps, -@@ -11228,7 +11497,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) - coninfo->dobj.name, - tbinfo->dobj.namespace->dobj.name, - indxinfo->tablespace, -- tbinfo->rolname, false, -+ tbinfo->rolname, false, false, - "CONSTRAINT", SECTION_POST_DATA, - q->data, delq->data, NULL, - coninfo->dobj.dependencies, coninfo->dobj.nDeps, -@@ -11261,7 +11530,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) - coninfo->dobj.name, - tbinfo->dobj.namespace->dobj.name, - NULL, -- tbinfo->rolname, false, -+ tbinfo->rolname, false, false, - "FK CONSTRAINT", SECTION_POST_DATA, - q->data, delq->data, NULL, - coninfo->dobj.dependencies, coninfo->dobj.nDeps, -@@ -11296,7 +11565,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) - coninfo->dobj.name, - tbinfo->dobj.namespace->dobj.name, - NULL, -- tbinfo->rolname, false, -+ tbinfo->rolname, false, false, - "CHECK CONSTRAINT", SECTION_POST_DATA, - q->data, delq->data, NULL, - coninfo->dobj.dependencies, coninfo->dobj.nDeps, -@@ -11332,7 +11601,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) - coninfo->dobj.name, - tyinfo->dobj.namespace->dobj.name, - NULL, -- tyinfo->rolname, false, -+ tyinfo->rolname, false, false, - "CHECK CONSTRAINT", SECTION_POST_DATA, - q->data, delq->data, NULL, - coninfo->dobj.dependencies, coninfo->dobj.nDeps, -@@ -11618,7 +11887,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) - tbinfo->dobj.namespace->dobj.name, - NULL, - tbinfo->rolname, -- false, "SEQUENCE", SECTION_PRE_DATA, -+ false, false, "SEQUENCE", SECTION_PRE_DATA, - query->data, delqry->data, NULL, - tbinfo->dobj.dependencies, tbinfo->dobj.nDeps, - NULL, NULL); -@@ -11654,7 +11923,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) - tbinfo->dobj.namespace->dobj.name, - NULL, - tbinfo->rolname, -- false, "SEQUENCE OWNED BY", SECTION_PRE_DATA, -+ false, false, "SEQUENCE OWNED BY", SECTION_PRE_DATA, - query->data, "", NULL, - &(tbinfo->dobj.dumpId), 1, - NULL, NULL); -@@ -11667,6 +11936,12 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) - dumpComment(fout, query->data, - tbinfo->dobj.namespace->dobj.name, tbinfo->rolname, - tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId); -+ -+ /* Dump sequence security label */ -+ dumpSecLabel(fout, tbinfo->dobj.dumpId, -+ query->data, -+ tbinfo->dobj.namespace->dobj.name, -+ tbinfo->rellabel); - } - - if (!schemaOnly) -@@ -11682,7 +11957,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) - tbinfo->dobj.namespace->dobj.name, - NULL, - tbinfo->rolname, -- false, "SEQUENCE SET", SECTION_PRE_DATA, -+ false, false, "SEQUENCE SET", SECTION_PRE_DATA, - query->data, "", NULL, - &(tbinfo->dobj.dumpId), 1, - NULL, NULL); -@@ -11866,7 +12141,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) - tginfo->dobj.name, - tbinfo->dobj.namespace->dobj.name, - NULL, -- tbinfo->rolname, false, -+ tbinfo->rolname, false, false, - "TRIGGER", SECTION_POST_DATA, - query->data, delqry->data, NULL, - tginfo->dobj.dependencies, tginfo->dobj.nDeps, -@@ -11986,7 +12261,7 @@ dumpRule(Archive *fout, RuleInfo *rinfo) - rinfo->dobj.name, - tbinfo->dobj.namespace->dobj.name, - NULL, -- tbinfo->rolname, false, -+ tbinfo->rolname, false, false, - "RULE", SECTION_POST_DATA, - cmd->data, delcmd->data, NULL, - rinfo->dobj.dependencies, rinfo->dobj.nDeps, -@@ -12351,7 +12626,7 @@ fmtQualifiedId(const char *schema, const char *id) - * "", not an invalid "()" column list. - */ - static const char * --fmtCopyColumnList(const TableInfo *ti) -+fmtCopyColumnList(const TableInfo *ti, bool secids) - { - static PQExpBuffer q = NULL; - int numatts = ti->numatts; -@@ -12367,6 +12642,11 @@ fmtCopyColumnList(const TableInfo *ti) - - appendPQExpBuffer(q, "("); - needComma = false; -+ if (secids) -+ { -+ appendPQExpBuffer(q, "security_label"); -+ needComma = true; -+ } - for (i = 0; i < numatts; i++) - { - if (attisdropped[i]) -diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h -index c309f69..2a35392 100644 ---- a/src/bin/pg_dump/pg_dump.h -+++ b/src/bin/pg_dump/pg_dump.h -@@ -137,6 +137,7 @@ typedef struct _namespaceInfo - DumpableObject dobj; - char *rolname; /* name of owner, or empty string */ - char *nspacl; -+ char *seclabel; - } NamespaceInfo; - - typedef struct _typeInfo -@@ -153,6 +154,7 @@ typedef struct _typeInfo - char typrelkind; /* 'r', 'v', 'c', etc */ - char typtype; /* 'b', 'c', etc */ - bool isArray; /* true if auto-generated array type */ -+ char *seclabel; - bool isDefined; /* true if typisdefined */ - /* If it's a dumpable base type, we create a "shell type" entry for it */ - struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */ -@@ -227,9 +229,11 @@ typedef struct _tableInfo - bool hasrules; /* does it have any rules? */ - bool hastriggers; /* does it have any triggers? */ - bool hasoids; /* does it have OIDs? */ -+ bool hassecids; /* does it have security-Id? */ - uint32 frozenxid; /* for restore frozen xid */ - int ncheck; /* # of CHECK expressions */ - char *reloftype; /* underlying type for typed table */ -+ char *rellabel; /* relation's security label */ - /* these two are set only if table is a sequence owned by a column: */ - Oid owning_tab; /* OID of table owning sequence */ - int owning_col; /* attr # of column owning sequence */ -@@ -252,6 +256,7 @@ typedef struct _tableInfo - char *attalign; /* attribute align, used by binary_upgrade */ - bool *attislocal; /* true if attr has local definition */ - char **attoptions; /* per-attribute options */ -+ char **attlabels; /* attribute's security label */ - - /* - * Note: we need to store per-attribute notnull, default, and constraint -@@ -287,6 +292,7 @@ typedef struct _tableDataInfo - DumpableObject dobj; - TableInfo *tdtable; /* link to table to dump */ - bool oids; /* include OIDs in data? */ -+ bool secids; /* include SecIDs in data? */ - } TableDataInfo; - - typedef struct _indxInfo -@@ -448,6 +454,7 @@ typedef struct _blobInfo - DumpableObject dobj; - char *rolname; - char *blobacl; -+ char *seclabel; - } BlobInfo; - - /* global decls */ -diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c -index 85032a9..3e4aad6 100644 ---- a/src/bin/pg_dump/pg_dumpall.c -+++ b/src/bin/pg_dump/pg_dumpall.c -@@ -69,6 +69,7 @@ static int disable_triggers = 0; - static int inserts = 0; - static int no_tablespaces = 0; - static int use_setsessauth = 0; -+static int security_label = 0; - static int server_version; - - static FILE *OPF; -@@ -132,6 +133,7 @@ main(int argc, char *argv[]) - {"no-tablespaces", no_argument, &no_tablespaces, 1}, - {"role", required_argument, NULL, 3}, - {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, -+ {"security-label", no_argument, &security_label, 1}, - - {NULL, 0, NULL, 0} - }; -@@ -285,6 +287,8 @@ main(int argc, char *argv[]) - no_tablespaces = 1; - else if (strcmp(optarg, "use-set-session-authorization") == 0) - use_setsessauth = 1; -+ else if (strcmp(optarg, "security-label") == 0) -+ security_label = 1; - else - { - fprintf(stderr, -@@ -368,6 +372,8 @@ main(int argc, char *argv[]) - appendPQExpBuffer(pgdumpopts, " --no-tablespaces"); - if (use_setsessauth) - appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization"); -+ if (security_label) -+ appendPQExpBuffer(pgdumpopts, " --security-label"); - - /* - * If there was a database specified on the command line, use that, -@@ -562,6 +568,7 @@ help(void) - printf(_(" --use-set-session-authorization\n" - " use SET SESSION AUTHORIZATION commands instead of\n" - " ALTER OWNER commands to set ownership\n")); -+ printf(_(" --security-label dump schema/data with security label\n")); - - printf(_("\nConnection options:\n")); - printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); -@@ -950,6 +957,7 @@ dropTablespaces(PGconn *conn) - static void - dumpTablespaces(PGconn *conn) - { -+ PQExpBuffer qry = createPQExpBuffer(); - PGresult *res; - int i; - -@@ -958,31 +966,37 @@ dumpTablespaces(PGconn *conn) - * pg_xxx) - */ - if (server_version >= 90000) -- res = executeQuery(conn, "SELECT spcname, " -+ appendPQExpBuffer(qry, "SELECT spcname, " - "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " - "spclocation, spcacl, " - "array_to_string(spcoptions, ', ')," - "pg_catalog.shobj_description(oid, 'pg_tablespace') " -+ ",%s AS seclabel " - "FROM pg_catalog.pg_tablespace " - "WHERE spcname !~ '^pg_' " -- "ORDER BY 1"); -+ "ORDER BY 1", -+ security_label ? "security_label" : "NULL"); - else if (server_version >= 80200) -- res = executeQuery(conn, "SELECT spcname, " -+ appendPQExpBuffer(qry, "SELECT spcname, " - "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " - "spclocation, spcacl, null, " - "pg_catalog.shobj_description(oid, 'pg_tablespace') " -+ ",NULL AS seclabel" - "FROM pg_catalog.pg_tablespace " - "WHERE spcname !~ '^pg_' " - "ORDER BY 1"); - else -- res = executeQuery(conn, "SELECT spcname, " -+ appendPQExpBuffer(qry, "SELECT spcname, " - "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " - "spclocation, spcacl, " - "null, null " -+ ",NULL AS seclabel" - "FROM pg_catalog.pg_tablespace " - "WHERE spcname !~ '^pg_' " - "ORDER BY 1"); - -+ res = PQexec(conn, qry->data); -+ - if (PQntuples(res) > 0) - fprintf(OPF, "--\n-- Tablespaces\n--\n\n"); - -@@ -995,6 +1009,7 @@ dumpTablespaces(PGconn *conn) - char *spcacl = PQgetvalue(res, i, 3); - char *spcoptions = PQgetvalue(res, i, 4); - char *spccomment = PQgetvalue(res, i, 5); -+ char *spcseclabel = PQgetvalue(res, i, 6); - char *fspcname; - - /* needed for buildACLCommands() */ -@@ -1011,6 +1026,10 @@ dumpTablespaces(PGconn *conn) - appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n", - fspcname, spcoptions); - -+ if (security_label && strlen(spcseclabel) > 0) -+ appendPQExpBuffer(buf, "ALTER TABLESPACE %s SECURITY LABEL TO '%s';\n", -+ fspcname, spcseclabel); -+ - if (!skip_acls && - !buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, spcowner, - "", server_version, buf)) -@@ -1154,48 +1173,48 @@ dumpCreateDB(PGconn *conn) - - /* Now collect all the information about databases to dump */ - if (server_version >= 80400) -- res = executeQuery(conn, -- "SELECT datname, " -+ appendPQExpBuffer(buf, "SELECT datname, " - "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "datcollate, datctype, datfrozenxid, " - "datistemplate, datacl, datconnlimit, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " -+ ",%s AS seclabel " - "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " -- "WHERE datallowconn ORDER BY 1"); -+ "WHERE datallowconn ORDER BY 1", -+ security_label ? "d.security_label" : "NULL"); - else if (server_version >= 80100) -- res = executeQuery(conn, -- "SELECT datname, " -+ appendPQExpBuffer(buf, "SELECT datname, " - "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, datfrozenxid, " - "datistemplate, datacl, datconnlimit, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " -+ ",NULL AS seclabel " - "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 80000) -- res = executeQuery(conn, -- "SELECT datname, " -+ appendPQExpBuffer(buf, "SELECT datname, " - "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, datfrozenxid, " - "datistemplate, datacl, -1 as datconnlimit, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " -+ ",NULL AS seclabel " - "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 70300) -- res = executeQuery(conn, -- "SELECT datname, " -+ appendPQExpBuffer(buf, "SELECT datname, " - "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, datfrozenxid, " - "datistemplate, datacl, -1 as datconnlimit, " - "'pg_default' AS dattablespace " -+ ",NULL AS seclabel " - "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 70100) -- res = executeQuery(conn, -- "SELECT datname, " -+ appendPQExpBuffer(buf, "SELECT datname, " - "coalesce(" - "(select usename from pg_shadow where usesysid=datdba), " - "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " -@@ -1203,6 +1222,7 @@ dumpCreateDB(PGconn *conn) - "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, " - "datistemplate, '' as datacl, -1 as datconnlimit, " - "'pg_default' AS dattablespace " -+ ",NULL AS seclabel " - "FROM pg_database d " - "WHERE datallowconn ORDER BY 1"); - else -@@ -1211,18 +1231,20 @@ dumpCreateDB(PGconn *conn) - * Note: 7.0 fails to cope with sub-select in COALESCE, so just deal - * with getting a NULL by not printing any OWNER clause. - */ -- res = executeQuery(conn, -- "SELECT datname, " -+ appendPQExpBuffer(buf, "SELECT datname, " - "(select usename from pg_shadow where usesysid=datdba), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, " - "'f' as datistemplate, " - "'' as datacl, -1 as datconnlimit, " - "'pg_default' AS dattablespace " -+ ",NULL AS seclabel " - "FROM pg_database d " - "ORDER BY 1"); - } - -+ res = PQexec(conn, buf->data); -+ - for (i = 0; i < PQntuples(res); i++) - { - char *dbname = PQgetvalue(res, i, 0); -@@ -1235,6 +1257,7 @@ dumpCreateDB(PGconn *conn) - char *dbacl = PQgetvalue(res, i, 7); - char *dbconnlimit = PQgetvalue(res, i, 8); - char *dbtablespace = PQgetvalue(res, i, 9); -+ char *dbseclabel = PQgetvalue(res, i, 10); - char *fdbname; - - fdbname = strdup(fmtId(dbname)); -@@ -1310,6 +1333,9 @@ dumpCreateDB(PGconn *conn) - appendPQExpBuffer(buf, ";\n"); - } - } -+ if (security_label && strlen(dbseclabel) > 0) -+ appendPQExpBuffer(buf, "ALTER DATABASE %s SECURITY LABEL TO '%s';\n", -+ dbname, dbseclabel); - - if (!skip_acls && - !buildACLCommands(fdbname, NULL, "DATABASE", dbacl, dbowner, -diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c -index dbdf7ac..03b9d67 100644 ---- a/src/bin/pg_dump/pg_restore.c -+++ b/src/bin/pg_dump/pg_restore.c -@@ -76,6 +76,7 @@ main(int argc, char **argv) - static int no_data_for_failed_tables = 0; - static int outputNoTablespaces = 0; - static int use_setsessauth = 0; -+ static int no_security_label = 0; - - struct option cmdopts[] = { - {"clean", 0, NULL, 'c'}, -@@ -116,6 +117,7 @@ main(int argc, char **argv) - {"no-tablespaces", no_argument, &outputNoTablespaces, 1}, - {"role", required_argument, NULL, 2}, - {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, -+ {"no-security-label", no_argument, &no_security_label, 1}, - - {NULL, 0, NULL, 0} - }; -@@ -262,6 +264,8 @@ main(int argc, char **argv) - outputNoTablespaces = 1; - else if (strcmp(optarg, "use-set-session-authorization") == 0) - use_setsessauth = 1; -+ else if (strcmp(optarg, "no-security-label") == 0) -+ no_security_label = 1; - else - { - fprintf(stderr, -@@ -337,6 +341,7 @@ main(int argc, char **argv) - opts->noDataForFailedTables = no_data_for_failed_tables; - opts->noTablespace = outputNoTablespaces; - opts->use_setsessauth = use_setsessauth; -+ opts->noSecLabel = no_security_label; - - if (opts->formatName) - { -@@ -448,6 +453,7 @@ usage(const char *progname) - " ALTER OWNER commands to set ownership\n")); - printf(_(" -1, --single-transaction\n" - " restore as a single transaction\n")); -+ printf(_(" --no-security-label skip restoration of security labels\n")); - - printf(_("\nConnection options:\n")); - printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); -diff --git a/src/include/access/htup.h b/src/include/access/htup.h -index 3be701b..4501289 100644 ---- a/src/include/access/htup.h -+++ b/src/include/access/htup.h -@@ -163,7 +163,7 @@ typedef HeapTupleHeaderData *HeapTupleHeader; - #define HEAP_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */ - #define HEAP_HASEXTERNAL 0x0004 /* has external stored attribute(s) */ - #define HEAP_HASOID 0x0008 /* has an object-id field */ --/* bit 0x0010 is available */ -+#define HEAP_HASSECID 0x0010 /* has an security-id field */ - #define HEAP_COMBOCID 0x0020 /* t_cid is a combo cid */ - #define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */ - #define HEAP_XMAX_SHARED_LOCK 0x0080 /* xmax is shared locker */ -@@ -292,6 +292,9 @@ do { \ - (tup)->t_choice.t_datum.datum_typmod = (typmod) \ - ) - -+#define HeapTupleHeaderHasOid(tup) \ -+ ((tup)->t_infomask & HEAP_HASOID) -+ - #define HeapTupleHeaderGetOid(tup) \ - ( \ - ((tup)->t_infomask & HEAP_HASOID) ? \ -@@ -351,6 +354,25 @@ do { \ - (tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \ - ) - -+#define HeapTupleHeaderHasSecid(tup) \ -+ ((tup)->t_infomask & HEAP_HASSECID) -+ -+#define HeapTupleHeaderGetSecid(tup) \ -+ ( \ -+ HeapTupleHeaderHasSecid(tup) \ -+ ? (*(Oid *)((char *)(tup) + (tup)->t_hoff \ -+ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \ -+ - sizeof(Oid))) \ -+ : InvalidOid \ -+ ) -+ -+#define HeapTupleHeaderSetSecid(tup, secid) \ -+ do { \ -+ Assert(HeapTupleHeaderHasSecid(tup)); \ -+ *((Oid *)((char *)(tup) + (tup)->t_hoff \ -+ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \ -+ - sizeof(Oid))) = (secid); \ -+ } while(0) - - /* - * BITMAPLEN(NATTS) - -@@ -545,12 +567,23 @@ typedef HeapTupleData *HeapTuple; - #define HeapTupleClearHeapOnly(tuple) \ - HeapTupleHeaderClearHeapOnly((tuple)->t_data) - -+#define HeapTupleHasOid(tuple) \ -+ HeapTupleHeaderHasOid((tuple)->t_data) -+ - #define HeapTupleGetOid(tuple) \ - HeapTupleHeaderGetOid((tuple)->t_data) - - #define HeapTupleSetOid(tuple, oid) \ - HeapTupleHeaderSetOid((tuple)->t_data, (oid)) - -+#define HeapTupleHasSecid(tuple) \ -+ HeapTupleHeaderHasSecid((tuple)->t_data) -+ -+#define HeapTupleGetSecid(tuple) \ -+ HeapTupleHeaderGetSecid((tuple)->t_data) -+ -+#define HeapTupleSetSecid(tuple, secid) \ -+ HeapTupleHeaderSetSecid((tuple)->t_data, (secid)) - - /* - * WAL record definitions for heapam.c's WAL operations -diff --git a/src/include/access/sysattr.h b/src/include/access/sysattr.h -index 6047735..ce9a994 100644 ---- a/src/include/access/sysattr.h -+++ b/src/include/access/sysattr.h -@@ -25,7 +25,8 @@ - #define MaxTransactionIdAttributeNumber (-5) - #define MaxCommandIdAttributeNumber (-6) - #define TableOidAttributeNumber (-7) --#define FirstLowInvalidHeapAttributeNumber (-8) -+#define SecurityLabelAttributeNumber (-8) -+#define FirstLowInvalidHeapAttributeNumber (-9) - - - #endif /* SYSATTR_H */ -diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h -index e38a6e7..d5688d5 100644 ---- a/src/include/access/tupdesc.h -+++ b/src/include/access/tupdesc.h -@@ -75,13 +75,14 @@ typedef struct tupleDesc - Oid tdtypeid; /* composite type ID for tuple type */ - int32 tdtypmod; /* typmod for tuple type */ - bool tdhasoid; /* tuple has oid attribute in its header */ -+ bool tdhassecid; /* tuple has security id in its header */ - int tdrefcount; /* reference count, or -1 if not counting */ - } *TupleDesc; - - --extern TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid); -+extern TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid, bool hassecid); - --extern TupleDesc CreateTupleDesc(int natts, bool hasoid, -+extern TupleDesc CreateTupleDesc(int natts, bool hasoid, bool hassecid, - Form_pg_attribute *attrs); - - extern TupleDesc CreateTupleDescCopy(TupleDesc tupdesc); -diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h -index 5e989ef..c3ed1d5 100644 ---- a/src/include/bootstrap/bootstrap.h -+++ b/src/include/bootstrap/bootstrap.h -@@ -24,6 +24,7 @@ typedef enum - BgWriterProcess, - WalWriterProcess, - WalReceiverProcess, -+ SecurityWorkerProcess, - - NUM_AUXPROCTYPES /* Must be last! */ - } AuxProcType; -diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h -index 557c311..162ad1c 100644 ---- a/src/include/catalog/heap.h -+++ b/src/include/catalog/heap.h -@@ -61,7 +61,8 @@ extern Oid heap_create_with_catalog(const char *relname, - OnCommitAction oncommit, - Datum reloptions, - bool use_user_acl, -- bool allow_system_table_mods); -+ bool allow_system_table_mods, -+ Oid *secLabels); - - extern void heap_drop_with_catalog(Oid relid); - -@@ -75,13 +76,15 @@ extern List *heap_truncate_find_FKs(List *relationIds); - - extern void InsertPgAttributeTuple(Relation pg_attribute_rel, - Form_pg_attribute new_attribute, -- CatalogIndexState indstate); -+ CatalogIndexState indstate, -+ Oid securityId); - - extern void InsertPgClassTuple(Relation pg_class_desc, - Relation new_rel_desc, - Oid new_rel_oid, - Datum relacl, -- Datum reloptions); -+ Datum reloptions, -+ Oid securityId); - - extern List *AddRelationNewConstraints(Relation rel, - List *newColDefaults, -@@ -106,10 +109,13 @@ extern void RemoveAttrDefaultById(Oid attrdefId); - extern void RemoveStatistics(Oid relid, AttrNumber attnum); - - extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, -- bool relhasoids); -+ bool relhasoids, bool relhassecids); - - extern Form_pg_attribute SystemAttributeByName(const char *attname, -- bool relhasoids); -+ bool relhasoids, bool relhassecids); -+ -+extern bool SystemAttributeWritable(AttrNumber attno, -+ bool relhasoids, bool relhassecids); - - extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, - bool allow_system_table_mods); -diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h -index 752a35e..a3da55e 100644 ---- a/src/include/catalog/indexing.h -+++ b/src/include/catalog/indexing.h -@@ -255,6 +255,11 @@ DECLARE_UNIQUE_INDEX(pg_type_oid_index, 2703, on pg_type using btree(oid oid_ops - DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index, 2704, on pg_type using btree(typname name_ops, typnamespace oid_ops)); - #define TypeNameNspIndexId 2704 - -+DECLARE_UNIQUE_INDEX(pg_seclabel_secid_index, 3401, on pg_seclabel using btree(secid oid_ops, datid oid_ops, relid oid_ops)); -+#define SecLabelSecidIndexId 3401 -+DECLARE_INDEX(pg_seclabel_label_index, 3402, on pg_seclabel using btree(datid oid_ops, relid oid_ops, label text_ops)); -+#define SecLabelLabelIndexId 3402 -+ - DECLARE_UNIQUE_INDEX(pg_foreign_data_wrapper_oid_index, 112, on pg_foreign_data_wrapper using btree(oid oid_ops)); - #define ForeignDataWrapperOidIndexId 112 - -diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h -index 2296fa2..4a412aa 100644 ---- a/src/include/catalog/pg_class.h -+++ b/src/include/catalog/pg_class.h -@@ -60,6 +60,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO - */ - int2 relchecks; /* # of CHECK constraints for class */ - bool relhasoids; /* T if we generate OIDs for rows of rel */ -+ bool relhassecids; /* T if we generate SIDs for rows of rel */ - bool relhaspkey; /* has (or has had) PRIMARY KEY index */ - bool relhasexclusion; /* has (or has had) exclusion constraint */ - bool relhasrules; /* has (or has had) any rules */ -@@ -93,7 +94,7 @@ typedef FormData_pg_class *Form_pg_class; - * ---------------- - */ - --#define Natts_pg_class 27 -+#define Natts_pg_class 28 - #define Anum_pg_class_relname 1 - #define Anum_pg_class_relnamespace 2 - #define Anum_pg_class_reltype 3 -@@ -113,14 +114,15 @@ typedef FormData_pg_class *Form_pg_class; - #define Anum_pg_class_relnatts 17 - #define Anum_pg_class_relchecks 18 - #define Anum_pg_class_relhasoids 19 --#define Anum_pg_class_relhaspkey 20 --#define Anum_pg_class_relhasexclusion 21 --#define Anum_pg_class_relhasrules 22 --#define Anum_pg_class_relhastriggers 23 --#define Anum_pg_class_relhassubclass 24 --#define Anum_pg_class_relfrozenxid 25 --#define Anum_pg_class_relacl 26 --#define Anum_pg_class_reloptions 27 -+#define Anum_pg_class_relhassecids 20 -+#define Anum_pg_class_relhaspkey 21 -+#define Anum_pg_class_relhasexclusion 22 -+#define Anum_pg_class_relhasrules 23 -+#define Anum_pg_class_relhastriggers 24 -+#define Anum_pg_class_relhassubclass 25 -+#define Anum_pg_class_relfrozenxid 26 -+#define Anum_pg_class_relacl 27 -+#define Anum_pg_class_reloptions 28 - - /* ---------------- - * initial contents of pg_class -@@ -132,13 +134,13 @@ typedef FormData_pg_class *Form_pg_class; - */ - - /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ --DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f f r 28 0 t f f f f f 3 _null_ _null_ )); -+DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f f r 28 0 t t f f f f f 3 _null_ _null_ )); - DESCR(""); --DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f f r 19 0 f f f f f f 3 _null_ _null_ )); -+DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f f r 19 0 f t f f f f f 3 _null_ _null_ )); - DESCR(""); --DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f f r 25 0 t f f f f f 3 _null_ _null_ )); -+DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f f r 25 0 t t f f f f f 3 _null_ _null_ )); - DESCR(""); --DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f f r 27 0 t f f f f f 3 _null_ _null_ )); -+DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f f r 28 0 t t f f f f f 3 _null_ _null_ )); - DESCR(""); - - #define RELKIND_INDEX 'i' /* secondary index */ -diff --git a/src/include/catalog/pg_conversion_fn.h b/src/include/catalog/pg_conversion_fn.h -index 3086936..47f49e2 100644 ---- a/src/include/catalog/pg_conversion_fn.h -+++ b/src/include/catalog/pg_conversion_fn.h -@@ -17,7 +17,7 @@ - extern Oid ConversionCreate(const char *conname, Oid connamespace, - Oid conowner, - int32 conforencoding, int32 contoencoding, -- Oid conproc, bool def); -+ Oid conproc, bool def, Oid securityId); - extern void RemoveConversionById(Oid conversionOid); - extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding); - -diff --git a/src/include/catalog/pg_largeobject.h b/src/include/catalog/pg_largeobject.h -index 78b3119..cf43db1 100644 ---- a/src/include/catalog/pg_largeobject.h -+++ b/src/include/catalog/pg_largeobject.h -@@ -51,9 +51,10 @@ typedef FormData_pg_largeobject *Form_pg_largeobject; - #define Anum_pg_largeobject_pageno 2 - #define Anum_pg_largeobject_data 3 - --extern Oid LargeObjectCreate(Oid loid); -+extern Oid LargeObjectCreate(Oid loid, Oid securityId); - extern void LargeObjectDrop(Oid loid); - extern void LargeObjectAlterOwner(Oid loid, Oid newOwnerId); -+extern void LargeObjectAlterSecLabel(Oid loid, char *new_label); - extern bool LargeObjectExists(Oid loid); - - #endif /* PG_LARGEOBJECT_H */ -diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h -index cc576a5..eeb1079 100644 ---- a/src/include/catalog/pg_namespace.h -+++ b/src/include/catalog/pg_namespace.h -@@ -77,6 +77,6 @@ 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, Oid secid); - - #endif /* PG_NAMESPACE_H */ -diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h -index 31a9650..254e19b 100644 ---- a/src/include/catalog/pg_proc.h -+++ b/src/include/catalog/pg_proc.h -@@ -3715,6 +3715,10 @@ DESCR("current user privilege on role by role name"); - DATA(insert OID = 2710 ( pg_has_role PGNSP PGUID 12 1 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ pg_has_role_id _null_ _null_ _null_ )); - DESCR("current user privilege on role by role oid"); - -+/* SE-PostgreSQL related stuff */ -+DATA(insert OID = 3405 ( seclabel_to_secid PGNSP PGUID 12 1 0 0 f f f t f v 1 0 26 "2249" _null_ _null_ _null_ _null_ seclabel_to_secid _null_ _null_ _null_ )); -+DATA(insert OID = 3407 ( sepgsql_getcon PGNSP PGUID 12 1 0 0 f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ sepgsql_getcon _null_ _null_ _null_)); -+ - DATA(insert OID = 1269 ( pg_column_size PGNSP PGUID 12 1 0 0 f f f t f s 1 0 23 "2276" _null_ _null_ _null_ _null_ pg_column_size _null_ _null_ _null_ )); - DESCR("bytes required to store the value, perhaps with compression"); - DATA(insert OID = 2322 ( pg_tablespace_size PGNSP PGUID 12 1 0 0 f f f t f v 1 0 20 "26" _null_ _null_ _null_ _null_ pg_tablespace_size_oid _null_ _null_ _null_ )); -diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h -index 0cb82b0..44ee57b 100644 ---- a/src/include/catalog/pg_proc_fn.h -+++ b/src/include/catalog/pg_proc_fn.h -@@ -37,7 +37,8 @@ extern Oid ProcedureCreate(const char *procedureName, - List *parameterDefaults, - Datum proconfig, - float4 procost, -- float4 prorows); -+ float4 prorows, -+ Oid prosecid); - - extern bool function_parse_error_transpose(const char *prosrc); - -diff --git a/src/include/catalog/pg_seclabel.h b/src/include/catalog/pg_seclabel.h -new file mode 100644 -index 0000000..21b25de ---- /dev/null -+++ b/src/include/catalog/pg_seclabel.h -@@ -0,0 +1,79 @@ -+/* -+ * pg_seclabel.h -+ * Definition of the security label relation (pg_seclabel) -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#ifndef PG_SECLABEL_H -+#define PG_SECLABEL_H -+ -+#include "catalog/genbki.h" -+ -+#include "access/htup.h" -+#include "access/skey.h" -+#include "utils/relcache.h" -+ -+#define SecLabelRelationId 3400 -+ -+CATALOG(pg_seclabel,3400) BKI_SHARED_RELATION BKI_WITHOUT_OIDS -+{ -+ /* Identifier of the security label */ -+ Oid secid; -+ -+ /* OID of the database which referes the entry */ -+ Oid datid; -+ -+ /* OID of the table which refers the entry */ -+ Oid relid; -+ -+ /* Text representation of the security label */ -+ text label; -+} FormData_pg_seclabel; -+ -+/* -+ * Form_pg_seclabel corresponds to a pointer to a tuple with -+ * the format of pg_seclabel relation. -+ */ -+typedef FormData_pg_seclabel *Form_pg_seclabel; -+ -+/* -+ * Compiler constants for pg_seclabel -+ */ -+#define Natts_pg_seclabel 4 -+#define Anum_pg_seclabel_secid 1 -+#define Anum_pg_seclabel_datid 2 -+#define Anum_pg_seclabel_relid 3 -+#define Anum_pg_seclabel_label 4 -+ -+/* -+ * Functions to translate between security label and identifier -+ */ -+extern bool ignore_security_label_input; -+ -+extern bool seclabelCatalogHasSysAttr(Oid relOid); -+extern void seclabelPostBootstrap(void); -+extern void seclabelOnCreateDatabase(Oid src_datOid, Oid dst_datOid); -+extern void seclabelOnDropDatabase(Oid datOid); -+extern void seclabelOnDropTable(Oid relOid); -+ -+extern Oid *seclabelMakeRelationDefaults(TupleDesc tupdesc, List *supOids); -+extern Oid *seclabelMakeToastDefaults(TupleDesc tupdesc, Oid relOid); -+ -+extern Oid seclabelGetNewSecid(Relation rel, HeapTuple tuple); -+ -+extern Oid seclabelRawInput(Oid relOid, char *seclabel); -+extern char *seclabelRawOutput(Oid relOid, Oid secid); -+extern Oid seclabelTransInput(Oid relOid, char *seclabel); -+extern char *seclabelTransOutput(Oid relOid, Oid secid); -+ -+extern Oid seclabelMoveSecid(Oid dst_relid, Oid src_relid, Oid secid); -+extern bool seclabelCompareSecid(Oid relid1, Oid secid1, -+ Oid relid2, Oid secid2); -+ -+extern Datum seclabelSysattOutput(Oid relOid, HeapTuple tuple); -+ -+extern void seclabelRelationReclaim(Oid relOid); -+extern Datum seclabel_to_secid(PG_FUNCTION_ARGS); -+ -+#endif /* PG_SECLABEL_H */ -diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h -index baf3012..c344bf8 100644 ---- a/src/include/catalog/pg_type_fn.h -+++ b/src/include/catalog/pg_type_fn.h -@@ -50,7 +50,8 @@ extern Oid TypeCreate(Oid newTypeOid, - char storage, - int32 typeMod, - int32 typNDims, -- bool typeNotNull); -+ bool typeNotNull, -+ Oid securityId); - - extern void GenerateTypeDependencies(Oid typeNamespace, - Oid typeObjectId, -diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h -index 056fd19..e99dea7 100644 ---- a/src/include/catalog/toasting.h -+++ b/src/include/catalog/toasting.h -@@ -58,5 +58,8 @@ DECLARE_TOAST(pg_shdescription, 2846, 2847); - DECLARE_TOAST(pg_db_role_setting, 2966, 2967); - #define PgDbRoleSettingToastTable 2966 - #define PgDbRoleSettingToastIndex 2967 -+DECLARE_TOAST(pg_seclabel, 3403, 3404); -+#define PgSecLabelToastTable 3403 -+#define PgSecLabelToastIndex 3404 - - #endif /* TOASTING_H */ -diff --git a/src/include/commands/alter.h b/src/include/commands/alter.h -index 83e735a..37b772e 100644 ---- a/src/include/commands/alter.h -+++ b/src/include/commands/alter.h -@@ -19,5 +19,6 @@ - extern void ExecRenameStmt(RenameStmt *stmt); - extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt); - extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt); -+extern void ExecAlterSecLabelStmt(AlterSecLabelStmt *stmt); - - #endif /* ALTER_H */ -diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h -index f150da3..c085321 100644 ---- a/src/include/commands/dbcommands.h -+++ b/src/include/commands/dbcommands.h -@@ -58,6 +58,7 @@ extern void RenameDatabase(const char *oldname, const char *newname); - extern void AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel); - extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt); - extern void AlterDatabaseOwner(const char *dbname, Oid newOwnerId); -+extern void AlterDatabaseSecLabel(const char *dbname, char *new_label); - - extern Oid get_database_oid(const char *dbname); - extern char *get_database_name(Oid dbid); -diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h -index cd5be6e..9a71ae4 100644 ---- a/src/include/commands/defrem.h -+++ b/src/include/commands/defrem.h -@@ -60,6 +60,8 @@ extern void SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType); - extern void RenameFunction(List *name, List *argtypes, const char *newname); - extern void AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId); - extern void AlterFunctionOwner_oid(Oid procOid, Oid newOwnerId); -+extern void AlterFunctionSecLabel(List *name, List *argtypes, -+ bool isagg, char *new_label); - extern void AlterFunction(AlterFunctionStmt *stmt); - extern void CreateCast(CreateCastStmt *stmt); - extern void DropCast(DropCastStmt *stmt); -diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h -index 62562fa..d122106 100644 ---- a/src/include/commands/schemacmds.h -+++ b/src/include/commands/schemacmds.h -@@ -26,5 +26,6 @@ extern void RemoveSchemaById(Oid schemaOid); - extern void RenameSchema(const char *oldname, const char *newname); - extern void AlterSchemaOwner(const char *name, Oid newOwnerId); - extern void AlterSchemaOwner_oid(Oid schemaOid, Oid newOwnerId); -+extern void AlterSchemaSecLabel(const char *name, char *new_label); - - #endif /* SCHEMACMDS_H */ -diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h -index c1774a2..cc6b11a 100644 ---- a/src/include/commands/tablecmds.h -+++ b/src/include/commands/tablecmds.h -@@ -35,6 +35,13 @@ extern void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, - Oid oldNspOid, Oid newNspOid, - bool hasDependEntry); - -+extern void AlterRelationSecLabel(RangeVar *relation, const char *attname, -+ ObjectType objtype, char *new_label); -+extern void AlterRelationSecLabelInternal(Oid relOid, Oid securityId, -+ int expected_parents); -+extern void AlterAttributeSecLabelInternal(Oid relOid, const char *attname, -+ Oid securityId, int expected_parents); -+ - extern void CheckTableNotInUse(Relation rel, const char *stmt); - - extern void ExecuteTruncate(TruncateStmt *stmt); -diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h -index 3d46eeb..71fa5d2 100644 ---- a/src/include/commands/tablespace.h -+++ b/src/include/commands/tablespace.h -@@ -44,6 +44,7 @@ extern void DropTableSpace(DropTableSpaceStmt *stmt); - extern void RenameTableSpace(const char *oldname, const char *newname); - extern void AlterTableSpaceOwner(const char *name, Oid newOwnerId); - extern void AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt); -+extern void AlterTableSpaceSecLabel(const char *tspaceName, char *newLabel); - - extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo); - -diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h -index 4dc2d4f..e50a83f 100644 ---- a/src/include/commands/typecmds.h -+++ b/src/include/commands/typecmds.h -@@ -43,5 +43,7 @@ extern void AlterTypeNamespace(List *names, const char *newschema); - extern void AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, - bool isImplicitArray, - bool errorOnTableType); -+extern void AlterTypeSecLabel(List *name, char *new_label); -+extern void AlterTypeSecLabelInternal(Oid typeOid, Oid securityId); - - #endif /* TYPECMDS_H */ -diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h -index 13b6aa5..0350a17 100644 ---- a/src/include/executor/executor.h -+++ b/src/include/executor/executor.h -@@ -131,8 +131,8 @@ extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable, - /* - * prototypes from functions in execJunk.c - */ --extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid, -- TupleTableSlot *slot); -+extern JunkFilter *ExecInitJunkFilter(List *targetList, -+ bool hasoid, bool hassecid, TupleTableSlot *slot); - extern JunkFilter *ExecInitJunkFilterConversion(List *targetList, - TupleDesc cleanTupType, - TupleTableSlot *slot); -@@ -166,6 +166,7 @@ extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, - int instrument_options); - extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid); - extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids); -+extern bool ExecContextForcesSecids(PlanState *planstate, bool *hassecid); - extern void ExecConstraints(ResultRelInfo *resultRelInfo, - TupleTableSlot *slot, EState *estate); - extern ExecRowMark *ExecFindRowMark(EState *estate, Index rti); -@@ -238,8 +239,8 @@ extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate); - extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate); - extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, - TupleDesc tupType); --extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid); --extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid); -+extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid, bool hassecid); -+extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hassecid); - extern TupleDesc ExecTypeFromExprList(List *exprList); - extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg); - -diff --git a/src/include/fmgr.h b/src/include/fmgr.h -index e588bb1..1298e3e 100644 ---- a/src/include/fmgr.h -+++ b/src/include/fmgr.h -@@ -51,6 +51,7 @@ typedef struct FmgrInfo - bool fn_retset; /* function returns a set */ - unsigned char fn_stats; /* collect stats if track_functions > this */ - void *fn_extra; /* extra space for use by handler */ -+ char *fn_seclabel; /* function is trusted procedure, or NULL */ - MemoryContext fn_mcxt; /* memory context to store fn_extra in */ - fmNodePtr fn_expr; /* expression parse tree for call, or NULL */ - } FmgrInfo; -diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h -index 401b69e..4e2c59d 100644 ---- a/src/include/nodes/nodes.h -+++ b/src/include/nodes/nodes.h -@@ -346,6 +346,7 @@ typedef enum NodeTag - T_AlterUserMappingStmt, - T_DropUserMappingStmt, - T_AlterTableSpaceOptionsStmt, -+ T_AlterSecLabelStmt, - - /* - * TAGS FOR PARSE TREE NODES (parsenodes.h) -diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h -index 54eebbc..94d0969 100644 ---- a/src/include/nodes/parsenodes.h -+++ b/src/include/nodes/parsenodes.h -@@ -731,6 +731,7 @@ typedef struct RangeTblEntry - Oid checkAsUser; /* if valid, check access as this role */ - Bitmapset *selectedCols; /* columns needing SELECT permission */ - Bitmapset *modifiedCols; /* columns needing INSERT/UPDATE permission */ -+ uint32 rowlvPerms; /* permissions for row-level access controls */ - } RangeTblEntry; - - /* -@@ -1134,6 +1135,8 @@ typedef enum AlterTableType - AT_DropCluster, /* SET WITHOUT CLUSTER */ - AT_AddOids, /* SET WITH OIDS */ - AT_DropOids, /* SET WITHOUT OIDS */ -+ AT_AddSecLabel, /* SET WITH SECURITY LABEL */ -+ AT_DropSecLabel, /* SET WITHOUT SECURITY LABEL */ - AT_SetTableSpace, /* SET TABLESPACE */ - AT_SetRelOptions, /* SET (...) -- AM specific parameters */ - AT_ResetRelOptions, /* RESET (...) -- AM specific parameters */ -@@ -2074,6 +2077,20 @@ typedef struct AlterOwnerStmt - char *newowner; /* the new owner */ - } AlterOwnerStmt; - -+/* ---------------------- -+ * Alter Security Label Statement -+ * ---------------------- -+ */ -+typedef struct AlterSecLabelStmt -+{ -+ NodeTag type; -+ ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */ -+ RangeVar *relation; /* in case it's a table */ -+ List *object; /* in case it's some other object */ -+ List *objarg; /* argument types, if applicable */ -+ char *addname; /* additional name if needed */ -+ Value *secLabel; /* the new security label */ -+} AlterSecLabelStmt; - - /* ---------------------- - * Create Rule Statement -diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h -index ad835d9..71595e3 100644 ---- a/src/include/parser/kwlist.h -+++ b/src/include/parser/kwlist.h -@@ -208,6 +208,7 @@ PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD) - PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD) - PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD) - PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD) -+PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD) - PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD) - PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD) - PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD) -diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in -index fd169b6..4dd3ca7 100644 ---- a/src/include/pg_config.h.in -+++ b/src/include/pg_config.h.in -@@ -418,6 +418,9 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_SECURITY_PAM_APPL_H - -+/* Define to 1 if you enable SELinux support */ -+#undef HAVE_SELINUX -+ - /* Define to 1 if you have the `setproctitle' function. */ - #undef HAVE_SETPROCTITLE - -diff --git a/src/include/sepgsql/hooks.h b/src/include/sepgsql/hooks.h -new file mode 100644 -index 0000000..b929e6d ---- /dev/null -+++ b/src/include/sepgsql/hooks.h -@@ -0,0 +1,293 @@ -+/* -+ * sepgsql/hooks.h -+ * -+ * Header of SE-PostgreSQL Hooks -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#ifndef SEPGSQL_HOOKS_H -+#define SEPGSQL_HOOKS_H -+ -+#include "executor/tuptable.h" -+#include "nodes/plannodes.h" -+#include "nodes/relation.h" -+#include "storage/fd.h" -+#include "utils/acl.h" -+#include "utils/rel.h" -+#include "utils/snapshot.h" -+ -+/* -+ * misc.c -+ */ -+extern char *sepgsql_get_client_label(void); -+extern char *sepgsql_set_client_label(char *new_label); -+extern void sepgsql_post_bootstraping(void); -+extern void sepgsql_initialize(void); -+extern bool sepgsql_worker_needed(void); -+extern void sepgsql_worker_main(void); -+ -+extern Datum sepgsql_getcon(PG_FUNCTION_ARGS); -+ -+/* -+ * database.c -+ */ -+extern Oid sepgsql_database_create(const char *datName, Oid templateOid); -+extern void sepgsql_database_alter(Oid databaseOid); -+extern Oid sepgsql_database_relabel(Oid databaseOid, char *new_label); -+extern void sepgsql_database_drop(Oid databaseOid, bool cascade); -+extern void sepgsql_database_grant(Oid databaseOid); -+extern void sepgsql_database_comment(Oid databaseOid); -+extern void sepgsql_database_connect(Oid databaseOid); -+extern void sepgsql_database_reindex(Oid databaseOid); -+extern void sepgsql_database_getattr(Oid databaseOid); -+ -+/* -+ * schema.c -+ */ -+extern Oid sepgsql_schema_create(const char *nspName, bool is_temp); -+extern void sepgsql_schema_alter(Oid namespaceOid); -+extern Oid sepgsql_schema_relabel(Oid namespaceOid, char *new_label); -+extern void sepgsql_schema_drop(Oid namespaceOid, bool cascade); -+extern void sepgsql_schema_grant(Oid namespaceOid); -+extern bool sepgsql_schema_search(Oid namespaceOid, bool abort); -+extern void sepgsql_schema_comment(Oid namespaceOid); -+ -+/* -+ * relation.c -+ */ -+extern bool sepgsql_relation_perms(Oid relOid, AclMode aclmask, -+ Bitmapset *selectedCols, -+ Bitmapset *modifiedCols, bool abort); -+extern Oid *sepgsql_relation_create(const char *relName, -+ char relkind, -+ TupleDesc tupDesc, -+ Oid namespaceId, -+ List *supOids, -+ bool createAs); -+extern void sepgsql_relation_alter(Oid relationOid); -+extern void sepgsql_relation_alter_schema(Oid relationOid, Oid newSchema); -+extern void sepgsql_relation_alter_rename(Oid relationOid, -+ const char *newName); -+extern void sepgsql_relation_alter_inherit(Oid childOid, Oid parentOid); -+extern Oid sepgsql_relation_relabel(Oid relationOid, char *new_label); -+extern void sepgsql_relation_drop(Oid relationOid, bool cascade); -+extern void sepgsql_relation_getattr(Oid relationOid); -+extern void sepgsql_relation_grant(Oid relationOid); -+extern void sepgsql_relation_comment(Oid relationOid); -+extern bool sepgsql_relation_cluster(Oid relationOid, bool abort); -+extern void sepgsql_relation_truncate(Relation rel); -+extern void sepgsql_relation_lock(Relation rel); -+extern void sepgsql_relation_reindex(Oid relOid); -+extern void sepgsql_view_replace(Oid viewOid); -+extern void sepgsql_index_create(Oid relationOid, Oid namespaceOid); -+extern void sepgsql_index_reindex(Oid indexOid); -+extern void sepgsql_sequence_get_value(Oid sequenceOid); -+extern void sepgsql_sequence_next_value(Oid sequenceOid); -+extern void sepgsql_sequence_set_value(Oid sequenceOid); -+extern void sepgsql_rule_create(Oid relationOid, -+ const char *ruleName); -+extern void sepgsql_rule_drop(Oid relationOid, -+ const char *ruleName, bool cascade); -+extern void sepgsql_rule_comment(Oid relationOid, const char *ruleName); -+extern void sepgsql_trigger_create(Oid relationOid, const char *triggerName, -+ Oid constrrelid, Oid funcOid); -+extern void sepgsql_trigger_alter(Oid relOid, const char *tgName); -+extern void sepgsql_trigger_drop(Oid relOid, const char *tgName, bool cascade); -+extern void sepgsql_trigger_comment(Oid relOid, const char *tgName); -+extern void sepgsql_constraint_comment(Oid relOid, const char *constName); -+ -+/* -+ * attribute.c -+ */ -+extern Oid sepgsql_attribute_create(Oid relOid, const char *attName); -+extern void sepgsql_attribute_alter(Oid relOid, const char *attName); -+extern Oid sepgsql_attribute_relabel(Oid relOid, const char *attName, -+ char *new_label); -+extern void sepgsql_attribute_drop(Oid relOid, const char *attName, bool cascade); -+extern void sepgsql_attribute_grant(Oid relOid, AttrNumber attnum); -+extern void sepgsql_attribute_comment(Oid relOid, AttrNumber attnum); -+ -+/* -+ * proc.c -+ */ -+extern Oid sepgsql_proc_create(const char *proName, Oid replaced, -+ Oid namespaceOid, Oid langageOid); -+extern void sepgsql_proc_alter(Oid procOid); -+extern void sepgsql_proc_alter_rename(Oid procOid, const char *newName); -+extern void sepgsql_proc_alter_schema(Oid procOid, Oid newSchema); -+extern Oid sepgsql_proc_relabel(Oid procOid, char *new_label); -+extern void sepgsql_proc_drop(Oid procOid, bool cascade); -+extern void sepgsql_proc_grant(Oid procOid); -+extern void sepgsql_proc_comment(Oid procOid); -+extern void sepgsql_proc_execute(Oid procOid); -+extern bool sepgsql_proc_be_inlined(HeapTuple protup); -+extern char *sepgsql_proc_domtrans(HeapTuple protup, MemoryContext mcxt); -+extern Oid sepgsql_aggregate_create(const char *aggName, Oid namespaceId, -+ Oid transFunc, Oid finalFunc); -+extern void sepgsql_aggregate_execute(Oid aggOid); -+ -+/* -+ * type.c -+ */ -+extern Oid sepgsql_type_create(const char *typeName, Oid replaced, -+ Oid namespaceId, char typeType, -+ Oid inputFunc, Oid outputFunc, -+ Oid recvFunc, Oid sendFunc, -+ Oid modinFunc, Oid modoutFunc, -+ Oid analyzeFunc); -+extern void sepgsql_type_alter(Oid typeOid); -+extern void sepgsql_type_alter_rename(Oid typeOid, const char *newName); -+extern void sepgsql_type_alter_schema(Oid typeOid, Oid newSchema); -+extern Oid sepgsql_type_relabel(Oid typeOid, char *newLabel); -+extern void sepgsql_type_drop(Oid typeOid, bool cascade); -+extern void sepgsql_type_comment(Oid typeOid); -+extern Oid sepgsql_cast_create(Oid sourceTypeOid, Oid targetTypeOid, -+ char castMethod, Oid castFuncOid); -+extern void sepgsql_cast_drop(Oid srcTypeOid, Oid dstTypeOid, bool cascade); -+extern void sepgsql_cast_comment(Oid srcTypeOid, Oid dstTypeOid); -+ -+/* -+ * tablespace.h -+ */ -+extern Oid sepgsql_tablespace_create(const char *tablespaceName); -+extern void sepgsql_tablespace_alter(Oid tablespaceOid); -+extern Oid sepgsql_tablespace_relabel(Oid tablespaceOid, char *newLabel); -+extern void sepgsql_tablespace_drop(Oid tablespaceOid, bool cascade); -+extern void sepgsql_tablespace_grant(Oid tablespaceOid); -+extern void sepgsql_tablespace_getattr(Oid tablespaceOid); -+extern void sepgsql_tablespace_comment(Oid tablespaceOid); -+ -+/* -+ * operator.h -+ */ -+extern Oid sepgsql_operator_create(const char *operName, Oid replaced, -+ Oid namespaceId, -+ Oid codeFn, Oid restrictFn, Oid joinFn, -+ Oid commutatorOp, Oid negatorOp); -+extern void sepgsql_operator_alter(Oid operOid); -+extern Oid sepgsql_operator_relabel(Oid operOid, char *newLabel); -+extern void sepgsql_operator_drop(Oid operOid, bool cascade); -+extern void sepgsql_operator_comment(Oid operOid); -+ -+extern Oid sepgsql_opclass_create(const char *opcName, Oid namespaceId, -+ Oid typeOid, Oid opfamilyOid, Oid storageOid); -+extern void sepgsql_opclass_alter(Oid opcOid); -+extern void sepgsql_opclass_alter_rename(Oid opcOid, const char *newName); -+extern void sepgsql_opclass_drop(Oid opcOid, bool cascade); -+extern void sepgsql_opclass_comment(Oid opcOid); -+ -+extern Oid sepgsql_opfamily_create(const char *opfName, -+ Oid namespaceId, Oid amOid); -+extern void sepgsql_opfamily_alter(Oid opfOid, bool isDrop, Oid amOid, -+ List *operators, List *procedures); -+extern void sepgsql_opfamily_alter_rename(Oid opfOid, const char *newName); -+extern void sepgsql_opfamily_alter_owner(Oid opfOid, Oid newOwner); -+extern void sepgsql_opfamily_drop(Oid opfOid, bool cascade); -+extern void sepgsql_opfamily_comment(Oid opfOid); -+ -+/* -+ * role.c -+ */ -+extern Oid sepgsql_role_create(const char *roleName); -+extern void sepgsql_role_alter(Oid roleOid); -+extern Oid sepgsql_role_relabel(Oid roleOid, char *newLabel); -+extern void sepgsql_role_drop(Oid roleOid, bool cascade); -+extern void sepgsql_role_grant(Oid roleOid, bool is_grant, List *memberIds); -+extern void sepgsql_role_comment(Oid roleOid); -+ -+/* -+ * blob.c -+ */ -+extern Oid sepgsql_largeobject_create(Oid loid); -+extern void sepgsql_largeobject_alter(Oid loid); -+extern Oid sepgsql_largeobject_relabel(Oid loid, char *newLabel); -+extern void sepgsql_largeobject_drop(Oid loid, bool cascade); -+extern void sepgsql_largeobject_read(Oid loid, Snapshot snapshot); -+extern void sepgsql_largeobject_write(Oid loid, Snapshot snapshot); -+extern Oid sepgsql_largeobject_import(Oid loid, const char *filename); -+extern void sepgsql_largeobject_export(Oid loid, Snapshot snapshot, -+ const char *filename); -+extern void sepgsql_largeobject_grant(Oid loid); -+extern void sepgsql_largeobject_comment(Oid loid); -+ -+/* -+ * conversion.c -+ */ -+extern Oid sepgsql_conversion_create(const char *convName, -+ Oid namespaceId, Oid conversionFunc); -+extern void sepgsql_conversion_alter(Oid convOid); -+extern void sepgsql_conversion_alter_rename(Oid convOid, const char *newName); -+extern void sepgsql_conversion_drop(Oid convOid, bool cascade); -+extern void sepgsql_conversion_comment(Oid convOid); -+ -+/* -+ * tsearch.c -+ */ -+extern Oid sepgsql_ts_config_create(const char *confName, Oid namespaceId); -+extern void sepgsql_ts_config_alter(Oid confOid); -+extern void sepgsql_ts_config_alter_rename(Oid confOid, const char *newName); -+extern void sepgsql_ts_config_drop(Oid confOid, bool cascade); -+extern void sepgsql_ts_config_comment(Oid confOid); -+extern Oid sepgsql_ts_dict_create(const char *dictName, Oid namespaceId); -+extern void sepgsql_ts_dict_alter(Oid dictOid); -+extern void sepgsql_ts_dict_alter_rename(Oid dictOid, const char *newName); -+extern void sepgsql_ts_dict_drop(Oid dictOid, bool cascade); -+extern void sepgsql_ts_dict_comment(Oid dictOid); -+extern Oid sepgsql_ts_parser_create(const char *parseName, Oid namespaceId, -+ Oid startFunc, Oid tokenFunc, Oid endFunc, -+ Oid headlineFunc, Oid lextypeFunc); -+extern void sepgsql_ts_parser_alter_rename(Oid parseOid, const char *newName); -+extern void sepgsql_ts_parser_drop(Oid parseOid, bool cascade); -+extern void sepgsql_ts_parser_comment(Oid parseOid); -+extern Oid sepgsql_ts_template_create(const char *templateName, -+ Oid namespaceId, -+ Oid initFunc, Oid lexizeFunc); -+extern void sepgsql_ts_template_alter_rename(Oid templateOid, -+ const char *newName); -+extern void sepgsql_ts_template_drop(Oid templateOid, bool cascade); -+extern void sepgsql_ts_template_comment(Oid templateOid); -+ -+/* -+ * fdw.c -+ */ -+extern Oid sepgsql_fdw_create(const char *fdwName, Oid validatorFunc); -+extern void sepgsql_fdw_alter(Oid fdwOid, Oid newValidator); -+extern void sepgsql_fdw_drop(Oid fdwOid, bool cascade); -+extern void sepgsql_fdw_grant(Oid fdwOid); -+ -+extern Oid sepgsql_fserver_create(const char *fservName, Oid fdwOid); -+extern void sepgsql_fserver_alter(Oid fservOid); -+extern void sepgsql_fserver_drop(Oid fservOid, bool cascade); -+extern void sepgsql_fserver_grant(Oid fservOid); -+ -+extern Oid sepgsql_user_mapping_create(Oid mappedRoleId, Oid fservOid); -+extern void sepgsql_user_mapping_alter(Oid umapOid); -+extern void sepgsql_user_mapping_drop(Oid umapOid, bool cascade); -+ -+extern void sepgsql_file_getattr(const char *filename); -+extern void sepgsql_file_read(const char *filename); -+extern void sepgsql_file_write(const char *filename, bool may_create); -+extern void sepgsql_file_append(const char *filename); -+extern void sepgsql_file_unlink(const char *filename); -+extern void sepgsql_file_rename(const char *oldpath, const char *newpath); -+extern void sepgsql_dir_list(const char *dirname); -+ -+/* -+ * row-level access controls -+ */ -+#define SEPGSQL_ROWLV_FILTER 1 -+#define SEPGSQL_ROWLV_ABORT 2 -+#define SEPGSQL_ROWLV_BYPASS 3 -+ -+extern int sepgsql_rowlv_get_mode(void); -+extern int sepgsql_rowlv_set_mode(int new_mode); -+extern bool sepgsql_rowlv_quals(Relation rel, uint32 required, -+ TupleTableSlot *slot, bool abort); -+extern bool sepgsql_rowlv_copyto(Relation rel, HeapTuple tuple); -+extern uint32 sepgsql_rowlv_permissions(RangeTblEntry *rte); -+ -+extern void sepgsql_tuple_insert(Relation rel, HeapTuple tuple); -+extern void sepgsql_tuple_update(Relation rel, ItemPointer otid, HeapTuple newtup); -+ -+#endif /* SEPGSQL_HOOKS_H */ -diff --git a/src/include/sepgsql/sepgsql.h b/src/include/sepgsql/sepgsql.h -new file mode 100644 -index 0000000..5fd7195 ---- /dev/null -+++ b/src/include/sepgsql/sepgsql.h -@@ -0,0 +1,318 @@ -+/* -+ * sepgsql/sepgsql.h -+ * -+ * Header of SE-PostgreSQL Internal -+ * -+ * Copyright (C) 2006-2010, NEC Corporation -+ * KaiGai Kohei -+ */ -+#ifndef SEPGSQL_H -+#define SEPGSQL_H -+ -+#include "utils/snapshot.h" -+ -+/* GUC : sepostgresql */ -+extern int sepostgresql_mode; -+ -+#define SEPGSQL_MODE_DEFAULT 1 -+#define SEPGSQL_MODE_ENFORCING 2 -+#define SEPGSQL_MODE_PERMISSIVE 3 -+#define SEPGSQL_MODE_INTERNAL 4 -+#define SEPGSQL_MODE_DISABLED 5 -+ -+/* GUC: sepostgresql_mcstrans */ -+extern bool sepgsql_mcstrans; -+ -+/* GUC: sepostgresql_debug_audit */ -+extern bool sepgsql_debug_audit; -+ -+/* Objject classes and permissions internally used */ -+enum SepgsqlClasses -+{ -+ SEPG_CLASS_PROCESS = 0, -+ SEPG_CLASS_FILE, -+ SEPG_CLASS_DIR, -+ SEPG_CLASS_LNK_FILE, -+ SEPG_CLASS_CHR_FILE, -+ SEPG_CLASS_BLK_FILE, -+ SEPG_CLASS_SOCK_FILE, -+ SEPG_CLASS_FIFO_FILE, -+ SEPG_CLASS_DB_DATABASE, -+ SEPG_CLASS_DB_SCHEMA, -+ SEPG_CLASS_DB_TABLE, -+ SEPG_CLASS_DB_VIEW, -+ SEPG_CLASS_DB_SEQUENCE, -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_CLASS_DB_COLUMN, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_CLASS_DB_LANGUAGE, -+ SEPG_CLASS_MAX, -+}; -+ -+#define SEPG_PROCESS__TRANSITION (1<<0) -+ -+#define SEPG_FILE__READ (1<<0) -+#define SEPG_FILE__WRITE (1<<1) -+#define SEPG_FILE__CREATE (1<<2) -+#define SEPG_FILE__GETATTR (1<<3) -+#define SEPG_FILE__UNLINK (1<<4) -+#define SEPG_FILE__RENAME (1<<5) -+#define SEPG_FILE__APPEND (1<<6) -+ -+#define SEPG_DIR__READ (SEPG_FILE__READ) -+#define SEPG_DIR__WRITE (SEPG_FILE__WRITE) -+#define SEPG_DIR__CREATE (SEPG_FILE__CREATE) -+#define SEPG_DIR__GETATTR (SEPG_FILE__GETATTR) -+#define SEPG_DIR__UNLINK (SEPG_FILE__UNLINK) -+#define SEPG_DIR__RENAME (SEPG_FILE__RENAME) -+#define SEPG_DIR__SEARCH (1<<6) -+#define SEPG_DIR__ADD_NAME (1<<7) -+#define SEPG_DIR__REMOVE_NAME (1<<8) -+#define SEPG_DIR__RMDIR (1<<9) -+#define SEPG_DIR__REPARENT (1<<10) -+ -+#define SEPG_LNK_FILE__READ (SEPG_FILE__READ) -+#define SEPG_LNK_FILE__WRITE (SEPG_FILE__WRITE) -+#define SEPG_LNK_FILE__CREATE (SEPG_FILE__CREATE) -+#define SEPG_LNK_FILE__GETATTR (SEPG_FILE__GETATTR) -+#define SEPG_LNK_FILE__UNLINK (SEPG_FILE__UNLINK) -+#define SEPG_LNK_FILE__RENAME (SEPG_FILE__RENAME) -+ -+#define SEPG_CHR_FILE__READ (SEPG_FILE__READ) -+#define SEPG_CHR_FILE__WRITE (SEPG_FILE__WRITE) -+#define SEPG_CHR_FILE__CREATE (SEPG_FILE__CREATE) -+#define SEPG_CHR_FILE__GETATTR (SEPG_FILE__GETATTR) -+#define SEPG_CHR_FILE__UNLINK (SEPG_FILE__UNLINK) -+#define SEPG_CHR_FILE__RENAME (SEPG_FILE__RENAME) -+ -+#define SEPG_BLK_FILE__READ (SEPG_FILE__READ) -+#define SEPG_BLK_FILE__WRITE (SEPG_FILE__WRITE) -+#define SEPG_BLK_FILE__CREATE (SEPG_FILE__CREATE) -+#define SEPG_BLK_FILE__GETATTR (SEPG_FILE__GETATTR) -+#define SEPG_BLK_FILE__UNLINK (SEPG_FILE__UNLINK) -+#define SEPG_BLK_FILE__RENAME (SEPG_FILE__RENAME) -+ -+#define SEPG_SOCK_FILE__READ (SEPG_FILE__READ) -+#define SEPG_SOCK_FILE__WRITE (SEPG_FILE__WRITE) -+#define SEPG_SOCK_FILE__CREATE (SEPG_FILE__CREATE) -+#define SEPG_SOCK_FILE__GETATTR (SEPG_FILE__GETATTR) -+#define SEPG_SOCK_FILE__UNLINK (SEPG_FILE__UNLINK) -+#define SEPG_SOCK_FILE__RENAME (SEPG_FILE__RENAME) -+ -+#define SEPG_FIFO_FILE__READ (SEPG_FILE__READ) -+#define SEPG_FIFO_FILE__WRITE (SEPG_FILE__WRITE) -+#define SEPG_FIFO_FILE__CREATE (SEPG_FILE__CREATE) -+#define SEPG_FIFO_FILE__GETATTR (SEPG_FILE__GETATTR) -+#define SEPG_FIFO_FILE__UNLINK (SEPG_FILE__UNLINK) -+#define SEPG_FIFO_FILE__RENAME (SEPG_FILE__RENAME) -+ -+#define SEPG_DB_DATABASE__CREATE (1<<0) -+#define SEPG_DB_DATABASE__DROP (1<<1) -+#define SEPG_DB_DATABASE__GETATTR (1<<2) -+#define SEPG_DB_DATABASE__SETATTR (1<<3) -+#define SEPG_DB_DATABASE__RELABELFROM (1<<4) -+#define SEPG_DB_DATABASE__RELABELTO (1<<5) -+#define SEPG_DB_DATABASE__ACCESS (1<<6) -+#define SEPG_DB_DATABASE__LOAD_MODULE (1<<7) -+ -+#define SEPG_DB_SCHEMA__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_SCHEMA__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_SCHEMA__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_SCHEMA__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_SCHEMA__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_SCHEMA__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_SCHEMA__SEARCH (1<<6) -+#define SEPG_DB_SCHEMA__ADD_NAME (1<<7) -+#define SEPG_DB_SCHEMA__REMOVE_NAME (1<<8) -+ -+#define SEPG_DB_TABLE__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_TABLE__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_TABLE__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_TABLE__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_TABLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_TABLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_TABLE__SELECT (1<<6) -+#define SEPG_DB_TABLE__UPDATE (1<<7) -+#define SEPG_DB_TABLE__INSERT (1<<8) -+#define SEPG_DB_TABLE__DELETE (1<<9) -+#define SEPG_DB_TABLE__LOCK (1<<10) -+#define SEPG_DB_TABLE__INDEXON (1<<11) -+ -+#define SEPG_DB_SEQUENCE__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_SEQUENCE__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_SEQUENCE__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_SEQUENCE__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_SEQUENCE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_SEQUENCE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_SEQUENCE__GET_VALUE (1<<6) -+#define SEPG_DB_SEQUENCE__NEXT_VALUE (1<<7) -+#define SEPG_DB_SEQUENCE__SET_VALUE (1<<8) -+ -+#define SEPG_DB_VIEW__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_VIEW__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_VIEW__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_VIEW__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_VIEW__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_VIEW__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_VIEW__EXPAND (1<<6) -+ -+#define SEPG_DB_PROCEDURE__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_PROCEDURE__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_PROCEDURE__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_PROCEDURE__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_PROCEDURE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_PROCEDURE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_PROCEDURE__EXECUTE (1<<6) -+#define SEPG_DB_PROCEDURE__ENTRYPOINT (1<<7) -+#define SEPG_DB_PROCEDURE__INSTALL (1<<8) -+ -+#define SEPG_DB_COLUMN__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_COLUMN__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_COLUMN__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_COLUMN__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_COLUMN__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_COLUMN__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_COLUMN__SELECT (1<<6) -+#define SEPG_DB_COLUMN__UPDATE (1<<7) -+#define SEPG_DB_COLUMN__INSERT (1<<8) -+ -+#define SEPG_DB_TUPLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_TUPLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_TUPLE__SELECT (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_TUPLE__UPDATE (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_TUPLE__INSERT (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_TUPLE__DELETE (SEPG_DB_DATABASE__DROP) -+ -+#define SEPG_DB_BLOB__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_BLOB__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_BLOB__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_BLOB__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_BLOB__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_BLOB__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_BLOB__READ (1<<6) -+#define SEPG_DB_BLOB__WRITE (1<<7) -+#define SEPG_DB_BLOB__IMPORT (1<<8) -+#define SEPG_DB_BLOB__EXPORT (1<<9) -+ -+#define SEPG_DB_LANGUAGE__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_LANGUAGE__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_LANGUAGE__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_LANGUAGE__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_LANGUAGE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_LANGUAGE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_LANGUAGE__IMPLEMENTE (1<<6) -+#define SEPG_DB_LANGUAGE__EXECUTE (1<<7) -+ -+/* -+ * sepgsql_sid_t : alternative representation of security context -+ */ -+typedef struct { -+ Oid relid; -+ Oid secid; -+} sepgsql_sid_t; -+ -+struct av_decision; -+ -+/* -+ * selinux.c -+ */ -+extern bool sepgsql_is_enabled(void); -+extern bool sepgsql_get_enforce(void); -+extern const char *sepgsql_show_mode(void); -+ -+extern Size sepgsql_shmem_size(void); -+ -+extern void sepgsql_audit_log(bool denied, -+ char *scontext, -+ char *tcontext, -+ uint16 tclass, -+ uint32 audited, -+ const char *audit_name); -+extern void sepgsql_compute_avd(char *scontext, -+ char *tcontext, -+ uint16 tclass, -+ struct av_decision *avd); -+extern bool sepgsql_compute_perms(char *scontext, -+ char *tcontext, -+ uint16 tclass, -+ uint32 required, -+ const char *audit_name, -+ bool abort); -+extern char *sepgsql_compute_create(char *scontext, -+ char *tcontext, -+ uint16 tclass); -+extern bool sepgsql_client_perms(sepgsql_sid_t tsid, -+ uint16 tclass, -+ uint32 required, -+ const char *audit_name, -+ bool abort); -+extern sepgsql_sid_t sepgsql_client_create_secid(sepgsql_sid_t tsid, -+ uint16 tclass, -+ Oid nrelid); -+extern char *sepgsql_client_create_label(sepgsql_sid_t tsid, -+ uint16 tclass); -+extern void sepgsql_avc_worker_main(void); -+ -+/* -+ * avc.c -+ */ -+extern Size sepgsql_shmem_size(void); -+extern void sepgsql_avc_init(void); -+extern void sepgsql_avc_switch(const char *scontext); -+ -+ -+/* -+ * label.c -+ */ -+extern sepgsql_sid_t sepgsql_move_secid(Oid dst_relid, sepgsql_sid_t ssid); -+ -+extern sepgsql_sid_t sepgsql_get_default_database_secid(Oid templateOid); -+extern sepgsql_sid_t sepgsql_get_default_schema_secid(Oid databaseOid); -+extern sepgsql_sid_t sepgsql_get_default_table_secid(Oid namespaceOid); -+extern sepgsql_sid_t sepgsql_get_default_sequence_secid(Oid namespaceOid); -+extern sepgsql_sid_t sepgsql_get_default_view_secid(Oid namespaceOid); -+extern sepgsql_sid_t sepgsql_get_default_proc_secid(Oid namespaceOid); -+extern sepgsql_sid_t sepgsql_get_default_column_secid(Oid tableOid); -+extern sepgsql_sid_t sepgsql_get_default_tuple_secid(Oid tableOid); -+extern sepgsql_sid_t sepgsql_get_default_blob_secid(Oid databaseOid); -+extern Oid sepgsql_get_default_secid(Relation rel, HeapTuple tuple); -+ -+extern void sepgsql_initial_labeling(void); -+ -+extern char *sepgsql_mcstrans_out(char *label); -+extern char *sepgsql_mcstrans_in(char *label); -+extern char *sepgsql_rawlabel_out(char *label); -+extern char *sepgsql_rawlabel_in(char *label); -+ -+/* -+ * sepgsql_(object)_common -+ */ -+extern bool sepgsql_database_common(Oid datOid, uint32 required, bool abort); -+extern bool sepgsql_schema_common(Oid nspOid, uint32 required, bool abort); -+extern bool sepgsql_relation_common(Oid relOid, uint32 required, bool abort); -+extern bool sepgsql_attribute_common(Oid relOid, AttrNumber attno, -+ uint32 required, bool abort); -+extern bool sepgsql_proc_common(Oid procOid, uint32 required, bool abort); -+extern bool sepgsql_type_common(Oid typeOid, uint32 required, bool abort); -+extern bool sepgsql_cast_common(Oid srcTypeOid, Oid dstTypeOid, -+ uint32 required, bool abort); -+extern bool sepgsql_tablespace_common(Oid tspaceOid, uint32 required, bool abort); -+extern bool sepgsql_operator_common(Oid operOid, uint32 required, bool abort); -+extern bool sepgsql_opclass_common(Oid opcOid, uint32 required, bool abort); -+extern bool sepgsql_opfamily_common(Oid opfOid, uint32 required, bool abort); -+extern bool sepgsql_role_common(Oid roleOid, uint32 required, bool abort); -+extern bool sepgsql_largeobejct_common(Oid loid, Snapshot snapshot, -+ uint32 required, bool abort); -+extern bool sepgsql_conversion_common(Oid convOid, uint32 required, bool abort); -+extern bool sepgsql_largeobject_common(Oid loid, Snapshot snapshot, -+ uint32 required, bool abort); -+extern bool sepgsql_ts_config_common(Oid confOid, uint32 required, bool abort); -+extern bool sepgsql_ts_dict_common(Oid dictOid, uint32 required, bool abort); -+extern bool sepgsql_ts_parser_common(Oid parseOid, uint32 required, bool abort); -+extern bool sepgsql_ts_template_common(Oid templateOid, uint32 required, bool abort); -+extern bool sepgsql_fdw_common(Oid fdwOid, uint32 required, bool abort); -+extern bool sepgsql_fserver_common(Oid fservOid, uint32 required, bool abort); -+extern bool sepgsql_user_mapping_common(Oid umapOid, uint32 required, bool abort); -+ -+#endif /* SEPGSQL_H */ -diff --git a/src/include/storage/large_object.h b/src/include/storage/large_object.h -index b8de372..2bd6973 100644 ---- a/src/include/storage/large_object.h -+++ b/src/include/storage/large_object.h -@@ -70,7 +70,7 @@ typedef struct LargeObjectDesc - - /* inversion stuff in inv_api.c */ - extern void close_lo_relation(bool isCommit); --extern Oid inv_create(Oid lobjId); -+extern Oid inv_create(Oid lobjId, Oid securityId); - extern LargeObjectDesc *inv_open(Oid lobjId, int flags, MemoryContext mcxt); - extern void inv_close(LargeObjectDesc *obj_desc); - extern int inv_drop(Oid lobjId); -diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h -index 0322007..f807707 100644 ---- a/src/include/storage/lwlock.h -+++ b/src/include/storage/lwlock.h -@@ -70,6 +70,7 @@ typedef enum LWLockId - RelationMappingLock, - AsyncCtlLock, - AsyncQueueLock, -+ SepgsqlAvcLock, - /* Individual lock IDs end here */ - FirstBufMappingLock, - FirstLockMgrLock = FirstBufMappingLock + NUM_BUFFER_PARTITIONS, -diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h -index 9eb37b88..6165c4d 100644 ---- a/src/include/utils/guc.h -+++ b/src/include/utils/guc.h -@@ -166,6 +166,7 @@ extern bool log_btree_build_stats; - - extern PGDLLIMPORT bool check_function_bodies; - extern bool default_with_oids; -+extern bool default_with_secids; - extern bool SQL_inheritance; - - extern int log_min_error_statement; -diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h -index 9faefbe..90b7c94 100644 ---- a/src/include/utils/syscache.h -+++ b/src/include/utils/syscache.h -@@ -101,6 +101,8 @@ extern bool SearchSysCacheExists(int cacheId, - Datum key1, Datum key2, Datum key3, Datum key4); - extern Oid GetSysCacheOid(int cacheId, - Datum key1, Datum key2, Datum key3, Datum key4); -+extern Oid GetSysCacheSecid(int cacheId, -+ Datum key1, Datum key2, Datum key3, Datum key4); - - extern HeapTuple SearchSysCacheAttName(Oid relid, const char *attname); - extern HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname); -@@ -154,6 +156,15 @@ extern struct catclist *SearchSysCacheList(int cacheId, int nkeys, - #define GetSysCacheOid4(cacheId, key1, key2, key3, key4) \ - GetSysCacheOid(cacheId, key1, key2, key3, key4) - -+#define GetSysCacheSecid1(cacheId, key1) \ -+ GetSysCacheSecid(cacheId, key1, 0, 0, 0) -+#define GetSysCacheSecid2(cacheId, key1, key2) \ -+ GetSysCacheSecid(cacheId, key1, key2, 0, 0) -+#define GetSysCacheSecid3(cacheId, key1, key2, key3) \ -+ GetSysCacheSecid(cacheId, key1, key2, key3, 0) -+#define GetSysCacheSecid4(cacheId, key1, key2, key3, key4) \ -+ GetSysCacheSecid(cacheId, key1, key2, key3, key4) -+ - #define SearchSysCacheList1(cacheId, key1) \ - SearchSysCacheList(cacheId, 1, key1, 0, 0, 0) - #define SearchSysCacheList2(cacheId, key1, key2) \ -diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c -index 589d514..5370346 100644 ---- a/src/pl/plpgsql/src/pl_comp.c -+++ b/src/pl/plpgsql/src/pl_comp.c -@@ -1965,7 +1965,7 @@ build_row_from_vars(PLpgSQL_variable **vars, int numvars) - - row = palloc0(sizeof(PLpgSQL_row)); - row->dtype = PLPGSQL_DTYPE_ROW; -- row->rowtupdesc = CreateTemplateTupleDesc(numvars, false); -+ row->rowtupdesc = CreateTemplateTupleDesc(numvars, false, false); - row->nfields = numvars; - row->fieldnames = palloc(numvars * sizeof(char *)); - row->varnos = palloc(numvars * sizeof(int)); -diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out -index 1d9e110..9596b0b 100644 ---- a/src/test/regress/expected/sanity_check.out -+++ b/src/test/regress/expected/sanity_check.out -@@ -114,6 +114,7 @@ SELECT relname, relhasindex - pg_pltemplate | t - pg_proc | t - pg_rewrite | t -+ pg_seclabel | t - pg_shdepend | t - pg_shdescription | t - pg_statistic | t -@@ -153,7 +154,7 @@ SELECT relname, relhasindex - timetz_tbl | f - tinterval_tbl | f - varchar_tbl | f --(142 rows) -+(143 rows) - - -- - -- another sanity check: every system catalog that has OIDs should have diff --git a/sepostgresql-fedora-prefix.patch b/sepostgresql-fedora-prefix.patch deleted file mode 100644 index 98cd3b2..0000000 --- a/sepostgresql-fedora-prefix.patch +++ /dev/null @@ -1,105 +0,0 @@ -diff --git a/src/Makefile.global.in b/src/Makefile.global.in -index 0e3bed5..aee6064 100644 ---- a/src/Makefile.global.in -+++ b/src/Makefile.global.in -@@ -74,14 +74,14 @@ bindir := @bindir@ - datadir := @datadir@ - ifeq "$(findstring pgsql, $(datadir))" "" - ifeq "$(findstring postgres, $(datadir))" "" --override datadir := $(datadir)/postgresql -+override datadir := $(datadir)/sepgsql - endif - endif - - sysconfdir := @sysconfdir@ - ifeq "$(findstring pgsql, $(sysconfdir))" "" - ifeq "$(findstring postgres, $(sysconfdir))" "" --override sysconfdir := $(sysconfdir)/postgresql -+override sysconfdir := $(sysconfdir)/sepgsql - endif - endif - -@@ -90,7 +90,7 @@ libdir := @libdir@ - pkglibdir = $(libdir) - ifeq "$(findstring pgsql, $(pkglibdir))" "" - ifeq "$(findstring postgres, $(pkglibdir))" "" --override pkglibdir := $(pkglibdir)/postgresql -+override pkglibdir := $(pkglibdir)/sepgsql - endif - endif - -@@ -99,7 +99,7 @@ includedir := @includedir@ - pkgincludedir = $(includedir) - ifeq "$(findstring pgsql, $(pkgincludedir))" "" - ifeq "$(findstring postgres, $(pkgincludedir))" "" --override pkgincludedir := $(pkgincludedir)/postgresql -+override pkgincludedir := $(pkgincludedir)/sepgsql - endif - endif - -@@ -108,7 +108,7 @@ mandir := @mandir@ - docdir := @docdir@ - ifeq "$(findstring pgsql, $(docdir))" "" - ifeq "$(findstring postgres, $(docdir))" "" --override docdir := $(docdir)/postgresql -+override docdir := $(docdir)/sepgsql - endif - endif - -diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c -index 497bdf0..54908f8 100644 ---- a/src/bin/initdb/initdb.c -+++ b/src/bin/initdb/initdb.c -@@ -2722,7 +2722,7 @@ main(int argc, char *argv[]) - */ - putenv("TZ=GMT"); - -- if ((ret = find_other_exec(argv[0], "postgres", PG_BACKEND_VERSIONSTR, -+ if ((ret = find_other_exec(argv[0], "sepostgres", PG_BACKEND_VERSIONSTR, - backend_exec)) < 0) - { - char full_path[MAXPGPATH]; -diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c -index 814ce97..2550e57 100644 ---- a/src/bin/pg_ctl/pg_ctl.c -+++ b/src/bin/pg_ctl/pg_ctl.c -@@ -654,7 +654,7 @@ do_init(void) - char cmd[MAXPGPATH]; - - if (exec_path == NULL) -- exec_path = find_other_exec_or_die(argv0, "initdb", "initdb (PostgreSQL) " PG_VERSION "\n"); -+ exec_path = find_other_exec_or_die(argv0, "initdb.sepgsql", "initdb (PostgreSQL) " PG_VERSION "\n"); - - if (pgdata_opt == NULL) - pgdata_opt = ""; -@@ -699,7 +699,7 @@ do_start(void) - pgdata_opt = ""; - - if (exec_path == NULL) -- exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR); -+ exec_path = find_other_exec_or_die(argv0, "sepostgres", PG_BACKEND_VERSIONSTR); - - #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE) - if (allow_core_files) -@@ -1069,7 +1069,7 @@ pgwin32_CommandLine(bool registration) - } - else - { -- ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR, -+ ret = find_other_exec(argv0, "sepostgres", PG_BACKEND_VERSIONSTR, - cmdLine); - if (ret != 0) - { -diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c -index 83f1678..a0a9444 100644 ---- a/src/bin/pg_dump/pg_dumpall.c -+++ b/src/bin/pg_dump/pg_dumpall.c -@@ -156,7 +156,7 @@ main(int argc, char *argv[]) - } - } - -- if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR, -+ if ((ret = find_other_exec(argv[0], "sepg_dump", PGDUMP_VERSIONSTR, - pg_dump_bin)) < 0) - { - char full_path[MAXPGPATH]; diff --git a/sepostgresql.8 b/sepostgresql.8 deleted file mode 100644 index 9c60ef5..0000000 --- a/sepostgresql.8 +++ /dev/null @@ -1,137 +0,0 @@ -.TH "sepostgresql" "8" "Jul 15 2007" "kaigai@kaigai.gr.jp" "Security-Enhanced PostgreSQL" - -.SH "NAME" -sepostgresql \- Security-Enhances PostgreSQL - -.SH "DESCRIPTION" -Security-Enhanced PostgreSQL (SE-PostgreSQL) is an enhancement of PostgreSQL, -to apply fine grained mandatory access control for database objects based on -the security policy of SELinux. -These features enable to apply flexible integrated access control policy -on both of operating system and database management system, during all -stages of the life of the information. -.PP -This document describes the way to customize SE-PostgreSQL on the default -security policy. - -.SH "BOOLEANS" -The SELinux policy is customizable via BOOLEAN variable. This variable has -two states, 1 (on) or 0 (off). We can validate or invalidate a part of the -security policy depending on the state of boolean variables. - -\fBsepgsql_enable_users_ddl\fP enables to toggle permissions of confined -users/applications to invoke DDL statement, like CREATE TABLE. It is set to -\fBon\fP in the default. -In most cases, DDL statements are used to set up initial database structure, -and permissions to invoke them are not necessary on operation phase. -You can turn off this boolean as follows: - -.EX -setsebool -P sepgsql_enable_users_ddl ( \fBon\fP | off ) -.EE - -Rest of booleans are provided by \fBselinux-devel.pp\fP policy module. -It provides developments/debugs related permissions. -You can install it as follows: - -.EX -semodule -i /usr/share/selinux/targeted/sepostgresql-devel.pp -.EE - -\fBsepgsql_enable_auditallow\fP toggles output of audit messages in the case -when required permission checks are allowed, except for tuples because it -easily make a flood of audit logs. -In the default, it is set to off. You can set it as follows: - -.EX -setsebool -P sepgsql_enable_auditallow ( on | \fBoff\fP ) -.EE - -\fBsepgsql_enable_auditdeny\fP toggles output of audit messages in the case -when required permission checks are denied, except for tuples because it -easily make a flood of audit logs. -In the default, it is set to on. You can set it as follows: - -.EX -setsebool -P sepgsql_enable_auditdeny ( \fBon\fP | off ) -.EE - -\fBsepgsql_regression_test_mode\fP allows to load shared libraries deployed -on user's home directory. We recommend you to keep \fBoff\fP in operation -phase to prevent to load malicious libraries. -However, typical PostgreSQL regression test requires to load it, so we -have to reduce several restriction during the test. -In the default, it is set to off. You can set it as follows: - -.EX -setsebool -P sepgsql_regression_test_mode ( on | \fBoff\fP ) -.EE - -.SH "TYPES" - -\fBsepgsql_db_t\fP is a only type for database itself. -It is attched for newly created databases in the default. - -\fBsepgsql_table_t\fP is a type for tables, columns and tuples. -It is the default type of newly created tables by unconfined or -non-roled domain. It allows confined clietns to access with any -kind of operations except for relabeling, so we can use this type -for compatible purpose. - -\fBsepgsql_secret_table_t\fP is a type for tables, columns and tuples. -It never allows confined clients to access, so we can use this type -to store sensitive information. We reccomend to apply trusted procedures -to access tables/columns/tuples with this type under safe operation. - -\fBsepgsql_ro_table_t\fP is a type for read-only tables, columns and tuples. -It does not allow confined clients to modify any objects with this type. - -\fBsepgsql_fixed_table_t\fP is a type for non-manupulatable tables, columns -and tuples. It does not allow confined clients to update or delete any -objects with this type. - -\fBsepgsql_ROLE_table_t\fP is a type for a role specific tables, columns -and tuples. It allows confined clients with its role to access with any -kind of operations except for relabeling. -It is the default type of newly created tables by confined clients with -its role, and we can use this type to describe role level separation. - -\fBsepgsql_proc_t\fP is a type for procedures. -It is attached for newly created procedures by unconfined clients. -It allows any clients to invoke procedures with this type. -All of PostgreSQL built-in functions are labeled as this type in the default. - -\fBsepgsql_ROLE_proc_t\fP is a type for a role specific procedure. -It is attached for newly created procedures by confined clients with its role. -It allows clients with same role to invoke procedure with this type. -Note that unconfined clients cannot invoke this type to avoid to execute -dangerous functions with unconfined authorities. They have to confirm its -contains and relabel to \fBsepgsql_proc_t\fP for its invocation. - -\fBsepgsql_trusted_proc_exec_t\fP is a type for trusted procedures. -To call procedures with this type invokes domain transition to -unconfined domain, so it can access any kind of database objects. -We can use this type to provide a secure method to access sensitive -information. - -\fBsepgsql_blob_t\fP is a type for binary large objects (blob). -It is attached for newly created blob in the default. -Non-administrative clients can read and write the blobs with this type. - -\fBsepgsql_ro_blob_t\fP is a type for read-only binary large objects (blob). -Non-administrative clients cannot write the blobs with this type. - -.SH "BACKUP and RESTORE" -\fI--enable-selinux\fP option in \fBsepg_dump\fP and \fBsepg_dumpall\fP enable to dump database image with security context. We can restore the dumped image using the standard \fIpg_restore\fP and so on. - -.EX -Example) -$ sepg_dump -Ft -b --enable-selinux postgres | gzip -c > postgres.tgz -.EE - -.SH AUTHOR -This manual page was written by KaiGai Kohei - -.SH "SEE ALSO" - -selinux(8), boolean(8) diff --git a/sepostgresql.init b/sepostgresql.init deleted file mode 100644 index bc668c4..0000000 --- a/sepostgresql.init +++ /dev/null @@ -1,205 +0,0 @@ -#!/bin/sh -# sepostgresql This is the init script for starting up SE-PostgreSQL -# -# chkconfig: - 62 38 -# description: Starts and stops the SE-PostgreSQL backend daemon -# processname: postmaster -# pidfile: /var/run/postmaster.pid -#--------------------------------------------------------------------- - -# source function library -. /etc/rc.d/init.d/functions - -# get config -. /etc/sysconfig/network - -# find the name of the script -NAME=`basename $0` -if [ ${NAME:0:1} = "S" -o ${NAME:0:1} = "K" ]; then - NAME=${NAME:3} -fi - -PGVERSION=`rpm -q --queryformat='%{version}' ${NAME}` -PGMAJORVERSION=`echo "$PGVERSION" | sed 's/^\([0-9]*\.[0-9a-z]*\).*$/\1/'` - -# set defaults for configurable variables -SEPGSQL_CTL="/usr/bin/sepg_ctl" -SEPGSQL_DATA="/var/lib/sepgsql/data" -SEPGSQL_OPTS="-i -p 5432" -SEPGSQL_STARTUP_LOG="/var/lib/sepgsql/pgstartup.log" -SEPGSQL_LOG="/var/log/sepostgresql.log" - -# override defaults from /etc/sysconfig/sepostgresql -test -f /etc/sysconfig/${NAME} && . /etc/sysconfig/${NAME} - -# Check that networking is up. -test "${NETWORKING}" = "no" && exit 0 -test -f "/usr/bin/sepostgres" || exit 1 - -script_result=0 - -do_start() { - PSQL_START=$"Starting ${NAME} service: " - echo -n "$PSQL_START" - - # make sure startup-time log file is valid - if [ ! -e "${SEPGSQL_STARTUP_LOG}" -a ! -h "${SEPGSQL_STARTUP_LOG}" ]; then - touch "${SEPGSQL_STARTUP_LOG}" || exit 1 - chown sepgsql:sepgsql "${SEPGSQL_STARTUP_LOG}" - chmod 600 "${SEPGSQL_STARTUP_LOG}" - /sbin/restorecon "${SEPGSQL_STARTUP_LOG}" - fi - - # check for the SEPGSQL_DATA structure - if [ -f "${SEPGSQL_DATA}/PG_VERSION" ] && [ -d "${SEPGSQL_DATA}/base" ]; then - if [ x`cat "${SEPGSQL_DATA}/PG_VERSION"` != x"${PGMAJORVERSION}" ]; then - echo_failure - echo - echo "HINT: An old version of the database format was found." - echo "HINT: You need to upgrade the data format before using SE-PostgreSQL." - exit 1 - fi - else - echo_failure - echo - echo "HINT: ${SEPGSQL_DATA} is missing." - echo "HINT: Use '/etc/init.d/${NAME} initdb'" - echo "HINT: to initialize the database cluster first." - exit 1 - fi - - # make sure SEPGSQL_LOG - touch ${SEPGSQL_LOG} - chown sepgsql:sepgsql ${SEPGSQL_LOG} - chmod 600 ${SEPGSQL_LOG} - test -x /sbin/restorecon && /sbin/restorecon ${SEPGSQL_LOG} - - /sbin/runuser sepgsql -c "${SEPGSQL_CTL} -w -t 10 -l ${SEPGSQL_LOG} -D ${SEPGSQL_DATA} -o '${SEPGSQL_OPTS}' start" \ - >> ${SEPGSQL_STARTUP_LOG} 2>&1 < /dev/null - sleep 1 - PID=`/sbin/runuser sepgsql -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} status 2>/dev/null \ - | sed 's/^.*PID: //g' | sed 's/[^0-9].*$//g'"` - if [ ${PIPESTATUS[0]} -eq 0 ]; then - echo "$PID" > "/var/run/${NAME}.pid" - touch "/var/lock/subsys/${NAME}.lock" - echo_success - else - script_result=1 - echo_failure - fi - echo -} - -do_stop() { - echo -n $"Stopping ${NAME} service: " - /sbin/runuser sepgsql -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} stop" \ - >> ${SEPGSQL_STARTUP_LOG} 2>&1 < /dev/null - ret=$? - if [ $ret -eq 0 ]; then - echo_success - else - echo_failure - script_result=1 - fi - echo - rm -f "/var/run/${NAME}.pid" - rm -f "/var/lock/subsys/${NAME}.lock" -} - -do_status() { - /sbin/runuser sepgsql -- -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} status" 2>/dev/null \ - | head -1 | sed "s/^sepg_ctl:/${NAME}:/g" - - if [ ${PIPESTATUS[0]} -ne 0 ]; then - script_result=3 - test -e "/var/run/${NAME}.pid" && script_result=1 - test -e "/var/lock/subsys/${NAME}.lock" && script_result=2 - fi -} - -do_condrestart() { - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} status" &>/dev/null && do_stop && do_start -} - -do_condstop() { - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} status" &>/dev/null && do_stop -} - -do_reload() { - echo -n $"Reloading ${NAME} service: " - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} reload" &>/dev/null < /dev/null - if [ $? -eq 0 ]; then - echo_success - else - echo_failure - script_result=1 - fi - echo -} - -do_initdb() { - echo -n $"Initializing database: " - - if [ -f "${SEPGSQL_DATA}/PG_VERSION" ]; then - echo_failure - echo - echo "HINT: Data directory is not empty" - script_result=1 - else - if [ ! -e "${SEPGSQL_DATA}" -a ! -h "${SEPGSQL_DATA}" ]; then - mkdir -p "${SEPGSQL_DATA}" || exit 1 - chown sepgsql:sepgsql "${SEPGSQL_DATA}" - chmod 600 "${SEPGSQL_DATA}" - fi - # cleanup SELinux labeling for "${SEPGSQL_DATA}" - test -x /sbin/restorecon && /sbin/restorecon -R "${SEPGSQL_DATA}" - # Initialize the database - /sbin/runuser -- sepgsql -c "${SEPGSQL_CTL} initdb -o '--enable-selinux --pgdata=${SEPGSQL_DATA} --auth=ident' -D ${SEPGSQL_DATA}" \ - >> "${SEPGSQL_STARTUP_LOG}" 2>&1 < /dev/null - if [ -f "${SEPGSQL_DATA}/PG_VERSION" ]; then - echo_success - else - echo_failure - script_result=1 - fi - echo - fi -} - -# see how we were called. -case "$1" in - start) - do_start - ;; - stop) - do_stop - ;; - status) - do_status - ;; - restart) - do_stop - do_start - ;; - condrestart) - do_condrestart - ;; - condstop) - do_condstop - ;; - reload|force-reload) - do_reload - ;; - initdb) - do_initdb - ;; - *) - echo $"Usage: $0 {start|stop|status|restart|condrestart|condstop|reload|force-reload|initdb}" - exit 1 - ;; -esac - -exit $script_result diff --git a/sepostgresql.logrotate b/sepostgresql.logrotate deleted file mode 100644 index 3ed7081..0000000 --- a/sepostgresql.logrotate +++ /dev/null @@ -1,11 +0,0 @@ -# logrotate configuration for SE-PostgreSQL - -/var/log/sepostgresql.log { - rotate 4 - compress - size 4M - notifempty - postrotate - /sbin/service sepostgresql restart >& /dev/null - endscript -} diff --git a/sepostgresql.spec b/sepostgresql.spec deleted file mode 100644 index 6c40640..0000000 --- a/sepostgresql.spec +++ /dev/null @@ -1,482 +0,0 @@ -# -# Security Enhanced PostgreSQL (SE-PostgreSQL) -# -# Copyright 2007 KaiGai Kohei -# ----------------------------------------------------- - -# SE-PostgreSQL status extension -%define selinux_policy_stores targeted mls - -%{!?ssl:%define ssl 1} - -Summary: Security Enhanced PostgreSQL -Name: sepostgresql -Version: 9.0.3 -Release: 20110415%{?dist} -License: PostgreSQL -Group: Applications/Databases -Url: http://code.google.com/p/sepgsql/ -Buildroot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) -Source0: ftp://ftp.postgresql.org/pub/source/v%{version}/postgresql-%{version}.tar.gz -Source1: sepostgresql.init -Source2: sepostgresql.8 -Source3: sepostgresql.logrotate -Patch0: sepostgresql-fedora-prefix.patch -Patch1: sepostgresql-9.0-fullset.patch -BuildRequires: perl glibc-devel bison flex readline-devel zlib-devel >= 1.0.4 -BuildRequires: checkpolicy libselinux-devel >= 2.0.96 audit-libs-devel -BuildRequires: selinux-policy >= 3.6.8 -%if %{ssl} -BuildRequires: openssl-devel -%endif -Requires(pre): shadow-utils -Requires(post): policycoreutils /sbin/chkconfig -Requires(preun): /sbin/chkconfig /sbin/service -Requires(postun): policycoreutils -Requires: policycoreutils >= 2.0.16 libselinux >= 2.0.96 -Requires: selinux-policy >= 3.6.8 -Requires: tzdata logrotate - -%description -Security Enhanced PostgreSQL is an extension of PostgreSQL -based on SELinux security policy, that applies fine grained -mandatory access control to many objects within the database, -and takes advantage of user authorization integrated within -the operating system. SE-PostgreSQL works as a userspace -reference monitor to check any SQL query. - -%prep -%setup -q -n postgresql-%{version} -%patch0 -p1 -%patch1 -p1 - -%build -CFLAGS="${CFLAGS:-%optflags}" ; export CFLAGS -CXXFLAGS="${CXXFLAGS:-%optflags}" ; export CXXFLAGS - -# build SE-PostgreSQL -%configure --disable-rpath \ - --enable-selinux \ -%if %{ssl} - --with-openssl \ -%endif - --enable-debug \ - --enable-cassert \ - --with-system-tzdata=/usr/share/zoneinfo - -# parallel build, if possible -rm -f src/Makefile.custom -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} - -make DESTDIR=%{buildroot} install - -# avoid to conflict with native postgresql package -mv %{buildroot}%{_bindir} %{buildroot}%{_bindir}.orig -install -d %{buildroot}%{_bindir}/ -mv %{buildroot}%{_bindir}.orig/initdb %{buildroot}%{_bindir}/initdb.sepgsql -mv %{buildroot}%{_bindir}.orig/pg_ctl %{buildroot}%{_bindir}/sepg_ctl -mv %{buildroot}%{_bindir}.orig/postgres %{buildroot}%{_bindir}/sepostgres -mv %{buildroot}%{_bindir}.orig/pg_dump %{buildroot}%{_bindir}/sepg_dump -mv %{buildroot}%{_bindir}.orig/pg_dumpall %{buildroot}%{_bindir}/sepg_dumpall -mv %{buildroot}%{_bindir}.orig/pg_restore %{buildroot}%{_bindir}/sepg_restore - -mv %{buildroot}%{_libdir} %{buildroot}%{_libdir}.orig -install -d %{buildroot}%{_libdir}/sepgsql -mv %{buildroot}%{_libdir}.orig/sepgsql/dict_snowball.so \ - %{buildroot}%{_libdir}.orig/sepgsql/plpgsql.so \ - %{buildroot}%{_libdir}.orig/sepgsql/*_and_*.so \ - %{buildroot}%{_libdir}.orig/sepgsql/euc2004_sjis2004.so \ - %{buildroot}%{_libdir}.orig/sepgsql/libpqwalreceiver.so \ - %{buildroot}%{_libdir}/sepgsql - -# remove unnecessary files -rm -rf %{buildroot}%{_bindir}.orig -rm -rf %{buildroot}%{_libdir}.orig -rm -rf %{buildroot}%{_includedir} -rm -rf %{buildroot}%{_datadir}/doc -rm -rf %{buildroot}%{_datadir}/sepgsql/timezone -rm -rf %{buildroot}%{_mandir} - -# /var/lib/sepgsql -install -d -m 700 %{buildroot}%{_localstatedir}/lib/sepgsql -install -d -m 700 %{buildroot}%{_localstatedir}/lib/sepgsql/data -install -d -m 700 %{buildroot}%{_localstatedir}/lib/sepgsql/backups - -# /etc/rc.d/init.d/* -mkdir -p %{buildroot}%{_initrddir} -install -p -m 755 %{SOURCE1} %{buildroot}%{_initrddir}/sepostgresql - -# /usr/share/man/* -mkdir -p %{buildroot}%{_mandir}/man8 -install -p -m 644 %{SOURCE2} %{buildroot}%{_mandir}/man8 - -# /etc/logrotate.d/ -mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d -install -p -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/logrotate.d/sepostgresql - -%clean -rm -rf %{buildroot} - -%pre -getent group sepgsql >/dev/null || groupadd -r sepgsql -getent passwd sepgsql >/dev/null || \ - useradd -r -g sepgsql -s /bin/bash -c "SE-PostgreSQL" sepgsql -exit 0 - -%post -/sbin/chkconfig --add %{name} -/sbin/ldconfig - -# Fix up non-standard file contexts -/sbin/fixfiles -R %{name} restore || : -/sbin/restorecon -R %{_localstatedir}/lib/sepgsql || : - -%preun -if [ $1 -eq 0 ]; then # rpm -e case - /sbin/service %{name} condstop >/dev/null 2>&1 - /sbin/chkconfig --del %{name} -fi - -%postun -/sbin/ldconfig -if [ $1 -ge 1 ]; then # rpm -U case - /sbin/service %{name} condrestart >/dev/null 2>&1 || : -fi -if [ $1 -eq 0 ]; then # rpm -e case - /sbin/fixfiles -R %{name} restore || : - test -d %{_localstatedir}/lib/sepgsql && \ - /sbin/restorecon -R %{_localstatedir}/lib/sepgsql || : -fi - -%files -%defattr(-,root,root,-) -%doc COPYRIGHT README -%{_initrddir}/sepostgresql -%{_sysconfdir}/logrotate.d/sepostgresql -%{_bindir}/initdb.sepgsql -%{_bindir}/sepg_ctl -%{_bindir}/sepostgres -%{_bindir}/sepg_dump -%{_bindir}/sepg_dumpall -%{_bindir}/sepg_restore -%{_libdir}/sepgsql/*.so -%{_mandir}/man8/sepostgresql.* -%dir %{_datadir}/sepgsql -%{_datadir}/sepgsql/postgres.bki -%{_datadir}/sepgsql/postgres.description -%{_datadir}/sepgsql/postgres.shdescription -%{_datadir}/sepgsql/system_views.sql -%{_datadir}/sepgsql/*.sample -%{_datadir}/sepgsql/snowball_create.sql -%{_datadir}/sepgsql/timezonesets/ -%{_datadir}/sepgsql/tsearch_data/ -%{_datadir}/sepgsql/conversion_create.sql -%{_datadir}/sepgsql/information_schema.sql -%{_datadir}/sepgsql/sql_features.txt -%attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql -%attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/data -%attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/backups - -%changelog -* Fri Apr 15 2011 KaiGai Kohei - 9.0.3-20110415 -- upgrade base version to 9.0.3 -- initial labeling logic was revised to use selabel_lookup() - -* Wed Feb 09 2011 Fedora Release Engineering - 9.0.1-20101008 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild - -* Thu Oct 7 2010 KaiGai Kohei - 9.0.1-20101007 -- upgrade base version to 9.0.1 - -* Tue Oct 5 2010 KaiGai Kohei - 9.0.0-20101005 -- upgrade base version to 9.0.0 - -* Tue May 11 2010 KaiGai Kohei - 9.0.0-20100511 -- upgrade base version to 9.0beta1 - -* Sun Apr 4 2010 KaiGai Kohei - 9.0.0-20100404 -- upgrade base version 8.4.3->9.0alpha5 - -* Thu Mar 18 2010 KaiGai Kohei - 8.4.3-2582 -- upgrade base version 8.4.2->8.4.3 - -* Mon Feb 15 2010 KaiGai Kohei - 8.4.2-2488 -- fix: build failed due to an implicit header file include -- update: feature backport from v8.5 development - -* Wed Dec 16 2009 KaiGai Kohei - 8.4.2-2487 -- upgrade base version 8.4.1->8.4.2 - -* Fri Dec 8 2009 KaiGai Kohei - 8.4.1-2464 -- rework: backport features from v8.5devel tree -- fixbug: selinux netlink receiver process didn't have correct ps display - -* Fri Sep 11 2009 KaiGai Kohei - 8.4.1-2305 -- Upgrade base SE-PostgreSQL v8.4.0->v8.4.1 -- rework: backport features from v8.5devel tree - -* Fri Aug 21 2009 Tomas Mraz - 8.4.0-2238 -- rebuilt with new openssl - -* Wed Aug 19 2009 KaiGai Kohei - 8.4.0-2237 -- Upgrade SE-PostgreSQL to 8.4.x series - -* Sun Jul 26 2009 Fedora Release Engineering - 8.3.7-1991 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild - -* Tue Jun 9 2009 KaiGai Kohei - 8.3.7-1990 -- backport features from v8.4devel, it also needs libselinux-2.0.80 - -* Fri Apr 17 2009 KaiGai Kohei - 8.3.7-1772 -- bugfix: /etc/init.d/sepostgresql initdb didn't work correctly - -* Fri Mar 27 2009 KaiGai Kohei - 8.3.7-1770 -- upgrade base PostgreSQL versin 8.3.6->8.3.7 -- backport features from v8.4devel - -* Thu Feb 26 2009 KaiGai Kohei - 8.3.6-2.1635 -- bugfix: possible information leak by the order of permission checks - in row level permission checks. - -* Wed Feb 25 2009 Fedora Release Engineering - 8.3.6-3.1518 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild - -* Fri Feb 6 2009 - 8.3.6-2.1523 -- upgrade base PostgreSQL version 8.3.5->8.3.6 -- backport features from 8.4devel tree -- security policy fix for Fedora 9 - -* Sat Jan 17 2009 Tomas Mraz - 8.3.5-2.1183 -- rebuild with new openssl - -* Wed Nov 5 2008 - 8.3.5-2.1182 -- upgrade base PostgreSQL version 8.3.4->8.3.5 -- backport cumulative bugfixes from 8.4devel series - -* Thu Oct 2 2008 - 8.3.4-2.1076 -- bugfix: "(null)" audit logs for non-cached decision making. -- A hook is added for "COPY TO/FROM " cases. - -* Sat Sep 27 2008 - 8.3.4-2.1066 -- update base version to 8.3.4 -- sepostgresql.pp was marked as obsolute - -* Tue Sep 23 2008 - 8.3.3-2.1043 -- bugfix: a case when INSERT a FK reference to invisible PK - -* Wed Aug 13 2008 - 8.3.3-2.964 -- bugfix: trusted procedure invokation - -* Fri Jul 11 2008 - 8.3.3-2.952 -- Security policy module updates - -* Fri Jul 11 2008 - 8.3.3-2.945 -- Add OpenSSL support -- backport 8.4devel fixes - -* Sun Jun 15 2008 - 8.3.3-2.889 -- backport 8.4devel features. - -* Fri Jun 13 2008 - 8.3.3-2.869 -- upgrade base PostgreSQL 8.3.1 -> 8.3.3 - -* Wed Apr 30 2008 - 8.3.1-2.197 -- Inconsistent version number format at Changelogs - -* Wed Apr 30 2008 - 8.3.1-2.196 -- BUGFIX: ROW-level control did not work correctly on TRUNCATE - -* Sun Mar 9 2008 - 8.3.0-2.129 -- BUGFIX: more conprehensive fixes in "SELECT COUNT(*) ..." - -* Sun Mar 2 2008 - 8.3.0-2.120 -- BUGFIX: CREATE TABLE statement with explicit labeled columns -- BUGFIX: SELECT count(*) does not filter unallowed tuples - -* Wed Feb 27 2008 - 8.3.0-2.117 -- ".beta" removed. - -* Wed Feb 27 2008 - 8.3.0-2.114 -- Security policy updates - -* Tue Feb 26 2008 - 8.3.0-2.113 -- BUGFIX: CREATE/ALTER TABLE with CONTEXT='...' did nothing. - -* Thu Feb 7 2008 - 8.3.0-2.108 -- add /etc/logrotate.d/sepostgresql - -* Thu Feb 7 2008 - 8.3.0-2.105 -- update base version to stable 8.3.0 -- add tzdata dependency -- allow db_database:{get_param set_param} for generic domain -- error message cleanups -- Improve large object hooks in PGACE framework -- BUGFIX: db_blob:{drop} was checked at loread() -- BUGFIX: incorrect permission in DELETE with RETURNING clause -- incorrect permission when we read and update security_context in same time. - -* Fri Jan 25 2008 - 8.3RC2-2.62 -- BUGFIX: add handling to invalid contexts already stored - -* Tue Jan 22 2008 - 8.3RC2-2.56 -- BUGFIX: lack of locks when refering buffer pages at update/delete hooks -- BUGFIX: explicit labeling using SELECT ... INTO statement. - -* Sun Jan 20 2008 - 8.3RC2-2.52 -- shares /usr/lib/pgsql/*.so libraries, with original postgresql. - -* Thu Jan 10 2008 - 8.3RC1-2.37 -- add sepg_dump/sepg_dumpall support for 8.3base package. - -* Mon Nov 26 2007 - 8.3beta3-2.0 -- Branch from 8.2.x tree - -* Wed Nov 21 2007 - 8.2.5-1.66 -- Add a policy module hotfix for labeled networking - -* Thu Nov 1 2007 - 8.2.5-1.51 -- Re-organize repository to prepare to branch 8.3.x based tree. - (no differences from 8.2.5-1.33) - -* Wed Oct 17 2007 - 8.2.5-1.33 -- Fix bug: security context was not canonicalized - when irregular context (but interpretable) was inputed. - -* Mon Oct 15 2007 - 8.2.5-1.31 -- Fix bug: type definitions of security_label_to_text() - and text_to_security_label() are mismatched. - -* Sat Sep 22 2007 - 8.2.5-1.23 -- update base PostgreSQL to 8.2.5 - -* Mon Sep 1 2007 - 8.2.4-1.0 -- mark as SE-PostgreSQL 8.2.4-1.0 - -* Thu Aug 28 2007 - 8.2.4-0.434.beta -- add Requires: postgresql-server, instead of Conflicts: tag - (Some sharable files are removed from sepostgresql package) - -* Fri Aug 24 2007 - 8.2.4-0.429.beta -- add policycoreutils to Requires(post/postun) -- upstreamed selinux-policy got SE-PostgreSQL related object classes definition. - -* Sat Aug 18 2007 - 8.2.4-0.427.beta -- sepg_dumpall uses /usr/bin/sepg_dump - -* Fri Aug 17 2007 - 8.2.4-0.423.beta -- fix policy not to execute sepgsql_user_proc_t from administrative domain - -* Fri Aug 10 2007 - 8.2.4-0.418.beta -- object classes are renamed with "db_" prefix -- /etc/init.d/sepostgresql script is improved. - -* Thu Aug 2 2007 - 8.2.4-0.409.beta -- specfile updated based on the following comments - https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=249522#c5 - -* Mon Jul 30 2007 - 8.2.4-0.407.beta -- fix spec file based on Fedora reviewing process -- add rawhide support - -* Mon Jul 23 2007 - 8.2.4-0.402.beta -- add manpage of sepostgresql -- fix specfile convention for Fedora suitable - -* Sun Jul 15 2007 - 8.2.4-0.398.beta -- SECCLASS_DATABASE is updated (fc7->62, fc6->61) - -* Sun Jul 1 2007 - 8.2.4-0.391.beta -- Mark as a beta version. - -* Sat Jun 30 2007 - 8.2.4-0.384.alpha -- add fallback context support with $SEPGSQL_FALLBACK_CONTEXT -- add sepgsql_enable_users_ddl boolean to restrict sepgsql_sysobj_t -- BUGFIX: incorrect inherited attribute expanding for RECORD type (attno=0) -- BUGFIX: trigger functions were not checked in COPY FROM statement - -* Tue Jun 26 2007 - 8.2.4-0.376.alpha -- add pgaceExecutorStart() to hook ExecutorStart() - -* Mon Jun 25 2007 - 8.2.4-0.372.alpha -- add table name prefix for column name on audit messages -- use security_label_raw_in as an alternative for security_label_in -- add hook for query execution path with SPI_ interface -- add trigger function suppoer -- BUGFIX: remove unnecessary checks for COPY TO/FROM on non-table relation -- BUGFIX: remove unnecessary checks for LOCK on non-table relation -- BUGFIX: incorrect object id for tuples within pg_security -- BUGFIX: CommandCounterIncrement() might be called during heap_create_with_catalog. -- BUGFIX: correct self-deadlock -- update security policy: sepgsql_sysobj_t, sepgsql_user_proc_t, sepgsql_ro_blob_t - -* Tue Jun 19 2007 - 8.2.4-0.351.alpha -- BUGFIX: sepgsql_compute_avc_datum() accessed userspace AVC without - holding any lock. -- improve build scripts. - -* Sat Jun 16 2007 - 8.2.4-0.320.alpha -- update: sepostgresql.pp security policy fot strict/mls suitable -- BUGFIX: column:drop evaluation for ALTER TABLE tbl DROP col; statement -- add --enable-security option for pg_dumpall command -- add {use} permission for table/column/tuple object classes - -* Tue May 29 2007 - 8.2.4-0.306.alpha -- BUGFIX: RangeTblEntry->requiredPerms are polluted. - -* Sun May 27 2007 - 8.2.4-0.304.alpha -- add support for dynamic object class/access vector mapping -- BUGFIX: Lack of implicit labeling on COPY FROM statement for system catalogs -- BUGFIX: Incorrect security context handling for inherited tables - -* Fri May 25 2007 - 8.2.4-0.292.alpha -- add pg_dump/pg_dumpall/pg_restore with --enable-security option -- add support on OUTER JOIN by rewriting query. -- add security_context support on COPY TO/FROM statement -- add unlabeled security context support (enable to obtain /selinux/initial_contexts/*) -- BUGFIX: lack of checks on JOIN ON condition -- BUGFIX: pseudo relation object (sequence, toast, ...) are not handled as database obj. -- BUGFIX: lack of tuple:insert checks at COPY FROM statement -- BUGFIX: server crash when CREATE TABLE command with newly defined CONTEXT = '...'. - -* Wed May 16 2007 - 8.2.4-0.266.alpha -- BUGFIX: incorrect security context of newly generated system object. -- BUGFIX: missing error text when audit log is disabled. -- BUGFIX: incorrect Oid of newly generated tuples within pg_security. -- BUGFIX: sepgsql_enable_audittuple is misconditioned. -- add checks for T_RowExpr/T_RowCompareExpr/T_BooleanTest - T_DistinctExpr/T_ConvertRowtypeExpr -- add support CONTEXT = 'xxx' for CREATE TABLE/FUNCTION/DATABASE statement - -* Sun Apr 30 2007 - 8.2.4-0.240.alpha -- update base version 8.2.3 -> 8.2.4 -- BUGFIX: unexpected expose in OUTER JOIN statement. - add rewrite OUTER JOIN into SUBQUERY to ensure filtering violated tuples. -- BUGFIX: strange operation in text_to_security_label() -- BUGFIX: infinite recursive call on security label -> oid mapping -- BUGFIX: sepgsql_avc_init() is called in policy state monitoring process - to avoid nonsense initialization of avc_shmem. - -* Fri Apr 27 2007 - 8.2.3-0.232.alpha -- object class numbers were redefined. (SECCLASS_DATABASE got into 61) -- is_selinux_enabled() was cached on the shared memory segment. -- BUGFIX: server went into infinit loop on foreign key constraint. - -* Mon Apr 16 2007 - 8.2.3-0.226.alpha -- BUGFIX: cases when several variables with same type in a single table - -* Sat Apr 07 2007 - 8.2.3-0.214.alpha -- add the first implementation of SE-PostgreSQL on PGACE framework - -* Wed Mar 21 2007 - 8.2.3-0.212.alpha -- BUGFIX: SetOperation didn't handle its subquery correctly. - So, it caused server crash. - -* Wed Mar 07 2007 - 8.2.3-0.209.alpha -- BUGFIX: var->varlevelsup was ignored, so outer references - from subqueries cause a fault. - -* Tue Feb 27 2007 - 8.2.3-0.178.alpha -- Initial RPM build diff --git a/sources b/sources deleted file mode 100644 index 8ba5714..0000000 --- a/sources +++ /dev/null @@ -1 +0,0 @@ -56386ded2d5dcd8a4ceef0da81c3d22c postgresql-9.0.3.tar.gz