12650 lines
367 KiB
Diff
12650 lines
367 KiB
Diff
diff -rpNU3 base/configure sepgsql/configure
|
|
--- base/configure 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/configure 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -314,7 +314,7 @@ ac_includes_default="\
|
|
# include <unistd.h>
|
|
#endif"
|
|
|
|
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS configure_args build build_cpu build_vendor build_os host host_cpu host_vendor host_os PORTNAME docdir enable_nls WANTED_LANGUAGES default_port enable_shared enable_rpath enable_debug enable_profiling DTRACE DTRACEFLAGS enable_dtrace CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP GCC TAS autodepend INCLUDES enable_thread_safety with_tcl with_perl with_python with_gssapi with_krb5 krb_srvtab with_pam with_ldap with_bonjour with_openssl with_ossp_uuid XML2_CONFIG with_libxml with_libxslt with_system_tzdata with_zlib EGREP ELF_SYS LDFLAGS_SL LD with_gnu_ld ld_R_works RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP STRIP_STATIC_LIB STRIP_SHARED_LIB TAR LN_S AWK YACC YFLAGS FLEX FLEXFLAGS PERL perl_archlibexp perl_privlibexp perl_useshrplib perl_embed_ldflags PYTHON python_version python_configdir python_includespec python_libdir python_libspec python_additional_libs OSSP_UUID_LIBS HAVE_IPV6 LIBOBJS acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS LDAP_LIBS_FE LDAP_LIBS_BE HAVE_POSIX_SIGNALS MSGFMT MSGMERGE XGETTEXT localedir TCLSH TCL_CONFIG_SH TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIBS TCL_LIB_SPEC TCL_SHARED_BUILD TCL_SHLIB_LD_LIBS NSGMLS JADE have_docbook DOCBOOKSTYLE COLLATEINDEX SGMLSPL vpath_build LTLIBOBJS'
|
|
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS configure_args build build_cpu build_vendor build_os host host_cpu host_vendor host_os PORTNAME docdir enable_nls WANTED_LANGUAGES default_port enable_shared enable_rpath enable_debug enable_profiling DTRACE DTRACEFLAGS enable_dtrace CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP GCC TAS autodepend INCLUDES enable_thread_safety with_tcl with_perl with_python with_gssapi with_krb5 krb_srvtab with_pam with_ldap with_bonjour with_openssl with_ossp_uuid XML2_CONFIG with_libxml with_libxslt with_system_tzdata with_zlib enable_selinux EGREP ELF_SYS LDFLAGS_SL LD with_gnu_ld ld_R_works RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP STRIP_STATIC_LIB STRIP_SHARED_LIB TAR LN_S AWK YACC YFLAGS FLEX FLEXFLAGS PERL perl_archlibexp perl_privlibexp perl_useshrplib perl_embed_ldflags PYTHON python_version python_configdir python_includespec python_libdir python_libspec python_additional_libs OSSP_UUID_LIBS HAVE_IPV6 LIBOBJS acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS LDAP_LIBS_FE LDAP_LIBS_BE HAVE_POSIX_SIGNALS MSGFMT MSGMERGE XGETTEXT localedir TCLSH TCL_CONFIG_SH TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIBS TCL_LIB_SPEC TCL_SHARED_BUILD TCL_SHLIB_LD_LIBS NSGMLS JADE have_docbook DOCBOOKSTYLE COLLATEINDEX SGMLSPL vpath_build LTLIBOBJS'
|
|
ac_subst_files=''
|
|
|
|
# Initialize some variables set by options.
|
|
@@ -871,6 +871,7 @@ Optional Features:
|
|
--enable-cassert enable assertion checks (for debugging)
|
|
--enable-thread-safety make client libraries thread-safe
|
|
--enable-thread-safety-force force thread-safety despite thread test failure
|
|
+ --enable-selinux build with SELinux support
|
|
--disable-largefile omit support for large files
|
|
|
|
Optional Packages:
|
|
@@ -4619,6 +4620,115 @@ fi;
|
|
|
|
|
|
#
|
|
+# SELinux support
|
|
+#
|
|
+
|
|
+pgac_args="$pgac_args enable_selinux"
|
|
+
|
|
+# Check whether --enable-selinux or --disable-selinux was given.
|
|
+if test "${enable_selinux+set}" = set; then
|
|
+ enableval="$enable_selinux"
|
|
+
|
|
+ case $enableval in
|
|
+ yes)
|
|
+ :
|
|
+ ;;
|
|
+ no)
|
|
+ :
|
|
+ ;;
|
|
+ *)
|
|
+ { { echo "$as_me:$LINENO: error: no argument expected for --enable-selinux option" >&5
|
|
+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
|
|
+ echo "$as_me:$LINENO: checking for getpeercon in -lselinux" >&5
|
|
+echo $ECHO_N "checking for getpeercon in -lselinux... $ECHO_C" >&6
|
|
+if test "${ac_cv_lib_selinux_getpeercon+set}" = set; then
|
|
+ echo $ECHO_N "(cached) $ECHO_C" >&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 gcc2 internal prototype to avoid an error. */
|
|
+#ifdef __cplusplus
|
|
+extern "C"
|
|
+#endif
|
|
+/* We use char because int might match the return type of a gcc2
|
|
+ builtin and then its argument prototype would still apply. */
|
|
+char getpeercon ();
|
|
+int
|
|
+main ()
|
|
+{
|
|
+getpeercon ();
|
|
+ ;
|
|
+ return 0;
|
|
+}
|
|
+_ACEOF
|
|
+rm -f conftest.$ac_objext conftest$ac_exeext
|
|
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
|
|
+ (eval $ac_link) 2>conftest.er1
|
|
+ ac_status=$?
|
|
+ grep -v '^ *+' conftest.er1 >conftest.err
|
|
+ rm -f conftest.er1
|
|
+ cat conftest.err >&5
|
|
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
|
+ (exit $ac_status); } &&
|
|
+ { ac_try='test -z "$ac_c_werror_flag"
|
|
+ || test ! -s conftest.err'
|
|
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
|
+ (eval $ac_try) 2>&5
|
|
+ ac_status=$?
|
|
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
|
+ (exit $ac_status); }; } &&
|
|
+ { ac_try='test -s conftest$ac_exeext'
|
|
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
|
+ (eval $ac_try) 2>&5
|
|
+ ac_status=$?
|
|
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
|
+ (exit $ac_status); }; }; then
|
|
+ ac_cv_lib_selinux_getpeercon=yes
|
|
+else
|
|
+ echo "$as_me: failed program was:" >&5
|
|
+sed 's/^/| /' conftest.$ac_ext >&5
|
|
+
|
|
+ac_cv_lib_selinux_getpeercon=no
|
|
+fi
|
|
+rm -f conftest.err conftest.$ac_objext \
|
|
+ conftest$ac_exeext conftest.$ac_ext
|
|
+LIBS=$ac_check_lib_save_LIBS
|
|
+fi
|
|
+echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_getpeercon" >&5
|
|
+echo "${ECHO_T}$ac_cv_lib_selinux_getpeercon" >&6
|
|
+if test $ac_cv_lib_selinux_getpeercon = yes; then
|
|
+
|
|
+cat >>confdefs.h <<_ACEOF
|
|
+#define HAVE_SELINUX 1
|
|
+_ACEOF
|
|
+
|
|
+
|
|
+else
|
|
+ { { echo "$as_me:$LINENO: error: \"--enable-selinux requires libselinux.\"" >&5
|
|
+echo "$as_me: error: \"--enable-selinux requires libselinux.\"" >&2;}
|
|
+ { (exit 1); exit 1; }; }
|
|
+fi
|
|
+
|
|
+fi
|
|
+
|
|
+#
|
|
# Elf
|
|
#
|
|
|
|
@@ -26019,6 +26129,7 @@ s,@with_libxml@,$with_libxml,;t t
|
|
s,@with_libxslt@,$with_libxslt,;t t
|
|
s,@with_system_tzdata@,$with_system_tzdata,;t t
|
|
s,@with_zlib@,$with_zlib,;t t
|
|
+s,@enable_selinux@,$enable_selinux,;t t
|
|
s,@EGREP@,$EGREP,;t t
|
|
s,@ELF_SYS@,$ELF_SYS,;t t
|
|
s,@LDFLAGS_SL@,$LDFLAGS_SL,;t t
|
|
diff -rpNU3 base/configure.in sepgsql/configure.in
|
|
--- base/configure.in 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/configure.in 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -626,6 +626,19 @@ PGAC_ARG_BOOL(with, zlib, yes,
|
|
AC_SUBST(with_zlib)
|
|
|
|
#
|
|
+# SELinux support
|
|
+#
|
|
+PGAC_ARG_BOOL(enable, selinux, no,
|
|
+ [ --enable-selinux build with SELinux support])
|
|
+if test "$enable_selinux" = yes; then
|
|
+ AC_CHECK_LIB(selinux, getpeercon,
|
|
+ AC_DEFINE_UNQUOTED(HAVE_SELINUX, 1,
|
|
+ [SE-PostgreSQL feature is enabled])
|
|
+ AC_SUBST(enable_selinux),
|
|
+ AC_MSG_ERROR("--enable-selinux requires libselinux."))
|
|
+fi
|
|
+
|
|
+#
|
|
# Elf
|
|
#
|
|
|
|
diff -rpNU3 base/contrib/sepgsql_policy/Makefile sepgsql/contrib/sepgsql_policy/Makefile
|
|
--- base/contrib/sepgsql_policy/Makefile 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/contrib/sepgsql_policy/Makefile 2008-06-26 11:44:44.000000000 +0900
|
|
@@ -0,0 +1,40 @@
|
|
+#
|
|
+# contrib/sepgsql_policy/Makefile
|
|
+# Makefile of security policy module for SE-PostgreSQL
|
|
+#
|
|
+top_builddir = ../..
|
|
+include $(top_builddir)/src/Makefile.global
|
|
+
|
|
+policy_basedir := /usr/share/selinux
|
|
+policy_makefile := $(policy_basedir)/devel/Makefile
|
|
+policy_types := targeted mls
|
|
+policy := $(strip $(shell $(AWK) -F= '/^SELINUXTYPE/{ print $$2 }' /etc/selinux/config))
|
|
+package_names := sepostgresql sepostgresql-devel
|
|
+prefix_ptn := "s/%%__prefix__%%/$(shell echo $(prefix)|sed 's/\//\\\//g')/g"
|
|
+bindir_ptn := "s/%%__bindir__%%/$(shell echo $(bindir)|sed 's/\//\\\//g')/g"
|
|
+libdir_ptn := "s/%%__libdir__%%/$(shell echo $(pkglibdir)|sed 's/\//\\\//g')/g"
|
|
+
|
|
+all:
|
|
+ $(foreach pkg, $(package_names), $(foreach p, $(policy_types), $(MAKE) $(MAKEOVERRIDES) policy=$(p) $(pkg).pp;))
|
|
+ $(foreach pkg, $(package_names), test -e $(pkg).pp.$(policy) && ln -sf $(pkg).pp.$(policy) $(pkg).pp;)
|
|
+
|
|
+.install-policy:
|
|
+ test -d $(DESTDIR)$(policy_basedir)/$(policy) || install -d $(DESTDIR)$(policy_basedir)/$(policy)
|
|
+ $(foreach pkg, $(package_names), install -p -m 644 $(pkg).pp.$(policy) $(DESTDIR)$(policy_basedir)/$(policy)/$(pkg).pp;)
|
|
+
|
|
+install: all
|
|
+ $(foreach p, $(policy_types), $(MAKE) $(MAKEOVERRIDES) policy=$(p) .install-policy;)
|
|
+
|
|
+%.pp: %.te %.if %.fc
|
|
+ $(MAKE) NAME=$(policy) -f $(policy_makefile) $@
|
|
+ mv $@ $@.$(policy)
|
|
+
|
|
+sepostgresql-devel.fc: sepostgresql.fc.template
|
|
+ cat $< | grep -v ^/var | sed -e $(prefix_ptn) -e $(bindir_ptn) -e $(libdir_ptn) > $@
|
|
+
|
|
+sepostgresql.fc: sepostgresql.fc.template
|
|
+ cat $< | sed -e $(prefix_ptn) -e $(bindir_ptn) -e $(libdir_ptn) > $@
|
|
+
|
|
+clean:
|
|
+ $(MAKE) -f $(policy_makefile) clean
|
|
+ rm -f *.pp.* *.fc
|
|
diff -rpNU3 base/contrib/sepgsql_policy/README sepgsql/contrib/sepgsql_policy/README
|
|
--- base/contrib/sepgsql_policy/README 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/contrib/sepgsql_policy/README 2008-06-19 13:12:15.000000000 +0900
|
|
@@ -0,0 +1,50 @@
|
|
+The security policy module of SE-PostgreSQL
|
|
+-------------------------------------------
|
|
+
|
|
+o Introduction
|
|
+
|
|
+ We provide two kind of security policy modules.
|
|
+
|
|
+ One is "sepostgresql.pp" which contains full-set of security policy
|
|
+ and suitable for legacy base policy (selinux-policy-3.4.1, or prior).
|
|
+
|
|
+ The other is "sepostgresql-devel.pp" which provides several booleans
|
|
+ for developers, and suitable for newer base policy (selinux-policy-3.4.2,
|
|
+ or later).
|
|
+
|
|
+ In the selinux-policy-3.4.2, most part of the policy got upstreamed.
|
|
+ So, we don't need to install "sepostgresql.pp" explicitly on the newer
|
|
+ base security policy.
|
|
+
|
|
+ If you need to run regression test, or (don't) want to generate access
|
|
+ logs, install "sepostgresql-devel.pp" and turn on/off booleans.
|
|
+
|
|
+o Build & Installation
|
|
+
|
|
+ $ cd contrib/sepgsql_policy
|
|
+ $ make
|
|
+ $ su
|
|
+ # /usr/sbin/semodule -i sepostgresql-devel.pp
|
|
+ or
|
|
+ # /usr/sbin/semodule -i sepostgresql.pp
|
|
+
|
|
+o Booleans
|
|
+
|
|
+- sepgsql_enable_users_ddl (default: on)
|
|
+ This boolean enables to control to execute DDL statement come from
|
|
+ confined users.
|
|
+
|
|
+- sepgsql_enable_auditallow (default: off)
|
|
+ This boolean enables to generate access allow logs except for tuple
|
|
+ level.
|
|
+
|
|
+- sepgsql_enable_auditdeny (default: on)
|
|
+ This boolean enables to generata access denied logs except for tuple
|
|
+ level.
|
|
+
|
|
+- sepgsql_regression_test_mode (default: off)
|
|
+ This boolean provides several permission to run regression test on
|
|
+ your home directory. It enables to load shared library files deployed
|
|
+ on home directory.
|
|
+ However, we don't recommend it to turn on in the operation phase.
|
|
+
|
|
diff -rpNU3 base/contrib/sepgsql_policy/sepostgresql-devel.if sepgsql/contrib/sepgsql_policy/sepostgresql-devel.if
|
|
--- base/contrib/sepgsql_policy/sepostgresql-devel.if 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/contrib/sepgsql_policy/sepostgresql-devel.if 2008-06-19 13:12:15.000000000 +0900
|
|
@@ -0,0 +1 @@
|
|
+## There are no interface declaration
|
|
diff -rpNU3 base/contrib/sepgsql_policy/sepostgresql-devel.te sepgsql/contrib/sepgsql_policy/sepostgresql-devel.te
|
|
--- base/contrib/sepgsql_policy/sepostgresql-devel.te 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/contrib/sepgsql_policy/sepostgresql-devel.te 2008-06-26 11:44:44.000000000 +0900
|
|
@@ -0,0 +1,82 @@
|
|
+policy_module(sepostgresql-devel, 3.11)
|
|
+
|
|
+gen_require(`
|
|
+ class db_database all_db_database_perms;
|
|
+ class db_table all_db_table_perms;
|
|
+ class db_procedure all_db_procedure_perms;
|
|
+ class db_column all_db_column_perms;
|
|
+ class db_tuple all_db_tuple_perms;
|
|
+ class db_blob all_db_blob_perms;
|
|
+
|
|
+ attribute domain, home_type;
|
|
+ attribute sepgsql_client_type;
|
|
+ attribute sepgsql_unconfined_type;
|
|
+
|
|
+ attribute sepgsql_database_type;
|
|
+ attribute sepgsql_table_type;
|
|
+ attribute sepgsql_sysobj_table_type;
|
|
+ attribute sepgsql_procedure_type;
|
|
+ attribute sepgsql_blob_type;
|
|
+ attribute sepgsql_module_type;
|
|
+')
|
|
+
|
|
+#################################
|
|
+#
|
|
+# SE-PostgreSQL Declarations
|
|
+#
|
|
+
|
|
+## <desc>
|
|
+## <p>
|
|
+## Allow to generate auditallow logs
|
|
+## </p>
|
|
+## </desc>
|
|
+gen_tunable(sepgsql_enable_auditallow, false)
|
|
+
|
|
+## <desc>
|
|
+## <p>
|
|
+## Allow to generate auditdeny logs
|
|
+## </p>
|
|
+## </desc>
|
|
+gen_tunable(sepgsql_enable_auditdeny, true)
|
|
+
|
|
+## <desc>
|
|
+## <p>
|
|
+## Allow widespread permissions for regression test
|
|
+## Don't set TRUE on operation phase
|
|
+## </p>
|
|
+## </desc>
|
|
+gen_tunable(sepgsql_regression_test_mode, false)
|
|
+
|
|
+########################################
|
|
+#
|
|
+# SE-PostgreSQL audit switch for debugging
|
|
+#
|
|
+tunable_policy(`sepgsql_enable_auditallow',`
|
|
+ auditallow domain sepgsql_database_type : db_database *;
|
|
+ auditallow domain sepgsql_table_type : db_table *;
|
|
+ auditallow domain sepgsql_table_type : db_column *;
|
|
+ auditallow domain sepgsql_procedure_type : db_procedure *;
|
|
+ auditallow domain sepgsql_blob_type : db_blob *;
|
|
+ auditallow domain sepgsql_module_type : db_database { install_module };
|
|
+ auditallow sepgsql_database_type sepgsql_module_type : db_database { load_module };
|
|
+')
|
|
+
|
|
+tunable_policy(`! sepgsql_enable_auditdeny',`
|
|
+ dontaudit domain sepgsql_database_type : db_database *;
|
|
+ dontaudit domain sepgsql_table_type : db_table *;
|
|
+ dontaudit domain sepgsql_table_type : db_column *;
|
|
+ dontaudit domain sepgsql_procedure_type : db_procedure *;
|
|
+ dontaudit domain sepgsql_blob_type : db_blob *;
|
|
+ dontaudit domain sepgsql_module_type : db_database { install_module };
|
|
+ dontaudit sepgsql_database_type sepgsql_module_type : db_database { load_module };
|
|
+')
|
|
+
|
|
+########################################
|
|
+#
|
|
+# SE-PostgreSQL regression test mode switch
|
|
+#
|
|
+tunable_policy(`sepgsql_regression_test_mode',`
|
|
+ allow sepgsql_client_type home_type : db_database { install_module };
|
|
+ allow sepgsql_unconfined_type home_type : db_database { install_module };
|
|
+ allow sepgsql_database_type home_type : db_database { load_module };
|
|
+')
|
|
diff -rpNU3 base/contrib/sepgsql_policy/sepostgresql.fc.template sepgsql/contrib/sepgsql_policy/sepostgresql.fc.template
|
|
--- base/contrib/sepgsql_policy/sepostgresql.fc.template 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/contrib/sepgsql_policy/sepostgresql.fc.template 2008-06-14 19:20:56.000000000 +0900
|
|
@@ -0,0 +1,15 @@
|
|
+#
|
|
+# SE-PostgreSQL install path
|
|
+#
|
|
+%%__prefix__%%(/.*)? -- gen_context(system_u:object_r:usr_t,s0)
|
|
+
|
|
+%%__bindir__%%/(se)?postgres -- gen_context(system_u:object_r:postgresql_exec_t,s0)
|
|
+%%__bindir__%%/(se)?pg_ctl -- gen_context(system_u:object_r:initrc_exec_t,s0)
|
|
+%%__bindir__%%/initdb(\.sepgsql)? -- gen_context(system_u:object_r:postgresql_exec_t,s0)
|
|
+%%__bindir__%%(/.*)? -- gen_context(system_u:object_r:bin_t,s0)
|
|
+
|
|
+%%__libdir__%%(/.*)? -- gen_context(system_u:object_r:lib_t,s0)
|
|
+
|
|
+/var/lib/sepgsql(/.*)? gen_context(system_u:object_r:postgresql_db_t,s0)
|
|
+/var/lib/sepgsql/pgstartup\.log gen_context(system_u:object_r:postgresql_log_t,s0)
|
|
+/var/log/sepostgresql\.log.* -- gen_context(system_u:object_r:postgresql_log_t,s0)
|
|
diff -rpNU3 base/contrib/sepgsql_policy/sepostgresql.if sepgsql/contrib/sepgsql_policy/sepostgresql.if
|
|
--- base/contrib/sepgsql_policy/sepostgresql.if 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/contrib/sepgsql_policy/sepostgresql.if 2008-06-26 11:44:44.000000000 +0900
|
|
@@ -0,0 +1,259 @@
|
|
+#######################################
|
|
+## <summary>
|
|
+## The userdomain template for the SE-PostgreSQL.
|
|
+## </summary>
|
|
+## <desc>
|
|
+## This template creates a delivered types which are used
|
|
+## for given userdomains.
|
|
+## </desc>
|
|
+## <param name="userdomain_prefix">
|
|
+## <summary>
|
|
+## The prefix of the user domain (e.g., user
|
|
+## is the prefix for user_t).
|
|
+## </summary>
|
|
+## </param>
|
|
+## <param name="user_domain">
|
|
+## <summary>
|
|
+## The type of the user domain.
|
|
+## </summary>
|
|
+## </param>
|
|
+## <param name="user_role">
|
|
+## <summary>
|
|
+## The role associated with the user domain.
|
|
+## </summary>
|
|
+## </param>
|
|
+#
|
|
+template(`sepostgresql_userdom_template',`
|
|
+ gen_require(`
|
|
+ class db_database all_db_database_perms;
|
|
+ class db_table all_db_table_perms;
|
|
+ class db_procedure all_db_procedure_perms;
|
|
+ class db_column all_db_column_perms;
|
|
+ class db_tuple all_db_tuple_perms;
|
|
+ class db_blob all_db_blob_perms;
|
|
+
|
|
+ attribute sepgsql_client_type;
|
|
+ attribute sepgsql_database_type;
|
|
+ attribute sepgsql_sysobj_table_type;
|
|
+
|
|
+ type sepgsql_trusted_proc_t;
|
|
+ type sepgsql_trusted_proc_exec_t;
|
|
+ ')
|
|
+
|
|
+ ########################################
|
|
+ #
|
|
+ # Declarations
|
|
+ #
|
|
+
|
|
+ typeattribute $2 sepgsql_client_type;
|
|
+
|
|
+ type $1_sepgsql_blob_t;
|
|
+ postgresql_blob_object($1_sepgsql_blob_t)
|
|
+
|
|
+ type $1_sepgsql_proc_exec_t;
|
|
+ postgresql_procedure_object($1_sepgsql_proc_exec_t)
|
|
+
|
|
+ type $1_sepgsql_sysobj_t;
|
|
+ postgresql_system_table_object($1_sepgsql_sysobj_t)
|
|
+
|
|
+ type $1_sepgsql_table_t;
|
|
+ postgresql_table_object($1_sepgsql_table_t)
|
|
+
|
|
+ role $3 types sepgsql_trusted_proc_t;
|
|
+
|
|
+ ##############################
|
|
+ #
|
|
+ # Client local policy
|
|
+ #
|
|
+
|
|
+ tunable_policy(`sepgsql_enable_users_ddl',`
|
|
+ allow $2 $1_sepgsql_table_t : db_table { create drop };
|
|
+ type_transition $2 sepgsql_database_type:db_table $1_sepgsql_table_t;
|
|
+
|
|
+ allow $2 $1_sepgsql_table_t : db_column { create drop };
|
|
+
|
|
+ allow $2 $1_sepgsql_sysobj_t : db_tuple { update insert delete };
|
|
+ type_transition $2 sepgsql_sysobj_table_type:db_tuple $1_sepgsql_sysobj_t;
|
|
+ ')
|
|
+
|
|
+ allow $2 $1_sepgsql_table_t : db_table { getattr setattr use select update insert delete };
|
|
+ allow $2 $1_sepgsql_table_t : db_column { getattr setattr use select update insert };
|
|
+ allow $2 $1_sepgsql_table_t : db_tuple { use select update insert delete };
|
|
+ allow $2 $1_sepgsql_sysobj_t : db_tuple { use select };
|
|
+
|
|
+ allow $2 $1_sepgsql_proc_exec_t : db_procedure { create drop getattr setattr execute };
|
|
+ type_transition $2 sepgsql_database_type:db_procedure $1_sepgsql_proc_exec_t;
|
|
+
|
|
+ allow $2 $1_sepgsql_blob_t : db_blob { create drop getattr setattr read write };
|
|
+ type_transition $2 sepgsql_database_type:db_blob $1_sepgsql_blob_t;
|
|
+
|
|
+ allow $2 sepgsql_trusted_proc_t:process transition;
|
|
+ type_transition $2 sepgsql_trusted_proc_exec_t:process sepgsql_trusted_proc_t;
|
|
+')
|
|
+
|
|
+########################################
|
|
+## <summary>
|
|
+## Marks as a SE-PostgreSQL loadable shared library module
|
|
+## </summary>
|
|
+## <param name="type">
|
|
+## <summary>
|
|
+## Type marked as a database object type.
|
|
+## </summary>
|
|
+## </param>
|
|
+#
|
|
+interface(`sepostgresql_loadable_module',`
|
|
+ gen_require(`
|
|
+ attribute sepgsql_module_type;
|
|
+ ')
|
|
+
|
|
+ typeattribute $1 sepgsql_module_type;
|
|
+')
|
|
+
|
|
+########################################
|
|
+## <summary>
|
|
+## Marks as a SE-PostgreSQL database object type
|
|
+## </summary>
|
|
+## <param name="type">
|
|
+## <summary>
|
|
+## Type marked as a database object type.
|
|
+## </summary>
|
|
+## </param>
|
|
+#
|
|
+interface(`sepostgresql_database_object',`
|
|
+ gen_require(`
|
|
+ attribute sepgsql_database_type;
|
|
+ ')
|
|
+
|
|
+ typeattribute $1 sepgsql_database_type;
|
|
+')
|
|
+
|
|
+########################################
|
|
+## <summary>
|
|
+## Marks as a SE-PostgreSQL table/column/tuple object type
|
|
+## </summary>
|
|
+## <param name="type">
|
|
+## <summary>
|
|
+## Type marked as a table/column/tuple object type.
|
|
+## </summary>
|
|
+## </param>
|
|
+#
|
|
+interface(`sepostgresql_table_object',`
|
|
+ gen_require(`
|
|
+ attribute sepgsql_table_type;
|
|
+ ')
|
|
+
|
|
+ typeattribute $1 sepgsql_table_type;
|
|
+')
|
|
+
|
|
+########################################
|
|
+## <summary>
|
|
+## Marks as a SE-PostgreSQL system table/column/tuple object type
|
|
+## </summary>
|
|
+## <param name="type">
|
|
+## <summary>
|
|
+## Type marked as a table/column/tuple object type.
|
|
+## </summary>
|
|
+## </param>
|
|
+#
|
|
+interface(`sepostgresql_system_table_object',`
|
|
+ gen_require(`
|
|
+ attribute sepgsql_table_type;
|
|
+ attribute sepgsql_sysobj_table_type;
|
|
+ ')
|
|
+
|
|
+ typeattribute $1 sepgsql_table_type;
|
|
+ typeattribute $1 sepgsql_sysobj_table_type;
|
|
+')
|
|
+
|
|
+########################################
|
|
+## <summary>
|
|
+## Marks as a SE-PostgreSQL procedure object type
|
|
+## </summary>
|
|
+## <param name="type">
|
|
+## <summary>
|
|
+## Type marked as a database object type.
|
|
+## </summary>
|
|
+## </param>
|
|
+#
|
|
+interface(`sepostgresql_procedure_object',`
|
|
+ gen_require(`
|
|
+ attribute sepgsql_procedure_type;
|
|
+ ')
|
|
+
|
|
+ typeattribute $1 sepgsql_procedure_type;
|
|
+')
|
|
+
|
|
+########################################
|
|
+## <summary>
|
|
+## Marks as a SE-PostgreSQL binary large object type
|
|
+## </summary>
|
|
+## <param name="type">
|
|
+## <summary>
|
|
+## Type marked as a database binary large object type.
|
|
+## </summary>
|
|
+## </param>
|
|
+#
|
|
+interface(`sepostgresql_blob_object',`
|
|
+ gen_require(`
|
|
+ attribute sepgsql_blob_type;
|
|
+ ')
|
|
+
|
|
+ typeattribute $1 sepgsql_blob_type;
|
|
+')
|
|
+
|
|
+########################################
|
|
+## <summary>
|
|
+## Allow the specified domain unprivileged accesses to unifined database objects
|
|
+## managed by SE-PostgreSQL,
|
|
+## </summary>
|
|
+## <param name="domain">
|
|
+## <summary>
|
|
+## Domain allowed access.
|
|
+## </summary>
|
|
+## </param>
|
|
+#
|
|
+interface(`sepostgresql_unpriv_client',`
|
|
+ gen_require(`
|
|
+ class db_table all_db_table_perms;
|
|
+ class db_procedure all_db_procedure_perms;
|
|
+ class db_blob all_db_blob_perms;
|
|
+
|
|
+ attribute sepgsql_client_type;
|
|
+ attribute sepgsql_database_type;
|
|
+
|
|
+ type sepgsql_table_t;
|
|
+ type sepgsql_proc_t;
|
|
+ type sepgsql_blob_t;
|
|
+
|
|
+ type sepgsql_trusted_proc_t;
|
|
+ type sepgsql_trusted_proc_exec_t;
|
|
+ ')
|
|
+
|
|
+ typeattribute $1 sepgsql_client_type;
|
|
+
|
|
+ type_transition $1 sepgsql_database_type:db_table sepgsql_table_t;
|
|
+ type_transition $1 sepgsql_database_type:db_procedure sepgsql_proc_t;
|
|
+ type_transition $1 sepgsql_database_type:db_blob sepgsql_blob_t;
|
|
+
|
|
+ type_transition $1 sepgsql_trusted_proc_exec_t:process sepgsql_trusted_proc_t;
|
|
+ allow $1 sepgsql_trusted_proc_t:process transition;
|
|
+')
|
|
+
|
|
+########################################
|
|
+## <summary>
|
|
+## Allow the specified domain unconfined accesses to any database objects
|
|
+## managed by SE-PostgreSQL,
|
|
+## </summary>
|
|
+## <param name="domain">
|
|
+## <summary>
|
|
+## Domain allowed access.
|
|
+## </summary>
|
|
+## </param>
|
|
+#
|
|
+interface(`sepostgresql_unconfined',`
|
|
+ gen_require(`
|
|
+ attribute sepgsql_unconfined_type;
|
|
+ ')
|
|
+
|
|
+ typeattribute $1 sepgsql_unconfined_type;
|
|
+')
|
|
diff -rpNU3 base/contrib/sepgsql_policy/sepostgresql.te sepgsql/contrib/sepgsql_policy/sepostgresql.te
|
|
--- base/contrib/sepgsql_policy/sepostgresql.te 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/contrib/sepgsql_policy/sepostgresql.te 2008-06-26 13:45:05.000000000 +0900
|
|
@@ -0,0 +1,308 @@
|
|
+policy_module(sepostgresql, 3.11)
|
|
+
|
|
+gen_require(`
|
|
+ class db_database all_db_database_perms;
|
|
+ class db_table all_db_table_perms;
|
|
+ class db_procedure all_db_procedure_perms;
|
|
+ class db_column all_db_column_perms;
|
|
+ class db_tuple all_db_tuple_perms;
|
|
+ class db_blob all_db_blob_perms;
|
|
+
|
|
+ attribute domain, home_type;
|
|
+ type postgresql_t, unlabeled_t;
|
|
+
|
|
+ role system_r;
|
|
+')
|
|
+
|
|
+#################################
|
|
+#
|
|
+# SE-PostgreSQL Declarations
|
|
+#
|
|
+
|
|
+## <desc>
|
|
+## <p>
|
|
+## Allow to generate auditallow logs
|
|
+## </p>
|
|
+## </desc>
|
|
+gen_tunable(sepgsql_enable_auditallow, false)
|
|
+
|
|
+## <desc>
|
|
+## <p>
|
|
+## Allow to generate auditdeny logs
|
|
+## </p>
|
|
+## </desc>
|
|
+gen_tunable(sepgsql_enable_auditdeny, true)
|
|
+
|
|
+## <desc>
|
|
+## <p>
|
|
+## Allow unprivileged users to execute DDL statement
|
|
+## </p>
|
|
+## </desc>
|
|
+gen_tunable(sepgsql_enable_users_ddl, true)
|
|
+
|
|
+## <desc>
|
|
+## <p>
|
|
+## Allow widespread permissions for regression test
|
|
+## Don't set TRUE on operation phase
|
|
+## </p>
|
|
+## </desc>
|
|
+gen_tunable(sepgsql_regression_test_mode, false)
|
|
+
|
|
+# database clients attribute
|
|
+attribute sepgsql_client_type;
|
|
+attribute sepgsql_unconfined_type;
|
|
+
|
|
+# database objects attribute
|
|
+attribute sepgsql_database_type;
|
|
+attribute sepgsql_table_type;
|
|
+attribute sepgsql_sysobj_table_type;
|
|
+attribute sepgsql_procedure_type;
|
|
+attribute sepgsql_blob_type;
|
|
+attribute sepgsql_module_type;
|
|
+
|
|
+# database object types
|
|
+type sepgsql_blob_t;
|
|
+sepostgresql_blob_object(sepgsql_blob_t)
|
|
+
|
|
+type sepgsql_db_t;
|
|
+sepostgresql_database_object(sepgsql_db_t)
|
|
+
|
|
+type sepgsql_fixed_table_t;
|
|
+sepostgresql_table_object(sepgsql_fixed_table_t)
|
|
+
|
|
+type sepgsql_proc_t;
|
|
+sepostgresql_procedure_object(sepgsql_proc_t)
|
|
+
|
|
+type sepgsql_ro_blob_t;
|
|
+sepostgresql_blob_object(sepgsql_ro_blob_t)
|
|
+
|
|
+type sepgsql_ro_table_t;
|
|
+sepostgresql_table_object(sepgsql_ro_table_t)
|
|
+
|
|
+type sepgsql_secret_blob_t;
|
|
+sepostgresql_blob_object(sepgsql_secret_blob_t)
|
|
+
|
|
+type sepgsql_secret_table_t;
|
|
+sepostgresql_table_object(sepgsql_secret_table_t)
|
|
+
|
|
+type sepgsql_sysobj_t;
|
|
+sepostgresql_system_table_object(sepgsql_sysobj_t)
|
|
+
|
|
+type sepgsql_table_t;
|
|
+sepostgresql_table_object(sepgsql_table_t)
|
|
+
|
|
+type sepgsql_trusted_proc_exec_t;
|
|
+sepostgresql_procedure_object(sepgsql_trusted_proc_exec_t)
|
|
+
|
|
+# Trusted Procedure Domain
|
|
+type sepgsql_trusted_proc_t;
|
|
+domain_type(sepgsql_trusted_proc_t)
|
|
+sepostgresql_unconfined(sepgsql_trusted_proc_t)
|
|
+role system_r types sepgsql_trusted_proc_t;
|
|
+
|
|
+########################################
|
|
+#
|
|
+# SE-PostgreSQL Local Policy
|
|
+#
|
|
+allow postgresql_t self:netlink_selinux_socket create_socket_perms;
|
|
+selinux_get_enforce_mode(postgresql_t)
|
|
+selinux_validate_context(postgresql_t)
|
|
+selinux_compute_access_vector(postgresql_t)
|
|
+selinux_compute_create_context(postgresql_t)
|
|
+selinux_compute_relabel_context(postgresql_t)
|
|
+seutil_libselinux_linked(postgresql_t)
|
|
+
|
|
+allow postgresql_t sepgsql_database_type:db_database *;
|
|
+type_transition postgresql_t postgresql_t:db_database sepgsql_db_t;
|
|
+
|
|
+allow postgresql_t sepgsql_module_type:db_database install_module;
|
|
+allow postgresql_t sepgsql_table_type:{ db_table db_column db_tuple } *;
|
|
+allow postgresql_t sepgsql_procedure_type:db_procedure *;
|
|
+allow postgresql_t sepgsql_blob_type:db_blob *;
|
|
+
|
|
+# server specific type transitions
|
|
+type_transition postgresql_t sepgsql_database_type:db_table sepgsql_sysobj_t;
|
|
+type_transition postgresql_t sepgsql_database_type:db_procedure sepgsql_proc_t;
|
|
+type_transition postgresql_t sepgsql_database_type:db_blob sepgsql_blob_t;
|
|
+
|
|
+# Database/Loadable module
|
|
+allow sepgsql_database_type sepgsql_module_type:db_database load_module;
|
|
+
|
|
+########################################
|
|
+#
|
|
+# Rules common to all clients
|
|
+#
|
|
+
|
|
+# Client domain constraint
|
|
+allow sepgsql_client_type sepgsql_db_t:db_database { getattr access get_param set_param };
|
|
+type_transition sepgsql_client_type sepgsql_client_type:db_database sepgsql_db_t;
|
|
+
|
|
+allow sepgsql_client_type sepgsql_fixed_table_t:db_table { getattr use select insert };
|
|
+allow sepgsql_client_type sepgsql_fixed_table_t:db_column { getattr use select insert };
|
|
+allow sepgsql_client_type sepgsql_fixed_table_t:db_tuple { use select insert };
|
|
+
|
|
+allow sepgsql_client_type sepgsql_table_t:db_table { getattr use select update insert delete };
|
|
+allow sepgsql_client_type sepgsql_table_t:db_column { getattr use select update insert };
|
|
+allow sepgsql_client_type sepgsql_table_t:db_tuple { use select update insert delete };
|
|
+
|
|
+allow sepgsql_client_type sepgsql_ro_table_t:db_table { getattr use select };
|
|
+allow sepgsql_client_type sepgsql_ro_table_t:db_column { getattr use select };
|
|
+allow sepgsql_client_type sepgsql_ro_table_t:db_tuple { use select };
|
|
+
|
|
+allow sepgsql_client_type sepgsql_secret_table_t:db_table getattr;
|
|
+allow sepgsql_client_type sepgsql_secret_table_t:db_column getattr;
|
|
+
|
|
+allow sepgsql_client_type sepgsql_sysobj_t:db_table { getattr use select };
|
|
+allow sepgsql_client_type sepgsql_sysobj_t:db_column { getattr use select };
|
|
+allow sepgsql_client_type sepgsql_sysobj_t:db_tuple { use select };
|
|
+
|
|
+allow sepgsql_client_type sepgsql_proc_t:db_procedure { getattr execute };
|
|
+allow sepgsql_client_type sepgsql_trusted_proc_t:db_procedure { getattr execute entrypoint };
|
|
+
|
|
+allow sepgsql_client_type sepgsql_blob_t:db_blob { create drop getattr setattr read write };
|
|
+allow sepgsql_client_type sepgsql_ro_blob_t:db_blob { getattr read };
|
|
+allow sepgsql_client_type sepgsql_secret_blob_t:db_blob getattr;
|
|
+
|
|
+tunable_policy(`sepgsql_enable_users_ddl',`
|
|
+ allow sepgsql_client_type sepgsql_table_t:db_table { create drop setattr };
|
|
+ allow sepgsql_client_type sepgsql_table_t:db_column { create drop setattr };
|
|
+ allow sepgsql_client_type sepgsql_sysobj_t:db_tuple { update insert delete };
|
|
+')
|
|
+
|
|
+########################################
|
|
+#
|
|
+# Unconfined access to this module
|
|
+#
|
|
+
|
|
+allow sepgsql_unconfined_type sepgsql_database_type:db_database *;
|
|
+allow sepgsql_unconfined_type sepgsql_table_type:{ db_table db_column db_tuple } *;
|
|
+allow sepgsql_unconfined_type sepgsql_blob_type:db_blob *;
|
|
+allow sepgsql_unconfined_type { sepgsql_proc_t sepgsql_trusted_proc_t }:db_procedure *;
|
|
+allow sepgsql_unconfined_type sepgsql_procedure_type:db_procedure { create drop getattr setattr relabelfrom relabelto };
|
|
+allow sepgsql_unconfined_type sepgsql_module_type:db_database install_module;
|
|
+
|
|
+type_transition sepgsql_unconfined_type sepgsql_unconfined_type:db_database sepgsql_db_t;
|
|
+type_transition sepgsql_unconfined_type sepgsql_database_type:db_table sepgsql_table_t;
|
|
+type_transition sepgsql_unconfined_type sepgsql_database_type:db_procedure sepgsql_proc_t;
|
|
+type_transition sepgsql_unconfined_type sepgsql_database_type:db_blob sepgsql_blob_t;
|
|
+
|
|
+
|
|
+########################################
|
|
+#
|
|
+# Allow permission to external domains
|
|
+#
|
|
+
|
|
+# relabelfrom for invalid security context
|
|
+allow sepgsql_unconfined_type unlabeled_t:db_database { setattr relabelfrom };
|
|
+allow sepgsql_unconfined_type unlabeled_t:db_table { setattr relabelfrom };
|
|
+allow sepgsql_unconfined_type unlabeled_t:db_procedure { setattr relabelfrom };
|
|
+allow sepgsql_unconfined_type unlabeled_t:db_column { setattr relabelfrom };
|
|
+allow sepgsql_unconfined_type unlabeled_t:db_tuple { update relabelfrom };
|
|
+allow sepgsql_unconfined_type unlabeled_t:db_blob { setattr relabelfrom };
|
|
+
|
|
+# administrative client domain
|
|
+optional_policy(`
|
|
+ gen_require(`
|
|
+ type unconfined_t;
|
|
+ ')
|
|
+ sepostgresql_unconfined(unconfined_t)
|
|
+')
|
|
+
|
|
+optional_policy(`
|
|
+ gen_require(`
|
|
+ type sysadm_t;
|
|
+ ')
|
|
+ sepostgresql_unconfined(sysadm_t)
|
|
+')
|
|
+
|
|
+# unprivilleged client domain
|
|
+optional_policy(`
|
|
+ gen_require(`
|
|
+ type user_t;
|
|
+ role user_r;
|
|
+ ')
|
|
+ sepostgresql_userdom_template(user,user_t,user_r)
|
|
+')
|
|
+
|
|
+optional_policy(`
|
|
+ gen_require(`
|
|
+ type staff_t;
|
|
+ role staff_r;
|
|
+ ')
|
|
+ sepostgresql_userdom_template(staff,staff_t,staff_r)
|
|
+')
|
|
+
|
|
+optional_policy(`
|
|
+ gen_require(`
|
|
+ type guest_t;
|
|
+ role guest_r;
|
|
+ ')
|
|
+ sepostgresql_userdom_template(guest,guest_t,guest_r)
|
|
+')
|
|
+
|
|
+optional_policy(`
|
|
+ gen_require(`
|
|
+ type xguest_t;
|
|
+ role xguest_r;
|
|
+ ')
|
|
+ sepostgresql_userdom_template(xguest,xguest_t,xguest_r)
|
|
+')
|
|
+
|
|
+optional_policy(`
|
|
+ gen_require(`
|
|
+ type httpd_t;
|
|
+ ')
|
|
+ sepostgresql_unpriv_client(httpd_t)
|
|
+')
|
|
+
|
|
+optional_policy(`
|
|
+ gen_require(`
|
|
+ type httpd_sys_script_t;
|
|
+ ')
|
|
+ sepostgresql_unpriv_client(httpd_sys_script_t)
|
|
+')
|
|
+
|
|
+# SE-PostgreSQL loadable modules
|
|
+optional_policy(`
|
|
+ gen_require(`
|
|
+ type lib_t, textrel_shlib_t;
|
|
+ ')
|
|
+ sepostgresql_loadable_module(lib_t)
|
|
+ sepostgresql_loadable_module(textrel_shlib_t)
|
|
+')
|
|
+
|
|
+########################################
|
|
+#
|
|
+# SE-PostgreSQL audit switch for debugging
|
|
+#
|
|
+tunable_policy(`sepgsql_enable_auditallow',`
|
|
+ auditallow domain sepgsql_database_type : db_database *;
|
|
+ auditallow domain sepgsql_table_type : db_table *;
|
|
+ auditallow domain sepgsql_table_type : db_column *;
|
|
+ auditallow domain sepgsql_procedure_type : db_procedure *;
|
|
+ auditallow domain sepgsql_blob_type : db_blob *;
|
|
+ auditallow domain sepgsql_module_type : db_database { install_module };
|
|
+ auditallow sepgsql_database_type sepgsql_module_type : db_database { load_module };
|
|
+')
|
|
+
|
|
+tunable_policy(`! sepgsql_enable_auditdeny',`
|
|
+ dontaudit domain sepgsql_database_type : db_database *;
|
|
+ dontaudit domain sepgsql_table_type : db_table *;
|
|
+ dontaudit domain sepgsql_table_type : db_column *;
|
|
+ dontaudit domain sepgsql_procedure_type : db_procedure *;
|
|
+ dontaudit domain sepgsql_blob_type : db_blob *;
|
|
+ dontaudit domain sepgsql_module_type : db_database { install_module };
|
|
+ dontaudit sepgsql_database_type sepgsql_module_type : db_database { load_module };
|
|
+')
|
|
+
|
|
+dontaudit domain { sepgsql_table_type - sepgsql_sysobj_table_type } : db_tuple { use select update insert delete };
|
|
+
|
|
+########################################
|
|
+#
|
|
+# SE-PostgreSQL regression test mode switch
|
|
+#
|
|
+tunable_policy(`sepgsql_regression_test_mode',`
|
|
+ allow sepgsql_client_type home_type : db_database { install_module };
|
|
+ allow sepgsql_unconfined_type home_type : db_database { install_module };
|
|
+ allow sepgsql_database_type home_type : db_database { load_module };
|
|
+')
|
|
diff -rpNU3 base/src/Makefile.global.in sepgsql/src/Makefile.global.in
|
|
--- base/src/Makefile.global.in 2007-11-17 20:15:40.000000000 +0900
|
|
+++ sepgsql/src/Makefile.global.in 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -165,6 +165,7 @@ enable_rpath = @enable_rpath@
|
|
enable_nls = @enable_nls@
|
|
enable_debug = @enable_debug@
|
|
enable_dtrace = @enable_dtrace@
|
|
+enable_selinux = @enable_selinux@
|
|
enable_thread_safety = @enable_thread_safety@
|
|
|
|
python_includespec = @python_includespec@
|
|
diff -rpNU3 base/src/backend/Makefile sepgsql/src/backend/Makefile
|
|
--- base/src/backend/Makefile 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/Makefile 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -16,7 +16,7 @@ include $(top_builddir)/src/Makefile.glo
|
|
|
|
DIRS = access bootstrap catalog parser commands executor lib libpq \
|
|
main nodes optimizer port postmaster regex rewrite \
|
|
- storage tcop tsearch utils $(top_builddir)/src/timezone
|
|
+ security storage tcop tsearch utils $(top_builddir)/src/timezone
|
|
|
|
SUBSYSOBJS = $(DIRS:%=%/SUBSYS.o)
|
|
|
|
@@ -32,6 +32,11 @@ LIBS := $(filter-out -lpgport, $(LIBS))
|
|
# The backend doesn't need everything that's in LIBS, however
|
|
LIBS := $(filter-out -lz -lreadline -ledit -ltermcap -lncurses -lcurses, $(LIBS))
|
|
|
|
+# SELinux support needs to link libselinux
|
|
+ifeq ($(enable_selinux), yes)
|
|
+LIBS += -lselinux
|
|
+endif
|
|
+
|
|
##########################################################################
|
|
|
|
all: submake-libpgport postgres $(POSTGRES_IMP)
|
|
diff -rpNU3 base/src/backend/access/common/heaptuple.c sepgsql/src/backend/access/common/heaptuple.c
|
|
--- base/src/backend/access/common/heaptuple.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/access/common/heaptuple.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -67,6 +67,7 @@
|
|
#include "access/heapam.h"
|
|
#include "access/tuptoaster.h"
|
|
#include "executor/tuptable.h"
|
|
+#include "security/pgace.h"
|
|
|
|
|
|
/* Does att's datatype allow packing into the 1-byte-header varlena format? */
|
|
@@ -473,6 +474,7 @@ heap_attisnull(HeapTuple tup, int attnum
|
|
case MinCommandIdAttributeNumber:
|
|
case MaxTransactionIdAttributeNumber:
|
|
case MaxCommandIdAttributeNumber:
|
|
+ case SecurityLabelAttributeNumber:
|
|
/* these are never null */
|
|
break;
|
|
|
|
@@ -785,6 +787,9 @@ heap_getsysattr(HeapTuple tup, int attnu
|
|
case TableOidAttributeNumber:
|
|
result = ObjectIdGetDatum(tup->t_tableOid);
|
|
break;
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ result = pgaceHeapGetSecurityLabelSysattr(tup);
|
|
+ break;
|
|
default:
|
|
elog(ERROR, "invalid attnum: %d", attnum);
|
|
result = 0; /* keep compiler quiet */
|
|
@@ -909,6 +914,9 @@ heap_form_tuple(TupleDesc tupleDescripto
|
|
if (tupleDescriptor->tdhasoid)
|
|
len += sizeof(Oid);
|
|
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ len += sizeof(Oid);
|
|
+
|
|
hoff = len = MAXALIGN(len); /* align user data safely */
|
|
|
|
data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
|
|
@@ -940,6 +948,9 @@ heap_form_tuple(TupleDesc tupleDescripto
|
|
if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
|
|
td->t_infomask = HEAP_HASOID;
|
|
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ td->t_infomask |= HEAP_HAS_SECLABEL;
|
|
+
|
|
heap_fill_tuple(tupleDescriptor,
|
|
values,
|
|
isnull,
|
|
@@ -1020,6 +1031,9 @@ heap_formtuple(TupleDesc tupleDescriptor
|
|
if (tupleDescriptor->tdhasoid)
|
|
len += sizeof(Oid);
|
|
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ len += sizeof(Oid);
|
|
+
|
|
hoff = len = MAXALIGN(len); /* align user data safely */
|
|
|
|
data_len = ComputeDataSize(tupleDescriptor, values, nulls);
|
|
@@ -1051,6 +1065,9 @@ heap_formtuple(TupleDesc tupleDescriptor
|
|
if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
|
|
td->t_infomask = HEAP_HASOID;
|
|
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ td->t_infomask |= HEAP_HAS_SECLABEL;
|
|
+
|
|
DataFill(tupleDescriptor,
|
|
values,
|
|
nulls,
|
|
@@ -1129,6 +1146,8 @@ heap_modify_tuple(HeapTuple tuple,
|
|
newTuple->t_tableOid = tuple->t_tableOid;
|
|
if (tupleDesc->tdhasoid)
|
|
HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
|
|
+ if (HeapTupleHasSecLabel(newTuple))
|
|
+ HeapTupleSetSecLabel(newTuple, HeapTupleGetSecLabel(tuple));
|
|
|
|
return newTuple;
|
|
}
|
|
@@ -1201,6 +1220,8 @@ heap_modifytuple(HeapTuple tuple,
|
|
newTuple->t_tableOid = tuple->t_tableOid;
|
|
if (tupleDesc->tdhasoid)
|
|
HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
|
|
+ if (HeapTupleHasSecLabel(newTuple))
|
|
+ HeapTupleSetSecLabel(newTuple, HeapTupleGetSecLabel(tuple));
|
|
|
|
return newTuple;
|
|
}
|
|
@@ -1847,6 +1868,9 @@ heap_form_minimal_tuple(TupleDesc tupleD
|
|
if (tupleDescriptor->tdhasoid)
|
|
len += sizeof(Oid);
|
|
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ len += sizeof(Oid);
|
|
+
|
|
hoff = len = MAXALIGN(len); /* align user data safely */
|
|
|
|
data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
|
|
@@ -1868,6 +1892,9 @@ heap_form_minimal_tuple(TupleDesc tupleD
|
|
if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
|
|
tuple->t_infomask = HEAP_HASOID;
|
|
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ tuple->t_infomask |= HEAP_HAS_SECLABEL;
|
|
+
|
|
heap_fill_tuple(tupleDescriptor,
|
|
values,
|
|
isnull,
|
|
@@ -1965,6 +1992,7 @@ minimal_tuple_from_heap_tuple(HeapTuple
|
|
HeapTuple
|
|
heap_addheader(int natts, /* max domain index */
|
|
bool withoid, /* reserve space for oid */
|
|
+ bool withsecurity, /* reserve space for security */
|
|
Size structlen, /* its length */
|
|
void *structure) /* pointer to the struct */
|
|
{
|
|
@@ -1979,6 +2007,10 @@ heap_addheader(int natts, /* max domain
|
|
hoff = offsetof(HeapTupleHeaderData, t_bits);
|
|
if (withoid)
|
|
hoff += sizeof(Oid);
|
|
+
|
|
+ if (withsecurity)
|
|
+ hoff += sizeof(Oid);
|
|
+
|
|
hoff = MAXALIGN(hoff);
|
|
len = hoff + structlen;
|
|
|
|
@@ -1997,6 +2029,9 @@ heap_addheader(int natts, /* max domain
|
|
if (withoid) /* else leave infomask = 0 */
|
|
td->t_infomask = HEAP_HASOID;
|
|
|
|
+ if (withsecurity)
|
|
+ td->t_infomask |= HEAP_HAS_SECLABEL;
|
|
+
|
|
memcpy((char *) td + hoff, structure, structlen);
|
|
|
|
return tuple;
|
|
diff -rpNU3 base/src/backend/access/common/tupdesc.c sepgsql/src/backend/access/common/tupdesc.c
|
|
--- base/src/backend/access/common/tupdesc.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/access/common/tupdesc.c 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -84,6 +84,7 @@ CreateTemplateTupleDesc(int natts, bool
|
|
desc->tdtypeid = RECORDOID;
|
|
desc->tdtypmod = -1;
|
|
desc->tdhasoid = hasoid;
|
|
+ desc->tdhasseclabel = false; /* set a proper value, if necessary */
|
|
desc->tdrefcount = -1; /* assume not reference-counted */
|
|
|
|
return desc;
|
|
@@ -117,6 +118,7 @@ CreateTupleDesc(int natts, bool hasoid,
|
|
desc->tdtypeid = RECORDOID;
|
|
desc->tdtypmod = -1;
|
|
desc->tdhasoid = hasoid;
|
|
+ desc->tdhasseclabel = false; /* set a proper value, if necessary */
|
|
desc->tdrefcount = -1; /* assume not reference-counted */
|
|
|
|
return desc;
|
|
@@ -146,6 +148,7 @@ CreateTupleDescCopy(TupleDesc tupdesc)
|
|
|
|
desc->tdtypeid = tupdesc->tdtypeid;
|
|
desc->tdtypmod = tupdesc->tdtypmod;
|
|
+ desc->tdhasseclabel = tupdesc->tdhasseclabel;
|
|
|
|
return desc;
|
|
}
|
|
@@ -204,6 +207,7 @@ CreateTupleDescCopyConstr(TupleDesc tupd
|
|
|
|
desc->tdtypeid = tupdesc->tdtypeid;
|
|
desc->tdtypmod = tupdesc->tdtypmod;
|
|
+ desc->tdhasseclabel = tupdesc->tdhasseclabel;
|
|
|
|
return desc;
|
|
}
|
|
@@ -310,6 +314,8 @@ equalTupleDescs(TupleDesc tupdesc1, Tupl
|
|
return false;
|
|
if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
|
|
return false;
|
|
+ if (tupdesc1->tdhasseclabel != tupdesc2->tdhasseclabel)
|
|
+ return false;
|
|
|
|
for (i = 0; i < tupdesc1->natts; i++)
|
|
{
|
|
diff -rpNU3 base/src/backend/access/heap/heapam.c sepgsql/src/backend/access/heap/heapam.c
|
|
--- base/src/backend/access/heap/heapam.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/access/heap/heapam.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -50,6 +50,7 @@
|
|
#include "catalog/namespace.h"
|
|
#include "miscadmin.h"
|
|
#include "pgstat.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/procarray.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/datum.h"
|
|
@@ -1958,6 +1959,12 @@ heap_insert(Relation relation, HeapTuple
|
|
Oid
|
|
simple_heap_insert(Relation relation, HeapTuple tup)
|
|
{
|
|
+ if (!pgaceHeapTupleInsert(relation, tup, true, false))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("could not insert tuple on \"%s\" due to pgace security",
|
|
+ RelationGetRelationName(relation))));
|
|
+
|
|
return heap_insert(relation, tup, GetCurrentCommandId(true), true, true);
|
|
}
|
|
|
|
@@ -2239,6 +2246,12 @@ simple_heap_delete(Relation relation, It
|
|
ItemPointerData update_ctid;
|
|
TransactionId update_xmax;
|
|
|
|
+ if (!pgaceHeapTupleDelete(relation, tid, true, false))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("could not delete tuple on \"%s\" due to pgace security",
|
|
+ RelationGetRelationName(relation))));
|
|
+
|
|
result = heap_delete(relation, tid,
|
|
&update_ctid, &update_xmax,
|
|
GetCurrentCommandId(true), InvalidSnapshot,
|
|
@@ -2883,6 +2896,12 @@ simple_heap_update(Relation relation, It
|
|
ItemPointerData update_ctid;
|
|
TransactionId update_xmax;
|
|
|
|
+ if (!pgaceHeapTupleUpdate(relation, otid, tup, true, false))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("could not update tuple on \"%s\" due to pgace security",
|
|
+ RelationGetRelationName(relation))));
|
|
+
|
|
result = heap_update(relation, otid, tup,
|
|
&update_ctid, &update_xmax,
|
|
GetCurrentCommandId(true), InvalidSnapshot,
|
|
diff -rpNU3 base/src/backend/access/heap/tuptoaster.c sepgsql/src/backend/access/heap/tuptoaster.c
|
|
--- base/src/backend/access/heap/tuptoaster.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql/src/backend/access/heap/tuptoaster.c 2009-01-14 15:06:52.000000000 +0900
|
|
@@ -35,6 +35,7 @@
|
|
#include "access/tuptoaster.h"
|
|
#include "access/xact.h"
|
|
#include "catalog/catalog.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/pg_lzcompress.h"
|
|
#include "utils/typcache.h"
|
|
@@ -589,6 +590,8 @@ toast_insert_or_update(Relation rel, Hea
|
|
hoff += BITMAPLEN(numAttrs);
|
|
if (newtup->t_data->t_infomask & HEAP_HASOID)
|
|
hoff += sizeof(Oid);
|
|
+ if (newtup->t_data->t_infomask & HEAP_HAS_SECLABEL)
|
|
+ hoff += sizeof(Oid);
|
|
hoff = MAXALIGN(hoff);
|
|
Assert(hoff == newtup->t_data->t_hoff);
|
|
/* now convert to a limit on the tuple data size */
|
|
@@ -838,6 +841,8 @@ toast_insert_or_update(Relation rel, Hea
|
|
new_len += BITMAPLEN(numAttrs);
|
|
if (olddata->t_infomask & HEAP_HASOID)
|
|
new_len += sizeof(Oid);
|
|
+ if (olddata->t_infomask & HEAP_HAS_SECLABEL)
|
|
+ new_len += sizeof(Oid);
|
|
new_len = MAXALIGN(new_len);
|
|
Assert(new_len == olddata->t_hoff);
|
|
new_data_len = heap_compute_data_size(tupleDesc,
|
|
@@ -989,6 +994,8 @@ toast_flatten_tuple_attribute(Datum valu
|
|
new_len += BITMAPLEN(numAttrs);
|
|
if (olddata->t_infomask & HEAP_HASOID)
|
|
new_len += sizeof(Oid);
|
|
+ if (olddata->t_infomask & HEAP_HAS_SECLABEL)
|
|
+ new_len += sizeof(Oid);
|
|
new_len = MAXALIGN(new_len);
|
|
Assert(new_len == olddata->t_hoff);
|
|
new_data_len = heap_compute_data_size(tupleDesc,
|
|
@@ -1173,6 +1180,12 @@ toast_save_datum(Relation rel, Datum val
|
|
memcpy(VARDATA(&chunk_data), data_p, chunk_size);
|
|
toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull);
|
|
|
|
+ if (!pgaceHeapTupleInsert(toastrel, toasttup, true, false))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("could not insert tuple \"%s\" due to pgace security",
|
|
+ RelationGetRelationName(toastrel))));
|
|
+
|
|
heap_insert(toastrel, toasttup, mycid, use_wal, use_fsm);
|
|
|
|
/*
|
|
diff -rpNU3 base/src/backend/bootstrap/bootparse.y sepgsql/src/backend/bootstrap/bootparse.y
|
|
--- base/src/backend/bootstrap/bootparse.y 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/bootstrap/bootparse.y 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -42,6 +42,7 @@
|
|
#include "nodes/pg_list.h"
|
|
#include "nodes/primnodes.h"
|
|
#include "rewrite/prs2lock.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/block.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/ipc.h"
|
|
@@ -194,6 +195,13 @@ Boot_CreateStmt:
|
|
RELKIND_RELATION,
|
|
$3,
|
|
true);
|
|
+ /*
|
|
+ * fixup boot_reldesc->rd_att->tdhasseclabel
|
|
+ */
|
|
+ boot_reldesc->rd_rel->relkind = RELKIND_RELATION;
|
|
+ boot_reldesc->rd_att->tdhasseclabel
|
|
+ = pgaceTupleDescHasSecLabel(boot_reldesc, NIL);
|
|
+
|
|
elog(DEBUG4, "bootstrap relation created");
|
|
}
|
|
else
|
|
@@ -212,7 +220,8 @@ Boot_CreateStmt:
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
(Datum) 0,
|
|
- true);
|
|
+ true,
|
|
+ NIL);
|
|
elog(DEBUG4, "relation created with oid %u", id);
|
|
}
|
|
do_end();
|
|
diff -rpNU3 base/src/backend/bootstrap/bootstrap.c sepgsql/src/backend/bootstrap/bootstrap.c
|
|
--- base/src/backend/bootstrap/bootstrap.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/bootstrap/bootstrap.c 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -31,6 +31,7 @@
|
|
#include "nodes/makefuncs.h"
|
|
#include "postmaster/bgwriter.h"
|
|
#include "postmaster/walwriter.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/freespace.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/proc.h"
|
|
@@ -499,6 +500,8 @@ BootstrapModeMain(void)
|
|
*/
|
|
boot_yyparse();
|
|
|
|
+ pgacePostBootstrapingMode();
|
|
+
|
|
/* Perform a checkpoint to ensure everything's down to disk */
|
|
SetProcessingMode(NormalProcessing);
|
|
CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);
|
|
@@ -796,6 +799,7 @@ InsertOneTuple(Oid objectid)
|
|
tupDesc = CreateTupleDesc(numattr,
|
|
RelationGetForm(boot_reldesc)->relhasoids,
|
|
attrtypes);
|
|
+ tupDesc->tdhasseclabel = pgaceTupleDescHasSecLabel(boot_reldesc, NIL);
|
|
tuple = heap_formtuple(tupDesc, values, Blanks);
|
|
if (objectid != (Oid) 0)
|
|
HeapTupleSetOid(tuple, objectid);
|
|
diff -rpNU3 base/src/backend/catalog/Makefile sepgsql/src/backend/catalog/Makefile
|
|
--- base/src/backend/catalog/Makefile 2007-09-11 10:53:53.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/Makefile 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -35,6 +35,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_sr
|
|
pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
|
|
pg_database.h pg_tablespace.h pg_pltemplate.h \
|
|
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
|
|
+ pg_security.h \
|
|
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
|
|
pg_ts_parser.h pg_ts_template.h \
|
|
toasting.h indexing.h \
|
|
diff -rpNU3 base/src/backend/catalog/catalog.c sepgsql/src/backend/catalog/catalog.c
|
|
--- base/src/backend/catalog/catalog.c 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/catalog.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -30,6 +30,7 @@
|
|
#include "catalog/pg_database.h"
|
|
#include "catalog/pg_namespace.h"
|
|
#include "catalog/pg_pltemplate.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_shdepend.h"
|
|
#include "catalog/pg_shdescription.h"
|
|
#include "catalog/pg_tablespace.h"
|
|
@@ -257,6 +258,7 @@ IsSharedRelation(Oid relationId)
|
|
relationId == AuthMemRelationId ||
|
|
relationId == DatabaseRelationId ||
|
|
relationId == PLTemplateRelationId ||
|
|
+ relationId == SecurityRelationId ||
|
|
relationId == SharedDescriptionRelationId ||
|
|
relationId == SharedDependRelationId ||
|
|
relationId == TableSpaceRelationId)
|
|
@@ -269,6 +271,8 @@ IsSharedRelation(Oid relationId)
|
|
relationId == DatabaseNameIndexId ||
|
|
relationId == DatabaseOidIndexId ||
|
|
relationId == PLTemplateNameIndexId ||
|
|
+ relationId == SecurityOidIndexId ||
|
|
+ relationId == SecuritySeclabelIndexId ||
|
|
relationId == SharedDescriptionObjIndexId ||
|
|
relationId == SharedDependDependerIndexId ||
|
|
relationId == SharedDependReferenceIndexId ||
|
|
diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c
|
|
--- base/src/backend/catalog/heap.c 2009-03-15 17:47:25.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/heap.c 2009-03-15 17:53:20.000000000 +0900
|
|
@@ -53,6 +53,7 @@
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_expr.h"
|
|
#include "parser/parse_relation.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
@@ -67,7 +68,8 @@ static void AddNewRelationTuple(Relation
|
|
Oid new_rel_oid, Oid new_type_oid,
|
|
Oid relowner,
|
|
char relkind,
|
|
- Datum reloptions);
|
|
+ Datum reloptions,
|
|
+ List *pgace_attr_list);
|
|
static Oid AddNewRelationType(const char *typeName,
|
|
Oid typeNamespace,
|
|
Oid new_rel_oid,
|
|
@@ -145,7 +147,13 @@ 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};
|
|
+static FormData_pg_attribute a8 = {
|
|
+ 0, {SecurityLabelAttributeName}, 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.
|
|
@@ -185,6 +193,18 @@ SystemAttributeByName(const char *attnam
|
|
return NULL;
|
|
}
|
|
|
|
+/*
|
|
+ * This function returns true, if the given attribute number is writable
|
|
+ * system column. If not, returns false.
|
|
+ */
|
|
+bool
|
|
+SystemAttributeIsWritable(AttrNumber attnum)
|
|
+{
|
|
+ if (attnum == SecurityLabelAttributeNumber)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* XXX END OF UGLY HARD CODED BADNESS XXX
|
|
@@ -468,7 +488,8 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|
TupleDesc tupdesc,
|
|
char relkind,
|
|
bool oidislocal,
|
|
- int oidinhcount)
|
|
+ int oidinhcount,
|
|
+ List *pgace_attr_list)
|
|
{
|
|
const Form_pg_attribute *dpp;
|
|
int i;
|
|
@@ -501,8 +522,10 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|
|
|
tup = heap_addheader(Natts_pg_attribute,
|
|
false,
|
|
+ RelationGetDescr(rel)->tdhasseclabel,
|
|
ATTRIBUTE_TUPLE_SIZE,
|
|
(void *) *dpp);
|
|
+ pgaceCreateAttributeCommon(rel, tup, pgace_attr_list);
|
|
|
|
simple_heap_insert(rel, tup);
|
|
|
|
@@ -538,6 +561,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|
|
|
tup = heap_addheader(Natts_pg_attribute,
|
|
false,
|
|
+ RelationGetDescr(rel)->tdhasseclabel,
|
|
ATTRIBUTE_TUPLE_SIZE,
|
|
(void *) *dpp);
|
|
attStruct = (Form_pg_attribute) GETSTRUCT(tup);
|
|
@@ -593,7 +617,8 @@ void
|
|
InsertPgClassTuple(Relation pg_class_desc,
|
|
Relation new_rel_desc,
|
|
Oid new_rel_oid,
|
|
- Datum reloptions)
|
|
+ Datum reloptions,
|
|
+ List *pgace_attr_list)
|
|
{
|
|
Form_pg_class rd_rel = new_rel_desc->rd_rel;
|
|
Datum values[Natts_pg_class];
|
|
@@ -643,12 +668,16 @@ InsertPgClassTuple(Relation pg_class_des
|
|
* be embarrassing to do this sort of thing in polite company.
|
|
*/
|
|
HeapTupleSetOid(tup, new_rel_oid);
|
|
+ pgaceCreateRelationCommon(pg_class_desc, tup, pgace_attr_list);
|
|
|
|
/* finally insert the new tuple, update the indexes, and clean up */
|
|
simple_heap_insert(pg_class_desc, tup);
|
|
|
|
CatalogUpdateIndexes(pg_class_desc, tup);
|
|
|
|
+ /* temporary use for this tuple */
|
|
+ InsertSysCache(RelationGetRelid(pg_class_desc), tup);
|
|
+
|
|
heap_freetuple(tup);
|
|
}
|
|
|
|
@@ -666,7 +695,8 @@ AddNewRelationTuple(Relation pg_class_de
|
|
Oid new_type_oid,
|
|
Oid relowner,
|
|
char relkind,
|
|
- Datum reloptions)
|
|
+ Datum reloptions,
|
|
+ List *pgace_attr_list)
|
|
{
|
|
Form_pg_class new_rel_reltup;
|
|
|
|
@@ -726,7 +756,7 @@ AddNewRelationTuple(Relation pg_class_de
|
|
new_rel_desc->rd_att->tdtypeid = new_type_oid;
|
|
|
|
/* Now build and insert the tuple */
|
|
- InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions);
|
|
+ InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions, pgace_attr_list);
|
|
}
|
|
|
|
|
|
@@ -794,7 +824,8 @@ heap_create_with_catalog(const char *rel
|
|
int oidinhcount,
|
|
OnCommitAction oncommit,
|
|
Datum reloptions,
|
|
- bool allow_system_table_mods)
|
|
+ bool allow_system_table_mods,
|
|
+ List *pgace_attr_list)
|
|
{
|
|
Relation pg_class_desc;
|
|
Relation new_rel_desc;
|
|
@@ -968,13 +999,20 @@ heap_create_with_catalog(const char *rel
|
|
new_type_oid,
|
|
ownerid,
|
|
relkind,
|
|
- reloptions);
|
|
+ reloptions,
|
|
+ pgace_attr_list);
|
|
|
|
/*
|
|
* 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, pgace_attr_list);
|
|
+
|
|
+ /*
|
|
+ * Fixup rel->rd_att->tdhasseclabel
|
|
+ */
|
|
+ new_rel_desc->rd_att->tdhasseclabel
|
|
+ = pgaceTupleDescHasSecLabel(new_rel_desc, NIL);
|
|
|
|
/*
|
|
* Make a dependency link to force the relation to be deleted if its
|
|
diff -rpNU3 base/src/backend/catalog/index.c sepgsql/src/backend/catalog/index.c
|
|
--- base/src/backend/catalog/index.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/index.c 2009-02-02 11:58:34.000000000 +0900
|
|
@@ -45,6 +45,7 @@
|
|
#include "optimizer/clauses.h"
|
|
#include "optimizer/var.h"
|
|
#include "parser/parse_expr.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/procarray.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/builtins.h"
|
|
@@ -315,6 +316,7 @@ AppendAttributeTuples(Relation indexRela
|
|
|
|
new_tuple = heap_addheader(Natts_pg_attribute,
|
|
false,
|
|
+ RelationGetDescr(pg_attribute)->tdhasseclabel,
|
|
ATTRIBUTE_TUPLE_SIZE,
|
|
(void *) indexTupDesc->attrs[i]);
|
|
|
|
@@ -602,6 +604,12 @@ index_create(Oid heapRelationId,
|
|
Assert(indexRelationId == RelationGetRelid(indexRelation));
|
|
|
|
/*
|
|
+ * Fixup rel->rd_att->tdhasseclabel
|
|
+ */
|
|
+ indexRelation->rd_att->tdhasseclabel
|
|
+ = pgaceTupleDescHasSecLabel(indexRelation, NIL);
|
|
+
|
|
+ /*
|
|
* Obtain exclusive lock on it. Although no other backends can see it
|
|
* until we commit, this prevents deadlock-risk complaints from lock
|
|
* manager in cases such as CLUSTER.
|
|
@@ -624,7 +632,7 @@ index_create(Oid heapRelationId,
|
|
*/
|
|
InsertPgClassTuple(pg_class, indexRelation,
|
|
RelationGetRelid(indexRelation),
|
|
- reloptions);
|
|
+ reloptions, NIL);
|
|
|
|
/* done with pg_class */
|
|
heap_close(pg_class, RowExclusiveLock);
|
|
diff -rpNU3 base/src/backend/catalog/pg_aggregate.c sepgsql/src/backend/catalog/pg_aggregate.c
|
|
--- base/src/backend/catalog/pg_aggregate.c 2008-01-14 22:59:48.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/pg_aggregate.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -213,8 +213,9 @@ AggregateCreate(const char *aggName,
|
|
PointerGetDatum(NULL), /* parameterModes */
|
|
PointerGetDatum(NULL), /* parameterNames */
|
|
PointerGetDatum(NULL), /* proconfig */
|
|
- 1, /* procost */
|
|
- 0); /* prorows */
|
|
+ 1, /* procost */
|
|
+ 0, /* prorows */
|
|
+ NULL); /* PGACE opaque */
|
|
|
|
/*
|
|
* Okay to create the pg_aggregate entry.
|
|
diff -rpNU3 base/src/backend/catalog/pg_largeobject.c sepgsql/src/backend/catalog/pg_largeobject.c
|
|
--- base/src/backend/catalog/pg_largeobject.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/pg_largeobject.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -18,6 +18,7 @@
|
|
#include "access/heapam.h"
|
|
#include "catalog/indexing.h"
|
|
#include "catalog/pg_largeobject.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
|
|
@@ -57,6 +58,8 @@ LargeObjectCreate(Oid loid)
|
|
|
|
ntup = heap_formtuple(pg_largeobject->rd_att, values, nulls);
|
|
|
|
+ pgaceLargeObjectCreate(pg_largeobject, ntup);
|
|
+
|
|
/*
|
|
* Insert it
|
|
*/
|
|
@@ -78,6 +81,7 @@ LargeObjectDrop(Oid loid)
|
|
ScanKeyData skey[1];
|
|
SysScanDesc sd;
|
|
HeapTuple tuple;
|
|
+ void *pgaceItem = NULL;
|
|
|
|
ScanKeyInit(&skey[0],
|
|
Anum_pg_largeobject_loid,
|
|
@@ -91,6 +95,7 @@ LargeObjectDrop(Oid loid)
|
|
|
|
while ((tuple = systable_getnext(sd)) != NULL)
|
|
{
|
|
+ pgaceLargeObjectDrop(pg_largeobject, tuple, &pgaceItem);
|
|
simple_heap_delete(pg_largeobject, &tuple->t_self);
|
|
found = true;
|
|
}
|
|
diff -rpNU3 base/src/backend/catalog/pg_proc.c sepgsql/src/backend/catalog/pg_proc.c
|
|
--- base/src/backend/catalog/pg_proc.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/pg_proc.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -27,6 +27,7 @@
|
|
#include "mb/pg_wchar.h"
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_type.h"
|
|
+#include "security/pgace.h"
|
|
#include "tcop/pquery.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/acl.h"
|
|
@@ -74,7 +75,8 @@ ProcedureCreate(const char *procedureNam
|
|
Datum parameterNames,
|
|
Datum proconfig,
|
|
float4 procost,
|
|
- float4 prorows)
|
|
+ float4 prorows,
|
|
+ void *pgaceItem)
|
|
{
|
|
Oid retval;
|
|
int parameterCount;
|
|
@@ -339,6 +341,7 @@ ProcedureCreate(const char *procedureNam
|
|
|
|
/* Okay, do it... */
|
|
tup = heap_modifytuple(oldtup, tupDesc, values, nulls, replaces);
|
|
+ pgaceGramCreateFunction(rel, tup, (DefElem *)pgaceItem);
|
|
simple_heap_update(rel, &tup->t_self, tup);
|
|
|
|
ReleaseSysCache(oldtup);
|
|
@@ -348,6 +351,7 @@ ProcedureCreate(const char *procedureNam
|
|
{
|
|
/* Creating a new procedure */
|
|
tup = heap_formtuple(tupDesc, values, nulls);
|
|
+ pgaceGramCreateFunction(rel, tup, (DefElem *)pgaceItem);
|
|
simple_heap_insert(rel, tup);
|
|
is_update = false;
|
|
}
|
|
diff -rpNU3 base/src/backend/catalog/toasting.c sepgsql/src/backend/catalog/toasting.c
|
|
--- base/src/backend/catalog/toasting.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/toasting.c 2008-11-24 12:05:32.000000000 +0900
|
|
@@ -199,7 +199,8 @@ create_toast_table(Relation rel, Oid toa
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
(Datum) 0,
|
|
- true);
|
|
+ true,
|
|
+ NIL);
|
|
|
|
/* make the toast relation visible, else index creation will fail */
|
|
CommandCounterIncrement();
|
|
diff -rpNU3 base/src/backend/commands/cluster.c sepgsql/src/backend/commands/cluster.c
|
|
--- base/src/backend/commands/cluster.c 2008-02-03 01:11:28.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/cluster.c 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -666,7 +666,8 @@ make_new_heap(Oid OIDOldHeap, const char
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
reloptions,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ NIL);
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
@@ -857,6 +858,10 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOl
|
|
if (NewHeap->rd_rel->relhasoids)
|
|
HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple));
|
|
|
|
+ /* Preserve SID, if any */
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(copiedTuple, HeapTupleGetSecLabel(tuple));
|
|
+
|
|
/* The heap rewrite module does the rest */
|
|
rewrite_heap_tuple(rwstate, tuple, copiedTuple);
|
|
|
|
diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c
|
|
--- base/src/backend/commands/copy.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/copy.c 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -22,6 +22,7 @@
|
|
|
|
#include "access/heapam.h"
|
|
#include "access/xact.h"
|
|
+#include "catalog/heap.h"
|
|
#include "catalog/namespace.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "commands/copy.h"
|
|
@@ -34,6 +35,7 @@
|
|
#include "optimizer/planner.h"
|
|
#include "parser/parse_relation.h"
|
|
#include "rewrite/rewriteHandler.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/fd.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/acl.h"
|
|
@@ -159,6 +161,10 @@ 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;
|
|
@@ -242,7 +248,7 @@ static const char BinarySignature[11] =
|
|
/* 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, Oid tupleOid, Oid secLabelId,
|
|
Datum *values, bool *nulls);
|
|
static void CopyFrom(CopyState cstate);
|
|
static bool CopyReadLine(CopyState cstate);
|
|
@@ -1073,6 +1079,8 @@ DoCopy(const CopyStmt *stmt, const char
|
|
/* Generate or convert list of attributes to process */
|
|
cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
|
|
|
|
+ pgaceCopyTable(cstate->rel, cstate->attnumlist, is_from);
|
|
+
|
|
num_phys_attrs = tupDesc->natts;
|
|
|
|
/* Convert FORCE QUOTE name list to per-column flags, check validity */
|
|
@@ -1089,11 +1097,32 @@ DoCopy(const CopyStmt *stmt, const char
|
|
int attnum = lfirst_int(cur);
|
|
|
|
if (!list_member_int(cstate->attnumlist, attnum))
|
|
+ {
|
|
+ Form_pg_attribute attForm;
|
|
+
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ attForm = SystemAttributeDefinition(attnum, true);
|
|
+ else
|
|
+ attForm = tupDesc->attrs[attnum - 1];
|
|
+
|
|
+ Assert(attForm != NULL);
|
|
+
|
|
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))));
|
|
+ }
|
|
+
|
|
+ switch (attnum)
|
|
+ {
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ cstate->seclabel_force_quot = true;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ cstate->force_quote_flags[attnum - 1] = true;
|
|
+ break;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -1111,10 +1140,24 @@ DoCopy(const CopyStmt *stmt, const char
|
|
int attnum = lfirst_int(cur);
|
|
|
|
if (!list_member_int(cstate->attnumlist, attnum))
|
|
+ {
|
|
+ Form_pg_attribute attForm;
|
|
+
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ attForm = SystemAttributeDefinition(attnum, true);
|
|
+ else
|
|
+ attForm = tupDesc->attrs[attnum - 1];
|
|
+
|
|
+ Assert(attForm != NULL);
|
|
+
|
|
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))));
|
|
+ }
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ continue; /* ignore, if specified */
|
|
+
|
|
cstate->force_notnull_flags[attnum - 1] = true;
|
|
}
|
|
}
|
|
@@ -1242,6 +1285,9 @@ DoCopyTo(CopyState cstate)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
errmsg("\"%s\" is a directory", cstate->filename)));
|
|
+
|
|
+ pgaceCopyFile(cstate->rel, fileno(cstate->copy_file),
|
|
+ cstate->filename, false);
|
|
}
|
|
|
|
PG_TRY();
|
|
@@ -1305,16 +1351,30 @@ CopyTo(CopyState cstate)
|
|
int attnum = lfirst_int(cur);
|
|
Oid out_func_oid;
|
|
bool isvarlena;
|
|
+ FmgrInfo *out_fmgr;
|
|
+ Form_pg_attribute attForm;
|
|
+
|
|
+ switch (attnum)
|
|
+ {
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ attForm = SystemAttributeDefinition(attnum, true);
|
|
+ out_fmgr = &cstate->seclabel_out_function;
|
|
+ break;
|
|
+ default: /* user columns */
|
|
+ attForm = attr[attnum - 1];
|
|
+ out_fmgr = &cstate->out_functions[attnum - 1];
|
|
+ break;
|
|
+ }
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
@@ -1369,7 +1429,14 @@ CopyTo(CopyState cstate)
|
|
CopySendChar(cstate, cstate->delim[0]);
|
|
hdr_delim = true;
|
|
|
|
- colname = NameStr(attr[attnum - 1]->attname);
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ {
|
|
+ Form_pg_attribute attForm
|
|
+ = SystemAttributeDefinition(attnum, true);
|
|
+ colname = NameStr(attForm->attname);
|
|
+ }
|
|
+ else
|
|
+ colname = NameStr(attr[attnum - 1]->attname);
|
|
|
|
CopyAttributeOutCSV(cstate, colname, false,
|
|
list_length(cstate->attnumlist) == 1);
|
|
@@ -1395,11 +1462,17 @@ CopyTo(CopyState cstate)
|
|
{
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
+ if (!pgaceCopyToTuple(cstate->rel, cstate->attnumlist, 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,
|
|
+ HeapTupleGetOid(tuple),
|
|
+ HeapTupleGetSecLabel(tuple),
|
|
+ values, nulls);
|
|
}
|
|
|
|
heap_endscan(scandesc);
|
|
@@ -1425,7 +1498,8 @@ CopyTo(CopyState cstate)
|
|
* Emit one row during CopyTo().
|
|
*/
|
|
static void
|
|
-CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls)
|
|
+CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid secLabelId,
|
|
+ Datum *values, bool *nulls)
|
|
{
|
|
bool need_delim = false;
|
|
FmgrInfo *out_functions = cstate->out_functions;
|
|
@@ -1464,8 +1538,10 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
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)
|
|
{
|
|
@@ -1474,6 +1550,23 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
need_delim = true;
|
|
}
|
|
|
|
+ switch (attnum)
|
|
+ {
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ value = CStringGetTextDatum(pgaceSidToSecurityLabel(secLabelId));
|
|
+ isnull = false;
|
|
+ force_quot = cstate->seclabel_force_quot;
|
|
+ out_fmgr = &cstate->seclabel_out_function;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ value = values[attnum - 1];
|
|
+ isnull = nulls[attnum - 1];
|
|
+ force_quot = cstate->force_quote_flags[attnum - 1];
|
|
+ out_fmgr = &out_functions[attnum - 1];
|
|
+ break;
|
|
+ }
|
|
+
|
|
if (isnull)
|
|
{
|
|
if (!cstate->binary)
|
|
@@ -1485,11 +1578,9 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
{
|
|
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);
|
|
@@ -1498,8 +1589,7 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
{
|
|
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);
|
|
@@ -1633,10 +1723,13 @@ 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;
|
|
+ ListCell *l;
|
|
Oid in_func_oid;
|
|
Datum *values;
|
|
char *nulls;
|
|
@@ -1737,6 +1830,9 @@ CopyFrom(CopyState cstate)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
errmsg("\"%s\" is a directory", cstate->filename)));
|
|
+
|
|
+ pgaceCopyFile(cstate->rel, fileno(cstate->copy_file),
|
|
+ cstate->filename, true);
|
|
}
|
|
|
|
tupDesc = RelationGetDescr(cstate->rel);
|
|
@@ -1872,6 +1968,24 @@ CopyFrom(CopyState cstate)
|
|
fmgr_info(in_func_oid, &oid_in_function);
|
|
}
|
|
|
|
+ foreach (l, cstate->attnumlist)
|
|
+ {
|
|
+ switch (lfirst_int(l))
|
|
+ {
|
|
+ case 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);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
|
|
nulls = (char *) palloc(num_phys_attrs * sizeof(char));
|
|
|
|
@@ -1904,6 +2018,7 @@ CopyFrom(CopyState cstate)
|
|
{
|
|
bool skip_tuple;
|
|
Oid loaded_oid = InvalidOid;
|
|
+ Datum loaded_seclabel = PointerGetDatum(NULL);
|
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
@@ -1978,6 +2093,37 @@ CopyFrom(CopyState cstate)
|
|
int attnum = lfirst_int(cur);
|
|
int m = attnum - 1;
|
|
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ {
|
|
+ Form_pg_attribute attForm
|
|
+ = SystemAttributeDefinition(attnum, true);
|
|
+
|
|
+ if (fieldno >= fldct)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
|
+ errmsg("missing data for column \"%s\"",
|
|
+ NameStr(attForm->attname))));
|
|
+ string = field_strings[fieldno++];
|
|
+ cstate->cur_attname = NameStr(attForm->attname);
|
|
+ cstate->cur_attval = string;
|
|
+ if (string)
|
|
+ {
|
|
+ switch (attnum)
|
|
+ {
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ loaded_seclabel
|
|
+ = InputFunctionCall(&seclabel_in_function,
|
|
+ string,
|
|
+ seclabel_typioparam,
|
|
+ attForm->atttypmod);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ cstate->cur_attname = NULL;
|
|
+ cstate->cur_attval = NULL;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
if (fieldno >= fldct)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
|
@@ -2048,6 +2194,31 @@ CopyFrom(CopyState cstate)
|
|
int attnum = lfirst_int(cur);
|
|
int m = attnum - 1;
|
|
|
|
+ if (SystemAttributeIsWritable(attnum))
|
|
+ {
|
|
+ Form_pg_attribute attForm
|
|
+ = SystemAttributeDefinition(attnum, false);
|
|
+ Datum tmp;
|
|
+
|
|
+ cstate->cur_attname = NameStr(attForm->attname);
|
|
+ i++;
|
|
+
|
|
+ switch (attnum)
|
|
+ {
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ tmp = CopyReadBinaryAttribute(cstate, i,
|
|
+ &seclabel_in_function,
|
|
+ seclabel_typioparam,
|
|
+ attForm->atttypmod,
|
|
+ &isnull);
|
|
+ if (!isnull)
|
|
+ loaded_seclabel = tmp;
|
|
+ break;
|
|
+ }
|
|
+ cstate->cur_attname = NULL;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
cstate->cur_attname = NameStr(attr[m]->attname);
|
|
i++;
|
|
values[m] = CopyReadBinaryAttribute(cstate,
|
|
@@ -2079,6 +2250,11 @@ CopyFrom(CopyState cstate)
|
|
|
|
if (cstate->oids && file_has_oids)
|
|
HeapTupleSetOid(tuple, loaded_oid);
|
|
+ if (loaded_seclabel != PointerGetDatum(NULL))
|
|
+ {
|
|
+ char *label = TextDatumGetCString(loaded_seclabel);
|
|
+ HeapTupleSetSecLabel(tuple, pgaceSecurityLabelToSid(label));
|
|
+ }
|
|
|
|
/* Triggers and stuff need to be invoked in query context. */
|
|
MemoryContextSwitchTo(oldcontext);
|
|
@@ -2102,6 +2278,9 @@ CopyFrom(CopyState cstate)
|
|
}
|
|
}
|
|
|
|
+ if (!skip_tuple && !pgaceHeapTupleInsert(cstate->rel, tuple, false, false))
|
|
+ skip_tuple = true;
|
|
+
|
|
if (!skip_tuple)
|
|
{
|
|
/* Place tuple in tuple slot */
|
|
@@ -3364,6 +3543,16 @@ CopyGetAttnums(TupleDesc tupDesc, Relati
|
|
break;
|
|
}
|
|
}
|
|
+
|
|
+ /* Is it writable system column? */
|
|
+ if (attnum == InvalidAttrNumber)
|
|
+ {
|
|
+ Form_pg_attribute attForm
|
|
+ = SystemAttributeByName(name, tupDesc->tdhasoid);
|
|
+ if (attForm && SystemAttributeIsWritable(attForm->attnum))
|
|
+ attnum = attForm->attnum;
|
|
+ }
|
|
+
|
|
if (attnum == InvalidAttrNumber)
|
|
{
|
|
if (rel != NULL)
|
|
@@ -3413,7 +3602,9 @@ copy_dest_receive(TupleTableSlot *slot,
|
|
slot_getallattrs(slot);
|
|
|
|
/* And send the data */
|
|
- CopyOneRowTo(cstate, InvalidOid, slot->tts_values, slot->tts_isnull);
|
|
+ CopyOneRowTo(cstate,
|
|
+ InvalidOid, InvalidOid,
|
|
+ slot->tts_values, slot->tts_isnull);
|
|
}
|
|
|
|
/*
|
|
diff -rpNU3 base/src/backend/commands/dbcommands.c sepgsql/src/backend/commands/dbcommands.c
|
|
--- base/src/backend/commands/dbcommands.c 2008-11-05 09:57:00.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/dbcommands.c 2008-11-05 10:01:30.000000000 +0900
|
|
@@ -40,6 +40,7 @@
|
|
#include "miscadmin.h"
|
|
#include "pgstat.h"
|
|
#include "postmaster/bgwriter.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/freespace.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/procarray.h"
|
|
@@ -100,6 +101,7 @@ createdb(const CreatedbStmt *stmt)
|
|
DefElem *dtemplate = NULL;
|
|
DefElem *dencoding = NULL;
|
|
DefElem *dconnlimit = NULL;
|
|
+ DefElem *dpgace_item = NULL;
|
|
char *dbname = stmt->dbname;
|
|
char *dbowner = NULL;
|
|
const char *dbtemplate = NULL;
|
|
@@ -160,6 +162,13 @@ createdb(const CreatedbStmt *stmt)
|
|
errmsg("LOCATION is not supported anymore"),
|
|
errhint("Consider using tablespaces instead.")));
|
|
}
|
|
+ else if (pgaceIsGramSecurityItem(defel)) {
|
|
+ if (dpgace_item)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ dpgace_item = defel;
|
|
+ }
|
|
else
|
|
elog(ERROR, "option \"%s\" not recognized",
|
|
defel->defname);
|
|
@@ -433,6 +442,7 @@ createdb(const CreatedbStmt *stmt)
|
|
new_record, new_record_nulls);
|
|
|
|
HeapTupleSetOid(tuple, dboid);
|
|
+ pgaceGramCreateDatabase(pg_database_rel, tuple, dpgace_item);
|
|
|
|
simple_heap_insert(pg_database_rel, tuple);
|
|
|
|
@@ -858,6 +868,7 @@ AlterDatabase(AlterDatabaseStmt *stmt)
|
|
ListCell *option;
|
|
int connlimit = -1;
|
|
DefElem *dconnlimit = NULL;
|
|
+ DefElem *dpgace_item = NULL;
|
|
Datum new_record[Natts_pg_database];
|
|
char new_record_nulls[Natts_pg_database];
|
|
char new_record_repl[Natts_pg_database];
|
|
@@ -875,6 +886,13 @@ AlterDatabase(AlterDatabaseStmt *stmt)
|
|
errmsg("conflicting or redundant options")));
|
|
dconnlimit = defel;
|
|
}
|
|
+ else if (pgaceIsGramSecurityItem(defel)) {
|
|
+ if (dpgace_item)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ dpgace_item = defel;
|
|
+ }
|
|
else
|
|
elog(ERROR, "option \"%s\" not recognized",
|
|
defel->defname);
|
|
@@ -920,6 +938,7 @@ AlterDatabase(AlterDatabaseStmt *stmt)
|
|
|
|
newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), new_record,
|
|
new_record_nulls, new_record_repl);
|
|
+ pgaceGramAlterDatabase(rel, newtuple, dpgace_item);
|
|
simple_heap_update(rel, &tuple->t_self, newtuple);
|
|
|
|
/* Update indexes */
|
|
diff -rpNU3 base/src/backend/commands/functioncmds.c sepgsql/src/backend/commands/functioncmds.c
|
|
--- base/src/backend/commands/functioncmds.c 2009-03-15 17:47:25.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/functioncmds.c 2009-03-15 17:53:20.000000000 +0900
|
|
@@ -47,6 +47,7 @@
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_func.h"
|
|
#include "parser/parse_type.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
@@ -412,7 +413,8 @@ compute_attributes_sql_style(List *optio
|
|
bool *security_definer,
|
|
ArrayType **proconfig,
|
|
float4 *procost,
|
|
- float4 *prorows)
|
|
+ float4 *prorows,
|
|
+ DefElem **pgaceItem)
|
|
{
|
|
ListCell *option;
|
|
DefElem *as_item = NULL;
|
|
@@ -444,6 +446,14 @@ compute_attributes_sql_style(List *optio
|
|
errmsg("conflicting or redundant options")));
|
|
language_item = defel;
|
|
}
|
|
+ else if (pgaceIsGramSecurityItem(defel))
|
|
+ {
|
|
+ if (*pgaceItem)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ *pgaceItem = defel;
|
|
+ }
|
|
else if (compute_common_attribute(defel,
|
|
&volatility_item,
|
|
&strict_item,
|
|
@@ -624,6 +634,7 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|
HeapTuple languageTuple;
|
|
Form_pg_language languageStruct;
|
|
List *as_clause;
|
|
+ DefElem *pgaceItem = NULL;
|
|
|
|
/* Convert list of names to a name and namespace */
|
|
namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
|
|
@@ -647,7 +658,7 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|
compute_attributes_sql_style(stmt->options,
|
|
&as_clause, &language,
|
|
&volatility, &isStrict, &security,
|
|
- &proconfig, &procost, &prorows);
|
|
+ &proconfig, &procost, &prorows, &pgaceItem);
|
|
|
|
/* Convert language name to canonical case */
|
|
languageName = case_translate_language_name(language);
|
|
@@ -801,7 +812,8 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|
PointerGetDatum(parameterNames),
|
|
PointerGetDatum(proconfig),
|
|
procost,
|
|
- prorows);
|
|
+ prorows,
|
|
+ pgaceItem);
|
|
}
|
|
|
|
|
|
@@ -1151,6 +1163,7 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|
List *set_items = NIL;
|
|
DefElem *cost_item = NULL;
|
|
DefElem *rows_item = NULL;
|
|
+ DefElem *pgaceItem = NULL;
|
|
|
|
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
|
|
|
|
@@ -1182,6 +1195,15 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|
{
|
|
DefElem *defel = (DefElem *) lfirst(l);
|
|
|
|
+ if (pgaceIsGramSecurityItem(defel)) {
|
|
+ if (pgaceItem)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ pgaceItem = defel;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
if (compute_common_attribute(defel,
|
|
&volatility_item,
|
|
&strict_item,
|
|
@@ -1252,6 +1274,7 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|
tup = heap_modifytuple(tup, RelationGetDescr(rel),
|
|
repl_val, repl_null, repl_repl);
|
|
}
|
|
+ pgaceGramAlterFunction(rel, tup, pgaceItem);
|
|
|
|
/* Do the update */
|
|
simple_heap_update(rel, &tup->t_self, tup);
|
|
diff -rpNU3 base/src/backend/commands/lockcmds.c sepgsql/src/backend/commands/lockcmds.c
|
|
--- base/src/backend/commands/lockcmds.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/lockcmds.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -18,6 +18,7 @@
|
|
#include "catalog/namespace.h"
|
|
#include "commands/lockcmds.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/lsyscache.h"
|
|
|
|
@@ -59,6 +60,8 @@ LockTableCommand(LockStmt *lockstmt)
|
|
aclcheck_error(aclresult, ACL_KIND_CLASS,
|
|
get_rel_name(reloid));
|
|
|
|
+ pgaceLockTable(reloid);
|
|
+
|
|
if (lockstmt->nowait)
|
|
rel = relation_open_nowait(reloid, lockstmt->mode);
|
|
else
|
|
diff -rpNU3 base/src/backend/commands/proclang.c sepgsql/src/backend/commands/proclang.c
|
|
--- base/src/backend/commands/proclang.c 2008-06-12 22:34:19.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/proclang.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -146,7 +146,8 @@ CreateProceduralLanguage(CreatePLangStmt
|
|
PointerGetDatum(NULL),
|
|
PointerGetDatum(NULL),
|
|
1,
|
|
- 0);
|
|
+ 0,
|
|
+ NULL);
|
|
}
|
|
|
|
/*
|
|
@@ -179,7 +180,8 @@ CreateProceduralLanguage(CreatePLangStmt
|
|
PointerGetDatum(NULL),
|
|
PointerGetDatum(NULL),
|
|
1,
|
|
- 0);
|
|
+ 0,
|
|
+ NULL);
|
|
}
|
|
}
|
|
else
|
|
diff -rpNU3 base/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/tablecmds.c
|
|
--- base/src/backend/commands/tablecmds.c 2008-11-05 09:57:00.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/tablecmds.c 2009-01-21 17:26:07.000000000 +0900
|
|
@@ -57,6 +57,7 @@
|
|
#include "parser/parser.h"
|
|
#include "rewrite/rewriteDefine.h"
|
|
#include "rewrite/rewriteHandler.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
@@ -434,7 +435,8 @@ DefineRelation(CreateStmt *stmt, char re
|
|
parentOidCount,
|
|
stmt->oncommit,
|
|
reloptions,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ pgaceRelationAttrList(stmt));
|
|
|
|
StoreCatalogInheritance(relationId, inheritOids);
|
|
|
|
@@ -598,6 +600,8 @@ ExecuteTruncate(TruncateStmt *stmt)
|
|
heap_truncate_check_FKs(rels, false);
|
|
#endif
|
|
|
|
+ pgaceExecTruncate(rels);
|
|
+
|
|
/*
|
|
* OK, truncate each table.
|
|
*/
|
|
@@ -2031,6 +2035,7 @@ ATPrepCmd(List **wqueue, Relation rel, A
|
|
case AT_DisableRule:
|
|
case AT_AddInherit: /* INHERIT / NO INHERIT */
|
|
case AT_DropInherit:
|
|
+ case AT_SetSecurityLabel:
|
|
ATSimplePermissions(rel, false);
|
|
/* These commands never recurse */
|
|
/* No command-specific prep needed */
|
|
@@ -2253,6 +2258,9 @@ ATExecCmd(AlteredTableInfo *tab, Relatio
|
|
case AT_DropInherit:
|
|
ATExecDropInherit(rel, (RangeVar *) cmd->def);
|
|
break;
|
|
+ case AT_SetSecurityLabel:
|
|
+ pgaceAlterRelationCommon(rel, cmd);
|
|
+ break;
|
|
default: /* oops */
|
|
elog(ERROR, "unrecognized alter table type: %d",
|
|
(int) cmd->subtype);
|
|
@@ -2591,11 +2599,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oi
|
|
if (newrel)
|
|
{
|
|
Oid tupOid = InvalidOid;
|
|
+ Oid tupSid = InvalidOid;
|
|
|
|
/* Extract data from old tuple */
|
|
heap_deform_tuple(tuple, oldTupDesc, values, isnull);
|
|
if (oldTupDesc->tdhasoid)
|
|
tupOid = HeapTupleGetOid(tuple);
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ tupSid = HeapTupleGetSecLabel(tuple);
|
|
|
|
/* Set dropped attributes to null in new tuple */
|
|
foreach(lc, dropped_attrs)
|
|
@@ -2627,6 +2638,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oi
|
|
/* Preserve OID, if any */
|
|
if (newTupDesc->tdhasoid)
|
|
HeapTupleSetOid(tuple, tupOid);
|
|
+ /* Preserve Security ID, if any */
|
|
+ if (tupSid != InvalidOid)
|
|
+ HeapTupleSetSecLabel(tuple, tupSid);
|
|
}
|
|
|
|
/* Now check any constraints on the possibly-changed tuple */
|
|
@@ -3113,6 +3127,7 @@ ATExecAddColumn(AlteredTableInfo *tab, R
|
|
|
|
attributeTuple = heap_addheader(Natts_pg_attribute,
|
|
false,
|
|
+ RelationGetDescr(attrdesc)->tdhasseclabel,
|
|
ATTRIBUTE_TUPLE_SIZE,
|
|
(void *) &attributeD);
|
|
|
|
diff -rpNU3 base/src/backend/commands/trigger.c sepgsql/src/backend/commands/trigger.c
|
|
--- base/src/backend/commands/trigger.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/trigger.c 2009-02-02 11:58:34.000000000 +0900
|
|
@@ -31,6 +31,7 @@
|
|
#include "miscadmin.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/parse_func.h"
|
|
+#include "security/pgace.h"
|
|
#include "tcop/utility.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
@@ -1551,10 +1552,16 @@ ExecCallTriggerFunc(TriggerData *trigdat
|
|
* call.
|
|
*/
|
|
if (finfo->fn_oid == InvalidOid)
|
|
+ {
|
|
fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
|
|
+ pgaceCallFunction(finfo);
|
|
+ }
|
|
|
|
Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);
|
|
|
|
+ if (!pgaceCallTriggerFunction(trigdata))
|
|
+ return (HeapTuple) NULL;
|
|
+
|
|
/*
|
|
* If doing EXPLAIN ANALYZE, start charging time to this trigger.
|
|
*/
|
|
@@ -1574,6 +1581,7 @@ ExecCallTriggerFunc(TriggerData *trigdat
|
|
*/
|
|
InitFunctionCallInfoData(fcinfo, finfo, 0, (Node *) trigdata, NULL);
|
|
|
|
+
|
|
result = FunctionCallInvoke(&fcinfo);
|
|
|
|
MemoryContextSwitchTo(oldContext);
|
|
@@ -1971,6 +1979,20 @@ ExecBRUpdateTriggers(EState *estate, Res
|
|
if (newSlot != NULL)
|
|
intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
|
|
|
|
+ /*
|
|
+ * The before-row-triggers are fired prior to transcribing system
|
|
+ * attributes from the old tuple to the new one. When no explicit
|
|
+ * new values are given, we have to preserve them, so the following
|
|
+ * code do it to avoid to make triggers get confusion.
|
|
+ */
|
|
+ if (HeapTupleHasOid(newtuple) &&
|
|
+ !OidIsValid(HeapTupleGetOid(newtuple)))
|
|
+ HeapTupleSetOid(newtuple, HeapTupleGetOid(trigtuple));
|
|
+
|
|
+ if (HeapTupleHasSecLabel(newtuple) &&
|
|
+ !OidIsValid(HeapTupleGetSecLabel(newtuple)))
|
|
+ HeapTupleSetSecLabel(newtuple, HeapTupleGetSecLabel(trigtuple));
|
|
+
|
|
LocTriggerData.type = T_TriggerData;
|
|
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
|
|
TRIGGER_EVENT_ROW |
|
|
diff -rpNU3 base/src/backend/executor/execJunk.c sepgsql/src/backend/executor/execJunk.c
|
|
--- base/src/backend/executor/execJunk.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/execJunk.c 2008-11-21 23:11:55.000000000 +0900
|
|
@@ -60,7 +60,8 @@
|
|
* An optional resultSlot can be passed as well.
|
|
*/
|
|
JunkFilter *
|
|
-ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
|
|
+ExecInitJunkFilter(List *targetList, bool hasoid, bool hassecurity,
|
|
+ TupleTableSlot *slot)
|
|
{
|
|
JunkFilter *junkfilter;
|
|
TupleDesc cleanTupType;
|
|
@@ -72,7 +73,7 @@ ExecInitJunkFilter(List *targetList, boo
|
|
/*
|
|
* Compute the tuple descriptor for the cleaned tuple.
|
|
*/
|
|
- cleanTupType = ExecCleanTypeFromTL(targetList, hasoid);
|
|
+ cleanTupType = ExecCleanTypeFromTL(targetList, hasoid, hassecurity);
|
|
|
|
/*
|
|
* Use the given slot, or make a new slot if we weren't given one.
|
|
diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/execMain.c
|
|
--- base/src/backend/executor/execMain.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/execMain.c 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -49,6 +49,7 @@
|
|
#include "parser/parse_clause.h"
|
|
#include "parser/parse_expr.h"
|
|
#include "parser/parsetree.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
@@ -139,6 +140,8 @@ ExecutorStart(QueryDesc *queryDesc, int
|
|
Assert(queryDesc != NULL);
|
|
Assert(queryDesc->estate == NULL);
|
|
|
|
+ pgaceExecutorStart(queryDesc, eflags);
|
|
+
|
|
/*
|
|
* If the transaction is read-only, we need to check if any writes are
|
|
* planned to non-temporary tables. EXPLAIN is considered read-only.
|
|
@@ -738,16 +741,16 @@ InitPlan(QueryDesc *queryDesc, int eflag
|
|
for (i = 0; i < as_nplans; i++)
|
|
{
|
|
PlanState *subplan = appendplans[i];
|
|
+ Relation resultRel = resultRelInfo->ri_RelationDesc;
|
|
JunkFilter *j;
|
|
|
|
if (operation == CMD_UPDATE)
|
|
- ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
|
|
- subplan->plan->targetlist);
|
|
+ ExecCheckPlanOutput(resultRel, subplan->plan->targetlist);
|
|
|
|
j = ExecInitJunkFilter(subplan->plan->targetlist,
|
|
- resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
|
|
- ExecAllocTableSlot(estate->es_tupleTable));
|
|
-
|
|
+ RelationGetDescr(resultRel)->tdhasoid,
|
|
+ RelationGetDescr(resultRel)->tdhasseclabel,
|
|
+ ExecAllocTableSlot(estate->es_tupleTable));
|
|
/*
|
|
* Since it must be UPDATE/DELETE, there had better be a
|
|
* "ctid" junk attribute in the tlist ... but ctid could
|
|
@@ -789,7 +792,7 @@ InitPlan(QueryDesc *queryDesc, int eflag
|
|
planstate->plan->targetlist);
|
|
|
|
j = ExecInitJunkFilter(planstate->plan->targetlist,
|
|
- tupType->tdhasoid,
|
|
+ tupType->tdhasoid, tupType->tdhasseclabel,
|
|
ExecAllocTableSlot(estate->es_tupleTable));
|
|
estate->es_junkFilter = j;
|
|
if (estate->es_result_relation_info)
|
|
@@ -848,7 +851,7 @@ InitPlan(QueryDesc *queryDesc, int eflag
|
|
* We assume all the sublists will generate the same output tupdesc.
|
|
*/
|
|
tupType = ExecTypeFromTL((List *) linitial(plannedstmt->returningLists),
|
|
- false);
|
|
+ false, false);
|
|
|
|
/* Set up a slot for the output of the RETURNING projection(s) */
|
|
slot = ExecAllocTableSlot(estate->es_tupleTable);
|
|
@@ -1171,6 +1174,42 @@ ExecContextForcesOids(PlanState *plansta
|
|
return false;
|
|
}
|
|
|
|
+/*
|
|
+ * ExecContextForcesSecLabel
|
|
+ *
|
|
+ * We need to ensure that result tuples have space for security attribute,
|
|
+ * if the security mechanism are going to be stored it into the given
|
|
+ * relation.
|
|
+ * The hook gives relation identifier and its kind as a hint. However,
|
|
+ * the relation identifer can be InvalidOid when the relation is to
|
|
+ * be newly created via SELECT INTO, because the creation of the relation
|
|
+ * will be done after invocation of the function.
|
|
+ */
|
|
+bool ExecContextForcesSecLabel(PlanState *planstate, bool *hasseclabel)
|
|
+{
|
|
+ if (planstate->state->es_select_into)
|
|
+ {
|
|
+ IntoClause *into = planstate->state->es_plannedstmt->intoClause;
|
|
+
|
|
+ Assert(into != NULL);
|
|
+
|
|
+ *hasseclabel = pgaceTupleDescHasSecLabel(NULL, into->options);
|
|
+ return true;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ResultRelInfo *ri = planstate->state->es_result_relation_info;
|
|
+
|
|
+ if (ri && ri->ri_RelationDesc)
|
|
+ {
|
|
+ *hasseclabel = pgaceTupleDescHasSecLabel(ri->ri_RelationDesc, NIL);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
/* ----------------------------------------------------------------
|
|
* ExecEndPlan
|
|
*
|
|
@@ -1251,6 +1290,61 @@ ExecEndPlan(PlanState *planstate, EState
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * fetchWritableSystemAttribute() fetches writable system column data
|
|
+ * using Junkfilter, and saves them at TupleTableSlot temporary.
|
|
+ *
|
|
+ * storeWritableSystemAttribute() copies these fetched data into
|
|
+ * header structure of HeapTuple.
|
|
+ */
|
|
+static void
|
|
+fetchWritableSystemAttribute(JunkFilter *junkfilter, TupleTableSlot *slot,
|
|
+ Datum *tts_seclabel)
|
|
+{
|
|
+ AttrNumber attno;
|
|
+ Datum datum;
|
|
+ bool isnull;
|
|
+
|
|
+ /* for Security Label */
|
|
+ attno = ExecFindJunkAttribute(junkfilter, SecurityLabelAttributeName);
|
|
+ if (attno != InvalidAttrNumber)
|
|
+ {
|
|
+ datum = ExecGetJunkAttribute(slot, attno, &isnull);
|
|
+ if (isnull)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("null value in column \"%s\" violates not-null constraint",
|
|
+ SecurityLabelAttributeName)));
|
|
+ *tts_seclabel = datum;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+storeWritableSystemAttribute(Relation rel, TupleTableSlot *slot, HeapTuple tuple)
|
|
+{
|
|
+ /* for security attribute */
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ {
|
|
+ if (!DatumGetPointer(slot->tts_seclabel))
|
|
+ HeapTupleSetSecLabel(tuple, InvalidOid);
|
|
+ else
|
|
+ {
|
|
+ char *label = TextDatumGetCString(slot->tts_seclabel);
|
|
+
|
|
+ HeapTupleSetSecLabel(tuple,
|
|
+ pgaceSecurityLabelToSid(label));
|
|
+ }
|
|
+ }
|
|
+ else if (DatumGetPointer(slot->tts_seclabel))
|
|
+ {
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("enhanced security mechanism does not allocate "
|
|
+ "a field to store security attribute for relation: %s",
|
|
+ RelationGetRelationName(rel))));
|
|
+ }
|
|
+}
|
|
+
|
|
/* ----------------------------------------------------------------
|
|
* ExecutePlan
|
|
*
|
|
@@ -1318,6 +1412,8 @@ ExecutePlan(EState *estate,
|
|
|
|
for (;;)
|
|
{
|
|
+ Datum tts_seclabel = PointerGetDatum(NULL);
|
|
+
|
|
/* Reset the per-output-tuple exprcontext */
|
|
ResetPerTupleExprContext(estate);
|
|
|
|
@@ -1442,6 +1538,11 @@ lnext: ;
|
|
}
|
|
|
|
/*
|
|
+ * extract writable system attribute
|
|
+ */
|
|
+ fetchWritableSystemAttribute(junkfilter, slot, &tts_seclabel);
|
|
+
|
|
+ /*
|
|
* extract the 'ctid' junk attribute.
|
|
*/
|
|
if (operation == CMD_UPDATE || operation == CMD_DELETE)
|
|
@@ -1468,6 +1569,7 @@ lnext: ;
|
|
if (operation != CMD_DELETE)
|
|
slot = ExecFilterJunk(junkfilter, slot);
|
|
}
|
|
+ slot->tts_seclabel = tts_seclabel;
|
|
|
|
/*
|
|
* now that we have a tuple, do the appropriate thing with it.. either
|
|
@@ -1588,6 +1690,8 @@ ExecInsert(TupleTableSlot *slot,
|
|
resultRelInfo = estate->es_result_relation_info;
|
|
resultRelationDesc = resultRelInfo->ri_RelationDesc;
|
|
|
|
+ storeWritableSystemAttribute(resultRelationDesc, slot, tuple);
|
|
+
|
|
/* BEFORE ROW INSERT Triggers */
|
|
if (resultRelInfo->ri_TrigDesc &&
|
|
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
|
|
@@ -1624,6 +1728,13 @@ ExecInsert(TupleTableSlot *slot,
|
|
ExecConstraints(resultRelInfo, slot, estate);
|
|
|
|
/*
|
|
+ * Mandatory access controls of the tuple
|
|
+ */
|
|
+ if (!pgaceHeapTupleInsert(resultRelationDesc, tuple,
|
|
+ false, !!resultRelInfo->ri_projectReturning))
|
|
+ return;
|
|
+
|
|
+ /*
|
|
* insert the tuple
|
|
*
|
|
* Note: heap_insert returns the tid (location) of the new tuple in the
|
|
@@ -1690,6 +1801,10 @@ ExecDelete(ItemPointer tupleid,
|
|
return;
|
|
}
|
|
|
|
+ if (!pgaceHeapTupleDelete(resultRelationDesc, tupleid,
|
|
+ false, !!resultRelInfo->ri_projectReturning))
|
|
+ return;
|
|
+
|
|
/*
|
|
* delete the tuple
|
|
*
|
|
@@ -1826,6 +1941,8 @@ ExecUpdate(TupleTableSlot *slot,
|
|
resultRelInfo = estate->es_result_relation_info;
|
|
resultRelationDesc = resultRelInfo->ri_RelationDesc;
|
|
|
|
+ storeWritableSystemAttribute(resultRelationDesc, slot, tuple);
|
|
+
|
|
/* BEFORE ROW UPDATE Triggers */
|
|
if (resultRelInfo->ri_TrigDesc &&
|
|
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
|
|
@@ -1870,6 +1987,13 @@ lreplace:;
|
|
ExecConstraints(resultRelInfo, slot, estate);
|
|
|
|
/*
|
|
+ * Mandatory access controls of the tuple
|
|
+ */
|
|
+ if (!pgaceHeapTupleUpdate(resultRelationDesc, tupleid, tuple,
|
|
+ false, !!resultRelInfo->ri_projectReturning))
|
|
+ return;
|
|
+
|
|
+ /*
|
|
* replace the heap tuple
|
|
*
|
|
* Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that
|
|
@@ -2733,7 +2857,8 @@ OpenIntoRel(QueryDesc *queryDesc)
|
|
0,
|
|
into->onCommit,
|
|
reloptions,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ NIL);
|
|
|
|
FreeTupleDesc(tupdesc);
|
|
|
|
@@ -2839,6 +2964,12 @@ intorel_receive(TupleTableSlot *slot, De
|
|
|
|
tuple = ExecCopySlotTuple(slot);
|
|
|
|
+ storeWritableSystemAttribute(estate->es_into_relation_descriptor, slot, tuple);
|
|
+ if (!pgaceHeapTupleInsert(estate->es_into_relation_descriptor, tuple, false, false)) {
|
|
+ heap_freetuple(tuple);
|
|
+ return;
|
|
+ }
|
|
+
|
|
heap_insert(estate->es_into_relation_descriptor,
|
|
tuple,
|
|
estate->es_output_cid,
|
|
diff -rpNU3 base/src/backend/executor/execQual.c sepgsql/src/backend/executor/execQual.c
|
|
--- base/src/backend/executor/execQual.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/execQual.c 2009-02-02 11:58:34.000000000 +0900
|
|
@@ -47,6 +47,7 @@
|
|
#include "nodes/makefuncs.h"
|
|
#include "optimizer/planmain.h"
|
|
#include "parser/parse_expr.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -1010,6 +1011,7 @@ init_fcache(Oid foid, FuncExprState *fca
|
|
|
|
/* Set up the primary fmgr lookup information */
|
|
fmgr_info_cxt(foid, &(fcache->func), fcacheCxt);
|
|
+ pgaceCallFunction(&fcache->func);
|
|
|
|
/* Initialize additional info */
|
|
fcache->setArgsValid = false;
|
|
@@ -3679,6 +3681,8 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprS
|
|
|
|
/* Initialize additional info */
|
|
astate->elemfunc.fn_expr = (Node *) acoerce;
|
|
+
|
|
+ pgaceCallFunction(&astate->elemfunc);
|
|
}
|
|
|
|
/*
|
|
diff -rpNU3 base/src/backend/executor/execScan.c sepgsql/src/backend/executor/execScan.c
|
|
--- base/src/backend/executor/execScan.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/execScan.c 2009-02-25 22:31:25.000000000 +0900
|
|
@@ -20,6 +20,7 @@
|
|
|
|
#include "executor/executor.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/memutils.h"
|
|
|
|
|
|
@@ -53,6 +54,7 @@ ExecScan(ScanState *node,
|
|
ProjectionInfo *projInfo;
|
|
ExprDoneCond isDone;
|
|
TupleTableSlot *resultSlot;
|
|
+ Scan *scan = (Scan *)node->ps.plan;
|
|
|
|
/*
|
|
* Fetch data from node
|
|
@@ -64,7 +66,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 && !scan->pgaceTuplePerms)
|
|
return (*accessMtd) (node);
|
|
|
|
/*
|
|
@@ -127,9 +129,14 @@ ExecScan(ScanState *node,
|
|
* check for non-nil qual here to avoid a function call to ExecQual()
|
|
* when the qual is nil ... saves only a few cycles, but they add up
|
|
* ...
|
|
+ * And security check for tuple level access controls at the last.
|
|
*/
|
|
- if (!qual || ExecQual(qual, econtext, false))
|
|
+ if (pgaceExecScan(scan, node->ss_currentRelation, slot, false)
|
|
+ && (!qual || ExecQual(qual, econtext, false)))
|
|
{
|
|
+ /* special care for FK checks */
|
|
+ pgaceExecScan(scan, node->ss_currentRelation, slot, true);
|
|
+
|
|
/*
|
|
* Found a satisfactory scan tuple.
|
|
*/
|
|
@@ -197,6 +204,7 @@ tlist_matches_tupdesc(PlanState *ps, Lis
|
|
int numattrs = tupdesc->natts;
|
|
int attrno;
|
|
bool hasoid;
|
|
+ bool hasseclabel;
|
|
ListCell *tlist_item = list_head(tlist);
|
|
|
|
/* Check the tlist attributes */
|
|
@@ -240,12 +248,16 @@ tlist_matches_tupdesc(PlanState *ps, Lis
|
|
return false; /* tlist too long */
|
|
|
|
/*
|
|
- * If the plan context requires a particular hasoid setting, then that has
|
|
- * to match, too.
|
|
+ * If the plan context requires a particular hasoid/hassecurity setting,
|
|
+ * then they have to match, too.
|
|
*/
|
|
if (ExecContextForcesOids(ps, &hasoid) &&
|
|
hasoid != tupdesc->tdhasoid)
|
|
return false;
|
|
|
|
+ if (ExecContextForcesSecLabel(ps, &hasseclabel) &&
|
|
+ hasseclabel != tupdesc->tdhasseclabel)
|
|
+ return false;
|
|
+
|
|
return true;
|
|
}
|
|
diff -rpNU3 base/src/backend/executor/execTuples.c sepgsql/src/backend/executor/execTuples.c
|
|
--- base/src/backend/executor/execTuples.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/execTuples.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -100,7 +100,7 @@
|
|
|
|
|
|
static TupleDesc ExecTypeFromTLInternal(List *targetList,
|
|
- bool hasoid, bool skipjunk);
|
|
+ bool hasoid, bool hassecurity, bool skipjunk);
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
@@ -941,9 +941,9 @@ ExecInitNullTupleSlot(EState *estate, Tu
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
TupleDesc
|
|
-ExecTypeFromTL(List *targetList, bool hasoid)
|
|
+ExecTypeFromTL(List *targetList, bool hasoid, bool hasseclabel)
|
|
{
|
|
- return ExecTypeFromTLInternal(targetList, hasoid, false);
|
|
+ return ExecTypeFromTLInternal(targetList, hasoid, hasseclabel, false);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
@@ -953,13 +953,14 @@ ExecTypeFromTL(List *targetList, bool ha
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
TupleDesc
|
|
-ExecCleanTypeFromTL(List *targetList, bool hasoid)
|
|
+ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hasseclabel)
|
|
{
|
|
- return ExecTypeFromTLInternal(targetList, hasoid, true);
|
|
+ return ExecTypeFromTLInternal(targetList, hasoid, hasseclabel, true);
|
|
}
|
|
|
|
static TupleDesc
|
|
-ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk)
|
|
+ExecTypeFromTLInternal(List *targetList,
|
|
+ bool hasoid, bool hasseclabel, bool skipjunk)
|
|
{
|
|
TupleDesc typeInfo;
|
|
ListCell *l;
|
|
@@ -971,6 +972,7 @@ ExecTypeFromTLInternal(List *targetList,
|
|
else
|
|
len = ExecTargetListLength(targetList);
|
|
typeInfo = CreateTemplateTupleDesc(len, hasoid);
|
|
+ typeInfo->tdhasseclabel = hasseclabel;
|
|
|
|
foreach(l, targetList)
|
|
{
|
|
diff -rpNU3 base/src/backend/executor/execUtils.c sepgsql/src/backend/executor/execUtils.c
|
|
--- base/src/backend/executor/execUtils.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/execUtils.c 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -506,6 +506,7 @@ void
|
|
ExecAssignResultTypeFromTL(PlanState *planstate)
|
|
{
|
|
bool hasoid;
|
|
+ bool hassecurity;
|
|
TupleDesc tupDesc;
|
|
|
|
if (ExecContextForcesOids(planstate, &hasoid))
|
|
@@ -518,12 +519,15 @@ ExecAssignResultTypeFromTL(PlanState *pl
|
|
hasoid = false;
|
|
}
|
|
|
|
+ if (!ExecContextForcesSecLabel(planstate, &hassecurity))
|
|
+ hassecurity = 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, hassecurity);
|
|
ExecAssignResultType(planstate, tupDesc);
|
|
}
|
|
|
|
diff -rpNU3 base/src/backend/executor/functions.c sepgsql/src/backend/executor/functions.c
|
|
--- base/src/backend/executor/functions.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/functions.c 2008-11-21 23:11:55.000000000 +0900
|
|
@@ -995,7 +995,7 @@ check_sql_fn_retval(Oid func_id, Oid ret
|
|
* 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 -rpNU3 base/src/backend/executor/nodeAgg.c sepgsql/src/backend/executor/nodeAgg.c
|
|
--- base/src/backend/executor/nodeAgg.c 2008-11-05 09:57:00.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/nodeAgg.c 2009-01-16 17:07:29.000000000 +0900
|
|
@@ -80,6 +80,7 @@
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_expr.h"
|
|
#include "parser/parse_oper.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -1398,6 +1399,8 @@ ExecInitAgg(Agg *node, EState *estate, i
|
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
|
get_func_name(aggref->aggfnoid));
|
|
|
|
+ pgaceCallAggFunction(aggTuple);
|
|
+
|
|
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
|
|
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
|
|
|
|
@@ -1461,11 +1464,13 @@ ExecInitAgg(Agg *node, EState *estate, i
|
|
|
|
fmgr_info(transfn_oid, &peraggstate->transfn);
|
|
peraggstate->transfn.fn_expr = (Node *) transfnexpr;
|
|
+ pgaceCallFunction(&peraggstate->transfn);
|
|
|
|
if (OidIsValid(finalfn_oid))
|
|
{
|
|
fmgr_info(finalfn_oid, &peraggstate->finalfn);
|
|
peraggstate->finalfn.fn_expr = (Node *) finalfnexpr;
|
|
+ pgaceCallFunction(&peraggstate->finalfn);
|
|
}
|
|
|
|
get_typlenbyval(aggref->aggtype,
|
|
diff -rpNU3 base/src/backend/executor/nodeMergejoin.c sepgsql/src/backend/executor/nodeMergejoin.c
|
|
--- base/src/backend/executor/nodeMergejoin.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/nodeMergejoin.c 2009-01-16 17:07:29.000000000 +0900
|
|
@@ -98,6 +98,7 @@
|
|
#include "executor/execdefs.h"
|
|
#include "executor/nodeMergejoin.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/lsyscache.h"
|
|
#include "utils/memutils.h"
|
|
@@ -221,6 +222,7 @@ MJExamineQuals(List *mergeclauses,
|
|
|
|
/* Set up the fmgr lookup information */
|
|
fmgr_info(cmpproc, &(clause->cmpfinfo));
|
|
+ pgaceCallFunction(&clause->cmpfinfo);
|
|
|
|
/* Fill the additional comparison-strategy flags */
|
|
if (opstrategy == BTLessStrategyNumber)
|
|
diff -rpNU3 base/src/backend/executor/nodeSubplan.c sepgsql/src/backend/executor/nodeSubplan.c
|
|
--- base/src/backend/executor/nodeSubplan.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/nodeSubplan.c 2008-11-21 23:11:55.000000000 +0900
|
|
@@ -855,7 +855,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanSt
|
|
* (hack alert!). The righthand expressions will be evaluated in our
|
|
* own innerecontext.
|
|
*/
|
|
- tupDesc = ExecTypeFromTL(leftptlist, false);
|
|
+ tupDesc = ExecTypeFromTL(leftptlist, false, false);
|
|
slot = ExecAllocTableSlot(tupTable);
|
|
ExecSetSlotDescriptor(slot, tupDesc);
|
|
sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
|
|
@@ -863,7 +863,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanSt
|
|
slot,
|
|
NULL);
|
|
|
|
- tupDesc = ExecTypeFromTL(rightptlist, false);
|
|
+ tupDesc = ExecTypeFromTL(rightptlist, false, false);
|
|
slot = ExecAllocTableSlot(tupTable);
|
|
ExecSetSlotDescriptor(slot, tupDesc);
|
|
sstate->projRight = ExecBuildProjectionInfo(righttlist,
|
|
diff -rpNU3 base/src/backend/executor/spi.c sepgsql/src/backend/executor/spi.c
|
|
--- base/src/backend/executor/spi.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/spi.c 2009-02-02 11:58:34.000000000 +0900
|
|
@@ -631,6 +631,8 @@ SPI_modifytuple(Relation rel, HeapTuple
|
|
mtuple->t_tableOid = tuple->t_tableOid;
|
|
if (rel->rd_att->tdhasoid)
|
|
HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(mtuple, HeapTupleGetSecLabel(tuple));
|
|
}
|
|
else
|
|
{
|
|
diff -rpNU3 base/src/backend/libpq/be-fsstubs.c sepgsql/src/backend/libpq/be-fsstubs.c
|
|
--- base/src/backend/libpq/be-fsstubs.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/libpq/be-fsstubs.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -45,6 +45,7 @@
|
|
#include "libpq/be-fsstubs.h"
|
|
#include "libpq/libpq-fs.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/large_object.h"
|
|
#include "utils/memutils.h"
|
|
@@ -154,6 +155,8 @@ lo_read(int fd, char *buf, int len)
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
errmsg("invalid large-object descriptor: %d", fd)));
|
|
|
|
+ pgaceLargeObjectRead(cookies[fd], len);
|
|
+
|
|
status = inv_read(cookies[fd], buf, len);
|
|
|
|
return status;
|
|
@@ -175,6 +178,8 @@ lo_write(int fd, const char *buf, int le
|
|
errmsg("large object descriptor %d was not opened for writing",
|
|
fd)));
|
|
|
|
+ pgaceLargeObjectWrite(cookies[fd], len);
|
|
+
|
|
status = inv_write(cookies[fd], buf, len);
|
|
|
|
return status;
|
|
@@ -359,6 +364,11 @@ lo_import(PG_FUNCTION_ARGS)
|
|
lobjOid = inv_create(InvalidOid);
|
|
|
|
/*
|
|
+ * check permission to import a file into this object
|
|
+ */
|
|
+ pgaceLargeObjectImport(lobjOid, FileRawDescriptor(fd), fnamebuf);
|
|
+
|
|
+ /*
|
|
* read in from the filesystem and write to the inversion object
|
|
*/
|
|
lobj = inv_open(lobjOid, INV_WRITE, fscxt);
|
|
@@ -433,6 +443,10 @@ lo_export(PG_FUNCTION_ARGS)
|
|
(errcode_for_file_access(),
|
|
errmsg("could not create server file \"%s\": %m",
|
|
fnamebuf)));
|
|
+ /*
|
|
+ * check permission to export this object into a file
|
|
+ */
|
|
+ pgaceLargeObjectExport(lobjId, FileRawDescriptor(fd), fnamebuf);
|
|
|
|
/*
|
|
* read in from the inversion file and write to the filesystem
|
|
@@ -468,6 +482,8 @@ lo_truncate(PG_FUNCTION_ARGS)
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
errmsg("invalid large-object descriptor: %d", fd)));
|
|
|
|
+ pgaceLargeObjectTruncate(cookies[fd], len);
|
|
+
|
|
inv_truncate(cookies[fd], len);
|
|
|
|
PG_RETURN_INT32(0);
|
|
diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfuncs.c
|
|
--- base/src/backend/nodes/copyfuncs.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/nodes/copyfuncs.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -24,6 +24,7 @@
|
|
|
|
#include "nodes/plannodes.h"
|
|
#include "nodes/relation.h"
|
|
+#include "nodes/security.h"
|
|
#include "utils/datum.h"
|
|
|
|
|
|
@@ -85,6 +86,7 @@ _copyPlannedStmt(PlannedStmt *from)
|
|
COPY_NODE_FIELD(rowMarks);
|
|
COPY_NODE_FIELD(relationOids);
|
|
COPY_SCALAR_FIELD(nParamExec);
|
|
+ COPY_NODE_FIELD(pgaceItem);
|
|
|
|
return newnode;
|
|
}
|
|
@@ -226,6 +228,7 @@ CopyScanFields(Scan *from, Scan *newnode
|
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
|
|
|
COPY_SCALAR_FIELD(scanrelid);
|
|
+ COPY_SCALAR_FIELD(pgaceTuplePerms);
|
|
}
|
|
|
|
/*
|
|
@@ -1524,6 +1527,7 @@ _copyRangeTblEntry(RangeTblEntry *from)
|
|
COPY_SCALAR_FIELD(inFromCl);
|
|
COPY_SCALAR_FIELD(requiredPerms);
|
|
COPY_SCALAR_FIELD(checkAsUser);
|
|
+ COPY_SCALAR_FIELD(pgaceTuplePerms);
|
|
|
|
return newnode;
|
|
}
|
|
@@ -1790,6 +1794,7 @@ _copyColumnDef(ColumnDef *from)
|
|
COPY_NODE_FIELD(raw_default);
|
|
COPY_STRING_FIELD(cooked_default);
|
|
COPY_NODE_FIELD(constraints);
|
|
+ COPY_NODE_FIELD(pgaceItem);
|
|
|
|
return newnode;
|
|
}
|
|
@@ -1870,6 +1875,7 @@ _copyQuery(Query *from)
|
|
COPY_NODE_FIELD(limitCount);
|
|
COPY_NODE_FIELD(rowMarks);
|
|
COPY_NODE_FIELD(setOperations);
|
|
+ COPY_NODE_FIELD(pgaceItem);
|
|
|
|
return newnode;
|
|
}
|
|
@@ -2106,6 +2112,7 @@ _copyCreateStmt(CreateStmt *from)
|
|
COPY_NODE_FIELD(options);
|
|
COPY_SCALAR_FIELD(oncommit);
|
|
COPY_STRING_FIELD(tablespacename);
|
|
+ COPY_NODE_FIELD(pgaceItem);
|
|
|
|
return newnode;
|
|
}
|
|
@@ -2999,6 +3006,25 @@ _copyValue(Value *from)
|
|
return newnode;
|
|
}
|
|
|
|
+/* ****************************************************************
|
|
+ * nodes/security.h copy functions
|
|
+ * ****************************************************************
|
|
+ */
|
|
+static SelinuxEvalItem *
|
|
+_copySelinuxEvalItem(SelinuxEvalItem *from)
|
|
+{
|
|
+ SelinuxEvalItem *newnode = makeNode(SelinuxEvalItem);
|
|
+
|
|
+ COPY_SCALAR_FIELD(relid);
|
|
+ COPY_SCALAR_FIELD(inh);
|
|
+
|
|
+ COPY_SCALAR_FIELD(relperms);
|
|
+ COPY_SCALAR_FIELD(nattrs);
|
|
+ COPY_POINTER_FIELD(attperms, from->nattrs * sizeof(uint32));
|
|
+
|
|
+ return newnode;
|
|
+}
|
|
+
|
|
/*
|
|
* copyObject
|
|
*
|
|
@@ -3601,6 +3627,9 @@ copyObject(void *from)
|
|
case T_XmlSerialize:
|
|
retval = _copyXmlSerialize(from);
|
|
break;
|
|
+ case T_SelinuxEvalItem:
|
|
+ retval = _copySelinuxEvalItem(from);
|
|
+ break;
|
|
|
|
default:
|
|
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
|
|
diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalfuncs.c
|
|
--- base/src/backend/nodes/equalfuncs.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/nodes/equalfuncs.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -26,6 +26,7 @@
|
|
#include "postgres.h"
|
|
|
|
#include "nodes/relation.h"
|
|
+#include "nodes/security.h"
|
|
#include "utils/datum.h"
|
|
|
|
|
|
@@ -769,6 +770,7 @@ _equalQuery(Query *a, Query *b)
|
|
COMPARE_NODE_FIELD(limitCount);
|
|
COMPARE_NODE_FIELD(rowMarks);
|
|
COMPARE_NODE_FIELD(setOperations);
|
|
+ COMPARE_NODE_FIELD(pgaceItem);
|
|
|
|
return true;
|
|
}
|
|
@@ -971,6 +973,7 @@ _equalCreateStmt(CreateStmt *a, CreateSt
|
|
COMPARE_NODE_FIELD(options);
|
|
COMPARE_SCALAR_FIELD(oncommit);
|
|
COMPARE_STRING_FIELD(tablespacename);
|
|
+ COMPARE_NODE_FIELD(pgaceItem);
|
|
|
|
return true;
|
|
}
|
|
@@ -1819,6 +1822,7 @@ _equalColumnDef(ColumnDef *a, ColumnDef
|
|
COMPARE_NODE_FIELD(raw_default);
|
|
COMPARE_STRING_FIELD(cooked_default);
|
|
COMPARE_NODE_FIELD(constraints);
|
|
+ COMPARE_NODE_FIELD(pgaceItem);
|
|
|
|
return true;
|
|
}
|
|
@@ -1926,6 +1930,21 @@ _equalXmlSerialize(XmlSerialize *a, XmlS
|
|
}
|
|
|
|
/*
|
|
+ * Stuff from nodes/security.h
|
|
+ */
|
|
+static bool
|
|
+_equalSelinuxEvalItem(SelinuxEvalItem *a, SelinuxEvalItem *b)
|
|
+{
|
|
+ COMPARE_SCALAR_FIELD(relid);
|
|
+ COMPARE_SCALAR_FIELD(inh);
|
|
+ COMPARE_SCALAR_FIELD(relperms);
|
|
+ COMPARE_SCALAR_FIELD(nattrs);
|
|
+ COMPARE_POINTER_FIELD(attperms, a->nattrs * sizeof(uint32));
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
* Stuff from pg_list.h
|
|
*/
|
|
|
|
@@ -2528,6 +2547,9 @@ equal(void *a, void *b)
|
|
case T_XmlSerialize:
|
|
retval = _equalXmlSerialize(a, b);
|
|
break;
|
|
+ case T_SelinuxEvalItem:
|
|
+ retval = _equalSelinuxEvalItem(a, b);
|
|
+ break;
|
|
|
|
default:
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs.c
|
|
--- base/src/backend/nodes/outfuncs.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/nodes/outfuncs.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -26,6 +26,7 @@
|
|
#include "lib/stringinfo.h"
|
|
#include "nodes/plannodes.h"
|
|
#include "nodes/relation.h"
|
|
+#include "nodes/security.h"
|
|
#include "utils/datum.h"
|
|
|
|
|
|
@@ -252,6 +253,7 @@ _outPlannedStmt(StringInfo str, PlannedS
|
|
WRITE_NODE_FIELD(rowMarks);
|
|
WRITE_NODE_FIELD(relationOids);
|
|
WRITE_INT_FIELD(nParamExec);
|
|
+ WRITE_NODE_FIELD(pgaceItem);
|
|
}
|
|
|
|
/*
|
|
@@ -282,6 +284,7 @@ _outScanInfo(StringInfo str, Scan *node)
|
|
_outPlanInfo(str, (Plan *) node);
|
|
|
|
WRITE_UINT_FIELD(scanrelid);
|
|
+ WRITE_UINT_FIELD(pgaceTuplePerms);
|
|
}
|
|
|
|
/*
|
|
@@ -1376,6 +1379,7 @@ _outRelOptInfo(StringInfo str, RelOptInf
|
|
WRITE_BOOL_FIELD(has_eclass_joins);
|
|
WRITE_BITMAPSET_FIELD(index_outer_relids);
|
|
WRITE_NODE_FIELD(index_inner_paths);
|
|
+ WRITE_UINT_FIELD(pgaceTuplePerms);
|
|
}
|
|
|
|
static void
|
|
@@ -1546,6 +1550,7 @@ _outCreateStmt(StringInfo str, CreateStm
|
|
WRITE_NODE_FIELD(options);
|
|
WRITE_ENUM_FIELD(oncommit, OnCommitAction);
|
|
WRITE_STRING_FIELD(tablespacename);
|
|
+ WRITE_NODE_FIELD(pgaceItem);
|
|
}
|
|
|
|
static void
|
|
@@ -1661,6 +1666,7 @@ _outColumnDef(StringInfo str, ColumnDef
|
|
WRITE_NODE_FIELD(raw_default);
|
|
WRITE_STRING_FIELD(cooked_default);
|
|
WRITE_NODE_FIELD(constraints);
|
|
+ WRITE_NODE_FIELD(pgaceItem);
|
|
}
|
|
|
|
static void
|
|
@@ -1750,6 +1756,7 @@ _outQuery(StringInfo str, Query *node)
|
|
WRITE_NODE_FIELD(limitCount);
|
|
WRITE_NODE_FIELD(rowMarks);
|
|
WRITE_NODE_FIELD(setOperations);
|
|
+ WRITE_NODE_FIELD(pgaceItem);
|
|
}
|
|
|
|
static void
|
|
@@ -1835,6 +1842,7 @@ _outRangeTblEntry(StringInfo str, RangeT
|
|
WRITE_BOOL_FIELD(inFromCl);
|
|
WRITE_UINT_FIELD(requiredPerms);
|
|
WRITE_OID_FIELD(checkAsUser);
|
|
+ WRITE_UINT_FIELD(pgaceTuplePerms);
|
|
}
|
|
|
|
static void
|
|
@@ -2047,6 +2055,29 @@ _outFkConstraint(StringInfo str, FkConst
|
|
WRITE_BOOL_FIELD(skip_validation);
|
|
}
|
|
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Stuff from nodes/security.h
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+static void
|
|
+_outSelinuxEvalItem(StringInfo str, SelinuxEvalItem *node)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ WRITE_NODE_TYPE("SELINUXEVALITEM");
|
|
+
|
|
+ WRITE_OID_FIELD(relid);
|
|
+ WRITE_BOOL_FIELD(inh);
|
|
+
|
|
+ WRITE_UINT_FIELD(relperms);
|
|
+ WRITE_UINT_FIELD(nattrs);
|
|
+
|
|
+ appendStringInfo(str, " :attperms [");
|
|
+ for (i = 0; i < node->nattrs; i++)
|
|
+ appendStringInfo(str, " %u", node->attperms[i]);
|
|
+ appendStringInfo(str, " ]");
|
|
+}
|
|
|
|
/*
|
|
* _outNode -
|
|
@@ -2440,6 +2471,9 @@ _outNode(StringInfo str, void *obj)
|
|
case T_XmlSerialize:
|
|
_outXmlSerialize(str, obj);
|
|
break;
|
|
+ case T_SelinuxEvalItem:
|
|
+ _outSelinuxEvalItem(str, obj);
|
|
+ break;
|
|
|
|
default:
|
|
|
|
diff -rpNU3 base/src/backend/nodes/readfuncs.c sepgsql/src/backend/nodes/readfuncs.c
|
|
--- base/src/backend/nodes/readfuncs.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/nodes/readfuncs.c 2009-01-21 17:02:57.000000000 +0900
|
|
@@ -24,6 +24,7 @@
|
|
|
|
#include "nodes/parsenodes.h"
|
|
#include "nodes/readfuncs.h"
|
|
+#include "nodes/security.h"
|
|
|
|
|
|
/*
|
|
@@ -154,6 +155,7 @@ _readQuery(void)
|
|
READ_NODE_FIELD(limitCount);
|
|
READ_NODE_FIELD(rowMarks);
|
|
READ_NODE_FIELD(setOperations);
|
|
+ READ_NODE_FIELD(pgaceItem);
|
|
|
|
READ_DONE();
|
|
}
|
|
@@ -1003,10 +1005,49 @@ _readRangeTblEntry(void)
|
|
READ_BOOL_FIELD(inFromCl);
|
|
READ_UINT_FIELD(requiredPerms);
|
|
READ_OID_FIELD(checkAsUser);
|
|
+ READ_UINT_FIELD(pgaceTuplePerms);
|
|
|
|
READ_DONE();
|
|
}
|
|
|
|
+/*
|
|
+ * Stuff from nodes/security.h
|
|
+ */
|
|
+static SelinuxEvalItem *
|
|
+_readSelinuxEvalItem(void)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ READ_LOCALS(SelinuxEvalItem);
|
|
+
|
|
+ READ_OID_FIELD(relid);
|
|
+ READ_BOOL_FIELD(inh);
|
|
+
|
|
+ READ_UINT_FIELD(relperms);
|
|
+ READ_UINT_FIELD(nattrs);
|
|
+
|
|
+ /*
|
|
+ * TODO: This part should be moved to readArray() ?
|
|
+ */
|
|
+ local_node->attperms = palloc0(local_node->nattrs * sizeof(uint32));
|
|
+
|
|
+ token = pg_strtok(&length); /* skip :attperms */
|
|
+ token = pg_strtok(&length); /* read '[' */
|
|
+ if (token == NULL || strcmp(token, "[") != 0)
|
|
+ elog(ERROR, "expected \"[\" to start array, but got \"%s\"",
|
|
+ token ? (const char *) token : "[NULL]");
|
|
+ for (i = 0; i < local_node->nattrs; i++)
|
|
+ {
|
|
+ token = pg_strtok(&length);
|
|
+ local_node->attperms[i] = atoui(token);
|
|
+ }
|
|
+ token = pg_strtok(&length); /* read ']' */
|
|
+ if (token == NULL || strcmp(token, "[") != 0)
|
|
+ elog(ERROR, "expected \"[\" to end array, but got \"%s\"",
|
|
+ token ? (const char *) token : "[NULL]");
|
|
+
|
|
+ READ_DONE();
|
|
+}
|
|
|
|
/*
|
|
* parseNodeString
|
|
@@ -1124,6 +1165,8 @@ parseNodeString(void)
|
|
return_value = _readNotifyStmt();
|
|
else if (MATCH("DECLARECURSOR", 13))
|
|
return_value = _readDeclareCursorStmt();
|
|
+ else if (MATCH("SELINUXEVALITEM", 15))
|
|
+ return_value = _readSelinuxEvalItem();
|
|
else
|
|
{
|
|
elog(ERROR, "badly formatted node string \"%.32s\"...", token);
|
|
diff -rpNU3 base/src/backend/optimizer/plan/createplan.c sepgsql/src/backend/optimizer/plan/createplan.c
|
|
--- base/src/backend/optimizer/plan/createplan.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/optimizer/plan/createplan.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -287,6 +287,12 @@ create_scan_plan(PlannerInfo *root, Path
|
|
}
|
|
|
|
/*
|
|
+ * The guest of PGACE can refer plan->pgaceTuplePerms to apply
|
|
+ * tuple level access control in the pgaceExecScan() hook.
|
|
+ */
|
|
+ ((Scan *)plan)->pgaceTuplePerms = rel->pgaceTuplePerms;
|
|
+
|
|
+ /*
|
|
* If there are any pseudoconstant clauses attached to this node, insert a
|
|
* gating Result node that evaluates the pseudoconstants as one-time
|
|
* quals.
|
|
diff -rpNU3 base/src/backend/optimizer/plan/planner.c sepgsql/src/backend/optimizer/plan/planner.c
|
|
--- base/src/backend/optimizer/plan/planner.c 2008-06-12 22:34:19.000000000 +0900
|
|
+++ sepgsql/src/backend/optimizer/plan/planner.c 2008-11-24 20:26:40.000000000 +0900
|
|
@@ -197,6 +197,7 @@ standard_planner(Query *parse, int curso
|
|
result->rowMarks = parse->rowMarks;
|
|
result->relationOids = glob->relationOids;
|
|
result->nParamExec = list_length(glob->paramlist);
|
|
+ result->pgaceItem = parse->pgaceItem;
|
|
|
|
return result;
|
|
}
|
|
diff -rpNU3 base/src/backend/optimizer/util/clauses.c sepgsql/src/backend/optimizer/util/clauses.c
|
|
--- base/src/backend/optimizer/util/clauses.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql/src/backend/optimizer/util/clauses.c 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -39,6 +39,7 @@
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_expr.h"
|
|
#include "tcop/tcopprot.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/datum.h"
|
|
@@ -3057,6 +3058,9 @@ inline_function(Oid funcid, Oid result_t
|
|
if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK)
|
|
return NULL;
|
|
|
|
+ if (!pgaceAllowFunctionInlined(funcid, func_tuple))
|
|
+ return NULL;
|
|
+
|
|
/*
|
|
* Setup error traceback support for ereport(). This is so that we can
|
|
* finger the function that bad information came from.
|
|
diff -rpNU3 base/src/backend/optimizer/util/relnode.c sepgsql/src/backend/optimizer/util/relnode.c
|
|
--- base/src/backend/optimizer/util/relnode.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/optimizer/util/relnode.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -90,6 +90,7 @@ build_simple_rel(PlannerInfo *root, int
|
|
rel->has_eclass_joins = false;
|
|
rel->index_outer_relids = NULL;
|
|
rel->index_inner_paths = NIL;
|
|
+ rel->pgaceTuplePerms = rte->pgaceTuplePerms;
|
|
|
|
/* Check type of rtable entry */
|
|
switch (rte->rtekind)
|
|
diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze.c
|
|
--- base/src/backend/parser/analyze.c 2009-03-15 17:47:25.000000000 +0900
|
|
+++ sepgsql/src/backend/parser/analyze.c 2009-03-15 17:53:20.000000000 +0900
|
|
@@ -24,6 +24,7 @@
|
|
|
|
#include "postgres.h"
|
|
|
|
+#include "catalog/heap.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "optimizer/clauses.h"
|
|
@@ -36,6 +37,7 @@
|
|
#include "parser/parse_relation.h"
|
|
#include "parser/parse_target.h"
|
|
#include "parser/parsetree.h"
|
|
+#include "security/pgace.h"
|
|
|
|
|
|
typedef struct
|
|
@@ -616,14 +618,15 @@ transformInsertStmt(ParseState *pstate,
|
|
Expr *expr = (Expr *) lfirst(lc);
|
|
ResTarget *col;
|
|
TargetEntry *tle;
|
|
+ AttrNumber anum = (AttrNumber) lfirst_int(attnos);
|
|
|
|
col = (ResTarget *) lfirst(icols);
|
|
Assert(IsA(col, ResTarget));
|
|
|
|
tle = makeTargetEntry(expr,
|
|
- (AttrNumber) lfirst_int(attnos),
|
|
+ anum,
|
|
col->name,
|
|
- false);
|
|
+ anum < 0 ? true : false);
|
|
qry->targetList = lappend(qry->targetList, tle);
|
|
|
|
icols = lnext(icols);
|
|
@@ -721,6 +724,46 @@ transformInsertRow(ParseState *pstate, L
|
|
return result;
|
|
}
|
|
|
|
+static void
|
|
+transformSelectIntoSystemColumn(ParseState *pstate, Query *qry)
|
|
+{
|
|
+ ListCell *l;
|
|
+ uint32 system_attrs = 0;
|
|
+ bool relhasoids
|
|
+ = interpretOidsOption(qry->intoClause->options);
|
|
+
|
|
+ foreach (l, qry->targetList) {
|
|
+ Form_pg_attribute attr;
|
|
+ TargetEntry *tle = lfirst(l);
|
|
+
|
|
+ if (tle->resjunk)
|
|
+ continue;
|
|
+
|
|
+ attr = SystemAttributeByName(tle->resname, relhasoids);
|
|
+ if (attr && SystemAttributeIsWritable(attr->attnum))
|
|
+ {
|
|
+ uint32 mask = (1<<(-attr->attnum));
|
|
+
|
|
+ /* duplication checks */
|
|
+ if (system_attrs & mask)
|
|
+ continue;
|
|
+ system_attrs |= mask;
|
|
+
|
|
+ if (exprType((Node *) tle->expr) != attr->atttypid)
|
|
+ {
|
|
+ tle->expr =
|
|
+ (Expr *) coerce_to_target_type(pstate,
|
|
+ (Node *) tle->expr,
|
|
+ exprType((Node *) tle->expr),
|
|
+ attr->atttypid,
|
|
+ attr->atttypmod,
|
|
+ COERCION_IMPLICIT,
|
|
+ COERCE_IMPLICIT_CAST);
|
|
+ }
|
|
+ tle->resjunk = true;
|
|
+ }
|
|
+ }
|
|
+}
|
|
|
|
/*
|
|
* transformSelectStmt -
|
|
@@ -787,6 +830,7 @@ transformSelectStmt(ParseState *pstate,
|
|
if (stmt->intoClause)
|
|
{
|
|
qry->intoClause = stmt->intoClause;
|
|
+ transformSelectIntoSystemColumn(pstate, qry);
|
|
if (stmt->intoClause->colNames)
|
|
applyColumnNames(qry->targetList, stmt->intoClause->colNames);
|
|
}
|
|
diff -rpNU3 base/src/backend/parser/gram.y sepgsql/src/backend/parser/gram.y
|
|
--- base/src/backend/parser/gram.y 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql/src/backend/parser/gram.y 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -56,6 +56,7 @@
|
|
#include "commands/defrem.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/gramparse.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/lmgr.h"
|
|
#include "utils/date.h"
|
|
#include "utils/datetime.h"
|
|
@@ -351,6 +352,8 @@ static Node *makeXmlExpr(XmlExprOp op, c
|
|
%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
|
|
%type <list> opt_check_option
|
|
|
|
+%type <defelt> OptSecurityItem SecurityItem
|
|
+
|
|
%type <target> xml_attribute_el
|
|
%type <list> xml_attribute_list xml_attributes
|
|
%type <node> xml_root_version opt_xml_root_standalone
|
|
@@ -1637,6 +1640,24 @@ alter_table_cmd:
|
|
n->def = (Node *) $3;
|
|
$$ = (Node *)n;
|
|
}
|
|
+ /* ALTER TABLE <relation> CONTEXT = '...' */
|
|
+ | SecurityItem
|
|
+ {
|
|
+ AlterTableCmd *n = makeNode(AlterTableCmd);
|
|
+ n->subtype = AT_SetSecurityLabel;
|
|
+ n->name = NULL;
|
|
+ n->def = (Node *) $1;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
+ /* ALTER TABLE <relation> ALTER [COLUMN] <colname> CONTEXT = '...' */
|
|
+ | ALTER opt_column ColId SecurityItem
|
|
+ {
|
|
+ AlterTableCmd *n = makeNode(AlterTableCmd);
|
|
+ n->subtype = AT_SetSecurityLabel;
|
|
+ n->name = $3;
|
|
+ n->def = (Node *) $4;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
| alter_rel_cmd
|
|
{
|
|
$$ = $1;
|
|
@@ -1883,7 +1904,7 @@ opt_using:
|
|
*****************************************************************************/
|
|
|
|
CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
|
|
- OptInherit OptWith OnCommitOption OptTableSpace
|
|
+ OptInherit OptWith OnCommitOption OptTableSpace OptSecurityItem
|
|
{
|
|
CreateStmt *n = makeNode(CreateStmt);
|
|
$4->istemp = $2;
|
|
@@ -1894,10 +1915,11 @@ CreateStmt: CREATE OptTemp TABLE qualifi
|
|
n->options = $9;
|
|
n->oncommit = $10;
|
|
n->tablespacename = $11;
|
|
+ n->pgaceItem = (Node *) $12;
|
|
$$ = (Node *)n;
|
|
}
|
|
| CREATE OptTemp TABLE qualified_name OF qualified_name
|
|
- '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace
|
|
+ '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace OptSecurityItem
|
|
{
|
|
/* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
|
|
* by our inheritance capabilities. Let's try it...
|
|
@@ -1911,6 +1933,7 @@ CreateStmt: CREATE OptTemp TABLE qualifi
|
|
n->options = $10;
|
|
n->oncommit = $11;
|
|
n->tablespacename = $12;
|
|
+ n->pgaceItem = (Node *) $13;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
@@ -1953,13 +1976,14 @@ TableElement:
|
|
| TableConstraint { $$ = $1; }
|
|
;
|
|
|
|
-columnDef: ColId Typename ColQualList
|
|
+columnDef: ColId Typename ColQualList OptSecurityItem
|
|
{
|
|
ColumnDef *n = makeNode(ColumnDef);
|
|
n->colname = $1;
|
|
n->typename = $2;
|
|
n->constraints = $3;
|
|
n->is_local = true;
|
|
+ n->pgaceItem = (Node *) $4;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
@@ -4278,6 +4302,10 @@ common_func_opt_item:
|
|
/* we abuse the normal content of a DefElem here */
|
|
$$ = makeDefElem("set", (Node *)$1);
|
|
}
|
|
+ | SecurityItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
;
|
|
|
|
createfunc_opt_item:
|
|
@@ -5361,6 +5389,10 @@ createdb_opt_item:
|
|
{
|
|
$$ = makeDefElem("owner", NULL);
|
|
}
|
|
+ | SecurityItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
;
|
|
|
|
/*
|
|
@@ -5409,6 +5441,10 @@ alterdb_opt_item:
|
|
{
|
|
$$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
|
|
}
|
|
+ | SecurityItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
;
|
|
|
|
|
|
@@ -8736,6 +8772,28 @@ target_el: a_expr AS ColLabel
|
|
}
|
|
;
|
|
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * PGACE Security Items
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+
|
|
+OptSecurityItem:
|
|
+ SecurityItem { $$ = $1; }
|
|
+ | /* EMPTY */ { $$ = NULL; }
|
|
+ ;
|
|
+
|
|
+SecurityItem:
|
|
+ IDENT '=' Sconst
|
|
+ {
|
|
+ DefElem *node = makeDefElem($1, (Node *) makeString($3));
|
|
+
|
|
+ if (!pgaceIsGramSecurityItem(node))
|
|
+ yyerror("syntax error");
|
|
+
|
|
+ $$ = node;
|
|
+ }
|
|
+ ;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
diff -rpNU3 base/src/backend/parser/parse_target.c sepgsql/src/backend/parser/parse_target.c
|
|
--- base/src/backend/parser/parse_target.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/parser/parse_target.c 2008-12-05 17:58:33.000000000 +0900
|
|
@@ -14,6 +14,7 @@
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
+#include "catalog/heap.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "commands/dbcommands.h"
|
|
#include "funcapi.h"
|
|
@@ -26,6 +27,7 @@
|
|
#include "parser/parse_relation.h"
|
|
#include "parser/parse_target.h"
|
|
#include "parser/parse_type.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
#include "utils/typcache.h"
|
|
@@ -333,16 +335,33 @@ transformAssignedExpr(ParseState *pstate
|
|
Oid attrtype; /* type of target column */
|
|
int32 attrtypmod;
|
|
Relation rd = pstate->p_target_relation;
|
|
+ bool relhasoids = RelationGetForm(rd)->relhasoids;
|
|
|
|
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
|
|
+ = SystemAttributeDefinition(attrno, relhasoids);
|
|
+ if (attr && SystemAttributeIsWritable(attrno))
|
|
+ {
|
|
+ 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; /* compiler kindness */
|
|
+ }
|
|
+ }
|
|
|
|
/*
|
|
* If the expression is a DEFAULT placeholder, insert the attribute's
|
|
@@ -483,6 +502,9 @@ updateTargetListEntry(ParseState *pstate
|
|
*/
|
|
tle->resno = (AttrNumber) attrno;
|
|
tle->resname = colname;
|
|
+
|
|
+ if (SystemAttributeIsWritable(attrno))
|
|
+ tle->resjunk = true;
|
|
}
|
|
|
|
|
|
@@ -749,6 +771,7 @@ checkInsertTargets(ParseState *pstate, L
|
|
Bitmapset *wholecols = NULL;
|
|
Bitmapset *partialcols = NULL;
|
|
ListCell *tl;
|
|
+ uint32 system_attrs = 0;
|
|
|
|
foreach(tl, cols)
|
|
{
|
|
@@ -757,14 +780,37 @@ checkInsertTargets(ParseState *pstate, L
|
|
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)
|
|
+ {
|
|
+ if (SystemAttributeIsWritable(attrno))
|
|
+ {
|
|
+ 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(pstate->p_target_relation)),
|
|
+ parser_errposition(pstate, col->location)));
|
|
+ }
|
|
|
|
/*
|
|
* Check for duplicates, but only of whole columns --- we allow
|
|
diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmaster/postmaster.c
|
|
--- base/src/backend/postmaster/postmaster.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/postmaster/postmaster.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -107,6 +107,7 @@
|
|
#include "postmaster/pgarch.h"
|
|
#include "postmaster/postmaster.h"
|
|
#include "postmaster/syslogger.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/pg_shmem.h"
|
|
@@ -214,7 +215,8 @@ static pid_t StartupPID = 0,
|
|
AutoVacPID = 0,
|
|
PgArchPID = 0,
|
|
PgStatPID = 0,
|
|
- SysLoggerPID = 0;
|
|
+ SysLoggerPID = 0,
|
|
+ pgaceWorkerPID = 0;
|
|
|
|
/* Startup/shutdown state */
|
|
#define NoShutdown 0
|
|
@@ -1323,6 +1325,10 @@ ServerLoop(void)
|
|
if (PgStatPID == 0 && pmState == PM_RUN)
|
|
PgStatPID = pgstat_start();
|
|
|
|
+ /* If we have lost the pgace worker (if needed), try to start a new one */
|
|
+ if (pgaceWorkerPID == 0 && pmState == PM_RUN)
|
|
+ pgaceWorkerPID = pgaceStartupWorkerProcess();
|
|
+
|
|
/* If we need to signal the autovacuum launcher, do so now */
|
|
if (avlauncher_needs_signal)
|
|
{
|
|
@@ -1921,6 +1927,8 @@ SIGHUP_handler(SIGNAL_ARGS)
|
|
signal_child(PgArchPID, SIGHUP);
|
|
if (SysLoggerPID != 0)
|
|
signal_child(SysLoggerPID, SIGHUP);
|
|
+ if (pgaceWorkerPID != 0)
|
|
+ signal_child(pgaceWorkerPID, SIGHUP);
|
|
/* PgStatPID does not currently need SIGHUP */
|
|
|
|
/* Reload authentication config files too */
|
|
@@ -1978,6 +1986,9 @@ pmdie(SIGNAL_ARGS)
|
|
/* and the walwriter too */
|
|
if (WalWriterPID != 0)
|
|
signal_child(WalWriterPID, SIGTERM);
|
|
+ /* and the pgace worker too */
|
|
+ if (pgaceWorkerPID != 0)
|
|
+ signal_child(pgaceWorkerPID, SIGTERM);
|
|
pmState = PM_WAIT_BACKENDS;
|
|
}
|
|
|
|
@@ -2017,6 +2028,9 @@ pmdie(SIGNAL_ARGS)
|
|
/* and the walwriter too */
|
|
if (WalWriterPID != 0)
|
|
signal_child(WalWriterPID, SIGTERM);
|
|
+ /* and the walwriter too */
|
|
+ if (pgaceWorkerPID != 0)
|
|
+ signal_child(pgaceWorkerPID, SIGTERM);
|
|
pmState = PM_WAIT_BACKENDS;
|
|
}
|
|
|
|
@@ -2050,6 +2064,8 @@ pmdie(SIGNAL_ARGS)
|
|
signal_child(PgArchPID, SIGQUIT);
|
|
if (PgStatPID != 0)
|
|
signal_child(PgStatPID, SIGQUIT);
|
|
+ if (pgaceWorkerPID != 0)
|
|
+ signal_child(pgaceWorkerPID, SIGQUIT);
|
|
ExitPostmaster(0);
|
|
break;
|
|
}
|
|
@@ -2298,6 +2314,16 @@ reaper(SIGNAL_ARGS)
|
|
continue;
|
|
}
|
|
|
|
+ /* Was it the PGACE worker process? */
|
|
+ if (pid == pgaceWorkerPID)
|
|
+ {
|
|
+ pgaceWorkerPID = 0;
|
|
+ if (!EXIT_STATUS_0(exitstatus))
|
|
+ LogChildExit(LOG, _("PGACE worker process"),
|
|
+ pid, exitstatus);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
/*
|
|
* Else do standard backend child cleanup.
|
|
*/
|
|
@@ -2465,6 +2491,18 @@ HandleChildCrash(int pid, int exitstatus
|
|
signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
|
|
}
|
|
|
|
+ /* Take care of the pgace worker too */
|
|
+ if (pid == pgaceWorkerPID)
|
|
+ pgaceWorkerPID = 0;
|
|
+ else if (pgaceWorkerPID != 0 && !FatalError)
|
|
+ {
|
|
+ ereport(DEBUG2,
|
|
+ (errmsg_internal("sending %s to process %d",
|
|
+ (SendStop ? "SIGSTOP" : "SIGQUIT"),
|
|
+ (int) pgaceWorkerPID)));
|
|
+ signal_child(pgaceWorkerPID, (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
|
|
@@ -2584,7 +2622,8 @@ PostmasterStateMachine(void)
|
|
StartupPID == 0 &&
|
|
(BgWriterPID == 0 || !FatalError) &&
|
|
WalWriterPID == 0 &&
|
|
- AutoVacPID == 0)
|
|
+ AutoVacPID == 0 &&
|
|
+ pgaceWorkerPID == 0)
|
|
{
|
|
if (FatalError)
|
|
{
|
|
diff -rpNU3 base/src/backend/rewrite/rewriteHandler.c sepgsql/src/backend/rewrite/rewriteHandler.c
|
|
--- base/src/backend/rewrite/rewriteHandler.c 2008-11-05 09:57:00.000000000 +0900
|
|
+++ sepgsql/src/backend/rewrite/rewriteHandler.c 2009-01-16 10:33:08.000000000 +0900
|
|
@@ -24,6 +24,7 @@
|
|
#include "rewrite/rewriteDefine.h"
|
|
#include "rewrite/rewriteHandler.h"
|
|
#include "rewrite/rewriteManip.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
#include "commands/trigger.h"
|
|
@@ -1919,5 +1920,5 @@ QueryRewrite(Query *parsetree)
|
|
if (!foundOriginalQuery && lastInstead != NULL)
|
|
lastInstead->canSetTag = true;
|
|
|
|
- return results;
|
|
+ return pgacePostQueryRewrite(results);
|
|
}
|
|
diff -rpNU3 base/src/backend/security/Makefile sepgsql/src/backend/security/Makefile
|
|
--- base/src/backend/security/Makefile 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/Makefile 2009-01-14 15:33:08.000000000 +0900
|
|
@@ -0,0 +1,32 @@
|
|
+#
|
|
+# src/backend/security/Makefile
|
|
+# Makefile for Security Purpose Extensions
|
|
+#
|
|
+# Copyright (c) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+#
|
|
+subdir = src/backend/security
|
|
+top_builddir = ../../..
|
|
+include $(top_builddir)/src/Makefile.global
|
|
+
|
|
+
|
|
+OBJS := pgaceCommon.o pgaceHooks.o
|
|
+
|
|
+ifeq ($(enable_selinux), yes)
|
|
+OBJS += sepgsql/avc.o sepgsql/core.o sepgsql/hooks.o \
|
|
+ sepgsql/permissions.o sepgsql/proxy.o
|
|
+endif
|
|
+
|
|
+all: SUBSYS.o
|
|
+
|
|
+SUBSYS.o: $(OBJS)
|
|
+ $(LD) $(LDREL) $(LDOUT) $@ $^
|
|
+
|
|
+depend dep:
|
|
+ $(CC) -MM $(CFLAGS) *.c >depend
|
|
+
|
|
+clean:
|
|
+ rm -f SUBSYS.o $(OBJS)
|
|
+
|
|
+ifeq (depend,$(wildcard depend))
|
|
+include depend
|
|
+endif
|
|
diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security/pgaceCommon.c
|
|
--- base/src/backend/security/pgaceCommon.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/pgaceCommon.c 2009-01-14 15:25:24.000000000 +0900
|
|
@@ -0,0 +1,814 @@
|
|
+
|
|
+/*
|
|
+ * src/backend/security/pgaceCommon.c
|
|
+ * common framework of security modules
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ *
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/genam.h"
|
|
+#include "access/hash.h"
|
|
+#include "access/heapam.h"
|
|
+#include "access/xact.h"
|
|
+#include "catalog/catalog.h"
|
|
+#include "catalog/indexing.h"
|
|
+#include "catalog/pg_attribute.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "catalog/pg_type.h"
|
|
+#include "executor/executor.h"
|
|
+#include "libpq/be-fsstubs.h"
|
|
+#include "miscadmin.h"
|
|
+#include "nodes/makefuncs.h"
|
|
+#include "nodes/parsenodes.h"
|
|
+#include "parser/parse_expr.h"
|
|
+#include "security/pgace.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/syscache.h"
|
|
+#include "utils/tqual.h"
|
|
+#include <unistd.h>
|
|
+#include <sys/file.h>
|
|
+
|
|
+/*****************************************************************************
|
|
+ * GUC Parameter Support
|
|
+ *****************************************************************************/
|
|
+
|
|
+int pgace_feature;
|
|
+char *pgace_feature_string;
|
|
+
|
|
+const char *
|
|
+pgaceAssignFeatureString(const char *value, bool doit, GucSource source)
|
|
+{
|
|
+ char *result;
|
|
+
|
|
+ if (strcmp(value, "none") == 0)
|
|
+ {
|
|
+ pgace_feature = PGACE_FEATURE_NONE;
|
|
+ result = strdup(value);
|
|
+ }
|
|
+#ifdef HAVE_SELINUX
|
|
+ else if (strcmp(value, "selinux") == 0)
|
|
+ {
|
|
+ pgace_feature = PGACE_FEATURE_SELINUX;
|
|
+ result = strdup(value);
|
|
+ }
|
|
+#endif
|
|
+ else
|
|
+ {
|
|
+ pgace_feature = PGACE_FEATURE_NONE;
|
|
+ result = strdup("none");
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * Extended SQL statements support
|
|
+ *****************************************************************************/
|
|
+
|
|
+/*
|
|
+ * PGACE enables to create a new table labed as explicitly specified security
|
|
+ * attribute. It is implemented as an extension of SQL statement like:
|
|
+ * CREATE TABLE memo (
|
|
+ * id integer primary key,
|
|
+ * msg TEXT
|
|
+ * ) CONTEXT = 'system_u:object_r:sepgsql_secret_table_t';
|
|
+ *
|
|
+ * The specified security attribute is chained as a list of DefElem object,
|
|
+ * at CreateStmt->pgaceItem for a table, ColumnDef->pgaceItem for a column.
|
|
+ *
|
|
+ * These items are generated at pgaceGramSecurityItem() hook invoked from
|
|
+ * parser/gram.y. Then, pgaceRelationAttrList() pick them up and re-organize
|
|
+ * as a list, to pass it as an argument of heap_create_with_catalog().
|
|
+ *
|
|
+ * When the list is not NIL, it means user specifies a security attribute
|
|
+ * explicitly for a newly created table or column.
|
|
+ * pgaceGramCreateRelation() and pgaceGramCreateAttribute() are invoked
|
|
+ * just before inserting a new tuple into system catalog, and PGACE
|
|
+ * framework invokes pgaceGramCreateRelation() and/or pgaceGramCreateAttribute()
|
|
+ * hooks to give a chance the gurst to attach proper security attributes.
|
|
+ */
|
|
+
|
|
+List *
|
|
+pgaceRelationAttrList(CreateStmt *stmt)
|
|
+{
|
|
+ List *result = NIL;
|
|
+ ListCell *l;
|
|
+ DefElem *defel, *newel;
|
|
+
|
|
+ if (stmt->pgaceItem)
|
|
+ {
|
|
+ defel = (DefElem *) stmt->pgaceItem;
|
|
+
|
|
+ Assert(IsA(defel, DefElem));
|
|
+
|
|
+ if (!pgaceIsGramSecurityItem(defel))
|
|
+ elog(ERROR, "node is not a pgace security item");
|
|
+ newel = makeDefElem(NULL, (Node *) copyObject(defel));
|
|
+ result = lappend(result, newel);
|
|
+ }
|
|
+
|
|
+ foreach(l, stmt->tableElts)
|
|
+ {
|
|
+ ColumnDef *cdef = (ColumnDef *) lfirst(l);
|
|
+
|
|
+ defel = (DefElem *) cdef->pgaceItem;
|
|
+
|
|
+ if (defel)
|
|
+ {
|
|
+ Assert(IsA(defel, DefElem));
|
|
+
|
|
+ if (!pgaceIsGramSecurityItem(defel))
|
|
+ elog(ERROR, "node is not a pgace security item");
|
|
+ newel = makeDefElem(pstrdup(cdef->colname),
|
|
+ (Node *) copyObject(defel));
|
|
+ result = lappend(result, newel);
|
|
+ }
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+void
|
|
+pgaceCreateRelationCommon(Relation rel, HeapTuple tuple, List *pgaceAttrList)
|
|
+{
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach(l, pgaceAttrList)
|
|
+ {
|
|
+ DefElem *defel = (DefElem *) lfirst(l);
|
|
+
|
|
+ if (!defel->defname)
|
|
+ {
|
|
+ Assert(pgaceIsGramSecurityItem((DefElem *) defel->arg));
|
|
+ pgaceGramCreateRelation(rel, tuple, (DefElem *) defel->arg);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void
|
|
+pgaceCreateAttributeCommon(Relation rel, HeapTuple tuple,
|
|
+ List *pgaceAttrList)
|
|
+{
|
|
+ Form_pg_attribute attr = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach(l, pgaceAttrList)
|
|
+ {
|
|
+ DefElem *defel = lfirst(l);
|
|
+
|
|
+ if (!defel->defname)
|
|
+ continue; /* for table */
|
|
+ if (strcmp(defel->defname, NameStr(attr->attname)) == 0)
|
|
+ {
|
|
+ Assert(pgaceIsGramSecurityItem((DefElem *) defel->arg));
|
|
+ pgaceGramCreateAttribute(rel, tuple, (DefElem *) defel->arg);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceAlterRelationCommon()
|
|
+ *
|
|
+ * This function is invoked when a user requires to change security attribute
|
|
+ * of table/column with "ALTER TABLE" statement.
|
|
+ *
|
|
+ * When a user attempt to relabel a table, PGACE invokes alterRelationCommon()
|
|
+ * and it gives the guest module a chance to set a new security attribute of
|
|
+ * specified table.
|
|
+ * When a user attempt to relabel a column, PGACE invokes alterAttributeCommon()
|
|
+ * and it gives the guest module a chance to set a new security attribute of
|
|
+ * specified column.
|
|
+ */
|
|
+
|
|
+static void
|
|
+alterRelationCommon(Relation rel, DefElem *defel)
|
|
+{
|
|
+ Relation pg_class;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ pg_class = heap_open(RelationRelationId, RowExclusiveLock);
|
|
+
|
|
+ tuple = SearchSysCacheCopy(RELOID,
|
|
+ ObjectIdGetDatum(RelationGetRelid(rel)),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for relation '%s'",
|
|
+ RelationGetRelationName(rel));
|
|
+ pgaceGramAlterRelation(rel, tuple, defel);
|
|
+
|
|
+ simple_heap_update(pg_class, &tuple->t_self, tuple);
|
|
+ CatalogUpdateIndexes(pg_class, tuple);
|
|
+
|
|
+ heap_freetuple(tuple);
|
|
+ heap_close(pg_class, RowExclusiveLock);
|
|
+}
|
|
+
|
|
+static void
|
|
+alterAttributeCommon(Relation rel, char *colName, DefElem *defel)
|
|
+{
|
|
+ Relation pg_attr;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ pg_attr = heap_open(AttributeRelationId, RowExclusiveLock);
|
|
+
|
|
+ tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for attribute '%s' of relation '%s'",
|
|
+ colName, RelationGetRelationName(rel));
|
|
+ pgaceGramAlterAttribute(rel, tuple, defel);
|
|
+
|
|
+ simple_heap_update(pg_attr, &tuple->t_self, tuple);
|
|
+ CatalogUpdateIndexes(pg_attr, tuple);
|
|
+
|
|
+ heap_freetuple(tuple);
|
|
+ heap_close(pg_attr, RowExclusiveLock);
|
|
+}
|
|
+
|
|
+void
|
|
+pgaceAlterRelationCommon(Relation rel, AlterTableCmd *cmd)
|
|
+{
|
|
+ DefElem *defel = (DefElem *) cmd->def;
|
|
+
|
|
+ Assert(IsA(defel, DefElem));
|
|
+
|
|
+ if (!pgaceIsGramSecurityItem(defel))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("PGACE: unsupported security item")));
|
|
+
|
|
+ if (!cmd->name)
|
|
+ {
|
|
+ alterRelationCommon(rel, defel);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ alterAttributeCommon(rel, cmd->name, defel);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * security attribute management
|
|
+ *****************************************************************************/
|
|
+
|
|
+/*
|
|
+ * The following functions enables to manage security attribute of each tuple
|
|
+ * (including ones within system catalog).
|
|
+ *
|
|
+ * Security attribute has these features:
|
|
+ * 1. It is imported/exported with text representation, like
|
|
+ * 'system_u:object_r:sepgsql_table_t:s0'
|
|
+ * 2. In generally, many tuples share a same security attribute.
|
|
+ * (They are grouped by security attribute in other word.)
|
|
+ * 3. A object can have one security attribute at most.
|
|
+ * (It can have a state of unlabeled.)
|
|
+ *
|
|
+ * PGACE utilizes a newly added system catalog of pg_security to store text
|
|
+ * representation of security attribute efficiently. Any tuple has a object id
|
|
+ * of a tuple within pg_security system catalog, we call it as a security id.
|
|
+ *
|
|
+ * Users can show security attribute as if it stored text data, but any tuple
|
|
+ * has a security id which has a length of sizeof(Oid), without text data.
|
|
+ * It is translated each other when it is exported/imported.
|
|
+ *
|
|
+ * pgaceSidToSecurityLabel() returns a text representation for a given security,
|
|
+ * id, and pgaceSecurityLabelToSid() returns a security id for a give text
|
|
+ * representation. (If a given text representation was not found on pg_security
|
|
+ * system catalog, PGACE inserts a new entry automatically.)
|
|
+ *
|
|
+ * In the very early phase (invoked by initdb), pg_security system catalos is
|
|
+ * not available yet. The earlySecurityLabelToSid() and earlySidToSecurityLabel()
|
|
+ * is used to hold relationships between security id and text representation.
|
|
+ * These relationships are stored at the end of bootstraping mode by
|
|
+ * pgacePostBootstrapingMode(). It write any cached relationships into pg_security
|
|
+ * system catalog.
|
|
+ */
|
|
+
|
|
+typedef struct earlySeclabel
|
|
+{
|
|
+ struct earlySeclabel *next;
|
|
+ Oid sid;
|
|
+ char label[1];
|
|
+} earlySeclabel;
|
|
+
|
|
+static earlySeclabel *earlySeclabelList = NULL;
|
|
+
|
|
+static Oid
|
|
+earlySecurityLabelToSid(char *label)
|
|
+{
|
|
+ earlySeclabel *es;
|
|
+ Oid minsid = SecurityRelationId;
|
|
+
|
|
+ for (es = earlySeclabelList; es != NULL; es = es->next)
|
|
+ {
|
|
+ if (!strcmp(label, es->label))
|
|
+ return es->sid;
|
|
+ if (es->sid < minsid)
|
|
+ minsid = es->sid;
|
|
+ }
|
|
+ /*
|
|
+ * not found
|
|
+ */
|
|
+ es = malloc(sizeof(earlySeclabel) + strlen(label));
|
|
+ es->next = earlySeclabelList;
|
|
+ es->sid = minsid - 1;
|
|
+ strcpy(es->label, label);
|
|
+ earlySeclabelList = es;
|
|
+
|
|
+ return es->sid;
|
|
+}
|
|
+
|
|
+static char *
|
|
+earlySidToSecurityLabel(Oid sid)
|
|
+{
|
|
+ earlySeclabel *es;
|
|
+
|
|
+ for (es = earlySeclabelList; es != NULL; es = es->next)
|
|
+ {
|
|
+ if (es->sid == sid)
|
|
+ return pstrdup(es->label);
|
|
+ }
|
|
+
|
|
+ return NULL; /* not found */
|
|
+}
|
|
+
|
|
+void
|
|
+pgacePostBootstrapingMode(void)
|
|
+{
|
|
+ Relation rel;
|
|
+ CatalogIndexState ind;
|
|
+ HeapTuple tuple;
|
|
+ earlySeclabel *es, *_es;
|
|
+ Oid meta_sid;
|
|
+ Datum value;
|
|
+ bool isnull;
|
|
+
|
|
+ if (!earlySeclabelList)
|
|
+ return;
|
|
+
|
|
+ StartTransactionCommand();
|
|
+
|
|
+ meta_sid = earlySecurityLabelToSid(pgaceSecurityLabelOfLabel());
|
|
+
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+ ind = CatalogOpenIndexes(rel);
|
|
+
|
|
+ for (es = earlySeclabelList; es != NULL; es = _es)
|
|
+ {
|
|
+ _es = es->next;
|
|
+
|
|
+ value = DirectFunctionCall1(textin, CStringGetDatum(es->label));
|
|
+ isnull = false;
|
|
+ tuple = heap_form_tuple(RelationGetDescr(rel), &value, &isnull);
|
|
+
|
|
+ HeapTupleSetOid(tuple, es->sid);
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, meta_sid);
|
|
+
|
|
+ simple_heap_insert(rel, tuple);
|
|
+ CatalogIndexInsert(ind, tuple);
|
|
+
|
|
+ heap_freetuple(tuple);
|
|
+
|
|
+ free(es);
|
|
+ }
|
|
+ CatalogCloseIndexes(ind);
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+
|
|
+ CommitTransactionCommand();
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLookupSecurityId()
|
|
+ *
|
|
+ * The PGACE guest subsystem can use this interface to get a security id
|
|
+ * for a given text representation.
|
|
+ */
|
|
+Oid
|
|
+pgaceLookupSecurityId(char *raw_label)
|
|
+{
|
|
+ Oid labelOid, labelSid;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ return earlySecurityLabelToSid(raw_label);
|
|
+
|
|
+ /*
|
|
+ * lookup syscache at first
|
|
+ */
|
|
+ tuple = SearchSysCache(SECURITYLABEL,
|
|
+ CStringGetTextDatum(raw_label),
|
|
+ 0, 0, 0);
|
|
+ if (HeapTupleIsValid(tuple))
|
|
+ {
|
|
+ labelOid = HeapTupleGetOid(tuple);
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /*
|
|
+ * not found, insert a new one into pg_security
|
|
+ */
|
|
+ Relation rel;
|
|
+ CatalogIndexState ind;
|
|
+ char *slabel;
|
|
+ Datum labelTxt;
|
|
+ bool isnull;
|
|
+
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+
|
|
+ slabel = pgaceSecurityLabelOfLabel();
|
|
+
|
|
+ if (!slabel)
|
|
+ {
|
|
+ labelSid = InvalidOid;
|
|
+ labelOid = GetNewOid(rel);
|
|
+ }
|
|
+ else if (!strcmp(raw_label, slabel))
|
|
+ {
|
|
+ labelOid = labelSid = GetNewOid(rel);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ labelSid = pgaceLookupSecurityId(slabel);
|
|
+ labelOid = GetNewOid(rel);
|
|
+ }
|
|
+
|
|
+ ind = CatalogOpenIndexes(rel);
|
|
+
|
|
+ labelTxt = CStringGetTextDatum(raw_label);
|
|
+ isnull = false;
|
|
+ tuple = heap_form_tuple(RelationGetDescr(rel),
|
|
+ &labelTxt, &isnull);
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, labelSid);
|
|
+ HeapTupleSetOid(tuple, labelOid);
|
|
+
|
|
+ simple_heap_insert(rel, tuple);
|
|
+ CatalogIndexInsert(ind, tuple);
|
|
+
|
|
+ /*
|
|
+ * NOTE:
|
|
+ * We also have to insert a cache entry of new tuple of
|
|
+ * pg_security for temporary usage.
|
|
+ * If user tries to apply same security attribute twice
|
|
+ * or more within same command id, PGACE cannot decide
|
|
+ * whether it should be inserted, or not, because it
|
|
+ * cannot scan the prior one with SnapshotNow.
|
|
+ *
|
|
+ * A cache entry inserted will be invalidated on the
|
|
+ * next CommandIdIncrement().
|
|
+ * The purpose of InsertSysCache() here is to prevent
|
|
+ * duplicate insertion
|
|
+ */
|
|
+ InsertSysCache(RelationGetRelid(rel), tuple);
|
|
+
|
|
+ CatalogCloseIndexes(ind);
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
+
|
|
+ return labelOid;
|
|
+}
|
|
+
|
|
+Oid
|
|
+pgaceSecurityLabelToSid(char *label)
|
|
+{
|
|
+ char *raw_label = pgaceTranslateSecurityLabelIn(label);
|
|
+
|
|
+ if (!pgaceCheckValidSecurityLabel(raw_label))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("PGACE: invalid security label: %s", raw_label)));
|
|
+
|
|
+ return pgaceLookupSecurityId(raw_label);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLookupSecurityLabel()
|
|
+ *
|
|
+ * The PGACE guest module can use this interface to get a text representation
|
|
+ * in raw-format, without cosmetic translation.
|
|
+ */
|
|
+char *
|
|
+pgaceLookupSecurityLabel(Oid sid)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ Datum labelTxt;
|
|
+ char *label;
|
|
+ bool isnull;
|
|
+
|
|
+ if (!OidIsValid(sid))
|
|
+ return NULL;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ return earlySidToSecurityLabel(sid);
|
|
+
|
|
+ tuple = SearchSysCache(SECURITYOID,
|
|
+ ObjectIdGetDatum(sid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ return NULL;
|
|
+
|
|
+ labelTxt = SysCacheGetAttr(SECURITYOID,
|
|
+ tuple, Anum_pg_security_seclabel, &isnull);
|
|
+ Assert(!isnull);
|
|
+ label = TextDatumGetCString(labelTxt);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return label;
|
|
+}
|
|
+
|
|
+char *
|
|
+pgaceSidToSecurityLabel(Oid sid)
|
|
+{
|
|
+ char *label;
|
|
+
|
|
+ label = pgaceLookupSecurityLabel(sid);
|
|
+ if (!label || !pgaceCheckValidSecurityLabel(label))
|
|
+ label = pgaceUnlabeledSecurityLabel();
|
|
+
|
|
+ if (!label)
|
|
+ return pstrdup("");
|
|
+
|
|
+ return pgaceTranslateSecurityLabelOut(label);
|
|
+}
|
|
+
|
|
+Datum
|
|
+pgaceHeapGetSecurityLabelSysattr(HeapTuple tuple)
|
|
+{
|
|
+ Oid sid = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ return CStringGetTextDatum(pgaceSidToSecurityLabel(sid));
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * Set/Get security attribute of Large Object
|
|
+ *****************************************************************************/
|
|
+
|
|
+/*
|
|
+ * lo_get_security()
|
|
+ *
|
|
+ * This function returns a security attribute of large object
|
|
+ * in TEXT representation.
|
|
+ *
|
|
+ * It assumes the first page means the whole of large object.
|
|
+ * The guest of PGACE should pay effort to keep its consistency.
|
|
+ */
|
|
+Datum
|
|
+lo_get_security(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid loid = PG_GETARG_OID(0);
|
|
+ Relation rel;
|
|
+ ScanKeyData skey;
|
|
+ SysScanDesc scan;
|
|
+ HeapTuple tuple;
|
|
+ Oid sid;
|
|
+
|
|
+ rel = heap_open(LargeObjectRelationId, AccessShareLock);
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(loid));
|
|
+
|
|
+ scan = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
|
|
+ SnapshotNow, 1, &skey);
|
|
+ tuple = systable_getnext(scan);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
+ errmsg("large object %u does not exist", loid)));
|
|
+ pgaceLargeObjectGetSecurity(rel, tuple);
|
|
+ sid = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ systable_endscan(scan);
|
|
+ heap_close(rel, AccessShareLock);
|
|
+
|
|
+ return CStringGetTextDatum(pgaceSidToSecurityLabel(sid));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * lo_set_security()
|
|
+ *
|
|
+ * This function set a new security attribute of a large object.
|
|
+ * It scans pg_largeobject system catalog with a given loid,
|
|
+ * and invokes pgaceLargeObjectSetSecurity() for each page frame.
|
|
+ */
|
|
+Datum
|
|
+lo_set_security(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid loid = PG_GETARG_OID(0);
|
|
+ Datum labelTxt = PG_GETARG_DATUM(1);
|
|
+ Relation rel;
|
|
+ ScanKeyData skey;
|
|
+ SysScanDesc sd;
|
|
+ HeapTuple oldtup, newtup;
|
|
+ CatalogIndexState indstate;
|
|
+ Oid sid;
|
|
+ List *okList = NIL;
|
|
+ bool found = false;
|
|
+
|
|
+ sid = pgaceSecurityLabelToSid(TextDatumGetCString(labelTxt));
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber,
|
|
+ F_OIDEQ, ObjectIdGetDatum(loid));
|
|
+
|
|
+ rel = heap_open(LargeObjectRelationId, RowExclusiveLock);
|
|
+
|
|
+ indstate = CatalogOpenIndexes(rel);
|
|
+
|
|
+ sd = systable_beginscan(rel,
|
|
+ LargeObjectLOidPNIndexId, true,
|
|
+ SnapshotNow, 1, &skey);
|
|
+
|
|
+ while ((oldtup = systable_getnext(sd)) != NULL)
|
|
+ {
|
|
+ ListCell *l;
|
|
+
|
|
+ newtup = heap_copytuple(oldtup);
|
|
+ HeapTupleSetSecLabel(newtup, sid);
|
|
+
|
|
+ foreach (l, okList)
|
|
+ {
|
|
+ if (HeapTupleGetSecLabel(oldtup) == lfirst_oid(l))
|
|
+ goto skip; /* already checked */
|
|
+ }
|
|
+ okList = lappend_oid(okList, HeapTupleGetSecLabel(oldtup));
|
|
+
|
|
+ pgaceLargeObjectSetSecurity(rel, newtup, oldtup);
|
|
+ skip:
|
|
+ simple_heap_update(rel, &newtup->t_self, newtup);
|
|
+ CatalogUpdateIndexes(rel, newtup);
|
|
+ found = true;
|
|
+ }
|
|
+ systable_endscan(sd);
|
|
+ CatalogCloseIndexes(indstate);
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+
|
|
+ CommandCounterIncrement();
|
|
+
|
|
+ if (!found)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
+ errmsg("large object %u does not exist", loid)));
|
|
+
|
|
+ PG_RETURN_BOOL(true);
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Function stubs related to security modules
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * Legacy functions support
|
|
+ */
|
|
+Datum security_label_in(PG_FUNCTION_ARGS);
|
|
+Datum security_label_out(PG_FUNCTION_ARGS);
|
|
+Datum security_label_raw_in(PG_FUNCTION_ARGS);
|
|
+Datum security_label_raw_out(PG_FUNCTION_ARGS);
|
|
+Datum text_to_security_label(PG_FUNCTION_ARGS);
|
|
+Datum security_label_to_text(PG_FUNCTION_ARGS);
|
|
+
|
|
+Datum
|
|
+security_label_in(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return DirectFunctionCall1(textin, PG_GETARG_DATUM(0));
|
|
+}
|
|
+
|
|
+Datum
|
|
+security_label_out(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return DirectFunctionCall1(textout, PG_GETARG_DATUM(0));
|
|
+}
|
|
+
|
|
+Datum
|
|
+security_label_raw_in(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("%s is no longer supported", __FUNCTION__)));
|
|
+ PG_RETURN_VOID();
|
|
+}
|
|
+
|
|
+Datum
|
|
+security_label_raw_out(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("%s is no longer supported", __FUNCTION__)));
|
|
+ PG_RETURN_VOID();
|
|
+}
|
|
+
|
|
+Datum
|
|
+text_to_security_label(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("%s is no longer supported", __FUNCTION__)));
|
|
+ PG_RETURN_VOID();
|
|
+}
|
|
+
|
|
+Datum
|
|
+security_label_to_text(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("%s is no longer supported", __FUNCTION__)));
|
|
+ PG_RETURN_VOID();
|
|
+}
|
|
+
|
|
+/*
|
|
+ * If the guest of PGACE added its specific functions, it has to put
|
|
+ * function stubs on the following section, because the guest modules
|
|
+ * are not compiled and linked when it is disabled.
|
|
+ * It can cause a build problem in other environments.
|
|
+ */
|
|
+#ifndef HAVE_SELINUX
|
|
+
|
|
+static Datum
|
|
+unavailable_function(const char *fn_name, int error_code)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(error_code),
|
|
+ errmsg("%s is not available", fn_name)));
|
|
+ PG_RETURN_VOID();
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_getcon(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__,
|
|
+ ERRCODE_SELINUX_ERROR);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_getservcon(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__,
|
|
+ ERRCODE_SELINUX_ERROR);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_user(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__,
|
|
+ ERRCODE_SELINUX_ERROR);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_role(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__,
|
|
+ ERRCODE_SELINUX_ERROR);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_type(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__,
|
|
+ ERRCODE_SELINUX_ERROR);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_get_range(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__,
|
|
+ ERRCODE_SELINUX_ERROR);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_user(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__,
|
|
+ ERRCODE_SELINUX_ERROR);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_role(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__,
|
|
+ ERRCODE_SELINUX_ERROR);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_type(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__,
|
|
+ ERRCODE_SELINUX_ERROR);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_set_range(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ return unavailable_function(__FUNCTION__,
|
|
+ ERRCODE_SELINUX_ERROR);
|
|
+}
|
|
+
|
|
+#endif /* HAVE_SELINUX */
|
|
diff -rpNU3 base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/pgaceHooks.c
|
|
--- base/src/backend/security/pgaceHooks.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/pgaceHooks.c 2009-02-25 22:31:25.000000000 +0900
|
|
@@ -0,0 +1,1462 @@
|
|
+/*
|
|
+ * src/backend/security/pgaceHooks.c
|
|
+ * Security hooks in PostgreSQL Access Control Extension (PGACE)
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ *
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "security/pgace.h"
|
|
+
|
|
+/*
|
|
+ * GUC parameter: pgace_feature
|
|
+ * It allows users to choose an enhanced security feature.
|
|
+ * It has a state of 'none' in the default, so you should
|
|
+ * specify it explicitly with initdb --pgace-feature=FEATURE.
|
|
+ */
|
|
+int pgace_feature;
|
|
+
|
|
+/*
|
|
+ * PGACE (PostgreSQL Access Control Extension)
|
|
+ *
|
|
+ * It provides a set of security hooks at strategic points and
|
|
+ * common facilities to manage security attribute of database
|
|
+ * objects. Its purpose is to allow various kind of enhanced
|
|
+ * security features with minimum impact to the core PostgreSQL
|
|
+ * codes.
|
|
+ * In generally, individual security feature has its own access
|
|
+ * control model, policy and granuality, however, they also have
|
|
+ * facilities to be shared commonly.
|
|
+ *
|
|
+ * The one is a set of security hooks. All the enhanced security
|
|
+ * codes have to be invoked via the hooks, and return a proper
|
|
+ * value or raise an error, if necessary.
|
|
+ * When you add a new security feature, you need the following steps.
|
|
+ * 1. add a option to 'pgace_feature' parameter.
|
|
+ * 2. modify hooks to invoke your security feature.
|
|
+ * Please note that you don't need to modify all the hooks.
|
|
+ * If you don't provide any feature, please keep it as is.
|
|
+ *
|
|
+ * Example: pgaceHeapTupleInsert() hook
|
|
+ * ------------------------------------
|
|
+ * bool
|
|
+ * pgaceHeapTupleInsert(Relation rel, HeapTuple tuple,
|
|
+ * bool is_internal, bool with_returning)
|
|
+ * {
|
|
+ * switch (pgace_feature)
|
|
+ * {
|
|
+ * #ifdef HAVE_SELINUX
|
|
+ * case PGACE_FEATURE_SELINUX:
|
|
+ * if (sepgsqlIsEnabled())
|
|
+ * return sepgsqlHeapTupleInsert(rel, tuple,
|
|
+ * is_internal,
|
|
+ * with_returning);
|
|
+ * break;
|
|
+ * #endif
|
|
+ * #ifdef HAVE_FOO_SECURITY
|
|
+ * case PGACE_FEATURE_FOO_SECURITY:
|
|
+ * return fooSecurityHeapTupleInsert(rel, tuple,
|
|
+ * is_internal,
|
|
+ * with_returning);
|
|
+ * break;
|
|
+ * #endif
|
|
+ * default:
|
|
+ * break;
|
|
+ * }
|
|
+ * return true;
|
|
+ * }
|
|
+ * ------------------------------------
|
|
+ * If your security feature has platform dependency, related code
|
|
+ * should be enclosed by #ifdef ... #endif block.
|
|
+ * (In this case, it is named as FOO_SECURITY.)
|
|
+ * The pgace_feature shows what enhanced security feature is activated
|
|
+ * in this system. If your security feature is chosen, it can be invoked
|
|
+ * via pgaceHeapTupleInsert() just before a new tuple is inserted on
|
|
+ * the target relation. Your fooSecurityHeapTupleInsert() can make its
|
|
+ * decision based on its policy and given informations.
|
|
+ * This hook requires to return 'true' or 'false'. If it returns 'false',
|
|
+ * it will be skipped to insert the given tuple.
|
|
+ *
|
|
+ * The other is facilities to manage security attribtue of database
|
|
+ * objects. They have text representation as most of secure operating
|
|
+ * system doing, but it is not stored in each tuples directly, to reduce
|
|
+ * storage comsumption.
|
|
+ * We can fetch them via HeapTupleGetSecLabel(tuple) macro. It is stored
|
|
+ * as a Oid value (called as security identifier) which indicates pg_security
|
|
+ * system catalog. It holds mapping between security identifier and security
|
|
+ * attribute in text representation.
|
|
+ * User can see/set security attribute of database objects via security_label
|
|
+ * system column.
|
|
+ */
|
|
+
|
|
+/******************************************************************
|
|
+ * Initialization hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceShmemSize
|
|
+ *
|
|
+ * This hook has to return the size of shared memory required
|
|
+ * by the guest. If it needs no shared memory region, it should
|
|
+ * return 0.
|
|
+ */
|
|
+Size
|
|
+pgaceShmemSize(void)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlShmemSize();
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return (Size) 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceInitialize
|
|
+ *
|
|
+ * This hook is invoked when a new PostgreSQL instance is created.
|
|
+ * The guest can use this hook to initialize itself.
|
|
+ *
|
|
+ * is_bootstrap is true, if bootstraping mode.
|
|
+ */
|
|
+void
|
|
+pgaceInitialize(bool is_bootstrap)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlInitialize(is_bootstrap);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceStartupWorkerProcess
|
|
+ *
|
|
+ * The guest can create a worker process in this hook, if necessary.
|
|
+ * (currently, PGACE does not support multiple worker processes.)
|
|
+ *
|
|
+ * This hooks has to return the PID of child process. It is managed
|
|
+ * by postmaster in the same way to manage the other children.
|
|
+ * So, the worker process has to be available to handle signals.
|
|
+ *
|
|
+ * If unnecessary, it has to return (pid_t) 0.
|
|
+ */
|
|
+pid_t
|
|
+pgaceStartupWorkerProcess(void)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlStartupWorkerProcess();
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return (pid_t) 0;
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * SQL proxy hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgacePostQueryRewrite
|
|
+ *
|
|
+ * This hook is invoked just after query is rewritten.
|
|
+ *
|
|
+ * The guest can check/modify/replace given query trees in this
|
|
+ * hook, if necessary.
|
|
+ * queryList is a list of Query object processes by rewriter.
|
|
+ */
|
|
+List *
|
|
+pgacePostQueryRewrite(List *queryList)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlPostQueryRewrite(queryList);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return queryList;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceExecutorStart
|
|
+ *
|
|
+ * This hook is invoked on the head of ExecutorStart().
|
|
+ *
|
|
+ * The arguments of this hook are come from the ones of ExecutorStart
|
|
+ * as is.
|
|
+ */
|
|
+void
|
|
+pgaceExecutorStart(QueryDesc *queryDesc, int eflags)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlExecutorStart(queryDesc, eflags);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceRowlvBehaviorSwitchTo
|
|
+ * changes internal state during FK constraint checks
|
|
+ */
|
|
+bool
|
|
+pgaceRowlvBehaviorSwitchTo(bool new_abort)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlRowlvBehaviorSwitchTo(new_abort);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return new_abort;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceExecScan
|
|
+ *
|
|
+ * This hook is invoked on ExecScan for each tuple fetched.
|
|
+ * The guest can check its visibility, and can skip to scan the given
|
|
+ * tuple. If this hook returns false, the tuple is filtered from the
|
|
+ * result set or the target of updates/deletion.
|
|
+ *
|
|
+ * Otherwise, it has to return true.
|
|
+ *
|
|
+ * The guest can refer Scan::pgaceTuplePerms (declared as uint32).
|
|
+ * It is a copy come from RangeTblEntry::pgaceTuplePerms set in
|
|
+ * the previous phase. It can be used to mark what permissions are
|
|
+ * required to scanned tuples.
|
|
+ */
|
|
+bool
|
|
+pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlExecScan(scan, rel, slot, abort);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceProcessUtility
|
|
+ *
|
|
+ * This hooks is invoked on the head of ProcessUtility().
|
|
+ */
|
|
+void
|
|
+pgaceProcessUtility(Node *parsetree, ParamListInfo params, bool isTopLevel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlProcessUtility(parsetree, params, isTopLevel);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * HeapTuple modification hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceHeapTupleInsert
|
|
+ *
|
|
+ * This hooks is invoked just before a new tuple is inserted.
|
|
+ * If it returns false, inserting the given tuple is skipped.
|
|
+ * (or generates an error, if we cannot skip it simply.)
|
|
+ *
|
|
+ * The guest has to set a security attribute of a newly inserted
|
|
+ * tuple, if necessary and when user does not specify it explicitly.
|
|
+ *
|
|
+ * arguments:
|
|
+ * - rel is the target relation to be inserted.
|
|
+ * - tuple is the new tuple to be inserted.
|
|
+ * - is_internal is a bool to show whether it directly come from
|
|
+ * user's query, or not.
|
|
+ * - with_returning is a bool to show whether this INSERT statement
|
|
+ * has RETURNING clause, or not.
|
|
+ */
|
|
+bool
|
|
+pgaceHeapTupleInsert(Relation rel, HeapTuple tuple,
|
|
+ bool is_internal, bool with_returning)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlHeapTupleInsert(rel, tuple,
|
|
+ is_internal,
|
|
+ with_returning);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceHeapTupleUpdate
|
|
+ *
|
|
+ * This hook is invoked just before a tuple is updated.
|
|
+ * If it returns false, updating the given tuple is skipped.
|
|
+ * (or generates an error, if we cannot skip it simply.)
|
|
+ *
|
|
+ * The guest has to preserve a security attribute of the updated
|
|
+ * tuple, if necessary and when user specify its new security
|
|
+ * attribute explicitly.
|
|
+ *
|
|
+ * arguments:
|
|
+ * - rel is the target relation to be updated.
|
|
+ * - otid is the ItemPointer of the tuple with older version.
|
|
+ * - newtup is the tuple to be updated.
|
|
+ * - is_internal is a bool to show whether it directly come from
|
|
+ * user's query, or not.
|
|
+ * - with_returning is a bool to show whether this INSERT statement
|
|
+ * has RETURNING clause, or not.
|
|
+ */
|
|
+bool
|
|
+pgaceHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup,
|
|
+ bool is_internal, bool with_returning)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlHeapTupleUpdate(rel, otid, newtup,
|
|
+ is_internal,
|
|
+ with_returning);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceHeapTupleDelete
|
|
+ *
|
|
+ * This hook is invoked just before a tuple is deleted.
|
|
+ * If it returns false, deleting the given tuple is skipped.
|
|
+ * (or generates an error, if we cannot skip it simply.)
|
|
+ *
|
|
+ * arguments:
|
|
+ * - rel is the target relation to be deleted.
|
|
+ * - otid is the ItemPointer of the tuple to be deleted.
|
|
+ * - is_internal is a bool to show whether it directly come from
|
|
+ * user's query, or not.
|
|
+ * - with_returning is a bool to show whether this INSERT statement
|
|
+ * has RETURNING clause, or not.
|
|
+ */
|
|
+bool
|
|
+pgaceHeapTupleDelete(Relation rel, ItemPointer otid,
|
|
+ bool is_internal, bool with_returning)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlHeapTupleDelete(rel, otid,
|
|
+ is_internal,
|
|
+ with_returning);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Extended SQL statement hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceIsGramSecurityItem
|
|
+ *
|
|
+ * PGACE framework provides its guest to manage security attribute
|
|
+ * for some kind of database obejcts, using an enhanced SQL statement.
|
|
+ *
|
|
+ * For example:
|
|
+ * CREATE TABLE tbl (
|
|
+ * x integer,
|
|
+ * y text
|
|
+ * ) security_label = 'system_u:object_r:sepgsql_table_t:Classified';
|
|
+ *
|
|
+ * This hook is invoked during parsing given queries at parser/gram.y.
|
|
+ * It generates a DefElem object which holds explicitly specified
|
|
+ * security attribute. If working guest support the feature and the
|
|
+ * given DefElem has correct pair of defname and argument string,
|
|
+ * this hook should return true.
|
|
+ * In ths above example, the given DefElem has "security_label" as
|
|
+ * defname, and "system_u:object_r:sepgsql_table_t:Classified" as
|
|
+ * its argument string.
|
|
+ */
|
|
+bool
|
|
+pgaceIsGramSecurityItem(DefElem *defel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlIsGramSecurityItem(defel);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * The series of following hooks has three arguments.
|
|
+ * - rel is an opened relation of the target system catalog.
|
|
+ * - tuple is a new tuple to be inserted/updated.
|
|
+ * - defel is a DefElem object checked in pgaceIsGramSecurityItem().
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * pgaceGramCreateRelation
|
|
+ *
|
|
+ * This hook invoked to apply an explicitly specified security attribute
|
|
+ * just before inserting a new tuple into pg_class system catalog on
|
|
+ * the processing of CREATE TABLE.
|
|
+ * The guest can attach the required security attribute for the given
|
|
+ * tuple which means a new relation.
|
|
+ */
|
|
+void
|
|
+pgaceGramCreateRelation(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ {
|
|
+ sepgsqlGramCreateRelation(rel, tuple, defel);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (defel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("unable to set security attribute of table "
|
|
+ "via CREATE TABLE")));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceGramCreateAttribute
|
|
+ *
|
|
+ * This hook invoked to apply an explicitly specified security attribute
|
|
+ * just before inserting a new tuple into pg_attribute system catalog on
|
|
+ * the processing of CREATE TABLE.
|
|
+ * The guest can attach the required security attribute for the given
|
|
+ * tuple which means a new column.
|
|
+ */
|
|
+void
|
|
+pgaceGramCreateAttribute(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ {
|
|
+ sepgsqlGramCreateAttribute(rel, tuple, defel);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (defel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("unable to set security attribute of column "
|
|
+ "via CREATE TABLE")));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceGramAlterRelation
|
|
+ *
|
|
+ * This hook invoked to apply an explicitly specified security attribute
|
|
+ * just before updating an older tuple of pg_class system catalog on
|
|
+ * the processing of ALTER TABLE.
|
|
+ * The guest can attach the required security attribute for the given
|
|
+ * tuple which means a table.
|
|
+ */
|
|
+void
|
|
+pgaceGramAlterRelation(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ {
|
|
+ sepgsqlGramAlterRelation(rel, tuple, defel);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (defel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("unable to set security attribute of table "
|
|
+ "via ALTER TABLE")));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceGramAlterAttribute
|
|
+ *
|
|
+ * This hook invoked to apply an explicitly specified security attribute
|
|
+ * just before updating an older tuple of pg_attribute system catalog on
|
|
+ * the processing of ALTER TABLE.
|
|
+ * The guest can attach the required security attribute for the given
|
|
+ * tuple which means a column.
|
|
+ */
|
|
+void
|
|
+pgaceGramAlterAttribute(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ {
|
|
+ sepgsqlGramAlterAttribute(rel, tuple, defel);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (defel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("unable to set security attribute of column "
|
|
+ "via ALTER TABLE")));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceGramCreateDatabase
|
|
+ *
|
|
+ * This hook invoked to apply an explicitly specified security attribute
|
|
+ * just before inserting a new tuple into pg_database system catalog on
|
|
+ * the processing of CREATE DATABASE.
|
|
+ * The guest can attach the required security attribute for the given
|
|
+ * tuple which means a database.
|
|
+ */
|
|
+void
|
|
+pgaceGramCreateDatabase(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ {
|
|
+ sepgsqlGramCreateDatabase(rel, tuple, defel);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (defel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("unable to set security attribute of database "
|
|
+ "via CREATE DATABASE")));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceGramAlterDatabase
|
|
+ *
|
|
+ * This hook invoked to apply an explicitly specified security attribute
|
|
+ * just before updating an older tuple of pg_database system catalog on
|
|
+ * the processing of ALTER DATABASE.
|
|
+ * The guest can attach the required security attribute for the given
|
|
+ * tuple which means a database.
|
|
+ */
|
|
+void
|
|
+pgaceGramAlterDatabase(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ {
|
|
+ sepgsqlGramAlterDatabase(rel, tuple, defel);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (defel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("unable to set security attribute of database "
|
|
+ "via ALTER DATABASE")));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceGramCreateFunction
|
|
+ *
|
|
+ * This hook invoked to apply an explicitly specified security attribute
|
|
+ * just before inserting a new tuple into pg_proc system catalog on
|
|
+ * the processing of CREATE FUNCTION.
|
|
+ * The guest can attach the required security attribute for the given
|
|
+ * tuple which means a function.
|
|
+ */
|
|
+void
|
|
+pgaceGramCreateFunction(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ {
|
|
+ sepgsqlGramCreateFunction(rel, tuple, defel);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (defel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("unable to set security attribute of function "
|
|
+ "via CREATE FUNCTION")));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceGramAlterFunction
|
|
+ *
|
|
+ * This hook invoked to apply an explicitly specified security attribute
|
|
+ * just before updating an older tuple of pg_proc system catalog on
|
|
+ * the processing of ALTER FUNCTION.
|
|
+ * The guest can attach the required security attribute for the given
|
|
+ * tuple which means a function.
|
|
+ */
|
|
+void
|
|
+pgaceGramAlterFunction(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ {
|
|
+ sepgsqlGramAlterFunction(rel, tuple, defel);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (defel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("unable to set security attribute of function "
|
|
+ "via ALTER FUNCTION")));
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * DATABASE related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceSetDatabaseParam
|
|
+ *
|
|
+ * This hook is invoked just before putting a new value on a GUC
|
|
+ * variable.
|
|
+ *
|
|
+ * arguments:
|
|
+ * - name is a name of GUC variable.
|
|
+ * - argstring is its new value. NULL means user tries to reset
|
|
+ * the given GUC variable.
|
|
+ */
|
|
+void
|
|
+pgaceSetDatabaseParam(const char *name, char *argstring)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlSetDatabaseParam(name, argstring);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceGetDatabaseParam
|
|
+ *
|
|
+ * This hook is invoked just before reffering a GUC variable.
|
|
+ *
|
|
+ * arguments:
|
|
+ * - name is a name of GUC variable.
|
|
+ */
|
|
+void
|
|
+pgaceGetDatabaseParam(const char *name)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlGetDatabaseParam(name);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * FUNCTION related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceCallFunction
|
|
+ *
|
|
+ * This hook is invoked when a function is invoked as a part
|
|
+ * of the given query. It provides a FmgrInfo object of the
|
|
+ * function, so the guest can store its opaque data within
|
|
+ * FmgrInfo::fn_pgaceItem.
|
|
+ */
|
|
+void
|
|
+pgaceCallFunction(FmgrInfo *finfo)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlCallFunction(finfo);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceCallAggFunction
|
|
+ *
|
|
+ * This hook is invoked when an aggregate function is invoked
|
|
+ * in the given query. pgaceCallFunction() is also invoked for
|
|
+ * its transate function and finalize function.
|
|
+ *
|
|
+ * arguments:
|
|
+ * - aggTuple is the tuple of target aggregate function stored
|
|
+ * in pg_aggregate system catalog.
|
|
+ */
|
|
+void
|
|
+pgaceCallAggFunction(HeapTuple aggTuple)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlCallAggFunction(aggTuple);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceCallFunctionTrigger
|
|
+ *
|
|
+ * This hook is invoked just before executing trigger function.
|
|
+ * If it returns false, the trigger function is not invoked and
|
|
+ * caller receives a NULL tuple as a result.
|
|
+ * (It also means skip to update/delete the tuple in BR-triggers.)
|
|
+ */
|
|
+bool
|
|
+pgaceCallTriggerFunction(TriggerData *tgdata)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlCallTriggerFunction(tgdata);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceAllowInlineFunction
|
|
+ *
|
|
+ * This hook gives guest a chance to make decision just before
|
|
+ * a set-returning function is inlined.
|
|
+ *
|
|
+ * arguments:
|
|
+ * - fnoid is oid of the function to be inlined.
|
|
+ * - func_tuple is tuple of the function stored in pg_proc.
|
|
+ */
|
|
+bool
|
|
+pgaceAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlAllowFunctionInlined(fnoid, func_tuple);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * TABLE related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceLockTable
|
|
+ *
|
|
+ * This hook is invoked when user tries to LOCK a table explicitly.
|
|
+ * The argument of relid shows the target relation id.
|
|
+ */
|
|
+void
|
|
+pgaceLockTable(Oid relid)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLockTable(relid);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceExecTruncate
|
|
+ *
|
|
+ * This hook is invoked just before it truncate tables.
|
|
+ * The argument is a list of already opened relations with
|
|
+ * AccessExclusiveLock.
|
|
+ */
|
|
+void
|
|
+pgaceExecTruncate(List *trunk_rels)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlExecTruncate(trunk_rels);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * COPY TO/COPY FROM statement hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceCopyTable
|
|
+ *
|
|
+ * This hook is invoked before executing COPY TO/COPY FROM statement,
|
|
+ * to give the guest a chance to check tables/columns appeared in.
|
|
+ *
|
|
+ * arguments:
|
|
+ * - rel is the target relation of this COPY TO/FROM statement.
|
|
+ * It can be NULL, when COPY (SELECT ...) TO ... is given.
|
|
+ * - attNumList is a list of attribute number
|
|
+ * - isFrom is a bool to show the direction of the COPY
|
|
+ */
|
|
+void
|
|
+pgaceCopyTable(Relation rel, List *attNumList, bool isFrom)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlCopyTable(rel, attNumList, isFrom);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceCopyFile
|
|
+ *
|
|
+ * This hook is invoked just after a target file is opened
|
|
+ * at COPY TO/COPY FROM statement to give the guest a chance to
|
|
+ * check whether it allows to read/write the file.
|
|
+ *
|
|
+ * arguments:
|
|
+ * - rel is the target relation of this COPY TO/FROM statement.
|
|
+ * It can be NULL, when COPY (SELECT ...) TO ... is given.
|
|
+ * - isFrom is a bool to show the direction of the COPY
|
|
+ * - fdesc is the file descriptor of the target file opened.
|
|
+ * - filename is the filename of fdesc
|
|
+ */
|
|
+void
|
|
+pgaceCopyFile(Relation rel, int fdesc, const char *filename, bool isFrom)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlCopyFile(rel, fdesc, filename, isFrom);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceCopyToTuple
|
|
+ *
|
|
+ * This hook is invoked just before output of a fetched tuple on
|
|
+ * processing COPY TO statement, to give the guest a chance to make
|
|
+ * a decision whether the given tuple is visible, or not.
|
|
+ * If it returns false, the given tuple is not exported, as if it
|
|
+ * does not exist on the target relation.
|
|
+ * Elsewhere,
|
|
+ *
|
|
+ * arguments:
|
|
+ * - rel is the target relation of this
|
|
+ * - attNumList is a list of attribute number
|
|
+ * - tuple is a tuple to be checked
|
|
+ */
|
|
+bool
|
|
+pgaceCopyToTuple(Relation rel, List *attNumList, HeapTuple tuple)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlCopyToTuple(rel, attNumList, tuple);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Loadable shared library module hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceLoadSharedModule
|
|
+ *
|
|
+ * This hook is invoked before loading a shared library module,
|
|
+ * to give the guest a change to confirm whether the required
|
|
+ * module is safe, or not.
|
|
+ *
|
|
+ * This hook can be also invoked implicitly when a user tries
|
|
+ * to call a function implemented within external modules.
|
|
+ */
|
|
+void
|
|
+pgaceLoadSharedModule(const char *filename)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLoadSharedModule(filename);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Binary Large Object (BLOB) hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectCreate
|
|
+ *
|
|
+ * This hooks is invoked just before the first tuple of a new large
|
|
+ * object is inserted, to give the guest a change to make its
|
|
+ * decision and attach proper security context for the tuple.
|
|
+ *
|
|
+ * The argument of rel is the opened pg_largeobject system catalog.
|
|
+ */
|
|
+void
|
|
+pgaceLargeObjectCreate(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectCreate(rel, tuple);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectDrop
|
|
+ *
|
|
+ * This hook is invoked just before each tuple of a large object
|
|
+ * are deleted, to give the guest a change to make its decision.
|
|
+ *
|
|
+ * The argument of pgaceItem is an opaque data, the guest can
|
|
+ * use it discreationally.
|
|
+ */
|
|
+void
|
|
+pgaceLargeObjectDrop(Relation rel, HeapTuple tuple, void **pgaceItem)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectDrop(rel, tuple, pgaceItem);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectRead
|
|
+ *
|
|
+ * This hook is invoked at the head of lo_read().
|
|
+ * If the guest allows a large object to have non-uniform security
|
|
+ * attributes (not a unique one for each page frame), using HeapTuple
|
|
+ * related hooks are more recommendable.
|
|
+ */
|
|
+void
|
|
+pgaceLargeObjectRead(LargeObjectDesc *lodesc, int length)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectRead(lodesc, length);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectWrite
|
|
+ *
|
|
+ * This hook is invoked at the head of lo_write().
|
|
+ */
|
|
+void
|
|
+pgaceLargeObjectWrite(LargeObjectDesc *lodesc, int length)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectWrite(lodesc, length);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectTruncate
|
|
+ *
|
|
+ * This hook is invoked at the head of lo_truncate().
|
|
+ */
|
|
+void
|
|
+pgaceLargeObjectTruncate(LargeObjectDesc *lodesc, int offset)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectTruncate(lodesc, offset);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectImport
|
|
+ *
|
|
+ * This hook is invoked just before importing the given file.
|
|
+ */
|
|
+void
|
|
+pgaceLargeObjectImport(Oid loid, int fdesc, const char *filename)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectImport(loid, fdesc, filename);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectExport
|
|
+ *
|
|
+ * This hook is invoked just before exporting the given large object.
|
|
+ */
|
|
+void
|
|
+pgaceLargeObjectExport(Oid loid, int fdesc, const char *filename)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectExport(loid, fdesc, filename);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectGetSecurity
|
|
+ *
|
|
+ * This hook is invoked when user requires to run lo_get_security()
|
|
+ * Note that PGACE assumes the security attribute of first page frame
|
|
+ * of large object represents its security attribute.
|
|
+ */
|
|
+void
|
|
+pgaceLargeObjectGetSecurity(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ {
|
|
+ sepgsqlLargeObjectGetSecurity(rel, tuple);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("no enhanced security feature is available.")));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectSetSecurity
|
|
+ *
|
|
+ * This hook is invoked when user requires to run lo_set_security(),
|
|
+ * for each tuple within a given large object, which have unchecked
|
|
+ * security attribute. In other word, PGACE does not require the guest
|
|
+ * to check permission toward same security attribute twice, or more.
|
|
+ */
|
|
+void
|
|
+pgaceLargeObjectSetSecurity(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ {
|
|
+ sepgsqlLargeObjectSetSecurity(rel, newtup, oldtup);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_PGACE_ERROR),
|
|
+ errmsg("no enhanced security feature is available.")));
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Security Label hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceTupleDescHasSecurity
|
|
+ *
|
|
+ * This hook enables to control the value in TupleDesc->tdhasseclabel.
|
|
+ * If it returns true, sizeof(Oid) bytes are allocated at the header
|
|
+ * of HeapTupleHeader structure.
|
|
+ *
|
|
+ * The 'rel' argument can be NULL, when we make a decision for newly
|
|
+ * created relation via SELECT INTO/CREATE TABLE AS. In this case,
|
|
+ * unparsed relation options are delivered.
|
|
+ */
|
|
+bool
|
|
+pgaceTupleDescHasSecLabel(Relation rel, List *relopts)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlTupleDescHasSecLabel(rel, relopts);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceTranslateSecurityLabelIn
|
|
+ *
|
|
+ * This hook enables the guest to translate a text representation
|
|
+ * of a given security attribute in external format into internal
|
|
+ * raw-format. It is invoked when user specifies security attribute
|
|
+ * explicitly in INSERT/UPDATE statement, to translate it into
|
|
+ * raw-internal format.
|
|
+ *
|
|
+ * It has to return a palloc()'ed Cstring, as a raw-internal format.
|
|
+ *
|
|
+ * In SE-PostgreSQL it supports translation in MLS/MCS labels like:
|
|
+ * "system_u:object_r:sepgsql_table_t:SystemHigh"
|
|
+ * <--> "system_u:object_r:sepgsql_table_t:s0:c0.c1023"
|
|
+ */
|
|
+char *
|
|
+pgaceTranslateSecurityLabelIn(char *seclabel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlTranslateSecurityLabelIn(seclabel);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return seclabel;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceTranslateSecurityLabelOut
|
|
+ *
|
|
+ * This hook enables the guest to translate a text representation
|
|
+ * of a given security attribute in internal format into cosmetic
|
|
+ * external format.
|
|
+ */
|
|
+char *
|
|
+pgaceTranslateSecurityLabelOut(char *seclabel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlTranslateSecurityLabelOut(seclabel);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return seclabel;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceValidateSecurityLabel
|
|
+ *
|
|
+ * This hook enables the guest to validate the given security attribute
|
|
+ * in raw-internal format.
|
|
+ */
|
|
+bool
|
|
+pgaceCheckValidSecurityLabel(char *seclabel)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlCheckValidSecurityLabel(seclabel);
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceUnlabeledSecurityLabel
|
|
+ *
|
|
+ * This hooks allows the guest to provide an alternative security
|
|
+ * attribute, when no valid text representation found on pg_security.
|
|
+ * The hooks has to return an alternative attribute palloc()'ed.
|
|
+ */
|
|
+char *
|
|
+pgaceUnlabeledSecurityLabel(void)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlUnlabeledSecurityLabel();
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceSecurityLabelOfLabel
|
|
+ *
|
|
+ * This hook has to return the security attribute of a newly inserted
|
|
+ * tuple withing pg_security system catalog. Note that we need a special
|
|
+ * handling in the case of pg_security. If a new tuple requires a quite
|
|
+ * new security attribute which is not on pg_security, its insertion
|
|
+ * invokes one more insertion into pg_security. In the result, it makes
|
|
+ * infinite function invocation.
|
|
+ * This hook is used to avoid such a situation. The guest has to return
|
|
+ * a text represented security attribute.
|
|
+ */
|
|
+char *
|
|
+pgaceSecurityLabelOfLabel(void)
|
|
+{
|
|
+ switch (pgace_feature)
|
|
+ {
|
|
+#ifdef HAVE_SELINUX
|
|
+ case PGACE_FEATURE_SELINUX:
|
|
+ if (sepgsqlIsEnabled())
|
|
+ return sepgsqlSecurityLabelOfLabel();
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security/sepgsql/avc.c
|
|
--- base/src/backend/security/sepgsql/avc.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/sepgsql/avc.c 2009-01-22 14:10:59.000000000 +0900
|
|
@@ -0,0 +1,1202 @@
|
|
+
|
|
+/*
|
|
+ * src/backend/security/sepgsql/avc.c
|
|
+ * SE-PostgreSQL userspace access vector cache
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ *
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/hash.h"
|
|
+#include "libpq/pqsignal.h"
|
|
+#include "postmaster/postmaster.h"
|
|
+#include "security/pgace.h"
|
|
+#include "storage/ipc.h"
|
|
+#include "storage/lwlock.h"
|
|
+#include "utils/memutils.h"
|
|
+#include "utils/syscache.h"
|
|
+#include <linux/netlink.h>
|
|
+#include <linux/selinux_netlink.h>
|
|
+#include <signal.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+/*
|
|
+ * uAVC: userspace Access Vector Cache
|
|
+ *
|
|
+ * SE-PostgreSQL makes inqueries for SELinux to check whether the security
|
|
+ * policy allows the required action, or not. However, it need to invoke
|
|
+ * system call because SELinux is a kernel feature and it hold its security
|
|
+ * policy in the kernel memory.
|
|
+ *
|
|
+ * uAVC enables to reduce the number of kernel invocation, with caching
|
|
+ * the result of inquiries. When we have to make a decision based on the
|
|
+ * security policy of SELinux, it tries to find up an appropriate cache
|
|
+ * entry on the uAVC. If exist, we don't need to invoke a system call
|
|
+ * and can reduce unnecessary overhead.
|
|
+ *
|
|
+ * If not exist, SE-PostgreSQL makes a new cache entry based on the
|
|
+ * result of inquiries, and chains it on uAVC to prepare the following
|
|
+ * decision makings.
|
|
+ *
|
|
+ * uAVC has a version number to check whether it is now valid, or not.
|
|
+ * Not need to say, uAVC cache entry has to be invalid just after
|
|
+ * policy reloaded or state change.
|
|
+ * If it is not match the latest one, updated by the policy state
|
|
+ * monitoring process, uAVC has to be reseted.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Dynamic object class/access vector mapping
|
|
+ *
|
|
+ * SELinux exports the list of object classes (it means kind of object, like
|
|
+ * file or table) and access vectors (it means permission set, like read,
|
|
+ * select, ...) under /selinux/class.
|
|
+ * It enables to provide userspace object managers a interface to get what
|
|
+ * codes should be used to ask SELinux.
|
|
+ *
|
|
+ * libselinux provides an API to translate a string expression and a code
|
|
+ * used by the loaded security policy. These correspondences are not assured
|
|
+ * over the bound of policy loading, so we have to reload the mapping after
|
|
+ * in-kernel policy is reloaded, or its state is changed.
|
|
+ */
|
|
+static struct
|
|
+{
|
|
+ struct
|
|
+ {
|
|
+ const char *name;
|
|
+ security_class_t internal;
|
|
+ } tclass;
|
|
+ struct
|
|
+ {
|
|
+ char *name;
|
|
+ access_vector_t internal;
|
|
+ } av_perms[sizeof(access_vector_t) * 8];
|
|
+} selinux_catalog[] = {
|
|
+ {
|
|
+ { "db_database", SECCLASS_DB_DATABASE},
|
|
+ {
|
|
+ { "create", DB_DATABASE__CREATE },
|
|
+ { "drop", DB_DATABASE__DROP },
|
|
+ { "getattr", DB_DATABASE__GETATTR },
|
|
+ { "setattr", DB_DATABASE__SETATTR },
|
|
+ { "relabelfrom", DB_DATABASE__RELABELFROM },
|
|
+ { "relabelto", DB_DATABASE__RELABELTO },
|
|
+ { "access", DB_DATABASE__ACCESS },
|
|
+ { "install_module", DB_DATABASE__INSTALL_MODULE },
|
|
+ { "load_module", DB_DATABASE__LOAD_MODULE },
|
|
+ { "get_param", DB_DATABASE__GET_PARAM },
|
|
+ { "set_param", DB_DATABASE__SET_PARAM },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ { "db_table", SECCLASS_DB_TABLE},
|
|
+ {
|
|
+ { "create", DB_TABLE__CREATE },
|
|
+ { "drop", DB_TABLE__DROP },
|
|
+ { "getattr", DB_TABLE__GETATTR },
|
|
+ { "setattr", DB_TABLE__SETATTR },
|
|
+ { "relabelfrom", DB_TABLE__RELABELFROM },
|
|
+ { "relabelto", DB_TABLE__RELABELTO },
|
|
+ { "use", DB_TABLE__USE },
|
|
+ { "select", DB_TABLE__SELECT },
|
|
+ { "update", DB_TABLE__UPDATE },
|
|
+ { "insert", DB_TABLE__INSERT },
|
|
+ { "delete", DB_TABLE__DELETE },
|
|
+ { "lock", DB_TABLE__LOCK },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ { "db_procedure", SECCLASS_DB_PROCEDURE},
|
|
+ {
|
|
+ { "create", DB_PROCEDURE__CREATE },
|
|
+ { "drop", DB_PROCEDURE__DROP },
|
|
+ { "getattr", DB_PROCEDURE__GETATTR },
|
|
+ { "setattr", DB_PROCEDURE__SETATTR },
|
|
+ { "relabelfrom", DB_PROCEDURE__RELABELFROM },
|
|
+ { "relabelto", DB_PROCEDURE__RELABELTO },
|
|
+ { "execute", DB_PROCEDURE__EXECUTE },
|
|
+ { "entrypoint", DB_PROCEDURE__ENTRYPOINT },
|
|
+ { "install", DB_PROCEDURE__INSTALL },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ { "db_column", SECCLASS_DB_COLUMN},
|
|
+ {
|
|
+ { "create", DB_COLUMN__CREATE },
|
|
+ { "drop", DB_COLUMN__DROP },
|
|
+ { "getattr", DB_COLUMN__GETATTR },
|
|
+ { "setattr", DB_COLUMN__SETATTR },
|
|
+ { "relabelfrom", DB_COLUMN__RELABELFROM },
|
|
+ { "relabelto", DB_COLUMN__RELABELTO },
|
|
+ { "use", DB_COLUMN__USE },
|
|
+ { "select", DB_COLUMN__SELECT },
|
|
+ { "update", DB_COLUMN__UPDATE },
|
|
+ { "insert", DB_COLUMN__INSERT },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ { "db_tuple", SECCLASS_DB_TUPLE },
|
|
+ {
|
|
+ { "relabelfrom", DB_TUPLE__RELABELFROM},
|
|
+ { "relabelto", DB_TUPLE__RELABELTO},
|
|
+ { "use", DB_TUPLE__USE},
|
|
+ { "select", DB_TUPLE__SELECT},
|
|
+ { "update", DB_TUPLE__UPDATE},
|
|
+ { "insert", DB_TUPLE__INSERT},
|
|
+ { "delete", DB_TUPLE__DELETE},
|
|
+ { NULL, 0UL},
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ { "db_blob", SECCLASS_DB_BLOB },
|
|
+ {
|
|
+ { "create", DB_BLOB__CREATE},
|
|
+ { "drop", DB_BLOB__DROP},
|
|
+ { "getattr", DB_BLOB__GETATTR},
|
|
+ { "setattr", DB_BLOB__SETATTR},
|
|
+ { "relabelfrom", DB_BLOB__RELABELFROM},
|
|
+ { "relabelto", DB_BLOB__RELABELTO},
|
|
+ { "read", DB_BLOB__READ},
|
|
+ { "write", DB_BLOB__WRITE},
|
|
+ { "import", DB_BLOB__IMPORT},
|
|
+ { "export", DB_BLOB__EXPORT},
|
|
+ { NULL, 0UL},
|
|
+ }
|
|
+ },
|
|
+};
|
|
+
|
|
+static MemoryContext AvcMemCtx;
|
|
+
|
|
+#define AVC_HASH_NUM_SLOTS 256
|
|
+#define AVC_HASH_NUM_NODES 600
|
|
+
|
|
+static sig_atomic_t avc_version;
|
|
+static bool avc_enforcing;
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ uint32 hash_key;
|
|
+
|
|
+ security_class_t tclass;
|
|
+ Oid tsid; /* target security context */
|
|
+
|
|
+ security_context_t ncontext; /* newcontext */
|
|
+ Oid nsid; /* newly created security context */
|
|
+
|
|
+ access_vector_t allowed;
|
|
+ access_vector_t decided;
|
|
+ access_vector_t auditallow;
|
|
+ access_vector_t auditdeny;
|
|
+
|
|
+ bool hot_cache;
|
|
+} avc_datum;
|
|
+
|
|
+typedef struct avc_page
|
|
+{
|
|
+ struct avc_page *prev;
|
|
+ struct avc_page *next;
|
|
+
|
|
+ security_context_t scontext;
|
|
+
|
|
+ List *slot[AVC_HASH_NUM_SLOTS];
|
|
+
|
|
+ uint32 lru_hint;
|
|
+} avc_page;
|
|
+
|
|
+static avc_page *current_avc_page = NULL;
|
|
+static uint32 avc_datum_count = 0;
|
|
+
|
|
+/*
|
|
+ * selinux_state
|
|
+ *
|
|
+ * This structure shows the global state of SELinux and its security
|
|
+ * policy, and it is assigned on shared memory region.
|
|
+ *
|
|
+ * The most significant variable is selinux_state->version.
|
|
+ * Any instance can refer this variable to confirm current sequence
|
|
+ * number of policy state, without locking.
|
|
+ *
|
|
+ * The only process able to update this variable is policy state
|
|
+ * monitoring process forked by postmaster. It can receive notifications
|
|
+ * from the kernel via netlink socket, and it update selinux_state->version
|
|
+ * to encourage any instance to reflush its uAVC.
|
|
+ *
|
|
+ * When we read rest of variable, we have to hold SepgsqlAvcLock LWlock
|
|
+ * as a reader. enforceing shows the current SELinux working mode.
|
|
+ * catalog shows the mapping set of security classes and access vectors.
|
|
+ */
|
|
+struct
|
|
+{
|
|
+ /*
|
|
+ * only state monitoring process can update version.
|
|
+ * any other process can read it without locks.
|
|
+ */
|
|
+ volatile sig_atomic_t version;
|
|
+
|
|
+ bool enforcing;
|
|
+
|
|
+ struct
|
|
+ {
|
|
+ struct
|
|
+ {
|
|
+ security_class_t internal;
|
|
+ security_class_t external;
|
|
+ } tclass;
|
|
+ struct
|
|
+ {
|
|
+ access_vector_t internal;
|
|
+ access_vector_t external;
|
|
+ } av_perms[sizeof(access_vector_t) * 8];
|
|
+ } catalog[lengthof(selinux_catalog)];
|
|
+} *selinux_state = NULL;
|
|
+
|
|
+Size
|
|
+sepgsqlShmemSize(void)
|
|
+{
|
|
+ return sizeof(*selinux_state);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * load_class_av_mapping
|
|
+ *
|
|
+ * This function rebuild the mapping set of security classes and access
|
|
+ * vectors on selinux_state. It has to be invoked by the policy state
|
|
+ * monitoring process with SepgsqlAvcLock in LW_EXCLUSIVE.
|
|
+ */
|
|
+static void
|
|
+load_class_av_mapping(void)
|
|
+{
|
|
+ int i, j;
|
|
+
|
|
+ memset(selinux_state->catalog, 0, sizeof(selinux_state->catalog));
|
|
+
|
|
+ for (i = 0; i < lengthof(selinux_catalog); i++)
|
|
+ {
|
|
+ selinux_state->catalog[i].tclass.internal
|
|
+ = selinux_catalog[i].tclass.internal;
|
|
+ selinux_state->catalog[i].tclass.external
|
|
+ = string_to_security_class(selinux_catalog[i].tclass.name);
|
|
+
|
|
+ for (j = 0; selinux_catalog[i].av_perms[j].name; j++)
|
|
+ {
|
|
+ selinux_state->catalog[i].av_perms[j].internal
|
|
+ = selinux_catalog[i].av_perms[j].internal;
|
|
+ selinux_state->catalog[i].av_perms[j].external
|
|
+ = string_to_av_perm(selinux_state->catalog[i].tclass.external,
|
|
+ selinux_catalog[i].av_perms[j].name);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * trans_to_external_tclass
|
|
+ * translates internal object class number into external one
|
|
+ * needed to communicate with in-kernel SELinux.
|
|
+ */
|
|
+static security_class_t
|
|
+trans_to_external_tclass(security_class_t i_tclass)
|
|
+{
|
|
+ /* have to hold SepgsqlAvcLock with LW_SHARED */
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < lengthof(selinux_catalog); i++)
|
|
+ {
|
|
+ if (selinux_state->catalog[i].tclass.internal == i_tclass)
|
|
+ return selinux_state->catalog[i].tclass.external;
|
|
+ }
|
|
+ return i_tclass; /* use it as is for kernel classes */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * trans_to_internal_perms
|
|
+ * translates external permission bits into internal ones
|
|
+ * needed to understand the answer from in-kernel SELinux.
|
|
+ * If in-kernel SELinux doesn't define required permissions,
|
|
+ * it sets/clears undefined bits based on caller's preference.
|
|
+ * It enables SE-PostgreSQL to work on legacy security policy.
|
|
+ */
|
|
+static access_vector_t
|
|
+trans_to_internal_perms(security_class_t e_tclass, access_vector_t e_perms,
|
|
+ bool set_if_undefined)
|
|
+{
|
|
+ /* have to hold SepgsqlAvcLock with LW_SHARED */
|
|
+ access_vector_t i_perms = 0UL;
|
|
+ access_vector_t undef_mask = 0UL;
|
|
+ int i, j;
|
|
+
|
|
+ for (i = 0; i < lengthof(selinux_catalog); i++)
|
|
+ {
|
|
+ if (selinux_state->catalog[i].tclass.external != e_tclass)
|
|
+ continue;
|
|
+
|
|
+ for (j = 0; j < sizeof(access_vector_t) * 8; j++)
|
|
+ {
|
|
+ if (selinux_state->catalog[i].av_perms[j].external == 0)
|
|
+ undef_mask |= (1UL << j);
|
|
+ else if (selinux_state->catalog[i].av_perms[j].external & e_perms)
|
|
+ i_perms |= selinux_state->catalog[i].av_perms[j].internal;
|
|
+ }
|
|
+
|
|
+ if (set_if_undefined)
|
|
+ i_perms |= undef_mask;
|
|
+ else
|
|
+ i_perms &= ~undef_mask;
|
|
+
|
|
+ return i_perms;
|
|
+ }
|
|
+ return e_perms; /* use it as is for kernel classes */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsql_class_to_string
|
|
+ * sepgsql_av_perm_to_string
|
|
+ * returns string representation of given object class and permission.
|
|
+ * Please note that given code have internal ones, so we cannot use
|
|
+ * libselinux's facility, because it assumes 'external code'.
|
|
+ * (Kernel object classes are ABI, so these are stable.)
|
|
+ */
|
|
+static const char *
|
|
+sepgsql_class_to_string(security_class_t tclass)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < lengthof(selinux_catalog); i++)
|
|
+ {
|
|
+ if (selinux_catalog[i].tclass.internal == tclass)
|
|
+ return selinux_catalog[i].tclass.name;
|
|
+ }
|
|
+ /*
|
|
+ * tclass is stable for kernel object classes.
|
|
+ */
|
|
+ return security_class_to_string(tclass);
|
|
+}
|
|
+
|
|
+static const char *
|
|
+sepgsql_av_perm_to_string(security_class_t tclass, access_vector_t perm)
|
|
+{
|
|
+ int i, j;
|
|
+
|
|
+ for (i = 0; i < lengthof(selinux_catalog); i++)
|
|
+ {
|
|
+ if (selinux_catalog[i].tclass.internal == tclass)
|
|
+ {
|
|
+ char *perm_name;
|
|
+
|
|
+ for (j = 0; (perm_name = selinux_catalog[i].av_perms[j].name); j++)
|
|
+ {
|
|
+ if (selinux_catalog[i].av_perms[j].internal == perm)
|
|
+ return perm_name;
|
|
+ }
|
|
+ return "unknown";
|
|
+ }
|
|
+ }
|
|
+ /*
|
|
+ * tclass/perms are stable for kernel object classes.
|
|
+ */
|
|
+ return security_av_perm_to_string(tclass, perm);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsql_avc_reset
|
|
+ * clears all uAVC entries and update its version.
|
|
+ */
|
|
+static void
|
|
+sepgsql_avc_reset(void)
|
|
+{
|
|
+ MemoryContextReset(AvcMemCtx);
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
|
|
+
|
|
+ avc_version = selinux_state->version;
|
|
+ switch (sepostgresql_mode)
|
|
+ {
|
|
+ case SEPGSQL_MODE_DEFAULT:
|
|
+ avc_enforcing = selinux_state->enforcing;
|
|
+ break;
|
|
+ case SEPGSQL_MODE_PERMISSIVE:
|
|
+ avc_enforcing = false;
|
|
+ break;
|
|
+ case SEPGSQL_MODE_ENFORCING:
|
|
+ avc_enforcing = false;
|
|
+ break;
|
|
+ default:
|
|
+ elog(FATAL, "SELinux: undefined state in SE-PostgreSQL");
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ current_avc_page = NULL;
|
|
+
|
|
+ avc_datum_count = 0;
|
|
+
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ sepgsqlAvcSwitchClientContext(sepgsqlGetClientContext());
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsql_avc_reclaim
|
|
+ * reclaims recently unused uAVC entries, when the number of
|
|
+ * caches overs AVC_HASH_NUM_NODES.
|
|
+ */
|
|
+static void
|
|
+sepgsql_avc_reclaim(void)
|
|
+{
|
|
+ ListCell *l;
|
|
+ avc_page *avp;
|
|
+ avc_datum *cache;
|
|
+ int loop;
|
|
+
|
|
+ Assert(current_avc_page != NULL);
|
|
+
|
|
+ for (avp = current_avc_page->next; true; avp = avp->next)
|
|
+ {
|
|
+ for (loop = 0; loop < AVC_HASH_NUM_SLOTS; loop++)
|
|
+ {
|
|
+ if (avc_datum_count < AVC_HASH_NUM_NODES)
|
|
+ return;
|
|
+
|
|
+ avp->lru_hint = (avp->lru_hint + 1) % AVC_HASH_NUM_SLOTS;
|
|
+ foreach (l, avp->slot[avp->lru_hint])
|
|
+ {
|
|
+ cache = lfirst(l);
|
|
+
|
|
+ if (cache->hot_cache)
|
|
+ {
|
|
+ cache->hot_cache = false;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ list_delete_ptr(avp->slot[avp->lru_hint], cache);
|
|
+ pfree(cache);
|
|
+ avc_datum_count--;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * avc_audit_common
|
|
+ * generates an audit message on the give string buffer based on
|
|
+ * the given av_decision which means the resutl of permission checks.
|
|
+ */
|
|
+static bool
|
|
+avc_audit_common(char *buffer, uint32 buflen,
|
|
+ avc_datum *cache, access_vector_t perms,
|
|
+ const char *scontext, const char *tcontext, const char *objname)
|
|
+{
|
|
+ access_vector_t denied, audited, mask;
|
|
+ security_context_t svcon, tvcon;
|
|
+ uint32 ofs = 0;
|
|
+
|
|
+ denied = perms & ~cache->allowed;
|
|
+ audited = denied ? (denied & cache->auditdeny) : (perms & cache->auditallow);
|
|
+
|
|
+ if (audited == 0)
|
|
+ return false;
|
|
+
|
|
+ ofs += snprintf(buffer + ofs, buflen - ofs, "%s {",
|
|
+ denied ? "denied" : "granted");
|
|
+ for (mask = 1; mask != 0; mask <<= 1)
|
|
+ {
|
|
+ if ((audited & mask) != 0)
|
|
+ ofs += snprintf(buffer + ofs, buflen - ofs, " %s",
|
|
+ sepgsql_av_perm_to_string(cache->tclass, mask));
|
|
+ }
|
|
+ ofs += snprintf(buffer + ofs, buflen - ofs, " } ");
|
|
+
|
|
+ if (!scontext)
|
|
+ svcon = sepgsqlTranslateSecurityLabelOut(current_avc_page->scontext);
|
|
+ else
|
|
+ svcon = sepgsqlTranslateSecurityLabelOut(scontext);
|
|
+
|
|
+ if (!tcontext)
|
|
+ tvcon = pgaceSidToSecurityLabel(cache->tsid);
|
|
+ else
|
|
+ tvcon = sepgsqlTranslateSecurityLabelOut(tcontext);
|
|
+
|
|
+ ofs += snprintf(buffer + ofs, buflen - ofs,
|
|
+ "scontext=%s tcontext=%s tclass=%s",
|
|
+ svcon, tvcon, sepgsql_class_to_string(cache->tclass));
|
|
+
|
|
+ pfree(svcon);
|
|
+ pfree(tvcon);
|
|
+ if (objname)
|
|
+ ofs += snprintf(buffer + ofs, buflen - ofs, " name=%s", objname);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * avc_permission_common
|
|
+ * makes decision and output audit messages based on given avc_datum.
|
|
+ * If required permissions are not completely allowed, it raises an
|
|
+ * error or returns 'false' when permissive mode.
|
|
+ */
|
|
+static bool
|
|
+avc_permission_common(avc_datum *cache, access_vector_t perms, bool abort,
|
|
+ const char *scontext, const char *tcontext, const char *objname)
|
|
+{
|
|
+ char audit_buffer[2048];
|
|
+ access_vector_t denied;
|
|
+ bool audit;
|
|
+ bool rc = true;
|
|
+
|
|
+ audit = avc_audit_common(audit_buffer, sizeof(audit_buffer),
|
|
+ cache, perms, scontext, tcontext, objname);
|
|
+
|
|
+ denied = perms & ~cache->allowed;
|
|
+ if (!perms || denied)
|
|
+ {
|
|
+ if (avc_enforcing)
|
|
+ rc = false;
|
|
+ else
|
|
+ {
|
|
+ /*
|
|
+ * In permissive mode, once denied permissions are
|
|
+ * allowed to avoid a flood of denied logs.
|
|
+ */
|
|
+ cache->allowed |= perms;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (audit)
|
|
+ {
|
|
+ ereport((!rc && abort) ? ERROR : NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_AUDIT),
|
|
+ errmsg("SELinux: %s", audit_buffer)));
|
|
+ }
|
|
+ else if (!rc && abort)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_AUDIT),
|
|
+ errmsg("SELinux: security policy violation")));
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * avc_make_entry
|
|
+ * makes a query to in-kernel SELinux and an avc_datum object to
|
|
+ * cache the result of SELinux's decision for access rights and
|
|
+ * default security context.
|
|
+ */
|
|
+#define avc_hash_key(tsid,tclass) ((tsid) ^ ((tclass) << 2))
|
|
+
|
|
+static avc_datum *
|
|
+avc_make_entry(Oid tsid, security_class_t tclass)
|
|
+{
|
|
+ security_context_t scontext, tcontext, ncontext;
|
|
+ security_class_t e_tclass;
|
|
+ MemoryContext oldctx = MemoryContextSwitchTo(AvcMemCtx);
|
|
+ struct av_decision avd;
|
|
+ avc_datum *cache;
|
|
+ uint32 hash_key, index;
|
|
+
|
|
+ hash_key = avc_hash_key(tsid, tclass);
|
|
+ index = hash_key % AVC_HASH_NUM_SLOTS;
|
|
+
|
|
+ cache = palloc0(sizeof(avc_datum));
|
|
+ cache->hash_key = hash_key;
|
|
+ cache->tsid = tsid;
|
|
+ cache->tclass = tclass;
|
|
+
|
|
+ scontext = current_avc_page->scontext;
|
|
+ tcontext = pgaceLookupSecurityLabel(tsid);
|
|
+ if (!tcontext || !pgaceCheckValidSecurityLabel(tcontext))
|
|
+ tcontext = pgaceUnlabeledSecurityLabel();
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
|
|
+
|
|
+ e_tclass = trans_to_external_tclass(tclass);
|
|
+
|
|
+ if (security_compute_av_raw(scontext, tcontext, e_tclass, 0, &avd) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not compute av_decision: "
|
|
+ "scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext, sepgsql_class_to_string(tclass))));
|
|
+
|
|
+ cache->allowed = trans_to_internal_perms(e_tclass, avd.allowed, true);
|
|
+ cache->decided = trans_to_internal_perms(e_tclass, avd.decided, false);
|
|
+ cache->auditallow = trans_to_internal_perms(e_tclass, avd.auditallow, false);
|
|
+ cache->auditdeny = trans_to_internal_perms(e_tclass, avd.auditdeny, false);
|
|
+ cache->hot_cache = true;
|
|
+
|
|
+ if (security_compute_create_raw(scontext, tcontext, e_tclass, &ncontext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not compute new context: "
|
|
+ "scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext, sepgsql_class_to_string(tclass))));
|
|
+ pfree(tcontext);
|
|
+
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ cache->ncontext = pstrdup(ncontext);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(ncontext);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ freecon(ncontext);
|
|
+
|
|
+ sepgsql_avc_reclaim();
|
|
+
|
|
+ current_avc_page->slot[index]
|
|
+ = lcons(cache, current_avc_page->slot[index]);
|
|
+
|
|
+ avc_datum_count++;
|
|
+
|
|
+ MemoryContextSwitchTo(oldctx);
|
|
+
|
|
+ return cache;
|
|
+}
|
|
+
|
|
+static avc_datum *avc_lookup(Oid tsid, security_class_t tclass)
|
|
+{
|
|
+ avc_datum *cache = NULL;
|
|
+ uint32 hash_key, index;
|
|
+ ListCell *l;
|
|
+
|
|
+ /*
|
|
+ * check avc invalidation
|
|
+ */
|
|
+ if (avc_version != selinux_state->version)
|
|
+ sepgsql_avc_reset();
|
|
+
|
|
+ /*
|
|
+ * lookup avc entry
|
|
+ */
|
|
+ hash_key = avc_hash_key(tsid, tclass);
|
|
+ index = hash_key % AVC_HASH_NUM_SLOTS;
|
|
+
|
|
+ foreach (l, current_avc_page->slot[index])
|
|
+ {
|
|
+ cache = lfirst(l);
|
|
+ if (cache->hash_key == hash_key
|
|
+ && cache->tclass == tclass
|
|
+ && cache->tsid == tsid)
|
|
+ {
|
|
+ cache->hot_cache = true;
|
|
+ return cache;
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlAvcSwitchClientContext()
|
|
+ * switches current avc_page.
|
|
+ *
|
|
+ * NOTE: In most cases, SE-PostgreSQL checks whether client is allowed
|
|
+ * to do required actions (like SELECT, UPDATE, ...) on the targets.
|
|
+ * Both of client and targets have its security context, and all rules
|
|
+ * are described as relationship between security context of a client,
|
|
+ * a target and kind of actions.
|
|
+ * However, the security context of client is unchanged in SE-PostgreSQL
|
|
+ * (an exception is invocation of trusted procedure), so we can omit
|
|
+ * to compare security context of client with entries of uAVC.
|
|
+ * The avc_page is a set of avc_datum sorted out by the security context
|
|
+ * of client, so we can lookup correct avc_datum on currently focued
|
|
+ * avc_page without comparing the security context of client.
|
|
+ * The reason why we don't not use a unique uAVC is the security context
|
|
+ * of client does not have its security identifier on pg_security, so
|
|
+ * it requires strcmp() for each entries, but it is heavier than integer
|
|
+ * comparisons.
|
|
+ * Thus we have to switch current avc_page, whenever the security context
|
|
+ * of client changes (via trusted procedure). It makes performance well
|
|
+ * in most cases.
|
|
+ */
|
|
+void sepgsqlAvcSwitchClientContext(security_context_t newcontext)
|
|
+{
|
|
+ MemoryContext oldctx;
|
|
+ avc_page *avp;
|
|
+ int i;
|
|
+
|
|
+ if (current_avc_page)
|
|
+ {
|
|
+ avp = current_avc_page;
|
|
+ do {
|
|
+ if (!strcmp(avp->scontext, newcontext))
|
|
+ {
|
|
+ current_avc_page = avp;
|
|
+ return;
|
|
+ }
|
|
+ avp = avp->next;
|
|
+ } while (avp != current_avc_page);
|
|
+ }
|
|
+
|
|
+ /* create a new avc_page */
|
|
+ oldctx = MemoryContextSwitchTo(AvcMemCtx);
|
|
+ avp = palloc0(sizeof(avc_page));
|
|
+ avp->scontext = pstrdup(newcontext);
|
|
+ MemoryContextSwitchTo(oldctx);
|
|
+
|
|
+ for (i=0; i < AVC_HASH_NUM_SLOTS; i++)
|
|
+ avp->slot[i] = NIL;
|
|
+
|
|
+ if (!current_avc_page)
|
|
+ {
|
|
+ avp->next = avp->prev = avp;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ avp->next = current_avc_page;
|
|
+ avp->prev = current_avc_page->prev;
|
|
+ avp->prev->next = avp;
|
|
+ avp->next->prev = avp;
|
|
+ }
|
|
+ current_avc_page = avp;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlClientHasPermission
|
|
+ * checks client's privileges on given objects via uAVC.
|
|
+ * It raised an error, if required actions are violated.
|
|
+ */
|
|
+void
|
|
+sepgsqlClientHasPermission(Oid tsid, security_class_t tclass,
|
|
+ access_vector_t perms,
|
|
+ const char *objname)
|
|
+{
|
|
+ avc_datum *cache = avc_lookup(tsid, tclass);
|
|
+
|
|
+ if (!cache)
|
|
+ cache = avc_make_entry(tsid, tclass);
|
|
+
|
|
+ avc_permission_common(cache, perms, true, NULL, NULL, objname);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlClientHasPermissionNoAbort
|
|
+ * checks client's privileges on given objects via uAVC.
|
|
+ * It returns false, if required actions are violated.
|
|
+ */
|
|
+bool
|
|
+sepgsqlClientHasPermissionNoAbort(Oid tsid, security_class_t tclass,
|
|
+ access_vector_t perms,
|
|
+ const char *objname)
|
|
+{
|
|
+ avc_datum *cache = avc_lookup(tsid, tclass);
|
|
+
|
|
+ if (!cache)
|
|
+ cache = avc_make_entry(tsid, tclass);
|
|
+
|
|
+ return avc_permission_common(cache, perms, false, NULL, NULL, objname);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlClientCreateSid
|
|
+ * returns security identifier of newly created database object.
|
|
+ * Please note that you don't have to invoke this function for
|
|
+ * object classes except for database objects. It have a possibility
|
|
+ * to make an entry on pg_security via pgaceSecurityLabelToSid(),
|
|
+ * but it should be restricted to database object.
|
|
+ */
|
|
+Oid
|
|
+sepgsqlClientCreateSid(Oid tsid, security_class_t tclass)
|
|
+{
|
|
+ avc_datum *cache = avc_lookup(tsid, tclass);
|
|
+
|
|
+ if (!cache || cache->nsid == InvalidOid)
|
|
+ {
|
|
+ if (!cache)
|
|
+ cache = avc_make_entry(tsid, tclass);
|
|
+ cache->nsid = pgaceSecurityLabelToSid(cache->ncontext);
|
|
+ }
|
|
+ return cache->nsid;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlClientCreateContext
|
|
+ * returns security context (string representation) of newly
|
|
+ * created object. It is available for any kind of object
|
|
+ * classes.
|
|
+ */
|
|
+security_context_t
|
|
+sepgsqlClientCreateContext(Oid tsid, security_class_t tclass)
|
|
+{
|
|
+ avc_datum *cache = avc_lookup(tsid, tclass);
|
|
+
|
|
+ if (!cache)
|
|
+ cache = avc_make_entry(tsid, tclass);
|
|
+
|
|
+ return pstrdup(cache->ncontext);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsql_shmem_init
|
|
+ * attaches shared memory segment.
|
|
+ */
|
|
+static void
|
|
+sepgsql_shmem_init(void)
|
|
+{
|
|
+ bool found;
|
|
+
|
|
+ selinux_state = ShmemInitStruct("SELinux policy state",
|
|
+ sepgsqlShmemSize(), &found);
|
|
+ if (!found)
|
|
+ {
|
|
+ int enforcing = security_getenforce();
|
|
+
|
|
+ Assert(enforcing == 0 || enforcing == 1);
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
|
|
+ selinux_state->version = 0;
|
|
+ selinux_state->enforcing = enforcing;
|
|
+ load_class_av_mapping();
|
|
+
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlAvcInit
|
|
+ * initialize local uAVC facility.
|
|
+ */
|
|
+void
|
|
+sepgsqlAvcInit(void)
|
|
+{
|
|
+ /*
|
|
+ * local memory context
|
|
+ */
|
|
+ AvcMemCtx = AllocSetContextCreate(TopMemoryContext,
|
|
+ "SE-PostgreSQL userspace avc",
|
|
+ ALLOCSET_DEFAULT_MINSIZE,
|
|
+ ALLOCSET_DEFAULT_INITSIZE,
|
|
+ ALLOCSET_DEFAULT_MAXSIZE);
|
|
+ sepgsql_shmem_init();
|
|
+
|
|
+ /*
|
|
+ * reset local avc
|
|
+ */
|
|
+ sepgsql_avc_reset();
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlComputePermission
|
|
+ * sepgsqlComputeCreateContext
|
|
+ *
|
|
+ * The following two functions make a query to in-kernel SELinux
|
|
+ * without userspace caches, due to some reasons.
|
|
+ * The uAVC can cover most of cases, but some of corner cases are
|
|
+ * not suitable for uAVC structure, so we need uncached interfaces.
|
|
+ * For example, uAVC is unavailable when we tries to load a shared
|
|
+ * library module, because security context of the library does not
|
|
+ * have its security identifier, so we cannot put it on uAVC.
|
|
+ */
|
|
+bool
|
|
+sepgsqlComputePermission(const security_context_t scontext,
|
|
+ const security_context_t tcontext,
|
|
+ security_class_t tclass,
|
|
+ access_vector_t perms,
|
|
+ const char *objname)
|
|
+{
|
|
+ security_context_t svcon, tvcon;
|
|
+ security_class_t e_tclass;
|
|
+ struct av_decision avd;
|
|
+ avc_datum cache;
|
|
+ bool rc;
|
|
+
|
|
+ svcon = (!security_check_context_raw(scontext)
|
|
+ ? scontext : sepgsqlGetUnlabeledContext());
|
|
+ tvcon = (!security_check_context_raw(tcontext)
|
|
+ ? tcontext : sepgsqlGetUnlabeledContext());
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
|
|
+ e_tclass = trans_to_external_tclass(tclass);
|
|
+
|
|
+ if (security_compute_av_raw(svcon, tvcon, e_tclass, 0, &avd) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not compute an av_decision"
|
|
+ " scontext=%s tcontext=%s tclass=%s",
|
|
+ svcon, tvcon, security_class_to_string(e_tclass))));
|
|
+
|
|
+ cache.tclass = tclass;
|
|
+ cache.allowed = trans_to_internal_perms(e_tclass, avd.allowed, true);
|
|
+ cache.decided = trans_to_internal_perms(e_tclass, avd.decided, false);
|
|
+ cache.auditallow = trans_to_internal_perms(e_tclass, avd.auditallow, false);
|
|
+ cache.auditdeny = trans_to_internal_perms(e_tclass, avd.auditdeny, false);
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ rc = avc_permission_common(&cache, perms, true, svcon, tvcon, objname);
|
|
+
|
|
+ if (svcon != scontext)
|
|
+ pfree(svcon);
|
|
+ if (tvcon != tcontext)
|
|
+ pfree(tvcon);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+security_context_t
|
|
+sepgsqlComputeCreateContext(const security_context_t scontext,
|
|
+ const security_context_t tcontext,
|
|
+ security_class_t tclass)
|
|
+{
|
|
+ security_context_t svcon, tvcon, nwcon, copy;
|
|
+ security_class_t e_tclass;
|
|
+
|
|
+ svcon = (!security_check_context_raw(scontext)
|
|
+ ? scontext : sepgsqlGetUnlabeledContext());
|
|
+ tvcon = (!security_check_context_raw(tcontext)
|
|
+ ? tcontext : sepgsqlGetUnlabeledContext());
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
|
|
+ e_tclass = trans_to_external_tclass(tclass);
|
|
+
|
|
+ if (security_compute_create_raw(svcon, tvcon, e_tclass, &nwcon) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not compute a default context"
|
|
+ " scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext, security_class_to_string(e_tclass))));
|
|
+
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ if (svcon != scontext)
|
|
+ pfree(svcon);
|
|
+ if (tvcon != tcontext)
|
|
+ pfree(tvcon);
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ copy = pstrdup(nwcon);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(nwcon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ freecon(nwcon);
|
|
+
|
|
+ return copy;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * SELinux state monitoring process
|
|
+ *
|
|
+ * This process is forked from postmaster to monitor the state of SELinux.
|
|
+ * SELinux can make a notifier message to userspace object manager via
|
|
+ * netlink socket. When it receives the message, it updates selinux_state
|
|
+ * structure assigned on shared memory region to make any instance reset
|
|
+ * its AVC soon.
|
|
+ */
|
|
+
|
|
+static bool sepgsqlStateMonitorAlive = true;
|
|
+
|
|
+static void
|
|
+sepgsqlStateMonitorSIGHUP(SIGNAL_ARGS)
|
|
+{
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_INFO),
|
|
+ errmsg("SELinux: invalidate userspace avc")));
|
|
+ selinux_state->version = selinux_state->version + 1;
|
|
+}
|
|
+
|
|
+static int
|
|
+sepgsqlStateMonitorMain()
|
|
+{
|
|
+ char buffer[2048];
|
|
+ struct sockaddr_nl addr;
|
|
+ socklen_t addrlen;
|
|
+ struct nlmsghdr *nlh;
|
|
+ int rc, nl_sockfd;
|
|
+
|
|
+ /*
|
|
+ * map shared memory segment
|
|
+ */
|
|
+ sepgsql_shmem_init();
|
|
+
|
|
+ /*
|
|
+ * setup the signal handler
|
|
+ */
|
|
+ pqinitmask();
|
|
+ pqsignal(SIGHUP, sepgsqlStateMonitorSIGHUP);
|
|
+ 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);
|
|
+
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_INFO),
|
|
+ errmsg("SELinux: policy state monitor process (pid: %u)",
|
|
+ getpid())));
|
|
+ /*
|
|
+ * open netlink socket
|
|
+ */
|
|
+ nl_sockfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_SELINUX);
|
|
+ if (nl_sockfd < 0)
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not open netlink socket")));
|
|
+ return 1;
|
|
+ }
|
|
+ memset(&addr, 0, sizeof(addr));
|
|
+ addr.nl_family = AF_NETLINK;
|
|
+ addr.nl_groups = SELNL_GRP_AVC;
|
|
+ if (bind(nl_sockfd, (struct sockaddr *) &addr, sizeof(addr)))
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not bind netlink socket")));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * waiting loop
|
|
+ */
|
|
+ while (sepgsqlStateMonitorAlive)
|
|
+ {
|
|
+ addrlen = sizeof(addr);
|
|
+ rc = recvfrom(nl_sockfd, buffer, sizeof(buffer), 0,
|
|
+ (struct sockaddr *) &addr, &addrlen);
|
|
+ if (rc < 0)
|
|
+ {
|
|
+ if (errno == EINTR)
|
|
+ continue;
|
|
+
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: error on netlink recvfrom(): %s",
|
|
+ strerror(errno))));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (addrlen != sizeof(addr))
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: netlink address truncated (len=%d)",
|
|
+ addrlen)));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (addr.nl_pid)
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: netlink received spoofed packet from: %u",
|
|
+ addr.nl_pid)));
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (rc == 0)
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: netlink received EOF")));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ nlh = (struct nlmsghdr *) buffer;
|
|
+ if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > (unsigned int) rc)
|
|
+ {
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: netlink incomplete message")));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ switch (nlh->nlmsg_type)
|
|
+ {
|
|
+ case SELNL_MSG_SETENFORCE:
|
|
+ {
|
|
+ struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh);
|
|
+
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_INFO),
|
|
+ errmsg("SELinux: setenforce notifier"
|
|
+ " (enforcing=%d)", msg->val)));
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
|
|
+ load_class_av_mapping();
|
|
+
|
|
+ /*
|
|
+ * userspace avc invalidation
|
|
+ */
|
|
+ selinux_state->version = selinux_state->version + 1;
|
|
+ selinux_state->enforcing = msg->val ? true : false;
|
|
+
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+ break;
|
|
+ }
|
|
+ case SELNL_MSG_POLICYLOAD:
|
|
+ {
|
|
+ struct selnl_msg_policyload *msg = NLMSG_DATA(nlh);
|
|
+
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_INFO),
|
|
+ errmsg("policyload notifier (seqno=%d)",
|
|
+ msg->seqno)));
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
|
|
+ load_class_av_mapping();
|
|
+ /*
|
|
+ * userspace avc invalidation
|
|
+ */
|
|
+ selinux_state->version = selinux_state->version + 1;
|
|
+
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+ break;
|
|
+ }
|
|
+ case NLMSG_ERROR:
|
|
+ {
|
|
+ struct nlmsgerr *err = NLMSG_DATA(nlh);
|
|
+
|
|
+ if (err->error == 0)
|
|
+ break;
|
|
+
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: netlink error: %s",
|
|
+ strerror(-err->error))));
|
|
+ return 1;
|
|
+ }
|
|
+ default:
|
|
+ ereport(NOTICE,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("netlink unknown message type (%d)",
|
|
+ nlh->nlmsg_type)));
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+pid_t
|
|
+sepgsqlStartupWorkerProcess(void)
|
|
+{
|
|
+ pid_t chld;
|
|
+
|
|
+ chld = fork();
|
|
+ if (chld == 0)
|
|
+ {
|
|
+ ClosePostmasterPorts(false);
|
|
+
|
|
+ on_exit_reset();
|
|
+
|
|
+ exit(sepgsqlStateMonitorMain());
|
|
+ }
|
|
+ else if (chld > 0)
|
|
+ return chld;
|
|
+
|
|
+ return (pid_t) 0;
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/security/sepgsql/core.c
|
|
--- base/src/backend/security/sepgsql/core.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/sepgsql/core.c 2009-01-24 22:44:20.000000000 +0900
|
|
@@ -0,0 +1,672 @@
|
|
+
|
|
+/*
|
|
+ * src/backend/security/sepgsqlCore.c
|
|
+ * SE-PostgreSQL core facilities
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ *
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "libpq/libpq.h"
|
|
+#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/syscache.h"
|
|
+#include <selinux/context.h>
|
|
+
|
|
+int sepostgresql_mode;
|
|
+char *sepostgresql_mode_string;
|
|
+
|
|
+static security_context_t serverContext = NULL;
|
|
+static security_context_t clientContext = NULL;
|
|
+static security_context_t unlabeledContext = NULL;
|
|
+
|
|
+const security_context_t
|
|
+sepgsqlGetServerContext(void)
|
|
+{
|
|
+ Assert(serverContext != NULL);
|
|
+ return serverContext;
|
|
+}
|
|
+
|
|
+const security_context_t
|
|
+sepgsqlGetClientContext(void)
|
|
+{
|
|
+ Assert(clientContext != NULL);
|
|
+ return clientContext;
|
|
+}
|
|
+
|
|
+const security_context_t
|
|
+sepgsqlGetDatabaseContext(void)
|
|
+{
|
|
+ security_context_t result;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ {
|
|
+ static security_context_t dbcontext = NULL;
|
|
+
|
|
+ if (!dbcontext)
|
|
+ {
|
|
+ if (security_compute_create_raw(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetClientContext(),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ &dbcontext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not get database context")));
|
|
+ }
|
|
+ result = pstrdup(dbcontext);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for database: %u", MyDatabaseId);
|
|
+
|
|
+ result = pgaceLookupSecurityLabel(HeapTupleGetSecLabel(tuple));
|
|
+ if (!result || !pgaceCheckValidSecurityLabel(result))
|
|
+ result = pgaceUnlabeledSecurityLabel();
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+Oid
|
|
+sepgsqlGetDatabaseSecurityId(void)
|
|
+{
|
|
+ Oid sid;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ {
|
|
+ security_context_t dcontext
|
|
+ = sepgsqlGetDatabaseContext();
|
|
+
|
|
+ sid = pgaceSecurityLabelToSid(dcontext);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for database: %u", MyDatabaseId);
|
|
+
|
|
+ sid = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ return sid;
|
|
+}
|
|
+
|
|
+const security_context_t
|
|
+sepgsqlGetUnlabeledContext(void)
|
|
+{
|
|
+ if (unlabeledContext)
|
|
+ return unlabeledContext;
|
|
+
|
|
+ if (security_get_initial_context_raw("unlabeled", &unlabeledContext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not get unlabeled context")));
|
|
+
|
|
+ return unlabeledContext;
|
|
+}
|
|
+
|
|
+const security_context_t
|
|
+sepgsqlSwitchClientContext(security_context_t new_context)
|
|
+{
|
|
+ security_context_t original_context = clientContext;
|
|
+
|
|
+ clientContext = new_context;
|
|
+
|
|
+ sepgsqlAvcSwitchClientContext(new_context);
|
|
+
|
|
+ return original_context;
|
|
+}
|
|
+
|
|
+static void
|
|
+initContexts(void)
|
|
+{
|
|
+ /*
|
|
+ * server context
|
|
+ */
|
|
+ if (getcon_raw(&serverContext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not get server process context")));
|
|
+
|
|
+ /*
|
|
+ * client context
|
|
+ */
|
|
+ if (!MyProcPort)
|
|
+ {
|
|
+ /*
|
|
+ * When the proces is not invoked as a backend of clietnt,
|
|
+ * it works as a server process and as a client process
|
|
+ * in same time.
|
|
+ */
|
|
+ clientContext = serverContext;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (getpeercon_raw(MyProcPort->sock, &clientContext) < 0)
|
|
+ {
|
|
+ /*
|
|
+ * fallbacked security context
|
|
+ *
|
|
+ * When getpeercon() API does not obtain the context of
|
|
+ * peer process, SEPGSQL_FALLBACK_CONTEXT environment
|
|
+ * variable is used as an alternative security context
|
|
+ * of the peer.
|
|
+ *
|
|
+ * getpeercon() needs the following condition to fail:
|
|
+ * - Connection come from remote host,
|
|
+ * - and, there is no labeled ipsec configuration between
|
|
+ * localhost and remote host.
|
|
+ * - and, there is no static fallbacked context configuration
|
|
+ * for the remote host.
|
|
+ */
|
|
+ char *fallback = getenv("SEPGSQL_FALLBACK_CONTEXT");
|
|
+
|
|
+ if (!fallback)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg
|
|
+ ("SELinux: could not get client process context")));
|
|
+
|
|
+ if (security_check_context(fallback) < 0
|
|
+ || selinux_trans_to_raw_context(fallback, &clientContext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: %s is not a valid context",
|
|
+ fallback)));
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlInitialize
|
|
+ *
|
|
+ * It initializes SE-PostgreSQL itself including assignment of shared
|
|
+ * memory segment, reset of AVC, obtaining the client/server security
|
|
+ * context and checks whether the client can access the required database,
|
|
+ * or not.
|
|
+ */
|
|
+void
|
|
+sepgsqlInitialize(bool bootstrap)
|
|
+{
|
|
+ char *dbname;
|
|
+
|
|
+ initContexts();
|
|
+
|
|
+ sepgsqlAvcInit();
|
|
+
|
|
+ /*
|
|
+ * check db_database:{ access }
|
|
+ */
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ dbname = "template1";
|
|
+ else
|
|
+ {
|
|
+ Form_pg_database dbForm;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId), 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for database %u",
|
|
+ MyDatabaseId);
|
|
+ dbForm = (Form_pg_database) GETSTRUCT(tuple);
|
|
+
|
|
+ dbname = pstrdup(NameStr(dbForm->datname));
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ sepgsqlComputePermission(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetDatabaseContext(),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__ACCESS,
|
|
+ dbname);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlIsEnabled
|
|
+ *
|
|
+ * This function returns the state of SE-PostgreSQL when PGACE hooks
|
|
+ * are invoked, to prevent to call sepgsqlXXXX() functions when
|
|
+ * SE-PostgreSQL is disabled.
|
|
+ *
|
|
+ * We can config the state of SE-PostgreSQL in $PGDATA/postgresql.conf.
|
|
+ * The GUC option "sepostgresql" can have the following four parameter.
|
|
+ *
|
|
+ * - default : It always follows the in-kernel SELinux state. When it
|
|
+ * works in Enforcing mode, SE-PostgreSQL also works in
|
|
+ * Enforcing mode. Changes of in-kernel state are delivered
|
|
+ * to userspace SE-PostgreSQL soon, and SELinux state
|
|
+ * monitoring process updates it rapidly.
|
|
+ * - enforcing : It always works in Enforcing mode. In-kernel SELinux
|
|
+ * has to be enabled.
|
|
+ * - permissive : It always works in Permissive mode. In-kernel SELinux
|
|
+ * has to be enabled.
|
|
+ * - disabled : It disables SE-PostgreSQL feature. It works as if
|
|
+ * original PostgreSQL
|
|
+ */
|
|
+const char *sepgsqlAssignModeString(const char *value, bool doit, GucSource source)
|
|
+{
|
|
+ SepgsqlModeType config_mode = SEPGSQL_MODE_DEFAULT;
|
|
+
|
|
+ if (strcmp(value, "default") == 0)
|
|
+ config_mode = SEPGSQL_MODE_DEFAULT;
|
|
+ else if (strcmp(value, "enforcing") == 0)
|
|
+ config_mode = SEPGSQL_MODE_ENFORCING;
|
|
+ else if (strcmp(value, "permissive") == 0)
|
|
+ config_mode = SEPGSQL_MODE_PERMISSIVE;
|
|
+ else if (strcmp(value, "disabled") == 0)
|
|
+ config_mode = SEPGSQL_MODE_DISABLED;
|
|
+ else
|
|
+ ereport(GUC_complaint_elevel(source),
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ "SELinux: unexpected mode: %s", value));
|
|
+ if (doit)
|
|
+ sepostgresql_mode = config_mode;
|
|
+
|
|
+ return value;
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlIsEnabled(void)
|
|
+{
|
|
+ static int enabled = -1;
|
|
+
|
|
+ if (enabled < 0)
|
|
+ {
|
|
+ if (sepostgresql_mode == SEPGSQL_MODE_DISABLED)
|
|
+ enabled = 0;
|
|
+ else
|
|
+ {
|
|
+ enabled = is_selinux_enabled();
|
|
+ if (enabled == 0 /* in-kernel SELinux is disabled */
|
|
+ && sepostgresql_mode != SEPGSQL_MODE_DEFAULT)
|
|
+ {
|
|
+ ereport(FATAL,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: disabled in kernel, but sepostgresql = %s",
|
|
+ SEPGSQL_MODE_ENFORCING ? "enforcing" : "permissive")));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return enabled > 0 ? true : false;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsql_getcon(void)
|
|
+ *
|
|
+ * It returns security context of client
|
|
+ */
|
|
+Datum
|
|
+sepgsql_getcon(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ security_context_t context;
|
|
+ Datum labelTxt;
|
|
+
|
|
+ if (pgace_feature != PGACE_FEATURE_SELINUX || !sepgsqlIsEnabled())
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: disabled now")));
|
|
+
|
|
+ if (selinux_raw_to_trans_context(clientContext, &context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not translate mls label")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ labelTxt = CStringGetTextDatum(context);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(context);
|
|
+
|
|
+ PG_RETURN_DATUM(labelTxt);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsql_getcon(void)
|
|
+ *
|
|
+ * It returns security context of server process
|
|
+ */
|
|
+Datum
|
|
+sepgsql_getservcon(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ security_context_t context;
|
|
+ Datum labelTxt;
|
|
+
|
|
+ if (pgace_feature != PGACE_FEATURE_SELINUX || !sepgsqlIsEnabled())
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: disabled now")));
|
|
+
|
|
+ if (selinux_raw_to_trans_context(serverContext, &context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not translate mls label")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ labelTxt = CStringGetTextDatum(context);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(context);
|
|
+
|
|
+ PG_RETURN_DATUM(labelTxt);
|
|
+}
|
|
+
|
|
+static void
|
|
+parse_to_context(security_context_t context,
|
|
+ char **user, char **role, char **type, char **range)
|
|
+{
|
|
+ security_context_t raw_context;
|
|
+
|
|
+ if (pgace_feature != PGACE_FEATURE_SELINUX || !sepgsqlIsEnabled())
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: disabled now")));
|
|
+
|
|
+ if (selinux_trans_to_raw_context(context, &raw_context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not translate mls label")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ char *tmp;
|
|
+
|
|
+ tmp = pstrdup(strtok(raw_context, ":"));
|
|
+ if (user)
|
|
+ *user = tmp;
|
|
+ tmp = pstrdup(strtok(NULL, ":"));
|
|
+ if (role)
|
|
+ *role = tmp;
|
|
+ tmp = pstrdup(strtok(NULL, ":"));
|
|
+ if (type)
|
|
+ *type = tmp;
|
|
+ if (is_selinux_mls_enabled())
|
|
+ {
|
|
+ tmp = pstrdup(strtok(NULL, "\0"));
|
|
+ if (range)
|
|
+ *range = tmp;
|
|
+ }
|
|
+ else if (range)
|
|
+ *range = NULL;
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(raw_context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(raw_context);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * text sepgsql_get_user(text)
|
|
+ *
|
|
+ * It picks up the USER field of given security context.
|
|
+ */
|
|
+Datum
|
|
+sepgsql_get_user(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *user;
|
|
+
|
|
+ parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
|
|
+ &user, NULL, NULL, NULL);
|
|
+ PG_RETURN_TEXT_P(CStringGetTextDatum(user));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * text sepgsql_set_user(text, text)
|
|
+ *
|
|
+ * It replaces the USER field of given security context by the second argument.
|
|
+ */
|
|
+Datum
|
|
+sepgsql_set_user(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *user, *role, *type, *range;
|
|
+ char buffer[1024];
|
|
+ security_context_t newcon;
|
|
+ Datum result;
|
|
+
|
|
+ parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
|
|
+ &user, &role, &type, &range);
|
|
+ if (range)
|
|
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s:%s",
|
|
+ TextDatumGetCString(PG_GETARG_TEXT_P(1)), role, type, range);
|
|
+ else
|
|
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s",
|
|
+ TextDatumGetCString(PG_GETARG_TEXT_P(1)), role, type);
|
|
+ if (selinux_raw_to_trans_context((security_context_t) buffer, &newcon) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not set a new user")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = CStringGetTextDatum(newcon);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(newcon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(newcon);
|
|
+
|
|
+ PG_RETURN_DATUM(result);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * text sepgsql_get_role(text)
|
|
+ *
|
|
+ * It picks up the ROLE field of given security context.
|
|
+ */
|
|
+Datum
|
|
+sepgsql_get_role(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *role;
|
|
+
|
|
+ parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
|
|
+ NULL, &role, NULL, NULL);
|
|
+ PG_RETURN_TEXT_P(CStringGetTextDatum(role));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * text sepgsql_set_user(text, text)
|
|
+ *
|
|
+ * It replaces the ROLE field of given security context by the second argument.
|
|
+ */
|
|
+Datum
|
|
+sepgsql_set_role(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *user, *role, *type, *range;
|
|
+ char buffer[1024];
|
|
+ security_context_t newcon;
|
|
+ Datum result;
|
|
+
|
|
+ parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
|
|
+ &user, &role, &type, &range);
|
|
+ if (range)
|
|
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s:%s",
|
|
+ user, TextDatumGetCString(PG_GETARG_TEXT_P(1)), type, range);
|
|
+ else
|
|
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s",
|
|
+ user, TextDatumGetCString(PG_GETARG_TEXT_P(1)), type);
|
|
+ if (selinux_raw_to_trans_context((security_context_t) buffer, &newcon) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not set a new role")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = CStringGetTextDatum(newcon);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(newcon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(newcon);
|
|
+
|
|
+ PG_RETURN_DATUM(result);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * text sepgsql_get_type(text)
|
|
+ *
|
|
+ * It picks up the TYPE field of given security context.
|
|
+ */
|
|
+Datum
|
|
+sepgsql_get_type(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *type;
|
|
+
|
|
+ parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
|
|
+ NULL, NULL, &type, NULL);
|
|
+ PG_RETURN_TEXT_P(CStringGetTextDatum(type));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * text sepgsql_set_user(text, text)
|
|
+ *
|
|
+ * It replaces the TYPE field of given security context by the second argument.
|
|
+ */
|
|
+Datum
|
|
+sepgsql_set_type(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *user, *role, *type, *range;
|
|
+ char buffer[1024];
|
|
+ security_context_t newcon;
|
|
+ Datum result;
|
|
+
|
|
+ parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
|
|
+ &user, &role, &type, &range);
|
|
+ if (range)
|
|
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s:%s",
|
|
+ user, role, TextDatumGetCString(PG_GETARG_TEXT_P(1)), range);
|
|
+ else
|
|
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s",
|
|
+ user, role, TextDatumGetCString(PG_GETARG_TEXT_P(1)));
|
|
+ if (selinux_raw_to_trans_context((security_context_t) buffer, &newcon) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not set a new type")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = CStringGetTextDatum(newcon);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(newcon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(newcon);
|
|
+
|
|
+ PG_RETURN_DATUM(result);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * text sepgsql_get_range(text)
|
|
+ *
|
|
+ * It picks up the RANGE field of given security context.
|
|
+ */
|
|
+Datum
|
|
+sepgsql_get_range(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *range;
|
|
+
|
|
+ parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
|
|
+ NULL, NULL, NULL, &range);
|
|
+ PG_RETURN_TEXT_P(CStringGetTextDatum(range));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * text sepgsql_set_user(text, text)
|
|
+ *
|
|
+ * It replaces the RANGE field of given security context by the second argument.
|
|
+ */
|
|
+Datum
|
|
+sepgsql_set_range(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *user, *role, *type, *range;
|
|
+ char buffer[1024];
|
|
+ security_context_t newcon;
|
|
+ Datum result;
|
|
+
|
|
+ parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
|
|
+ &user, &role, &type, &range);
|
|
+ if (range)
|
|
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s:%s",
|
|
+ user, role, type, TextDatumGetCString(PG_GETARG_TEXT_P(1)));
|
|
+ else
|
|
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s", user, role, type);
|
|
+ if (selinux_raw_to_trans_context((security_context_t) buffer, &newcon) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not set a new range")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = CStringGetTextDatum(newcon);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(newcon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(newcon);
|
|
+
|
|
+ PG_RETURN_DATUM(result);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL legacy function support
|
|
+ */
|
|
+Datum sepgsql_tuple_perms(PG_FUNCTION_ARGS);
|
|
+Datum sepgsql_tuple_perms_abort(PG_FUNCTION_ARGS);
|
|
+
|
|
+Datum
|
|
+sepgsql_tuple_perms(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("%s is no longer supported", __FUNCTION__)));
|
|
+ PG_RETURN_VOID();
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_tuple_perms_abort(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("%s is no longer supported", __FUNCTION__)));
|
|
+ PG_RETURN_VOID();
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/security/sepgsql/hooks.c
|
|
--- base/src/backend/security/sepgsql/hooks.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/sepgsql/hooks.c 2009-02-26 21:08:58.000000000 +0900
|
|
@@ -0,0 +1,1160 @@
|
|
+/*
|
|
+ * src/backend/security/sepgsql/hooks.c
|
|
+ * implementations of PGACE framework
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ *
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/heapam.h"
|
|
+#include "access/genam.h"
|
|
+#include "access/skey.h"
|
|
+#include "catalog/indexing.h"
|
|
+#include "catalog/pg_aggregate.h"
|
|
+#include "catalog/pg_amproc.h"
|
|
+#include "catalog/pg_cast.h"
|
|
+#include "catalog/pg_conversion.h"
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_language.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_operator.h"
|
|
+#include "catalog/pg_proc.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "catalog/pg_trigger.h"
|
|
+#include "catalog/pg_ts_parser.h"
|
|
+#include "catalog/pg_ts_template.h"
|
|
+#include "catalog/pg_type.h"
|
|
+#include "miscadmin.h"
|
|
+#include "nodes/makefuncs.h"
|
|
+#include "security/pgace.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/syscache.h"
|
|
+#include "utils/tqual.h"
|
|
+#include <fcntl.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Extended SQL statement hooks
|
|
+ *******************************************************************************/
|
|
+bool
|
|
+sepgsqlIsGramSecurityItem(DefElem *defel)
|
|
+{
|
|
+ Assert(IsA(defel, DefElem));
|
|
+
|
|
+ if (defel->defname &&
|
|
+ strcmp(defel->defname, SecurityLabelAttributeName) == 0)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static void
|
|
+putExplicitContext(HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ if (defel)
|
|
+ {
|
|
+ Oid sid = pgaceSecurityLabelToSid(strVal(defel->arg));
|
|
+
|
|
+ HeapTupleSetSecLabel(tuple, sid);
|
|
+ }
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlGramCreateRelation(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ putExplicitContext(tuple, defel);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlGramCreateAttribute(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ putExplicitContext(tuple, defel);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlGramAlterRelation(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ putExplicitContext(tuple, defel);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlGramAlterAttribute(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ putExplicitContext(tuple, defel);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlGramCreateDatabase(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ putExplicitContext(tuple, defel);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlGramAlterDatabase(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ putExplicitContext(tuple, defel);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlGramCreateFunction(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ putExplicitContext(tuple, defel);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlGramAlterFunction(Relation rel, HeapTuple tuple, DefElem *defel)
|
|
+{
|
|
+ putExplicitContext(tuple, defel);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * DATABASE object related hooks
|
|
+ *******************************************************************************/
|
|
+
|
|
+void
|
|
+sepgsqlGetDatabaseParam(const char *name)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ const char *audit_name;
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId), 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for database %u",
|
|
+ MyDatabaseId);
|
|
+
|
|
+ audit_name = sepgsqlTupleName(DatabaseRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__GET_PARAM,
|
|
+ audit_name);
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlSetDatabaseParam(const char *name, char *argstring)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ const char *audit_name;
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId), 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for database %u",
|
|
+ MyDatabaseId);
|
|
+
|
|
+ audit_name = sepgsqlTupleName(DatabaseRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__SET_PARAM,
|
|
+ audit_name);
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * RELATION(Table)/ATTRIBTUE(column) object related hooks
|
|
+ *******************************************************************************/
|
|
+void
|
|
+sepgsqlLockTable(Oid relid)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation %u", relid);
|
|
+
|
|
+ if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
|
|
+ {
|
|
+ const char *audit_name
|
|
+ = sepgsqlTupleName(RelationRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_DB_TABLE,
|
|
+ DB_TABLE__LOCK,
|
|
+ audit_name);
|
|
+ }
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlExecTruncate(List *trunc_rels)
|
|
+{
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, trunc_rels)
|
|
+ {
|
|
+ const char *audit_name;
|
|
+ HeapTuple tuple;
|
|
+ HeapScanDesc scan;
|
|
+ Relation rel = (Relation) lfirst(l);
|
|
+
|
|
+ if (RelationGetForm(rel)->relkind != RELKIND_RELATION)
|
|
+ continue;
|
|
+
|
|
+ /*
|
|
+ * check db_table:{delete}
|
|
+ */
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(RelationGetRelid(rel)),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation %u",
|
|
+ RelationGetRelid(rel));
|
|
+
|
|
+ audit_name = sepgsqlTupleName(RelationRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_DB_TABLE,
|
|
+ DB_TABLE__DELETE,
|
|
+ audit_name);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ /*
|
|
+ * check db_tuple:{delete}
|
|
+ */
|
|
+ scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
|
|
+
|
|
+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
+ {
|
|
+ sepgsqlCheckTuplePerms(rel, tuple, NULL,
|
|
+ SEPGSQL_PERMS_DELETE, true);
|
|
+ }
|
|
+ heap_endscan(scan);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * PROCEDURE related hooks
|
|
+ *******************************************************************************/
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ PGFunction fn_addr;
|
|
+ security_context_t fn_con;
|
|
+} sepgsql_fn_info;
|
|
+
|
|
+static Datum
|
|
+invokeTrustedProcedure(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ sepgsql_fn_info *sefinfo = fcinfo->flinfo->fn_pgaceItem;
|
|
+ security_context_t orig_context;
|
|
+ Datum retval;
|
|
+
|
|
+ /*
|
|
+ * set new domain
|
|
+ */
|
|
+ orig_context = sepgsqlSwitchClientContext(sefinfo->fn_con);
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ retval = sefinfo->fn_addr(fcinfo);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ sepgsqlSwitchClientContext(orig_context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ sepgsqlSwitchClientContext(orig_context);
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlCallFunction(FmgrInfo *finfo)
|
|
+{
|
|
+ MemoryContext oldctx;
|
|
+ HeapTuple tuple;
|
|
+ security_context_t newcon;
|
|
+ access_vector_t perms = DB_PROCEDURE__EXECUTE;
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ return; /* under initialization of pg_proc */
|
|
+
|
|
+ tuple = SearchSysCache(PROCOID,
|
|
+ ObjectIdGetDatum(finfo->fn_oid),
|
|
+ 0, 0, 0);
|
|
+ Assert(HeapTupleIsValid(tuple));
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for procedure %u", finfo->fn_oid);
|
|
+
|
|
+ oldctx = MemoryContextSwitchTo(finfo->fn_mcxt);
|
|
+ /*
|
|
+ * check trusted procedure
|
|
+ */
|
|
+ newcon = sepgsqlClientCreateContext(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_PROCESS);
|
|
+ if (strcmp(newcon, sepgsqlGetClientContext()) != 0)
|
|
+ {
|
|
+ sepgsql_fn_info *sefinfo
|
|
+ = palloc0(sizeof(sepgsql_fn_info));
|
|
+
|
|
+ sefinfo->fn_addr = finfo->fn_addr;
|
|
+ sefinfo->fn_con = newcon;
|
|
+ finfo->fn_addr = invokeTrustedProcedure;
|
|
+ finfo->fn_pgaceItem = sefinfo;
|
|
+
|
|
+ perms |= DB_PROCEDURE__ENTRYPOINT;
|
|
+ }
|
|
+ else
|
|
+ pfree(newcon);
|
|
+
|
|
+ MemoryContextSwitchTo(oldctx);
|
|
+
|
|
+ audit_name = sepgsqlTupleName(ProcedureRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_DB_PROCEDURE,
|
|
+ perms,
|
|
+ audit_name);
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlCallAggFunction(HeapTuple aggTuple)
|
|
+{
|
|
+ Form_pg_aggregate aggForm
|
|
+ = (Form_pg_aggregate) GETSTRUCT(aggTuple);
|
|
+ HeapTuple tuple;
|
|
+ const char *audit_name;
|
|
+
|
|
+ /* check pg_proc.oid = pg_aggregate.aggfnoid */
|
|
+ tuple = SearchSysCache(PROCOID,
|
|
+ ObjectIdGetDatum(aggForm->aggfnoid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for procedure %u",
|
|
+ aggForm->aggfnoid);
|
|
+
|
|
+ audit_name = sepgsqlTupleName(ProcedureRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_DB_PROCEDURE,
|
|
+ DB_PROCEDURE__EXECUTE,
|
|
+ audit_name);
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlCallTriggerFunction(TriggerData *tgdata)
|
|
+{
|
|
+ Relation rel = tgdata->tg_relation;
|
|
+ HeapTuple newtup = NULL;
|
|
+ HeapTuple oldtup = NULL;
|
|
+
|
|
+ /*
|
|
+ * We don't need to check tuple permissions for
|
|
+ * statement triggers
|
|
+ */
|
|
+ if (TRIGGER_FIRED_FOR_STATEMENT(tgdata->tg_event))
|
|
+ return true;
|
|
+
|
|
+ if (TRIGGER_FIRED_BY_INSERT(tgdata->tg_event))
|
|
+ {
|
|
+ if (TRIGGER_FIRED_AFTER(tgdata->tg_event))
|
|
+ newtup = tgdata->tg_trigtuple;
|
|
+ }
|
|
+ else if (TRIGGER_FIRED_BY_UPDATE(tgdata->tg_event))
|
|
+ {
|
|
+ oldtup = tgdata->tg_trigtuple;
|
|
+ if (TRIGGER_FIRED_AFTER(tgdata->tg_event))
|
|
+ {
|
|
+ Oid securityId = HeapTupleGetSecLabel(tgdata->tg_newtuple);
|
|
+
|
|
+ if (HeapTupleGetSecLabel(oldtup) != securityId)
|
|
+ newtup = tgdata->tg_newtuple;
|
|
+ }
|
|
+ }
|
|
+ else if (TRIGGER_FIRED_BY_DELETE(tgdata->tg_event))
|
|
+ {
|
|
+ if (TRIGGER_FIRED_AFTER(tgdata->tg_event))
|
|
+ oldtup = tgdata->tg_trigtuple;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ elog(ERROR, "SELinux: unexpected trigger event type (%u)",
|
|
+ tgdata->tg_event);
|
|
+ }
|
|
+ if (oldtup && !sepgsqlCheckTuplePerms(rel, oldtup, NULL,
|
|
+ SEPGSQL_PERMS_SELECT, false))
|
|
+ return false;
|
|
+ if (newtup && !sepgsqlCheckTuplePerms(rel, newtup, NULL,
|
|
+ SEPGSQL_PERMS_SELECT, false))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool sepgsqlAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple)
|
|
+{
|
|
+ security_context_t newcon;
|
|
+ const char *audit_name;
|
|
+
|
|
+ /*
|
|
+ * If function is defined as trusted procedure, we always should
|
|
+ * not allow it to be inlined, and actual permission checks are
|
|
+ * done later phase.
|
|
+ */
|
|
+ newcon = sepgsqlClientCreateContext(HeapTupleGetSecLabel(func_tuple),
|
|
+ SECCLASS_PROCESS);
|
|
+ if (strcmp(newcon, sepgsqlGetClientContext()) != 0)
|
|
+ return false;
|
|
+
|
|
+ audit_name = sepgsqlTupleName(ProcedureRelationId, func_tuple);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(func_tuple),
|
|
+ SECCLASS_DB_PROCEDURE,
|
|
+ DB_PROCEDURE__EXECUTE,
|
|
+ audit_name);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckProcedureInstall
|
|
+ * checks permission: db_procedure:{install}, when client tries to modify
|
|
+ * a system catalog which contains procedure id to invoke it later.
|
|
+ * Because these functions are invoked internally, to search a table with
|
|
+ * a special index algorithm for example, the security policy has to prevent
|
|
+ * malicious user-defined functions to be installed.
|
|
+ */
|
|
+static void
|
|
+checkProcedureInstall(Oid proc_oid)
|
|
+{
|
|
+ if (!OidIsValid(proc_oid))
|
|
+ return;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ {
|
|
+ /*
|
|
+ * We assume all procedures have same security context
|
|
+ * in bootstrap processing mode, because no one can
|
|
+ * relabel it.
|
|
+ */
|
|
+ Oid proc_sid
|
|
+ = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
|
|
+ SECCLASS_DB_PROCEDURE);
|
|
+ sepgsqlClientHasPermission(proc_sid,
|
|
+ SECCLASS_DB_PROCEDURE,
|
|
+ DB_PROCEDURE__INSTALL,
|
|
+ NULL);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ HeapTuple protup;
|
|
+ const char *audit_name;
|
|
+
|
|
+ protup = SearchSysCache(PROCOID,
|
|
+ ObjectIdGetDatum(proc_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(protup))
|
|
+ return;
|
|
+
|
|
+ audit_name = sepgsqlTupleName(ProcedureRelationId, protup);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(protup),
|
|
+ SECCLASS_DB_PROCEDURE,
|
|
+ DB_PROCEDURE__INSTALL,
|
|
+ audit_name);
|
|
+ ReleaseSysCache(protup);
|
|
+ }
|
|
+}
|
|
+
|
|
+#define CHECK_PROC_INSTALL_HANDLER(catalog,member,newtup,oldtup) \
|
|
+ do { \
|
|
+ if (!HeapTupleIsValid(oldtup)) \
|
|
+ checkProcedureInstall(((Form_##catalog) GETSTRUCT(newtup))->member); \
|
|
+ else if (((Form_##catalog) GETSTRUCT(newtup))->member \
|
|
+ != ((Form_##catalog) GETSTRUCT(oldtup))->member) \
|
|
+ checkProcedureInstall(((Form_##catalog) GETSTRUCT(oldtup))->member); \
|
|
+ } while(0)
|
|
+
|
|
+static void
|
|
+sepgsqlCheckProcedureInstall(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|
+{
|
|
+ /*
|
|
+ * Some of system catalog can be configured to invoke functions
|
|
+ * implicitly. It checks permission to prevent implicit invocation
|
|
+ * of malicious functions.
|
|
+ */
|
|
+ switch (RelationGetRelid(rel))
|
|
+ {
|
|
+ case AggregateRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggfnoid, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggtransfn, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggfinalfn, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case AccessMethodRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, aminsert, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, ambeginscan, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, amgettuple, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, amgetmulti, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, amrescan, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, amendscan, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, ammarkpos, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, amrestrpos, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, ambuild, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, ambulkdelete, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, amvacuumcleanup, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, amcostestimate, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_am, amoptions, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case AccessMethodProcedureRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_amproc, amproc, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case CastRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_cast, castfunc, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case ConversionRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_conversion, conproc, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case LanguageRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_language, lanplcallfoid, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_language, lanvalidator, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case OperatorRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprcode, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprrest, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprjoin, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case TriggerRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_trigger, tgfoid, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case TSParserRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsstart, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prstoken, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsend, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsheadline, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prslextype, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case TSTemplateRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_ts_template, tmplinit, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_ts_template, tmpllexize, newtup, oldtup);
|
|
+ break;
|
|
+
|
|
+ case TypeRelationId:
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_type, typinput, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_type, typoutput, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_type, typreceive, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_type, typsend, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_type, typmodin, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_type, typmodout, newtup, oldtup);
|
|
+ CHECK_PROC_INSTALL_HANDLER(pg_type, typanalyze, newtup, oldtup);
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * LOAD shared library module hook
|
|
+ *******************************************************************************/
|
|
+void
|
|
+sepgsqlLoadSharedModule(const char *filename)
|
|
+{
|
|
+ security_context_t filecon;
|
|
+
|
|
+ if (getfilecon_raw(filename, &filecon) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not access file \"%s\": %m", filename)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePermission(sepgsqlGetDatabaseContext(),
|
|
+ filecon,
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__LOAD_MODULE,
|
|
+ filename);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(filecon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(filecon);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Binary Large Object hooks
|
|
+ *******************************************************************************/
|
|
+
|
|
+void
|
|
+sepgsqlLargeObjectCreate(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ const char *audit_name;
|
|
+
|
|
+ sepgsqlSetDefaultContext(rel, tuple);
|
|
+
|
|
+ audit_name = sepgsqlTupleName(LargeObjectRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__CREATE,
|
|
+ audit_name);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlLargeObjectDrop(Relation rel, HeapTuple tuple, void **pgaceItem)
|
|
+{
|
|
+ Oid security_id = HeapTupleGetSecLabel(tuple);
|
|
+ List *okList = (List *) (*pgaceItem);
|
|
+ ListCell *l;
|
|
+ const char *audit_name;
|
|
+
|
|
+ foreach (l, okList)
|
|
+ {
|
|
+ if (security_id == lfirst_oid(l))
|
|
+ return; /* already allowed */
|
|
+ }
|
|
+
|
|
+ audit_name = sepgsqlTupleName(LargeObjectRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(security_id,
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__DROP,
|
|
+ audit_name);
|
|
+
|
|
+ *pgaceItem = lappend_oid(okList, security_id);
|
|
+}
|
|
+
|
|
+static void
|
|
+checkLargeObjectPages(Oid loid, Snapshot snapshot,
|
|
+ int32 start_pageno, int32 end_pageno,
|
|
+ access_vector_t perms)
|
|
+{
|
|
+ Relation rel;
|
|
+ HeapTuple tuple;
|
|
+ SysScanDesc sd;
|
|
+ ScanKeyData skey[2];
|
|
+ List *okList = NIL;
|
|
+
|
|
+ rel = heap_open(LargeObjectRelationId, AccessShareLock);
|
|
+
|
|
+ ScanKeyInit(&skey[0],
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(loid));
|
|
+
|
|
+ if (start_pageno <= 0)
|
|
+ sd = systable_beginscan(rel, LargeObjectLOidPNIndexId,
|
|
+ true, snapshot, 1, skey);
|
|
+ else
|
|
+ {
|
|
+ ScanKeyInit(&skey[1],
|
|
+ Anum_pg_largeobject_pageno,
|
|
+ BTGreaterEqualStrategyNumber, F_INT4GE,
|
|
+ Int32GetDatum(start_pageno));
|
|
+
|
|
+ sd = systable_beginscan(rel, LargeObjectLOidPNIndexId,
|
|
+ true, snapshot, 2, skey);
|
|
+ }
|
|
+
|
|
+ while ((tuple = systable_getnext(sd)) != NULL)
|
|
+ {
|
|
+ Form_pg_largeobject loForm
|
|
+ = (Form_pg_largeobject) GETSTRUCT(tuple);
|
|
+ Oid security_id;
|
|
+ ListCell *l;
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (end_pageno >= 0 && loForm->pageno > end_pageno)
|
|
+ break;
|
|
+
|
|
+ security_id = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ foreach (l, okList)
|
|
+ {
|
|
+ if (security_id == lfirst_oid(l))
|
|
+ goto skip;
|
|
+ }
|
|
+ okList = lappend_oid(okList, security_id);
|
|
+
|
|
+ audit_name = sepgsqlTupleName(LargeObjectRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(security_id,
|
|
+ SECCLASS_DB_BLOB,
|
|
+ perms,
|
|
+ audit_name);
|
|
+ skip:
|
|
+ ;
|
|
+ }
|
|
+ systable_endscan(sd);
|
|
+
|
|
+ list_free(okList);
|
|
+
|
|
+ heap_close(rel, NoLock);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlLargeObjectRead(LargeObjectDesc *lodesc, int32 length)
|
|
+{
|
|
+ int32 start_pageno = lodesc->offset / LOBLKSIZE;
|
|
+ int32 end_pageno = (lodesc->offset + length + LOBLKSIZE - 1) / LOBLKSIZE;
|
|
+
|
|
+ checkLargeObjectPages(lodesc->id, lodesc->snapshot,
|
|
+ start_pageno, end_pageno, DB_BLOB__READ);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlLargeObjectWrite(LargeObjectDesc *lodesc, int32 length)
|
|
+{
|
|
+ int32 start_pageno = lodesc->offset / LOBLKSIZE;
|
|
+ int32 end_pageno = (lodesc->offset + length + LOBLKSIZE - 1) / LOBLKSIZE;
|
|
+
|
|
+ checkLargeObjectPages(lodesc->id, lodesc->snapshot,
|
|
+ start_pageno, end_pageno, DB_BLOB__WRITE);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlLargeObjectTruncate(LargeObjectDesc *lodesc, int32 offset)
|
|
+{
|
|
+ int32 start_pageno = lodesc->offset / LOBLKSIZE;
|
|
+
|
|
+ checkLargeObjectPages(lodesc->id, lodesc->snapshot,
|
|
+ start_pageno, -1, DB_BLOB__WRITE);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlLargeObjectImport(Oid loid, int fdesc, const char *filename)
|
|
+{
|
|
+ security_context_t tcontext;
|
|
+ security_class_t tclass
|
|
+ = sepgsqlFileObjectClass(fdesc, filename);
|
|
+
|
|
+ if (fgetfilecon_raw(fdesc, &tcontext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not get security context \"%s\": %m", filename)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePermission(sepgsqlGetClientContext(),
|
|
+ tcontext,
|
|
+ tclass,
|
|
+ FILE__READ,
|
|
+ filename);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(tcontext);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(tcontext);
|
|
+
|
|
+ checkLargeObjectPages(loid, SnapshotNow, -1, -1,
|
|
+ DB_BLOB__WRITE | DB_BLOB__IMPORT);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlLargeObjectExport(Oid loid, int fdesc, const char *filename)
|
|
+{
|
|
+ security_context_t tcontext;
|
|
+ security_class_t tclass
|
|
+ = sepgsqlFileObjectClass(fdesc, filename);
|
|
+
|
|
+ if (fgetfilecon_raw(fdesc, &tcontext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not security context \"%s\": %m", filename)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePermission(sepgsqlGetClientContext(),
|
|
+ tcontext,
|
|
+ tclass,
|
|
+ FILE__WRITE,
|
|
+ filename);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(tcontext);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(tcontext);
|
|
+
|
|
+ checkLargeObjectPages(loid, SnapshotNow, -1, -1,
|
|
+ DB_BLOB__READ | DB_BLOB__EXPORT);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlLargeObjectGetSecurity(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ const char *audit_name
|
|
+ = sepgsqlTupleName(LargeObjectRelationId, tuple);
|
|
+
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__GETATTR,
|
|
+ audit_name);
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlLargeObjectSetSecurity(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|
+{
|
|
+ const char *audit_name;
|
|
+
|
|
+ if (HeapTupleGetSecLabel(newtup) == HeapTupleGetSecLabel(oldtup))
|
|
+ return;
|
|
+
|
|
+ audit_name = sepgsqlTupleName(LargeObjectRelationId, oldtup);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(oldtup),
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__SETATTR | DB_BLOB__RELABELFROM,
|
|
+ audit_name);
|
|
+ /*
|
|
+ * check db_blob:{setattr relabelto}
|
|
+ */
|
|
+ audit_name = sepgsqlTupleName(LargeObjectRelationId, newtup);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(newtup),
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__RELABELTO,
|
|
+ audit_name);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * ExecScan hooks
|
|
+ *******************************************************************************/
|
|
+static bool abort_on_violated_tuple = false;
|
|
+
|
|
+bool
|
|
+sepgsqlRowlvBehaviorSwitchTo(bool new_abort)
|
|
+{
|
|
+ bool old_abort = abort_on_violated_tuple;
|
|
+
|
|
+ abort_on_violated_tuple = new_abort;
|
|
+
|
|
+ return old_abort;
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ uint32 perms = (scan->pgaceTuplePerms & SEPGSQL_PERMS_MASK);
|
|
+
|
|
+ if (abort_on_violated_tuple != abort)
|
|
+ return true; /* no need to do here */
|
|
+
|
|
+ if (perms == 0)
|
|
+ return true;
|
|
+
|
|
+ tuple = ExecMaterializeSlot(slot);
|
|
+
|
|
+ return sepgsqlCheckTuplePerms(rel, tuple, NULL, perms,
|
|
+ abort_on_violated_tuple);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * security_label hooks
|
|
+ *******************************************************************************/
|
|
+bool
|
|
+sepgsqlTupleDescHasSecLabel(Relation rel, List *relopts)
|
|
+{
|
|
+ /*
|
|
+ * Newly created table via SELECT INTO/CREATE TABLE AS
|
|
+ */
|
|
+ if (rel == NULL)
|
|
+ return sepostgresql_row_level;
|
|
+
|
|
+ if (RelationGetForm(rel)->relkind != RELKIND_RELATION &&
|
|
+ RelationGetForm(rel)->relkind != RELKIND_SEQUENCE)
|
|
+ return false;
|
|
+
|
|
+ if (RelationGetRelid(rel) == DatabaseRelationId ||
|
|
+ RelationGetRelid(rel) == RelationRelationId ||
|
|
+ RelationGetRelid(rel) == AttributeRelationId ||
|
|
+ RelationGetRelid(rel) == ProcedureRelationId ||
|
|
+ RelationGetRelid(rel) == LargeObjectRelationId)
|
|
+ return true;
|
|
+
|
|
+ return sepostgresql_row_level;
|
|
+}
|
|
+
|
|
+char *
|
|
+sepgsqlTranslateSecurityLabelIn(const char *context)
|
|
+{
|
|
+ security_context_t i_context;
|
|
+ char *result;
|
|
+
|
|
+ if (selinux_trans_to_raw_context((security_context_t) context, &i_context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not translate mls label")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(i_context);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(i_context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(i_context);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+char *
|
|
+sepgsqlTranslateSecurityLabelOut(const char *context)
|
|
+{
|
|
+ security_context_t o_context;
|
|
+ char *result;
|
|
+
|
|
+ if (selinux_raw_to_trans_context((security_context_t) context, &o_context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not translate mls label")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(o_context);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(o_context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(o_context);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckValidSecurityLabel() checks whether the given
|
|
+ * security context is valid on the current working security
|
|
+ * policy, or not.
|
|
+ * If it's invalid, sepgsqlUnlabeledSecurityLabel() is invoked
|
|
+ * at the next to get an alternative security label.
|
|
+ */
|
|
+bool
|
|
+sepgsqlCheckValidSecurityLabel(char *context)
|
|
+{
|
|
+ if (security_check_context_raw((security_context_t) context) < 0)
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+char *
|
|
+sepgsqlUnlabeledSecurityLabel(void)
|
|
+{
|
|
+ security_context_t unlabeled;
|
|
+ char *result;
|
|
+
|
|
+ if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not get unlabeled initial context")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(unlabeled);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(unlabeled);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(unlabeled);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+char *
|
|
+sepgsqlSecurityLabelOfLabel(void)
|
|
+{
|
|
+ security_context_t table_context, tuple_context;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ /*
|
|
+ * obtain security context of pg_security
|
|
+ */
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(SecurityRelationId), 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation %u",
|
|
+ SecurityRelationId);
|
|
+
|
|
+ table_context = pgaceLookupSecurityLabel(HeapTupleGetSecLabel(tuple));
|
|
+ if (!table_context || !pgaceCheckValidSecurityLabel(table_context))
|
|
+ table_context = pgaceUnlabeledSecurityLabel();
|
|
+
|
|
+ tuple_context = sepgsqlComputeCreateContext(sepgsqlGetServerContext(),
|
|
+ table_context, SECCLASS_DB_TUPLE);
|
|
+ pfree(table_context);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return tuple_context;
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * HeapTuple modification hooks
|
|
+ ******************************************************************/
|
|
+static HeapTuple
|
|
+getHeapTupleFromItemPointer(Relation rel, ItemPointer tid)
|
|
+{
|
|
+ /*
|
|
+ * obtain an old tuple
|
|
+ */
|
|
+ Buffer buffer;
|
|
+ PageHeader dp;
|
|
+ ItemId lp;
|
|
+ HeapTupleData tuple;
|
|
+ HeapTuple oldtup;
|
|
+
|
|
+ buffer = ReadBuffer(rel, ItemPointerGetBlockNumber(tid));
|
|
+ LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
|
+
|
|
+ dp = (PageHeader) BufferGetPage(buffer);
|
|
+ lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
|
|
+
|
|
+ Assert(ItemIdIsNormal(lp));
|
|
+
|
|
+ tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
|
|
+ tuple.t_len = ItemIdGetLength(lp);
|
|
+ tuple.t_self = *tid;
|
|
+ tuple.t_tableOid = RelationGetRelid(rel);
|
|
+ oldtup = heap_copytuple(&tuple);
|
|
+
|
|
+ LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
|
+ ReleaseBuffer(buffer);
|
|
+
|
|
+ return oldtup;
|
|
+}
|
|
+
|
|
+static bool
|
|
+isTrustedRelation(Relation rel, bool is_internal)
|
|
+{
|
|
+ if (!is_internal)
|
|
+ return false;
|
|
+
|
|
+ if (RelationGetForm(rel)->relkind != RELKIND_RELATION)
|
|
+ return true;
|
|
+
|
|
+ switch (RelationGetRelid(rel))
|
|
+ {
|
|
+ case LargeObjectRelationId:
|
|
+ case SecurityRelationId:
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlHeapTupleInsert(Relation rel, HeapTuple tuple,
|
|
+ bool is_internal, bool with_returning)
|
|
+{
|
|
+ uint32 perms;
|
|
+
|
|
+ sepgsqlCheckProcedureInstall(rel, tuple, NULL);
|
|
+
|
|
+ if (!OidIsValid(HeapTupleGetSecLabel(tuple)))
|
|
+ {
|
|
+ /*
|
|
+ * If user gives no valid security context,
|
|
+ * it assigns a default one on the new tuple.
|
|
+ */
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ sepgsqlSetDefaultContext(rel, tuple);
|
|
+ }
|
|
+ else if (!is_internal && RelationGetRelid(rel) == LargeObjectRelationId)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: unable to insert "
|
|
+ "pg_largeobject.security_context")));
|
|
+
|
|
+ if (isTrustedRelation(rel, is_internal))
|
|
+ return true;
|
|
+
|
|
+ perms = SEPGSQL_PERMS_INSERT;
|
|
+ if (with_returning)
|
|
+ perms |= SEPGSQL_PERMS_SELECT;
|
|
+
|
|
+ return sepgsqlCheckTuplePerms(rel, tuple, NULL, perms, is_internal);
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup,
|
|
+ bool is_internal, bool with_returning)
|
|
+{
|
|
+ Oid relid = RelationGetRelid(rel);
|
|
+ HeapTuple oldtup;
|
|
+ uint32 perms = 0;
|
|
+ bool rc = true;
|
|
+ bool relabel = false;
|
|
+
|
|
+ oldtup = getHeapTupleFromItemPointer(rel, otid);
|
|
+
|
|
+ sepgsqlCheckProcedureInstall(rel, newtup, oldtup);
|
|
+
|
|
+ if (!OidIsValid(HeapTupleGetSecLabel(newtup)))
|
|
+ {
|
|
+ /*
|
|
+ * If user does not specify new security context
|
|
+ * explicitly, it preserves a security context of
|
|
+ * older tuple.
|
|
+ */
|
|
+ Oid sid = HeapTupleGetSecLabel(oldtup);
|
|
+
|
|
+ if (HeapTupleHasSecLabel(newtup))
|
|
+ HeapTupleSetSecLabel(newtup, sid);
|
|
+ }
|
|
+ else if (!is_internal && RelationGetRelid(rel) == LargeObjectRelationId)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: unable to update "
|
|
+ "pg_largeobject.security_context")));
|
|
+
|
|
+ if (isTrustedRelation(rel, is_internal))
|
|
+ return true;
|
|
+
|
|
+ if (HeapTupleGetSecLabel(newtup) != HeapTupleGetSecLabel(oldtup) ||
|
|
+ sepgsqlTupleObjectClass(relid, newtup) != sepgsqlTupleObjectClass(relid, oldtup))
|
|
+ relabel = true;
|
|
+
|
|
+ if (is_internal)
|
|
+ perms |= SEPGSQL_PERMS_UPDATE;
|
|
+ if (relabel)
|
|
+ perms |= SEPGSQL_PERMS_RELABELFROM;
|
|
+ rc = sepgsqlCheckTuplePerms(rel, oldtup, newtup, perms, is_internal);
|
|
+ if (!rc)
|
|
+ goto out;
|
|
+
|
|
+ if (relabel)
|
|
+ {
|
|
+ perms = SEPGSQL_PERMS_RELABELTO;
|
|
+ if (with_returning)
|
|
+ perms |= SEPGSQL_PERMS_SELECT;
|
|
+ rc = sepgsqlCheckTuplePerms(rel, newtup, NULL, perms, is_internal);
|
|
+ }
|
|
+ out:
|
|
+ heap_freetuple(oldtup);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlHeapTupleDelete(Relation rel, ItemPointer otid,
|
|
+ bool is_internal, bool with_returning)
|
|
+{
|
|
+ HeapTuple oldtup;
|
|
+ uint32 perms = 0;
|
|
+ bool rc;
|
|
+
|
|
+ if (isTrustedRelation(rel, is_internal))
|
|
+ return true;
|
|
+ if (is_internal)
|
|
+ perms |= SEPGSQL_PERMS_DELETE;
|
|
+
|
|
+ oldtup = getHeapTupleFromItemPointer(rel, otid);
|
|
+ rc = sepgsqlCheckTuplePerms(rel, oldtup, NULL, perms, is_internal);
|
|
+ heap_freetuple(oldtup);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/security/sepgsql/permissions.c
|
|
--- base/src/backend/security/sepgsql/permissions.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/sepgsql/permissions.c 2009-02-26 21:08:58.000000000 +0900
|
|
@@ -0,0 +1,636 @@
|
|
+
|
|
+/*
|
|
+ * src/backend/security/sepgsql/permissions.c
|
|
+ * applies SE-PostgreSQL permission checks
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ *
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/heapam.h"
|
|
+#include "access/genam.h"
|
|
+#include "catalog/indexing.h"
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_language.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_proc.h"
|
|
+#include "catalog/pg_type.h"
|
|
+#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/lsyscache.h"
|
|
+#include "utils/syscache.h"
|
|
+#include "utils/tqual.h"
|
|
+
|
|
+#include <sys/stat.h>
|
|
+
|
|
+/*
|
|
+ * It can be configured via a GUC variable to toggle
|
|
+ * row-level access controls.
|
|
+ */
|
|
+bool sepostgresql_row_level = true;
|
|
+
|
|
+/*
|
|
+ * sepgsqlTupleName
|
|
+ * returns an identifier string to generate audit record for
|
|
+ * the given tuple. Please note that its results can indicate
|
|
+ * an address within the given tuple, so we should not refer
|
|
+ * the returned pointer after HeapTuple is released.
|
|
+ */
|
|
+const char *
|
|
+sepgsqlTupleName(Oid relid, HeapTuple tuple)
|
|
+{
|
|
+ static char buffer[NAMEDATALEN * 2 + 10];
|
|
+
|
|
+ switch (relid)
|
|
+ {
|
|
+ case DatabaseRelationId:
|
|
+ return NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname);
|
|
+
|
|
+ case RelationRelationId:
|
|
+ return NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname);
|
|
+
|
|
+ case AttributeRelationId:
|
|
+ if (!IsBootstrapProcessingMode())
|
|
+ {
|
|
+ Form_pg_attribute attForm
|
|
+ = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ char *relname
|
|
+ = get_rel_name(attForm->attrelid);
|
|
+
|
|
+ if (relname)
|
|
+ {
|
|
+ snprintf(buffer, sizeof(buffer), "%s.%s",
|
|
+ relname, NameStr(attForm->attname));
|
|
+ pfree(relname);
|
|
+ return buffer;
|
|
+ }
|
|
+ }
|
|
+ return NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname);
|
|
+
|
|
+ case ProcedureRelationId:
|
|
+ return NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname);
|
|
+
|
|
+ case LargeObjectRelationId:
|
|
+ snprintf(buffer, sizeof(buffer), "loid:%u",
|
|
+ ((Form_pg_largeobject) GETSTRUCT(tuple))->loid);
|
|
+ return buffer;
|
|
+ }
|
|
+ return NULL; /* No tuple name for audit record */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlFileObjectClass
|
|
+ *
|
|
+ * It returns proper object class of filesystem object already opened.
|
|
+ * It is necessary to check privileges voluntarily.
|
|
+ */
|
|
+security_class_t
|
|
+sepgsqlFileObjectClass(int fdesc, const char *filename)
|
|
+{
|
|
+ struct stat stbuf;
|
|
+
|
|
+ if (fstat(fdesc, &stbuf) != 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not stat file \"%s\": %m", filename)));
|
|
+
|
|
+ if (S_ISDIR(stbuf.st_mode))
|
|
+ return SECCLASS_DIR;
|
|
+ else if (S_ISCHR(stbuf.st_mode))
|
|
+ return SECCLASS_CHR_FILE;
|
|
+ else if (S_ISBLK(stbuf.st_mode))
|
|
+ return SECCLASS_BLK_FILE;
|
|
+ else if (S_ISFIFO(stbuf.st_mode))
|
|
+ return SECCLASS_FIFO_FILE;
|
|
+ else if (S_ISLNK(stbuf.st_mode))
|
|
+ return SECCLASS_LNK_FILE;
|
|
+ else if (S_ISSOCK(stbuf.st_mode))
|
|
+ return SECCLASS_SOCK_FILE;
|
|
+
|
|
+ return SECCLASS_FILE;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlTupleObjectClass
|
|
+ *
|
|
+ * It returns proper object class of given tuple
|
|
+ */
|
|
+security_class_t
|
|
+sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple)
|
|
+{
|
|
+ Form_pg_class clsForm;
|
|
+ Form_pg_attribute attForm;
|
|
+
|
|
+ switch (relid)
|
|
+ {
|
|
+ case DatabaseRelationId:
|
|
+ return SECCLASS_DB_DATABASE;
|
|
+
|
|
+ case RelationRelationId:
|
|
+ clsForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+ if (clsForm->relkind == RELKIND_RELATION)
|
|
+ return SECCLASS_DB_TABLE;
|
|
+ break;
|
|
+
|
|
+ case AttributeRelationId:
|
|
+ attForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+
|
|
+ if (attForm->attrelid == TypeRelationId ||
|
|
+ attForm->attrelid == ProcedureRelationId ||
|
|
+ attForm->attrelid == AttributeRelationId ||
|
|
+ attForm->attrelid == RelationRelationId ||
|
|
+ get_rel_relkind(attForm->attrelid) == RELKIND_RELATION)
|
|
+ return SECCLASS_DB_COLUMN;
|
|
+ break;
|
|
+
|
|
+ case ProcedureRelationId:
|
|
+ return SECCLASS_DB_PROCEDURE;
|
|
+
|
|
+ case LargeObjectRelationId:
|
|
+ return SECCLASS_DB_BLOB;
|
|
+ }
|
|
+
|
|
+ return SECCLASS_DB_TUPLE;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckTuplePerms
|
|
+ *
|
|
+ * This function evaluates given permission set (SEPGSQL_PERMS_*) onto the
|
|
+ * given tuple, with translating them into proper SELinux permission.
|
|
+ *
|
|
+ * Accesses to some of system catalog has special meanings. DELETE a tuple
|
|
+ * within pg_class also means DROP TABLE for instance. In this case,
|
|
+ * SE-PostgreSQL translate given SEPGSQL_PERMS_DELETE into DB_TABLE__DROP
|
|
+ * to keep consistency of user operation. To delete a tuple within pg_class
|
|
+ * always means dropping a table independent from what SQL statement is
|
|
+ * used.
|
|
+ *
|
|
+ * Thus, checks for some of system catalog need to modify given permission
|
|
+ * set at checkTuplePermsXXXX() functions.
|
|
+ */
|
|
+static access_vector_t
|
|
+sepgsqlPermsToCommonAv(uint32 perms)
|
|
+{
|
|
+ access_vector_t result = 0;
|
|
+
|
|
+ result |= (perms & SEPGSQL_PERMS_USE ? COMMON_DATABASE__GETATTR : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_SELECT ? COMMON_DATABASE__GETATTR : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_UPDATE ? COMMON_DATABASE__SETATTR : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_INSERT ? COMMON_DATABASE__CREATE : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_DELETE ? COMMON_DATABASE__DROP : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_RELABELFROM ? COMMON_DATABASE__RELABELFROM : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_RELABELTO ? COMMON_DATABASE__RELABELTO : 0);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static access_vector_t
|
|
+sepgsqlPermsToDatabaseAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
|
|
+{
|
|
+ return sepgsqlPermsToCommonAv(perms);
|
|
+}
|
|
+
|
|
+static access_vector_t
|
|
+sepgsqlPermsToTableAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
|
|
+{
|
|
+ return sepgsqlPermsToCommonAv(perms);
|
|
+}
|
|
+
|
|
+static access_vector_t
|
|
+sepgsqlPermsToProcedureAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
|
|
+{
|
|
+ access_vector_t result = sepgsqlPermsToCommonAv(perms);
|
|
+ Form_pg_proc proForm;
|
|
+ HeapTuple protup;
|
|
+ Datum probin;
|
|
+ bool isnull;
|
|
+
|
|
+ /*
|
|
+ * Check permission for loadable module installation
|
|
+ */
|
|
+ protup = HeapTupleIsValid(newtup) ? newtup : tuple;
|
|
+ proForm = (Form_pg_proc) GETSTRUCT(protup);
|
|
+
|
|
+ if (proForm->prolang == ClanguageId)
|
|
+ {
|
|
+ bool need_check = false;
|
|
+
|
|
+ probin = SysCacheGetAttr(PROCOID, protup,
|
|
+ Anum_pg_proc_probin,
|
|
+ &isnull);
|
|
+ if (!isnull)
|
|
+ {
|
|
+ if (result & DB_PROCEDURE__CREATE)
|
|
+ need_check = true;
|
|
+ else if (HeapTupleIsValid(newtup))
|
|
+ {
|
|
+ Form_pg_proc oldForm = (Form_pg_proc) GETSTRUCT(tuple);
|
|
+
|
|
+ if (oldForm->prolang != proForm->prolang)
|
|
+ need_check = true;
|
|
+ else
|
|
+ {
|
|
+ Datum oldbin = SysCacheGetAttr(PROCOID, tuple,
|
|
+ Anum_pg_proc_probin,
|
|
+ &isnull);
|
|
+ if (isnull)
|
|
+ need_check = true;
|
|
+ else
|
|
+ {
|
|
+ Datum comp = DirectFunctionCall2(byteane, oldbin, probin);
|
|
+ need_check = DatumGetBool(comp);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (need_check)
|
|
+ {
|
|
+ char *filename = TextDatumGetCString(probin);
|
|
+
|
|
+ sepgsqlCheckModuleInstallPerms(filename);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static access_vector_t
|
|
+sepgsqlPermsToColumnAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
|
|
+{
|
|
+ access_vector_t result = sepgsqlPermsToCommonAv(perms);
|
|
+
|
|
+ if (HeapTupleIsValid(newtup))
|
|
+ {
|
|
+ Form_pg_attribute oldatt = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ Form_pg_attribute newatt = (Form_pg_attribute) GETSTRUCT(newtup);
|
|
+
|
|
+ if (!oldatt->attisdropped && newatt->attisdropped)
|
|
+ result |= DB_COLUMN__DROP;
|
|
+ if (oldatt->attisdropped && !newatt->attisdropped)
|
|
+ result |= DB_COLUMN__CREATE;
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static access_vector_t
|
|
+sepgsqlPermsToTupleAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
|
|
+{
|
|
+ access_vector_t result = 0;
|
|
+
|
|
+ result |= (perms & SEPGSQL_PERMS_USE ? DB_TUPLE__USE : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_SELECT ? DB_TUPLE__SELECT : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_UPDATE ? DB_TUPLE__UPDATE : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_INSERT ? DB_TUPLE__INSERT : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_DELETE ? DB_TUPLE__DELETE : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_RELABELFROM ? DB_TUPLE__RELABELFROM : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_RELABELTO ? DB_TUPLE__RELABELTO : 0);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static access_vector_t
|
|
+sepgsqlPermsToBlobAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
|
|
+{
|
|
+ access_vector_t result = sepgsqlPermsToCommonAv(perms);
|
|
+
|
|
+ /*
|
|
+ * NOTE: INSERT tuples into pg_largeobject has a possibility to create
|
|
+ * a new largeobject, if the given loid is not exist on the current
|
|
+ * pg_largeobject. Ditto for DELETE statement, it also has a possibility
|
|
+ * to drop a largeobject, if it removes all tuples within a large object.
|
|
+ *
|
|
+ * UPDATE pg_largeobject.loid has a possibility to create and drop
|
|
+ * a largeobject in same time, so we need to check it when loid is
|
|
+ * changed.
|
|
+ *
|
|
+ * db_blob:{create} and db_blob:{drop} should be evaluated for
|
|
+ * creation/deletion of largeobject, but we have to check pg_largeobject
|
|
+ * with SnapshotSelf whether there is one or more tuple having same loid,
|
|
+ * or not, on each tuple insertion or deletion.
|
|
+ *
|
|
+ * So, we assume any INSERT means db_blob:{create}, any DELETE means
|
|
+ * db_blob:{drop}.
|
|
+ */
|
|
+ result |= (perms & SEPGSQL_PERMS_INSERT ? DB_BLOB__WRITE : 0);
|
|
+ if (perms & SEPGSQL_PERMS_UPDATE)
|
|
+ {
|
|
+ result |= DB_BLOB__WRITE;
|
|
+
|
|
+ if (((Form_pg_largeobject) GETSTRUCT(tuple))->loid !=
|
|
+ ((Form_pg_largeobject) GETSTRUCT(newtup))->loid)
|
|
+ result |= (DB_BLOB__CREATE | DB_BLOB__DROP);
|
|
+ }
|
|
+ result |= (perms & SEPGSQL_PERMS_DELETE ? DB_BLOB__WRITE : 0);
|
|
+ result |= (perms & SEPGSQL_PERMS_READ ? DB_BLOB__READ : 0);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+bool
|
|
+sepgsqlCheckTuplePerms(Relation rel, HeapTuple tuple, HeapTuple newtup,
|
|
+ uint32 perms, bool abort)
|
|
+{
|
|
+ security_class_t tclass;
|
|
+ access_vector_t av = 0;
|
|
+ bool rc = true;
|
|
+
|
|
+ Assert(HeapTupleIsValid(tuple));
|
|
+
|
|
+ tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple);
|
|
+
|
|
+ switch (tclass)
|
|
+ {
|
|
+ case SECCLASS_DB_DATABASE:
|
|
+ av = sepgsqlPermsToDatabaseAv(perms, tuple, newtup);
|
|
+ break;
|
|
+
|
|
+ case SECCLASS_DB_TABLE:
|
|
+ av = sepgsqlPermsToTableAv(perms, tuple, newtup);
|
|
+ break;
|
|
+
|
|
+ case SECCLASS_DB_PROCEDURE:
|
|
+ av = sepgsqlPermsToProcedureAv(perms, tuple, newtup);
|
|
+ break;
|
|
+
|
|
+ case SECCLASS_DB_COLUMN:
|
|
+ av = sepgsqlPermsToColumnAv(perms, tuple, newtup);
|
|
+ break;
|
|
+
|
|
+ case SECCLASS_DB_BLOB:
|
|
+ av = sepgsqlPermsToBlobAv(perms, tuple, newtup);
|
|
+ break;
|
|
+
|
|
+ default: /* SECCLASS_DB_TUPLE */
|
|
+ if (sepostgresql_row_level)
|
|
+ av = sepgsqlPermsToTupleAv(perms, tuple, newtup);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (av)
|
|
+ {
|
|
+ const char *audit_name
|
|
+ = sepgsqlTupleName(RelationGetRelid(rel), tuple);
|
|
+
|
|
+ if (abort)
|
|
+ {
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ tclass, av, audit_name);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ rc = sepgsqlClientHasPermissionNoAbort(HeapTupleGetSecLabel(tuple),
|
|
+ tclass, av, audit_name);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCheckModuleInstallPerms
|
|
+ *
|
|
+ * It checks client's privilege to install a new shared loadable file.
|
|
+ */
|
|
+void
|
|
+sepgsqlCheckModuleInstallPerms(const char *filename)
|
|
+{
|
|
+ security_context_t file_context;
|
|
+ Form_pg_database dbform;
|
|
+ HeapTuple dbtup;
|
|
+ char *fullpath;
|
|
+
|
|
+ /* (client) <-- db_database:module_install --> (database) */
|
|
+ dbtup = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(dbtup))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for database: %u", MyDatabaseId);
|
|
+
|
|
+ dbform = (Form_pg_database) GETSTRUCT(dbtup);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(dbtup),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__INSTALL_MODULE,
|
|
+ NameStr(dbform->datname));
|
|
+ ReleaseSysCache(dbtup);
|
|
+
|
|
+ /* (client) <-- db_databse:module_install --> (*.so file) */
|
|
+ fullpath = expand_dynamic_library_name(filename);
|
|
+ if (getfilecon_raw(fullpath, &file_context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not access file \"%s\": %m", fullpath)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePermission(sepgsqlGetClientContext(),
|
|
+ file_context,
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__INSTALL_MODULE,
|
|
+ fullpath);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(file_context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(file_context);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlSetDefaultContext
|
|
+ *
|
|
+ * This function attach a proper security context for a newly inserted tuple,
|
|
+ * refering the security policy.
|
|
+ * In the default, any tuple inherits the security context of its table.
|
|
+ * However, we have several exception for some of system catalog. It come from
|
|
+ * TYPE_TRANSITION rules in the security policy.
|
|
+ */
|
|
+static Oid
|
|
+sepgsqlDefaultDatabaseContext(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ security_context_t newcon;
|
|
+
|
|
+ newcon = sepgsqlComputeCreateContext(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetClientContext(),
|
|
+ SECCLASS_DB_DATABASE);
|
|
+ return pgaceSecurityLabelToSid(newcon);
|
|
+}
|
|
+
|
|
+static Oid
|
|
+sepgsqlDefaultTableContext(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ return sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
|
|
+ SECCLASS_DB_TABLE);
|
|
+}
|
|
+
|
|
+static Oid
|
|
+sepgsqlDefaultProcedureContext(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ return sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
|
|
+ SECCLASS_DB_PROCEDURE);
|
|
+}
|
|
+
|
|
+static Oid
|
|
+sepgsqlDefaultColumnContext(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ Form_pg_attribute attForm;
|
|
+ Oid tblsid;
|
|
+
|
|
+ attForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+
|
|
+ if (IsBootstrapProcessingMode() &&
|
|
+ (attForm->attrelid == TypeRelationId ||
|
|
+ attForm->attrelid == ProcedureRelationId ||
|
|
+ attForm->attrelid == AttributeRelationId ||
|
|
+ attForm->attrelid == RelationRelationId))
|
|
+ {
|
|
+ /*
|
|
+ * We cannot access relation caches on very early phase
|
|
+ * in bootstrap, so it assumes tables has default security
|
|
+ * context and unlabeled by initdb.
|
|
+ */
|
|
+ tblsid = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
|
|
+ SECCLASS_DB_TABLE);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ HeapTuple reltup
|
|
+ = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(attForm->attrelid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(reltup))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation: %u",
|
|
+ attForm->attrelid);
|
|
+
|
|
+ tblsid = HeapTupleGetSecLabel(reltup);
|
|
+
|
|
+ ReleaseSysCache(reltup);
|
|
+ }
|
|
+
|
|
+ return sepgsqlClientCreateSid(tblsid, SECCLASS_DB_COLUMN);
|
|
+}
|
|
+
|
|
+static Oid
|
|
+sepgsqlDefaultTupleContext(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ Oid tblsid;
|
|
+
|
|
+ if (IsBootstrapProcessingMode() &&
|
|
+ (RelationGetRelid(rel) == TypeRelationId ||
|
|
+ RelationGetRelid(rel) == ProcedureRelationId ||
|
|
+ RelationGetRelid(rel) == AttributeRelationId ||
|
|
+ RelationGetRelid(rel) == RelationRelationId))
|
|
+ {
|
|
+ /*
|
|
+ * We cannot access relation caches on very early phase
|
|
+ * in bootstrap, so it assumes tables has default security
|
|
+ * context and unlabeled by initdb.
|
|
+ */
|
|
+ tblsid = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
|
|
+ SECCLASS_DB_TABLE);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ HeapTuple reltup
|
|
+ = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(RelationGetRelid(rel)),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(reltup))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation: %u",
|
|
+ RelationGetRelid(rel));
|
|
+
|
|
+ tblsid = HeapTupleGetSecLabel(reltup);
|
|
+
|
|
+ ReleaseSysCache(reltup);
|
|
+ }
|
|
+
|
|
+ return sepgsqlClientCreateSid(tblsid, SECCLASS_DB_TUPLE);
|
|
+}
|
|
+
|
|
+static Oid
|
|
+sepgsqlDefaultBlobContext(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ /*
|
|
+ * NOTE:
|
|
+ * A new tuple to be inserted into pg_largeobject inherits
|
|
+ * a security context of prior tuples of same large object.
|
|
+ * The "SnapshotNow" is available for this purpose because
|
|
+ * lo_create() invokes CommandCounterIncrement() just after
|
|
+ * creation of a new large object.
|
|
+ *
|
|
+ * If we can find no prior tuples, it means this action to
|
|
+ * insert the first page, or client invokes INSERT INTO ...
|
|
+ * with multiple tuples with same loid. However, these
|
|
+ * tuples are labeled by same TYPE_TRANSITION rules in both
|
|
+ * cases. So, there are no differences.
|
|
+ */
|
|
+ Form_pg_largeobject loForm
|
|
+ = (Form_pg_largeobject) GETSTRUCT(tuple);
|
|
+ ScanKeyData skey;
|
|
+ SysScanDesc scan;
|
|
+ HeapTuple lotup;
|
|
+ Oid newsid = InvalidOid;
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(loForm->loid));
|
|
+ scan = systable_beginscan(rel,
|
|
+ LargeObjectLOidPNIndexId, true,
|
|
+ SnapshotNow, 1, &skey);
|
|
+ while ((lotup = systable_getnext(scan)) != NULL)
|
|
+ {
|
|
+ newsid = HeapTupleGetSecLabel(lotup);
|
|
+ if (OidIsValid(newsid))
|
|
+ break;
|
|
+ }
|
|
+ systable_endscan(scan);
|
|
+
|
|
+ if (!OidIsValid(newsid))
|
|
+ {
|
|
+ newsid = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
|
|
+ SECCLASS_DB_BLOB);
|
|
+ }
|
|
+
|
|
+ return newsid;
|
|
+}
|
|
+
|
|
+void
|
|
+sepgsqlSetDefaultContext(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ security_class_t tclass;
|
|
+ Oid newsid;
|
|
+
|
|
+ Assert(HeapTupleHasSecLabel(tuple));
|
|
+ tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple);
|
|
+
|
|
+ switch (tclass)
|
|
+ {
|
|
+ case SECCLASS_DB_DATABASE:
|
|
+ newsid = sepgsqlDefaultDatabaseContext(rel, tuple);
|
|
+ break;
|
|
+ case SECCLASS_DB_TABLE:
|
|
+ newsid = sepgsqlDefaultTableContext(rel, tuple);
|
|
+ break;
|
|
+ case SECCLASS_DB_PROCEDURE:
|
|
+ newsid = sepgsqlDefaultProcedureContext(rel, tuple);
|
|
+ break;
|
|
+ case SECCLASS_DB_COLUMN:
|
|
+ newsid = sepgsqlDefaultColumnContext(rel, tuple);
|
|
+ break;
|
|
+ case SECCLASS_DB_BLOB:
|
|
+ newsid = sepgsqlDefaultBlobContext(rel, tuple);
|
|
+ break;
|
|
+ default: /* SECCLASS_DB_TUPLE */
|
|
+ newsid = sepgsqlDefaultTupleContext(rel, tuple);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ HeapTupleSetSecLabel(tuple, newsid);
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/security/sepgsql/proxy.c
|
|
--- base/src/backend/security/sepgsql/proxy.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/sepgsql/proxy.c 2009-02-26 21:08:58.000000000 +0900
|
|
@@ -0,0 +1,1076 @@
|
|
+/*
|
|
+ * src/backend/security/sepgsql/proxy.c
|
|
+ * Proxying the given Query trees via SE-PostgreSQL
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, 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 "catalog/heap.h"
|
|
+#include "catalog/indexing.h"
|
|
+#include "catalog/namespace.h"
|
|
+#include "catalog/pg_attribute.h"
|
|
+#include "catalog/pg_class.h"
|
|
+#include "catalog/pg_constraint.h"
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_operator.h"
|
|
+#include "catalog/pg_proc.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "catalog/pg_trigger.h"
|
|
+#include "catalog/pg_type.h"
|
|
+#include "executor/executor.h"
|
|
+#include "nodes/security.h"
|
|
+#include "optimizer/clauses.h"
|
|
+#include "optimizer/plancat.h"
|
|
+#include "optimizer/prep.h"
|
|
+#include "optimizer/tlist.h"
|
|
+#include "parser/parsetree.h"
|
|
+#include "security/pgace.h"
|
|
+#include "storage/lock.h"
|
|
+#include "utils/array.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/fmgrtab.h"
|
|
+#include "utils/lsyscache.h"
|
|
+#include "utils/syscache.h"
|
|
+#include "utils/tqual.h"
|
|
+
|
|
+/*
|
|
+ * sepgsqlWalkerContext
|
|
+ *
|
|
+ * This structure holds a context during analyzing a given query.
|
|
+ * selist is a list of SEvalItemXXX objects to enumerate appared
|
|
+ * tables and columns. These are evaluated later, just before
|
|
+ * executing query.
|
|
+ * is_internal_use shows the current state whether the current
|
|
+ * Node is chained with target list, or conditional clause.
|
|
+ */
|
|
+typedef struct sepgsqlWalkerContext
|
|
+{
|
|
+ struct sepgsqlWalkerContext *parent;
|
|
+ Query *query; /* Query structure of current layer */
|
|
+ List *selist; /* list of SEvalItemXXX */
|
|
+ bool is_internal_use;
|
|
+} sepgsqlWalkerContext;
|
|
+
|
|
+#define seitem_index_to_attno(index) \
|
|
+ ((index) + FirstLowInvalidHeapAttributeNumber + 1)
|
|
+#define seitem_attno_to_index(attno) \
|
|
+ ((attno) - FirstLowInvalidHeapAttributeNumber - 1)
|
|
+
|
|
+
|
|
+/*
|
|
+ * addEvalRelation
|
|
+ * addEvalRelationRTE
|
|
+ *
|
|
+ * These functions add a given relation into selist, if it is not
|
|
+ * contained yet. In addition, addEvalRelationRTE also marks required
|
|
+ * permissions on rte->pgaceTuplePerms. It is delivered to Scan object
|
|
+ * and we can use it on ExecScan hook to apply tuple-level access
|
|
+ * controls.
|
|
+ */
|
|
+static List *
|
|
+addEvalRelation(List *selist, Oid relid, bool inh, uint32 perms)
|
|
+{
|
|
+ SelinuxEvalItem *seitem;
|
|
+ Form_pg_class relForm;
|
|
+ HeapTuple tuple;
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, selist)
|
|
+ {
|
|
+ seitem = (SelinuxEvalItem *) lfirst(l);
|
|
+ Assert(IsA(seitem, SelinuxEvalItem));
|
|
+
|
|
+ if (seitem->relid == relid && seitem->inh == inh)
|
|
+ {
|
|
+ seitem->relperms |= perms;
|
|
+ return selist;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* not found, so create a new one */
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for relation %u", relid);
|
|
+ relForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+
|
|
+ seitem = makeNode(SelinuxEvalItem);
|
|
+ seitem->relid = relid;
|
|
+ seitem->inh = inh;
|
|
+ seitem->relperms = perms;
|
|
+ seitem->nattrs = seitem_attno_to_index(relForm->relnatts) + 1;
|
|
+ seitem->attperms = palloc0(seitem->nattrs * sizeof(uint32));
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return lappend(selist, seitem);
|
|
+}
|
|
+
|
|
+static List *
|
|
+addEvalRelationRTE(List *selist, RangeTblEntry *rte, uint32 perms)
|
|
+{
|
|
+ rte->pgaceTuplePerms |= (perms & DB_TABLE__USE ? SEPGSQL_PERMS_USE : 0);
|
|
+ rte->pgaceTuplePerms |= (perms & DB_TABLE__SELECT ? SEPGSQL_PERMS_SELECT : 0);
|
|
+ rte->pgaceTuplePerms |= (perms & DB_TABLE__UPDATE ? SEPGSQL_PERMS_UPDATE : 0);
|
|
+ rte->pgaceTuplePerms |= (perms & DB_TABLE__DELETE ? SEPGSQL_PERMS_DELETE : 0);
|
|
+
|
|
+ return addEvalRelation(selist, rte->relid, rte->inh, perms);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * addEvalAttribute
|
|
+ * addEvalAttributeRTE
|
|
+ *
|
|
+ * These functions add a given attribute into selist, if it is not
|
|
+ * contained yet. In addition, addEvalAttributeRTE also marks required
|
|
+ * permissions on rte->pgaceTuplePerms. It is delivered to Scan object
|
|
+ * and we can use it on ExecScan hook to apply tuple-level access
|
|
+ * controls.
|
|
+ */
|
|
+static List *
|
|
+addEvalAttribute(List *selist, Oid relid, bool inh, AttrNumber attno, uint32 perms)
|
|
+{
|
|
+ SelinuxEvalItem *seitem;
|
|
+ Form_pg_class relForm;
|
|
+ HeapTuple tuple;
|
|
+ ListCell *l;
|
|
+ int index = seitem_attno_to_index(attno);
|
|
+
|
|
+ foreach (l, selist)
|
|
+ {
|
|
+ seitem = (SelinuxEvalItem *) lfirst(l);
|
|
+ Assert(IsA(seitem, SelinuxEvalItem));
|
|
+
|
|
+ if (seitem->relid == relid && seitem->inh == inh)
|
|
+ {
|
|
+ if (index >= seitem->nattrs)
|
|
+ {
|
|
+ uint32 *attperms, nattrs;
|
|
+
|
|
+ /*
|
|
+ * NOTE: the following step has a possibility that
|
|
+ * index number overs seitem->nattrs
|
|
+ *
|
|
+ * 1. PREPARE p AS SELECT t FROM t;
|
|
+ * 2. ALTER TABLE t ADD COLUMN x int;
|
|
+ * 3. EXECUTE p;
|
|
+ *
|
|
+ * Because whole-row-reference is extracted to
|
|
+ * references to all the user columns, so table
|
|
+ * may have different number of columns between
|
|
+ * state.1 and state.3.
|
|
+ * In this case, we need to rebuild seitem->attperms
|
|
+ */
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for relation %u", relid);
|
|
+ relForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+
|
|
+ nattrs = seitem_attno_to_index(relForm->relnatts) + 1;
|
|
+ attperms = palloc0(nattrs * sizeof(uint32));
|
|
+ memcpy(attperms, seitem->attperms,
|
|
+ seitem->nattrs * sizeof(uint32));
|
|
+ seitem->nattrs = nattrs;
|
|
+ seitem->attperms = attperms;
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ if (index < 0 || index >= seitem->nattrs)
|
|
+ elog(ERROR, "SELinux: invalid attribute number: %d at relation: %u",
|
|
+ attno, relid);
|
|
+
|
|
+ seitem->attperms[index] |= perms;
|
|
+
|
|
+ return selist;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* not found, so create a new one */
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for relation %u", relid);
|
|
+ relForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+
|
|
+ seitem = makeNode(SelinuxEvalItem);
|
|
+ seitem->relid = relid;
|
|
+ seitem->inh = inh;
|
|
+ seitem->relperms = 0;
|
|
+ seitem->nattrs = seitem_attno_to_index(relForm->relnatts) + 1;
|
|
+ seitem->attperms = palloc0(seitem->nattrs * sizeof(uint32));
|
|
+ if (index < 0 || index >= seitem->nattrs)
|
|
+ elog(ERROR, "SELinux: invalid attribute number: %d at relation: %u",
|
|
+ attno, relid);
|
|
+ seitem->attperms[index] |= perms;
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return lappend(selist, seitem);
|
|
+}
|
|
+
|
|
+static List *
|
|
+addEvalAttributeRTE(List *selist, RangeTblEntry *rte, AttrNumber attno, uint32 perms)
|
|
+{
|
|
+ uint32 tbl_perms = 0;
|
|
+
|
|
+ tbl_perms |= (perms & DB_COLUMN__USE ? DB_TABLE__USE : 0);
|
|
+ tbl_perms |= (perms & DB_COLUMN__SELECT ? DB_TABLE__SELECT : 0);
|
|
+ tbl_perms |= (perms & DB_COLUMN__INSERT ? DB_TABLE__INSERT : 0);
|
|
+ tbl_perms |= (perms & DB_COLUMN__UPDATE ? DB_TABLE__UPDATE : 0);
|
|
+ selist = addEvalRelationRTE(selist, rte, tbl_perms);
|
|
+
|
|
+ /*
|
|
+ * Special care for pg_largeobject.data
|
|
+ */
|
|
+ if ((perms & DB_COLUMN__SELECT) != 0 &&
|
|
+ rte->relid == LargeObjectRelationId &&
|
|
+ attno == Anum_pg_largeobject_data)
|
|
+ rte->pgaceTuplePerms |= SEPGSQL_PERMS_READ;
|
|
+
|
|
+ return addEvalAttribute(selist, rte->relid, rte->inh, attno, perms);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * addEvalForeignKeyConstraint
|
|
+ *
|
|
+ * This function add special case handling for PK/FK constraints.
|
|
+ * invoke trigger function requires to access rights for all attribute
|
|
+ *
|
|
+ */
|
|
+static List *
|
|
+addEvalForeignKeyConstraint(List *selist, Form_pg_trigger trigger)
|
|
+{
|
|
+ HeapTuple contup;
|
|
+ Datum attdat;
|
|
+ ArrayType *attrs;
|
|
+ int index;
|
|
+ int16 *attnum;
|
|
+ bool isnull;
|
|
+
|
|
+ contup = SearchSysCache(CONSTROID,
|
|
+ ObjectIdGetDatum(trigger->tgconstraint),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(contup))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for constraint %u",
|
|
+ trigger->tgconstrrelid);
|
|
+
|
|
+ if (trigger->tgfoid == F_RI_FKEY_CHECK_INS ||
|
|
+ trigger->tgfoid == F_RI_FKEY_CHECK_UPD)
|
|
+ attdat = SysCacheGetAttr(CONSTROID, contup,
|
|
+ Anum_pg_constraint_conkey, &isnull);
|
|
+ else
|
|
+ attdat = SysCacheGetAttr(CONSTROID, contup,
|
|
+ Anum_pg_constraint_confkey, &isnull);
|
|
+ if (isnull)
|
|
+ elog(ERROR, "null PK/FK for constraint %u",
|
|
+ trigger->tgconstrrelid);
|
|
+ attrs = DatumGetArrayTypeP(attdat);
|
|
+
|
|
+ if (ARR_NDIM(attrs) != 1 ||
|
|
+ ARR_HASNULL(attrs) ||
|
|
+ ARR_ELEMTYPE(attrs) != INT2OID)
|
|
+ elog(ERROR, "SELinux: unexpected constraint %u", trigger->tgconstrrelid);
|
|
+
|
|
+ attnum = (int16 *) ARR_DATA_PTR(attrs);
|
|
+ for (index = 0; index < ARR_DIMS(attrs)[0]; index++)
|
|
+ selist = addEvalAttribute(selist, trigger->tgrelid, false,
|
|
+ attnum[index], DB_COLUMN__SELECT);
|
|
+
|
|
+ ReleaseSysCache(contup);
|
|
+
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * addEvalTriggerFunction
|
|
+ *
|
|
+ * This function adds needed items into selist, to execute a trigger
|
|
+ * function. At least, it requires permission set to execute a function
|
|
+ * configured as a trigger, to select a table and whole of columns
|
|
+ * because whole of a tuple is delivered to trigger functions.
|
|
+ */
|
|
+static List *
|
|
+addEvalTriggerFunction(List *selist, Oid relid, int cmdType)
|
|
+{
|
|
+ Relation rel;
|
|
+ SysScanDesc scan;
|
|
+ ScanKeyData skey;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ rel = heap_open(TriggerRelationId, AccessShareLock);
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_trigger_tgrelid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid));
|
|
+ scan = systable_beginscan(rel, TriggerRelidNameIndexId,
|
|
+ true, SnapshotNow, 1, &skey);
|
|
+ while (HeapTupleIsValid((tuple = systable_getnext(scan))))
|
|
+ {
|
|
+ Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
|
|
+ Form_pg_class relForm;
|
|
+ HeapTuple reltup;
|
|
+
|
|
+ /*
|
|
+ * Skip not-invoked triggers
|
|
+ */
|
|
+ if (!trigForm->tgenabled)
|
|
+ continue;
|
|
+ if (cmdType == CMD_INSERT && !TRIGGER_FOR_INSERT(trigForm->tgtype))
|
|
+ continue;
|
|
+ if (cmdType == CMD_UPDATE && !TRIGGER_FOR_UPDATE(trigForm->tgtype))
|
|
+ continue;
|
|
+ if (cmdType == CMD_DELETE && !TRIGGER_FOR_DELETE(trigForm->tgtype))
|
|
+ continue;
|
|
+
|
|
+ /*
|
|
+ * per STATEMENT trigger cannot refer whole of a tuple
|
|
+ */
|
|
+ if (!TRIGGER_FOR_ROW(trigForm->tgtype))
|
|
+ continue;
|
|
+
|
|
+ /*
|
|
+ * BEFORE-ROW-INSERT trigger cannot refer whole of a tuple
|
|
+ */
|
|
+ if (TRIGGER_FOR_BEFORE(trigForm->tgtype) &&
|
|
+ TRIGGER_FOR_INSERT(trigForm->tgtype))
|
|
+ continue;
|
|
+
|
|
+ reltup = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ relForm = (Form_pg_class) GETSTRUCT(reltup);
|
|
+
|
|
+ selist = addEvalRelation(selist, relid, false, DB_TABLE__SELECT);
|
|
+
|
|
+ if (RI_FKey_trigger_type(trigForm->tgfoid) != RI_TRIGGER_NONE)
|
|
+ selist = addEvalForeignKeyConstraint(selist, trigForm);
|
|
+ else
|
|
+ selist = addEvalAttribute(selist, relid, false,
|
|
+ 0, DB_COLUMN__SELECT);
|
|
+ ReleaseSysCache(reltup);
|
|
+ }
|
|
+ systable_endscan(scan);
|
|
+ heap_close(rel, AccessShareLock);
|
|
+
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlExprWalker
|
|
+ *
|
|
+ * This function walks on the given expression tree to pick up
|
|
+ * all the appeared tables and columns. Their identifiers are
|
|
+ * chains on swc->selist to evaluate permissions on them later.
|
|
+ *
|
|
+ * walkVarHelper picks up an accessed column and its contained
|
|
+ * table, and chains them on swc->selist.
|
|
+ * When swc->is_internal_use is true, it means this reference
|
|
+ * is checked as "use" permission because its contents are
|
|
+ * consumed internally, and not to be returned to client directly.
|
|
+ * Otherwise, "select" permission is applied.
|
|
+ *
|
|
+ * walkQueryHelper walks on Query structure.
|
|
+ * The reason why we don't use query_tree_walker() is that
|
|
+ * SE-PostgreSQL need to apply different permission between
|
|
+ * targetList and havingQual, for example.
|
|
+ */
|
|
+
|
|
+static bool
|
|
+sepgsqlExprWalker(Node *node, sepgsqlWalkerContext *swc);
|
|
+
|
|
+static void
|
|
+sepgsqlExprWalkerFlags(Node *node, sepgsqlWalkerContext *swc,
|
|
+ bool is_internal_use);
|
|
+
|
|
+/*
|
|
+ * wholeRefJoinWalker
|
|
+ *
|
|
+ * A corner case need to invoke this walker function.
|
|
+ * When we use whole-row-reference on RTE_JOIN relation,
|
|
+ * it should be extracted to whole-row-references on
|
|
+ * sources relations.
|
|
+ *
|
|
+ * EXAMPLE:
|
|
+ * SELECT t4 FROM (t1 JOIN (t2 JOIN t3 USING (a)) USING (b)) AS t4;
|
|
+ *
|
|
+ * Because RangeTblEntry with RTE_JOIN does not have any identifiers
|
|
+ * of its source relations, we have to scan Query->jointree again to
|
|
+ * look up sources again. :(
|
|
+ */
|
|
+typedef struct
|
|
+{
|
|
+ Query *query;
|
|
+ int rtindex;
|
|
+ /*
|
|
+ * rtindex == 0 means we are now walking on the required JoinExpr
|
|
+ * or its leafs, so we need to pick up all the appeared relations
|
|
+ * under the JoinExpr in this case.
|
|
+ */
|
|
+ List *selist;
|
|
+ uint32 perms;
|
|
+} wholeRefJoinWalkerContext;
|
|
+
|
|
+static bool
|
|
+wholeRefJoinWalker(Node *node, wholeRefJoinWalkerContext *jwc)
|
|
+{
|
|
+ if (!node)
|
|
+ return false;
|
|
+
|
|
+ if (IsA(node, JoinExpr))
|
|
+ {
|
|
+ JoinExpr *j = (JoinExpr *) node;
|
|
+
|
|
+ if (j->rtindex == jwc->rtindex)
|
|
+ {
|
|
+ int rtindex_backup = jwc->rtindex;
|
|
+ bool rc;
|
|
+
|
|
+ jwc->rtindex = 0;
|
|
+ rc = expression_tree_walker(node, wholeRefJoinWalker, jwc);
|
|
+ jwc->rtindex = rtindex_backup;
|
|
+
|
|
+ return rc;
|
|
+ }
|
|
+ }
|
|
+ else if (IsA(node, RangeTblRef) && jwc->rtindex == 0)
|
|
+ {
|
|
+ RangeTblRef *rtr = (RangeTblRef *) node;
|
|
+ RangeTblEntry *rte = rt_fetch(rtr->rtindex,
|
|
+ jwc->query->rtable);
|
|
+ if (rte->rtekind == RTE_RELATION)
|
|
+ {
|
|
+ jwc->selist = addEvalAttributeRTE(jwc->selist, rte, 0, jwc->perms);
|
|
+ }
|
|
+ }
|
|
+ return expression_tree_walker(node, wholeRefJoinWalker, jwc);
|
|
+}
|
|
+
|
|
+static void
|
|
+walkVarHelper(Var *var, sepgsqlWalkerContext *swc)
|
|
+{
|
|
+ sepgsqlWalkerContext *cur = swc;
|
|
+ Query *query;
|
|
+ RangeTblEntry *rte;
|
|
+ int lv;
|
|
+
|
|
+ Assert(IsA(var, Var));
|
|
+
|
|
+ for (lv = var->varlevelsup; lv > 0; lv--)
|
|
+ {
|
|
+ Assert(cur->parent != NULL);
|
|
+ cur = cur->parent;
|
|
+ }
|
|
+ query = cur->query;
|
|
+
|
|
+ rte = rt_fetch(var->varno, query->rtable);
|
|
+ Assert(IsA(rte, RangeTblEntry));
|
|
+
|
|
+ if (rte->rtekind == RTE_RELATION)
|
|
+ {
|
|
+ uint32 perms = swc->is_internal_use
|
|
+ ? DB_COLUMN__USE : DB_COLUMN__SELECT;
|
|
+
|
|
+ swc->selist = addEvalAttributeRTE(swc->selist, rte,
|
|
+ var->varattno, perms);
|
|
+ }
|
|
+ else if (rte->rtekind == RTE_JOIN)
|
|
+ {
|
|
+ if (var->varattno == 0)
|
|
+ {
|
|
+ wholeRefJoinWalkerContext jwcData;
|
|
+
|
|
+ jwcData.query = query;
|
|
+ jwcData.rtindex = var->varno;
|
|
+ jwcData.selist = swc->selist;
|
|
+ jwcData.perms = swc->is_internal_use
|
|
+ ? DB_COLUMN__USE : DB_COLUMN__SELECT;
|
|
+
|
|
+ wholeRefJoinWalker((Node *)query->jointree, &jwcData);
|
|
+ swc->selist = jwcData.selist;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ Node *node = list_nth(rte->joinaliasvars,
|
|
+ var->varattno - 1);
|
|
+ sepgsqlExprWalker(node, swc);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static List *
|
|
+walkQueryHelper(Query *query, sepgsqlWalkerContext *swc)
|
|
+{
|
|
+ sepgsqlWalkerContext swcData;
|
|
+ RangeTblEntry *rte;
|
|
+
|
|
+ memset(&swcData, 0, sizeof(swcData));
|
|
+ swcData.parent = swc;
|
|
+ swcData.selist = (!swc ? NIL : swc->selist);
|
|
+ swcData.query = query;
|
|
+
|
|
+ if (query->commandType != CMD_DELETE)
|
|
+ {
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, query->targetList)
|
|
+ {
|
|
+ TargetEntry *tle = lfirst(l);
|
|
+ bool is_security = false;
|
|
+
|
|
+ Assert(IsA(tle, TargetEntry));
|
|
+
|
|
+ if (tle->resjunk &&
|
|
+ tle->resname &&
|
|
+ strcmp(tle->resname, SecurityLabelAttributeName) == 0)
|
|
+ is_security = true;
|
|
+
|
|
+ if (tle->resjunk && !is_security)
|
|
+ {
|
|
+ sepgsqlExprWalkerFlags((Node *) tle->expr, &swcData, true);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ sepgsqlExprWalkerFlags((Node *) tle->expr, &swcData, false);
|
|
+
|
|
+ if (query->commandType != CMD_SELECT)
|
|
+ {
|
|
+ AttrNumber attno = tle->resno;
|
|
+ uint32 perms;
|
|
+
|
|
+ if (is_security)
|
|
+ attno = SecurityLabelAttributeNumber;
|
|
+
|
|
+ if (query->commandType == CMD_UPDATE)
|
|
+ perms = DB_COLUMN__UPDATE;
|
|
+ else
|
|
+ perms = DB_COLUMN__INSERT;
|
|
+
|
|
+ rte = rt_fetch(query->resultRelation, query->rtable);
|
|
+ Assert(IsA(rte, RangeTblEntry));
|
|
+
|
|
+ swcData.selist
|
|
+ = addEvalAttributeRTE(swcData.selist, rte, attno, perms);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* no need to check column-level permission for DELETE */
|
|
+ rte = rt_fetch(query->resultRelation, query->rtable);
|
|
+ Assert(IsA(rte, RangeTblEntry));
|
|
+
|
|
+ swcData.selist
|
|
+ = addEvalRelationRTE(swcData.selist, rte, DB_TABLE__DELETE);
|
|
+ }
|
|
+
|
|
+ sepgsqlExprWalkerFlags((Node *) query->returningList, &swcData, false);
|
|
+ sepgsqlExprWalkerFlags((Node *) query->jointree, &swcData, true);
|
|
+ sepgsqlExprWalkerFlags((Node *) query->setOperations, &swcData, true);
|
|
+ sepgsqlExprWalkerFlags((Node *) query->havingQual, &swcData, true);
|
|
+ sepgsqlExprWalkerFlags((Node *) query->sortClause, &swcData, true);
|
|
+ sepgsqlExprWalkerFlags((Node *) query->groupClause, &swcData, true);
|
|
+ sepgsqlExprWalkerFlags((Node *) query->limitOffset, &swcData, true);
|
|
+ sepgsqlExprWalkerFlags((Node *) query->limitCount, &swcData, true);
|
|
+
|
|
+ return swcData.selist;
|
|
+}
|
|
+
|
|
+static void
|
|
+walkRangeTblRefHelper(RangeTblRef *rtr, sepgsqlWalkerContext *swc)
|
|
+{
|
|
+ Query *query = swc->query;
|
|
+ RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
|
|
+
|
|
+ Assert(IsA(rte, RangeTblEntry));
|
|
+
|
|
+ switch (rte->rtekind)
|
|
+ {
|
|
+ case RTE_RELATION:
|
|
+ if (rtr->rtindex != query->resultRelation)
|
|
+ swc->selist = addEvalRelationRTE(swc->selist, rte,
|
|
+ DB_TABLE__SELECT);
|
|
+ break;
|
|
+
|
|
+ case RTE_SUBQUERY:
|
|
+ swc->selist = walkQueryHelper(rte->subquery, swc);
|
|
+ break;
|
|
+
|
|
+ case RTE_FUNCTION:
|
|
+ sepgsqlExprWalker(rte->funcexpr, swc);
|
|
+ break;
|
|
+
|
|
+ case RTE_VALUES:
|
|
+ sepgsqlExprWalker((Node *) rte->values_lists, swc);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ /* do nothing */
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+walkSortClauseHelper(SortClause *sc, sepgsqlWalkerContext *swc)
|
|
+{
|
|
+ Query *query = swc->query;
|
|
+ TargetEntry *tle
|
|
+ = get_sortgroupref_tle(sc->tleSortGroupRef,
|
|
+ query->targetList);
|
|
+
|
|
+ Assert(IsA(tle, TargetEntry));
|
|
+
|
|
+ sepgsqlExprWalker((Node *) tle->expr, swc);
|
|
+}
|
|
+
|
|
+static bool
|
|
+sepgsqlExprWalker(Node *node, sepgsqlWalkerContext *swc)
|
|
+{
|
|
+ if (node == NULL)
|
|
+ return false;
|
|
+ else if (IsA(node, Var))
|
|
+ walkVarHelper((Var *) node, swc);
|
|
+ else if (IsA(node, RangeTblRef))
|
|
+ walkRangeTblRefHelper((RangeTblRef *) node, swc);
|
|
+ else if (IsA(node, Query))
|
|
+ {
|
|
+ swc->selist
|
|
+ = walkQueryHelper((Query *) node, swc);
|
|
+ }
|
|
+ else if (IsA(node, SortClause) ||
|
|
+ IsA(node, GroupClause))
|
|
+ {
|
|
+ walkSortClauseHelper((SortClause *) node, swc);
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+ return expression_tree_walker(node, sepgsqlExprWalker, (void *) swc);
|
|
+}
|
|
+
|
|
+static void
|
|
+sepgsqlExprWalkerFlags(Node *node, sepgsqlWalkerContext *swc,
|
|
+ bool is_internal_use)
|
|
+{
|
|
+ bool saved_is_internal_use = swc->is_internal_use;
|
|
+
|
|
+ swc->is_internal_use = is_internal_use;
|
|
+ sepgsqlExprWalker(node, swc);
|
|
+ swc->is_internal_use = saved_is_internal_use;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlPostQueryRewrite
|
|
+ *
|
|
+ * This function is invoked just after given queries are rewritten
|
|
+ * via query-rewritter phase. It walks on given query trees to
|
|
+ * picks up all appeared tables and columns, and to chains the list
|
|
+ * of them on query->pgaceItem.
|
|
+ * This list is used to evaluate permissions later, just before
|
|
+ * the query execution.
|
|
+ *
|
|
+ * It do nothing for DDL queries, because these are processed in
|
|
+ * sepgsqlProcessUtility() hook.
|
|
+ */
|
|
+List *
|
|
+sepgsqlPostQueryRewrite(List *queryList)
|
|
+{
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, queryList)
|
|
+ {
|
|
+ Query *query = (Query *) lfirst(l);
|
|
+
|
|
+ Assert(IsA(query, Query));
|
|
+
|
|
+ if (query->commandType == CMD_SELECT ||
|
|
+ query->commandType == CMD_UPDATE ||
|
|
+ query->commandType == CMD_INSERT ||
|
|
+ query->commandType == CMD_DELETE)
|
|
+ {
|
|
+ query->pgaceItem
|
|
+ = (Node *) walkQueryHelper(query, NULL);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return queryList;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * checkSelinuxEvalItem
|
|
+ * checks give SelinuxEvalItem object based on the security
|
|
+ * policy of SELinux.
|
|
+ */
|
|
+static void
|
|
+checkSelinuxEvalItem(SelinuxEvalItem *seitem)
|
|
+{
|
|
+ Form_pg_class relForm;
|
|
+ Form_pg_attribute attForm;
|
|
+ HeapTuple tuple;
|
|
+ AttrNumber attno;
|
|
+ const char *audit_name;
|
|
+ int index;
|
|
+
|
|
+ Assert(IsA(seitem, SelinuxEvalItem));
|
|
+
|
|
+ /*
|
|
+ * Prevent to write pg_security by hand
|
|
+ */
|
|
+ if (seitem->relid == SecurityRelationId &&
|
|
+ (seitem->relperms & (DB_TABLE__UPDATE | DB_TABLE__INSERT | DB_TABLE__DELETE)))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not modify pg_security by hand")));
|
|
+
|
|
+ /*
|
|
+ * Permission checks on table
|
|
+ */
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(seitem->relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation: %u",
|
|
+ seitem->relid);
|
|
+ relForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+ if (relForm->relkind != RELKIND_RELATION)
|
|
+ {
|
|
+ ReleaseSysCache(tuple);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ audit_name = sepgsqlTupleName(RelationRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_DB_TABLE,
|
|
+ seitem->relperms,
|
|
+ audit_name);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ /*
|
|
+ * Expand whole-row-reference
|
|
+ */
|
|
+ index = seitem_attno_to_index(InvalidAttrNumber);
|
|
+ if (seitem->attperms[index] != 0)
|
|
+ {
|
|
+ uint32 perms = seitem->attperms[index];
|
|
+
|
|
+ seitem->attperms[index] = 0;
|
|
+ for (index++; index < seitem->nattrs; index++)
|
|
+ seitem->attperms[index] |= perms;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Permission checks on columns
|
|
+ */
|
|
+ for (index = 0; index < seitem->nattrs; index++)
|
|
+ {
|
|
+ if (seitem->attperms[index] == 0)
|
|
+ continue;
|
|
+
|
|
+ attno = seitem_index_to_attno(index);
|
|
+ tuple = SearchSysCache(ATTNUM,
|
|
+ ObjectIdGetDatum(seitem->relid),
|
|
+ Int16GetDatum(attno),
|
|
+ 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for attribute %d of relation %u",
|
|
+ attno, seitem->relid);
|
|
+ attForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ /*
|
|
+ * NOTE: When user uses whole-row-reference on a table
|
|
+ * which has already dropped column, the column can have
|
|
+ * non-zero required permissions, but being ignorable.
|
|
+ */
|
|
+ if (attForm->attisdropped)
|
|
+ {
|
|
+ ReleaseSysCache(tuple);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ audit_name = sepgsqlTupleName(AttributeRelationId, tuple);
|
|
+ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
|
|
+ SECCLASS_DB_COLUMN,
|
|
+ seitem->attperms[index],
|
|
+ audit_name);
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+}
|
|
+
|
|
+static List *
|
|
+expandEvalItemInheritance(List *selist)
|
|
+{
|
|
+ List *result = NIL;
|
|
+ List *inherits;
|
|
+ ListCell *l, *i;
|
|
+ int index;
|
|
+
|
|
+ foreach (l, selist)
|
|
+ {
|
|
+ SelinuxEvalItem *seitem = lfirst(l);
|
|
+
|
|
+ Assert(IsA(seitem, SelinuxEvalItem));
|
|
+
|
|
+ if (!seitem->inh)
|
|
+ {
|
|
+ result = lappend(result, seitem);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ inherits = find_all_inheritors(seitem->relid);
|
|
+ foreach (i, inherits)
|
|
+ {
|
|
+ result = addEvalRelation(result, lfirst_oid(i), false,
|
|
+ seitem->relperms);
|
|
+ for (index = 0; index < seitem->nattrs; index++)
|
|
+ {
|
|
+ Oid relid_inh = lfirst_oid(i);
|
|
+ AttrNumber attno;
|
|
+
|
|
+ if (seitem->attperms[index] == 0)
|
|
+ continue;
|
|
+
|
|
+ attno = seitem_index_to_attno(index);
|
|
+ if (attno < 1 || seitem->relid == relid_inh)
|
|
+ {
|
|
+ /*
|
|
+ * If attribute is system-column or whole-row-reference,
|
|
+ * or inherit relation is itself, we don't need to fix up
|
|
+ * attribute number.
|
|
+ */
|
|
+ result = addEvalAttribute(result, relid_inh, false,
|
|
+ attno, seitem->attperms[index]);
|
|
+ continue;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ char *attname = get_attname(seitem->relid, attno);
|
|
+
|
|
+ if (!attname)
|
|
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
|
|
+ attno, seitem->relid);
|
|
+
|
|
+ attno = get_attnum(relid_inh, attname);
|
|
+ if (attno == InvalidAttrNumber)
|
|
+ elog(ERROR, "cache lookup failed for attribute %s of relation %u",
|
|
+ attname, relid_inh);
|
|
+
|
|
+ result = addEvalAttribute(result, relid_inh, false,
|
|
+ attno, seitem->attperms[index]);
|
|
+ pfree(attname);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlExecutorStart
|
|
+ *
|
|
+ * This function is invoked at the head of ExecutorStart, to evaluate
|
|
+ * permissions to access appeared object within the given query.
|
|
+ * Query->pgaceItem is a list of SelinuxEvalItem objects generated in
|
|
+ * previous phase, and it is copied to PlannedStmt->pgaceItem in the
|
|
+ * optimizer.
|
|
+ * This functions expand given selist based on table inheritance,
|
|
+ * adds additional permissions related to trigger functions, and
|
|
+ * expands whole-row-references. Then, these items are evaluated
|
|
+ * based on the security policy of SELinux.
|
|
+ */
|
|
+void
|
|
+sepgsqlExecutorStart(QueryDesc *queryDesc, int eflags)
|
|
+{
|
|
+ PlannedStmt *pstmt = queryDesc->plannedstmt;
|
|
+ RangeTblEntry *rte;
|
|
+ List *selist;
|
|
+ ListCell *l;
|
|
+
|
|
+ /*
|
|
+ * EXPLAIN statement does not access any object.
|
|
+ */
|
|
+ if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
|
|
+ return;
|
|
+
|
|
+ if (!pstmt->pgaceItem)
|
|
+ return;
|
|
+
|
|
+ Assert(IsA(pstmt->pgaceItem, List));
|
|
+ selist = copyObject(pstmt->pgaceItem);
|
|
+
|
|
+ /*
|
|
+ * expand table inheritances
|
|
+ */
|
|
+ selist = expandEvalItemInheritance(selist);
|
|
+
|
|
+ /*
|
|
+ * add checks for access via trigger function
|
|
+ */
|
|
+ foreach(l, pstmt->resultRelations)
|
|
+ {
|
|
+ Index rindex = lfirst_int(l);
|
|
+
|
|
+ rte = rt_fetch(rindex, pstmt->rtable);
|
|
+ Assert(IsA(rte, RangeTblEntry));
|
|
+
|
|
+ selist = addEvalTriggerFunction(selist, rte->relid,
|
|
+ pstmt->commandType);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Check SelinuxEvalItem
|
|
+ */
|
|
+ foreach (l, selist)
|
|
+ checkSelinuxEvalItem((SelinuxEvalItem *) lfirst(l));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * --------------------------------------------------------------
|
|
+ * Process Utility hooks
|
|
+ * --------------------------------------------------------------
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * sepgsqlProcessUtility
|
|
+ *
|
|
+ * This function is invoked from the head of ProcessUtility(), and
|
|
+ * checks given DDL queries.
|
|
+ * SE-PostgreSQL catch most of DDL actions on HeapTuple hooks, but
|
|
+ * an exception is TRUNCATE statement.
|
|
+ */
|
|
+void
|
|
+sepgsqlProcessUtility(Node *parsetree, ParamListInfo params, bool isTopLevel)
|
|
+{
|
|
+ switch (nodeTag(parsetree))
|
|
+ {
|
|
+ case T_LoadStmt:
|
|
+ sepgsqlCheckModuleInstallPerms(((LoadStmt *)parsetree)->filename);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ /* do nothing */
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* ----------------------------------------------------------
|
|
+ * COPY TO/COPY FROM statement hooks
|
|
+ * ---------------------------------------------------------- */
|
|
+
|
|
+/*
|
|
+ * sepgsqlCopyTable
|
|
+ *
|
|
+ * This function checks permission on the target table and columns
|
|
+ * of COPY statement. We don't place it at sepgsql/hooks.c because
|
|
+ * it internally uses addEvalXXXX() interface statically declared.
|
|
+ */
|
|
+void
|
|
+sepgsqlCopyTable(Relation rel, List *attNumList, bool isFrom)
|
|
+{
|
|
+ List *selist = NIL;
|
|
+ ListCell *l;
|
|
+
|
|
+ /*
|
|
+ * on 'COPY FROM SELECT ...' cases, any checkings are done in select.c
|
|
+ */
|
|
+ if (rel == NULL)
|
|
+ return;
|
|
+
|
|
+ /*
|
|
+ * no need to check non-table relation
|
|
+ */
|
|
+ if (RelationGetForm(rel)->relkind != RELKIND_RELATION)
|
|
+ return;
|
|
+
|
|
+ selist = addEvalRelation(selist, RelationGetRelid(rel), false,
|
|
+ isFrom ? DB_TABLE__INSERT : DB_TABLE__SELECT);
|
|
+ foreach(l, attNumList)
|
|
+ {
|
|
+ AttrNumber attnum = lfirst_int(l);
|
|
+
|
|
+ selist = addEvalAttribute(selist, RelationGetRelid(rel), false, attnum,
|
|
+ isFrom ? DB_COLUMN__INSERT : DB_COLUMN__SELECT);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * check call trigger function
|
|
+ */
|
|
+ if (isFrom)
|
|
+ selist = addEvalTriggerFunction(selist, RelationGetRelid(rel), CMD_INSERT);
|
|
+
|
|
+ foreach (l, selist)
|
|
+ checkSelinuxEvalItem((SelinuxEvalItem *) lfirst(l));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCopyFile
|
|
+ *
|
|
+ * This function check permission whether the client can
|
|
+ * read from/write to the given file.
|
|
+ */
|
|
+void sepgsqlCopyFile(Relation rel, int fdesc, const char *filename, bool isFrom)
|
|
+{
|
|
+ security_context_t context;
|
|
+ security_class_t tclass
|
|
+ = sepgsqlFileObjectClass(fdesc, filename);
|
|
+
|
|
+ if (fgetfilecon_raw(fdesc, &context) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not get context of %s", filename)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePermission(sepgsqlGetClientContext(),
|
|
+ context,
|
|
+ tclass,
|
|
+ isFrom ? FILE__READ : FILE__WRITE,
|
|
+ filename);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(context);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * sepgsqlCopyToTuple
|
|
+ *
|
|
+ * This function check permission to read the given tuple.
|
|
+ * If not allowed to read, it returns false to skip COPY TO
|
|
+ * this tuple. In the result, any violated tuples are filtered
|
|
+ * from the result of COPY TO, as if these are not exist.
|
|
+ */
|
|
+bool
|
|
+sepgsqlCopyToTuple(Relation rel, List *attNumList, HeapTuple tuple)
|
|
+{
|
|
+ uint32 perms = SEPGSQL_PERMS_SELECT;
|
|
+
|
|
+ /*
|
|
+ * for 'pg_largeobject'
|
|
+ */
|
|
+ if (RelationGetRelid(rel) == LargeObjectRelationId)
|
|
+ {
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach(l, attNumList)
|
|
+ {
|
|
+ AttrNumber attnum = lfirst_int(l);
|
|
+
|
|
+ if (attnum == Anum_pg_largeobject_data)
|
|
+ {
|
|
+ perms |= SEPGSQL_PERMS_READ;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return sepgsqlCheckTuplePerms(rel, tuple, NULL, perms, false);
|
|
+}
|
|
diff -rpNU3 base/src/backend/storage/file/fd.c sepgsql/src/backend/storage/file/fd.c
|
|
--- base/src/backend/storage/file/fd.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/storage/file/fd.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -1241,6 +1241,13 @@ FileTruncate(File file, long offset)
|
|
return returnCode;
|
|
}
|
|
|
|
+int
|
|
+FileRawDescriptor(File file)
|
|
+{
|
|
+ Assert(FileIsValid(file));
|
|
+
|
|
+ return VfdCache[file].fd;
|
|
+}
|
|
|
|
/*
|
|
* Routines that want to use stdio (ie, FILE*) should use AllocateFile
|
|
diff -rpNU3 base/src/backend/storage/ipc/ipci.c sepgsql/src/backend/storage/ipc/ipci.c
|
|
--- base/src/backend/storage/ipc/ipci.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/storage/ipc/ipci.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -25,6 +25,7 @@
|
|
#include "postmaster/autovacuum.h"
|
|
#include "postmaster/bgwriter.h"
|
|
#include "postmaster/postmaster.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/freespace.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/pg_shmem.h"
|
|
@@ -117,6 +118,7 @@ CreateSharedMemoryAndSemaphores(bool mak
|
|
#ifdef EXEC_BACKEND
|
|
size = add_size(size, ShmemBackendArraySize());
|
|
#endif
|
|
+ size = add_size(size, pgaceShmemSize());
|
|
|
|
/* freeze the addin request size and include it */
|
|
addin_request_allowed = false;
|
|
diff -rpNU3 base/src/backend/tcop/fastpath.c sepgsql/src/backend/tcop/fastpath.c
|
|
--- base/src/backend/tcop/fastpath.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/tcop/fastpath.c 2009-01-16 17:07:29.000000000 +0900
|
|
@@ -28,6 +28,7 @@
|
|
#include "miscadmin.h"
|
|
#include "tcop/fastpath.h"
|
|
#include "tcop/tcopprot.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/lsyscache.h"
|
|
#include "utils/syscache.h"
|
|
@@ -347,6 +348,7 @@ HandleFunctionRequest(StringInfo msgBuf)
|
|
if (aclresult != ACLCHECK_OK)
|
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
|
get_func_name(fid));
|
|
+ pgaceCallFunction(&fip->flinfo);
|
|
|
|
/*
|
|
* Prepare function call info block and insert arguments.
|
|
diff -rpNU3 base/src/backend/tcop/pquery.c sepgsql/src/backend/tcop/pquery.c
|
|
--- base/src/backend/tcop/pquery.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/tcop/pquery.c 2008-11-21 23:11:55.000000000 +0900
|
|
@@ -560,7 +560,7 @@ PortalStart(Portal portal, ParamListInfo
|
|
Assert(pstmt->returningLists);
|
|
portal->tupDesc =
|
|
ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
|
|
- false);
|
|
+ false, false);
|
|
}
|
|
|
|
/*
|
|
diff -rpNU3 base/src/backend/tcop/utility.c sepgsql/src/backend/tcop/utility.c
|
|
--- base/src/backend/tcop/utility.c 2008-11-05 09:57:00.000000000 +0900
|
|
+++ sepgsql/src/backend/tcop/utility.c 2008-11-05 10:01:30.000000000 +0900
|
|
@@ -49,6 +49,7 @@
|
|
#include "postmaster/bgwriter.h"
|
|
#include "rewrite/rewriteDefine.h"
|
|
#include "rewrite/rewriteRemove.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/fd.h"
|
|
#include "tcop/pquery.h"
|
|
#include "tcop/utility.h"
|
|
@@ -397,6 +398,8 @@ ProcessUtility(Node *parsetree,
|
|
if (completionTag)
|
|
completionTag[0] = '\0';
|
|
|
|
+ pgaceProcessUtility(parsetree, params, isTopLevel);
|
|
+
|
|
switch (nodeTag(parsetree))
|
|
{
|
|
/*
|
|
diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/adt/ri_triggers.c
|
|
--- base/src/backend/utils/adt/ri_triggers.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/adt/ri_triggers.c 2009-02-25 22:31:25.000000000 +0900
|
|
@@ -37,6 +37,7 @@
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_relation.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -3256,6 +3257,7 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPl
|
|
int spi_result;
|
|
Oid save_userid;
|
|
bool save_secdefcxt;
|
|
+ bool save_pgace;
|
|
Datum vals[RI_MAX_NUMKEYS * 2];
|
|
char nulls[RI_MAX_NUMKEYS * 2];
|
|
|
|
@@ -3336,11 +3338,22 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPl
|
|
GetUserIdAndContext(&save_userid, &save_secdefcxt);
|
|
SetUserIdAndContext(RelationGetForm(query_rel)->relowner, true);
|
|
|
|
- /* Finally we can run the query. */
|
|
- spi_result = SPI_execute_snapshot(qplan,
|
|
- vals, nulls,
|
|
- test_snapshot, crosscheck_snapshot,
|
|
- false, false, limit);
|
|
+ save_pgace = pgaceRowlvBehaviorSwitchTo(detectNewRows);
|
|
+ PG_TRY();
|
|
+ {
|
|
+ /* Finally we can run the query. */
|
|
+ spi_result = SPI_execute_snapshot(qplan,
|
|
+ vals, nulls,
|
|
+ test_snapshot, crosscheck_snapshot,
|
|
+ false, false, limit);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ pgaceRowlvBehaviorSwitchTo(save_pgace);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ pgaceRowlvBehaviorSwitchTo(save_pgace);
|
|
|
|
/* Restore UID */
|
|
SetUserIdAndContext(save_userid, save_secdefcxt);
|
|
diff -rpNU3 base/src/backend/utils/cache/catcache.c sepgsql/src/backend/utils/cache/catcache.c
|
|
--- base/src/backend/utils/cache/catcache.c 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/cache/catcache.c 2009-01-16 17:07:29.000000000 +0900
|
|
@@ -1313,6 +1313,38 @@ ReleaseCatCache(HeapTuple tuple)
|
|
CatCacheRemoveCTup(ct->my_cache, ct);
|
|
}
|
|
|
|
+/*
|
|
+ * InsertCatCache
|
|
+ *
|
|
+ * This function enables to refer a tuple recently inserted, using catcache
|
|
+ * until next CommandCounterIncrement.
|
|
+ */
|
|
+void InsertCatCache(CatCache *cache, HeapTuple tuple)
|
|
+{
|
|
+ ScanKeyData skey[4];
|
|
+ uint32 hashValue;
|
|
+ Index hashIndex;
|
|
+ bool isnull;
|
|
+ int i;
|
|
+
|
|
+ /* initialize the search key information */
|
|
+ memcpy(skey, cache->cc_skey, sizeof(skey));
|
|
+ for (i=0; i < cache->cc_nkeys; i++)
|
|
+ {
|
|
+ skey[i].sk_argument = heap_getattr(tuple, cache->cc_key[i],
|
|
+ cache->cc_tupdesc, &isnull);
|
|
+ Assert(!isnull);
|
|
+ }
|
|
+
|
|
+ /* find the hash bucket in which to look for the tuple */
|
|
+ if (cache->cc_tupdesc == NULL)
|
|
+ CatalogCacheInitializeCache(cache);
|
|
+ hashValue = CatalogCacheComputeHashValue(cache, cache->cc_nkeys, skey);
|
|
+ hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
|
|
+
|
|
+ /* Insert a new tuple */
|
|
+ CatalogCacheCreateEntry(cache, tuple, hashValue, hashIndex, false);
|
|
+}
|
|
|
|
/*
|
|
* SearchCatCacheList
|
|
diff -rpNU3 base/src/backend/utils/cache/plancache.c sepgsql/src/backend/utils/cache/plancache.c
|
|
--- base/src/backend/utils/cache/plancache.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/cache/plancache.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -894,12 +894,14 @@ PlanCacheComputeResultDesc(List *stmt_li
|
|
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;
|
|
@@ -910,13 +912,15 @@ PlanCacheComputeResultDesc(List *stmt_li
|
|
{
|
|
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->returningLists);
|
|
- return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), false);
|
|
+ return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
|
|
+ false, false);
|
|
}
|
|
/* other cases shouldn't happen, but return NULL */
|
|
break;
|
|
diff -rpNU3 base/src/backend/utils/cache/relcache.c sepgsql/src/backend/utils/cache/relcache.c
|
|
--- base/src/backend/utils/cache/relcache.c 2009-02-02 11:47:17.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/cache/relcache.c 2009-02-02 11:58:34.000000000 +0900
|
|
@@ -54,6 +54,7 @@
|
|
#include "optimizer/prep.h"
|
|
#include "optimizer/var.h"
|
|
#include "rewrite/rewriteDefine.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/builtins.h"
|
|
@@ -324,7 +325,13 @@ AllocateRelationDesc(Relation relation,
|
|
/* initialize relation tuple form */
|
|
relation->rd_rel = relationForm;
|
|
|
|
- /* and allocate attribute tuple form storage */
|
|
+ /*
|
|
+ * and allocate attribute tuple form storage
|
|
+ *
|
|
+ * Please note that relation->rd_att->tdhasseclabel should be fixed
|
|
+ * up correctly at RelationBuildTupleDesc(), because security module
|
|
+ * may need reloptions info to make its decision.
|
|
+ */
|
|
relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts,
|
|
relationForm->relhasoids);
|
|
/* which we mark as a reference-counted tupdesc */
|
|
@@ -877,6 +884,10 @@ RelationBuildDesc(Oid targetRelId, Relat
|
|
/* extract reloptions if any */
|
|
RelationParseRelOptions(relation, pg_class_tuple);
|
|
|
|
+ /* fixup relation->rd_att->tdhasseclabel */
|
|
+ relation->rd_att->tdhasseclabel
|
|
+ = pgaceTupleDescHasSecLabel(relation, NIL);
|
|
+
|
|
/*
|
|
* initialize the relation lock manager information
|
|
*/
|
|
@@ -1462,6 +1473,12 @@ formrdesc(const char *relationName, Oid
|
|
relation->rd_rel->relfilenode = RelationGetRelid(relation);
|
|
|
|
/*
|
|
+ * Fixup relation->rd_att->tdhasseclabel
|
|
+ */
|
|
+ RelationGetDescr(relation)->tdhasseclabel
|
|
+ = pgaceTupleDescHasSecLabel(relation, NIL);
|
|
+
|
|
+ /*
|
|
* initialize the relation lock manager information
|
|
*/
|
|
RelationInitLockInfo(relation); /* see lmgr.c */
|
|
@@ -2687,6 +2704,13 @@ BuildHardcodedDescriptor(int natts, Form
|
|
|
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
|
|
|
+ /*
|
|
+ * NOTE: we assume the returned TupleDesc is only used for
|
|
+ * references to toast'ed data, and it is not delivered to
|
|
+ * heap_form_tuple(), so TupleDesc->tdhasseclabel does not
|
|
+ * give any effect.
|
|
+ * We omit to invoke pgaceTupleDescHasSecurity() here.
|
|
+ */
|
|
result = CreateTemplateTupleDesc(natts, hasoids);
|
|
result->tdtypeid = RECORDOID; /* not right, but we don't care */
|
|
result->tdtypmod = -1;
|
|
@@ -3446,6 +3470,12 @@ load_relcache_init_file(void)
|
|
rel->rd_options = NULL;
|
|
}
|
|
|
|
+ /*
|
|
+ * fixup rel->rd_att->tdhasseclabel
|
|
+ */
|
|
+ rel->rd_att->tdhasseclabel
|
|
+ = pgaceTupleDescHasSecLabel(rel, NIL);
|
|
+
|
|
/* mark not-null status */
|
|
if (has_not_null)
|
|
{
|
|
diff -rpNU3 base/src/backend/utils/cache/syscache.c sepgsql/src/backend/utils/cache/syscache.c
|
|
--- base/src/backend/utils/cache/syscache.c 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/cache/syscache.c 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -39,6 +39,7 @@
|
|
#include "catalog/pg_opfamily.h"
|
|
#include "catalog/pg_proc.h"
|
|
#include "catalog/pg_rewrite.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_statistic.h"
|
|
#include "catalog/pg_ts_config.h"
|
|
#include "catalog/pg_ts_config_map.h"
|
|
@@ -676,7 +677,31 @@ static const struct cachedesc cacheinfo[
|
|
0
|
|
},
|
|
1024
|
|
- }
|
|
+ },
|
|
+ {SecurityRelationId, /*SECURITYOID */
|
|
+ SecurityOidIndexId,
|
|
+ 0,
|
|
+ 1,
|
|
+ {
|
|
+ ObjectIdAttributeNumber,
|
|
+ 0,
|
|
+ 0,
|
|
+ 0
|
|
+ },
|
|
+ 128
|
|
+ },
|
|
+ {SecurityRelationId, /* SECURITYLABEL */
|
|
+ SecuritySeclabelIndexId,
|
|
+ 0,
|
|
+ 1,
|
|
+ {
|
|
+ Anum_pg_security_seclabel,
|
|
+ 0,
|
|
+ 0,
|
|
+ 0
|
|
+ },
|
|
+ 128
|
|
+ },
|
|
};
|
|
|
|
static CatCache *SysCache[
|
|
@@ -784,6 +809,21 @@ ReleaseSysCache(HeapTuple tuple)
|
|
}
|
|
|
|
/*
|
|
+ * InsertSysCache
|
|
+ * interts a tuple temporary until next CommandCounterIncrement
|
|
+ */
|
|
+void InsertSysCache(Oid relid, HeapTuple tuple)
|
|
+{
|
|
+ int cacheId;
|
|
+
|
|
+ for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
|
|
+ {
|
|
+ if (SysCache[cacheId]->cc_reloid == relid)
|
|
+ InsertCatCache(SysCache[cacheId], tuple);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
* SearchSysCacheCopy
|
|
*
|
|
* A convenience routine that does SearchSysCache and (if successful)
|
|
diff -rpNU3 base/src/backend/utils/fmgr/dfmgr.c sepgsql/src/backend/utils/fmgr/dfmgr.c
|
|
--- base/src/backend/utils/fmgr/dfmgr.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/fmgr/dfmgr.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -22,6 +22,7 @@
|
|
#include "port/dynloader/win32.h"
|
|
#endif
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/dynamic_loader.h"
|
|
#include "utils/hsearch.h"
|
|
|
|
@@ -73,7 +74,6 @@ char *Dynamic_library_path;
|
|
static void *internal_load_library(const char *libname);
|
|
static void internal_unload_library(const char *libname);
|
|
static bool file_exists(const char *name);
|
|
-static char *expand_dynamic_library_name(const char *name);
|
|
static void check_restricted_library_name(const char *name);
|
|
static char *substitute_libpath_macro(const char *name);
|
|
static char *find_in_dynamic_libpath(const char *basename);
|
|
@@ -106,6 +106,9 @@ load_external_function(char *filename, c
|
|
/* Expand the possibly-abbreviated filename to an exact path name */
|
|
fullname = expand_dynamic_library_name(filename);
|
|
|
|
+ /* Check whether the shared library should be loaded, or not */
|
|
+ pgaceLoadSharedModule(fullname);
|
|
+
|
|
/* Load the shared library, unless we already did */
|
|
lib_handle = internal_load_library(fullname);
|
|
|
|
@@ -146,6 +149,9 @@ load_file(const char *filename, bool res
|
|
/* Expand the possibly-abbreviated filename to an exact path name */
|
|
fullname = expand_dynamic_library_name(filename);
|
|
|
|
+ /* Check whether the library should be loaded, or not */
|
|
+ pgaceLoadSharedModule(fullname);
|
|
+
|
|
/* Unload the library if currently loaded */
|
|
internal_unload_library(fullname);
|
|
|
|
@@ -403,7 +409,7 @@ file_exists(const char *name)
|
|
*
|
|
* The result will always be freshly palloc'd.
|
|
*/
|
|
-static char *
|
|
+char *
|
|
expand_dynamic_library_name(const char *name)
|
|
{
|
|
bool have_slash;
|
|
diff -rpNU3 base/src/backend/utils/init/postinit.c sepgsql/src/backend/utils/init/postinit.c
|
|
--- base/src/backend/utils/init/postinit.c 2008-09-25 15:09:40.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/init/postinit.c 2008-09-25 15:22:04.000000000 +0900
|
|
@@ -31,6 +31,7 @@
|
|
#include "pgstat.h"
|
|
#include "postmaster/autovacuum.h"
|
|
#include "postmaster/postmaster.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/backendid.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/ipc.h"
|
|
@@ -607,6 +608,9 @@ InitPostgres(const char *in_dbname, Oid
|
|
if (!bootstrap)
|
|
pgstat_bestart();
|
|
|
|
+ /* initialize mandatory access control facilities */
|
|
+ pgaceInitialize(bootstrap);
|
|
+
|
|
/* close the transaction we started above */
|
|
if (!bootstrap)
|
|
CommitTransactionCommand();
|
|
diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc.c
|
|
--- base/src/backend/utils/misc/guc.c 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/misc/guc.c 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -54,6 +54,7 @@
|
|
#include "postmaster/postmaster.h"
|
|
#include "postmaster/syslogger.h"
|
|
#include "postmaster/walwriter.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/freespace.h"
|
|
#include "tcop/tcopprot.h"
|
|
@@ -273,7 +274,6 @@ static bool integer_datetimes;
|
|
char *role_string;
|
|
char *session_authorization_string;
|
|
|
|
-
|
|
/*
|
|
* Displayable names for context types (enum GucContext)
|
|
*
|
|
@@ -2460,6 +2460,26 @@ static struct config_string ConfigureNam
|
|
},
|
|
#endif /* USE_SSL */
|
|
|
|
+ {
|
|
+ {"pgace_feature", PGC_POSTMASTER, UNGROUPED,
|
|
+ gettext_noop("A option to choose an enhanced security feature which is "
|
|
+ "a guest of PGACE security framework"),
|
|
+ NULL,
|
|
+ },
|
|
+ &pgace_feature_string,
|
|
+ "none", pgaceAssignFeatureString, NULL,
|
|
+ },
|
|
+#ifdef HAVE_SELINUX
|
|
+ {
|
|
+ {"sepostgresql", PGC_POSTMASTER, PRESET_OPTIONS,
|
|
+ gettext_noop("SE-PostgreSQL mode (default|permissive|enforcing|disabled)"),
|
|
+ NULL,
|
|
+ },
|
|
+ &sepostgresql_mode_string,
|
|
+ "default", sepgsqlAssignModeString, NULL,
|
|
+ },
|
|
+#endif
|
|
+
|
|
/* End-of-list marker */
|
|
{
|
|
{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
|
|
@@ -3300,6 +3320,8 @@ ResetAllOptions(void)
|
|
{
|
|
int i;
|
|
|
|
+ pgaceSetDatabaseParam("all", NULL);
|
|
+
|
|
for (i = 0; i < num_guc_variables; i++)
|
|
{
|
|
struct config_generic *gconf = guc_variables[i];
|
|
@@ -5002,6 +5024,7 @@ ExecSetVariableStmt(VariableSetStmt *stm
|
|
{
|
|
case VAR_SET_VALUE:
|
|
case VAR_SET_CURRENT:
|
|
+ pgaceSetDatabaseParam(stmt->name, ExtractSetVariableArgs(stmt));
|
|
set_config_option(stmt->name,
|
|
ExtractSetVariableArgs(stmt),
|
|
(superuser() ? PGC_SUSET : PGC_USERSET),
|
|
@@ -5059,6 +5082,7 @@ ExecSetVariableStmt(VariableSetStmt *stm
|
|
break;
|
|
case VAR_SET_DEFAULT:
|
|
case VAR_RESET:
|
|
+ pgaceSetDatabaseParam(stmt->name, NULL);
|
|
set_config_option(stmt->name,
|
|
NULL,
|
|
(superuser() ? PGC_SUSET : PGC_USERSET),
|
|
@@ -5387,6 +5411,9 @@ EmitWarningsOnPlaceholders(const char *c
|
|
void
|
|
GetPGVariable(const char *name, DestReceiver *dest)
|
|
{
|
|
+ /* Check get param permissions */
|
|
+ pgaceGetDatabaseParam(name);
|
|
+
|
|
if (guc_name_compare(name, "all") == 0)
|
|
ShowAllGUCConfig(dest);
|
|
else
|
|
diff -rpNU3 base/src/backend/utils/misc/postgresql.conf.sample sepgsql/src/backend/utils/misc/postgresql.conf.sample
|
|
--- base/src/backend/utils/misc/postgresql.conf.sample 2008-02-03 01:11:28.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/misc/postgresql.conf.sample 2008-12-28 01:19:14.000000000 +0900
|
|
@@ -487,6 +487,12 @@
|
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
+# ENHANCED SECURITY OPTIONS
|
|
+#------------------------------------------------------------------------------
|
|
+
|
|
+#pgace_feature = 'none'
|
|
+
|
|
+#------------------------------------------------------------------------------
|
|
# CUSTOMIZED OPTIONS
|
|
#------------------------------------------------------------------------------
|
|
|
|
diff -rpNU3 base/src/include/access/heapam.h sepgsql/src/include/access/heapam.h
|
|
--- base/src/include/access/heapam.h 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql/src/include/access/heapam.h 2008-11-21 23:11:55.000000000 +0900
|
|
@@ -249,7 +249,7 @@ extern void heap_free_minimal_tuple(Mini
|
|
extern MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup);
|
|
extern HeapTuple heap_tuple_from_minimal_tuple(MinimalTuple mtup);
|
|
extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup);
|
|
-extern HeapTuple heap_addheader(int natts, bool withoid,
|
|
+extern HeapTuple heap_addheader(int natts, bool withoid, bool withsecurity,
|
|
Size structlen, void *structure);
|
|
|
|
/* in heap/pruneheap.c */
|
|
diff -rpNU3 base/src/include/access/htup.h sepgsql/src/include/access/htup.h
|
|
--- base/src/include/access/htup.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/access/htup.h 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -161,7 +161,7 @@ typedef HeapTupleHeaderData *HeapTupleHe
|
|
#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_HAS_SECLABEL 0x0010 /* has an security label 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 */
|
|
@@ -288,6 +288,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) ? \
|
|
@@ -347,6 +350,34 @@ do { \
|
|
(tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \
|
|
)
|
|
|
|
+#define HeapTupleHeaderHasSecLabel(tup) \
|
|
+ ((tup)->t_infomask & HEAP_HAS_SECLABEL)
|
|
+
|
|
+#define HeapTupleHeaderGetSecLabel(tup) \
|
|
+ ( \
|
|
+ HeapTupleHeaderHasSecLabel(tup) \
|
|
+ ? (*((Oid *)((char *)(tup) + (tup)->t_hoff \
|
|
+ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \
|
|
+ - sizeof(Oid)))) \
|
|
+ : InvalidOid \
|
|
+ )
|
|
+
|
|
+#define HeapTupleHeaderSetSecLabel(tup, seclabel) \
|
|
+ do { \
|
|
+ Assert(HeapTupleHeaderHasSecLabel(tup)); \
|
|
+ *((Oid *)((char *)(tup) + (tup)->t_hoff \
|
|
+ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \
|
|
+ - sizeof(Oid))) = (seclabel); \
|
|
+ } while(0)
|
|
+
|
|
+#define HeapTupleHasSecLabel(tuple) \
|
|
+ HeapTupleHeaderHasSecLabel((tuple)->t_data)
|
|
+
|
|
+#define HeapTupleGetSecLabel(tuple) \
|
|
+ HeapTupleHeaderGetSecLabel((tuple)->t_data)
|
|
+
|
|
+#define HeapTupleSetSecLabel(tuple, seclabel) \
|
|
+ HeapTupleHeaderSetSecLabel((tuple)->t_data, (seclabel))
|
|
|
|
/*
|
|
* BITMAPLEN(NATTS) -
|
|
@@ -402,8 +433,8 @@ do { \
|
|
#define MaxTransactionIdAttributeNumber (-5)
|
|
#define MaxCommandIdAttributeNumber (-6)
|
|
#define TableOidAttributeNumber (-7)
|
|
-#define FirstLowInvalidHeapAttributeNumber (-8)
|
|
-
|
|
+#define SecurityLabelAttributeNumber (-8)
|
|
+#define FirstLowInvalidHeapAttributeNumber (-9)
|
|
|
|
/*
|
|
* MinimalTuple is an alternative representation that is used for transient
|
|
@@ -548,6 +579,9 @@ typedef HeapTupleData *HeapTuple;
|
|
#define HeapTupleClearHeapOnly(tuple) \
|
|
HeapTupleHeaderClearHeapOnly((tuple)->t_data)
|
|
|
|
+#define HeapTupleHasOid(tuple) \
|
|
+ HeapTupleHeaderHasOid((tuple)->t_data)
|
|
+
|
|
#define HeapTupleGetOid(tuple) \
|
|
HeapTupleHeaderGetOid((tuple)->t_data)
|
|
|
|
diff -rpNU3 base/src/include/access/tupdesc.h sepgsql/src/include/access/tupdesc.h
|
|
--- base/src/include/access/tupdesc.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/access/tupdesc.h 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -75,6 +75,7 @@ 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 tdhasseclabel; /* tuple has security label in its header */
|
|
int tdrefcount; /* reference count, or -1 if not counting */
|
|
} *TupleDesc;
|
|
|
|
diff -rpNU3 base/src/include/catalog/heap.h sepgsql/src/include/catalog/heap.h
|
|
--- base/src/include/catalog/heap.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/heap.h 2008-12-05 16:28:22.000000000 +0900
|
|
@@ -52,7 +52,8 @@ extern Oid heap_create_with_catalog(cons
|
|
int oidinhcount,
|
|
OnCommitAction oncommit,
|
|
Datum reloptions,
|
|
- bool allow_system_table_mods);
|
|
+ bool allow_system_table_mods,
|
|
+ List *pgace_attr_list);
|
|
|
|
extern void heap_drop_with_catalog(Oid relid);
|
|
|
|
@@ -65,7 +66,8 @@ extern List *heap_truncate_find_FKs(List
|
|
extern void InsertPgClassTuple(Relation pg_class_desc,
|
|
Relation new_rel_desc,
|
|
Oid new_rel_oid,
|
|
- Datum reloptions);
|
|
+ Datum reloptions,
|
|
+ List *pgace_attr_list);
|
|
|
|
extern List *AddRelationRawConstraints(Relation rel,
|
|
List *rawColDefaults,
|
|
@@ -96,6 +98,8 @@ extern Form_pg_attribute SystemAttribute
|
|
extern Form_pg_attribute SystemAttributeByName(const char *attname,
|
|
bool relhasoids);
|
|
|
|
+extern bool SystemAttributeIsWritable(AttrNumber attnum);
|
|
+
|
|
extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind);
|
|
|
|
extern void CheckAttributeType(const char *attname, Oid atttypid);
|
|
diff -rpNU3 base/src/include/catalog/indexing.h sepgsql/src/include/catalog/indexing.h
|
|
--- base/src/include/catalog/indexing.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/indexing.h 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -252,6 +252,11 @@ DECLARE_UNIQUE_INDEX(pg_type_oid_index,
|
|
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_security_oid_index, 3401, on pg_security using btree(oid oid_ops));
|
|
+#define SecurityOidIndexId 3401
|
|
+DECLARE_UNIQUE_INDEX(pg_security_seclabel_index, 3402, on pg_security using btree(seclabel text_ops));
|
|
+#define SecuritySeclabelIndexId 3402
|
|
+
|
|
/* last step of initialization script: build the indexes declared above */
|
|
BUILD_INDICES
|
|
|
|
diff -rpNU3 base/src/include/catalog/pg_attribute.h sepgsql/src/include/catalog/pg_attribute.h
|
|
--- base/src/include/catalog/pg_attribute.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/pg_attribute.h 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -282,6 +282,7 @@ DATA(insert ( 1247 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1247 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_proc
|
|
@@ -338,6 +339,7 @@ DATA(insert ( 1255 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1255 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_attribute
|
|
@@ -386,6 +388,7 @@ DATA(insert ( 1249 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1249 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_class
|
|
@@ -454,6 +457,7 @@ DATA(insert ( 1259 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1259 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_index
|
|
diff -rpNU3 base/src/include/catalog/pg_proc.h sepgsql/src/include/catalog/pg_proc.h
|
|
--- base/src/include/catalog/pg_proc.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/pg_proc.h 2008-09-30 11:51:54.000000000 +0900
|
|
@@ -4113,6 +4113,22 @@ DESCR("I/O");
|
|
DATA(insert OID = 2963 ( uuid_hash PGNSP PGUID 12 1 0 f f t f i 1 23 "2950" _null_ _null_ _null_ uuid_hash - _null_ _null_ ));
|
|
DESCR("hash");
|
|
|
|
+/* PostgreSQL Access Control Extension related functions */
|
|
+DATA(insert OID = 3410 ( lo_get_security PGNSP PGUID 12 1 0 f f t f v 1 25 "26" _null_ _null_ _null_ lo_get_security - _null_ _null_ ));
|
|
+DATA(insert OID = 3411 ( lo_set_security PGNSP PGUID 12 1 0 f f t f v 2 16 "26 25" _null_ _null_ _null_ lo_set_security - _null_ _null_ ));
|
|
+
|
|
+/* SE-PostgreSQL related function */
|
|
+DATA(insert OID = 3450 ( sepgsql_getcon PGNSP PGUID 12 1 0 f f t f v 0 25 "" _null_ _null_ _null_ sepgsql_getcon - _null_ _null_ ));
|
|
+DATA(insert OID = 3451 ( sepgsql_getservcon PGNSP PGUID 12 1 0 f f t f v 0 25 "" _null_ _null_ _null_ sepgsql_getservcon - _null_ _null_ ));
|
|
+DATA(insert OID = 3452 ( sepgsql_get_user PGNSP PGUID 12 1 0 f f t f v 1 25 "25" _null_ _null_ _null_ sepgsql_get_user - _null_ _null_ ));
|
|
+DATA(insert OID = 3453 ( sepgsql_set_user PGNSP PGUID 12 1 0 f f t f v 2 25 "25 25" _null_ _null_ _null_ sepgsql_set_user - _null_ _null_ ));
|
|
+DATA(insert OID = 3454 ( sepgsql_get_role PGNSP PGUID 12 1 0 f f t f v 1 25 "25" _null_ _null_ _null_ sepgsql_get_role - _null_ _null_ ));
|
|
+DATA(insert OID = 3455 ( sepgsql_set_role PGNSP PGUID 12 1 0 f f t f v 2 25 "25 25" _null_ _null_ _null_ sepgsql_set_role - _null_ _null_ ));
|
|
+DATA(insert OID = 3456 ( sepgsql_get_type PGNSP PGUID 12 1 0 f f t f v 1 25 "25" _null_ _null_ _null_ sepgsql_get_type - _null_ _null_ ));
|
|
+DATA(insert OID = 3457 ( sepgsql_set_type PGNSP PGUID 12 1 0 f f t f v 2 25 "25 25" _null_ _null_ _null_ sepgsql_set_type - _null_ _null_ ));
|
|
+DATA(insert OID = 3458 ( sepgsql_get_range PGNSP PGUID 12 1 0 f f t f v 1 25 "25" _null_ _null_ _null_ sepgsql_get_range - _null_ _null_ ));
|
|
+DATA(insert OID = 3459 ( sepgsql_set_range PGNSP PGUID 12 1 0 f f t f v 2 25 "25 25" _null_ _null_ _null_ sepgsql_set_range - _null_ _null_ ));
|
|
+
|
|
/* enum related procs */
|
|
DATA(insert OID = 3504 ( anyenum_in PGNSP PGUID 12 1 0 f f t f i 1 3500 "2275" _null_ _null_ _null_ anyenum_in - _null_ _null_ ));
|
|
DESCR("I/O");
|
|
@@ -4460,7 +4476,8 @@ extern Oid ProcedureCreate(const char *p
|
|
Datum parameterNames,
|
|
Datum proconfig,
|
|
float4 procost,
|
|
- float4 prorows);
|
|
+ float4 prorows,
|
|
+ void *pgaceItem);
|
|
|
|
extern bool function_parse_error_transpose(const char *prosrc);
|
|
|
|
diff -rpNU3 base/src/include/catalog/pg_security.h sepgsql/src/include/catalog/pg_security.h
|
|
--- base/src/include/catalog/pg_security.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/pg_security.h 2008-06-15 22:24:53.000000000 +0900
|
|
@@ -0,0 +1,31 @@
|
|
+/*
|
|
+ * src/include/catalog/pg_security.h
|
|
+ * Definition of the security label relation (pg_security)
|
|
+ *
|
|
+ * Copyright (c) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+ */
|
|
+#ifndef PG_SECURITY_H
|
|
+#define PG_SECURITY_H
|
|
+
|
|
+#define SecurityRelationId 3400
|
|
+
|
|
+CATALOG(pg_security,3400) BKI_SHARED_RELATION
|
|
+{
|
|
+ text seclabel; /* text representation of security label */
|
|
+} FormData_pg_security;
|
|
+
|
|
+/* ----------------
|
|
+ * Form_pg_security corresponds to a pointer to a tuple with
|
|
+ * the format of pg_security relation.
|
|
+ * ----------------
|
|
+ */
|
|
+typedef FormData_pg_security *Form_pg_security;
|
|
+
|
|
+/* ----------------
|
|
+ * compiler constants for pg_selinux
|
|
+ * ----------------
|
|
+ */
|
|
+#define Natts_pg_security 1
|
|
+#define Anum_pg_security_seclabel 1
|
|
+
|
|
+#endif /* PG_SELINUX_H */
|
|
diff -rpNU3 base/src/include/executor/executor.h sepgsql/src/include/executor/executor.h
|
|
--- base/src/include/executor/executor.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/executor/executor.h 2008-12-28 01:06:59.000000000 +0900
|
|
@@ -116,7 +116,7 @@ extern TupleHashEntry FindTupleHashEntry
|
|
/*
|
|
* prototypes from functions in execJunk.c
|
|
*/
|
|
-extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid,
|
|
+extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid, bool hassecurity,
|
|
TupleTableSlot *slot);
|
|
extern JunkFilter *ExecInitJunkFilterConversion(List *targetList,
|
|
TupleDesc cleanTupType,
|
|
@@ -140,6 +140,7 @@ extern void ExecutorEnd(QueryDesc *query
|
|
extern void ExecutorRewind(QueryDesc *queryDesc);
|
|
extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
|
|
extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
|
|
+extern bool ExecContextForcesSecLabel(PlanState *planstate, bool *hasseclabel);
|
|
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
|
|
TupleTableSlot *slot, EState *estate);
|
|
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
|
@@ -199,8 +200,8 @@ extern void ExecInitScanTupleSlot(EState
|
|
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 hasseclabel);
|
|
+extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hasseclabel);
|
|
extern TupleDesc ExecTypeFromExprList(List *exprList);
|
|
extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);
|
|
|
|
diff -rpNU3 base/src/include/executor/tuptable.h sepgsql/src/include/executor/tuptable.h
|
|
--- base/src/include/executor/tuptable.h 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/include/executor/tuptable.h 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -127,6 +127,9 @@ typedef struct TupleTableSlot
|
|
MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */
|
|
HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */
|
|
long tts_off; /* saved state for slot_deform_tuple */
|
|
+
|
|
+ /* temporary storage variables for writable system column */
|
|
+ Datum tts_seclabel; /* for security label */
|
|
} TupleTableSlot;
|
|
|
|
#define TTS_HAS_PHYSICAL_TUPLE(slot) \
|
|
diff -rpNU3 base/src/include/fmgr.h sepgsql/src/include/fmgr.h
|
|
--- base/src/include/fmgr.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/fmgr.h 2009-01-16 17:07:29.000000000 +0900
|
|
@@ -52,6 +52,8 @@ typedef struct FmgrInfo
|
|
void *fn_extra; /* extra space for use by handler */
|
|
MemoryContext fn_mcxt; /* memory context to store fn_extra in */
|
|
fmNodePtr fn_expr; /* expression parse tree for call, or NULL */
|
|
+
|
|
+ void *fn_pgaceItem; /* PGACE opaque field */
|
|
} FmgrInfo;
|
|
|
|
/*
|
|
@@ -511,6 +513,7 @@ extern Oid get_call_expr_argtype(fmNodeP
|
|
*/
|
|
extern char *Dynamic_library_path;
|
|
|
|
+extern char *expand_dynamic_library_name(const char *name);
|
|
extern PGFunction load_external_function(char *filename, char *funcname,
|
|
bool signalNotFound, void **filehandle);
|
|
extern PGFunction lookup_external_function(void *filehandle, char *funcname);
|
|
diff -rpNU3 base/src/include/libpq/be-fsstubs.h sepgsql/src/include/libpq/be-fsstubs.h
|
|
--- base/src/include/libpq/be-fsstubs.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/libpq/be-fsstubs.h 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -36,6 +36,9 @@ extern Datum lo_tell(PG_FUNCTION_ARGS);
|
|
extern Datum lo_unlink(PG_FUNCTION_ARGS);
|
|
extern Datum lo_truncate(PG_FUNCTION_ARGS);
|
|
|
|
+extern Datum lo_get_security(PG_FUNCTION_ARGS);
|
|
+extern Datum lo_set_security(PG_FUNCTION_ARGS);
|
|
+
|
|
/*
|
|
* These are not fmgr-callable, but are available to C code.
|
|
* Probably these should have had the underscore-free names,
|
|
diff -rpNU3 base/src/include/nodes/nodes.h sepgsql/src/include/nodes/nodes.h
|
|
--- base/src/include/nodes/nodes.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/nodes/nodes.h 2009-01-21 17:02:57.000000000 +0900
|
|
@@ -358,7 +358,9 @@ typedef enum NodeTag
|
|
*/
|
|
T_TriggerData = 950, /* in commands/trigger.h */
|
|
T_ReturnSetInfo, /* in nodes/execnodes.h */
|
|
- T_TIDBitmap /* in nodes/tidbitmap.h */
|
|
+ T_TIDBitmap, /* in nodes/tidbitmap.h */
|
|
+ T_SelinuxEvalItem, /* in nodes/security.h */
|
|
+ T_SEvalItemProcedure, /* in nodes/security.h */
|
|
} NodeTag;
|
|
|
|
/*
|
|
diff -rpNU3 base/src/include/nodes/parsenodes.h sepgsql/src/include/nodes/parsenodes.h
|
|
--- base/src/include/nodes/parsenodes.h 2008-03-19 09:48:23.000000000 +0900
|
|
+++ sepgsql/src/include/nodes/parsenodes.h 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -131,6 +131,7 @@ typedef struct Query
|
|
|
|
Node *setOperations; /* set-operation tree if this is top level of
|
|
* a UNION/INTERSECT/EXCEPT query */
|
|
+ Node *pgaceItem; /* PGACE: an opaque item for security purpose */
|
|
} Query;
|
|
|
|
|
|
@@ -391,6 +392,7 @@ typedef struct ColumnDef
|
|
Node *raw_default; /* default value (untransformed parse tree) */
|
|
char *cooked_default; /* nodeToString representation */
|
|
List *constraints; /* other constraints on column */
|
|
+ Node *pgaceItem; /* PGACE: security attribute */
|
|
} ColumnDef;
|
|
|
|
/*
|
|
@@ -602,6 +604,15 @@ typedef struct RangeTblEntry
|
|
bool inFromCl; /* present in FROM clause? */
|
|
AclMode requiredPerms; /* bitmask of required access permissions */
|
|
Oid checkAsUser; /* if valid, check access as this role */
|
|
+
|
|
+ /*
|
|
+ * The guest of PGACE can use pgaceTuplePerms to mark permission set
|
|
+ * of tuple-level access controls. This field is copied to scan node
|
|
+ * (like SeqSan), and it can be refered within pgaceExecScan() hook.
|
|
+ * If this hook returns false, the given tuple is filtered from the
|
|
+ * result set.
|
|
+ */
|
|
+ uint32 pgaceTuplePerms;
|
|
} RangeTblEntry;
|
|
|
|
/*
|
|
@@ -917,7 +928,8 @@ typedef enum AlterTableType
|
|
AT_EnableReplicaRule, /* ENABLE REPLICA RULE name */
|
|
AT_DisableRule, /* DISABLE RULE name */
|
|
AT_AddInherit, /* INHERIT parent */
|
|
- AT_DropInherit /* NO INHERIT parent */
|
|
+ AT_DropInherit, /* NO INHERIT parent */
|
|
+ AT_SetSecurityLabel, /* PGACE: set security label */
|
|
} AlterTableType;
|
|
|
|
typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
|
|
@@ -1108,6 +1120,7 @@ typedef struct CreateStmt
|
|
List *options; /* options from WITH clause */
|
|
OnCommitAction oncommit; /* what do we do at COMMIT? */
|
|
char *tablespacename; /* table space to use, or NULL */
|
|
+ Node *pgaceItem; /* PGACE: security attribute */
|
|
} CreateStmt;
|
|
|
|
/* ----------
|
|
diff -rpNU3 base/src/include/nodes/plannodes.h sepgsql/src/include/nodes/plannodes.h
|
|
--- base/src/include/nodes/plannodes.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/nodes/plannodes.h 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -73,6 +73,8 @@ typedef struct PlannedStmt
|
|
List *relationOids; /* OIDs of relations the plan depends on */
|
|
|
|
int nParamExec; /* number of PARAM_EXEC Params used */
|
|
+
|
|
+ Node *pgaceItem; /* PGACE: an opaque item for security purpose */
|
|
} PlannedStmt;
|
|
|
|
/* macro for fetching the Plan associated with a SubPlan node */
|
|
@@ -216,6 +218,14 @@ typedef struct Scan
|
|
{
|
|
Plan plan;
|
|
Index scanrelid; /* relid is index into the range table */
|
|
+
|
|
+ /*
|
|
+ * pgaceTuplePerms is used to show permission set to be applied to
|
|
+ * tuple-leve access controls by security module.
|
|
+ * It is copied from related RangeTblEntry's one when Scan structure
|
|
+ * is created.
|
|
+ */
|
|
+ uint32 pgaceTuplePerms;
|
|
} Scan;
|
|
|
|
/* ----------------
|
|
diff -rpNU3 base/src/include/nodes/relation.h sepgsql/src/include/nodes/relation.h
|
|
--- base/src/include/nodes/relation.h 2009-09-10 20:11:35.000000000 +0900
|
|
+++ sepgsql/src/include/nodes/relation.h 2009-09-10 20:54:22.000000000 +0900
|
|
@@ -366,6 +366,8 @@ typedef struct RelOptInfo
|
|
* list just to avoid recomputing the best inner indexscan repeatedly for
|
|
* similar outer relations. See comments for InnerIndexscanInfo.
|
|
*/
|
|
+
|
|
+ uint32 pgaceTuplePerms; /* copied from RangeTblEntry */
|
|
} RelOptInfo;
|
|
|
|
/*
|
|
diff -rpNU3 base/src/include/nodes/security.h sepgsql/src/include/nodes/security.h
|
|
--- base/src/include/nodes/security.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/include/nodes/security.h 2009-01-21 17:02:57.000000000 +0900
|
|
@@ -0,0 +1,40 @@
|
|
+/*-------------------------------------------------------------------------
|
|
+ *
|
|
+ * src/include/nodes/security.h
|
|
+ * definitions for security extention related nodes
|
|
+ *
|
|
+ * Portions Copyright (c) 2007-2008, PostgreSQL Global Development Group
|
|
+ *
|
|
+ *-------------------------------------------------------------------------
|
|
+ */
|
|
+#ifndef NODES_SECURITY_H
|
|
+#define NODES_SECURITY_H
|
|
+
|
|
+#include "access/attnum.h"
|
|
+#include "nodes/nodes.h"
|
|
+
|
|
+/*
|
|
+ * SelinuxEvalItem
|
|
+ *
|
|
+ * Required permissions on tables/columns used by SE-PostgreSQL.
|
|
+ * It is constracted just after query rewriter phase, then its
|
|
+ * list is checked based on the security policy of operating
|
|
+ * system.
|
|
+ *
|
|
+ * NOTE: attperms array can contains system attributes and
|
|
+ * whole-row-reference, so it is indexed as
|
|
+ * attperms[(attnum) + FirstLowInvalidHeapAttributeNumber - 1]
|
|
+ */
|
|
+typedef struct SelinuxEvalItem
|
|
+{
|
|
+ NodeTag type;
|
|
+
|
|
+ Oid relid; /* relation id */
|
|
+ bool inh; /* flags to inheritable/only */
|
|
+
|
|
+ uint32 relperms; /* required permissions on table */
|
|
+ uint32 nattrs; /* length of attperms */
|
|
+ uint32 *attperms; /* required permissions on columns */
|
|
+} SelinuxEvalItem;
|
|
+
|
|
+#endif /* NODES_SECURITY_H */
|
|
diff -rpNU3 base/src/include/pg_config.h.in sepgsql/src/include/pg_config.h.in
|
|
--- base/src/include/pg_config.h.in 2008-01-28 16:06:37.000000000 +0900
|
|
+++ sepgsql/src/include/pg_config.h.in 2008-12-12 18:45:55.000000000 +0900
|
|
@@ -366,6 +366,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 -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace.h
|
|
--- base/src/include/security/pgace.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/include/security/pgace.h 2009-02-25 22:31:25.000000000 +0900
|
|
@@ -0,0 +1,192 @@
|
|
+/*
|
|
+ * include/security/pgace.h
|
|
+ * headers for PostgreSQL Access Control Extension (PGACE)
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ *
|
|
+ */
|
|
+#ifndef PGACE_H
|
|
+#define PGACE_H
|
|
+
|
|
+#include "access/htup.h"
|
|
+#include "commands/trigger.h"
|
|
+#include "executor/execdesc.h"
|
|
+#include "fmgr.h"
|
|
+#include "nodes/params.h"
|
|
+#include "nodes/parsenodes.h"
|
|
+#include "nodes/plannodes.h"
|
|
+#include "storage/large_object.h"
|
|
+#include "utils/guc.h"
|
|
+#include "utils/rel.h"
|
|
+
|
|
+#ifdef HAVE_SELINUX
|
|
+#include "security/sepgsql.h"
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * pgace_feature : GUC parameter to choose an enhanced security feature
|
|
+ */
|
|
+typedef enum
|
|
+{
|
|
+ PGACE_FEATURE_NONE,
|
|
+#ifdef HAVE_SELINUX
|
|
+ PGACE_FEATURE_SELINUX,
|
|
+#endif
|
|
+} PgaceFeatureOpts;
|
|
+
|
|
+extern int pgace_feature;
|
|
+extern char *pgace_feature_string;
|
|
+
|
|
+/*
|
|
+ * Attribute names for the system-defined attributes
|
|
+ */
|
|
+#define SecurityLabelAttributeName "security_context"
|
|
+
|
|
+/*
|
|
+ * Initialization hooks
|
|
+ */
|
|
+extern Size pgaceShmemSize(void);
|
|
+extern void pgaceInitialize(bool is_bootstrap);
|
|
+extern pid_t pgaceStartupWorkerProcess(void);
|
|
+
|
|
+/*
|
|
+ * SQL proxy hooks
|
|
+ */
|
|
+extern List *pgacePostQueryRewrite(List *queryList);
|
|
+extern void pgaceExecutorStart(QueryDesc *queryDesc, int eflags);
|
|
+extern void pgaceProcessUtility(Node *parsetree, ParamListInfo params,
|
|
+ bool isTopLevel);
|
|
+/*
|
|
+ * HeapTuple input/output hooks
|
|
+ */
|
|
+extern bool pgaceRowlvBehaviorSwitchTo(bool new_abort);
|
|
+extern bool pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort);
|
|
+extern bool pgaceHeapTupleInsert(Relation rel, HeapTuple tuple,
|
|
+ bool is_internal, bool with_returning);
|
|
+extern bool pgaceHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup,
|
|
+ bool is_internal, bool with_returning);
|
|
+extern bool pgaceHeapTupleDelete(Relation rel, ItemPointer otid,
|
|
+ bool is_internal, bool with_returning);
|
|
+/*
|
|
+ * Enhanced SQL statements
|
|
+ */
|
|
+extern bool pgaceIsGramSecurityItem(DefElem *defel);
|
|
+extern void pgaceGramCreateRelation(Relation rel, HeapTuple tuple, DefElem *defel);
|
|
+extern void pgaceGramCreateAttribute(Relation rel, HeapTuple tuple, DefElem *defel);
|
|
+extern void pgaceGramAlterRelation(Relation rel, HeapTuple tuple, DefElem *defel);
|
|
+extern void pgaceGramAlterAttribute(Relation rel, HeapTuple tuple, DefElem *defel);
|
|
+extern void pgaceGramCreateDatabase(Relation rel, HeapTuple tuple, DefElem *defel);
|
|
+extern void pgaceGramAlterDatabase(Relation rel, HeapTuple tuple, DefElem *defel);
|
|
+extern void pgaceGramCreateFunction(Relation rel, HeapTuple tuple, DefElem *defel);
|
|
+extern void pgaceGramAlterFunction(Relation rel, HeapTuple tuple, DefElem *defel);
|
|
+
|
|
+/*
|
|
+ * Function related hooks
|
|
+ */
|
|
+extern void pgaceCallFunction(FmgrInfo *finfo);
|
|
+extern void pgaceCallAggFunction(HeapTuple aggTuple);
|
|
+extern bool pgaceCallTriggerFunction(TriggerData *tgdata);
|
|
+extern bool pgaceAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple);
|
|
+
|
|
+/*
|
|
+ * Misc hooks
|
|
+ */
|
|
+extern void pgaceSetDatabaseParam(const char *name, char *argstring);
|
|
+extern void pgaceGetDatabaseParam(const char *name);
|
|
+extern void pgaceExecTruncate(List *trunc_rels);
|
|
+extern void pgaceLockTable(Oid relid);
|
|
+
|
|
+/*
|
|
+ * COPY TO/FROM statement hooks
|
|
+ */
|
|
+extern void pgaceCopyTable(Relation rel, List *attNumList, bool isFrom);
|
|
+extern void pgaceCopyFile(Relation rel, int fdesc, const char *filename, bool isFrom);
|
|
+extern bool pgaceCopyToTuple(Relation rel, List *attNumList, HeapTuple tuple);
|
|
+
|
|
+/*
|
|
+ * Loadable shared library module hooks
|
|
+ */
|
|
+extern void pgaceLoadSharedModule(const char *filename);
|
|
+
|
|
+/*
|
|
+ * Binary Large Object hooks
|
|
+ */
|
|
+extern void pgaceLargeObjectCreate(Relation rel, HeapTuple tuple);
|
|
+extern void pgaceLargeObjectDrop(Relation rel, HeapTuple tuple, void **pgaceItem);
|
|
+extern void pgaceLargeObjectRead(LargeObjectDesc *lodesc, int length);
|
|
+extern void pgaceLargeObjectWrite(LargeObjectDesc *lodesc, int length);
|
|
+extern void pgaceLargeObjectTruncate(LargeObjectDesc *lodesc, int offset);
|
|
+extern void pgaceLargeObjectImport(Oid loid, int fdesc, const char *filename);
|
|
+extern void pgaceLargeObjectExport(Oid loid, int fdesc, const char *filename);
|
|
+extern void pgaceLargeObjectGetSecurity(Relation rel, HeapTuple tuple);
|
|
+extern void pgaceLargeObjectSetSecurity(Relation rel,
|
|
+ HeapTuple newtup, HeapTuple oldtup);
|
|
+/*
|
|
+ * Security Label hooks
|
|
+ */
|
|
+extern bool pgaceTupleDescHasSecLabel(Relation rel, List *relopts);
|
|
+extern char *pgaceTranslateSecurityLabelIn(char *seclabel);
|
|
+extern char *pgaceTranslateSecurityLabelOut(char *seclabel);
|
|
+extern bool pgaceCheckValidSecurityLabel(char *seclabel);
|
|
+extern char *pgaceUnlabeledSecurityLabel(void);
|
|
+extern char *pgaceSecurityLabelOfLabel(void);
|
|
+
|
|
+/*
|
|
+ * PGACE common facilities (not hooks)
|
|
+ */
|
|
+
|
|
+/* security label management */
|
|
+extern void pgacePostBootstrapingMode(void);
|
|
+
|
|
+extern Oid pgaceLookupSecurityId(char *label);
|
|
+
|
|
+extern char *pgaceLookupSecurityLabel(Oid sid);
|
|
+
|
|
+extern Oid pgaceSecurityLabelToSid(char *label);
|
|
+
|
|
+extern char *pgaceSidToSecurityLabel(Oid sid);
|
|
+
|
|
+/* Enhanced SQL statements related */
|
|
+extern List *pgaceRelationAttrList(CreateStmt *stmt);
|
|
+
|
|
+extern void pgaceCreateRelationCommon(Relation rel, HeapTuple tuple,
|
|
+ List *pgaceAttrList);
|
|
+extern void pgaceCreateAttributeCommon(Relation rel, HeapTuple tuple,
|
|
+ List *pgaceAttrList);
|
|
+extern void pgaceAlterRelationCommon(Relation rel, AlterTableCmd *cmd);
|
|
+
|
|
+/* Export security system columns */
|
|
+extern Datum pgaceHeapGetSecurityLabelSysattr(HeapTuple tuple);
|
|
+
|
|
+/******************************************************************
|
|
+ * Ported utility functions from 8.4devel
|
|
+ ******************************************************************/
|
|
+#define CStringGetTextDatum(x) \
|
|
+ (DirectFunctionCall1(textin, CStringGetDatum(x)))
|
|
+#define TextDatumGetCString(x) \
|
|
+ (DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(x))))
|
|
+
|
|
+extern const char *pgaceAssignFeatureString(const char *value, bool doit, GucSource source);
|
|
+
|
|
+/******************************************************************
|
|
+ * SQL function declaration related to PGACE security framework
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * SQL functions
|
|
+ */
|
|
+
|
|
+/* SE-PostgreSQL */
|
|
+extern Datum sepgsql_getcon(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_getservcon(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_get_user(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_get_role(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_get_type(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_get_range(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_set_user(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_set_role(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_set_type(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_set_range(PG_FUNCTION_ARGS);
|
|
+
|
|
+#endif // PGACE_H
|
|
diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sepgsql.h
|
|
--- base/src/include/security/sepgsql.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/include/security/sepgsql.h 2009-02-25 22:31:25.000000000 +0900
|
|
@@ -0,0 +1,242 @@
|
|
+/*
|
|
+ * src/include/security/sepgsql.h
|
|
+ * headers for Security-Enhanced PostgreSQL (SE-PostgreSQL)
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ *
|
|
+ */
|
|
+#ifndef SEPGSQL_H
|
|
+#define SEPGSQL_H
|
|
+
|
|
+#include <selinux/selinux.h>
|
|
+#include <selinux/flask.h>
|
|
+#include <selinux/av_permissions.h>
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL modes
|
|
+ */
|
|
+typedef enum
|
|
+{
|
|
+ SEPGSQL_MODE_DEFAULT,
|
|
+ SEPGSQL_MODE_ENFORCING,
|
|
+ SEPGSQL_MODE_PERMISSIVE,
|
|
+ SEPGSQL_MODE_DISABLED,
|
|
+} SepgsqlModeType;
|
|
+
|
|
+extern int sepostgresql_mode;
|
|
+extern char *sepostgresql_mode_string;
|
|
+extern bool sepostgresql_row_level;
|
|
+
|
|
+extern const char *sepgsqlAssignModeString(const char *value, bool doit, GucSource source);
|
|
+
|
|
+/*
|
|
+ * Permission bits delivered to sepgsqlCheckTuplePerms().
|
|
+ * Please note that 0x000000ff of RangeTblEntry->pgaceTuplePerms
|
|
+ * are reserved by rowacl. These bits are also stored within
|
|
+ * pgaceTuplePerms, we have to avoid to use the lower bits.
|
|
+ */
|
|
+#define SEPGSQL_PERMS_USE (1UL << 8)
|
|
+#define SEPGSQL_PERMS_SELECT (1UL << 9)
|
|
+#define SEPGSQL_PERMS_UPDATE (1UL << 10)
|
|
+#define SEPGSQL_PERMS_INSERT (1UL << 11)
|
|
+#define SEPGSQL_PERMS_DELETE (1UL << 12)
|
|
+#define SEPGSQL_PERMS_RELABELFROM (1UL << 13)
|
|
+#define SEPGSQL_PERMS_RELABELTO (1UL << 14)
|
|
+#define SEPGSQL_PERMS_READ (1UL << 15)
|
|
+#define SEPGSQL_PERMS_MASK (0xffffff00)
|
|
+
|
|
+/*
|
|
+ * The implementation of PGACE/SE-PostgreSQL hooks
|
|
+ */
|
|
+
|
|
+/* Initialize / Finalize related hooks */
|
|
+extern Size sepgsqlShmemSize(void);
|
|
+
|
|
+extern void sepgsqlInitialize(bool is_bootstrap);
|
|
+
|
|
+extern pid_t sepgsqlStartupWorkerProcess(void);
|
|
+
|
|
+/* SQL proxy hooks */
|
|
+extern List *sepgsqlPostQueryRewrite(List *queryList);
|
|
+
|
|
+extern void sepgsqlExecutorStart(QueryDesc *queryDesc, int eflags);
|
|
+
|
|
+extern void sepgsqlProcessUtility(Node *parsetree, ParamListInfo params, bool isTopLevel);
|
|
+
|
|
+/* ExecScan hooks */
|
|
+extern bool sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort);
|
|
+
|
|
+extern bool sepgsqlRowlvBehaviorSwitchTo(bool new_abort);
|
|
+
|
|
+/* HeapTuple modification hooks */
|
|
+extern bool sepgsqlHeapTupleInsert(Relation rel, HeapTuple tuple,
|
|
+ bool is_internal, bool with_returning);
|
|
+extern bool sepgsqlHeapTupleUpdate(Relation rel, ItemPointer otid,
|
|
+ HeapTuple newtup, bool is_internal,
|
|
+ bool with_returning);
|
|
+extern bool sepgsqlHeapTupleDelete(Relation rel, ItemPointer otid,
|
|
+ bool is_internal, bool with_returning);
|
|
+
|
|
+/* Extended SQL statement hooks */
|
|
+extern bool sepgsqlIsGramSecurityItem(DefElem *defel);
|
|
+
|
|
+extern void sepgsqlGramCreateRelation(Relation rel, HeapTuple tuple,
|
|
+ DefElem *defel);
|
|
+extern void sepgsqlGramCreateAttribute(Relation rel, HeapTuple tuple,
|
|
+ DefElem *defel);
|
|
+extern void sepgsqlGramAlterRelation(Relation rel, HeapTuple tuple,
|
|
+ DefElem *defel);
|
|
+extern void sepgsqlGramAlterAttribute(Relation rel, HeapTuple tuple,
|
|
+ DefElem *defel);
|
|
+extern void sepgsqlGramCreateDatabase(Relation rel, HeapTuple tuple,
|
|
+ DefElem *defel);
|
|
+extern void sepgsqlGramAlterDatabase(Relation rel, HeapTuple tuple,
|
|
+ DefElem *defel);
|
|
+extern void sepgsqlGramCreateFunction(Relation rel, HeapTuple tuple,
|
|
+ DefElem *defel);
|
|
+extern void sepgsqlGramAlterFunction(Relation rel, HeapTuple tuple,
|
|
+ DefElem *defel);
|
|
+
|
|
+/* DATABASE related hooks */
|
|
+extern void sepgsqlSetDatabaseParam(const char *name, char *argstring);
|
|
+
|
|
+extern void sepgsqlGetDatabaseParam(const char *name);
|
|
+
|
|
+/* FUNCTION related hooks */
|
|
+extern void sepgsqlCallFunction(FmgrInfo *finfo);
|
|
+
|
|
+extern void sepgsqlCallAggFunction(HeapTuple aggTuple);
|
|
+
|
|
+extern bool sepgsqlCallTriggerFunction(TriggerData *tgdata);
|
|
+
|
|
+extern bool sepgsqlAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple);
|
|
+
|
|
+/* TABLE related hooks */
|
|
+extern void sepgsqlLockTable(Oid relid);
|
|
+
|
|
+extern void sepgsqlExecTruncate(List *trunc_rels);
|
|
+
|
|
+extern bool sepgsqlAlterTable(Relation rel, AlterTableCmd *cmd);
|
|
+
|
|
+/* COPY TO/COPY FROM statement hooks */
|
|
+extern void sepgsqlCopyTable(Relation rel, List *attnumlist, bool is_from);
|
|
+
|
|
+extern void sepgsqlCopyFile(Relation rel, int fdesc, const char *filename, bool isFrom);
|
|
+
|
|
+extern bool sepgsqlCopyToTuple(Relation rel, List *attnumlist, HeapTuple tuple);
|
|
+
|
|
+/* Loadable shared library module hooks */
|
|
+extern void sepgsqlLoadSharedModule(const char *filename);
|
|
+
|
|
+/* Binary Large Object (BLOB) hooks */
|
|
+extern void sepgsqlLargeObjectCreate(Relation rel, HeapTuple tuple);
|
|
+
|
|
+extern void sepgsqlLargeObjectDrop(Relation rel, HeapTuple tuple, void **pgaceItem);
|
|
+
|
|
+extern void sepgsqlLargeObjectRead(LargeObjectDesc *lodesc, int length);
|
|
+
|
|
+extern void sepgsqlLargeObjectWrite(LargeObjectDesc *lodesc, int length);
|
|
+
|
|
+extern void sepgsqlLargeObjectTruncate(LargeObjectDesc *lodesc, int offset);
|
|
+
|
|
+extern void sepgsqlLargeObjectImport(Oid loid, int fdesc, const char *filename);
|
|
+
|
|
+extern void sepgsqlLargeObjectExport(Oid loid, int fdesc, const char *filename);
|
|
+
|
|
+extern void sepgsqlLargeObjectGetSecurity(Relation rel, HeapTuple tuple);
|
|
+
|
|
+extern void sepgsqlLargeObjectSetSecurity(Relation rel, HeapTuple newtup, HeapTuple oldtup);
|
|
+
|
|
+/* Security Label hooks */
|
|
+extern bool sepgsqlTupleDescHasSecLabel(Relation rel, List *relopts);
|
|
+
|
|
+extern char *sepgsqlTranslateSecurityLabelIn(const char *context);
|
|
+
|
|
+extern char *sepgsqlTranslateSecurityLabelOut(const char *context);
|
|
+
|
|
+extern bool sepgsqlCheckValidSecurityLabel(char *context);
|
|
+
|
|
+extern char *sepgsqlUnlabeledSecurityLabel(void);
|
|
+
|
|
+extern char *sepgsqlSecurityLabelOfLabel(void);
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL core functions
|
|
+ * src/backend/security/sepgsql/core.c
|
|
+ */
|
|
+extern bool sepgsqlIsEnabled(void);
|
|
+
|
|
+extern const security_context_t sepgsqlGetServerContext(void);
|
|
+
|
|
+extern const security_context_t sepgsqlGetClientContext(void);
|
|
+
|
|
+extern const security_context_t sepgsqlGetDatabaseContext(void);
|
|
+
|
|
+extern const security_context_t sepgsqlGetUnlabeledContext(void);
|
|
+
|
|
+extern const security_context_t sepgsqlSwitchClientContext(security_context_t newcon);
|
|
+
|
|
+extern Oid sepgsqlGetDatabaseSecurityId(void);
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL userspace avc functions
|
|
+ * src/backend/security/sepgsql/avc.c
|
|
+ */
|
|
+extern void sepgsqlAvcInit(void);
|
|
+
|
|
+extern void sepgsqlAvcSwitchClientContext(security_context_t context);
|
|
+
|
|
+extern void sepgsqlClientHasPermission(Oid target_security_id,
|
|
+ security_class_t tclass,
|
|
+ access_vector_t perms,
|
|
+ const char *objname);
|
|
+
|
|
+extern bool sepgsqlClientHasPermissionNoAbort(Oid target_security_id,
|
|
+ security_class_t tclass,
|
|
+ access_vector_t perms,
|
|
+ const char *objname);
|
|
+
|
|
+extern Oid sepgsqlClientCreateSid(Oid target_security_id,
|
|
+ security_class_t tclass);
|
|
+
|
|
+extern security_context_t
|
|
+sepgsqlClientCreateContext(Oid target_security_id,
|
|
+ security_class_t tclass);
|
|
+
|
|
+extern bool sepgsqlComputePermission(const security_context_t scontext,
|
|
+ const security_context_t tcontext,
|
|
+ security_class_t tclass,
|
|
+ access_vector_t perms,
|
|
+ const char *objname);
|
|
+
|
|
+extern security_context_t
|
|
+sepgsqlComputeCreateContext(const security_context_t scontext,
|
|
+ const security_context_t tcontext,
|
|
+ security_class_t tclass);
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL permission evaluation related
|
|
+ * src/backend/security/sepgsql/permission.c
|
|
+ */
|
|
+extern const char *sepgsqlTupleName(Oid relid, HeapTuple tuple);
|
|
+
|
|
+extern security_class_t sepgsqlFileObjectClass(int fdesc, const char *filename);
|
|
+
|
|
+extern security_class_t sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple);
|
|
+
|
|
+extern void sepgsqlSetDefaultContext(Relation rel, HeapTuple tuple);
|
|
+
|
|
+extern bool sepgsqlCheckTuplePerms(Relation rel, HeapTuple tuple, HeapTuple newtup,
|
|
+ uint32 perms, bool abort);
|
|
+
|
|
+extern void sepgsqlCheckModuleInstallPerms(const char *filename);
|
|
+
|
|
+/*
|
|
+ * workaround for older libselinux
|
|
+ */
|
|
+#ifndef DB_PROCEDURE__INSTALL
|
|
+#define DB_PROCEDURE__INSTALL 0x00000100UL
|
|
+#endif
|
|
+
|
|
+#endif /* SEPGSQL_H */
|
|
diff -rpNU3 base/src/include/storage/fd.h sepgsql/src/include/storage/fd.h
|
|
--- base/src/include/storage/fd.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/storage/fd.h 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -67,6 +67,7 @@ extern int FileWrite(File file, char *bu
|
|
extern int FileSync(File file);
|
|
extern long FileSeek(File file, long offset, int whence);
|
|
extern int FileTruncate(File file, long offset);
|
|
+extern int FileRawDescriptor(File file);
|
|
|
|
/* Operations that allow use of regular stdio --- USE WITH CAUTION */
|
|
extern FILE *AllocateFile(const char *name, const char *mode);
|
|
diff -rpNU3 base/src/include/storage/lwlock.h sepgsql/src/include/storage/lwlock.h
|
|
--- base/src/include/storage/lwlock.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/storage/lwlock.h 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -63,6 +63,7 @@ typedef enum LWLockId
|
|
AutovacuumLock,
|
|
AutovacuumScheduleLock,
|
|
SyncScanLock,
|
|
+ SepgsqlAvcLock,
|
|
/* Individual lock IDs end here */
|
|
FirstBufMappingLock,
|
|
FirstLockMgrLock = FirstBufMappingLock + NUM_BUFFER_PARTITIONS,
|
|
diff -rpNU3 base/src/include/utils/catcache.h sepgsql/src/include/utils/catcache.h
|
|
--- base/src/include/utils/catcache.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/utils/catcache.h 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -172,6 +172,7 @@ extern HeapTuple SearchCatCache(CatCache
|
|
Datum v1, Datum v2,
|
|
Datum v3, Datum v4);
|
|
extern void ReleaseCatCache(HeapTuple tuple);
|
|
+extern void InsertCatCache(CatCache *cache, HeapTuple tuple);
|
|
|
|
extern CatCList *SearchCatCacheList(CatCache *cache, int nkeys,
|
|
Datum v1, Datum v2,
|
|
diff -rpNU3 base/src/include/utils/errcodes.h sepgsql/src/include/utils/errcodes.h
|
|
--- base/src/include/utils/errcodes.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/utils/errcodes.h 2008-12-02 11:39:45.000000000 +0900
|
|
@@ -339,6 +339,12 @@
|
|
#define ERRCODE_NO_DATA_FOUND MAKE_SQLSTATE('P','0', '0','0','2')
|
|
#define ERRCODE_TOO_MANY_ROWS MAKE_SQLSTATE('P','0', '0','0','3')
|
|
|
|
+/* Class SE - Security Error (PGACE/SE-PostgreSQL error class) */
|
|
+#define ERRCODE_PGACE_ERROR MAKE_SQLSTATE('S','E', '0','0','0')
|
|
+#define ERRCODE_SELINUX_ERROR MAKE_SQLSTATE('S','E', '0','1','1')
|
|
+#define ERRCODE_SELINUX_AUDIT MAKE_SQLSTATE('S','E', '0','1','2')
|
|
+#define ERRCODE_SELINUX_INFO MAKE_SQLSTATE('S','E', '0','1','3')
|
|
+
|
|
/* Class XX - Internal Error (PostgreSQL-specific error class) */
|
|
/* (this is for "can't-happen" conditions and software bugs) */
|
|
#define ERRCODE_INTERNAL_ERROR MAKE_SQLSTATE('X','X', '0','0','0')
|
|
diff -rpNU3 base/src/include/utils/syscache.h sepgsql/src/include/utils/syscache.h
|
|
--- base/src/include/utils/syscache.h 2008-01-07 23:51:33.000000000 +0900
|
|
+++ sepgsql/src/include/utils/syscache.h 2008-06-14 02:36:58.000000000 +0900
|
|
@@ -76,6 +76,8 @@
|
|
#define TSTEMPLATEOID 45
|
|
#define TYPENAMENSP 46
|
|
#define TYPEOID 47
|
|
+#define SECURITYOID 48
|
|
+#define SECURITYLABEL 49
|
|
|
|
extern void InitCatalogCache(void);
|
|
extern void InitCatalogCachePhase2(void);
|
|
@@ -84,6 +86,8 @@ extern HeapTuple SearchSysCache(int cach
|
|
Datum key1, Datum key2, Datum key3, Datum key4);
|
|
extern void ReleaseSysCache(HeapTuple tuple);
|
|
|
|
+extern void InsertSysCache(Oid relid, HeapTuple tuple);
|
|
+
|
|
/* convenience routines */
|
|
extern HeapTuple SearchSysCacheCopy(int cacheId,
|
|
Datum key1, Datum key2, Datum key3, Datum key4);
|
|
diff -rpNU3 base/src/test/regress/expected/sanity_check.out sepgsql/src/test/regress/expected/sanity_check.out
|
|
--- base/src/test/regress/expected/sanity_check.out 2007-11-25 12:49:12.000000000 +0900
|
|
+++ sepgsql/src/test/regress/expected/sanity_check.out 2008-11-24 19:46:15.000000000 +0900
|
|
@@ -111,6 +111,7 @@ SELECT relname, relhasindex
|
|
pg_pltemplate | t
|
|
pg_proc | t
|
|
pg_rewrite | t
|
|
+ pg_security | t
|
|
pg_shdepend | t
|
|
pg_shdescription | t
|
|
pg_statistic | t
|
|
@@ -149,7 +150,7 @@ SELECT relname, relhasindex
|
|
timetz_tbl | f
|
|
tinterval_tbl | f
|
|
varchar_tbl | f
|
|
-(138 rows)
|
|
+(139 rows)
|
|
|
|
--
|
|
-- another sanity check: every system catalog that has OIDs should have
|