19565 lines
577 KiB
Diff
19565 lines
577 KiB
Diff
diff --git a/configure b/configure
|
|
index b91de59..b44a6be 100755
|
|
--- a/configure
|
|
+++ b/configure
|
|
@@ -707,6 +707,7 @@ LDFLAGS_SL
|
|
ELF_SYS
|
|
EGREP
|
|
GREP
|
|
+enable_selinux
|
|
with_zlib
|
|
with_system_tzdata
|
|
with_libxslt
|
|
@@ -842,6 +843,7 @@ with_libxml
|
|
with_libxslt
|
|
with_system_tzdata
|
|
with_zlib
|
|
+enable_selinux
|
|
with_gnu_ld
|
|
enable_largefile
|
|
enable_float4_byval
|
|
@@ -1498,6 +1500,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
|
|
@@ -5608,6 +5611,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 b2fa682..5797ff5 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 13e04b2..c613826 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/contrib/sepgtest/sepgtest b/contrib/sepgtest/sepgtest
|
|
new file mode 100755
|
|
index 0000000..30e7cb9
|
|
--- /dev/null
|
|
+++ b/contrib/sepgtest/sepgtest
|
|
@@ -0,0 +1,45 @@
|
|
+#!/bin/sh
|
|
+
|
|
+SEPGTEST=`basename $0`
|
|
+PSQL=`which psql`
|
|
+DIFF=`which diff`
|
|
+RUNCON=`which runcon`
|
|
+
|
|
+DBUSER=""
|
|
+DBHOST=""
|
|
+DBPORT=""
|
|
+DBNAME="testdb"
|
|
+
|
|
+usage()
|
|
+{
|
|
+ echo "${SEPGTEST}: [-u <username>] [-h <host>] [-p <port>] [-d <dbname>]"
|
|
+ exit 1
|
|
+}
|
|
+
|
|
+# parse options
|
|
+CMD_OPTS=`getopt -n "${SEPGTEST}" "u:h:p:d:" $*` || usage
|
|
+eval set -- $CMD_OPTS
|
|
+while [ -n "$1" ];
|
|
+do
|
|
+ case $1 in
|
|
+ -u)
|
|
+ DBUSER="-U $2"; shift 2;;
|
|
+ -h)
|
|
+ DBHOST="-h $2"; shift 2;;
|
|
+ -p)
|
|
+ DBPORT="-p $2"; shift 2;;
|
|
+ -d)
|
|
+ DBNAME="$2"; shift 2;;
|
|
+ --)
|
|
+ shift; break;;
|
|
+ *)
|
|
+ usage; shift 2;;
|
|
+ esac
|
|
+done
|
|
+
|
|
+PSQL_OPTS="${PSQL} ${DBUSER} ${DBHOST} ${DBPORT} ${DBNAME}"
|
|
+
|
|
+# check environment
|
|
+
|
|
+
|
|
+
|
|
diff --git a/contrib/sepgtest/sepgtest.in b/contrib/sepgtest/sepgtest.in
|
|
new file mode 100755
|
|
index 0000000..30e7cb9
|
|
--- /dev/null
|
|
+++ b/contrib/sepgtest/sepgtest.in
|
|
@@ -0,0 +1,45 @@
|
|
+#!/bin/sh
|
|
+
|
|
+SEPGTEST=`basename $0`
|
|
+PSQL=`which psql`
|
|
+DIFF=`which diff`
|
|
+RUNCON=`which runcon`
|
|
+
|
|
+DBUSER=""
|
|
+DBHOST=""
|
|
+DBPORT=""
|
|
+DBNAME="testdb"
|
|
+
|
|
+usage()
|
|
+{
|
|
+ echo "${SEPGTEST}: [-u <username>] [-h <host>] [-p <port>] [-d <dbname>]"
|
|
+ exit 1
|
|
+}
|
|
+
|
|
+# parse options
|
|
+CMD_OPTS=`getopt -n "${SEPGTEST}" "u:h:p:d:" $*` || usage
|
|
+eval set -- $CMD_OPTS
|
|
+while [ -n "$1" ];
|
|
+do
|
|
+ case $1 in
|
|
+ -u)
|
|
+ DBUSER="-U $2"; shift 2;;
|
|
+ -h)
|
|
+ DBHOST="-h $2"; shift 2;;
|
|
+ -p)
|
|
+ DBPORT="-p $2"; shift 2;;
|
|
+ -d)
|
|
+ DBNAME="$2"; shift 2;;
|
|
+ --)
|
|
+ shift; break;;
|
|
+ *)
|
|
+ usage; shift 2;;
|
|
+ esac
|
|
+done
|
|
+
|
|
+PSQL_OPTS="${PSQL} ${DBUSER} ${DBHOST} ${DBPORT} ${DBNAME}"
|
|
+
|
|
+# check environment
|
|
+
|
|
+
|
|
+
|
|
diff --git a/git-update-branches.sh b/git-update-branches.sh
|
|
new file mode 100755
|
|
index 0000000..2f25fde
|
|
--- /dev/null
|
|
+++ b/git-update-branches.sh
|
|
@@ -0,0 +1,89 @@
|
|
+#!/bin/sh
|
|
+
|
|
+GIT_BIN=`which git`
|
|
+GIT_DIR=`(cd \`dirname $0\`; pwd)`
|
|
+UPSTREAM_URL="git://git.postgresql.org/git/postgresql.git"
|
|
+UPSTREAM_BRANCH="master"
|
|
+LOCAL_BRANCHES="master v9.0/sepgsql"
|
|
+RPMSOURCE=`rpm -E '%{_sourcedir}'`
|
|
+#================================================================
|
|
+
|
|
+cd ${GIT_DIR}
|
|
+
|
|
+CURRENT_BRANCH=`${GIT_BIN} branch -l | grep '^*' | awk '{print $2}'`
|
|
+
|
|
+for tree in ${LOCAL_BRANCHES}
|
|
+do
|
|
+ ${GIT_BIN} branch -lr | grep -q "origin/${tree}" || exit 1
|
|
+ ${GIT_BIN} branch -l | grep -q "${tree}" || \
|
|
+ ${GIT_BIN} checkout --track "origin/${tree}" || exit 1
|
|
+done
|
|
+
|
|
+# ======== create patches ========
|
|
+if [ "$1" = "--patch" ]; then
|
|
+ LEFT_TREE=""
|
|
+ RIGHT_TREE=""
|
|
+ NUM=0
|
|
+
|
|
+ BASE_VERSION=`grep AC_INIT ${GIT_DIR}/configure.in \
|
|
+ | head -1 \
|
|
+ | sed -e 's/,/ /g' -e 's/\[//g' -e 's/\]//g' \
|
|
+ | awk '{print $2}'`
|
|
+ BASE_MAJOR=`echo $BASE_VERSION | sed 's/\.[0-9]\+$//g'`
|
|
+
|
|
+ for tree in ${LOCAL_BRANCHES}
|
|
+ do
|
|
+ LEFT_TREE=$RIGHT_TREE
|
|
+ RIGHT_TREE=$tree
|
|
+
|
|
+ if [ -n "$LEFT_TREE" -a -n "$RIGHT_TREE" ]; then
|
|
+ tag=`basename ${RIGHT_TREE}`
|
|
+ ${GIT_BIN} diff $LEFT_TREE $RIGHT_TREE \
|
|
+ > $RPMSOURCE/pgsql-${NUM}-${BASE_MAJOR}-${tag}.patch
|
|
+ echo "${NUM}) $RPMSOURCE/pgsql-${NUM}-${BASE_MAJOR}-${tag}.patch"
|
|
+ fi
|
|
+ NUM=`printf "%02d" \`expr $NUM + 1\``
|
|
+ done
|
|
+
|
|
+ exit 0
|
|
+fi
|
|
+
|
|
+# ======== sync remote git ========
|
|
+
|
|
+if echo "$1" | grep -q '^--sync-upstream=\?'; then
|
|
+ UPSTREAM_TAG=`echo "$1" | sed 's/^--sync-upstream=\?//g'`
|
|
+ if [ -n "${UPSTREAM_TAG}" ]; then
|
|
+ UPSTREAM_TAG=HEAD
|
|
+ fi
|
|
+
|
|
+ LOCAL_MASTER=`echo "${LOCAL_BRANCHES}" | awk '{print $1}'`
|
|
+
|
|
+ ${GIT_BIN} checkout ${LOCAL_MASTER} || exit 1
|
|
+ ${GIT_BIN} pull ${UPSTREAM_URL} ${UPSTREAM_BRANCH} ${UPSTREAM_TAG}
|
|
+ if [ $? -ne 0 ]; then
|
|
+ ${GIT_BIN} reset HEAD
|
|
+ ${GIT_BIN} checkout .
|
|
+ ${GIT_BIN} clean -fd
|
|
+ ${GIT_BIN} pull --no-commit ${UPSTREAM_URL} ${UPSTREAM_BRANCH} ${UPSTREAM_TAG}
|
|
+ exit 2
|
|
+ fi
|
|
+fi
|
|
+
|
|
+LEFT_TREE=""
|
|
+for RIGHT_TREE in ${LOCAL_BRANCHES}
|
|
+do
|
|
+ if [ -n "${LEFT_TREE}" -a -n "${RIGHT_TREE}" ]; then
|
|
+ ${GIT_BIN} checkout ${RIGHT_TREE} || exit 1
|
|
+ ${GIT_BIN} pull ${GIT_DIR} ${LEFT_TREE} || exit 1
|
|
+ if [ $? -ne 0 ]; then
|
|
+ ${GIT_BIN} reset HEAD
|
|
+ ${GIT_BIN} checkout .
|
|
+ ${GIT_BIN} clean -fd
|
|
+ ${GIT_BIN} pull --no-commit ${GIT_DIR} ${LEFT_TREE}
|
|
+ exit 2
|
|
+ fi
|
|
+ fi
|
|
+ LEFT_TREE=${RIGHT_TREE}
|
|
+done
|
|
+
|
|
+${GIT_BIN} checkout ${CURRENT_BRANCH}
|
|
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
|
|
index 1c38ac2..0e3bed5 100644
|
|
--- a/src/Makefile.global.in
|
|
+++ b/src/Makefile.global.in
|
|
@@ -164,6 +164,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 218544e..0b1dd31 100644
|
|
--- a/src/backend/Makefile
|
|
+++ b/src/backend/Makefile
|
|
@@ -16,7 +16,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
|
|
|
|
@@ -40,6 +40,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 6ec73f0..db0023f 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);
|
|
|
|
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 9a8611f..325dbde 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 f01ed1e..4e8dfcb 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 759fc35..2fc282d 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 2af81df..18341f4 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);
|
|
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 d432c9d..28e7bde 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 b88cff2..d6636f7 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 */
|
|
@@ -1658,6 +1663,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
|
|
*/
|
|
@@ -2162,6 +2171,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
|
|
*/
|
|
@@ -4006,6 +4019,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...
|
|
@@ -4145,6 +4162,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 0b05e25..4f783e5 100644
|
|
--- a/src/backend/access/transam/xlog.c
|
|
+++ b/src/backend/access/transam/xlog.c
|
|
@@ -8765,7 +8765,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 387d43e..aecb449 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 455eac1..0590156 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 dafae3f..c2aea7a 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 2561d83..002a66c 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/fmgroids.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -1499,6 +1501,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;
|
|
@@ -1608,6 +1614,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.
|
|
@@ -1869,6 +1877,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.
|
|
@@ -2063,6 +2073,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.
|
|
@@ -2188,6 +2200,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.
|
|
@@ -2313,6 +2327,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.
|
|
@@ -2831,6 +2847,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.
|
|
@@ -2955,6 +2973,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 3edfc23..b451e59 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 31aabda..c9fc09e 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 d848ef0..deaf2fb 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 69946fe..23fb19b 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"
|
|
@@ -90,7 +91,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,
|
|
@@ -155,7 +157,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
|
|
@@ -182,7 +184,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
|
|
{
|
|
@@ -339,13 +342,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
|
|
*/
|
|
@@ -367,7 +373,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);
|
|
@@ -545,6 +552,7 @@ index_create(Oid heapRelationId,
|
|
bool mapped_relation;
|
|
bool is_exclusion;
|
|
Oid namespaceId;
|
|
+ Oid securityId;
|
|
int i;
|
|
|
|
is_exclusion = (indexInfo->ii_ExclusionOps != NULL);
|
|
@@ -682,15 +690,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);
|
|
@@ -706,7 +720,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 5581346..cf1910a 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;
|
|
}
|
|
|
|
@@ -2903,7 +2907,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);
|
|
}
|
|
}
|
|
@@ -2930,7 +2935,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);
|
|
}
|
|
}
|
|
@@ -2996,9 +3002,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:
|
|
@@ -3016,6 +3025,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
|
|
@@ -3031,8 +3043,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))
|
|
@@ -3045,7 +3055,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();
|
|
}
|
|
@@ -3070,7 +3082,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 582d894..d7b6bd1 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 99085c9..b4c0b3a 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 e3f18bf..572ce01 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 to for large object metadata, for fear of
|
|
diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c
|
|
index 22111a3..cba7274 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 2362268..f6df55e 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 d76e415..f4c74a3 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 76f9e06..0b4dcc3 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 435dfdd..5d86354 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 4964fb3..390a1c1 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 17e1e77..c1c8bfd 100644
|
|
--- a/src/backend/commands/alter.c
|
|
+++ b/src/backend/commands/alter.c
|
|
@@ -289,3 +289,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 ccb4599..394740a 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);
|
|
@@ -1464,7 +1480,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 64792f2..6d71642 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 */
|
|
@@ -1505,6 +1554,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 */
|
|
@@ -1522,6 +1574,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);
|
|
}
|
|
@@ -1536,6 +1590,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);
|
|
}
|
|
@@ -1551,6 +1607,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);
|
|
}
|
|
@@ -1565,6 +1623,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 57ddab0..0c10a64 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 9d46e47..270eb74 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 e7dac22..16360db 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 0bda24a..334b123 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 14356a2..d1f255e 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 9a584ed..f914280 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 94657b8..7cb3634 100644
|
|
--- a/src/backend/commands/indexcmds.c
|
|
+++ b/src/backend/commands/indexcmds.c
|
|
@@ -39,6 +39,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"
|
|
@@ -242,6 +243,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
|
|
@@ -363,7 +368,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);
|
|
@@ -1572,6 +1579,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);
|
|
@@ -1604,6 +1614,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, false))
|
|
@@ -1642,6 +1655,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 283947a..657ff95 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 ac0270f..25b84fd 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);
|
|
@@ -1990,6 +2029,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
|
|
@@ -2112,7 +2153,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 9c07cf3..2e19448 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"
|
|
@@ -319,6 +320,9 @@ RemoveOperator(RemoveFuncStmt *stmt)
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
|
|
NameListToString(operatorName));
|
|
|
|
+ /* SELinux checks */
|
|
+ sepgsql_operator_drop(operOid, false);
|
|
+
|
|
ReleaseSysCache(tup);
|
|
|
|
/*
|
|
@@ -426,6 +430,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 e765382..a54dd3f 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 633a093..a3375b2 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 b0a9a22..57951fe 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 f52e1d8..ecff05d 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 9b5ce65..34ffbe2 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);
|
|
@@ -355,6 +360,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
|
List *old_constraints;
|
|
bool localHasOids;
|
|
int parentOidCount;
|
|
+ int parentSecidCount;
|
|
List *rawDefaults;
|
|
List *cookedDefaults;
|
|
Datum reloptions;
|
|
@@ -362,6 +368,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
|
AttrNumber attnum;
|
|
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
|
Oid ofTypeId;
|
|
+ Oid *secLabels;
|
|
|
|
/*
|
|
* Truncate relname to appropriate length (probably a waste of time, as
|
|
@@ -461,7 +468,8 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
|
*/
|
|
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
|
|
@@ -473,6 +481,16 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
|
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
|
|
@@ -546,7 +564,8 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
|
stmt->oncommit,
|
|
reloptions,
|
|
true,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ secLabels);
|
|
|
|
StoreCatalogInheritance(relationId, inheritOids);
|
|
|
|
@@ -755,6 +774,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),
|
|
@@ -918,6 +940,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);
|
|
@@ -1086,6 +1111,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,
|
|
@@ -1146,6 +1173,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.
|
|
@@ -1191,13 +1219,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 */
|
|
@@ -1325,6 +1355,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;
|
|
@@ -1626,6 +1658,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
|
*supOids = parentOids;
|
|
*supconstr = constraints;
|
|
*supOidCount = parentsWithOids;
|
|
+ *supSecidCount = parentsWithSecids;
|
|
return schema;
|
|
}
|
|
|
|
@@ -1985,6 +2018,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
|
|
@@ -2136,6 +2172,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.
|
|
@@ -2566,6 +2605,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 */
|
|
@@ -2690,7 +2750,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);
|
|
@@ -2762,17 +2822,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
|
|
*/
|
|
@@ -3126,6 +3191,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
|
|
MemoryContext oldCxt;
|
|
List *dropped_attrs = NIL;
|
|
ListCell *lc;
|
|
+ Oid tupSecidInherit = InvalidOid;
|
|
|
|
econtext = GetPerTupleExprContext(estate);
|
|
|
|
@@ -3156,6 +3222,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.
|
|
*/
|
|
@@ -3172,11 +3251,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)
|
|
@@ -3208,6 +3292,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 */
|
|
@@ -3601,7 +3688,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,
|
|
@@ -3615,12 +3702,16 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
|
int32 typmod;
|
|
Form_pg_type tform;
|
|
Expr *defval;
|
|
+ Oid securityId;
|
|
|
|
if (rel->rd_rel->reloftype)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
errmsg("cannot add column to typed table")));
|
|
|
|
+ /* SELinux permission check */
|
|
+ securityId = sepgsql_attribute_create(myrelid, colDef->colname);
|
|
+
|
|
attrdesc = heap_open(AttributeRelationId, RowExclusiveLock);
|
|
|
|
/*
|
|
@@ -3648,6 +3739,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,
|
|
@@ -3655,6 +3753,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);
|
|
@@ -3694,6 +3799,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;
|
|
@@ -3733,7 +3840,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
|
|
|
ReleaseSysCache(typeTuple);
|
|
|
|
- InsertPgAttributeTuple(attrdesc, &attribute, NULL);
|
|
+ InsertPgAttributeTuple(attrdesc, &attribute, NULL, securityId);
|
|
|
|
heap_close(attrdesc, RowExclusiveLock);
|
|
|
|
@@ -3742,6 +3849,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;
|
|
|
|
@@ -3853,7 +3962,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;
|
|
|
|
/*
|
|
@@ -3906,6 +4015,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
|
|
@@ -3917,6 +4051,9 @@ ATExecDropNotNull(Relation rel, const char *colName)
|
|
List *indexoidlist;
|
|
ListCell *indexoidscan;
|
|
|
|
+ /* SELinux checks */
|
|
+ sepgsql_attribute_alter(RelationGetRelid(rel), colName);
|
|
+
|
|
/*
|
|
* lookup the attribute
|
|
*/
|
|
@@ -4007,6 +4144,9 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
|
|
AttrNumber attnum;
|
|
Relation attr_rel;
|
|
|
|
+ /* SELinux checks */
|
|
+ sepgsql_attribute_alter(RelationGetRelid(rel), colName);
|
|
+
|
|
/*
|
|
* lookup the attribute
|
|
*/
|
|
@@ -4057,6 +4197,9 @@ ATExecColumnDefault(Relation rel, const char *colName,
|
|
{
|
|
AttrNumber attnum;
|
|
|
|
+ /* SELinux checks */
|
|
+ sepgsql_attribute_alter(RelationGetRelid(rel), colName);
|
|
+
|
|
/*
|
|
* get the number of the attribute
|
|
*/
|
|
@@ -4131,6 +4274,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);
|
|
|
|
@@ -4197,6 +4343,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);
|
|
@@ -4256,6 +4405,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);
|
|
|
|
@@ -4346,6 +4498,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
|
|
*/
|
|
@@ -4371,8 +4526,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\"",
|
|
@@ -4488,7 +4645,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;
|
|
@@ -4503,7 +4661,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 */
|
|
@@ -4650,6 +4812,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
|
|
@@ -4847,6 +5012,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.
|
|
*
|
|
@@ -5592,6 +5760,9 @@ ATExecDropConstraint(Relation rel, const char *constrName,
|
|
if (recursing)
|
|
ATSimplePermissions(rel, false);
|
|
|
|
+ /* SELinux checks */
|
|
+ sepgsql_relation_alter(RelationGetRelid(rel));
|
|
+
|
|
conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
|
|
|
|
/*
|
|
@@ -5924,6 +6095,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 */
|
|
@@ -6537,6 +6711,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));
|
|
@@ -6702,6 +6878,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))
|
|
@@ -6726,6 +6905,9 @@ ATExecClusterOn(Relation rel, const char *indexName)
|
|
static void
|
|
ATExecDropCluster(Relation rel)
|
|
{
|
|
+ /* SELinux checks */
|
|
+ sepgsql_relation_alter(RelationGetRelid(rel));
|
|
+
|
|
mark_index_clustered(rel, InvalidOid);
|
|
}
|
|
|
|
@@ -6776,6 +6958,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 */
|
|
|
|
@@ -7090,6 +7275,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);
|
|
}
|
|
|
|
@@ -7102,6 +7290,9 @@ static void
|
|
ATExecEnableDisableRule(Relation rel, char *trigname,
|
|
char fires_when)
|
|
{
|
|
+ /* SELinux checks */
|
|
+ sepgsql_relation_alter(RelationGetRelid(rel));
|
|
+
|
|
EnableDisableRule(rel, trigname, fires_when);
|
|
}
|
|
|
|
@@ -7135,6 +7326,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,
|
|
@@ -7487,6 +7682,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
|
|
@@ -7784,6 +7982,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),
|
|
@@ -7981,6 +8182,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 862cd2d..8ea4118 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)
|
|
@@ -787,6 +797,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,
|
|
@@ -868,6 +881,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
|
|
@@ -985,6 +1001,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 2cbc192..2ea9e6e 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 ba3de63..19bebb4 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 1e14dca..f7429f0 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 2f0788e..8de31ae 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 49a206e..4646c41 100644
|
|
--- a/src/backend/commands/vacuum.c
|
|
+++ b/src/backend/commands/vacuum.c
|
|
@@ -980,6 +980,12 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound,
|
|
relation_close(onerel, NoLock);
|
|
|
|
/*
|
|
+ * VACUUM FULL also reclaim orphan security labels, if exist
|
|
+ */
|
|
+ if (vacstmt->options & VACOPT_FULL)
|
|
+ seclabelRelationReclaim(relid);
|
|
+
|
|
+ /*
|
|
* Complete the transaction and free all temporary memory used.
|
|
*/
|
|
PopActiveSnapshot();
|
|
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
|
|
index d7a06bc..5480c83 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 5e555ad..963096d 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 d299310..febb02e 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);
|
|
}
|
|
}
|
|
|
|
@@ -829,6 +841,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
|
|
|
j = ExecInitJunkFilter(planstate->plan->targetlist,
|
|
tupType->tdhasoid,
|
|
+ tupType->tdhassecid,
|
|
ExecInitExtraTupleSlot(estate));
|
|
estate->es_junkFilter = j;
|
|
|
|
@@ -1065,6 +1078,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
|
|
*
|
|
@@ -2073,6 +2117,7 @@ OpenIntoRel(QueryDesc *queryDesc)
|
|
Oid intoRelationId;
|
|
TupleDesc tupdesc;
|
|
DR_intorel *myState;
|
|
+ Oid *secLabels;
|
|
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
|
|
|
Assert(into);
|
|
@@ -2144,6 +2189,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,
|
|
@@ -2174,7 +2227,8 @@ OpenIntoRel(QueryDesc *queryDesc)
|
|
into->onCommit,
|
|
reloptions,
|
|
true,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ secLabels);
|
|
|
|
FreeTupleDesc(tupdesc);
|
|
|
|
@@ -2298,6 +2352,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 005e15e..6e93932 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",
|
|
@@ -4108,6 +4112,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 53fe195..68f790f 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 1caf976..64f6468 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 98e4a64..14f9404 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 d552698..ed1913f 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)
|
|
{
|
|
@@ -1192,7 +1192,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 */
|
|
}
|
|
}
|
|
@@ -1205,7 +1205,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 ddd91fc..cfb685e 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 66e6b74..a31907c 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 ca6b0f8..b5c79d0 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"
|
|
@@ -216,6 +217,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 7856b66..eee2739 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;
|
|
+
|
|
planSlot = ExecProcNode(subplanstate);
|
|
|
|
if (TupIsNull(planSlot))
|
|
@@ -705,6 +760,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.
|
|
*/
|
|
@@ -734,11 +797,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,
|
|
@@ -850,7 +913,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);
|
|
@@ -884,7 +947,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);
|
|
|
|
@@ -976,6 +1039,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 9f1ff16..bef704b 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 712bab1..e69f3c7 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 7f0b5e4..2e2c63b 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 f4f50f8..4ab5698 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 e770e89..9642a66 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)
|
|
{
|
|
@@ -3968,6 +3984,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 5d83727..fd4071d 100644
|
|
--- a/src/backend/nodes/equalfuncs.c
|
|
+++ b/src/backend/nodes/equalfuncs.c
|
|
@@ -1308,6 +1308,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);
|
|
@@ -2186,6 +2199,7 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
|
|
COMPARE_SCALAR_FIELD(checkAsUser);
|
|
COMPARE_BITMAPSET_FIELD(selectedCols);
|
|
COMPARE_BITMAPSET_FIELD(modifiedCols);
|
|
+ COMPARE_SCALAR_FIELD(rowlvPerms);
|
|
|
|
return true;
|
|
}
|
|
@@ -2657,6 +2671,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 e7dae4b..4e8b350 100644
|
|
--- a/src/backend/nodes/outfuncs.c
|
|
+++ b/src/backend/nodes/outfuncs.c
|
|
@@ -2135,6 +2135,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 bc6e2a6..792b9ff 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 3950ab4..18e5d80 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 e525ba6..6474fbc 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"
|
|
@@ -3712,6 +3713,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.
|
|
@@ -4164,7 +4169,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 6b99a10..4eb9d24 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"
|
|
|
|
|
|
@@ -651,7 +653,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 b793c4d..866e0ba 100644
|
|
--- a/src/backend/parser/gram.y
|
|
+++ b/src/backend/parser/gram.y
|
|
@@ -183,8 +183,8 @@ static TypeName *TableFuncTypeName(List *columns);
|
|
%type <node> 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 <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
|
|
%type <list> opt_check_option
|
|
|
|
+%type <value> SecLabelItem
|
|
+
|
|
%type <target> xml_attribute_el
|
|
%type <list> xml_attribute_list xml_attributes
|
|
%type <node> 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
|
|
@@ -1758,6 +1761,20 @@ alter_table_cmd:
|
|
n->subtype = AT_DropOids;
|
|
$$ = (Node *)n;
|
|
}
|
|
+ /* ALTER TABLE <name> SET WITH SECURITY LABEL */
|
|
+ | SET WITH SECURITY LABEL
|
|
+ {
|
|
+ AlterTableCmd *n = makeNode(AlterTableCmd);
|
|
+ n->subtype = AT_AddSecLabel;
|
|
+ $$ = (Node *)n;
|
|
+ }
|
|
+ /* ALTER TABLE <name> SET WITHOUT SECURITY LABEL */
|
|
+ | SET WITHOUT SECURITY LABEL
|
|
+ {
|
|
+ AlterTableCmd *n = makeNode(AlterTableCmd);
|
|
+ n->subtype = AT_DropSecLabel;
|
|
+ $$ = (Node *)n;
|
|
+ }
|
|
/* ALTER TABLE <name> CLUSTER ON <indexname> */
|
|
| CLUSTER ON name
|
|
{
|
|
@@ -6022,6 +6039,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);
|
|
+ }
|
|
+ ;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
@@ -10921,6 +11034,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 38c7e91..fbc4e9f 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 e542dc0..8191f94 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 90d5c76..b78f9ba 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 */
|
|
|
|
@@ -587,6 +591,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;
|
|
|
|
@@ -1368,7 +1375,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.
|
|
@@ -1945,6 +1952,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 aa8f2da..604a72c 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)
|
|
{
|
|
@@ -2120,6 +2128,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())
|
|
@@ -2180,6 +2190,10 @@ 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
|
|
* right away, because at present doing so does not release
|
|
@@ -2241,6 +2255,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;
|
|
}
|
|
|
|
@@ -2276,6 +2293,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;
|
|
}
|
|
@@ -2547,6 +2566,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.
|
|
*/
|
|
@@ -2750,6 +2779,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
|
|
@@ -2906,7 +2947,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 68be146..6ba1d2f 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 c1c5ce9..0f6a446 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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <selinux/selinux.h>
|
|
+#include <selinux/avc.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+/* ------------------------------------------------------------
|
|
+ *
|
|
+ * 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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "sepgsql/hooks.h"
|
|
+#include "sepgsql/sepgsql.h"
|
|
+
|
|
+#include <libgen.h>
|
|
+#ifdef HAVE_SELINUX
|
|
+#include <selinux/selinux.h>
|
|
+#endif
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#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..7ab355c
|
|
--- /dev/null
|
|
+++ b/src/backend/sepgsql/label.c
|
|
@@ -0,0 +1,656 @@
|
|
+/*
|
|
+ * label.c
|
|
+ * SE-PostgreSQL security label management
|
|
+ *
|
|
+ * Copyright (C) 2006-2010, NEC Corporation
|
|
+ * KaiGai Kohei <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <fnmatch.h> // for workaround hack
|
|
+#include <selinux/selinux.h>
|
|
+
|
|
+/*
|
|
+ * 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;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * a workaround implementation until libselinux/refpolicy don't
|
|
+ * support db_schema or other object classes.
|
|
+ */
|
|
+static struct {
|
|
+ uint16 tclass;
|
|
+ char *pattern;
|
|
+ char *context;
|
|
+} initial_label_catalog[] = {
|
|
+ {SEPG_CLASS_DB_DATABASE, "*",
|
|
+ "system_u:object_r:sepgsql_db_t:s0"},
|
|
+ {SEPG_CLASS_DB_SCHEMA, "*.*",
|
|
+ "system_u:object_r:sepgsql_db_t:s0"},
|
|
+ {SEPG_CLASS_DB_TABLE, "*.pg_catalog.*",
|
|
+ "system_u:object_r:sepgsql_sysobj_t:s0"},
|
|
+ {SEPG_CLASS_DB_TABLE, "*.*.*",
|
|
+ "system_u:object_r:sepgsql_table_t:s0"},
|
|
+ {SEPG_CLASS_DB_VIEW, "*.*.*",
|
|
+ "system_u:object_r:sepgsql_db_t:s0"},
|
|
+ {SEPG_CLASS_DB_SEQUENCE, "*.*.*",
|
|
+ "system_u:object_r:sepgsql_db_t:s0"},
|
|
+ {SEPG_CLASS_DB_PROCEDURE, "*.pg_catalog.*",
|
|
+ "system_u:object_r:sepgsql_proc_exec_t:s0"},
|
|
+ {SEPG_CLASS_DB_PROCEDURE, "*.*.*",
|
|
+ "system_u:object_r:sepgsql_user_proc_exec_t:s0"},
|
|
+ {SEPG_CLASS_DB_COLUMN, "*.pg_catalog.*.*",
|
|
+ "system_u:object_r:sepgsql_sysobj_t:s0"},
|
|
+ {SEPG_CLASS_DB_COLUMN, "*.*.*.*",
|
|
+ "system_u:object_r:sepgsql_table_t:s0"},
|
|
+ {SEPG_CLASS_DB_TUPLE, "*.pg_catalog.*",
|
|
+ "system_u:object_r:sepgsql_sysobj_t:s0"},
|
|
+ {SEPG_CLASS_DB_TUPLE, "*.*.*",
|
|
+ "system_u:object_r:sepgsql_table_t:s0"},
|
|
+ {SEPG_CLASS_DB_BLOB, "*.*",
|
|
+ "system_u:object_r:sepgsql_blob_t:s0"},
|
|
+ {0, NULL, NULL},
|
|
+};
|
|
+
|
|
+static char *
|
|
+lookup_init_catalog(uint16 tclass, const char *name)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; initial_label_catalog[i].pattern; i++)
|
|
+ {
|
|
+ if (initial_label_catalog[i].tclass == tclass &&
|
|
+ fnmatch(initial_label_catalog[i].pattern, name, 0) == 0)
|
|
+ return initial_label_catalog[i].context;
|
|
+ }
|
|
+ elog(ERROR, "no valid initial security context for %s (tclass=%d)",
|
|
+ name, tclass);
|
|
+ return NULL; /* for compiler quiet */
|
|
+}
|
|
+
|
|
+static char *
|
|
+lookup_init_tuple_label(Oid relOid, HeapTuple tuple)
|
|
+{
|
|
+ Oid relNsp = get_rel_namespace(relOid);
|
|
+ char namebuf[NAMEDATALEN * 3 + 10];
|
|
+
|
|
+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s",
|
|
+ get_database_name(MyDatabaseId),
|
|
+ get_namespace_name(relNsp),
|
|
+ get_rel_name(relOid));
|
|
+
|
|
+ return lookup_init_catalog(SEPG_CLASS_DB_TUPLE, namebuf);
|
|
+}
|
|
+
|
|
+static char *
|
|
+lookup_init_database_label(HeapTuple tuple)
|
|
+{
|
|
+ Form_pg_database datForm = (Form_pg_database) GETSTRUCT(tuple);
|
|
+
|
|
+ return lookup_init_catalog(SEPG_CLASS_DB_DATABASE,
|
|
+ NameStr(datForm->datname));
|
|
+}
|
|
+
|
|
+static char *
|
|
+lookup_init_schema_label(HeapTuple tuple)
|
|
+{
|
|
+ Form_pg_namespace nspForm = (Form_pg_namespace) GETSTRUCT(tuple);
|
|
+ char namebuf[NAMEDATALEN * 2 + 10];
|
|
+
|
|
+ snprintf(namebuf, sizeof(namebuf), "%s.%s",
|
|
+ get_database_name(MyDatabaseId),
|
|
+ NameStr(nspForm->nspname));
|
|
+
|
|
+ return lookup_init_catalog(SEPG_CLASS_DB_SCHEMA, namebuf);
|
|
+}
|
|
+
|
|
+static char *
|
|
+lookup_init_relation_label(HeapTuple tuple)
|
|
+{
|
|
+ Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+ const char *relName = NameStr(classForm->relname);
|
|
+ Oid relNsp = classForm->relnamespace;
|
|
+ char *seclabel;
|
|
+ char namebuf[NAMEDATALEN * 3 + 10];
|
|
+
|
|
+ switch (classForm->relkind)
|
|
+ {
|
|
+ case RELKIND_RELATION:
|
|
+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s",
|
|
+ get_database_name(MyDatabaseId),
|
|
+ get_namespace_name(relNsp), relName);
|
|
+ seclabel = lookup_init_catalog(SEPG_CLASS_DB_TABLE, namebuf);
|
|
+ break;
|
|
+
|
|
+ case RELKIND_SEQUENCE:
|
|
+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s",
|
|
+ get_database_name(MyDatabaseId),
|
|
+ get_namespace_name(relNsp), relName);
|
|
+ seclabel = lookup_init_catalog(SEPG_CLASS_DB_SEQUENCE, namebuf);
|
|
+ break;
|
|
+
|
|
+ case RELKIND_VIEW:
|
|
+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s",
|
|
+ get_database_name(MyDatabaseId),
|
|
+ get_namespace_name(relNsp), relName);
|
|
+ seclabel = lookup_init_catalog(SEPG_CLASS_DB_VIEW, namebuf);
|
|
+ break;
|
|
+
|
|
+ case RELKIND_INDEX: {
|
|
+ HeapTuple tbltup;
|
|
+ HeapTuple indtup;
|
|
+ Oid tblOid;
|
|
+ Oid indOid = HeapTupleGetOid(tuple);
|
|
+
|
|
+ indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indOid));
|
|
+ if (!HeapTupleIsValid(indtup))
|
|
+ elog(ERROR, "cache lookup failed for index %u", indOid);
|
|
+
|
|
+ tblOid = ((Form_pg_index) GETSTRUCT(indtup))->indrelid;
|
|
+ tbltup = SearchSysCache1(RELOID, ObjectIdGetDatum(tblOid));
|
|
+ if (!HeapTupleIsValid(tbltup))
|
|
+ elog(ERROR, "cache lookup failed for relation %u", tblOid);
|
|
+
|
|
+ seclabel = lookup_init_relation_label(tbltup);
|
|
+
|
|
+ ReleaseSysCache(tbltup);
|
|
+ ReleaseSysCache(indtup);
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ case RELKIND_TOASTVALUE: {
|
|
+ HeapTuple tbltup;
|
|
+ Oid tblOid;
|
|
+
|
|
+ /*
|
|
+ * 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
|
|
+ */
|
|
+ tblOid = strtoul(relName + 9, NULL, 10);
|
|
+
|
|
+ tbltup = SearchSysCache1(RELOID,
|
|
+ ObjectIdGetDatum(tblOid));
|
|
+ if (!HeapTupleIsValid(tbltup))
|
|
+ elog(ERROR, "cache lookup failed for relation %u", tblOid);
|
|
+
|
|
+ seclabel = lookup_init_relation_label(tbltup);
|
|
+
|
|
+ ReleaseSysCache(tbltup);
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ case RELKIND_COMPOSITE_TYPE: {
|
|
+ Oid typOid = classForm->reltype;
|
|
+ HeapTuple typtup;
|
|
+
|
|
+ typtup = SearchSysCache1(TYPEOID,
|
|
+ ObjectIdGetDatum(typOid));
|
|
+ if (!HeapTupleIsValid(typtup))
|
|
+ elog(ERROR, "cache lookup failed for type %u", typOid);
|
|
+
|
|
+ seclabel = lookup_init_tuple_label(TypeRelationId, typtup);
|
|
+
|
|
+ ReleaseSysCache(typtup);
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ elog(ERROR, "unexpected relkind %c of \"%s\"",
|
|
+ classForm->relkind, relName);
|
|
+ seclabel = NULL; /* compiler quiet */
|
|
+ break;
|
|
+ }
|
|
+ return seclabel;
|
|
+}
|
|
+
|
|
+static char *
|
|
+lookup_init_attribute_label(HeapTuple tuple)
|
|
+{
|
|
+ Form_pg_attribute attForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ Oid tblOid = attForm->attrelid;
|
|
+ char *seclabel;
|
|
+ char namebuf[NAMEDATALEN * 4 + 10];
|
|
+
|
|
+ if (get_rel_relkind(tblOid) == RELKIND_RELATION)
|
|
+ {
|
|
+ Oid tblNsp = get_rel_namespace(tblOid);
|
|
+
|
|
+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s.%s",
|
|
+ get_database_name(MyDatabaseId),
|
|
+ get_namespace_name(tblNsp),
|
|
+ get_rel_name(tblOid),
|
|
+ NameStr(attForm->attname));
|
|
+
|
|
+ seclabel = lookup_init_catalog(SEPG_CLASS_DB_COLUMN, namebuf);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ HeapTuple tbltup;
|
|
+
|
|
+ tbltup = SearchSysCache1(RELOID, ObjectIdGetDatum(tblOid));
|
|
+ if (!HeapTupleIsValid(tbltup))
|
|
+ elog(ERROR, "cache lookup failed for relation %u", tblOid);
|
|
+
|
|
+ seclabel = lookup_init_relation_label(tbltup);
|
|
+
|
|
+ ReleaseSysCache(tbltup);
|
|
+ }
|
|
+ return seclabel;
|
|
+}
|
|
+
|
|
+static char *
|
|
+lookup_init_procedure_label(HeapTuple tuple)
|
|
+{
|
|
+ Form_pg_proc proForm = (Form_pg_proc) GETSTRUCT(tuple);
|
|
+ Oid proNsp = proForm->pronamespace;
|
|
+ char namebuf[NAMEDATALEN * 3 + 10];
|
|
+
|
|
+ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s",
|
|
+ get_database_name(MyDatabaseId),
|
|
+ get_namespace_name(proNsp),
|
|
+ NameStr(proForm->proname));
|
|
+
|
|
+ return lookup_init_catalog(SEPG_CLASS_DB_PROCEDURE, namebuf);
|
|
+}
|
|
+
|
|
+static char *
|
|
+lookup_init_largeobject_label(HeapTuple tuple)
|
|
+{
|
|
+ char namebuf[NAMEDATALEN + 20];
|
|
+
|
|
+ snprintf(namebuf, sizeof(namebuf), "%s.%u",
|
|
+ get_database_name(MyDatabaseId),
|
|
+ HeapTupleGetOid(tuple));
|
|
+
|
|
+ return lookup_init_catalog(SEPG_CLASS_DB_BLOB, namebuf);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsql_initial_labeling(void)
|
|
+{
|
|
+ Relation classRel;
|
|
+ SysScanDesc classScan;
|
|
+ ScanKeyData classSkey;
|
|
+ HeapTuple classTup;
|
|
+ Relation rel;
|
|
+ HeapScanDesc scan;
|
|
+ HeapTuple oldtup;
|
|
+ HeapTuple newtup;
|
|
+
|
|
+ Assert(IsBootstrapProcessingMode());
|
|
+
|
|
+ StartTransactionCommand();
|
|
+
|
|
+ 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)))
|
|
+ {
|
|
+ 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)))
|
|
+ {
|
|
+ char *label;
|
|
+ Oid secid;
|
|
+
|
|
+ switch (relOid)
|
|
+ {
|
|
+ case DatabaseRelationId:
|
|
+ label = lookup_init_database_label(oldtup);
|
|
+ break;
|
|
+
|
|
+ case NamespaceRelationId:
|
|
+ label = lookup_init_schema_label(oldtup);
|
|
+ break;
|
|
+
|
|
+ case RelationRelationId:
|
|
+ label = lookup_init_relation_label(oldtup);
|
|
+ break;
|
|
+
|
|
+ case AttributeRelationId:
|
|
+ label = lookup_init_attribute_label(oldtup);
|
|
+ break;
|
|
+
|
|
+ case ProcedureRelationId:
|
|
+ label = lookup_init_procedure_label(oldtup);
|
|
+ break;
|
|
+
|
|
+ case LargeObjectMetadataRelationId:
|
|
+ label = lookup_init_largeobject_label(oldtup);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ label = lookup_init_tuple_label(relOid, oldtup);
|
|
+ break;
|
|
+ }
|
|
+ /*
|
|
+ * inplace-updating
|
|
+ */
|
|
+ newtup = heap_copytuple(oldtup);
|
|
+
|
|
+ secid = seclabelTransInput(relOid, label);
|
|
+
|
|
+ HeapTupleSetSecid(newtup, secid);
|
|
+
|
|
+ heap_inplace_update(rel, newtup);
|
|
+
|
|
+ heap_freetuple(newtup);
|
|
+ }
|
|
+ heap_endscan(scan);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
+ systable_endscan(classScan);
|
|
+
|
|
+ heap_close(classRel, AccessShareLock);
|
|
+
|
|
+ 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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <selinux/selinux.h>
|
|
+
|
|
+/*
|
|
+ * 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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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..1078777
|
|
--- /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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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;
|
|
+ bool result;
|
|
+
|
|
+ /* 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;
|
|
+ default: /* index, toast */
|
|
+ tclass = SEPG_CLASS_DB_TABLE;
|
|
+ break;
|
|
+ }
|
|
+ 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:
|
|
+ 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;
|
|
+
|
|
+ default:
|
|
+ tclass = SEPG_CLASS_DB_TUPLE;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* do permission check */
|
|
+ tsid.relid = RelationGetRelid(rel);
|
|
+ tsid.secid = HeapTupleGetSecid(tuple);
|
|
+
|
|
+ result = sepgsql_client_perms(tsid, tclass, required, NULL, abort);
|
|
+
|
|
+ if (!result)
|
|
+ elog(NOTICE, "denied: oid=%u tsid(relid=%u, secid=%u) label=%s tclass=%d required=%u", HeapTupleGetOid(tuple), tsid.relid, tsid.secid, seclabelRawOutput(tsid.relid, tsid.secid), tclass, required);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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/selinux.h>
|
|
+
|
|
+/*
|
|
+ * 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_<class>__<perms>
|
|
+ * 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_<class>__<perm>)
|
|
+ * 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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 ca48cdd..bb0688f 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 575fa86..eb2b5e8 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"
|
|
@@ -347,6 +348,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);
|
|
+
|
|
/*
|
|
* Prepare function call info block and insert arguments.
|
|
*/
|
|
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
|
|
index 8ad4915..54961d8 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 8960246..e8f8ea3 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:
|
|
@@ -696,6 +697,10 @@ standard_ProcessUtility(Node *parsetree,
|
|
ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
|
|
break;
|
|
|
|
+ case T_AlterSecLabelStmt:
|
|
+ ExecAlterSecLabelStmt((AlterSecLabelStmt *) parsetree);
|
|
+ break;
|
|
+
|
|
case T_AlterTableStmt:
|
|
{
|
|
List *stmts;
|
|
@@ -1760,6 +1765,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)
|
|
{
|
|
@@ -2352,6 +2397,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 0fed35c..ca9e9d1 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 faad11e..53e6944 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 ed81ced..f3d4b99 100644
|
|
--- a/src/backend/utils/adt/datetime.c
|
|
+++ b/src/backend/utils/adt/datetime.c
|
|
@@ -4193,7 +4193,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",
|
|
@@ -4286,7 +4286,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 a4e0252..36d07b7 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 e074b79..8bb707f 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 07e6aab..e5c8182 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 11342b2..0ddf907 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 8379407..d44655b 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 9db070d..6881976 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 c837e67..1bf4eb8 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 70246fb..b996537 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 78f08f4..4a44810 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 88d8d8b..281acb0 100644
|
|
--- a/src/backend/utils/cache/plancache.c
|
|
+++ b/src/backend/utils/cache/plancache.c
|
|
@@ -924,12 +924,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;
|
|
@@ -940,13 +940,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 d462510..c704bc9 100644
|
|
--- a/src/backend/utils/cache/relcache.c
|
|
+++ b/src/backend/utils/cache/relcache.c
|
|
@@ -216,7 +216,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);
|
|
@@ -355,7 +355,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;
|
|
|
|
@@ -437,6 +438,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));
|
|
@@ -1396,7 +1398,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;
|
|
@@ -1459,6 +1461,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;
|
|
|
|
/*
|
|
@@ -1468,7 +1471,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;
|
|
@@ -2551,6 +2554,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: */
|
|
@@ -2793,11 +2797,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 */
|
|
}
|
|
@@ -2848,13 +2852,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 */
|
|
}
|
|
@@ -3007,6 +3011,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);
|
|
|
|
@@ -3117,7 +3122,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;
|
|
@@ -3125,7 +3130,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;
|
|
|
|
@@ -3155,7 +3160,7 @@ GetPgClassDescriptor(void)
|
|
if (pgclassdesc == NULL)
|
|
pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
|
|
Desc_pg_class,
|
|
- true);
|
|
+ true, true);
|
|
|
|
return pgclassdesc;
|
|
}
|
|
@@ -3169,7 +3174,7 @@ GetPgIndexDescriptor(void)
|
|
if (pgindexdesc == NULL)
|
|
pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
|
|
Desc_pg_index,
|
|
- false);
|
|
+ false, false);
|
|
|
|
return pgindexdesc;
|
|
}
|
|
@@ -3985,7 +3990,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 61b06ac..b08654b 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 c3c0440..fb5b762 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 382008c..e6eba47 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 179d009..4bd7314 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"
|
|
@@ -304,6 +305,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.
|
|
*
|
|
@@ -800,6 +804,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 920daeb..44fd3a9 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/fd.h"
|
|
#include "tcop/tcopprot.h"
|
|
@@ -337,6 +339,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
|
|
*/
|
|
@@ -366,6 +380,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;
|
|
@@ -1094,6 +1109,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
|
|
@@ -1261,6 +1284,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
|
|
@@ -2820,7 +2873,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 */
|
|
{
|
|
@@ -6113,7 +6175,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",
|
|
@@ -6129,7 +6191,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);
|
|
}
|
|
@@ -6152,7 +6214,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);
|
|
|
|
@@ -6179,7 +6241,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",
|
|
@@ -6574,7 +6636,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 2ed8412..10f8947 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 ac62d45..f05a094 100644
|
|
--- a/src/backend/utils/mmgr/portalmem.c
|
|
+++ b/src/backend/utils/mmgr/portalmem.c
|
|
@@ -894,7 +894,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 f40ad87..497bdf0 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 14fe652..40b7b40 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 6bbe2de..9da50b0 100644
|
|
--- a/src/bin/pg_dump/pg_backup_archiver.c
|
|
+++ b/src/bin/pg_dump/pg_backup_archiver.c
|
|
@@ -540,6 +540,8 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te,
|
|
}
|
|
else
|
|
{
|
|
+ bool need_reset = false;
|
|
+
|
|
_disableTriggersIfNecessary(AH, te, ropt);
|
|
|
|
/* Select owner and schema as necessary */
|
|
@@ -575,6 +577,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
|
|
@@ -595,6 +607,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);
|
|
@@ -712,7 +727,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,
|
|
@@ -744,6 +759,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);
|
|
@@ -2027,6 +2043,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++)
|
|
@@ -2138,6 +2155,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)
|
|
{
|
|
@@ -2256,6 +2283,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->create && strcmp(te->desc, "DATABASE") == 0)
|
|
return 0;
|
|
@@ -2322,6 +2352,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
|
|
@@ -2473,6 +2505,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.
|
|
@@ -2571,6 +2633,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
|
|
@@ -2808,9 +2882,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 2e944c1..67f62ac 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 2431d71..e7ef296 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,
|
|
@@ -515,6 +523,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)
|
|
{
|
|
@@ -833,6 +845,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"));
|
|
@@ -1127,7 +1140,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 */
|
|
|
|
@@ -1251,14 +1264,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));
|
|
}
|
|
@@ -1398,7 +1413,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;
|
|
}
|
|
@@ -1412,7 +1427,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);
|
|
@@ -1457,6 +1472,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;
|
|
@@ -1780,6 +1796,7 @@ dumpDatabase(Archive *AH)
|
|
NULL, /* Tablespace */
|
|
dba, /* Owner */
|
|
false, /* with oids */
|
|
+ false, /* with secids */
|
|
"DATABASE", /* Desc */
|
|
SECTION_PRE_DATA, /* Section */
|
|
creaQry->data, /* Create */
|
|
@@ -1825,7 +1842,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);
|
|
@@ -1857,7 +1874,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);
|
|
}
|
|
@@ -1896,7 +1913,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);
|
|
@@ -1923,7 +1940,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);
|
|
@@ -1956,16 +1973,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);
|
|
@@ -1995,6 +2013,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;
|
|
}
|
|
|
|
/*
|
|
@@ -2034,7 +2057,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,
|
|
@@ -2049,6 +2072,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",
|
|
@@ -2356,6 +2383,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
|
|
@@ -2372,6 +2400,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]);
|
|
|
|
@@ -2382,6 +2411,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]);
|
|
|
|
@@ -2402,8 +2432,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);
|
|
@@ -2417,6 +2447,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++)
|
|
{
|
|
@@ -2427,6 +2458,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]);
|
|
@@ -2515,6 +2547,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
|
|
@@ -2547,8 +2580,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)
|
|
{
|
|
@@ -2561,6 +2596,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);
|
|
}
|
|
@@ -2575,6 +2611,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);
|
|
}
|
|
@@ -2591,6 +2628,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);
|
|
}
|
|
@@ -2615,6 +2653,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++)
|
|
{
|
|
@@ -2642,6 +2681,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]);
|
|
|
|
@@ -3407,6 +3448,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;
|
|
@@ -3414,6 +3456,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");
|
|
@@ -3450,6 +3493,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, "
|
|
@@ -3457,6 +3501,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 "
|
|
@@ -3467,6 +3512,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);
|
|
@@ -3483,6 +3529,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, "
|
|
@@ -3490,6 +3537,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 "
|
|
@@ -3500,6 +3548,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);
|
|
@@ -3516,6 +3565,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, "
|
|
@@ -3523,6 +3573,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 "
|
|
@@ -3548,6 +3599,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, "
|
|
@@ -3555,6 +3607,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 "
|
|
@@ -3580,6 +3633,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, "
|
|
@@ -3587,6 +3641,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 "
|
|
@@ -3608,6 +3663,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, "
|
|
@@ -3615,6 +3671,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",
|
|
@@ -3631,6 +3688,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, "
|
|
@@ -3638,6 +3696,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",
|
|
@@ -3671,6 +3730,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",
|
|
@@ -3709,6 +3769,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");
|
|
@@ -3716,6 +3777,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)
|
|
{
|
|
@@ -3748,6 +3810,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;
|
|
@@ -3767,6 +3830,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 */
|
|
|
|
@@ -5082,6 +5146,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|
int i_attalign;
|
|
int i_attislocal;
|
|
int i_attoptions;
|
|
+ int i_seclabel;
|
|
PGresult *res;
|
|
int ntups;
|
|
bool hasdefaults;
|
|
@@ -5128,11 +5193,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)
|
|
@@ -5144,6 +5211,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 "
|
|
@@ -5165,6 +5233,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 "
|
|
@@ -5183,6 +5252,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 "
|
|
@@ -5209,6 +5279,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 *));
|
|
@@ -5227,6 +5298,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++)
|
|
@@ -5256,6 +5328,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);
|
|
@@ -6146,7 +6219,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);
|
|
@@ -6207,7 +6280,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);
|
|
@@ -6229,7 +6302,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);
|
|
@@ -6509,7 +6582,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);
|
|
@@ -6549,7 +6622,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);
|
|
@@ -6561,6 +6634,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);
|
|
@@ -6678,7 +6754,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,
|
|
@@ -6692,6 +6768,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);
|
|
@@ -7054,7 +7136,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,
|
|
@@ -7068,6 +7150,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);
|
|
@@ -7178,7 +7266,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,
|
|
@@ -7192,6 +7280,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);
|
|
@@ -7283,7 +7377,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,
|
|
@@ -7298,6 +7392,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);
|
|
@@ -7402,7 +7502,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);
|
|
@@ -7454,7 +7554,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,
|
|
@@ -7609,7 +7709,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);
|
|
@@ -7795,6 +7895,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
char **argmodes = NULL;
|
|
char **argnames = NULL;
|
|
char **configitems = NULL;
|
|
+ char *proseclabel;
|
|
int nconfigitems = 0;
|
|
int i;
|
|
|
|
@@ -7825,8 +7926,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)
|
|
@@ -7838,6 +7941,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);
|
|
@@ -7851,6 +7955,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);
|
|
@@ -7866,6 +7971,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);
|
|
@@ -7881,6 +7987,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);
|
|
@@ -7898,6 +8005,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);
|
|
@@ -7915,6 +8023,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);
|
|
@@ -7959,6 +8068,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
|
|
@@ -8169,7 +8279,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,
|
|
@@ -8182,6 +8292,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,
|
|
@@ -8323,7 +8439,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);
|
|
@@ -8567,7 +8683,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);
|
|
@@ -9026,7 +9142,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);
|
|
@@ -9307,7 +9423,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);
|
|
@@ -9423,7 +9539,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);
|
|
@@ -9504,11 +9620,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 */
|
|
@@ -9531,9 +9649,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)
|
|
@@ -9543,6 +9663,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",
|
|
@@ -9555,6 +9676,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);
|
|
@@ -9567,6 +9689,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);
|
|
@@ -9592,6 +9715,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);
|
|
@@ -9599,6 +9723,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);
|
|
@@ -9667,7 +9792,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);
|
|
@@ -9679,6 +9804,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
|
|
@@ -9755,7 +9886,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);
|
|
@@ -9847,7 +9978,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);
|
|
@@ -9907,7 +10038,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);
|
|
@@ -10040,7 +10171,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);
|
|
@@ -10096,7 +10227,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);
|
|
@@ -10183,7 +10314,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);
|
|
@@ -10279,7 +10410,7 @@ dumpUserMappings(Archive *fout, const char *target,
|
|
tag->data,
|
|
namespace,
|
|
NULL,
|
|
- owner, false,
|
|
+ owner, false, false,
|
|
"USER MAPPING", SECTION_PRE_DATA,
|
|
q->data, delq->data, NULL,
|
|
&dumpId, 1,
|
|
@@ -10350,7 +10481,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);
|
|
@@ -10407,7 +10538,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);
|
|
@@ -10416,6 +10547,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
|
|
*/
|
|
@@ -10571,7 +10819,6 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
|
|
|
appendPQExpBuffer(q, "CREATE VIEW %s AS\n %s\n",
|
|
fmtId(tbinfo->dobj.name), viewdef);
|
|
-
|
|
PQclear(res);
|
|
}
|
|
else
|
|
@@ -10922,6 +11169,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,
|
|
@@ -10942,6 +11190,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);
|
|
@@ -10990,7 +11259,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);
|
|
@@ -11086,7 +11355,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,
|
|
@@ -11211,7 +11480,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,
|
|
@@ -11244,7 +11513,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,
|
|
@@ -11279,7 +11548,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,
|
|
@@ -11315,7 +11584,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,
|
|
@@ -11601,7 +11870,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);
|
|
@@ -11637,7 +11906,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);
|
|
@@ -11650,6 +11919,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)
|
|
@@ -11665,7 +11940,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);
|
|
@@ -11849,7 +12124,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,
|
|
@@ -11969,7 +12244,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,
|
|
@@ -12334,7 +12609,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;
|
|
@@ -12350,6 +12625,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 c93bada..78a50bd 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 0c3f63f..83f1678 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,
|
|
@@ -330,6 +334,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 (optind < argc)
|
|
{
|
|
@@ -561,6 +567,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"));
|
|
@@ -949,6 +956,7 @@ dropTablespaces(PGconn *conn)
|
|
static void
|
|
dumpTablespaces(PGconn *conn)
|
|
{
|
|
+ PQExpBuffer qry = createPQExpBuffer();
|
|
PGresult *res;
|
|
int i;
|
|
|
|
@@ -957,31 +965,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");
|
|
|
|
@@ -994,6 +1008,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() */
|
|
@@ -1010,6 +1025,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))
|
|
@@ -1153,48 +1172,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'))), "
|
|
@@ -1202,6 +1221,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
|
|
@@ -1210,18 +1230,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);
|
|
@@ -1234,6 +1256,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));
|
|
@@ -1309,6 +1332,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 b0bcbc2..cdb2592 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,
|
|
@@ -326,6 +330,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)
|
|
{
|
|
@@ -437,6 +442,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 d87e888..270ff67 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 59cd2cd..ad5903b 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 53e0be6..dea713b 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 49a32e3..f088876 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 8292273..e2a86e8 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 4f437fd..069256f 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 5ea514d..0f07482 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 d40dea6..add5fd9 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 c4c4a26..6025f56 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 425f039..0f8043d 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 f2751a4..3e024b3 100644
|
|
--- a/src/include/catalog/pg_proc.h
|
|
+++ b/src/include/catalog/pg_proc.h
|
|
@@ -3719,6 +3719,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 c886f81..f2351c1 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 5cf90af..1ca2dd4 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 fb6f678..f642ded 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 b1e04fb..6cd19ba 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 542fc27..874e07a 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 e8dbe81..7fc4922 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 c914bd5..edd5abd 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 f9269cc..a531f45 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 cf005ee..e9e8a55 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 8e5b610..f8c5872 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 820314c..7873b44 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);
|
|
@@ -164,6 +164,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 TupleTableSlot *EvalPlanQual(EState *estate, EPQState *epqstate,
|
|
@@ -234,8 +235,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 d1a0dc1..e9de809 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 1b5e476..37ffdfa 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 b591073..53609e8 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 */
|
|
@@ -2073,6 +2076,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 49d4b6c..13c88a1 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 684aed4..2080c95 100644
|
|
--- a/src/include/pg_config.h.in
|
|
+++ b/src/include/pg_config.h.in
|
|
@@ -412,6 +412,9 @@
|
|
/* Define to 1 if you have the <security/pam_appl.h> 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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 <kaigai@ak.jp.nec.com>
|
|
+ */
|
|
+#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 43a61f3..6385b5c 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 4eece8b..4176eac 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 c22c65a..5b94283 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 2f19e5c..6744782 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 656ea73..2ce4e94 100644
|
|
--- a/src/pl/plpgsql/src/pl_comp.c
|
|
+++ b/src/pl/plpgsql/src/pl_comp.c
|
|
@@ -1936,7 +1936,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
|