diff --git a/.cvsignore b/.cvsignore deleted file mode 100644 index e18d446..0000000 --- a/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -postgresql-8.3.7.tar.bz2 diff --git a/Makefile b/Makefile deleted file mode 100644 index dad7c56..0000000 --- a/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Makefile for source rpm: sepostgresql -# $Id$ -NAME := sepostgresql -SPECFILE = $(firstword $(wildcard *.spec)) - -define find-makefile-common -for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done -endef - -MAKEFILE_COMMON := $(shell $(find-makefile-common)) - -ifeq ($(MAKEFILE_COMMON),) -# attept a checkout -define checkout-makefile-common -test -f CVS/Root && { cvs -Q -d $$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2 -endef - -MAKEFILE_COMMON := $(shell $(checkout-makefile-common)) -endif - -include $(MAKEFILE_COMMON) diff --git a/dead.package b/dead.package new file mode 100644 index 0000000..e1c0fac --- /dev/null +++ b/dead.package @@ -0,0 +1 @@ +SE-PostgreSQL was merged into mainstream as contrib/sepgsql extension diff --git a/sepostgresql-core-8.3.patch b/sepostgresql-core-8.3.patch deleted file mode 100644 index 79af7f8..0000000 --- a/sepostgresql-core-8.3.patch +++ /dev/null @@ -1,9793 +0,0 @@ -diff -rpNU3 base/configure sepgsql-new/configure ---- base/configure 2009-03-15 17:47:25.000000000 +0900 -+++ sepgsql-new/configure 2009-03-15 17:58:10.000000000 +0900 -@@ -314,7 +314,7 @@ ac_includes_default="\ - # include - #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 enable to 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-new/configure.in ---- base/configure.in 2009-03-15 17:47:25.000000000 +0900 -+++ sepgsql-new/configure.in 2009-03-15 17:58:10.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 enable to 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/src/Makefile.global.in sepgsql-new/src/Makefile.global.in ---- base/src/Makefile.global.in 2007-11-17 20:15:40.000000000 +0900 -+++ sepgsql-new/src/Makefile.global.in 2009-03-13 18:14:33.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-new/src/backend/Makefile ---- base/src/backend/Makefile 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/Makefile 2009-03-13 18:14:33.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 needs libselinux -+ifeq ($(enable_selinux), yes) -+LIBS += -lselinux -+endif -+ - ########################################################################## - - all: submake-libpgport postgres $(POSTGRES_IMP) -diff -rpNU3 base/src/backend/access/common/heaptuple.c sepgsql-new/src/backend/access/common/heaptuple.c ---- base/src/backend/access/common/heaptuple.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/access/common/heaptuple.c 2009-03-13 18:14:33.000000000 +0900 -@@ -66,6 +66,7 @@ - - #include "access/heapam.h" - #include "access/tuptoaster.h" -+#include "catalog/pg_security.h" - #include "executor/tuptable.h" - - -@@ -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 = securityHeapGetSecLabelSysattr(tup); -+ break; - default: - elog(ERROR, "invalid attnum: %d", attnum); - result = 0; /* keep compiler quiet */ -@@ -908,6 +913,8 @@ 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 */ - -@@ -939,6 +946,8 @@ 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, -@@ -1019,6 +1028,8 @@ heap_formtuple(TupleDesc tupleDescriptor - - if (tupleDescriptor->tdhasoid) - len += sizeof(Oid); -+ if (tupleDescriptor->tdhasseclabel) -+ len += sizeof(Oid); - - hoff = len = MAXALIGN(len); /* align user data safely */ - -@@ -1050,6 +1061,8 @@ 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, -@@ -1129,6 +1142,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 +1216,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; - } -@@ -1846,6 +1863,8 @@ 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 */ - -@@ -1867,6 +1886,8 @@ 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, -@@ -1965,6 +1986,7 @@ minimal_tuple_from_heap_tuple(HeapTuple - HeapTuple - heap_addheader(int natts, /* max domain index */ - bool withoid, /* reserve space for oid */ -+ bool withseclabel, /* reserve space for security */ - Size structlen, /* its length */ - void *structure) /* pointer to the struct */ - { -@@ -1979,6 +2001,8 @@ heap_addheader(int natts, /* max domain - hoff = offsetof(HeapTupleHeaderData, t_bits); - if (withoid) - hoff += sizeof(Oid); -+ if (withseclabel) -+ hoff += sizeof(Oid); - hoff = MAXALIGN(hoff); - len = hoff + structlen; - -@@ -1996,6 +2020,8 @@ heap_addheader(int natts, /* max domain - - if (withoid) /* else leave infomask = 0 */ - td->t_infomask = HEAP_HASOID; -+ if (withseclabel) -+ td->t_infomask |= HEAP_HAS_SECLABEL; - - memcpy((char *) td + hoff, structure, structlen); - -diff -rpNU3 base/src/backend/access/common/tupdesc.c sepgsql-new/src/backend/access/common/tupdesc.c ---- base/src/backend/access/common/tupdesc.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/access/common/tupdesc.c 2009-03-13 18:14:33.000000000 +0900 -@@ -84,6 +84,7 @@ CreateTemplateTupleDesc(int natts, bool - desc->tdtypeid = RECORDOID; - desc->tdtypmod = -1; - desc->tdhasoid = hasoid; -+ desc->tdhasseclabel = false; - 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; - 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-new/src/backend/access/heap/heapam.c ---- base/src/backend/access/heap/heapam.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/backend/access/heap/heapam.c 2009-03-13 18:14:33.000000000 +0900 -@@ -50,6 +50,7 @@ - #include "catalog/namespace.h" - #include "miscadmin.h" - #include "pgstat.h" -+#include "security/rowlevel.h" - #include "storage/procarray.h" - #include "storage/smgr.h" - #include "utils/datum.h" -@@ -1949,6 +1950,8 @@ heap_insert(Relation relation, HeapTuple - Oid - simple_heap_insert(Relation relation, HeapTuple tup) - { -+ rowlvHeapTupleInsert(relation, tup, true); -+ - return heap_insert(relation, tup, GetCurrentCommandId(true), true, true); - } - -@@ -2230,6 +2233,8 @@ simple_heap_delete(Relation relation, It - ItemPointerData update_ctid; - TransactionId update_xmax; - -+ rowlvHeapTupleDelete(relation, tid, true); -+ - result = heap_delete(relation, tid, - &update_ctid, &update_xmax, - GetCurrentCommandId(true), InvalidSnapshot, -@@ -2874,6 +2879,8 @@ simple_heap_update(Relation relation, It - ItemPointerData update_ctid; - TransactionId update_xmax; - -+ rowlvHeapTupleUpdate(relation, otid, tup, true); -+ - result = heap_update(relation, otid, tup, - &update_ctid, &update_xmax, - GetCurrentCommandId(true), InvalidSnapshot, -diff -rpNU3 base/src/backend/access/heap/tuptoaster.c sepgsql-new/src/backend/access/heap/tuptoaster.c ---- base/src/backend/access/heap/tuptoaster.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql-new/src/backend/access/heap/tuptoaster.c 2009-03-13 18:14:33.000000000 +0900 -@@ -35,6 +35,7 @@ - #include "access/tuptoaster.h" - #include "access/xact.h" - #include "catalog/catalog.h" -+#include "security/rowlevel.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 (HeapTupleHasSecLabel(newtup)) -+ 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 (HeapTupleHeaderHasSecLabel(olddata)) -+ 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 (HeapTupleHeaderHasSecLabel(olddata)) -+ 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,8 @@ toast_save_datum(Relation rel, Datum val - memcpy(VARDATA(&chunk_data), data_p, chunk_size); - toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull); - -+ rowlvHeapTupleInsert(toastrel, toasttup, true); -+ - heap_insert(toastrel, toasttup, mycid, use_wal, use_fsm); - - /* -diff -rpNU3 base/src/backend/bootstrap/bootparse.y sepgsql-new/src/backend/bootstrap/bootparse.y ---- base/src/backend/bootstrap/bootparse.y 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/bootstrap/bootparse.y 2009-03-13 18:14:33.000000000 +0900 -@@ -33,6 +33,7 @@ - #include "catalog/pg_class.h" - #include "catalog/pg_namespace.h" - #include "catalog/pg_tablespace.h" -+#include "catalog/pg_security.h" - #include "catalog/toasting.h" - #include "commands/defrem.h" - #include "miscadmin.h" -@@ -42,6 +43,7 @@ - #include "nodes/pg_list.h" - #include "nodes/primnodes.h" - #include "rewrite/prs2lock.h" -+#include "security/sepgsql.h" - #include "storage/block.h" - #include "storage/fd.h" - #include "storage/ipc.h" -@@ -194,6 +196,12 @@ Boot_CreateStmt: - RELKIND_RELATION, - $3, - true); -+ /* -+ * fixup boot_reldesc->rd_att->tdhassecXXXX -+ */ -+ boot_reldesc->rd_rel->relkind = RELKIND_RELATION; -+ boot_reldesc->rd_att->tdhasseclabel -+ = securityTupleDescHasSecLabel(boot_reldesc); - 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-new/src/backend/bootstrap/bootstrap.c ---- base/src/backend/bootstrap/bootstrap.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/bootstrap/bootstrap.c 2009-03-13 18:14:33.000000000 +0900 -@@ -25,6 +25,7 @@ - #include "access/xact.h" - #include "bootstrap/bootstrap.h" - #include "catalog/index.h" -+#include "catalog/pg_security.h" - #include "catalog/pg_type.h" - #include "libpq/pqsignal.h" - #include "miscadmin.h" -@@ -499,6 +500,11 @@ BootstrapModeMain(void) - */ - boot_yyparse(); - -+ /* -+ * Flush all the cached security label -+ */ -+ securityPostBootstrapingMode(); -+ - /* Perform a checkpoint to ensure everything's down to disk */ - SetProcessingMode(NormalProcessing); - CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE); -@@ -796,6 +802,8 @@ InsertOneTuple(Oid objectid) - tupDesc = CreateTupleDesc(numattr, - RelationGetForm(boot_reldesc)->relhasoids, - attrtypes); -+ tupDesc->tdhasseclabel -+ = securityTupleDescHasSecLabel(boot_reldesc); - tuple = heap_formtuple(tupDesc, values, Blanks); - if (objectid != (Oid) 0) - HeapTupleSetOid(tuple, objectid); -diff -rpNU3 base/src/backend/catalog/Makefile sepgsql-new/src/backend/catalog/Makefile ---- base/src/backend/catalog/Makefile 2007-09-11 10:53:53.000000000 +0900 -+++ sepgsql-new/src/backend/catalog/Makefile 2009-03-13 18:14:33.000000000 +0900 -@@ -13,7 +13,7 @@ include $(top_builddir)/src/Makefile.glo - OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \ - pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \ - pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \ -- pg_type.o toasting.o -+ pg_security.o pg_type.o toasting.o - - BKIFILES = postgres.bki postgres.description postgres.shdescription - -@@ -35,7 +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_ts_config.h pg_ts_config_map.h pg_ts_dict.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/aclchk.c sepgsql-new/src/backend/catalog/aclchk.c ---- base/src/backend/catalog/aclchk.c 2008-06-12 22:34:19.000000000 +0900 -+++ sepgsql-new/src/backend/catalog/aclchk.c 2009-03-13 18:14:33.000000000 +0900 -@@ -39,6 +39,7 @@ - #include "commands/dbcommands.h" - #include "miscadmin.h" - #include "parser/parse_func.h" -+#include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/fmgroids.h" - #include "utils/lsyscache.h" -@@ -1979,7 +1980,14 @@ AclResult - pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode) - { - if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0) -+ { -+ /* SELinux: db_database:{access} permission */ -+ if ((mode & ACL_CONNECT) != 0 -+ && !sepgsqlCheckDatabaseAccess(db_oid)) -+ return ACLCHECK_NO_PRIV; -+ - return ACLCHECK_OK; -+ } - else - return ACLCHECK_NO_PRIV; - } -@@ -1991,7 +1999,14 @@ AclResult - pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode) - { - if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0) -+ { -+ /* SELinux: db_procedure:{execute} permission */ -+ if ((mode & ACL_EXECUTE) != 0 -+ && !sepgsqlCheckProcedureExecute(proc_oid)) -+ return ACLCHECK_NO_PRIV; -+ - return ACLCHECK_OK; -+ } - else - return ACLCHECK_NO_PRIV; - } -diff -rpNU3 base/src/backend/catalog/catalog.c sepgsql-new/src/backend/catalog/catalog.c ---- base/src/backend/catalog/catalog.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql-new/src/backend/catalog/catalog.c 2009-03-13 18:14:33.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-new/src/backend/catalog/heap.c ---- base/src/backend/catalog/heap.c 2009-03-15 17:47:25.000000000 +0900 -+++ sepgsql-new/src/backend/catalog/heap.c 2009-03-15 17:58:10.000000000 +0900 -@@ -42,6 +42,7 @@ - #include "catalog/pg_constraint.h" - #include "catalog/pg_inherits.h" - #include "catalog/pg_namespace.h" -+#include "catalog/pg_security.h" - #include "catalog/pg_statistic.h" - #include "catalog/pg_tablespace.h" - #include "catalog/pg_type.h" -@@ -53,6 +54,7 @@ - #include "parser/parse_coerce.h" - #include "parser/parse_expr.h" - #include "parser/parse_relation.h" -+#include "security/sepgsql.h" - #include "storage/smgr.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -@@ -67,7 +69,8 @@ static void AddNewRelationTuple(Relation - Oid new_rel_oid, Oid new_type_oid, - Oid relowner, - char relkind, -- Datum reloptions); -+ Datum reloptions, -+ List *selblList); - static Oid AddNewRelationType(const char *typeName, - Oid typeNamespace, - Oid new_rel_oid, -@@ -145,7 +148,16 @@ static FormData_pg_attribute a7 = { - true, 'p', 'i', true, false, false, true, 0 - }; - --static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; -+/* -+ * System columns for enhanced security features -+ */ -+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 +197,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 +492,8 @@ AddNewAttributeTuples(Oid new_rel_oid, - TupleDesc tupdesc, - char relkind, - bool oidislocal, -- int oidinhcount) -+ int oidinhcount, -+ List *selblList) - { - const Form_pg_attribute *dpp; - int i; -@@ -493,16 +518,40 @@ AddNewAttributeTuples(Oid new_rel_oid, - dpp = tupdesc->attrs; - for (i = 0; i < natts; i++) - { -+ ListCell *l; -+ Oid attselabel = InvalidOid; -+ - /* Fill in the correct relation OID */ - (*dpp)->attrelid = new_rel_oid; - /* Make sure these are OK, too */ - (*dpp)->attstattarget = -1; - (*dpp)->attcacheoff = -1; - -+ /* SELinux: extract a given security context */ -+ foreach (l, selblList) -+ { -+ DefElem *defel = lfirst(l); -+ -+ if (defel->defname && -+ strcmp(defel->defname, NameStr((*dpp)->attname)) == 0) -+ { -+ attselabel = sepgsqlInputGivenSecLabel(defel); -+ break; -+ } -+ } -+ - tup = heap_addheader(Natts_pg_attribute, - false, -+ RelationGetDescr(rel)->tdhasseclabel, - ATTRIBUTE_TUPLE_SIZE, - (void *) *dpp); -+ if (OidIsValid(attselabel)) -+ { -+ if (!HeapTupleHasSecLabel(tup)) -+ elog(ERROR, "Unable to assign security label on \"%s\"", -+ RelationGetRelationName(rel)); -+ HeapTupleSetSecLabel(tup, attselabel); -+ } - - simple_heap_insert(rel, tup); - -@@ -538,6 +587,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 +643,8 @@ void - InsertPgClassTuple(Relation pg_class_desc, - Relation new_rel_desc, - Oid new_rel_oid, -- Datum reloptions) -+ Datum reloptions, -+ Oid relselabel) - { - Form_pg_class rd_rel = new_rel_desc->rd_rel; - Datum values[Natts_pg_class]; -@@ -644,11 +695,23 @@ InsertPgClassTuple(Relation pg_class_des - */ - HeapTupleSetOid(tup, new_rel_oid); - -+ /* set explicit security label */ -+ if (OidIsValid(relselabel)) -+ { -+ if (!HeapTupleHasSecLabel(tup)) -+ elog(ERROR, "Unable to assign security label on \"%s\"", -+ RelationGetRelationName(pg_class_desc)); -+ HeapTupleSetSecLabel(tup, relselabel); -+ } -+ - /* 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,9 +729,12 @@ AddNewRelationTuple(Relation pg_class_de - Oid new_type_oid, - Oid relowner, - char relkind, -- Datum reloptions) -+ Datum reloptions, -+ List *selblList) - { - Form_pg_class new_rel_reltup; -+ Oid relselabel = InvalidOid; -+ ListCell *l; - - /* - * first we update some of the information in our uncataloged relation's -@@ -725,8 +791,21 @@ AddNewRelationTuple(Relation pg_class_de - - new_rel_desc->rd_att->tdtypeid = new_type_oid; - -+ /* SELinux: extract a given security context */ -+ foreach (l, selblList) -+ { -+ DefElem *defel = lfirst(l); -+ -+ if (!defel->defname) -+ { -+ relselabel = sepgsqlInputGivenSecLabel(defel); -+ break; -+ } -+ } -+ - /* 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, relselabel); - } - - -@@ -794,7 +873,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 *selblList) - { - Relation pg_class_desc; - Relation new_rel_desc; -@@ -968,13 +1048,20 @@ heap_create_with_catalog(const char *rel - new_type_oid, - ownerid, - relkind, -- reloptions); -+ reloptions, -+ selblList); - - /* - * 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, selblList); -+ -+ /* -+ * Fixup rel->rd_att->tdhassecacl and rel->rd_att->tdhasseclabel -+ */ -+ new_rel_desc->rd_att->tdhasseclabel -+ = securityTupleDescHasSecLabel(new_rel_desc); - - /* - * Make a dependency link to force the relation to be deleted if its -diff -rpNU3 base/src/backend/catalog/index.c sepgsql-new/src/backend/catalog/index.c ---- base/src/backend/catalog/index.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/backend/catalog/index.c 2009-03-13 18:14:33.000000000 +0900 -@@ -37,6 +37,7 @@ - #include "catalog/pg_constraint.h" - #include "catalog/pg_operator.h" - #include "catalog/pg_opclass.h" -+#include "catalog/pg_security.h" - #include "catalog/pg_tablespace.h" - #include "catalog/pg_type.h" - #include "commands/tablecmds.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->tdhassecXXX -+ */ -+ indexRelation->rd_att->tdhasseclabel -+ = securityTupleDescHasSecLabel(indexRelation); -+ -+ /* - * 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, InvalidOid); - - /* done with pg_class */ - heap_close(pg_class, RowExclusiveLock); -diff -rpNU3 base/src/backend/catalog/pg_aggregate.c sepgsql-new/src/backend/catalog/pg_aggregate.c ---- base/src/backend/catalog/pg_aggregate.c 2008-01-14 22:59:48.000000000 +0900 -+++ sepgsql-new/src/backend/catalog/pg_aggregate.c 2009-03-13 18:14:33.000000000 +0900 -@@ -214,7 +214,8 @@ AggregateCreate(const char *aggName, - PointerGetDatum(NULL), /* parameterNames */ - PointerGetDatum(NULL), /* proconfig */ - 1, /* procost */ -- 0); /* prorows */ -+ 0, /* prorows */ -+ InvalidOid); /* proseclabel */ - - /* - * Okay to create the pg_aggregate entry. -diff -rpNU3 base/src/backend/catalog/pg_largeobject.c sepgsql-new/src/backend/catalog/pg_largeobject.c ---- base/src/backend/catalog/pg_largeobject.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/catalog/pg_largeobject.c 2009-03-13 18:14:33.000000000 +0900 -@@ -18,6 +18,7 @@ - #include "access/heapam.h" - #include "catalog/indexing.h" - #include "catalog/pg_largeobject.h" -+#include "security/sepgsql.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" - -@@ -91,6 +92,8 @@ LargeObjectDrop(Oid loid) - - while ((tuple = systable_getnext(sd)) != NULL) - { -+ if (!found) -+ sepgsqlCheckBlobDrop(tuple); - simple_heap_delete(pg_largeobject, &tuple->t_self); - found = true; - } -diff -rpNU3 base/src/backend/catalog/pg_proc.c sepgsql-new/src/backend/catalog/pg_proc.c ---- base/src/backend/catalog/pg_proc.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/catalog/pg_proc.c 2009-03-13 18:14:33.000000000 +0900 -@@ -27,6 +27,7 @@ - #include "mb/pg_wchar.h" - #include "miscadmin.h" - #include "parser/parse_type.h" -+#include "security/sepgsql.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, -+ Oid proselabel) - { - Oid retval; - int parameterCount; -@@ -339,6 +341,13 @@ ProcedureCreate(const char *procedureNam - - /* Okay, do it... */ - tup = heap_modifytuple(oldtup, tupDesc, values, nulls, replaces); -+ if (OidIsValid(proselabel)) -+ { -+ if (!HeapTupleHasSecLabel(tup)) -+ elog(ERROR, "Unable to assign security label on \"%s\"", -+ RelationGetRelationName(rel)); -+ HeapTupleSetSecLabel(tup, proselabel); -+ } - simple_heap_update(rel, &tup->t_self, tup); - - ReleaseSysCache(oldtup); -@@ -348,6 +357,13 @@ ProcedureCreate(const char *procedureNam - { - /* Creating a new procedure */ - tup = heap_formtuple(tupDesc, values, nulls); -+ if (OidIsValid(proselabel)) -+ { -+ if (!HeapTupleHasSecLabel(tup)) -+ elog(ERROR, "Unable to assign security label on \"%s\"", -+ RelationGetRelationName(rel)); -+ HeapTupleSetSecLabel(tup, proselabel); -+ } - simple_heap_insert(rel, tup); - is_update = false; - } -diff -rpNU3 base/src/backend/catalog/pg_security.c sepgsql-new/src/backend/catalog/pg_security.c ---- base/src/backend/catalog/pg_security.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/catalog/pg_security.c 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,290 @@ -+/* -+ * src/backend/catalog/pg_security.c -+ * routines to support security label management -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#include "postgres.h" -+ -+#include "access/heapam.h" -+#include "access/xact.h" -+#include "catalog/catalog.h" -+#include "catalog/indexing.h" -+#include "catalog/pg_security.h" -+#include "miscadmin.h" -+#include "security/sepgsql.h" -+#include "utils/builtins.h" -+#include "utils/memutils.h" -+#include "utils/rel.h" -+#include "utils/syscache.h" -+ -+bool -+securityTupleDescHasSecLabel(Relation rel) -+{ -+ return sepgsqlTupleDescHasSecLabel(rel); -+} -+ -+static char * -+securityMetaSecurityLabel(void) -+{ -+ return sepgsqlMetaSecurityLabel(); -+} -+ -+typedef struct earlySecLabel -+{ -+ struct earlySecLabel *next; -+ Oid secid; -+ char seclabel[1]; -+} earlySecLabel; -+ -+static earlySecLabel *earlySecLabelList = NULL; -+ -+static Oid -+earlyLookupSecurityId(const char *seclabel) -+{ -+ earlySecLabel *es; -+ Oid minsecid = SecurityRelationId; -+ -+ for (es = earlySecLabelList; es; es = es->next) -+ { -+ if (strcmp(seclabel, es->seclabel) == 0) -+ return es->secid; -+ if (es->secid < minsecid) -+ minsecid = es->secid; -+ } -+ -+ /* not found */ -+ es = MemoryContextAllocZero(TopMemoryContext, -+ sizeof(*es) + strlen(seclabel)); -+ es->next = earlySecLabelList; -+ es->secid = minsecid - 1; -+ strcpy(es->seclabel, seclabel); -+ earlySecLabelList = es; -+ -+ return es->secid; -+} -+ -+static char * -+earlyLookupSecurityLabel(Oid secid) -+{ -+ earlySecLabel *es; -+ -+ for (es = earlySecLabelList; es; es = es->next) -+ { -+ if (es->secid == secid) -+ return pstrdup(es->seclabel); -+ } -+ -+ return NULL; /* not found */ -+} -+ -+void -+securityPostBootstrapingMode(void) -+{ -+ Relation rel; -+ CatalogIndexState ind; -+ HeapTuple tuple; -+ earlySecLabel *es; -+ Oid labelSid; -+ Datum values[Natts_pg_security]; -+ bool nulls[Natts_pg_security]; -+ char *meta_label; -+ -+ if (!earlySecLabelList) -+ return; /* do nothing */ -+ -+ StartTransactionCommand(); -+ -+ rel = heap_open(SecurityRelationId, RowExclusiveLock); -+ ind = CatalogOpenIndexes(rel); -+ -+ if (RelationGetDescr(rel)->tdhasseclabel && -+ (meta_label = securityMetaSecurityLabel()) != NULL) -+ labelSid = earlyLookupSecurityId(meta_label); -+ else -+ labelSid = InvalidOid; -+ -+ for (es = earlySecLabelList; es; es = es->next) -+ { -+ memset(nulls, false, sizeof(nulls)); -+ -+ values[Anum_pg_security_seclabel - 1] -+ = CStringGetTextDatum(es->seclabel); -+ -+ tuple = heap_form_tuple(RelationGetDescr(rel), -+ values, nulls); -+ HeapTupleSetOid(tuple, es->secid); -+ if (HeapTupleHasSecLabel(tuple)) -+ HeapTupleSetSecLabel(tuple, labelSid); -+ -+ simple_heap_insert(rel, tuple); -+ CatalogIndexInsert(ind, tuple); -+ -+ heap_freetuple(tuple); -+ } -+ -+ CatalogCloseIndexes(ind); -+ heap_close(rel, RowExclusiveLock); -+ -+ CommitTransactionCommand(); -+} -+ -+Oid -+securityLookupSecurityId(const char *seclabel) -+{ -+ Relation rel; -+ CatalogIndexState ind; -+ HeapTuple tuple; -+ Oid labelOid; -+ Oid labelSid; -+ Datum values[Natts_pg_security]; -+ bool nulls[Natts_pg_security]; -+ char *meta_label; -+ -+ if (IsBootstrapProcessingMode()) -+ return earlyLookupSecurityId(seclabel); -+ -+ /* -+ * lookup syscache at first -+ */ -+ tuple = SearchSysCache(SECURITYLABEL, -+ CStringGetTextDatum(seclabel), -+ 0, 0, 0); -+ if (HeapTupleIsValid(tuple)) -+ { -+ labelOid = HeapTupleGetOid(tuple); -+ ReleaseSysCache(tuple); -+ return labelOid; -+ } -+ -+ /* -+ * Not found, insert a new one into pg_security -+ */ -+ rel = heap_open(SecurityRelationId, RowExclusiveLock); -+ -+ ind = CatalogOpenIndexes(rel); -+ -+ if (RelationGetDescr(rel)->tdhasseclabel && -+ (meta_label = securityMetaSecurityLabel()) != NULL) -+ { -+ if (strcmp(seclabel, meta_label) == 0) -+ { -+ labelOid = labelSid = GetNewOid(rel); -+ } -+ else -+ { -+ labelOid = GetNewOid(rel); -+ labelSid = securityLookupSecurityId(meta_label); -+ } -+ } -+ else -+ { -+ labelOid = GetNewOid(rel); -+ labelSid = InvalidOid; -+ } -+ -+ memset(nulls, false, sizeof(nulls)); -+ values[Anum_pg_security_seclabel - 1] -+ = CStringGetTextDatum(seclabel); -+ -+ tuple = heap_form_tuple(RelationGetDescr(rel), -+ values, nulls); -+ -+ 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; -+} -+ -+char * -+securityLookupSecurityLabel(Oid secid) -+{ -+ HeapTuple tuple; -+ Datum labelTxt; -+ char *label; -+ bool isnull; -+ -+ if (!OidIsValid(secid)) -+ return NULL; -+ -+ if (IsBootstrapProcessingMode()) -+ return earlyLookupSecurityLabel(secid); -+ -+ tuple = SearchSysCache(SECURITYOID, -+ ObjectIdGetDatum(secid), -+ 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; -+} -+ -+/* -+ * "security_label" system column related stuffs -+ */ -+Oid -+securityTransSecLabelIn(char *seclabel) -+{ -+ char *rawlabel = sepgsqlSecurityLabelTransIn(seclabel); -+ -+ if (!sepgsqlCheckValidSecurityLabel(rawlabel)) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("invalid security label: %s", rawlabel))); -+ -+ return securityLookupSecurityId(rawlabel); -+} -+ -+char * -+securityTransSecLabelOut(Oid secid) -+{ -+ char *rawlabel = securityLookupSecurityLabel(secid); -+ -+ if (!rawlabel || !sepgsqlCheckValidSecurityLabel(rawlabel)) -+ rawlabel = sepgsqlGetUnlabeledLabel(); -+ -+ if (!rawlabel) -+ rawlabel = pstrdup("unlabeled"); -+ -+ return sepgsqlSecurityLabelTransOut(rawlabel); -+} -+ -+Datum -+securityHeapGetSecLabelSysattr(HeapTuple tuple) -+{ -+ Oid secid = HeapTupleGetSecLabel(tuple); -+ -+ return CStringGetTextDatum(securityTransSecLabelOut(secid)); -+} -diff -rpNU3 base/src/backend/catalog/toasting.c sepgsql-new/src/backend/catalog/toasting.c ---- base/src/backend/catalog/toasting.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/catalog/toasting.c 2009-03-13 18:14:33.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-new/src/backend/commands/cluster.c ---- base/src/backend/commands/cluster.c 2008-02-03 01:11:28.000000000 +0900 -+++ sepgsql-new/src/backend/commands/cluster.c 2009-03-13 18:14:33.000000000 +0900 -@@ -34,6 +34,7 @@ - #include "commands/trigger.h" - #include "commands/vacuum.h" - #include "miscadmin.h" -+#include "security/sepgsql.h" - #include "storage/procarray.h" - #include "utils/acl.h" - #include "utils/fmgroids.h" -@@ -666,7 +667,8 @@ make_new_heap(Oid OIDOldHeap, const char - 0, - ONCOMMIT_NOOP, - reloptions, -- allowSystemTableMods); -+ allowSystemTableMods, -+ NIL); - - ReleaseSysCache(tuple); - -@@ -856,6 +858,9 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOl - /* Preserve OID, if any */ - if (NewHeap->rd_rel->relhasoids) - HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple)); -+ /* Preserve SecLabel, if any */ -+ if (HeapTupleHasSecLabel(copiedTuple)) -+ 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-new/src/backend/commands/copy.c ---- base/src/backend/commands/copy.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/commands/copy.c 2009-03-13 18:14:33.000000000 +0900 -@@ -22,7 +22,9 @@ - - #include "access/heapam.h" - #include "access/xact.h" -+#include "catalog/heap.h" - #include "catalog/namespace.h" -+#include "catalog/pg_security.h" - #include "catalog/pg_type.h" - #include "commands/copy.h" - #include "commands/trigger.h" -@@ -34,6 +36,8 @@ - #include "optimizer/planner.h" - #include "parser/parse_relation.h" - #include "rewrite/rewriteHandler.h" -+#include "security/rowlevel.h" -+#include "security/sepgsql.h" - #include "storage/fd.h" - #include "tcop/tcopprot.h" - #include "utils/acl.h" -@@ -159,6 +163,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 +250,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 +1081,9 @@ DoCopy(const CopyStmt *stmt, const char - /* Generate or convert list of attributes to process */ - cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist); - -+ /* SELinux checks table/column level permissions */ -+ sepgsqlCheckCopyTable(cstate->rel, cstate->attnumlist, is_from); -+ - num_phys_attrs = tupDesc->natts; - - /* Convert FORCE QUOTE name list to per-column flags, check validity */ -@@ -1089,11 +1100,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 +1143,23 @@ 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 +1287,9 @@ DoCopyTo(CopyState cstate) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is a directory", cstate->filename))); -+ -+ /* SELinux: check file:{write} permission */ -+ sepgsqlCheckFileWrite(fileno(cstate->copy_file), cstate->filename); - } - - PG_TRY(); -@@ -1305,16 +1353,31 @@ 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: -+ 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 +1432,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 +1465,18 @@ CopyTo(CopyState cstate) - { - CHECK_FOR_INTERRUPTS(); - -+ /* Row-level controls on the fetched tuple */ -+ if (!rowlvCopyToTuple(cstate->rel, tuple)) -+ continue; -+ - /* Deconstruct the tuple ... faster than repeated heap_getattr */ - heap_deform_tuple(tuple, tupDesc, values, nulls); - - /* Format and send the data */ -- CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls); -+ CopyOneRowTo(cstate, -+ HeapTupleGetOid(tuple), -+ HeapTupleGetSecLabel(tuple), -+ values, nulls); - } - - heap_endscan(scandesc); -@@ -1425,7 +1502,7 @@ 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 +1541,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 +1553,23 @@ CopyOneRowTo(CopyState cstate, Oid tuple - need_delim = true; - } - -+ switch (attnum) -+ { -+ case SecurityLabelAttributeNumber: -+ value = CStringGetTextDatum(securityTransSecLabelOut(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 +1581,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 +1592,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,8 +1726,10 @@ CopyFrom(CopyState cstate) - num_defaults; - FmgrInfo *in_functions; - FmgrInfo oid_in_function; -+ FmgrInfo seclabel_in_function; - Oid *typioparams; - Oid oid_typioparam; -+ Oid seclabel_typioparam; - int attnum; - int i; - Oid in_func_oid; -@@ -1737,6 +1832,9 @@ CopyFrom(CopyState cstate) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is a directory", cstate->filename))); -+ -+ /* SELinux checks file:{read} permission */ -+ sepgsqlCheckFileRead(fileno(cstate->copy_file), cstate->filename); - } - - tupDesc = RelationGetDescr(cstate->rel); -@@ -1872,6 +1970,18 @@ CopyFrom(CopyState cstate) - fmgr_info(in_func_oid, &oid_in_function); - } - -+ if (list_member_int(cstate->attnumlist, -+ SecurityLabelAttributeNumber)) -+ { -+ if (!cstate->binary) -+ getTypeInputInfo(TEXTOID, -+ &in_func_oid, &seclabel_typioparam); -+ else -+ getTypeBinaryInputInfo(TEXTOID, -+ &in_func_oid, &seclabel_typioparam); -+ fmgr_info(in_func_oid, &seclabel_in_function); -+ } -+ - values = (Datum *) palloc(num_phys_attrs * sizeof(Datum)); - nulls = (char *) palloc(num_phys_attrs * sizeof(char)); - -@@ -1904,6 +2014,7 @@ CopyFrom(CopyState cstate) - { - bool skip_tuple; - Oid loaded_oid = InvalidOid; -+ Oid loaded_seclabel = InvalidOid; - - CHECK_FOR_INTERRUPTS(); - -@@ -1975,31 +2086,55 @@ CopyFrom(CopyState cstate) - /* Loop to read the user attributes on the line. */ - foreach(cur, cstate->attnumlist) - { -+ Form_pg_attribute attForm; -+ Datum dat; - int attnum = lfirst_int(cur); - int m = attnum - 1; - -+ if (SystemAttributeIsWritable(attnum)) -+ attForm = SystemAttributeDefinition(attnum, true); -+ else -+ attForm = attr[m]; -+ - if (fieldno >= fldct) - ereport(ERROR, - (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), - errmsg("missing data for column \"%s\"", -- NameStr(attr[m]->attname)))); -+ NameStr(attForm->attname)))); - string = field_strings[fieldno++]; - -- if (cstate->csv_mode && string == NULL && -- cstate->force_notnull_flags[m]) -+ cstate->cur_attname = NameStr(attForm->attname); -+ cstate->cur_attval = string; -+ -+ switch (attnum) - { -- /* Go ahead and read the NULL string */ -- string = cstate->null_print; -- } -+ case SecurityLabelAttributeNumber: -+ if (!string) -+ break; - -- cstate->cur_attname = NameStr(attr[m]->attname); -- cstate->cur_attval = string; -- values[m] = InputFunctionCall(&in_functions[m], -- string, -- typioparams[m], -- attr[m]->atttypmod); -- if (string != NULL) -- nulls[m] = ' '; -+ dat = InputFunctionCall(&seclabel_in_function, -+ string, -+ seclabel_typioparam, -+ attForm->atttypmod); -+ loaded_seclabel -+ = securityTransSecLabelIn(TextDatumGetCString(dat)); -+ break; -+ -+ default: -+ if (cstate->csv_mode && string == NULL && -+ cstate->force_notnull_flags[m]) -+ { -+ /* Go ahead and read the NULL string */ -+ string = cstate->null_print; -+ } -+ -+ values[m] = InputFunctionCall(&in_functions[m], -+ string, -+ typioparams[m], -+ attForm->atttypmod); -+ if (string != NULL) -+ nulls[m] = ' '; -+ } - cstate->cur_attname = NULL; - cstate->cur_attval = NULL; - } -@@ -2045,18 +2180,41 @@ CopyFrom(CopyState cstate) - i = 0; - foreach(cur, cstate->attnumlist) - { -+ Form_pg_attribute attForm; -+ Datum dat; - int attnum = lfirst_int(cur); - int m = attnum - 1; - -- cstate->cur_attname = NameStr(attr[m]->attname); -+ if (SystemAttributeIsWritable(attnum)) -+ attForm = SystemAttributeDefinition(attnum, false); -+ else -+ attForm = attr[m]; -+ -+ cstate->cur_attname = NameStr(attForm->attname); - i++; -- values[m] = CopyReadBinaryAttribute(cstate, -- i, -- &in_functions[m], -- typioparams[m], -- attr[m]->atttypmod, -- &isnull); -- nulls[m] = isnull ? 'n' : ' '; -+ -+ switch (attnum) -+ { -+ case SecurityLabelAttributeNumber: -+ dat = CopyReadBinaryAttribute(cstate, i, -+ &seclabel_in_function, -+ seclabel_typioparam, -+ attForm->atttypmod, -+ &isnull); -+ if (!isnull) -+ loaded_seclabel -+ = securityTransSecLabelIn(TextDatumGetCString(dat)); -+ break; -+ -+ default: -+ values[m] = CopyReadBinaryAttribute(cstate, i, -+ &in_functions[m], -+ typioparams[m], -+ attr[m]->atttypmod, -+ &isnull); -+ nulls[m] = isnull ? 'n' : ' '; -+ break; -+ } - cstate->cur_attname = NULL; - } - } -@@ -2080,6 +2238,9 @@ CopyFrom(CopyState cstate) - if (cstate->oids && file_has_oids) - HeapTupleSetOid(tuple, loaded_oid); - -+ if (HeapTupleHasSecLabel(tuple)) -+ HeapTupleSetSecLabel(tuple, loaded_seclabel); -+ - /* Triggers and stuff need to be invoked in query context. */ - MemoryContextSwitchTo(oldcontext); - -@@ -2102,6 +2263,9 @@ CopyFrom(CopyState cstate) - } - } - -+ if (!skip_tuple && !rowlvHeapTupleInsert(cstate->rel, tuple, false)) -+ skip_tuple = true; -+ - if (!skip_tuple) - { - /* Place tuple in tuple slot */ -@@ -3366,6 +3530,13 @@ CopyGetAttnums(TupleDesc tupDesc, Relati - } - 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) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), -@@ -3413,7 +3584,8 @@ 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-new/src/backend/commands/dbcommands.c ---- base/src/backend/commands/dbcommands.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql-new/src/backend/commands/dbcommands.c 2009-03-13 18:14:33.000000000 +0900 -@@ -40,6 +40,7 @@ - #include "miscadmin.h" - #include "pgstat.h" - #include "postmaster/bgwriter.h" -+#include "security/sepgsql.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 *dselabel = NULL; - char *dbname = stmt->dbname; - char *dbowner = NULL; - const char *dbtemplate = NULL; -@@ -160,6 +162,14 @@ createdb(const CreatedbStmt *stmt) - errmsg("LOCATION is not supported anymore"), - errhint("Consider using tablespaces instead."))); - } -+ else if (strcmp(defel->defname, "security_context") == 0) -+ { -+ if (dselabel) -+ ereport(ERROR, -+ (errcode(ERRCODE_SYNTAX_ERROR), -+ errmsg("conflicting or redundant options"))); -+ dselabel = defel; -+ } - else - elog(ERROR, "option \"%s\" not recognized", - defel->defname); -@@ -433,7 +443,15 @@ createdb(const CreatedbStmt *stmt) - new_record, new_record_nulls); - - HeapTupleSetOid(tuple, dboid); -+ if (dselabel) -+ { -+ Oid secid = sepgsqlInputGivenSecLabel(dselabel); - -+ if (!HeapTupleHasSecLabel(tuple)) -+ elog(ERROR, "Unable to assign security label on \"%s\"", -+ RelationGetRelationName(pg_database_rel)); -+ HeapTupleSetSecLabel(tuple, secid); -+ } - simple_heap_insert(pg_database_rel, tuple); - - /* Update indexes */ -@@ -858,6 +876,7 @@ AlterDatabase(AlterDatabaseStmt *stmt) - ListCell *option; - int connlimit = -1; - DefElem *dconnlimit = NULL; -+ DefElem *dselabel = NULL; - Datum new_record[Natts_pg_database]; - char new_record_nulls[Natts_pg_database]; - char new_record_repl[Natts_pg_database]; -@@ -875,6 +894,14 @@ AlterDatabase(AlterDatabaseStmt *stmt) - errmsg("conflicting or redundant options"))); - dconnlimit = defel; - } -+ else if (strcmp(defel->defname, "security_context") == 0) -+ { -+ if (dselabel) -+ ereport(ERROR, -+ (errcode(ERRCODE_SYNTAX_ERROR), -+ errmsg("conflicting or redundant options"))); -+ dselabel = defel; -+ } - else - elog(ERROR, "option \"%s\" not recognized", - defel->defname); -@@ -920,6 +947,15 @@ AlterDatabase(AlterDatabaseStmt *stmt) - - newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), new_record, - new_record_nulls, new_record_repl); -+ if (dselabel) -+ { -+ Oid secid = sepgsqlInputGivenSecLabel(dselabel); -+ -+ if (!HeapTupleHasSecLabel(newtuple)) -+ elog(ERROR, "Unable to assign security label on \"%s\"", -+ RelationGetRelationName(rel)); -+ HeapTupleSetSecLabel(newtuple, secid); -+ } - simple_heap_update(rel, &tuple->t_self, newtuple); - - /* Update indexes */ -diff -rpNU3 base/src/backend/commands/functioncmds.c sepgsql-new/src/backend/commands/functioncmds.c ---- base/src/backend/commands/functioncmds.c 2009-03-15 17:47:25.000000000 +0900 -+++ sepgsql-new/src/backend/commands/functioncmds.c 2009-03-15 17:58:10.000000000 +0900 -@@ -47,6 +47,7 @@ - #include "miscadmin.h" - #include "parser/parse_func.h" - #include "parser/parse_type.h" -+#include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -@@ -295,7 +296,8 @@ compute_common_attribute(DefElem *defel, - DefElem **security_item, - List **set_items, - DefElem **cost_item, -- DefElem **rows_item) -+ DefElem **rows_item, -+ DefElem **selabel_item) - { - if (strcmp(defel->defname, "volatility") == 0) - { -@@ -336,6 +338,13 @@ compute_common_attribute(DefElem *defel, - - *rows_item = defel; - } -+ else if (strcmp(defel->defname, "security_context") == 0) -+ { -+ if (*selabel_item) -+ goto duplicate_error; -+ -+ *selabel_item = defel; -+ } - else - return false; - -@@ -412,7 +421,8 @@ compute_attributes_sql_style(List *optio - bool *security_definer, - ArrayType **proconfig, - float4 *procost, -- float4 *prorows) -+ float4 *prorows, -+ Oid *proselabel) - { - ListCell *option; - DefElem *as_item = NULL; -@@ -423,6 +433,7 @@ compute_attributes_sql_style(List *optio - List *set_items = NIL; - DefElem *cost_item = NULL; - DefElem *rows_item = NULL; -+ DefElem *selabel_item = NULL; - - foreach(option, options) - { -@@ -450,7 +461,8 @@ compute_attributes_sql_style(List *optio - &security_item, - &set_items, - &cost_item, -- &rows_item)) -+ &rows_item, -+ &selabel_item)) - { - /* recognized common option */ - continue; -@@ -506,6 +518,8 @@ compute_attributes_sql_style(List *optio - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("ROWS must be positive"))); - } -+ if (selabel_item) -+ *proselabel = sepgsqlInputGivenSecLabel(selabel_item); - } - - -@@ -621,6 +635,7 @@ CreateFunction(CreateFunctionStmt *stmt) - ArrayType *proconfig; - float4 procost; - float4 prorows; -+ Oid proselabel; - HeapTuple languageTuple; - Form_pg_language languageStruct; - List *as_clause; -@@ -642,12 +657,13 @@ CreateFunction(CreateFunctionStmt *stmt) - proconfig = NULL; - procost = -1; /* indicates not set */ - prorows = -1; /* indicates not set */ -+ proselabel = InvalidOid; /* follows default labeling behavior */ - - /* override attributes from explicit list */ - compute_attributes_sql_style(stmt->options, - &as_clause, &language, - &volatility, &isStrict, &security, -- &proconfig, &procost, &prorows); -+ &proconfig, &procost, &prorows, &proselabel); - - /* Convert language name to canonical case */ - languageName = case_translate_language_name(language); -@@ -801,7 +817,8 @@ CreateFunction(CreateFunctionStmt *stmt) - PointerGetDatum(parameterNames), - PointerGetDatum(proconfig), - procost, -- prorows); -+ prorows, -+ proselabel); - } - - -@@ -1151,6 +1168,7 @@ AlterFunction(AlterFunctionStmt *stmt) - List *set_items = NIL; - DefElem *cost_item = NULL; - DefElem *rows_item = NULL; -+ DefElem *selabel_item = NULL; - - rel = heap_open(ProcedureRelationId, RowExclusiveLock); - -@@ -1188,7 +1206,8 @@ AlterFunction(AlterFunctionStmt *stmt) - &security_def_item, - &set_items, - &cost_item, -- &rows_item) == false) -+ &rows_item, -+ &selabel_item) == false) - elog(ERROR, "option \"%s\" not recognized", defel->defname); - } - -@@ -1218,7 +1237,7 @@ AlterFunction(AlterFunctionStmt *stmt) - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("ROWS is not applicable when function does not return a set"))); - } -- if (set_items) -+ if (set_items || selabel_item) - { - Datum datum; - bool isnull; -@@ -1227,30 +1246,42 @@ AlterFunction(AlterFunctionStmt *stmt) - char repl_null[Natts_pg_proc]; - char repl_repl[Natts_pg_proc]; - -- /* extract existing proconfig setting */ -- datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull); -- a = isnull ? NULL : DatumGetArrayTypeP(datum); -- -- /* update according to each SET or RESET item, left to right */ -- a = update_proconfig_value(a, set_items); -- -- /* update the tuple */ - memset(repl_repl, ' ', sizeof(repl_repl)); -- repl_repl[Anum_pg_proc_proconfig - 1] = 'r'; - -- if (a == NULL) -+ if (set_items) - { -- repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0; -- repl_null[Anum_pg_proc_proconfig - 1] = 'n'; -+ /* extract existing proconfig setting */ -+ datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull); -+ a = isnull ? NULL : DatumGetArrayTypeP(datum); -+ -+ /* update according to each SET or RESET item, left to right */ -+ a = update_proconfig_value(a, set_items); -+ -+ /* update the tuple */ -+ repl_repl[Anum_pg_proc_proconfig - 1] = 'r'; -+ -+ if (a == NULL) -+ { -+ repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0; -+ repl_null[Anum_pg_proc_proconfig - 1] = 'n'; -+ } -+ else -+ { -+ repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a); -+ repl_null[Anum_pg_proc_proconfig - 1] = ' '; -+ } - } -- else -+ tup = heap_modifytuple(tup, RelationGetDescr(rel), -+ repl_val, repl_null, repl_repl); -+ if (selabel_item) - { -- repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a); -- repl_null[Anum_pg_proc_proconfig - 1] = ' '; -- } -+ Oid secid = sepgsqlInputGivenSecLabel(selabel_item); - -- tup = heap_modifytuple(tup, RelationGetDescr(rel), -- repl_val, repl_null, repl_repl); -+ if (!HeapTupleHasSecLabel(tup)) -+ elog(ERROR, "Unable to assign security label on \"%s\"", -+ RelationGetRelationName(rel)); -+ HeapTupleSetSecLabel(tup, secid); -+ } - } - - /* Do the update */ -diff -rpNU3 base/src/backend/commands/lockcmds.c sepgsql-new/src/backend/commands/lockcmds.c ---- base/src/backend/commands/lockcmds.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/commands/lockcmds.c 2009-03-13 18:14:33.000000000 +0900 -@@ -18,6 +18,7 @@ - #include "catalog/namespace.h" - #include "commands/lockcmds.h" - #include "miscadmin.h" -+#include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/lsyscache.h" - -@@ -55,7 +56,8 @@ LockTableCommand(LockStmt *lockstmt) - aclresult = pg_class_aclcheck(reloid, GetUserId(), - ACL_UPDATE | ACL_DELETE); - -- if (aclresult != ACLCHECK_OK) -+ if (aclresult != ACLCHECK_OK || -+ !sepgsqlCheckTableLock(reloid)) - aclcheck_error(aclresult, ACL_KIND_CLASS, - get_rel_name(reloid)); - -diff -rpNU3 base/src/backend/commands/proclang.c sepgsql-new/src/backend/commands/proclang.c ---- base/src/backend/commands/proclang.c 2008-06-12 22:34:19.000000000 +0900 -+++ sepgsql-new/src/backend/commands/proclang.c 2009-03-13 18:14:33.000000000 +0900 -@@ -146,7 +146,8 @@ CreateProceduralLanguage(CreatePLangStmt - PointerGetDatum(NULL), - PointerGetDatum(NULL), - 1, -- 0); -+ 0, -+ InvalidOid); - } - - /* -@@ -179,7 +180,8 @@ CreateProceduralLanguage(CreatePLangStmt - PointerGetDatum(NULL), - PointerGetDatum(NULL), - 1, -- 0); -+ 0, -+ InvalidOid); - } - } - else -diff -rpNU3 base/src/backend/commands/tablecmds.c sepgsql-new/src/backend/commands/tablecmds.c ---- base/src/backend/commands/tablecmds.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql-new/src/backend/commands/tablecmds.c 2009-03-13 18:14:33.000000000 +0900 -@@ -57,6 +57,7 @@ - #include "parser/parser.h" - #include "rewrite/rewriteDefine.h" - #include "rewrite/rewriteHandler.h" -+#include "security/sepgsql.h" - #include "storage/smgr.h" - #include "utils/acl.h" - #include "utils/builtins.h" -@@ -259,6 +260,7 @@ static void ATExecEnableDisableRule(Rela - char fires_when); - static void ATExecAddInherit(Relation rel, RangeVar *parent); - static void ATExecDropInherit(Relation rel, RangeVar *parent); -+static void ATExecSetSecurityLabel(Relation rel, const char *name, DefElem *defel); - static void copy_relation_data(Relation rel, SMgrRelation dst); - - -@@ -281,6 +283,7 @@ DefineRelation(CreateStmt *stmt, char re - TupleDesc descriptor; - List *inheritOids; - List *old_constraints; -+ List *selblList; - bool localHasOids; - int parentOidCount; - List *rawDefaults; -@@ -365,6 +368,10 @@ DefineRelation(CreateStmt *stmt, char re - schema = MergeAttributes(schema, stmt->inhRelations, - stmt->relation->istemp, - &inheritOids, &old_constraints, &parentOidCount); -+ /* -+ * SELinux: fetch SECURITY_CONTEXT = '...' from CREATE TABLE statement -+ */ -+ selblList = sepgsqlInputGivenSecLabelRelation(stmt); - - /* - * Create a relation descriptor from the relation schema and create the -@@ -434,7 +441,8 @@ DefineRelation(CreateStmt *stmt, char re - parentOidCount, - stmt->oncommit, - reloptions, -- allowSystemTableMods); -+ allowSystemTableMods, -+ selblList); - - StoreCatalogInheritance(relationId, inheritOids); - -@@ -660,6 +668,10 @@ truncate_check_rel(Relation rel) - errmsg("permission denied: \"%s\" is a system catalog", - RelationGetRelationName(rel)))); - -+ if (!sepgsqlCheckTableTruncate(rel)) -+ aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, -+ RelationGetRelationName(rel)); -+ - /* - * We can never allow truncation of shared or nailed-in-cache relations, - * because we can't support changing their relfilenode values. -@@ -2031,6 +2043,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 +2266,9 @@ ATExecCmd(AlteredTableInfo *tab, Relatio - case AT_DropInherit: - ATExecDropInherit(rel, (RangeVar *) cmd->def); - break; -+ case AT_SetSecurityLabel: -+ ATExecSetSecurityLabel(rel, cmd->name, (DefElem *) cmd->def); -+ break; - default: /* oops */ - elog(ERROR, "unrecognized alter table type: %d", - (int) cmd->subtype); -@@ -2591,11 +2607,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oi - if (newrel) - { - Oid tupOid = InvalidOid; -+ Oid tupSecLabel = InvalidOid; - - /* Extract data from old tuple */ - heap_deform_tuple(tuple, oldTupDesc, values, isnull); - if (oldTupDesc->tdhasoid) - tupOid = HeapTupleGetOid(tuple); -+ if (HeapTupleHasSecLabel(tuple)) -+ tupSecLabel = HeapTupleGetSecLabel(tuple); - - /* Set dropped attributes to null in new tuple */ - foreach(lc, dropped_attrs) -@@ -2627,6 +2646,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oi - /* Preserve OID, if any */ - if (newTupDesc->tdhasoid) - HeapTupleSetOid(tuple, tupOid); -+ /* Preserve SecLabel, if any */ -+ if (HeapTupleHasSecLabel(tuple)) -+ HeapTupleSetSecLabel(tuple, tupSecLabel); - } - - /* Now check any constraints on the possibly-changed tuple */ -@@ -3113,6 +3135,7 @@ ATExecAddColumn(AlteredTableInfo *tab, R - - attributeTuple = heap_addheader(Natts_pg_attribute, - false, -+ RelationGetDescr(attrdesc)->tdhasseclabel, - ATTRIBUTE_TUPLE_SIZE, - (void *) &attributeD); - -@@ -6515,6 +6538,95 @@ ATExecDropInherit(Relation rel, RangeVar - heap_close(parent_rel, NoLock); - } - -+void -+ATExecSetSecurityLabel(Relation rel, const char *attr_name, DefElem *defel) -+{ -+ Relation class_rel; -+ Relation attr_rel; -+ HeapTuple tuple, newtup; -+ Oid secid; -+ -+ if (!sepgsqlIsEnabled()) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: disabled now"))); -+ -+ Assert(IsA(defel, DefElem)); -+ -+ if (!attr_name) -+ { -+ Datum values[Natts_pg_class]; -+ bool nulls[Natts_pg_class]; -+ bool replaces[Natts_pg_class]; -+ -+ memset(replaces, false, sizeof(replaces)); -+ -+ class_rel = heap_open(RelationRelationId, RowExclusiveLock); -+ -+ tuple = SearchSysCache(RELOID, -+ ObjectIdGetDatum(RelationGetRelid(rel)), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for relation: \"%s\"", -+ RelationGetRelationName(rel)); -+ /* -+ * NOTE: heap_modify_tuple() is necessary to make sure -+ * newtup has HEAP_HAS_SECLABEL and a field to store -+ * security lidentifier. -+ */ -+ newtup = heap_modify_tuple(tuple, RelationGetDescr(class_rel), -+ values, nulls, replaces); -+ if (!HeapTupleHasSecLabel(newtup)) -+ elog(ERROR, "Unable to assign security label on \"%s\"", -+ RelationGetRelationName(class_rel)); -+ -+ secid = sepgsqlInputGivenSecLabel(defel); -+ HeapTupleSetSecLabel(newtup, secid); -+ -+ simple_heap_update(class_rel, &tuple->t_self, newtup); -+ -+ CatalogUpdateIndexes(class_rel, newtup); -+ -+ ReleaseSysCache(tuple); -+ heap_close(class_rel, RowExclusiveLock); -+ } -+ else -+ { -+ Datum values[Natts_pg_attribute]; -+ bool nulls[Natts_pg_attribute]; -+ bool replaces[Natts_pg_attribute]; -+ -+ memset(replaces, false, sizeof(replaces)); -+ -+ attr_rel = heap_open(AttributeRelationId, RowExclusiveLock); -+ -+ tuple = SearchSysCacheAttName(RelationGetRelid(rel), -+ attr_name); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for column \"%s.%s\"", -+ RelationGetRelationName(rel), attr_name); -+ /* -+ * NOTE: heap_modify_tuple() is necessary to make sure -+ * newtup has HEAP_HAS_SECLABEL and a field to store -+ * security lidentifier. -+ */ -+ newtup = heap_modify_tuple(tuple, RelationGetDescr(attr_rel), -+ values, nulls, replaces); -+ if (!HeapTupleHasSecLabel(newtup)) -+ elog(ERROR, "Unable to assign security label on \"%s\"", -+ RelationGetRelationName(attr_rel)); -+ -+ secid = sepgsqlInputGivenSecLabel(defel); -+ HeapTupleSetSecLabel(newtup, secid); -+ -+ simple_heap_update(attr_rel, &tuple->t_self, newtup); -+ -+ CatalogUpdateIndexes(attr_rel, newtup); -+ -+ ReleaseSysCache(tuple); -+ heap_close(attr_rel, RowExclusiveLock); -+ } -+} - - /* - * Execute ALTER TABLE SET SCHEMA -diff -rpNU3 base/src/backend/executor/execJunk.c sepgsql-new/src/backend/executor/execJunk.c ---- base/src/backend/executor/execJunk.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/executor/execJunk.c 2009-03-13 18:14:33.000000000 +0900 -@@ -60,7 +60,7 @@ - * An optional resultSlot can be passed as well. - */ - JunkFilter * --ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot) -+ExecInitJunkFilter(List *targetList, bool hasoid, bool hasseclabel, TupleTableSlot *slot) - { - JunkFilter *junkfilter; - TupleDesc cleanTupType; -@@ -72,7 +72,7 @@ ExecInitJunkFilter(List *targetList, boo - /* - * Compute the tuple descriptor for the cleaned tuple. - */ -- cleanTupType = ExecCleanTypeFromTL(targetList, hasoid); -+ cleanTupType = ExecCleanTypeFromTL(targetList, hasoid, hasseclabel); - - /* - * Use the given slot, or make a new slot if we weren't given one. -diff -rpNU3 base/src/backend/executor/execMain.c sepgsql-new/src/backend/executor/execMain.c ---- base/src/backend/executor/execMain.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql-new/src/backend/executor/execMain.c 2009-03-15 17:38:39.000000000 +0900 -@@ -38,6 +38,7 @@ - #include "access/xact.h" - #include "catalog/heap.h" - #include "catalog/namespace.h" -+#include "catalog/pg_security.h" - #include "catalog/toasting.h" - #include "commands/tablespace.h" - #include "commands/trigger.h" -@@ -49,6 +50,8 @@ - #include "parser/parse_clause.h" - #include "parser/parse_expr.h" - #include "parser/parsetree.h" -+#include "security/rowlevel.h" -+#include "security/sepgsql.h" - #include "storage/smgr.h" - #include "utils/acl.h" - #include "utils/builtins.h" -@@ -383,7 +386,10 @@ ExecCheckRTPerms(List *rangeTable) - - foreach(l, rangeTable) - { -- ExecCheckRTEPerms((RangeTblEntry *) lfirst(l)); -+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); -+ -+ ExecCheckRTEPerms(rte); -+ sepgsqlCheckRTEPerms(rte); - } - } - -@@ -410,6 +416,13 @@ ExecCheckRTEPerms(RangeTblEntry *rte) - * No work if requiredPerms is empty. - */ - requiredPerms = rte->requiredPerms; -+ -+ /* fixup ACL_SELECT_FOR_UPDATE */ -+ if (requiredPerms & ACL_SELECT_FOR_UPDATE) -+ { -+ requiredPerms &= ~ACL_SELECT_FOR_UPDATE; -+ requiredPerms |= ACL_UPDATE; -+ } - if (requiredPerms == 0) - return; - -@@ -738,15 +751,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 -@@ -790,6 +804,7 @@ InitPlan(QueryDesc *queryDesc, int eflag - - j = ExecInitJunkFilter(planstate->plan->targetlist, - tupType->tdhasoid, -+ tupType->tdhasseclabel, - ExecAllocTableSlot(estate->es_tupleTable)); - estate->es_junkFilter = j; - if (estate->es_result_relation_info) -@@ -848,7 +863,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 +1186,33 @@ ExecContextForcesOids(PlanState *plansta - return false; - } - -+/* -+ * ExecContextForcesSecLabel -+ * -+ * We need to ensure that result tuples have space for security label, -+ * if the security feature need to store it within the given relation. -+ */ -+bool ExecContextForcesSecLabel(PlanState *planstate, bool *hassecurity) -+{ -+ if (planstate->state->es_select_into) -+ { -+ *hassecurity = securityTupleDescHasSecLabel(NULL); -+ return true; -+ } -+ else -+ { -+ ResultRelInfo *ri = planstate->state->es_result_relation_info; -+ -+ if (ri && ri->ri_RelationDesc) -+ { -+ *hassecurity = securityTupleDescHasSecLabel(ri->ri_RelationDesc); -+ return true; -+ } -+ } -+ -+ return false; -+} -+ - /* ---------------------------------------------------------------- - * ExecEndPlan - * -@@ -1251,6 +1293,47 @@ 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, Oid *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_FEATURE_NOT_SUPPORTED), -+ errmsg("setting NULL on \"%s\" system column is not supported", -+ SecurityLabelAttributeName))); -+ *tts_seclabel = securityTransSecLabelIn(TextDatumGetCString(datum)); -+ } -+} -+ -+static void -+storeWritableSystemAttribute(Relation rel, TupleTableSlot *slot, HeapTuple tuple) -+{ -+ /* "security_label" */ -+ if (HeapTupleHasSecLabel(tuple)) -+ HeapTupleSetSecLabel(tuple, slot->tts_seclabel); -+ else if (OidIsValid(slot->tts_seclabel)) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("Unable to assign security label on \"%s\"", -+ RelationGetRelationName(rel)))); -+} -+ - /* ---------------------------------------------------------------- - * ExecutePlan - * -@@ -1318,6 +1401,8 @@ ExecutePlan(EState *estate, - - for (;;) - { -+ Oid tts_seclabel = InvalidOid; -+ - /* Reset the per-output-tuple exprcontext */ - ResetPerTupleExprContext(estate); - -@@ -1442,6 +1527,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 +1558,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 +1679,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 +1717,12 @@ ExecInsert(TupleTableSlot *slot, - ExecConstraints(resultRelInfo, slot, estate); - - /* -+ * Check row-level permission on the tuple -+ */ -+ if (!rowlvHeapTupleInsert(resultRelationDesc, tuple, false)) -+ return; -+ -+ /* - * insert the tuple - * - * Note: heap_insert returns the tid (location) of the new tuple in the -@@ -1691,6 +1790,12 @@ ExecDelete(ItemPointer tupleid, - } - - /* -+ * Check row-level permission on the tuple -+ */ -+ if (!rowlvHeapTupleDelete(resultRelationDesc, tupleid, false)) -+ return; -+ -+ /* - * delete the tuple - * - * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that -@@ -1826,6 +1931,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 +1977,12 @@ lreplace:; - ExecConstraints(resultRelInfo, slot, estate); - - /* -+ * Check row-level permission on the tuple -+ */ -+ if (!rowlvHeapTupleUpdate(resultRelationDesc, tupleid, tuple, false)) -+ return; -+ -+ /* - * replace the heap tuple - * - * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that -@@ -2733,7 +2846,8 @@ OpenIntoRel(QueryDesc *queryDesc) - 0, - into->onCommit, - reloptions, -- allowSystemTableMods); -+ allowSystemTableMods, -+ NIL); - - FreeTupleDesc(tupdesc); - -@@ -2839,6 +2953,10 @@ intorel_receive(TupleTableSlot *slot, De - - tuple = ExecCopySlotTuple(slot); - -+ storeWritableSystemAttribute(estate->es_into_relation_descriptor, slot, tuple); -+ if (!rowlvHeapTupleInsert(estate->es_into_relation_descriptor, tuple, false)) -+ return; -+ - heap_insert(estate->es_into_relation_descriptor, - tuple, - estate->es_output_cid, -diff -rpNU3 base/src/backend/executor/execScan.c sepgsql-new/src/backend/executor/execScan.c ---- base/src/backend/executor/execScan.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/executor/execScan.c 2009-03-13 18:14:33.000000000 +0900 -@@ -20,6 +20,7 @@ - - #include "executor/executor.h" - #include "miscadmin.h" -+#include "security/rowlevel.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->requiredPerms) - return (*accessMtd) (node); - - /* -@@ -128,9 +130,17 @@ ExecScan(ScanState *node, - * when the qual is nil ... saves only a few cycles, but they add up - * ... - */ -- if (!qual || ExecQual(qual, econtext, false)) -+ if (rowlvExecScan(scan, node->ss_currentRelation, slot, false) -+ && (!qual || ExecQual(qual, econtext, false))) - { - /* -+ * NOTE: The purpose of rowlvExecScan() with abort = true is -+ * to ensure FK check works correctly. See also the comments -+ * at src/backend/security/rowlevel.c -+ */ -+ rowlvExecScan(scan, node->ss_currentRelation, slot, true); -+ -+ /* - * Found a satisfactory scan tuple. - */ - if (projInfo) -@@ -197,6 +207,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 +251,17 @@ tlist_matches_tupdesc(PlanState *ps, Lis - return false; /* tlist too long */ - - /* -- * If the plan context requires a particular hasoid setting, then that has -+ * If the plan context requires a particular hasoid, hasseclabel -+ * setting, then that has - * 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-new/src/backend/executor/execTuples.c ---- base/src/backend/executor/execTuples.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/executor/execTuples.c 2009-03-13 18:14:33.000000000 +0900 -@@ -100,7 +100,7 @@ - - - static TupleDesc ExecTypeFromTLInternal(List *targetList, -- bool hasoid, bool skipjunk); -+ bool hasoid, bool hasseclabel, bool skipjunk); - - - /* ---------------------------------------------------------------- -@@ -921,9 +921,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); - } - - /* ---------------------------------------------------------------- -@@ -933,13 +933,13 @@ 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; -@@ -951,6 +951,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-new/src/backend/executor/execUtils.c ---- base/src/backend/executor/execUtils.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/executor/execUtils.c 2009-03-13 18:14:33.000000000 +0900 -@@ -506,6 +506,7 @@ void - ExecAssignResultTypeFromTL(PlanState *planstate) - { - bool hasoid; -+ bool hasseclabel; - TupleDesc tupDesc; - - if (ExecContextForcesOids(planstate, &hasoid)) -@@ -518,12 +519,16 @@ ExecAssignResultTypeFromTL(PlanState *pl - hasoid = false; - } - -+ if (!ExecContextForcesSecLabel(planstate, &hasseclabel)) -+ hasseclabel = 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, hasseclabel); - ExecAssignResultType(planstate, tupDesc); - } - -diff -rpNU3 base/src/backend/executor/functions.c sepgsql-new/src/backend/executor/functions.c ---- base/src/backend/executor/functions.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/executor/functions.c 2009-03-13 18:14:33.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/nodeSubplan.c sepgsql-new/src/backend/executor/nodeSubplan.c ---- base/src/backend/executor/nodeSubplan.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/executor/nodeSubplan.c 2009-03-13 18:14:33.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-new/src/backend/executor/spi.c ---- base/src/backend/executor/spi.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/backend/executor/spi.c 2009-03-13 18:14:33.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(mtuple)) -+ HeapTupleSetSecLabel(mtuple, HeapTupleGetSecLabel(tuple)); - } - else - { -diff -rpNU3 base/src/backend/libpq/be-fsstubs.c sepgsql-new/src/backend/libpq/be-fsstubs.c ---- base/src/backend/libpq/be-fsstubs.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/libpq/be-fsstubs.c 2009-03-13 18:14:33.000000000 +0900 -@@ -42,11 +42,14 @@ - #include - #include - -+#include "catalog/pg_security.h" - #include "libpq/be-fsstubs.h" - #include "libpq/libpq-fs.h" - #include "miscadmin.h" -+#include "security/sepgsql.h" - #include "storage/fd.h" - #include "storage/large_object.h" -+#include "utils/builtins.h" - #include "utils/memutils.h" - - -@@ -153,6 +156,10 @@ lo_read(int fd, char *buf, int len) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("invalid large-object descriptor: %d", fd))); -+ /* -+ * SELinux: check db_blob:{read} -+ */ -+ sepgsqlCheckBlobRead(cookies[fd]); - - status = inv_read(cookies[fd], buf, len); - -@@ -175,6 +182,11 @@ lo_write(int fd, const char *buf, int le - errmsg("large object descriptor %d was not opened for writing", - fd))); - -+ /* -+ * SELinux: check db_blob:{write} permission -+ */ -+ sepgsqlCheckBlobWrite(cookies[fd]); -+ - status = inv_write(cookies[fd], buf, len); - - return status; -@@ -363,6 +375,11 @@ lo_import(PG_FUNCTION_ARGS) - */ - lobj = inv_open(lobjOid, INV_WRITE, fscxt); - -+ /* -+ * SELinux: check db_blob:{write import} and file:{read} permission -+ */ -+ sepgsqlCheckBlobImport(lobj, FileRawDescriptor(fd), fnamebuf); -+ - while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0) - { - tmp = inv_write(lobj, buf, nbytes); -@@ -435,6 +452,11 @@ lo_export(PG_FUNCTION_ARGS) - fnamebuf))); - - /* -+ * SELinux: check db_blob:{read export} and file:{write} -+ */ -+ sepgsqlCheckBlobExport(lobj, FileRawDescriptor(fd), fnamebuf); -+ -+ /* - * read in from the inversion file and write to the filesystem - */ - while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0) -@@ -468,12 +490,64 @@ lo_truncate(PG_FUNCTION_ARGS) - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("invalid large-object descriptor: %d", fd))); - -+ /* -+ * SELinux: check db_blob:{write} permission -+ */ -+ sepgsqlCheckBlobWrite(cookies[fd]); -+ - inv_truncate(cookies[fd], len); - - PG_RETURN_INT32(0); - } - - /* -+ * lo_get_seclabel -+ * get a security label of large object -+ */ -+Datum -+lo_get_security(PG_FUNCTION_ARGS) -+{ -+ Oid loid = PG_GETARG_OID(0); -+ Oid secid; -+ -+ secid = inv_get_security(loid); -+ -+ return CStringGetTextDatum(securityTransSecLabelOut(secid)); -+} -+ -+/* -+ * lo_set_seclabel -+ * set a security label of large object -+ */ -+Datum -+lo_set_security(PG_FUNCTION_ARGS) -+{ -+ Oid loid = PG_GETARG_OID(0); -+ char *seclabel = TextDatumGetCString(PG_GETARG_DATUM(1)); -+ Oid secid; -+ -+ secid = securityTransSecLabelIn(seclabel); -+ -+ inv_set_security(loid, secid); -+ -+ /* -+ * Also on memory caches to be updated -+ */ -+ if (fscxt != NULL) -+ { -+ int i; -+ -+ for (i = 0; i < cookies_size; i++) -+ { -+ if (cookies[i] != NULL && cookies[i]->id == loid) -+ cookies[i]->secid = secid; -+ } -+ } -+ -+ PG_RETURN_BOOL(true); -+} -+ -+/* - * AtEOXact_LargeObject - - * prepares large objects for transaction commit - */ -diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql-new/src/backend/nodes/copyfuncs.c ---- base/src/backend/nodes/copyfuncs.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql-new/src/backend/nodes/copyfuncs.c 2009-03-13 18:14:33.000000000 +0900 -@@ -226,6 +226,7 @@ CopyScanFields(Scan *from, Scan *newnode - CopyPlanFields((Plan *) from, (Plan *) newnode); - - COPY_SCALAR_FIELD(scanrelid); -+ COPY_SCALAR_FIELD(requiredPerms); - } - - /* -@@ -1523,6 +1524,8 @@ _copyRangeTblEntry(RangeTblEntry *from) - COPY_SCALAR_FIELD(inFromCl); - COPY_SCALAR_FIELD(requiredPerms); - COPY_SCALAR_FIELD(checkAsUser); -+ COPY_BITMAPSET_FIELD(selectedCols); -+ COPY_BITMAPSET_FIELD(modifiedCols); - - return newnode; - } -@@ -1789,6 +1792,7 @@ _copyColumnDef(ColumnDef *from) - COPY_NODE_FIELD(raw_default); - COPY_STRING_FIELD(cooked_default); - COPY_NODE_FIELD(constraints); -+ COPY_NODE_FIELD(secLabel); - - return newnode; - } -@@ -2105,6 +2109,7 @@ _copyCreateStmt(CreateStmt *from) - COPY_NODE_FIELD(options); - COPY_SCALAR_FIELD(oncommit); - COPY_STRING_FIELD(tablespacename); -+ COPY_NODE_FIELD(secLabel); - - return newnode; - } -diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql-new/src/backend/nodes/equalfuncs.c ---- base/src/backend/nodes/equalfuncs.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql-new/src/backend/nodes/equalfuncs.c 2009-03-13 18:14:33.000000000 +0900 -@@ -970,6 +970,7 @@ _equalCreateStmt(CreateStmt *a, CreateSt - COMPARE_NODE_FIELD(options); - COMPARE_SCALAR_FIELD(oncommit); - COMPARE_STRING_FIELD(tablespacename); -+ COMPARE_NODE_FIELD(secLabel); - - return true; - } -@@ -1818,6 +1819,7 @@ _equalColumnDef(ColumnDef *a, ColumnDef - COMPARE_NODE_FIELD(raw_default); - COMPARE_STRING_FIELD(cooked_default); - COMPARE_NODE_FIELD(constraints); -+ COMPARE_NODE_FIELD(secLabel); - - return true; - } -@@ -1873,6 +1875,8 @@ _equalRangeTblEntry(RangeTblEntry *a, Ra - COMPARE_SCALAR_FIELD(inFromCl); - COMPARE_SCALAR_FIELD(requiredPerms); - COMPARE_SCALAR_FIELD(checkAsUser); -+ COMPARE_BITMAPSET_FIELD(selectedCols); -+ COMPARE_BITMAPSET_FIELD(modifiedCols); - - return true; - } -diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql-new/src/backend/nodes/outfuncs.c ---- base/src/backend/nodes/outfuncs.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/backend/nodes/outfuncs.c 2009-03-13 18:14:33.000000000 +0900 -@@ -282,6 +282,7 @@ _outScanInfo(StringInfo str, Scan *node) - _outPlanInfo(str, (Plan *) node); - - WRITE_UINT_FIELD(scanrelid); -+ WRITE_UINT_FIELD(requiredPerms); - } - - /* -@@ -1376,6 +1377,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(requiredPerms); - } - - static void -@@ -1545,6 +1547,7 @@ _outCreateStmt(StringInfo str, CreateStm - WRITE_NODE_FIELD(options); - WRITE_ENUM_FIELD(oncommit, OnCommitAction); - WRITE_STRING_FIELD(tablespacename); -+ WRITE_NODE_FIELD(secLabel); - } - - static void -@@ -1660,6 +1663,7 @@ _outColumnDef(StringInfo str, ColumnDef - WRITE_NODE_FIELD(raw_default); - WRITE_STRING_FIELD(cooked_default); - WRITE_NODE_FIELD(constraints); -+ WRITE_NODE_FIELD(secLabel); - } - - static void -@@ -1834,6 +1838,8 @@ _outRangeTblEntry(StringInfo str, RangeT - WRITE_BOOL_FIELD(inFromCl); - WRITE_UINT_FIELD(requiredPerms); - WRITE_OID_FIELD(checkAsUser); -+ WRITE_BITMAPSET_FIELD(selectedCols); -+ WRITE_BITMAPSET_FIELD(modifiedCols); - } - - static void -diff -rpNU3 base/src/backend/nodes/readfuncs.c sepgsql-new/src/backend/nodes/readfuncs.c ---- base/src/backend/nodes/readfuncs.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/nodes/readfuncs.c 2009-03-13 13:09:47.000000000 +0900 -@@ -102,6 +102,10 @@ - token = pg_strtok(&length); /* skip :fldname */ \ - local_node->fldname = nodeRead(NULL, 0) - -+#define READ_BITMAPSET_FIELD(fldname) \ -+ token = pg_strtok(&length); /* skip :fldname */ \ -+ local_node->fldname = _readBitmapset() -+ - /* Routine exit */ - #define READ_DONE() \ - return local_node -@@ -125,6 +129,46 @@ - - static Datum readDatum(bool typbyval); - -+/* -+ * _readBitmapset -+ */ -+static Bitmapset * -+_readBitmapset(void) -+{ -+ Bitmapset *result = NULL; -+ READ_TEMP_LOCALS(); -+ -+ token = pg_strtok(&length); -+ if (token == NULL) -+ elog(ERROR, "incomplete Bitmapset structure"); -+ if (length != 1 || token[0] != '(') -+ elog(ERROR, "unrecognized token: \"%.*s\"", length, token); -+ -+ token = pg_strtok(&length); -+ if (token == NULL) -+ elog(ERROR, "incomplete Bitmapset structure"); -+ if (length != 1 || token[0] != 'b') -+ elog(ERROR, "unrecognized token: \"%.*s\"", length, token); -+ -+ for (;;) -+ { -+ int val; -+ char *endptr; -+ -+ token = pg_strtok(&length); -+ if (token == NULL) -+ elog(ERROR, "unterminated Bitmapset structure"); -+ if (length == 1 && token[0] == ')') -+ break; -+ val = (int) strtol(token, &endptr, 10); -+ if (endptr != token + length) -+ elog(ERROR, "unrecognized integer: \"%.*s\"", length, token); -+ result = bms_add_member(result, val); -+ } -+ -+ return result; -+} -+ - - /* - * _readQuery -@@ -1003,6 +1047,8 @@ _readRangeTblEntry(void) - READ_BOOL_FIELD(inFromCl); - READ_UINT_FIELD(requiredPerms); - READ_OID_FIELD(checkAsUser); -+ READ_BITMAPSET_FIELD(selectedCols); -+ READ_BITMAPSET_FIELD(modifiedCols); - - READ_DONE(); - } -diff -rpNU3 base/src/backend/optimizer/plan/createplan.c sepgsql-new/src/backend/optimizer/plan/createplan.c ---- base/src/backend/optimizer/plan/createplan.c 2008-06-12 22:34:19.000000000 +0900 -+++ sepgsql-new/src/backend/optimizer/plan/createplan.c 2009-03-13 18:14:33.000000000 +0900 -@@ -287,6 +287,11 @@ create_scan_plan(PlannerInfo *root, Path - } - - /* -+ * Copies row-level permissions -+ */ -+ ((Scan *)plan)->requiredPerms = rel->requiredPerms; -+ -+ /* - * 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/prep/prepunion.c sepgsql-new/src/backend/optimizer/prep/prepunion.c ---- base/src/backend/optimizer/prep/prepunion.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/backend/optimizer/prep/prepunion.c 2009-03-13 13:09:47.000000000 +0900 -@@ -75,6 +75,8 @@ static void make_inh_translation_lists(R - Index newvarno, - List **col_mappings, - List **translated_vars); -+static Bitmapset *translate_col_privs(const Bitmapset *parent_privs, -+ List *translated_vars); - static Node *adjust_appendrel_attrs_mutator(Node *node, - AppendRelInfo *context); - static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid); -@@ -882,6 +884,19 @@ expand_inherited_rtentry(PlannerInfo *ro - appinfo->parent_reloid = parentOID; - appinfos = lappend(appinfos, appinfo); - -+ /* -+ * Translate the column permissions bitmaps to the child's attnums -+ * (we have to build the translated_vars list before we can do this). -+ * But if this is the parent table, leave copyObject's result alone. -+ */ -+ if (childOID != parentOID) -+ { -+ childrte->selectedCols = translate_col_privs(rte->selectedCols, -+ appinfo->translated_vars); -+ childrte->modifiedCols = translate_col_privs(rte->modifiedCols, -+ appinfo->translated_vars); -+ } -+ - /* Close child relations, but keep locks */ - if (childOID != parentOID) - heap_close(newrelation, NoLock); -@@ -1015,6 +1030,62 @@ make_inh_translation_lists(Relation oldr - } - - /* -+ * translate_col_privs -+ * Translate a bitmapset representing per-column privileges from the -+ * parent rel's attribute numbering to the child's. -+ * -+ * The only surprise here is that we don't translate a parent whole-row -+ * reference into a child whole-row reference. That would mean requiring -+ * permissions on all child columns, which is overly strict, since the -+ * query is really only going to reference the inherited columns. Instead -+ * we set the per-column bits for all inherited columns. -+ */ -+static Bitmapset * -+translate_col_privs(const Bitmapset *parent_privs, -+ List *translated_vars) -+{ -+ Bitmapset *child_privs = NULL; -+ bool whole_row; -+ int attno; -+ ListCell *lc; -+ -+ /* System attributes have the same numbers in all tables */ -+ for (attno = FirstLowInvalidHeapAttributeNumber+1; attno < 0; attno++) -+ { -+ if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber, -+ parent_privs)) -+ child_privs = bms_add_member(child_privs, -+ attno - FirstLowInvalidHeapAttributeNumber); -+ } -+ -+ /* Check if parent has whole-row reference */ -+ whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber, -+ parent_privs); -+ /* Check if parent has whole-row reference */ -+ whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber, -+ parent_privs); -+ -+ /* And now translate the regular user attributes, using the vars list */ -+ attno = InvalidAttrNumber; -+ foreach(lc, translated_vars) -+ { -+ Var *var = (Var *) lfirst(lc); -+ -+ attno++; -+ if (var == NULL) /* ignore dropped columns */ -+ continue; -+ Assert(IsA(var, Var)); -+ if (whole_row || -+ bms_is_member(attno - FirstLowInvalidHeapAttributeNumber, -+ parent_privs)) -+ child_privs = bms_add_member(child_privs, -+ var->varattno - FirstLowInvalidHeapAttributeNumber); -+ } -+ -+ return child_privs; -+} -+ -+/* - * adjust_appendrel_attrs - * Copy the specified query or expression and translate Vars referring - * to the parent rel of the specified AppendRelInfo to refer to the -diff -rpNU3 base/src/backend/optimizer/util/clauses.c sepgsql-new/src/backend/optimizer/util/clauses.c ---- base/src/backend/optimizer/util/clauses.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql-new/src/backend/optimizer/util/clauses.c 2009-03-13 18:14:33.000000000 +0900 -@@ -38,6 +38,7 @@ - #include "parser/parse_clause.h" - #include "parser/parse_coerce.h" - #include "parser/parse_expr.h" -+#include "security/sepgsql.h" - #include "tcop/tcopprot.h" - #include "utils/acl.h" - #include "utils/builtins.h" -@@ -3046,6 +3047,7 @@ inline_function(Oid funcid, Oid result_t - funcform->prosecdef || - funcform->proretset || - !heap_attisnull(func_tuple, Anum_pg_proc_proconfig) || -+ !sepgsqlAllowFunctionInlined(func_tuple) || - funcform->pronargs != list_length(args)) - return NULL; - -diff -rpNU3 base/src/backend/optimizer/util/relnode.c sepgsql-new/src/backend/optimizer/util/relnode.c ---- base/src/backend/optimizer/util/relnode.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/optimizer/util/relnode.c 2009-03-13 18:14:33.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->requiredPerms = rte->requiredPerms; - - /* Check type of rtable entry */ - switch (rte->rtekind) -diff -rpNU3 base/src/backend/parser/analyze.c sepgsql-new/src/backend/parser/analyze.c ---- base/src/backend/parser/analyze.c 2009-03-15 17:47:25.000000000 +0900 -+++ sepgsql-new/src/backend/parser/analyze.c 2009-03-15 17:58:10.000000000 +0900 -@@ -24,6 +24,8 @@ - - #include "postgres.h" - -+#include "access/htup.h" -+#include "catalog/heap.h" - #include "catalog/pg_type.h" - #include "nodes/makefuncs.h" - #include "optimizer/clauses.h" -@@ -427,6 +429,7 @@ transformInsertStmt(ParseState *pstate, - * bugs of just that nature...) - */ - sub_pstate->p_rtable = sub_rtable; -+ sub_pstate->p_joinexprs = NIL; /* sub_rtable has no joins */ - sub_pstate->p_relnamespace = sub_relnamespace; - sub_pstate->p_varnamespace = sub_varnamespace; - -@@ -608,6 +611,7 @@ transformInsertStmt(ParseState *pstate, - /* - * Generate query's target list using the computed list of expressions. - */ -+ rte = pstate->p_target_rangetblentry; - qry->targetList = NIL; - icols = list_head(icolumns); - attnos = list_head(attrnos); -@@ -615,17 +619,22 @@ transformInsertStmt(ParseState *pstate, - { - Expr *expr = (Expr *) lfirst(lc); - ResTarget *col; -+ AttrNumber attr_num; - TargetEntry *tle; - - col = (ResTarget *) lfirst(icols); - Assert(IsA(col, ResTarget)); -+ attr_num = (AttrNumber) lfirst_int(attnos); - - tle = makeTargetEntry(expr, -- (AttrNumber) lfirst_int(attnos), -+ attr_num, - col->name, -- false); -+ attr_num < 0 ? true : false); - qry->targetList = lappend(qry->targetList, tle); - -+ rte->modifiedCols = bms_add_member(rte->modifiedCols, -+ attr_num - FirstLowInvalidHeapAttributeNumber); -+ - icols = lnext(icols); - attnos = lnext(attnos); - } -@@ -721,6 +730,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 +836,7 @@ transformSelectStmt(ParseState *pstate, - if (stmt->intoClause) - { - qry->intoClause = stmt->intoClause; -+ transformSelectIntoSystemColumn(pstate, qry); - if (stmt->intoClause->colNames) - applyColumnNames(qry->targetList, stmt->intoClause->colNames); - } -@@ -1478,6 +1528,7 @@ static Query * - transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) - { - Query *qry = makeNode(Query); -+ RangeTblEntry *target_rte; - Node *qual; - ListCell *origTargetList; - ListCell *tl; -@@ -1527,6 +1578,7 @@ transformUpdateStmt(ParseState *pstate, - pstate->p_next_resno = pstate->p_target_relation->rd_rel->relnatts + 1; - - /* Prepare non-junk columns for assignment to target table */ -+ target_rte = pstate->p_target_rangetblentry; - origTargetList = list_head(stmt->targetList); - - foreach(tl, qry->targetList) -@@ -1567,6 +1619,10 @@ transformUpdateStmt(ParseState *pstate, - origTarget->indirection, - origTarget->location); - -+ /* Mark the target column as requiring update permissions */ -+ target_rte->modifiedCols = bms_add_member(target_rte->modifiedCols, -+ attrno - FirstLowInvalidHeapAttributeNumber); -+ - origTargetList = lnext(origTargetList); - } - if (origTargetList != NULL) -diff -rpNU3 base/src/backend/parser/gram.y sepgsql-new/src/backend/parser/gram.y ---- base/src/backend/parser/gram.y 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql-new/src/backend/parser/gram.y 2009-03-13 18:14:33.000000000 +0900 -@@ -56,6 +56,7 @@ - #include "commands/defrem.h" - #include "nodes/makefuncs.h" - #include "parser/gramparse.h" -+#include "security/sepgsql.h" - #include "storage/lmgr.h" - #include "utils/date.h" - #include "utils/datetime.h" -@@ -351,6 +352,8 @@ static Node *makeXmlExpr(XmlExprOp op, c - %type OptTableSpace OptConsTableSpace OptTableSpaceOwner - %type opt_check_option - -+%type OptSecurityItem SecurityItem -+ - %type xml_attribute_el - %type xml_attribute_list xml_attributes - %type xml_root_version opt_xml_root_standalone -@@ -1637,7 +1640,25 @@ alter_table_cmd: - n->def = (Node *) $3; - $$ = (Node *)n; - } -- | alter_rel_cmd -+ /* ALTER TABLE CONTEXT = '...' */ -+ | SecurityItem -+ { -+ AlterTableCmd *n = makeNode(AlterTableCmd); -+ n->subtype = AT_SetSecurityLabel; -+ n->name = NULL; -+ n->def = (Node *) $1; -+ $$ = (Node *) n; -+ } -+ /* ALTER TABLE ALTER [COLUMN] 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->secLabel = (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 (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->secLabel = (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->secLabel = (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,27 @@ target_el: a_expr AS ColLabel - } - ; - -+/***************************************************************************** -+ * -+ * SE-PostgreSQL security items -+ * -+ *****************************************************************************/ -+ -+OptSecurityItem: -+ SecurityItem { $$ = $1; } -+ | /* EMPTY */ { $$ = NULL; } -+ ; -+ -+SecurityItem: -+ IDENT opt_equal Sconst -+ { -+ if (!sepgsqlIsEnabled() || -+ strcmp("security_context", $1) != 0) -+ yyerror("syntax error"); -+ -+ $$ = makeDefElem($1, (Node *) makeString($3)); -+ } -+ ; - - /***************************************************************************** - * -diff -rpNU3 base/src/backend/parser/parse_clause.c sepgsql-new/src/backend/parser/parse_clause.c ---- base/src/backend/parser/parse_clause.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/parser/parse_clause.c 2009-03-13 18:14:33.000000000 +0900 -@@ -46,6 +46,7 @@ static void extractRemainingColumns(List - List *src_colnames, List *src_colvars, - List **res_colnames, List **res_colvars); - static Node *transformJoinUsingClause(ParseState *pstate, -+ RangeTblEntry *leftRTE, RangeTblEntry *rightRTE, - List *leftVars, List *rightVars); - static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j, - RangeTblEntry *l_rte, -@@ -286,7 +287,9 @@ extractRemainingColumns(List *common_col - * Result is a transformed qualification expression. - */ - static Node * --transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars) -+transformJoinUsingClause(ParseState *pstate, -+ RangeTblEntry *leftRTE, RangeTblEntry *rightRTE, -+ List *leftVars, List *rightVars) - { - Node *result = NULL; - ListCell *lvars, -@@ -303,6 +306,10 @@ transformJoinUsingClause(ParseState *pst - Node *rvar = (Node *) lfirst(rvars); - A_Expr *e; - -+ /* Require read access to the join variables */ -+ markVarForSelectPriv(pstate, (Var *) lvar, leftRTE); -+ markVarForSelectPriv(pstate, (Var *) rvar, rightRTE); -+ - e = makeSimpleA_Expr(AEXPR_OP, "=", - copyObject(lvar), copyObject(rvar), - -1); -@@ -665,6 +672,7 @@ transformFromClauseItem(ParseState *psta - *r_colvars, - *res_colvars; - RangeTblEntry *rte; -+ int k; - - /* - * Recursively process the left and right subtrees -@@ -849,6 +857,8 @@ transformFromClauseItem(ParseState *psta - } - - j->quals = transformJoinUsingClause(pstate, -+ l_rte, -+ r_rte, - l_usingvars, - r_usingvars); - } -@@ -909,6 +919,12 @@ transformFromClauseItem(ParseState *psta - *top_rte = rte; - *top_rti = j->rtindex; - -+ /* make a matching link to the JoinExpr for later use */ -+ for (k = list_length(pstate->p_joinexprs) + 1; k < j->rtindex; k++) -+ pstate->p_joinexprs = lappend(pstate->p_joinexprs, NULL); -+ pstate->p_joinexprs = lappend(pstate->p_joinexprs, j); -+ Assert(list_length(pstate->p_joinexprs) == j->rtindex); -+ - /* - * Prepare returned namespace list. If the JOIN has an alias then it - * hides the contained RTEs as far as the relnamespace goes; -diff -rpNU3 base/src/backend/parser/parse_expr.c sepgsql-new/src/backend/parser/parse_expr.c ---- base/src/backend/parser/parse_expr.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql-new/src/backend/parser/parse_expr.c 2009-03-13 13:09:47.000000000 +0900 -@@ -1764,6 +1764,9 @@ transformWholeRowRef(ParseState *pstate, - break; - } - -+ /* mark relation as requiring whole-row SELECT access */ -+ markVarForSelectPriv(pstate, (Var *) result, rte); -+ - return result; - } - -diff -rpNU3 base/src/backend/parser/parse_relation.c sepgsql-new/src/backend/parser/parse_relation.c ---- base/src/backend/parser/parse_relation.c 2008-06-12 22:34:19.000000000 +0900 -+++ sepgsql-new/src/backend/parser/parse_relation.c 2009-03-13 18:14:33.000000000 +0900 -@@ -335,6 +335,7 @@ scanRTEForColumn(ParseState *pstate, Ran - { - Node *result = NULL; - int attnum = 0; -+ Var *var; - ListCell *c; - - /* -@@ -361,9 +362,10 @@ scanRTEForColumn(ParseState *pstate, Ran - errmsg("column reference \"%s\" is ambiguous", - colname), - parser_errposition(pstate, location))); -- result = (Node *) make_var(pstate, rte, attnum); -- /* Require read access */ -- rte->requiredPerms |= ACL_SELECT; -+ var = make_var(pstate, rte, attnum); -+ /* Require read access to the column */ -+ markVarForSelectPriv(pstate, var, rte); -+ result = (Node *) var; - } - } - -@@ -389,9 +391,10 @@ scanRTEForColumn(ParseState *pstate, Ran - Int16GetDatum(attnum), - 0, 0)) - { -- result = (Node *) make_var(pstate, rte, attnum); -- /* Require read access */ -- rte->requiredPerms |= ACL_SELECT; -+ var = make_var(pstate, rte, attnum); -+ /* Require read access to the column */ -+ markVarForSelectPriv(pstate, var, rte); -+ result = (Node *) var; - } - } - } -@@ -479,6 +482,122 @@ qualifiedNameToVar(ParseState *pstate, - } - - /* -+ * markRTEForSelectPriv -+ * Mark the specified column of an RTE as requiring SELECT privilege -+ * -+ * col == InvalidAttrNumber means a "whole row" reference -+ * -+ * The caller should pass the actual RTE if it has it handy; otherwise pass -+ * NULL, and we'll look it up here. (This uglification of the API is -+ * worthwhile because nearly all external callers have the RTE at hand.) -+ */ -+static void -+markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte, -+ int rtindex, AttrNumber col) -+{ -+ if (rte == NULL) -+ rte = rt_fetch(rtindex, pstate->p_rtable); -+ -+ if (rte->rtekind == RTE_RELATION) -+ { -+ /* Make sure the rel as a whole is marked for SELECT access */ -+ rte->requiredPerms |= ACL_SELECT; -+ /* Must offset the attnum to fit in a bitmapset */ -+ rte->selectedCols = bms_add_member(rte->selectedCols, -+ col - FirstLowInvalidHeapAttributeNumber); -+ } -+ else if (rte->rtekind == RTE_JOIN) -+ { -+ if (col == InvalidAttrNumber) -+ { -+ /* -+ * A whole-row reference to a join has to be treated as -+ * whole-row references to the two inputs. -+ */ -+ JoinExpr *j; -+ -+ if (rtindex > 0 && rtindex <= list_length(pstate->p_joinexprs)) -+ j = (JoinExpr *) list_nth(pstate->p_joinexprs, rtindex - 1); -+ else -+ j = NULL; -+ if (j == NULL) -+ elog(ERROR, "could not find JoinExpr for whole-row reference"); -+ Assert(IsA(j, JoinExpr)); -+ -+ /* Note: we can't see FromExpr here */ -+ if (IsA(j->larg, RangeTblRef)) -+ { -+ int varno = ((RangeTblRef *) j->larg)->rtindex; -+ -+ markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); -+ } -+ else if (IsA(j->larg, JoinExpr)) -+ { -+ int varno = ((JoinExpr *) j->larg)->rtindex; -+ -+ markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); -+ } -+ else -+ elog(ERROR, "unrecognized node type: %d", -+ (int) nodeTag(j->larg)); -+ if (IsA(j->rarg, RangeTblRef)) -+ { -+ int varno = ((RangeTblRef *) j->rarg)->rtindex; -+ -+ markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); -+ } -+ else if (IsA(j->rarg, JoinExpr)) -+ { -+ int varno = ((JoinExpr *) j->rarg)->rtindex; -+ -+ markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); -+ } -+ else -+ elog(ERROR, "unrecognized node type: %d", -+ (int) nodeTag(j->rarg)); -+ } -+ else -+ { -+ /* -+ * Regular join attribute, look at the alias-variable list. -+ * -+ * The aliasvar could be either a Var or a COALESCE expression, -+ * but in the latter case we should already have marked the two -+ * referent variables as being selected, due to their use in the -+ * JOIN clause. So we need only be concerned with the simple -+ * Var case. -+ */ -+ Var *aliasvar; -+ -+ Assert(col > 0 && col <= list_length(rte->joinaliasvars)); -+ aliasvar = (Var *) list_nth(rte->joinaliasvars, col - 1); -+ if (IsA(aliasvar, Var)) -+ markVarForSelectPriv(pstate, aliasvar, NULL); -+ } -+ } -+ /* other RTE types don't require privilege marking */ -+} -+ -+/* -+ * markVarForSelectPriv -+ * Mark the RTE referenced by a Var as requiring SELECT privilege -+ * -+ * The caller should pass the Var's referenced RTE if it has it handy -+ * (nearly all do); otherwise pass NULL. -+ */ -+void -+markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte) -+{ -+ Index lv; -+ -+ Assert(IsA(var, Var)); -+ /* Find the appropriate pstate if it's an uplevel Var */ -+ for (lv = 0; lv < var->varlevelsup; lv++) -+ pstate = pstate->parentParseState; -+ markRTEForSelectPriv(pstate, rte, var->varno, var->varattno); -+} -+ -+/* - * buildRelationAliases - * Construct the eref column name list for a relation RTE. - * This code is also used for the case of a function RTE returning -@@ -669,6 +788,8 @@ addRangeTableEntry(ParseState *pstate, - - rte->requiredPerms = ACL_SELECT; - rte->checkAsUser = InvalidOid; /* not set-uid by default, either */ -+ rte->selectedCols = NULL; -+ rte->modifiedCols = NULL; - - /* - * Add completed RTE to pstate's range table list, but not to join list -@@ -722,6 +843,8 @@ addRangeTableEntryForRelation(ParseState - - rte->requiredPerms = ACL_SELECT; - rte->checkAsUser = InvalidOid; /* not set-uid by default, either */ -+ rte->selectedCols = NULL; -+ rte->modifiedCols = NULL; - - /* - * Add completed RTE to pstate's range table list, but not to join list -@@ -800,6 +923,8 @@ addRangeTableEntryForSubquery(ParseState - - rte->requiredPerms = 0; - rte->checkAsUser = InvalidOid; -+ rte->selectedCols = NULL; -+ rte->modifiedCols = NULL; - - /* - * Add completed RTE to pstate's range table list, but not to join list -@@ -928,6 +1053,8 @@ addRangeTableEntryForFunction(ParseState - - rte->requiredPerms = 0; - rte->checkAsUser = InvalidOid; -+ rte->selectedCols = NULL; -+ rte->modifiedCols = NULL; - - /* - * Add completed RTE to pstate's range table list, but not to join list -@@ -997,6 +1124,8 @@ addRangeTableEntryForValues(ParseState * - rte->inFromCl = inFromCl; - rte->requiredPerms = 0; - rte->checkAsUser = InvalidOid; -+ rte->selectedCols = NULL; -+ rte->modifiedCols = NULL; - - /* - * Add completed RTE to pstate's range table list, but not to join list -@@ -1066,6 +1195,8 @@ addRangeTableEntryForJoin(ParseState *ps - - rte->requiredPerms = 0; - rte->checkAsUser = InvalidOid; -+ rte->selectedCols = NULL; -+ rte->modifiedCols = NULL; - - /* - * Add completed RTE to pstate's range table list, but not to join list -@@ -1520,6 +1651,9 @@ expandRelAttrs(ParseState *pstate, Range - label, - false); - te_list = lappend(te_list, te); -+ -+ /* Require read access to each column */ -+ markVarForSelectPriv(pstate, (Var *) varnode, rte); - } - - Assert(name == NULL && var == NULL); /* lists not the same length? */ -diff -rpNU3 base/src/backend/parser/parse_target.c sepgsql-new/src/backend/parser/parse_target.c ---- base/src/backend/parser/parse_target.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/parser/parse_target.c 2009-03-13 18:14: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" -@@ -333,16 +334,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 +501,9 @@ updateTargetListEntry(ParseState *pstate - */ - tle->resno = (AttrNumber) attrno; - tle->resname = colname; -+ -+ if (SystemAttributeIsWritable(attrno)) -+ tle->resjunk = true; - } - - -@@ -749,6 +770,7 @@ checkInsertTargets(ParseState *pstate, L - Bitmapset *wholecols = NULL; - Bitmapset *partialcols = NULL; - ListCell *tl; -+ uint32 system_attrs = 0UL; - - foreach(tl, cols) - { -@@ -757,14 +779,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 -@@ -902,9 +947,25 @@ ExpandColumnRefStar(ParseState *pstate, - else - { - List *vars; -+ ListCell *l; - - expandRTE(rte, rtindex, sublevels_up, false, - NULL, &vars); -+ /* -+ * Require read access to the table. This is normally redundant -+ * with the markVarForSelectPriv calls below, but not if the table -+ * has zero columns. -+ */ -+ rte->requiredPerms |= ACL_SELECT; -+ -+ /* Require read access to each column */ -+ foreach(l, vars) -+ { -+ Var *var = (Var *) lfirst(l); -+ -+ markVarForSelectPriv(pstate, var, rte); -+ } -+ - return vars; - } - } -diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql-new/src/backend/postmaster/postmaster.c ---- base/src/backend/postmaster/postmaster.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql-new/src/backend/postmaster/postmaster.c 2009-03-13 18:14:33.000000000 +0900 -@@ -107,6 +107,7 @@ - #include "postmaster/pgarch.h" - #include "postmaster/postmaster.h" - #include "postmaster/syslogger.h" -+#include "security/sepgsql.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, -+ sepgsqlWorkerPID = 0; - - /* Startup/shutdown state */ - #define NoShutdown 0 -@@ -1321,6 +1323,10 @@ ServerLoop(void) - if (PgStatPID == 0 && pmState == PM_RUN) - PgStatPID = pgstat_start(); - -+ /* If we have lost the sepgsql worker (if needed), try to start a new one */ -+ if (sepgsqlWorkerPID == 0 && pmState == PM_RUN) -+ sepgsqlWorkerPID = sepgsqlStartupWorkerProcess(); -+ - /* - * Touch the socket and lock file every 58 minutes, to ensure that - * they are not removed by overzealous /tmp-cleaning tasks. We assume -@@ -1911,6 +1917,8 @@ SIGHUP_handler(SIGNAL_ARGS) - signal_child(PgArchPID, SIGHUP); - if (SysLoggerPID != 0) - signal_child(SysLoggerPID, SIGHUP); -+ if (sepgsqlWorkerPID != 0) -+ signal_child(sepgsqlWorkerPID, SIGHUP); - /* PgStatPID does not currently need SIGHUP */ - - /* Reload authentication config files too */ -@@ -1968,6 +1976,9 @@ pmdie(SIGNAL_ARGS) - /* and the walwriter too */ - if (WalWriterPID != 0) - signal_child(WalWriterPID, SIGTERM); -+ /* and the sepgsql worker too */ -+ if (sepgsqlWorkerPID != 0) -+ signal_child(sepgsqlWorkerPID, SIGTERM); - pmState = PM_WAIT_BACKENDS; - } - -@@ -2006,6 +2017,9 @@ pmdie(SIGNAL_ARGS) - /* and the walwriter too */ - if (WalWriterPID != 0) - signal_child(WalWriterPID, SIGTERM); -+ /* and the walwriter too */ -+ if (sepgsqlWorkerPID != 0) -+ signal_child(sepgsqlWorkerPID, SIGTERM); - pmState = PM_WAIT_BACKENDS; - } - -@@ -2039,6 +2053,8 @@ pmdie(SIGNAL_ARGS) - signal_child(PgArchPID, SIGQUIT); - if (PgStatPID != 0) - signal_child(PgStatPID, SIGQUIT); -+ if (sepgsqlWorkerPID != 0) -+ signal_child(sepgsqlWorkerPID, SIGQUIT); - ExitPostmaster(0); - break; - } -@@ -2287,6 +2303,16 @@ reaper(SIGNAL_ARGS) - continue; - } - -+ /* Was it the sepgsql worker process? */ -+ if (pid == sepgsqlWorkerPID) -+ { -+ sepgsqlWorkerPID = 0; -+ if (!EXIT_STATUS_0(exitstatus)) -+ LogChildExit(LOG, _("SE-PostgreSQL worker process"), -+ pid, exitstatus); -+ continue; -+ } -+ - /* - * Else do standard backend child cleanup. - */ -@@ -2454,6 +2480,18 @@ HandleChildCrash(int pid, int exitstatus - signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT)); - } - -+ /* Take care of the sepgsql worker too */ -+ if (pid == sepgsqlWorkerPID) -+ sepgsqlWorkerPID = 0; -+ else if (sepgsqlWorkerPID != 0 && !FatalError) -+ { -+ ereport(DEBUG2, -+ (errmsg_internal("sending %s to process %d", -+ (SendStop ? "SIGSTOP" : "SIGQUIT"), -+ (int) sepgsqlWorkerPID))); -+ signal_child(sepgsqlWorkerPID, (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 -@@ -2573,7 +2611,8 @@ PostmasterStateMachine(void) - StartupPID == 0 && - (BgWriterPID == 0 || !FatalError) && - WalWriterPID == 0 && -- AutoVacPID == 0) -+ AutoVacPID == 0 && -+ sepgsqlWorkerPID == 0) - { - if (FatalError) - { -diff -rpNU3 base/src/backend/rewrite/rewriteHandler.c sepgsql-new/src/backend/rewrite/rewriteHandler.c ---- base/src/backend/rewrite/rewriteHandler.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql-new/src/backend/rewrite/rewriteHandler.c 2009-03-13 13:09:47.000000000 +0900 -@@ -1168,9 +1168,13 @@ ApplyRetrieveRule(Query *parsetree, - Assert(subrte->relid == relation->rd_id); - subrte->requiredPerms = rte->requiredPerms; - subrte->checkAsUser = rte->checkAsUser; -+ subrte->selectedCols = rte->selectedCols; -+ subrte->modifiedCols = rte->modifiedCols; - - rte->requiredPerms = 0; /* no permission check on subquery itself */ - rte->checkAsUser = InvalidOid; -+ rte->selectedCols = NULL; -+ rte->modifiedCols = NULL; - - /* - * FOR UPDATE/SHARE of view? -diff -rpNU3 base/src/backend/security/Makefile sepgsql-new/src/backend/security/Makefile ---- base/src/backend/security/Makefile 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/Makefile 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,34 @@ -+# -+# src/backend/security/Makefile -+# Makefile for Security Purpose Extensions -+# -+# Copyright (c) 2006 - 2007 KaiGai Kohei -+# -+subdir = src/backend/security -+top_builddir = ../../.. -+include $(top_builddir)/src/Makefile.global -+ -+ -+OBJS := rowlevel.o -+ -+ifeq ($(enable_selinux), yes) -+OBJS += sepgsql/avc.o sepgsql/checker.o sepgsql/core.o \ -+ sepgsql/hooks.o sepgsql/label.o sepgsql/perms.o -+else -+OBJS += sepgsql/dummy.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/rowlevel.c sepgsql-new/src/backend/security/rowlevel.c ---- base/src/backend/security/rowlevel.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/rowlevel.c 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,165 @@ -+/* -+ * src/backend/security/common.c -+ * common facilities for row-level access controls both of DAC and MAC -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#include "postgres.h" -+ -+#include "access/heapam.h" -+#include "catalog/pg_security.h" -+#include "security/rowlevel.h" -+#include "security/sepgsql.h" -+#include "storage/bufmgr.h" -+#include "storage/bufpage.h" -+#include "utils/rel.h" -+ -+/* -+ * rowlvBehaviorSwitchTo -+ * -+ * switches current behavior of the row level access control features. -+ * In the default, it works as a filter to skip fetching violated tuples -+ * at the ExecScan(). However, we should not apply simple filtering -+ * policy at a few exceptions, during checks of FK constraints. -+ * -+ * PostgreSQL implements FK constraints as trigger functions. -+ * When we update or delete tuples within PK table, these triggers are -+ * invoked to check FK tables whether the mofified PK is refered, or not. -+ * In this case, we have to consider a possibility one or more invisible -+ * or untouchable tuples are refering the target PK. If we simply filter -+ * out these tuples in this case, it allows to delete refered PKs, keep -+ * the current value of FK on SET CASCADE rules, and so on. -+ * -+ * So, it is necessary to raise an error when invisible or untouchable -+ * ones are refering PKs. It also makes another issues. -+ * In the filtering strategy, any permission checks are done earlier -+ * than evaluations of WHERE clause, because user can give a malicious -+ * function as a condition with side effects which allows to expose -+ * the contents of invisible tuples. -+ * However, when we adopt a strategy of "abort on violation", permission -+ * should be checked after the evaluation of WHERE clause, because it -+ * raises an error even if the given tuple is out of scopes. In this case, -+ * we have an assumption that WHERE clause is not malicious and does not -+ * has side effect. -+ * The built-in FK constraints always uses simple operators which are -+ * already cheked on installation both of database ACL and SELinux. -+ * So, it is possible to change the behavior during FK constraint. -+ * Elsewhere, we should apply filtering strategy, as far as we cannot -+ * ensure a malicious function is injected on WHERE clause. -+ */ -+static bool rowlvAbortBehavior = false; -+ -+bool -+rowlvBehaviorSwitchTo(bool new_abort) -+{ -+ bool old_abort = rowlvAbortBehavior; -+ -+ rowlvAbortBehavior = new_abort; -+ -+ return old_abort; -+} -+ -+/* -+ * rowlvExecScan -+ * a hook to filter out invisible/untouchable tuples. -+ */ -+bool -+rowlvExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort) -+{ -+ HeapTuple tuple; -+ AclMode required = scan->requiredPerms; -+ -+ /* It is not a time to make a decision */ -+ if (rowlvAbortBehavior != abort) -+ return true; -+ -+ /* skip row-level controls on virtual relation */ -+ if (!rel) -+ return true; -+ -+ tuple = ExecMaterializeSlot(slot); -+ -+ if (!sepgsqlExecScan(rel, tuple, required, abort)) -+ return false; -+ -+ return true; -+} -+ -+/* -+ * rowlvHeapTupleInsert -+ * assigns default acl and label on a newly inserted tuple, and checks -+ * permissions on insert a tuple. -+ */ -+bool -+rowlvHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal) -+{ -+ if (!sepgsqlHeapTupleInsert(rel, newtup, internal)) -+ return false; -+ -+ return true; -+} -+ -+/* -+ * rowlvHeapTupleUpdate -+ * preserves original acl and label if necessary, and checks -+ * permissions on update a tuple. -+ */ -+bool -+rowlvHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup, bool internal) -+{ -+ HeapTupleData oldtup; -+ Buffer oldbuf; -+ -+ ItemPointerCopy(otid, &oldtup.t_self); -+ if (!heap_fetch(rel, SnapshotAny, &oldtup, &oldbuf, false, NULL)) -+ elog(ERROR, "failed to fetch a tuple for row-level access controls"); -+ -+ if (!sepgsqlHeapTupleUpdate(rel, &oldtup, newtup, internal)) -+ { -+ ReleaseBuffer(oldbuf); -+ return false; -+ } -+ -+ ReleaseBuffer(oldbuf); -+ return true; -+} -+ -+/* -+ * rowlvHeapTupleDelete -+ * checks permissions on delete a tuple. -+ */ -+bool -+rowlvHeapTupleDelete(Relation rel, ItemPointer otid, bool internal) -+{ -+ HeapTupleData oldtup; -+ Buffer oldbuf; -+ -+ ItemPointerCopy(otid, &oldtup.t_self); -+ if (!heap_fetch(rel, SnapshotAny, &oldtup, &oldbuf, false, NULL)) -+ elog(ERROR, "failed to fetch a tuple for row-level access controls"); -+ -+ if (!sepgsqlHeapTupleDelete(rel, &oldtup, internal)) -+ { -+ ReleaseBuffer(oldbuf); -+ return false; -+ } -+ -+ ReleaseBuffer(oldbuf); -+ return true; -+} -+ -+/* -+ * rowlvCopyToTuple -+ * checks permission on fetched tuple -+ */ -+bool -+rowlvCopyToTuple(Relation rel, HeapTuple tuple) -+{ -+ AclMode required = ACL_SELECT; -+ -+ if (!sepgsqlExecScan(rel, tuple, required, false)) -+ return false; -+ -+ return true; -+} -diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql-new/src/backend/security/sepgsql/avc.c ---- base/src/backend/security/sepgsql/avc.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/sepgsql/avc.c 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,840 @@ -+/* -+ * src/backend/security/sepgsql/avc.c -+ * SE-PostgreSQL userspace access vector cache -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#include "postgres.h" -+ -+#include "access/hash.h" -+#include "catalog/pg_security.h" -+#include "libpq/pqsignal.h" -+#include "postmaster/postmaster.h" -+#include "security/sepgsql.h" -+#include "storage/ipc.h" -+#include "storage/lwlock.h" -+#include "utils/memutils.h" -+#include "utils/syscache.h" -+#include -+#include -+#include -+#include -+ -+/* -+ * AVC: 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. -+ * -+ * AVC 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. -+ */ -+static MemoryContext AvcMemCtx; -+ -+#define AVC_HASH_NUM_SLOTS 256 -+#define AVC_HASH_NUM_NODES 180 -+ -+typedef struct -+{ -+ uint32 hash_key; -+ -+ security_class_t tclass; -+ sepgsql_sid_t tsid; -+ sepgsql_sid_t nsid; -+ security_context_t ncontext; -+ -+ 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 *next; -+ -+ int avc_version; /* copied from global state */ -+ -+ bool avc_enforcing; /* copied from global state */ -+ -+ security_context_t scontext; -+ -+ List *slot[AVC_HASH_NUM_SLOTS]; -+ -+ uint32 avc_count; -+ uint32 lru_hint; -+} avc_page; -+ -+static avc_page *client_avc_page = NULL; -+ -+/* -+ * selinux_state -+ * -+ * This structure shows the global state of SELinux and its security -+ * policy, and it is assigned on shared memory region. -+ * -+ * The selinux_state->version should be checked prior to any avc -+ * accesses. If avc_page->avc_version is not matched with the -+ * global state, it means security policy is reloaded, system booleans -+ * are changed, or working mode (enforcing/permissive) is changed. -+ * The selinux_state->enforcing means current working mode. If it it -+ * true, it works in enforcing mode, elsewhere permissive mode. -+ * -+ * The only process able to update these variable are policy state -+ * monitoring process forked by postmaster. It enables to receive -+ * notifications from the kernwl via netlink socket. -+ * -+ * These global state is protected by SepgsqlAvcLock LWlock, so -+ * we need to acquire this lock when it is refered. -+ */ -+struct -+{ -+ int version; -+ -+ bool enforcing; -+ -+} *selinux_state = NULL; -+ -+Size -+sepgsqlShmemSize(void) -+{ -+ if (!sepgsqlIsEnabled()) -+ return 0; -+ -+ return sizeof(*selinux_state); -+} -+ -+/* -+ * sepgsql_avc_reset -+ * clears all AVC entries and update its version. -+ * caller need to hold SepgsqlAvcLock -+ */ -+static void -+sepgsql_avc_reset(void) -+{ -+ MemoryContextReset(AvcMemCtx); -+ -+ client_avc_page = NULL; -+ -+ sepgsqlAvcSwitchClient(); -+} -+ -+/* -+ * sepgsql_avc_reclaim -+ * reclaims recently unused AVC entries, when the number of -+ * caches overs AVC_HASH_NUM_NODES. -+ */ -+static void -+sepgsql_avc_reclaim(avc_page *page) -+{ -+ ListCell *l; -+ avc_datum *cache; -+ -+ while (page->avc_count > AVC_HASH_NUM_NODES) -+ { -+ foreach (l, page->slot[page->lru_hint]) -+ { -+ cache = lfirst(l); -+ -+ if (cache->hot_cache) -+ cache->hot_cache = false; -+ else -+ { -+ list_delete_ptr(page->slot[page->lru_hint], cache); -+ pfree(cache); -+ page->avc_count--; -+ } -+ } -+ page->lru_hint = (page->lru_hint + 1) % AVC_HASH_NUM_SLOTS; -+ } -+} -+ -+/* -+ * 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 void -+avc_audit_common(char *buffer, uint32 buflen, -+ security_context_t scontext, -+ security_context_t tcontext, -+ security_class_t tclass, -+ access_vector_t audited, -+ bool denied, -+ const char *audit_name) -+{ -+ access_vector_t mask; -+ uint32 ofs = 0; -+ -+ ofs += snprintf(buffer + ofs, buflen - ofs, "%s {", -+ denied ? "denied" : "granted"); -+ for (mask = 1; audited != 0; mask <<= 1) -+ { -+ if (audited & mask) -+ ofs += snprintf(buffer + ofs, buflen - ofs, " %s", -+ sepgsqlGetPermissionString(tclass, mask)); -+ audited &= ~mask; -+ } -+ ofs += snprintf(buffer + ofs, buflen - ofs, " } "); -+ -+ ofs += snprintf(buffer + ofs, buflen - ofs, -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, -+ sepgsqlGetClassString(tclass)); -+ -+ if (audit_name) -+ ofs += snprintf(buffer + ofs, buflen - ofs, " name=%s", audit_name); -+} -+ -+/* -+ * 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(tcontext, tclass) ((tsid) ^ ((tclass) << 3)) -+ -+static avc_datum * -+avc_make_entry(avc_page *page, sepgsql_sid_t tsid, security_class_t tclass) -+{ -+ security_context_t scontext, tcontext, ncontext; -+ security_class_t tclass_ex; -+ MemoryContext oldctx; -+ 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; -+ -+ oldctx = MemoryContextSwitchTo(AvcMemCtx); -+ cache = palloc0(sizeof(avc_datum)); -+ cache->hash_key = hash_key; -+ cache->tsid = tsid; -+ cache->tclass = tclass; -+ -+ scontext = page->scontext; -+ tcontext = securityLookupSecurityLabel(tsid); -+ if (!tcontext || !sepgsqlCheckValidSecurityLabel(tcontext)) -+ tcontext = sepgsqlGetUnlabeledLabel(); -+ -+ tclass_ex = sepgsqlTransToExternalClass(tclass); -+ -+ if (security_compute_av_raw(scontext, tcontext, tclass_ex, 0, &avd) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not compute av_decision: " -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, sepgsqlGetClassString(tclass)))); -+ sepgsqlTransToInternalPerms(tclass, &avd); -+ -+ cache->allowed = avd.allowed; -+ cache->decided = avd.decided; -+ cache->auditallow = avd.auditallow; -+ cache->auditdeny = avd.auditdeny; -+ cache->hot_cache = true; -+ -+ if (security_compute_create_raw(scontext, tcontext, tclass_ex, &ncontext) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not compute new context: " -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, sepgsqlGetClassString(tclass)))); -+ -+ PG_TRY(); -+ { -+ cache->ncontext = pstrdup(ncontext); -+ } -+ PG_CATCH(); -+ { -+ freecon(ncontext); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ -+ freecon(ncontext); -+ -+ sepgsql_avc_reclaim(page); -+ -+ page->slot[index] = lcons(cache, page->slot[index]); -+ -+ page->avc_count++; -+ -+ MemoryContextSwitchTo(oldctx); -+ -+ return cache; -+} -+ -+/* -+ * avc_lookup -+ * It lookups required avc entry. Because it also checks avc_version -+ * on the global state, the caller has to hold SepgsqlAvcLock. -+ */ -+static avc_datum * -+avc_lookup(avc_page *page, sepgsql_sid_t tsid, security_class_t tclass) -+{ -+ avc_datum *cache = NULL; -+ uint32 hash_key, index; -+ ListCell *l; -+ -+ /* check avc invalidation */ -+ if (page->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, 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; -+} -+ -+/* -+ * sepgsqlAvcSwitchClientLabel() -+ * 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. -+ */ -+static avc_page * -+sepgsqlAvcSwitch(avc_page *old_page, security_context_t scontext) -+{ -+ MemoryContext oldctx; -+ avc_page *new_page; -+ int i; -+ -+ if (old_page) -+ { -+ new_page = old_page; -+ do { -+ if (strcmp(new_page->scontext, scontext) == 0) -+ return new_page; -+ -+ new_page = old_page->next; -+ } while (new_page != old_page); -+ } -+ -+ /* Not found, so create a new avc_page */ -+ oldctx = MemoryContextSwitchTo(AvcMemCtx); -+ new_page = palloc0(sizeof(avc_page)); -+ new_page->scontext = pstrdup(scontext); -+ MemoryContextSwitchTo(oldctx); -+ -+ for (i=0; i < AVC_HASH_NUM_SLOTS; i++) -+ new_page->slot[i] = NIL; -+ -+ /* copy the global state of SELinux */ -+ new_page->avc_version = selinux_state->version; -+ new_page->avc_enforcing = selinux_state->enforcing; -+ -+ if (!old_page) -+ { -+ new_page->next = new_page; -+ } -+ else -+ { -+ new_page->next = old_page->next; -+ old_page->next = new_page; -+ } -+ -+ return new_page; -+} -+ -+void -+sepgsqlAvcSwitchClient(void) -+{ -+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED); -+ client_avc_page = sepgsqlAvcSwitch(client_avc_page, -+ sepgsqlGetClientLabel()); -+ LWLockRelease(SepgsqlAvcLock); -+} -+ -+/* -+ * sepgsqlClientHasPerms -+ * checks client's privileges on given objects via uAVC. -+ */ -+bool -+sepgsqlClientHasPerms(sepgsql_sid_t tsid, -+ security_class_t tclass, -+ access_vector_t required, -+ const char *audit_name, bool abort) -+{ -+ char audit_buffer[2048]; -+ access_vector_t denied, audited; -+ avc_datum *cache; -+ bool rc = true; -+ -+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED); -+ cache = avc_lookup(client_avc_page, tsid, tclass); -+ if (!cache) -+ cache = avc_make_entry(client_avc_page, tsid, tclass); -+ LWLockRelease(SepgsqlAvcLock); -+ -+ denied = required & ~cache->allowed; -+ audited = denied ? (denied & cache->auditdeny) -+ : (required & cache->auditallow); -+ if (audited) -+ { -+ security_context_t scon, tcon; -+ -+ scon = sepgsqlSecurityLabelTransOut(client_avc_page->scontext); -+ tcon = securityTransSecLabelOut(tsid); -+ -+ avc_audit_common(audit_buffer, sizeof(audit_buffer), -+ scon, tcon, cache->tclass, -+ audited, !!denied, audit_name); -+ pfree(scon); -+ pfree(tcon); -+ } -+ -+ if (!required || denied) -+ { -+ if (client_avc_page->avc_enforcing) -+ rc = false; -+ else -+ cache->allowed |= required; /* prevent flood of audit log */ -+ } -+ -+ if (audited) -+ 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; -+} -+ -+/* -+ * sepgsqlClientCreate -+ * sepgsqlClientCreateLabel -+ * It returns security label of database object newly created. -+ * sepgsqlClientCreate() returns it as sepgsql_sid_t, and -+ * sepgsqlClientCreateLabel() returns it as security_context_t. -+ * Please note that these types are not different in this version, -+ * but sepgsql_sid_t is planned to replace by an identifier. -+ */ -+sepgsql_sid_t -+sepgsqlClientCreate(sepgsql_sid_t tsid, security_class_t tclass) -+{ -+ avc_datum *cache; -+ -+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED); -+ cache = avc_lookup(client_avc_page, tsid, tclass); -+ if (!cache) -+ cache = avc_make_entry(client_avc_page, tsid, tclass); -+ LWLockRelease(SepgsqlAvcLock); -+ -+ if (!OidIsValid(cache->nsid)) -+ cache->nsid = securityLookupSecurityId(cache->ncontext); -+ -+ return cache->nsid; -+} -+ -+security_context_t -+sepgsqlClientCreateLabel(sepgsql_sid_t tsid, security_class_t tclass) -+{ -+ avc_datum *cache; -+ -+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED); -+ cache = avc_lookup(client_avc_page, tsid, tclass); -+ if (!cache) -+ cache = avc_make_entry(client_avc_page, tsid, tclass); -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return 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) -+ { -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ -+ selinux_state->version = 0; -+ selinux_state->enforcing = (security_getenforce() > 0); -+ -+ 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(); -+} -+ -+/* -+ * sepgsqlComputePerms -+ * sepgsqlComputeCreate -+ * -+ * The following two functions make a query to in-kernel SELinux -+ * without userspace caches, due to some reasons. -+ * The AVC can cover most of cases, but some of corner cases are -+ * not suitable for AVC structure, so we need uncached interfaces. -+ * For example, AVC 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 AVC. -+ */ -+bool -+sepgsqlComputePerms(security_context_t scontext, -+ security_context_t tcontext, -+ security_class_t tclass, -+ access_vector_t required, -+ const char *audit_name, bool abort) -+{ -+ access_vector_t denied, audited; -+ security_class_t tclass_ex; -+ struct av_decision avd; -+ char audit_buffer[2048]; -+ bool rc = true; -+ -+ scontext = (!security_check_context_raw(scontext) -+ ? scontext : sepgsqlGetUnlabeledLabel()); -+ tcontext = (!security_check_context_raw(tcontext) -+ ? tcontext : sepgsqlGetUnlabeledLabel()); -+ -+ tclass_ex = sepgsqlTransToExternalClass(tclass); -+ if (security_compute_av_raw(scontext, tcontext, tclass_ex, 0, &avd) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not compute an av_decision" -+ " scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, sepgsqlGetClassString(tclass)))); -+ sepgsqlTransToInternalPerms(tclass, &avd); -+ -+ denied = required & ~avd.allowed; -+ audited = denied ? (denied & avd.auditdeny) : (required & avd.auditallow); -+ if (audited) -+ { -+ security_context_t scon, tcon; -+ -+ scon = sepgsqlSecurityLabelTransOut(scontext); -+ tcon = sepgsqlSecurityLabelTransOut(tcontext); -+ -+ avc_audit_common(audit_buffer, sizeof(audit_buffer), -+ scon, tcon, tclass, -+ audited, !!denied, audit_name); -+ } -+ -+ if (!required || denied) -+ { -+ if (security_getenforce() > 0) -+ rc = false; -+ } -+ -+ if (audited) -+ 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; -+} -+ -+security_context_t -+sepgsqlComputeCreate(security_context_t scontext, -+ security_context_t tcontext, -+ security_class_t tclass) -+{ -+ security_context_t ncontext, result; -+ security_class_t tclass_ex; -+ -+ scontext = (!security_check_context_raw(scontext) -+ ? scontext : sepgsqlGetUnlabeledLabel()); -+ tcontext = (!security_check_context_raw(tcontext) -+ ? tcontext : sepgsqlGetUnlabeledLabel()); -+ -+ tclass_ex = sepgsqlTransToExternalClass(tclass); -+ if (security_compute_create_raw(scontext, tcontext, tclass_ex, &ncontext) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not compute a default context" -+ " scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, sepgsqlGetClassString(tclass)))); -+ PG_TRY(); -+ { -+ result = pstrdup(ncontext); -+ } -+ PG_CATCH(); -+ { -+ freecon(ncontext); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ -+ freecon(ncontext); -+ -+ return result; -+} -+ -+/* -+ * 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 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, SIG_IGN); -+ pqsignal(SIGINT, SIG_IGN); -+ pqsignal(SIGTERM, exit); -+ pqsignal(SIGQUIT, exit); -+ pqsignal(SIGUSR1, SIG_IGN); -+ pqsignal(SIGUSR2, SIG_IGN); -+ pqsignal(SIGCHLD, SIG_DFL); -+ PG_SETMASK(&UnBlockSig); -+ -+ 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 (true) -+ { -+ 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))); -+ /* switch enforcing/permissive */ -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ 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))); -+ -+ /* security policy reloaded */ -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ 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; -+ -+ if (!sepgsqlIsEnabled()) -+ return (pid_t) 0; -+ -+ 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/checker.c sepgsql-new/src/backend/security/sepgsql/checker.c ---- base/src/backend/security/sepgsql/checker.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/sepgsql/checker.c 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,523 @@ -+/* -+ * src/backend/security/sepgsql/checker.c -+ * walks on given Query tree and applies checks -+ * -+ * Portions Copyright (c) 1996-2009, 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_language.h" -+#include "catalog/pg_largeobject.h" -+#include "catalog/pg_proc.h" -+#include "catalog/pg_rewrite.h" -+#include "catalog/pg_security.h" -+#include "security/sepgsql.h" -+#include "storage/bufmgr.h" -+#include "utils/builtins.h" -+#include "utils/fmgroids.h" -+#include "utils/lsyscache.h" -+#include "utils/syscache.h" -+#include "utils/tqual.h" -+ -+/* -+ * fixupWholeRowReference -+ */ -+static Bitmapset * -+fixupWholeRowReference(Oid relid, int nattrs, Bitmapset *columns) -+{ -+ Bitmapset *result; -+ AttrNumber attno; -+ -+ attno = InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber; -+ -+ if (!bms_is_member(attno, columns)) -+ return columns; /* no need to fixup */ -+ -+ result = bms_copy(columns); -+ result = bms_del_member(result, attno); -+ -+ for (attno=1; attno <= nattrs; attno++) -+ { -+ Form_pg_attribute attform; -+ HeapTuple atttup; -+ -+ atttup = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(relid), -+ Int16GetDatum(attno), -+ 0, 0); -+ if (!HeapTupleIsValid(atttup)) -+ continue; -+ -+ attform = (Form_pg_attribute) GETSTRUCT(atttup); -+ if (!attform->attisdropped) -+ { -+ int cindex = attno - FirstLowInvalidHeapAttributeNumber; -+ result = bms_add_member(result, cindex); -+ } -+ ReleaseSysCache(atttup); -+ } -+ -+ return result; -+} -+ -+/* -+ * checkTabelColumnPerms -+ * This functions applies table/column level permissions for -+ * all the appeared ones in user's query, and raises an error -+ * if violated. -+ * It also applies a few hardwired policy which prevent to -+ * modified some of system catalogs. -+ */ -+static void -+checkTabelColumnPerms(Oid relid, Bitmapset *selected, Bitmapset *modified, -+ access_vector_t required) -+{ -+ Bitmapset *columns; -+ Bitmapset *selected_ex; -+ Bitmapset *modified_ex; -+ HeapTuple tuple; -+ AttrNumber attno; -+ int nattrs; -+ const char *audit_name; -+ -+ /* -+ * NOTE: HARDWIRED POLICY IN SE-POSTGRESQL -+ * - User cannot modify pg_rewrite.* by hand, because it holds -+ * a parsed Query tree which includes requiredPerms and -+ * RangeTblEntry with selectedCols/modifiedCols. -+ * The correctness of access controls depends on these data -+ * are protected from unexpected manipulation.. -+ * -+ * SE-PostgreSQL always prevent user's query tries to modify -+ * these system catalogs by hand. Please use approariate -+ * interfaces. -+ */ -+ if ((required & (SEPG_DB_TABLE__UPDATE -+ | SEPG_DB_TABLE__INSERT -+ | SEPG_DB_TABLE__DELETE)) != 0 && -+ (relid == RewriteRelationId || -+ relid == LargeObjectRelationId || -+ relid == SecurityRelationId)) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SE-PostgreSQL peremptorily prevent to modify " -+ "\"%s\" system catalog by hand", get_rel_name(relid)))); -+ -+ /* -+ * Check db_table:{...} permissions -+ */ -+ tuple = SearchSysCache(RELOID, -+ ObjectIdGetDatum(relid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for relation %u", relid); -+ -+ /* ignore, if the relation is not db_table class */ -+ if (sepgsqlTupleObjectClass(RelationRelationId, tuple) -+ != SEPG_CLASS_DB_TABLE) -+ { -+ ReleaseSysCache(tuple); -+ return; -+ } -+ -+ audit_name = sepgsqlAuditName(RelationRelationId, tuple); -+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple), -+ SEPG_CLASS_DB_TABLE, -+ required, -+ audit_name, true); -+ -+ nattrs = ((Form_pg_class) GETSTRUCT(tuple))->relnatts; -+ -+ ReleaseSysCache(tuple); -+ -+ /* -+ * Check db_column:{...} permissions -+ */ -+ selected_ex = fixupWholeRowReference(relid, nattrs, selected); -+ modified_ex = fixupWholeRowReference(relid, nattrs, modified); -+ columns = bms_union(selected_ex, modified_ex); -+ -+ while ((attno = bms_first_member(columns)) >= 0) -+ { -+ Form_pg_attribute attForm; -+ access_vector_t attperms = 0; -+ -+ if (bms_is_member(attno, selected_ex)) -+ attperms |= SEPG_DB_COLUMN__SELECT; -+ if (bms_is_member(attno, modified_ex)) -+ { -+ if (required & SEPG_DB_TABLE__UPDATE) -+ attperms |= SEPG_DB_COLUMN__UPDATE; -+ if (required & SEPG_DB_TABLE__INSERT) -+ attperms |= SEPG_DB_COLUMN__INSERT; -+ } -+ if (attperms == 0) -+ continue; -+ -+ /* remove the attribute number offset */ -+ attno += FirstLowInvalidHeapAttributeNumber; -+ tuple = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(relid), -+ Int16GetDatum(attno), -+ 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for attribute %d of relation %u", -+ attno, relid); -+ -+ attForm = (Form_pg_attribute) GETSTRUCT(tuple); -+ if (attForm->attisdropped) -+ elog(ERROR, "attribute %d of relation %u does not exist", -+ attno, relid); -+ -+ audit_name = sepgsqlAuditName(AttributeRelationId, tuple); -+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple), -+ SEPG_CLASS_DB_COLUMN, -+ attperms, -+ audit_name, true); -+ ReleaseSysCache(tuple); -+ } -+ -+ if (selected_ex != selected) -+ bms_free(selected_ex); -+ -+ if (modified_ex != modified) -+ bms_free(modified_ex); -+ -+ bms_free(columns); -+} -+ -+/* -+ * sepgsqlCheckQueryPerms -+ * It checks permission for all the required tables/columns on -+ * generic user queries. -+ */ -+void -+sepgsqlCheckRTEPerms(RangeTblEntry *rte) -+{ -+ access_vector_t required = 0; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ if (rte->rtekind != RTE_RELATION) -+ return; -+ -+ if (rte->requiredPerms & ACL_SELECT) -+ required |= SEPG_DB_TABLE__SELECT; -+ if (rte->requiredPerms & ACL_INSERT) -+ required |= SEPG_DB_TABLE__INSERT; -+ if (rte->requiredPerms & ACL_UPDATE) -+ required |= SEPG_DB_TABLE__UPDATE; -+ if (rte->requiredPerms & ACL_DELETE) -+ required |= SEPG_DB_TABLE__DELETE; -+ /* -+ * TODO: we should add SEPG_DB_TABLE__LOCK here, -+ * but ACL_SELECT_FOR_UPDATE has same value now. -+ */ -+ if (required == 0) -+ return; -+ -+ checkTabelColumnPerms(rte->relid, -+ rte->selectedCols, -+ rte->modifiedCols, -+ required); -+} -+ -+/* -+ * sepgsqlCheckCopyTable -+ * It checks permissions on COPY TO/FROM. -+ */ -+void -+sepgsqlCheckCopyTable(Relation rel, List *attnumlist, bool is_from) -+{ -+ Bitmapset *selected = NULL; -+ Bitmapset *modified = NULL; -+ ListCell *l; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* all checkes are done in sepgsqlCheckRTEPerms */ -+ if (!rel) -+ return; -+ -+ foreach (l, attnumlist) -+ { -+ AttrNumber attno = lfirst_int(l); -+ -+ attno -= FirstLowInvalidHeapAttributeNumber; -+ if (is_from) -+ modified = bms_add_member(modified, attno); -+ else -+ selected = bms_add_member(selected, attno); -+ } -+ -+ checkTabelColumnPerms(RelationGetRelid(rel), -+ selected, modified, -+ is_from ? SEPG_DB_TABLE__INSERT -+ : SEPG_DB_TABLE__SELECT); -+} -+ -+/* -+ * sepgsqlCheckSelectInto -+ * It checks db_table/db_column:{insert} on the table newly created -+ */ -+void -+sepgsqlCheckSelectInto(Oid relationId) -+{ -+ Bitmapset *modified = NULL; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ modified = bms_add_member(modified, InvalidAttrNumber -+ - FirstLowInvalidHeapAttributeNumber); -+ -+ checkTabelColumnPerms(relationId, NULL, modified, -+ SEPG_DB_TABLE__INSERT); -+} -+ -+/* -+ * fixupColumnAvPerms -+ * To change pg_attribute.attisdropped means dropping a column, -+ * although this operation done by update, so it need to change -+ * required permmision in this special case. -+ */ -+static access_vector_t -+fixupColumnAvPerms(HeapTuple newtup, HeapTuple oldtup) -+{ -+ Form_pg_attribute oldatt = (Form_pg_attribute) GETSTRUCT(oldtup); -+ Form_pg_attribute newatt = (Form_pg_attribute) GETSTRUCT(newtup); -+ -+ if (!oldatt->attisdropped && newatt->attisdropped) -+ return SEPG_DB_COLUMN__DROP; -+ if (oldatt->attisdropped && !newatt->attisdropped) -+ return SEPG_DB_COLUMN__CREATE; -+ -+ return 0; -+} -+ -+/* -+ * checkCLibraryInstallation -+ * It checks the correctness of C-library when user tries to -+ * create / replace C-functions. -+ */ -+static void -+checkCLibraryInstallation(HeapTuple newtup, HeapTuple oldtup) -+{ -+ Form_pg_proc oldpro, newpro; -+ Datum oldbin, newbin; -+ char *filename; -+ bool isnull; -+ -+ newpro = (Form_pg_proc) GETSTRUCT(newtup); -+ if (newpro->prolang != ClanguageId) -+ return; -+ -+ newbin = SysCacheGetAttr(PROCOID, newtup, -+ Anum_pg_proc_probin, &isnull); -+ if (isnull) -+ return; -+ -+ if (HeapTupleIsValid(oldtup)) -+ { -+ oldpro = (Form_pg_proc) GETSTRUCT(oldtup); -+ oldbin = SysCacheGetAttr(PROCOID, oldtup, -+ Anum_pg_proc_probin, &isnull); -+ if (!isnull && -+ oldpro->prolang == newpro->prolang && -+ DatumGetBool(DirectFunctionCall2(byteaeq, oldbin, newbin))) -+ return; /* no need to check, if unchanged */ -+ } -+ filename = TextDatumGetCString(newbin); -+ sepgsqlCheckDatabaseInstallModule(filename); -+} -+ -+/* -+ * Row-level decision making -+ */ -+bool -+sepgsqlExecScan(Relation rel, HeapTuple tuple, AclMode required, bool abort) -+{ -+ security_class_t tclass; -+ access_vector_t permissions = 0; -+ const char *audit_name; -+ -+ if (RelationGetForm(rel)->relkind != RELKIND_RELATION) -+ return true; -+ -+ if (required & ACL_SELECT) -+ permissions |= SEPG_DB_TUPLE__SELECT; -+ if (required & ACL_UPDATE) -+ permissions |= SEPG_DB_TUPLE__UPDATE; -+ if (required & ACL_DELETE) -+ permissions |= SEPG_DB_TUPLE__DELETE; -+ if (permissions == 0) -+ return true; -+ -+ audit_name = sepgsqlAuditName(RelationGetRelid(rel), tuple); -+ tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple); -+ return sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple), -+ tclass, -+ permissions, -+ audit_name, abort); -+} -+ -+/* -+ * checkTrustedAction -+ * It returns true, if we can ignore access controls for create/alter/drop -+ * on the given database objects. -+ */ -+static bool -+checkTrustedAction(Relation rel, bool internal) -+{ -+ if (RelationGetForm(rel)->relkind != RELKIND_RELATION) -+ return true; -+ -+ if (RelationGetRelid(rel) == DatabaseRelationId || -+ RelationGetRelid(rel) == RelationRelationId || -+ RelationGetRelid(rel) == AttributeRelationId || -+ RelationGetRelid(rel) == ProcedureRelationId) -+ return false; -+ -+ if (internal && -+ (RelationGetRelid(rel) == SecurityRelationId || -+ RelationGetRelid(rel) == LargeObjectRelationId)) -+ return true; -+ -+ return !sepostgresql_row_level; -+} -+ -+/* -+ * HeapTuple INSERT/UPDATE/DELETE -+ */ -+bool -+sepgsqlHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal) -+{ -+ Oid relid = RelationGetRelid(rel); -+ security_class_t tclass; -+ const char *audit_name; -+ -+ if (!sepgsqlIsEnabled()) -+ return true; -+ -+ /* set default security context */ -+ if (!OidIsValid(HeapTupleGetSecLabel(newtup))) -+ { -+ if (HeapTupleHasSecLabel(newtup)) -+ sepgsqlSetDefaultSecLabel(rel, newtup); -+ -+ /* need to check db_blob:{create} for the first tuple */ -+ if (internal && -+ RelationGetRelid(rel) == LargeObjectRelationId) -+ goto skip; -+ } -+ -+ if (checkTrustedAction(rel, internal)) -+ return true; -+ -+ /* check binary library installation */ -+ if (relid == ProcedureRelationId) -+ checkCLibraryInstallation(newtup, NULL); -+ /* check db_procedure:{install}, if necessary */ -+ sepgsqlCheckProcedureInstall(rel, newtup, NULL); -+ -+skip: -+ tclass = sepgsqlTupleObjectClass(relid, newtup); -+ audit_name = sepgsqlAuditName(relid, newtup); -+ return sepgsqlClientHasPerms(HeapTupleGetSecLabel(newtup), -+ tclass, -+ SEPG_DB_TUPLE__INSERT, -+ audit_name, internal); -+} -+ -+bool -+sepgsqlHeapTupleUpdate(Relation rel, HeapTuple oldtup, -+ HeapTuple newtup, bool internal) -+{ -+ Oid relid = RelationGetRelid(rel); -+ access_vector_t required = 0; -+ security_class_t tclass; -+ const char *audit_name; -+ -+ if (!sepgsqlIsEnabled()) -+ return true; -+ -+ /* preserve security label, if unchanged */ -+ if (!OidIsValid(HeapTupleGetSecLabel(newtup))) -+ { -+ sepgsql_sid_t oldsid = HeapTupleGetSecLabel(oldtup); -+ -+ if (HeapTupleHasSecLabel(newtup)) -+ HeapTupleSetSecLabel(newtup, oldsid); -+ } -+ -+ if (checkTrustedAction(rel, internal)) -+ return true; -+ -+ /* user's query is already checked in ExecScan */ -+ if (internal) -+ required |= SEPG_DB_TUPLE__UPDATE; -+ /* special case in column create/drop */ -+ if (relid == AttributeRelationId) -+ required |= fixupColumnAvPerms(newtup, oldtup); -+ /* check binary library installation */ -+ if (relid == ProcedureRelationId) -+ checkCLibraryInstallation(newtup, oldtup); -+ /* check db_procedure:{install}, if necessary */ -+ sepgsqlCheckProcedureInstall(rel, newtup, oldtup); -+ -+ /* relabeled? */ -+ if (sepgsqlTupleObjectClass(relid, newtup) -+ != sepgsqlTupleObjectClass(relid, oldtup) || -+ HeapTupleGetSecLabel(newtup) != HeapTupleGetSecLabel(oldtup)) -+ required |= SEPG_DB_TUPLE__RELABELFROM; -+ -+ if (required) -+ { -+ audit_name = sepgsqlAuditName(relid, oldtup); -+ tclass = sepgsqlTupleObjectClass(relid, oldtup); -+ if (!sepgsqlClientHasPerms(HeapTupleGetSecLabel(oldtup), -+ tclass, -+ required, -+ audit_name, internal)) -+ return false; -+ } -+ -+ if (required & SEPG_DB_TUPLE__RELABELFROM) -+ { -+ audit_name = sepgsqlAuditName(relid, newtup); -+ tclass = sepgsqlTupleObjectClass(relid, newtup); -+ if (!sepgsqlClientHasPerms(HeapTupleGetSecLabel(newtup), -+ tclass, -+ SEPG_DB_TUPLE__RELABELTO, -+ audit_name, internal)) -+ return false; -+ } -+ -+ return true; -+} -+ -+bool -+sepgsqlHeapTupleDelete(Relation rel, HeapTuple oldtup, bool internal) -+{ -+ Oid relid = RelationGetRelid(rel); -+ security_class_t tclass; -+ const char *audit_name; -+ -+ if (!sepgsqlIsEnabled() || checkTrustedAction(rel, internal)) -+ return true; -+ -+ /* user's query is already checked in ExecScan */ -+ if (!internal) -+ return true; -+ -+ audit_name = sepgsqlAuditName(relid, oldtup); -+ tclass = sepgsqlTupleObjectClass(relid, oldtup); -+ return sepgsqlClientHasPerms(HeapTupleGetSecLabel(oldtup), -+ tclass, -+ SEPG_DB_TUPLE__DELETE, -+ audit_name, internal); -+} -diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql-new/src/backend/security/sepgsql/core.c ---- base/src/backend/security/sepgsql/core.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/sepgsql/core.c 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,392 @@ -+/* -+ * src/backend/security/sepgsql/core.c -+ * The core facility of 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 "catalog/indexing.h" -+#include "catalog/pg_database.h" -+#include "catalog/pg_proc.h" -+#include "catalog/pg_security.h" -+#include "libpq/libpq-be.h" -+#include "miscadmin.h" -+#include "security/sepgsql.h" -+#include "utils/builtins.h" -+#include "utils/fmgroids.h" -+#include "utils/syscache.h" -+#include "utils/tqual.h" -+ -+static security_context_t clientLabel = NULL; -+static security_context_t serverLabel = NULL; -+static security_context_t unlabeledLabel = NULL; -+ -+security_context_t -+sepgsqlGetServerLabel(void) -+{ -+ if (!serverLabel) -+ { -+ if (getcon_raw(&serverLabel) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not get server label"))); -+ } -+ return serverLabel; -+} -+ -+security_context_t -+sepgsqlGetClientLabel(void) -+{ -+ if (!clientLabel) -+ { -+ /* -+ * When the process is not invoked as a backend of client, -+ * it works as a server process and as a client process -+ * in same time. -+ */ -+ if (!MyProcPort) -+ return sepgsqlGetServerLabel(); -+ -+ /* -+ * SELinux provides getpeercon(3) which enables to obtain -+ * the security context of peer process. -+ * If MyProcPort->sock is unix domain socket, no special -+ * configuration is necessary. If it is tcp/ip socket, -+ * labeled IPsec or fallback context to be configured. -+ */ -+ if (getpeercon_raw(MyProcPort->sock, &clientLabel) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not obtain client label"))); -+ } -+ -+ return clientLabel; -+} -+ -+security_context_t -+sepgsqlSwitchClient(security_context_t new_client) -+{ -+ char *old_client = sepgsqlGetClientLabel(); -+ -+ clientLabel = new_client; -+ -+ PG_TRY(); -+ { -+ sepgsqlAvcSwitchClient(); -+ } -+ PG_CATCH(); -+ { -+ clientLabel = old_client; -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ -+ return new_client; -+} -+ -+security_context_t -+sepgsqlGetUnlabeledLabel(void) -+{ -+ if (!unlabeledLabel) -+ { -+ if (security_get_initial_context_raw("unlabeled", -+ &unlabeledLabel) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not get unlabeled label"))); -+ } -+ return unlabeledLabel; -+} -+ -+security_context_t -+sepgsqlGetDatabaseLabel(void) -+{ -+ HeapTuple tuple; -+ sepgsql_sid_t dbsid; -+ security_context_t dbcon; -+ -+ if (IsBootstrapProcessingMode()) -+ { -+ static security_context_t databaseLabel = NULL; -+ -+ if (!databaseLabel) -+ { -+ security_class_t tclass -+ = string_to_security_class("db_database"); -+ -+ if (security_compute_create_raw(sepgsqlGetClientLabel(), -+ sepgsqlGetClientLabel(), -+ tclass, &databaseLabel) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: unable to compute database context"))); -+ } -+ return pstrdup(databaseLabel); -+ } -+ -+ tuple = SearchSysCache(DATABASEOID, -+ ObjectIdGetDatum(MyDatabaseId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for database: %u", -+ MyDatabaseId); -+ -+ dbsid = HeapTupleGetSecLabel(tuple); -+ dbcon = securityLookupSecurityLabel(dbsid); -+ if (!dbcon || !sepgsqlCheckValidSecurityLabel(dbcon)) -+ dbcon = pstrdup(sepgsqlGetUnlabeledLabel()); -+ -+ ReleaseSysCache(tuple); -+ -+ return dbcon; -+} -+ -+sepgsql_sid_t -+sepgsqlGetDatabaseSid(void) -+{ -+ security_context_t dbcontext = sepgsqlGetDatabaseLabel(); -+ -+ return securityLookupSecurityId(dbcontext); -+} -+ -+/* -+ * sepgsqlIsEnabled() -+ * -+ * returns the state of SE-PostgreSQL whether enabled, or not. -+ * When functions under src/backend/utils/ are invoked, they have to -+ * be checked on the head. -+ * This status is decided with two factors. The one is GUC parameter -+ * of "sepostgresql=on/off", and the other is is_selinux_enabled(). -+ * Both of them have to be true, when SE-PostgreSQL is activated. -+ */ -+bool sepostgresql_is_enabled; /* default is false */ -+ -+bool -+sepgsqlIsEnabled(void) -+{ -+ static int enabled = -1; /* unchecked */ -+ -+ if (!sepostgresql_is_enabled) -+ return false; -+ -+ if (enabled < 0) -+ enabled = is_selinux_enabled(); -+ -+ return enabled > 0 ? true : false; -+} -+ -+/* -+ * sepgsqlInitialize -+ */ -+void -+sepgsqlInitialize(void) -+{ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsqlGetClientLabel(); -+ -+ sepgsqlAvcInit(); -+} -+ -+/* -+ * SE-PostgreSQL specific functions -+ */ -+Datum -+sepgsql_getcon(PG_FUNCTION_ARGS) -+{ -+ security_context_t context; -+ -+ if (!sepgsqlIsEnabled()) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: disabled now"))); -+ -+ context = sepgsqlGetClientLabel(); -+ context = sepgsqlSecurityLabelTransOut(context); -+ return CStringGetTextDatum(context); -+} -+ -+Datum -+sepgsql_getservcon(PG_FUNCTION_ARGS) -+{ -+ security_context_t context; -+ -+ if (!sepgsqlIsEnabled()) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: disabled now"))); -+ -+ context = sepgsqlGetServerLabel(); -+ context = sepgsqlSecurityLabelTransOut(context); -+ return CStringGetTextDatum(context); -+} -+ -+/* -+ * sepgsql_(get|set)_(user|role|type|range) -+ * get/set a component of security context. -+ */ -+static void -+parse_security_context(security_context_t context, -+ char **user, char **role, char **type, char **range) -+{ -+ security_context_t raw_context; -+ char *tok; -+ -+ if (!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: %s", context))); -+ -+ PG_TRY(); -+ { -+ tok = strtok(raw_context, ":"); -+ if (user) -+ *user = (!tok ? NULL : pstrdup(tok)); -+ -+ tok = strtok(NULL, ":"); -+ if (role) -+ *role = (!tok ? NULL : pstrdup(tok)); -+ -+ tok = strtok(NULL, ":"); -+ if (type) -+ *type = (!tok ? NULL : pstrdup(tok)); -+ -+ tok = strtok(NULL, "\0"); -+ if (range) -+ *range = (!tok ? NULL : pstrdup(tok)); -+ } -+ PG_CATCH(); -+ { -+ freecon(raw_context); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(raw_context); -+} -+ -+Datum -+sepgsql_get_user(PG_FUNCTION_ARGS) -+{ -+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *user; -+ -+ parse_security_context(context, &user, NULL, NULL, NULL); -+ if (!user) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not extract user of \"%s\"", context))); -+ -+ PG_RETURN_TEXT_P(CStringGetTextDatum(user)); -+} -+ -+Datum -+sepgsql_get_role(PG_FUNCTION_ARGS) -+{ -+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *role; -+ -+ parse_security_context(context, NULL, &role, NULL, NULL); -+ if (!role) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not extract role of \"%s\"", context))); -+ -+ PG_RETURN_TEXT_P(CStringGetTextDatum(role)); -+} -+ -+Datum -+sepgsql_get_type(PG_FUNCTION_ARGS) -+{ -+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *type; -+ -+ parse_security_context(context, NULL, NULL, &type, NULL); -+ if (!type) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not extract type of \"%s\"", context))); -+ -+ PG_RETURN_TEXT_P(CStringGetTextDatum(type)); -+} -+ -+Datum -+sepgsql_get_range(PG_FUNCTION_ARGS) -+{ -+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *range; -+ -+ parse_security_context(context, NULL, NULL, NULL, &range); -+ if (!range) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not extract range of \"%s\"", context))); -+ -+ PG_RETURN_TEXT_P(CStringGetTextDatum(range)); -+} -+ -+static Datum -+sepgsql_set_common(char *context, char *user, char *role, char *type, char *range) -+{ -+ StringInfoData newcon; -+ -+ parse_security_context(context, -+ !user ? &user : NULL, -+ !role ? &role : NULL, -+ !type ? &type : NULL, -+ !range ? &range : NULL); -+ if (!user || !role || !type) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: invalid security context: \"%s\"", context))); -+ -+ initStringInfo(&newcon); -+ appendStringInfo(&newcon, "%s:%s:%s", user, role, type); -+ if (range) -+ appendStringInfo(&newcon, ":%s", range); -+ -+ return CStringGetTextDatum(sepgsqlSecurityLabelTransOut(newcon.data)); -+} -+ -+Datum -+sepgsql_set_user(PG_FUNCTION_ARGS) -+{ -+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *user = TextDatumGetCString(PG_GETARG_TEXT_P(1)); -+ -+ return sepgsql_set_common(context, user, NULL, NULL, NULL); -+} -+ -+Datum -+sepgsql_set_role(PG_FUNCTION_ARGS) -+{ -+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *role = TextDatumGetCString(PG_GETARG_TEXT_P(1)); -+ -+ return sepgsql_set_common(context, NULL, role, NULL, NULL); -+} -+ -+Datum -+sepgsql_set_type(PG_FUNCTION_ARGS) -+{ -+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *type = TextDatumGetCString(PG_GETARG_TEXT_P(1)); -+ -+ return sepgsql_set_common(context, NULL, NULL, type, NULL); -+} -+ -+Datum -+sepgsql_set_range(PG_FUNCTION_ARGS) -+{ -+ char *context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *range = TextDatumGetCString(PG_GETARG_TEXT_P(1)); -+ -+ return sepgsql_set_common(context, NULL, NULL, NULL, range); -+} -diff -rpNU3 base/src/backend/security/sepgsql/dummy.c sepgsql-new/src/backend/security/sepgsql/dummy.c ---- base/src/backend/security/sepgsql/dummy.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/sepgsql/dummy.c 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,79 @@ -+/* -+ * src/backend/utils/sepgsql/dummy.c -+ * A set of stubs when SE-PostgreSQL is not activated -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#include "postgres.h" -+ -+#include "security/sepgsql.h" -+ -+static Datum -+unavailable_function(const char *fn_name) -+{ -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("function \"%s\" is not available", fn_name))); -+ PG_RETURN_VOID(); -+} -+ -+Datum -+sepgsql_getcon(PG_FUNCTION_ARGS) -+{ -+ return unavailable_function(__FUNCTION__); -+} -+ -+Datum -+sepgsql_getservcon(PG_FUNCTION_ARGS) -+{ -+ return unavailable_function(__FUNCTION__); -+} -+ -+Datum -+sepgsql_get_user(PG_FUNCTION_ARGS) -+{ -+ return unavailable_function(__FUNCTION__); -+} -+ -+Datum -+sepgsql_get_role(PG_FUNCTION_ARGS) -+{ -+ return unavailable_function(__FUNCTION__); -+} -+ -+Datum -+sepgsql_get_type(PG_FUNCTION_ARGS) -+{ -+ return unavailable_function(__FUNCTION__); -+} -+ -+Datum -+sepgsql_get_range(PG_FUNCTION_ARGS) -+{ -+ return unavailable_function(__FUNCTION__); -+} -+ -+Datum -+sepgsql_set_user(PG_FUNCTION_ARGS) -+{ -+ return unavailable_function(__FUNCTION__); -+} -+ -+Datum -+sepgsql_set_role(PG_FUNCTION_ARGS) -+{ -+ return unavailable_function(__FUNCTION__); -+} -+ -+Datum -+sepgsql_set_type(PG_FUNCTION_ARGS) -+{ -+ return unavailable_function(__FUNCTION__); -+} -+ -+Datum -+sepgsql_set_range(PG_FUNCTION_ARGS) -+{ -+ return unavailable_function(__FUNCTION__); -+} -diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql-new/src/backend/security/sepgsql/hooks.c ---- base/src/backend/security/sepgsql/hooks.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/sepgsql/hooks.c 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,793 @@ -+/* -+ * src/backend/security/sepgsql/hooks.c -+ * SE-PostgreSQL security hooks -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#include "postgres.h" -+ -+#include "access/heapam.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_trigger.h" -+#include "catalog/pg_ts_parser.h" -+#include "catalog/pg_ts_template.h" -+#include "catalog/pg_ts_template.h" -+#include "catalog/pg_type.h" -+#include "miscadmin.h" -+#include "nodes/makefuncs.h" -+#include "nodes/nodes.h" -+#include "security/sepgsql.h" -+#include "storage/bufmgr.h" -+#include "utils/syscache.h" -+ -+/* -+ * sepgsqlCheckDatabaseAccess -+ * checks db_database:{access} permission when the client logs-in -+ * the given database. -+ * -+ * sepgsqlCheckDatabaseSuperuser -+ * checks db_database:{superuser} permission when the client tries -+ * to perform as a superuser on the given databse. -+ */ -+static bool -+checkDatabaseCommon(Oid database_oid, access_vector_t perms) -+{ -+ const char *audit_name; -+ HeapTuple tuple; -+ bool rc; -+ -+ if (!sepgsqlIsEnabled()) -+ return true; -+ -+ tuple = SearchSysCache(DATABASEOID, -+ ObjectIdGetDatum(database_oid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for database: %u", -+ database_oid); -+ -+ audit_name = sepgsqlAuditName(DatabaseRelationId, tuple); -+ rc = sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple), -+ SEPG_CLASS_DB_DATABASE, -+ perms, -+ audit_name, false); -+ ReleaseSysCache(tuple); -+ -+ return rc; -+} -+ -+bool -+sepgsqlCheckDatabaseAccess(Oid database_oid) -+{ -+ return checkDatabaseCommon(database_oid, -+ SEPG_DB_DATABASE__ACCESS); -+} -+ -+bool -+sepgsqlCheckDatabaseSuperuser(void) -+{ -+ return checkDatabaseCommon(MyDatabaseId, -+ SEPG_DB_DATABASE__SUPERUSER); -+} -+ -+/* -+ * sepgsqlDatabaseInstallModule -+ * checks db_database:{install_module} permission on -+ * the current database and a given loadable module. -+ */ -+void -+sepgsqlCheckDatabaseInstallModule(const char *filename) -+{ -+ security_context_t fcontext; -+ HeapTuple tuple; -+ const char *audit_name; -+ char *fullpath; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* (client) <-- db_database:module_install --> (database) */ -+ tuple = SearchSysCache(DATABASEOID, -+ ObjectIdGetDatum(MyDatabaseId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for database: %u", -+ MyDatabaseId); -+ -+ audit_name = sepgsqlAuditName(DatabaseRelationId, tuple); -+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple), -+ SEPG_CLASS_DB_DATABASE, -+ SEPG_DB_DATABASE__INSTALL_MODULE, -+ audit_name, true); -+ ReleaseSysCache(tuple); -+ -+ /* (client) <-- db_databse:module_install --> (*.so file) */ -+ fullpath = expand_dynamic_library_name(filename); -+ if (getfilecon_raw(fullpath, &fcontext) < 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not access file \"%s\": %m", fullpath))); -+ PG_TRY(); -+ { -+ sepgsqlComputePerms(sepgsqlGetClientLabel(), -+ fcontext, -+ SEPG_CLASS_DB_DATABASE, -+ SEPG_DB_DATABASE__INSTALL_MODULE, -+ fullpath, true); -+ } -+ PG_CATCH(); -+ { -+ freecon(fcontext); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(fcontext); -+} -+ -+/* -+ * sepgsqlDatabaseLoadModule -+ * checks capability of database to load a specific library -+ */ -+void -+sepgsqlCheckDatabaseLoadModule(const char *filename) -+{ -+ security_context_t filecon; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ if (getfilecon_raw(filename, &filecon) < 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not access file \"%s\": %m", filename))); -+ PG_TRY(); -+ { -+ sepgsqlComputePerms(sepgsqlGetDatabaseLabel(), -+ filecon, -+ SEPG_CLASS_DB_DATABASE, -+ SEPG_DB_DATABASE__LOAD_MODULE, -+ filename, true); -+ } -+ PG_CATCH(); -+ { -+ freecon(filecon); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(filecon); -+} -+ -+/* -+ * sepgsqlCheckTableLock -+ * checks db_table:{lock} permission when the client tries to -+ * aquire explicit lock on the given relation. -+ * -+ * sepgsqlCheckTableTruncate -+ * checks db_table:{delete} permission when the client tries to -+ * truncate the given relation. -+ */ -+static bool -+checkTableCommon(Oid table_oid, access_vector_t perms) -+{ -+ const char *audit_name; -+ security_class_t tclass; -+ HeapTuple tuple; -+ bool rc = true; -+ -+ if (!sepgsqlIsEnabled()) -+ return true; -+ -+ tuple = SearchSysCache(RELOID, -+ ObjectIdGetDatum(table_oid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for relation %u", table_oid); -+ -+ tclass = sepgsqlTupleObjectClass(RelationRelationId, tuple); -+ if (tclass == SEPG_CLASS_DB_TABLE) -+ { -+ audit_name = sepgsqlAuditName(RelationRelationId, tuple); -+ rc = sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple), -+ SEPG_CLASS_DB_TABLE, -+ perms, -+ audit_name, false); -+ } -+ ReleaseSysCache(tuple); -+ -+ return rc; -+} -+ -+bool -+sepgsqlCheckTableLock(Oid table_oid) -+{ -+ return checkTableCommon(table_oid, SEPG_DB_TABLE__LOCK); -+} -+ -+bool -+sepgsqlCheckTableTruncate(Relation rel) -+{ -+ HeapScanDesc scan; -+ HeapTuple tuple; -+ const char *audit_name; -+ bool rc = true; -+ -+ if (!checkTableCommon(RelationGetRelid(rel), SEPG_DB_TABLE__DELETE)) -+ return false; -+ -+ /* -+ * check db_tuple:{delete} permission -+ */ -+ scan = heap_beginscan(rel, SnapshotNow, 0, NULL); -+ -+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) -+ { -+ audit_name = sepgsqlAuditName(RelationGetRelid(rel), tuple); -+ rc = sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple), -+ SEPG_CLASS_DB_TABLE, -+ SEPG_DB_TUPLE__DELETE, -+ audit_name, false); -+ if (!rc) -+ break; -+ } -+ heap_endscan(scan); -+ -+ return rc; -+} -+ -+/* -+ * sepgsqlCheckProcedureExecute -+ * checks db_procedure:{execute} permission when the client tries -+ * to invoke the given SQL function. -+ */ -+bool sepgsqlCheckProcedureExecute(Oid proc_oid) -+{ -+ const char *audit_name; -+ HeapTuple tuple; -+ bool rc; -+ -+ if (!sepgsqlIsEnabled()) -+ return true; -+ -+ /* -+ * check db_procedure:{execute} permission -+ */ -+ tuple = SearchSysCache(PROCOID, -+ ObjectIdGetDatum(proc_oid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for procedure: %u", proc_oid); -+ -+ audit_name = sepgsqlAuditName(ProcedureRelationId, tuple); -+ rc = sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple), -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_DB_PROCEDURE__EXECUTE, -+ audit_name, false); -+ ReleaseSysCache(tuple); -+ -+ return rc; -+} -+ -+/* -+ * sepgsqlCheckProcedureEntrypoint -+ * checks whether the given function call causes domain transition, -+ * or not. If it needs a domain transition, it injects a wrapper -+ * function to invoke it under new domain. -+ */ -+static Datum -+sepgsqlTrustedProcInvoker(PG_FUNCTION_ARGS) -+{ -+ security_context_t old_client; -+ FmgrInfo *finfo = fcinfo->flinfo; -+ Datum retval; -+ -+ /* -+ * Set new domain and invocation -+ */ -+ old_client = sepgsqlSwitchClient(finfo->sepgsql_label); -+ -+ PG_TRY(); -+ { -+ retval = finfo->sepgsql_addr(fcinfo); -+ } -+ PG_CATCH(); -+ { -+ sepgsqlSwitchClient(old_client); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ -+ sepgsqlSwitchClient(old_client); -+ -+ return retval; -+} -+ -+void -+sepgsqlCheckProcedureEntrypoint(FmgrInfo *finfo, HeapTuple protup) -+{ -+ MemoryContext oldctx; -+ security_context_t newcon; -+ const char *audit_name; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* -+ * NOTE: It is not available to set up builtin functions as -+ * trusted procedure now, because it needs to invoke builtin -+ * functions to search system caches, then it also invokes -+ * fmgr_info_cxt_security() and makes infinite function call. -+ * This limitation should be fixed later. -+ * (It is same as security definer also) -+ */ -+ -+ oldctx = MemoryContextSwitchTo(finfo->fn_mcxt); -+ -+ newcon = sepgsqlClientCreateLabel(HeapTupleGetSecLabel(protup), -+ SEPG_CLASS_PROCESS); -+ if (strcmp(newcon, sepgsqlGetClientLabel()) == 0) -+ { -+ MemoryContextSwitchTo(oldctx); -+ return; -+ } -+ /* db_procedure:{entrypoint}, if trusted procedure */ -+ audit_name = sepgsqlAuditName(ProcedureRelationId, protup); -+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(protup), -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_DB_PROCEDURE__ENTRYPOINT, -+ audit_name, true); -+ -+ /* process:{transition}, if trusted procedure */ -+ sepgsqlComputePerms(sepgsqlGetClientLabel(), -+ newcon, -+ SEPG_CLASS_PROCESS, -+ SEPG_PROCESS__TRANSITION, -+ NULL, true); -+ -+ /* trusted procedure invocation */ -+ finfo->sepgsql_addr = finfo->fn_addr; -+ finfo->fn_addr = sepgsqlTrustedProcInvoker; -+ finfo->sepgsql_label = newcon; -+ -+ MemoryContextSwitchTo(oldctx); -+} -+ -+/* -+ * 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) -+{ -+ sepgsql_sid_t prosid; -+ HeapTuple protup = NULL; -+ const char *audit_name = NULL; -+ -+ if (!OidIsValid(proc_oid)) -+ return; -+ -+ if (IsBootstrapProcessingMode()) -+ { -+ /* -+ * Assumption: security label is unchanged -+ * during bootstraptin mode, because no one -+ * tries to relabel anything. -+ */ -+ prosid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(), -+ SEPG_CLASS_DB_PROCEDURE); -+ } -+ else -+ { -+ protup = SearchSysCache(PROCOID, -+ ObjectIdGetDatum(proc_oid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(protup)) -+ return; -+ -+ audit_name = sepgsqlAuditName(ProcedureRelationId, protup); -+ prosid = HeapTupleGetSecLabel(protup); -+ } -+ -+ sepgsqlClientHasPerms(prosid, -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_DB_PROCEDURE__INSTALL, -+ audit_name, true); -+ if (HeapTupleIsValid(protup)) -+ ReleaseSysCache(protup); -+} -+ -+#define CHECK_PROC_INSTALL_PERM(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(newtup))->member); \ -+ } while(0) -+ -+void -+sepgsqlCheckProcedureInstall(Relation rel, HeapTuple newtup, HeapTuple oldtup) -+{ -+ /* -+ * db_procedure:{install} check prevent a malicious functions -+ * to be installed, as a part of system catalogs. -+ * It is necessary to prevent other person implicitly to invoke -+ * malicious functions. -+ */ -+ switch (RelationGetRelid(rel)) -+ { -+ case AggregateRelationId: -+ /* -+ * db_procedure:{execute} is checked on invocations of: -+ * pg_aggregate.aggfnoid -+ * pg_aggregate.aggtransfn -+ * pg_aggregate.aggfinalfn -+ */ -+ break; -+ -+ case AccessMethodRelationId: -+ CHECK_PROC_INSTALL_PERM(pg_am, aminsert, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, ambeginscan, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, amgettuple, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, amgetmulti, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, amrescan, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, amendscan, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, ammarkpos, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, amrestrpos, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, ambuild, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, ambulkdelete, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, amvacuumcleanup, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, amcostestimate, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_am, amoptions, newtup, oldtup); -+ break; -+ -+ case AccessMethodProcedureRelationId: -+ CHECK_PROC_INSTALL_PERM(pg_amproc, amproc, newtup, oldtup); -+ break; -+ -+ case CastRelationId: -+ CHECK_PROC_INSTALL_PERM(pg_cast, castfunc, newtup, oldtup); -+ break; -+ -+ case ConversionRelationId: -+ CHECK_PROC_INSTALL_PERM(pg_conversion, conproc, newtup, oldtup); -+ break; -+ -+ case LanguageRelationId: -+ CHECK_PROC_INSTALL_PERM(pg_language, lanplcallfoid, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_language, lanvalidator, newtup, oldtup); -+ break; -+ -+ case OperatorRelationId: -+ CHECK_PROC_INSTALL_PERM(pg_operator, oprcode, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_operator, oprrest, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_operator, oprjoin, newtup, oldtup); -+ break; -+ -+ case TriggerRelationId: -+ CHECK_PROC_INSTALL_PERM(pg_trigger, tgfoid, newtup, oldtup); -+ break; -+ -+ case TSParserRelationId: -+ CHECK_PROC_INSTALL_PERM(pg_ts_parser, prsstart, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_ts_parser, prstoken, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_ts_parser, prsend, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_ts_parser, prsheadline, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_ts_parser, prslextype, newtup, oldtup); -+ break; -+ -+ case TSTemplateRelationId: -+ CHECK_PROC_INSTALL_PERM(pg_ts_template, tmplinit, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_ts_template, tmpllexize, newtup, oldtup); -+ break; -+ -+ case TypeRelationId: -+ CHECK_PROC_INSTALL_PERM(pg_type, typinput, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_type, typoutput, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_type, typreceive, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_type, typsend, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_type, typmodin, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_type, typmodout, newtup, oldtup); -+ CHECK_PROC_INSTALL_PERM(pg_type, typanalyze, newtup, oldtup); -+ break; -+ } -+} -+ -+/* -+ * sepgsqlCheckBlobDrop -+ * checks db_blob:{drop} permission -+ */ -+void -+sepgsqlCheckBlobDrop(HeapTuple lotup) -+{ -+ const char *audit_name; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ audit_name = sepgsqlAuditName(LargeObjectRelationId, lotup); -+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(lotup), -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__DROP, -+ audit_name, true); -+} -+ -+/* -+ * sepgsqlCheckBlobRead -+ * checks db_blob:{read} permission -+ */ -+void -+sepgsqlCheckBlobRead(LargeObjectDesc *lobj) -+{ -+ char audit_name[NAMEDATALEN]; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ snprintf(audit_name, sizeof(audit_name), "blob:%u", lobj->id); -+ sepgsqlClientHasPerms(lobj->secid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__READ, -+ audit_name, true); -+} -+ -+/* -+ * sepgsqlCheckBlobWrite -+ * check db_blob:{write} permission -+ */ -+void -+sepgsqlCheckBlobWrite(LargeObjectDesc *lobj) -+{ -+ char audit_name[NAMEDATALEN]; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ snprintf(audit_name, sizeof(audit_name), "blob:%u", lobj->id); -+ sepgsqlClientHasPerms(lobj->secid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__WRITE, -+ audit_name, true); -+} -+ -+/* -+ * sepgsqlCheckBlobGetattr -+ * check db_blob:{getattr} permission -+ */ -+void -+sepgsqlCheckBlobGetattr(HeapTuple tuple) -+{ -+ const char *audit_name; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ audit_name = sepgsqlAuditName(LargeObjectRelationId, tuple); -+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple), -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__GETATTR, -+ audit_name, true); -+} -+ -+/* -+ * sepgsqlCheckBlobSetattr -+ * check db_blob:{setattr} permission -+ */ -+void -+sepgsqlCheckBlobSetattr(HeapTuple tuple) -+{ -+ const char *audit_name; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ audit_name = sepgsqlAuditName(LargeObjectRelationId, tuple); -+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(tuple), -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__SETATTR, -+ audit_name, true); -+} -+ -+/* -+ * sepgsqlCheckBlobExport -+ * check db_blob:{read export} and file:{write} permission -+ */ -+void -+sepgsqlCheckBlobExport(LargeObjectDesc *lobj, -+ int fdesc, const char *filename) -+{ -+ security_context_t fcontext; -+ security_class_t fclass; -+ char audit_name[NAMEDATALEN]; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ snprintf(audit_name, sizeof(audit_name), "blob:%u", lobj->id); -+ sepgsqlClientHasPerms(lobj->secid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__READ | SEPG_DB_BLOB__EXPORT, -+ audit_name, true); -+ -+ fclass = sepgsqlFileObjectClass(fdesc); -+ if (fgetfilecon_raw(fdesc, &fcontext) < 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not get security context \"%s\"", filename))); -+ PG_TRY(); -+ { -+ sepgsqlComputePerms(sepgsqlGetClientLabel(), -+ fcontext, -+ fclass, -+ SEPG_FILE__WRITE, -+ filename, true); -+ } -+ PG_CATCH(); -+ { -+ freecon(fcontext); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(fcontext); -+} -+ -+/* -+ * sepgsqlCheckBlobImport -+ * check db_blob:{write import} and file:{read} permission -+ */ -+void -+sepgsqlCheckBlobImport(LargeObjectDesc *lobj, -+ int fdesc, const char *filename) -+{ -+ security_context_t fcontext; -+ security_class_t fclass; -+ char audit_name[NAMEDATALEN]; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ snprintf(audit_name, sizeof(audit_name), "blob:%u", lobj->id); -+ sepgsqlClientHasPerms(lobj->secid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__WRITE | SEPG_DB_BLOB__IMPORT, -+ audit_name, true); -+ -+ fclass = sepgsqlFileObjectClass(fdesc); -+ if (fgetfilecon_raw(fdesc, &fcontext) < 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not get security context \"%s\"", filename))); -+ PG_TRY(); -+ { -+ sepgsqlComputePerms(sepgsqlGetClientLabel(), -+ fcontext, -+ fclass, -+ SEPG_FILE__READ, -+ filename, true); -+ } -+ PG_CATCH(); -+ { -+ freecon(fcontext); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(fcontext); -+} -+ -+/* -+ * sepgsqlCheckBlobRelabel -+ * check db_blob:{setattr relabelfrom relabelto} -+ */ -+void -+sepgsqlCheckBlobRelabel(HeapTuple oldtup, HeapTuple newtup) -+{ -+ access_vector_t required = SEPG_DB_BLOB__SETATTR; -+ const char *audit_name; -+ -+ if (HeapTupleGetSecLabel(oldtup) != HeapTupleGetSecLabel(newtup)) -+ required |= SEPG_DB_BLOB__RELABELFROM; -+ -+ audit_name = sepgsqlAuditName(LargeObjectRelationId, oldtup); -+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(oldtup), -+ SEPG_CLASS_DB_BLOB, -+ required, -+ audit_name, true); -+ if ((required & SEPG_DB_BLOB__RELABELFROM) == 0) -+ return; -+ -+ audit_name = sepgsqlAuditName(LargeObjectRelationId, newtup); -+ sepgsqlClientHasPerms(HeapTupleGetSecLabel(newtup), -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__RELABELTO, -+ audit_name, true); -+} -+ -+/* -+ * sepgsqlCheckFileRead -+ * sepgsqlCheckFileWrite -+ * check file:{read} or file:{write} permission on the given file, -+ * and raises an error if violated. -+ */ -+static void -+checkFileCommon(int fdesc, const char *filename, access_vector_t perms) -+{ -+ security_context_t context; -+ security_class_t tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tclass = sepgsqlFileObjectClass(fdesc); -+ -+ if (fgetfilecon_raw(fdesc, &context) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not get context of %s", filename))); -+ PG_TRY(); -+ { -+ sepgsqlComputePerms(sepgsqlGetClientLabel(), -+ context, -+ tclass, -+ perms, -+ filename, true); -+ } -+ PG_CATCH(); -+ { -+ freecon(context); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(context); -+} -+ -+void -+sepgsqlCheckFileRead(int fdesc, const char *filename) -+{ -+ checkFileCommon(fdesc, filename, SEPG_FILE__READ); -+} -+ -+void -+sepgsqlCheckFileWrite(int fdesc, const char *filename) -+{ -+ checkFileCommon(fdesc, filename, SEPG_FILE__WRITE); -+} -+ -+/* -+ * sepgsqlAllowFunctionInlined -+ * It provides the optimizer a hint whether the given SQL function -+ * can be inlined, or not. If it can be configured as a trusted -+ * procedure, we should not allow it inlined. -+ */ -+bool -+sepgsqlAllowFunctionInlined(HeapTuple proc_tuple) -+{ -+ security_context_t context; -+ -+ if (!sepgsqlIsEnabled()) -+ return true; -+ -+ context = sepgsqlClientCreateLabel(HeapTupleGetSecLabel(proc_tuple), -+ SEPG_CLASS_PROCESS); -+ /* -+ * If the security context of client is unchange -+ * before or after invocation of the functions, -+ * it is not a trusted procedure, so it can be -+ * inlined due to performance purpose. -+ */ -+ if (strcmp(sepgsqlGetClientLabel(), context) == 0) -+ return true; -+ -+ return false; -+} -diff -rpNU3 base/src/backend/security/sepgsql/label.c sepgsql-new/src/backend/security/sepgsql/label.c ---- base/src/backend/security/sepgsql/label.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/sepgsql/label.c 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,339 @@ -+/* -+ * src/backend/security/sepgsql/label.c -+ * SE-PostgreSQL security label management -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#include "postgres.h" -+ -+#include "access/xact.h" -+#include "catalog/catalog.h" -+#include "catalog/indexing.h" -+#include "catalog/pg_attribute.h" -+#include "catalog/pg_class.h" -+#include "catalog/pg_database.h" -+#include "catalog/pg_largeobject.h" -+#include "catalog/pg_proc.h" -+#include "catalog/pg_security.h" -+#include "catalog/pg_type.h" -+#include "miscadmin.h" -+#include "nodes/makefuncs.h" -+#include "security/sepgsql.h" -+#include "utils/builtins.h" -+#include "utils/memutils.h" -+#include "utils/syscache.h" -+ -+/* -+ * sepgsqlTupleDescHasSecLabel -+ * controls TupleDesc->tdhasseclabel -+ */ -+bool sepostgresql_row_level; -+ -+bool -+sepgsqlTupleDescHasSecLabel(Relation rel) -+{ -+ if (!sepgsqlIsEnabled()) -+ return false; -+ -+ if (rel != NULL && -+ RelationGetForm(rel)->relkind != RELKIND_RELATION) -+ return false; -+ -+ if (rel != NULL && -+ (RelationGetRelid(rel) == DatabaseRelationId || /* db_database */ -+ RelationGetRelid(rel) == RelationRelationId || /* db_table */ -+ RelationGetRelid(rel) == AttributeRelationId || /* db_column */ -+ RelationGetRelid(rel) == ProcedureRelationId || /* db_procedure */ -+ RelationGetRelid(rel) == LargeObjectRelationId)) /* db_blob */ -+ return true; -+ -+ return sepostgresql_row_level; /* db_tuple class depends on a GUC parameter */ -+} -+ -+/* -+ * sepgsqlSetDefaultSecLabel -+ * -+ * It assigns a default security label on a tuple newly created. -+ * The default security label depends on the security policy, and -+ * its object class. -+ * The db_class and db_tuple class inherits the parent table's one, -+ * but we cannot refer system cache in very early phase, so it assumes -+ * nobody relabels the default one during initdb. -+ */ -+void -+sepgsqlSetDefaultSecLabel(Relation rel, HeapTuple tuple) -+{ -+ Form_pg_attribute attform; -+ security_context_t context; -+ security_class_t tclass; -+ sepgsql_sid_t newsid, table_sid; -+ HeapTuple reltup; -+ -+ Assert(HeapTupleHasSecLabel(tuple)); -+ tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple); -+ -+ switch (tclass) -+ { -+ case SEPG_CLASS_DB_DATABASE: -+ context = sepgsqlComputeCreate(sepgsqlGetClientLabel(), -+ sepgsqlGetClientLabel(), -+ SEPG_CLASS_DB_DATABASE); -+ newsid = securityTransSecLabelIn(context); -+ break; -+ -+ case SEPG_CLASS_DB_TABLE: -+ newsid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(), -+ SEPG_CLASS_DB_TABLE); -+ break; -+ -+ case SEPG_CLASS_DB_PROCEDURE: -+ newsid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(), -+ SEPG_CLASS_DB_PROCEDURE); -+ break; -+ case SEPG_CLASS_DB_COLUMN: -+ attform = (Form_pg_attribute) GETSTRUCT(tuple); -+ if (IsBootstrapProcessingMode() && -+ (attform->attrelid == TypeRelationId || -+ attform->attrelid == ProcedureRelationId || -+ attform->attrelid == AttributeRelationId || -+ attform->attrelid == RelationRelationId)) -+ { -+ table_sid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(), -+ SEPG_CLASS_DB_TABLE); -+ } -+ else -+ { -+ reltup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(attform->attrelid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(reltup)) -+ elog(ERROR, "SELinux: cache lookup failed fro relation: %u", -+ attform->attrelid); -+ -+ table_sid = HeapTupleGetSecLabel(reltup); -+ -+ ReleaseSysCache(reltup); -+ } -+ newsid = sepgsqlClientCreate(table_sid, SEPG_CLASS_DB_COLUMN); -+ break; -+ -+ case SEPG_CLASS_DB_BLOB: -+ /* -+ * NOTE: -+ * A object within db_blob class has a characteristic. -+ * It does not have one-to-one mapping on a object and -+ * a tuple, in other word, a large object consists of -+ * multiple tuples. In most cases, user accesses them -+ * via several certain interfaces, like loread(). -+ * So, we assume user don't touch pg_largeobject system -+ * catalog by hand, and it does not give us any degradation -+ * at interface incompatibility. -+ * -+ * Thus, all the tuples modified are come from internal -+ * interfaces, like simple_heap_insert(). The backend -+ * implementation has to set correct security context -+ * prior to insert a tuple. A security context of -+ * largeobject is cached on LargeObjectDesc->secid -+ * The only exception is inv_create(). It invoked -+ * simple_heap_insert() with no security context to -+ * assign a default one here. -+ */ -+ newsid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(), -+ SEPG_CLASS_DB_BLOB); -+ break; -+ -+ default: -+ if (IsBootstrapProcessingMode() && -+ (RelationGetRelid(rel) == TypeRelationId || -+ RelationGetRelid(rel) == ProcedureRelationId || -+ RelationGetRelid(rel) == AttributeRelationId || -+ RelationGetRelid(rel) == RelationRelationId)) -+ { -+ table_sid = sepgsqlClientCreate(sepgsqlGetDatabaseSid(), -+ SEPG_CLASS_DB_TABLE); -+ } -+ else -+ { -+ reltup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(RelationGetRelid(rel)), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(reltup)) -+ elog(ERROR, "SELinux: cache lookup failed fro relation: %u", -+ RelationGetRelid(rel)); -+ -+ table_sid = HeapTupleGetSecLabel(reltup); -+ -+ ReleaseSysCache(reltup); -+ } -+ newsid = sepgsqlClientCreate(table_sid, SEPG_CLASS_DB_TUPLE); -+ break; -+ } -+ -+ HeapTupleSetSecLabel(tuple, newsid); -+} -+ -+/* -+ * sepgsqlMetaSecurityLabel -+ * returns a security context of tuples within pg_security -+ */ -+char * -+sepgsqlMetaSecurityLabel(void) -+{ -+ security_context_t tcontext; -+ sepgsql_sid_t tsid; -+ HeapTuple tuple; -+ -+ tuple = SearchSysCache(RELOID, -+ ObjectIdGetDatum(SecurityRelationId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for relation %u", -+ SecurityRelationId); -+ -+ tsid = HeapTupleGetSecLabel(tuple); -+ -+ ReleaseSysCache(tuple); -+ -+ tcontext = securityLookupSecurityLabel(tsid); -+ if (!tcontext || !sepgsqlCheckValidSecurityLabel(tcontext)) -+ tcontext = sepgsqlGetUnlabeledLabel(); -+ -+ return sepgsqlComputeCreate(sepgsqlGetServerLabel(), -+ tcontext, -+ SEPG_CLASS_DB_TUPLE); -+} -+ -+/* -+ * sepgsqlInputGivenSecLabel -+ * translate a given security label in text form into a security -+ * identifier. It can raise an error, if its format is violated, -+ * but permission checks are done later. -+ */ -+Oid -+sepgsqlInputGivenSecLabel(DefElem *defel) -+{ -+ if (!defel) -+ return InvalidOid; -+ -+ if (!sepgsqlIsEnabled()) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: disabled now"))); -+ -+ return securityTransSecLabelIn(strVal(defel->arg)); -+} -+ -+/* -+ * sepgsqlInputGivenSecLabelRelation -+ * organize a set of given security labels on CREATE TABLE statement. -+ * User can specify a security label for individual table/columns. -+ * It returns a list of DefElem. !defel->defname means a specified one -+ * for the table, rest of them means one for columns. -+ */ -+List * -+sepgsqlInputGivenSecLabelRelation(CreateStmt *stmt) -+{ -+ List *results = NIL; -+ ListCell *l; -+ DefElem *defel, *newel; -+ -+ if (stmt->secLabel) -+ { -+ defel = (DefElem *) stmt->secLabel; -+ -+ Assert(IsA(defel, DefElem)); -+ -+ newel = makeDefElem(NULL, copyObject(defel->arg)); -+ results = lappend(results, newel); -+ } -+ -+ foreach (l, stmt->tableElts) -+ { -+ ColumnDef *cdef = lfirst(l); -+ -+ if (cdef->secLabel) -+ { -+ defel = (DefElem *) cdef->secLabel; -+ -+ Assert(IsA(defel, DefElem)); -+ -+ newel = makeDefElem(pstrdup(cdef->colname), -+ copyObject(defel->arg)); -+ results = lappend(results, newel); -+ } -+ } -+ -+ return results; -+} -+ -+/* -+ * sepgsqlSecurityLabelTransIn() -+ * translate external security label into internal one -+ */ -+security_context_t -+sepgsqlSecurityLabelTransIn(security_context_t context) -+{ -+ security_context_t raw_context, result; -+ -+ if (selinux_trans_to_raw_context(context, &raw_context) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not translate external label: %s", context))); -+ PG_TRY(); -+ { -+ result = pstrdup(raw_context); -+ } -+ PG_CATCH(); -+ { -+ freecon(raw_context); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ -+ freecon(raw_context); -+ -+ return result; -+} -+ -+/* -+ * sepgsqlSecurityLabelTransOut() -+ * translate internal security label into external one -+ */ -+security_context_t -+sepgsqlSecurityLabelTransOut(security_context_t context) -+{ -+ security_context_t trans_context, result; -+ -+ if (selinux_raw_to_trans_context(context, &trans_context) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not translate internal label: %s", context))); -+ PG_TRY(); -+ { -+ result = pstrdup(trans_context); -+ } -+ PG_CATCH(); -+ { -+ freecon(trans_context); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ -+ freecon(trans_context); -+ -+ return result; -+} -+ -+/* -+ * sepgsqlCheckValidSecurityLabel() -+ * checks whether the given security context is a valid one, or not -+ */ -+bool -+sepgsqlCheckValidSecurityLabel(security_context_t context) -+{ -+ if (security_check_context_raw(context) < 0) -+ return false; -+ -+ return true; -+} -diff -rpNU3 base/src/backend/security/sepgsql/perms.c sepgsql-new/src/backend/security/sepgsql/perms.c ---- base/src/backend/security/sepgsql/perms.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/sepgsql/perms.c 2009-03-15 17:09:41.000000000 +0900 -@@ -0,0 +1,410 @@ -+/* -+ * src/backend/utils/sepgsql/perms.c -+ * SE-PostgreSQL permission checks -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#include "postgres.h" -+ -+#include "catalog/indexing.h" -+#include "catalog/pg_database.h" -+#include "catalog/pg_proc.h" -+#include "catalog/pg_language.h" -+#include "catalog/pg_largeobject.h" -+#include "catalog/pg_type.h" -+#include "miscadmin.h" -+#include "security/sepgsql.h" -+#include "utils/builtins.h" -+#include "utils/lsyscache.h" -+#include "utils/syscache.h" -+#include -+ -+/* -+ * Dynamic object class/permissions mapping -+ * -+ * SELinux exports the list of object classes and permissions at -+ * /selinux/class. The libselinux provides an interface to translate -+ * between their names and codes. -+ */ -+static struct -+{ -+ const char *class_name; -+ security_class_t class_code; -+ struct -+ { -+ const char *perm_name; -+ access_vector_t perm_code; -+ } av[sizeof(access_vector_t) * 8]; -+} selinux_catalog[] = { -+ { -+ "process", SEPG_CLASS_PROCESS, -+ { -+ {"translation", SEPG_PROCESS__TRANSITION }, -+ {NULL, 0} -+ } -+ }, -+ { -+ "file", SEPG_CLASS_FILE, -+ { -+ {"read", SEPG_FILE__READ }, -+ {"write", SEPG_FILE__WRITE }, -+ {NULL, 0} -+ } -+ }, -+ { -+ "dir", SEPG_CLASS_DIR, -+ { -+ {"read", SEPG_DIR__READ }, -+ {"write", SEPG_DIR__WRITE }, -+ {NULL,0} -+ } -+ }, -+ { -+ "lnk_file", SEPG_CLASS_LNK_FILE, -+ { -+ {"read", SEPG_LNK_FILE__READ }, -+ {"write", SEPG_LNK_FILE__WRITE }, -+ {NULL,0} -+ } -+ }, -+ { -+ "chr_file", SEPG_CLASS_CHR_FILE, -+ { -+ {"read", SEPG_CHR_FILE__READ }, -+ {"write", SEPG_CHR_FILE__WRITE }, -+ {NULL,0} -+ } -+ }, -+ { -+ "blk_file", SEPG_CLASS_BLK_FILE, -+ { -+ {"read", SEPG_BLK_FILE__READ }, -+ {"write", SEPG_BLK_FILE__WRITE }, -+ {NULL,0} -+ } -+ }, -+ { -+ "sock_file", SEPG_CLASS_SOCK_FILE, -+ { -+ {"read", SEPG_SOCK_FILE__READ }, -+ {"write", SEPG_SOCK_FILE__WRITE }, -+ {NULL,0} -+ } -+ }, -+ { -+ "fifo_file", SEPG_CLASS_FIFO_FILE, -+ { -+ {"read", SEPG_FIFO_FILE__READ }, -+ {"write", SEPG_FIFO_FILE__WRITE }, -+ {NULL, 0UL } -+ } -+ }, -+ { -+ "db_database", SEPG_CLASS_DB_DATABASE, -+ { -+ { "create", SEPG_DB_DATABASE__CREATE }, -+ { "drop", SEPG_DB_DATABASE__DROP }, -+ { "getattr", SEPG_DB_DATABASE__GETATTR }, -+ { "setattr", SEPG_DB_DATABASE__SETATTR }, -+ { "relabelfrom", SEPG_DB_DATABASE__RELABELFROM }, -+ { "relabelto", SEPG_DB_DATABASE__RELABELTO }, -+ { "access", SEPG_DB_DATABASE__ACCESS }, -+ { "install_module", SEPG_DB_DATABASE__INSTALL_MODULE }, -+ { "load_module", SEPG_DB_DATABASE__LOAD_MODULE }, -+ { "superuser", SEPG_DB_DATABASE__SUPERUSER }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_table", SEPG_CLASS_DB_TABLE, -+ { -+ { "create", SEPG_DB_TABLE__CREATE }, -+ { "drop", SEPG_DB_TABLE__DROP }, -+ { "getattr", SEPG_DB_TABLE__GETATTR }, -+ { "setattr", SEPG_DB_TABLE__SETATTR }, -+ { "relabelfrom", SEPG_DB_TABLE__RELABELFROM }, -+ { "relabelto", SEPG_DB_TABLE__RELABELTO }, -+ { "select", SEPG_DB_TABLE__SELECT }, -+ { "update", SEPG_DB_TABLE__UPDATE }, -+ { "insert", SEPG_DB_TABLE__INSERT }, -+ { "delete", SEPG_DB_TABLE__DELETE }, -+ { "lock", SEPG_DB_TABLE__LOCK }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_procedure", SEPG_CLASS_DB_PROCEDURE, -+ { -+ { "create", SEPG_DB_PROCEDURE__CREATE }, -+ { "drop", SEPG_DB_PROCEDURE__DROP }, -+ { "getattr", SEPG_DB_PROCEDURE__GETATTR }, -+ { "setattr", SEPG_DB_PROCEDURE__SETATTR }, -+ { "relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM }, -+ { "relabelto", SEPG_DB_PROCEDURE__RELABELTO }, -+ { "execute", SEPG_DB_PROCEDURE__EXECUTE }, -+ { "entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT }, -+ { "install", SEPG_DB_PROCEDURE__INSTALL }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_column", SEPG_CLASS_DB_COLUMN, -+ { -+ { "create", SEPG_DB_COLUMN__CREATE }, -+ { "drop", SEPG_DB_COLUMN__DROP }, -+ { "getattr", SEPG_DB_COLUMN__GETATTR }, -+ { "setattr", SEPG_DB_COLUMN__SETATTR }, -+ { "relabelfrom", SEPG_DB_COLUMN__RELABELFROM }, -+ { "relabelto", SEPG_DB_COLUMN__RELABELTO }, -+ { "select", SEPG_DB_COLUMN__SELECT }, -+ { "update", SEPG_DB_COLUMN__UPDATE }, -+ { "insert", SEPG_DB_COLUMN__INSERT }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_tuple", SEPG_CLASS_DB_TUPLE, -+ { -+ { "relabelfrom", SEPG_DB_TUPLE__RELABELFROM }, -+ { "relabelto", SEPG_DB_TUPLE__RELABELTO }, -+ { "select", SEPG_DB_TUPLE__SELECT }, -+ { "update", SEPG_DB_TUPLE__UPDATE }, -+ { "insert", SEPG_DB_TUPLE__INSERT }, -+ { "delete", SEPG_DB_TUPLE__DELETE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_blob", SEPG_CLASS_DB_BLOB, -+ { -+ { "create", SEPG_DB_BLOB__CREATE }, -+ { "drop", SEPG_DB_BLOB__DROP }, -+ { "getattr", SEPG_DB_BLOB__GETATTR }, -+ { "setattr", SEPG_DB_BLOB__SETATTR }, -+ { "relabelfrom", SEPG_DB_BLOB__RELABELFROM }, -+ { "relabelto", SEPG_DB_BLOB__RELABELTO }, -+ { "read", SEPG_DB_BLOB__READ }, -+ { "write", SEPG_DB_BLOB__WRITE }, -+ { "import", SEPG_DB_BLOB__IMPORT }, -+ { "export", SEPG_DB_BLOB__EXPORT }, -+ { NULL, 0UL }, -+ } -+ } -+}; -+ -+/* -+ * sepgsqlTransToExternalClass -+ * It translate the given class code (defined as SEPGCLASS_(class)) into -+ * external code which is necessary to communicate in-kernel SELinux -+ */ -+extern security_class_t -+sepgsqlTransToExternalClass(security_class_t tclass) -+{ -+ security_class_t tclass_ex; -+ -+ Assert(tclass < SEPG_CLASS_MAX); -+ -+ tclass_ex = string_to_security_class(selinux_catalog[tclass].class_name); -+ if (!tclass_ex) -+ ereport(FATAL, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: \"%s\" class is not defined in the policy", -+ selinux_catalog[tclass].class_name))); -+ return tclass_ex; -+} -+ -+/* -+ * sepgsqlTransToInternalPerms -+ * It translate the given permission masks into internal representation -+ * defined as SEPG_(class)_(permission). -+ */ -+extern void -+sepgsqlTransToInternalPerms(security_class_t tclass, struct av_decision *avd) -+{ -+ security_class_t tclass_ex; -+ struct av_decision i_avd; -+ int i; -+ -+ Assert(tclass < SEPG_CLASS_MAX); -+ -+ memset(&i_avd, 0, sizeof(struct av_decision)); -+ -+ tclass_ex = sepgsqlTransToExternalClass(tclass); -+ for (i=0; selinux_catalog[tclass].av[i].perm_name; i++) -+ { -+ const char *perm_name = selinux_catalog[tclass].av[i].perm_name; -+ access_vector_t perm_code = selinux_catalog[tclass].av[i].perm_code; -+ access_vector_t perm_code_ex; -+ -+ perm_code_ex = string_to_av_perm(tclass_ex, perm_name); -+ if (!perm_code_ex) -+ { -+ /* permission is undefined */ -+ i_avd.allowed |= perm_code; -+ continue; -+ } -+ -+ if (avd->allowed & perm_code_ex) -+ i_avd.allowed |= perm_code; -+ if (avd->decided & perm_code_ex) -+ i_avd.decided |= perm_code; -+ if (avd->auditallow & perm_code_ex) -+ i_avd.auditallow |= perm_code; -+ if (avd->auditdeny & perm_code_ex) -+ i_avd.auditdeny |= perm_code; -+ } -+ -+ avd->allowed = i_avd.allowed; -+ avd->decided = i_avd.decided; -+ avd->auditallow = i_avd.auditallow; -+ avd->auditdeny = i_avd.auditdeny; -+} -+ -+/* -+ * sepgsqlGetClassString -+ * sepgsqlGetPermissionString -+ * It returns text representation of object classes/permissions -+ */ -+const char * -+sepgsqlGetClassString(security_class_t tclass) -+{ -+ Assert(tclass < SEPG_CLASS_MAX); -+ -+ return selinux_catalog[tclass].class_name; -+} -+ -+const char * -+sepgsqlGetPermissionString(security_class_t tclass, access_vector_t av) -+{ -+ int i; -+ -+ Assert(tclass < SEPG_CLASS_MAX); -+ -+ for (i=0; selinux_catalog[tclass].av[i].perm_name; i++) -+ { -+ if (selinux_catalog[tclass].av[i].perm_code == av) -+ return selinux_catalog[tclass].av[i].perm_name; -+ } -+ return NULL; -+} -+ -+/* -+ * sepgsqlAuditName -+ * 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 * -+sepgsqlAuditName(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); -+ } -+ return NULL; -+} -+ -+/* -+ * sepgsqlFileObjectClass -+ * -+ * It returns proper object class of filesystem object already opened. -+ * It is necessary to check privileges voluntarily. -+ */ -+security_class_t -+sepgsqlFileObjectClass(int fdesc) -+{ -+ struct stat stbuf; -+ -+ if (fstat(fdesc, &stbuf) != 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not stat file descriptor: %d", fdesc))); -+ -+ if (S_ISDIR(stbuf.st_mode)) -+ return SEPG_CLASS_DIR; -+ else if (S_ISCHR(stbuf.st_mode)) -+ return SEPG_CLASS_CHR_FILE; -+ else if (S_ISBLK(stbuf.st_mode)) -+ return SEPG_CLASS_BLK_FILE; -+ else if (S_ISFIFO(stbuf.st_mode)) -+ return SEPG_CLASS_FIFO_FILE; -+ else if (S_ISLNK(stbuf.st_mode)) -+ return SEPG_CLASS_LNK_FILE; -+ else if (S_ISSOCK(stbuf.st_mode)) -+ return SEPG_CLASS_SOCK_FILE; -+ -+ return SEPG_CLASS_FILE; -+} -+ -+/* -+ * sepgsqlTupleObjectClass -+ * -+ * It returns correct 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 SEPG_CLASS_DB_DATABASE; -+ -+ case RelationRelationId: -+ clsForm = (Form_pg_class) GETSTRUCT(tuple); -+ if (clsForm->relkind == RELKIND_RELATION) -+ return SEPG_CLASS_DB_TABLE; -+ break; -+ -+ case AttributeRelationId: -+ attForm = (Form_pg_attribute) GETSTRUCT(tuple); -+ if (IsBootstrapProcessingMode() && -+ (attForm->attrelid == TypeRelationId || -+ attForm->attrelid == ProcedureRelationId || -+ attForm->attrelid == AttributeRelationId || -+ attForm->attrelid == RelationRelationId)) -+ return SEPG_CLASS_DB_COLUMN; -+ -+ if (get_rel_relkind(attForm->attrelid) == RELKIND_RELATION) -+ return SEPG_CLASS_DB_COLUMN; -+ break; -+ -+ case ProcedureRelationId: -+ return SEPG_CLASS_DB_PROCEDURE; -+ -+ case LargeObjectRelationId: -+ return SEPG_CLASS_DB_BLOB; -+ } -+ return SEPG_CLASS_DB_TUPLE; -+} -diff -rpNU3 base/src/backend/security/sepgsql/policy/Makefile sepgsql-new/src/backend/security/sepgsql/policy/Makefile ---- base/src/backend/security/sepgsql/policy/Makefile 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/sepgsql/policy/Makefile 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,28 @@ -+# -+# Makefile for SE-PostgreSQL security policy module -+# -+top_builddir = ../../../../.. -+include $(top_builddir)/src/Makefile.global -+ -+POLICY_BASEDIR := $(DESTDIR)/usr/share/selinux -+POLICY_MAKEFILE := $(POLICY_BASEDIR)/devel/Makefile -+POLICY_TYPES := targeted mls -+POLICY_TARGET := $(strip $(shell $(AWK) -F= '/^SELINUXTYPE/{ print $$2 }' /etc/selinux/config)) -+PREFIX_RULE := "s/%%__prefix__%%/$(shell echo $(prefix)|sed 's/\//\\\//g')/g" -+BINDIR_RULE := "s/%%__bindir__%%/$(shell echo $(bindir)|sed 's/\//\\\//g')/g" -+LIBDIR_RULE := "s/%%__libdir__%%/$(shell echo $(pkglibdir)|sed 's/\//\\\//g')/g" -+ -+all: $(addprefix sepostgresql-devel.pp., $(POLICY_TYPES)) -+ ln -sf sepostgresql-devel.pp.$(POLICY_TARGET) sepostgresql-devel.pp -+ -+sepostgresql-devel.pp.%: sepostgresql-devel.te sepostgresql-devel.fc -+ $(MAKE) NAME=$(POLICY_TARGET) -f $(POLICY_MAKEFILE) clean -+ $(MAKE) NAME=$(POLICY_TARGET) -f $(POLICY_MAKEFILE) -+ mv $(basename $@) $@ -+ -+sepostgresql-devel.fc: sepostgresql-devel.fc.template -+ cat $< | sed -e $(PREFIX_RULE) -e $(BINDIR_RULE) -e $(LIBDIR_RULE) > $@ -+ -+clean: -+ $(MAKE) -f $(POLICY_MAKEFILE) clean -+ rm -f *.pp *.pp.* *.if *.fc -diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template sepgsql-new/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template ---- base/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,12 @@ -+# -+# 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) -+ -diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgsql-new/src/backend/security/sepgsql/policy/sepostgresql-devel.te ---- base/src/backend/security/sepgsql/policy/sepostgresql-devel.te 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/backend/security/sepgsql/policy/sepostgresql-devel.te 2009-03-28 11:17:32.000000000 +0900 -@@ -0,0 +1,128 @@ -+policy_module(sepostgresql-devel, 3.27) -+ -+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_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; -+ -+ # for regression test -+ type bin_t; -+ type user_home_t; -+ type sepgsql_trusted_proc_t; -+ -+ attribute tmpfile; -+ attribute ptynode; -+') -+ -+################################# -+# -+# Domain for Testcases -+# -+ -+role sepgsql_test_r; -+ -+userdom_unpriv_user_template(sepgsql_test) -+ -+ifdef(`postgresql_role', ` -+ postgresql_role(sepgsql_test_r, sepgsql_test_t) -+',` -+ postgresql_userdom_template(sepgsql_test, sepgsql_test_t, sepgsql_test_r) -+') -+ -+# workaround for sepgsql tests -+allow sepgsql_test_t user_sepgsql_blob_t : db_blob { import export }; -+dontaudit sepgsql_test_t sepgsql_blob_type : db_blob *; -+ -+allow sepgsql_test_t tmpfile : dir search_dir_perms; -+allow sepgsql_test_t tmpfile : file rw_file_perms; -+allow sepgsql_test_t ptynode : chr_file rw_file_perms; -+ -+optional_policy(` -+ gen_require(` -+ type unconfined_t; -+ role unconfined_r; -+ ') -+ -+ tunable_policy(`sepgsql_regression_test_mode',` -+ allow unconfined_t sepgsql_test_t : process transition; -+ ') -+ allow sepgsql_test_t unconfined_t : fifo_file read_file_perms; -+ role unconfined_r types sepgsql_test_t; -+ role unconfined_r types sepgsql_trusted_proc_t; -+') -+ -+################################# -+# -+# SE-PostgreSQL Declarations -+# -+ -+## -+##

-+## Allow to generate auditallow logs -+##

-+##
-+gen_tunable(sepgsql_enable_auditallow, false) -+ -+## -+##

-+## Allow to generate auditdeny logs -+##

-+##
-+gen_tunable(sepgsql_enable_auditdeny, true) -+ -+## -+##

-+## Allow widespread permissions for regression test -+## Don't set TRUE on operation phase -+##

-+##
-+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_table_type : db_tuple { relabelfrom relabelto }; -+ 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_table_type : db_tuple { relabelfrom relabelto }; -+ 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 user_home_t : db_database { install_module }; -+ allow sepgsql_unconfined_type user_home_t : db_database { install_module }; -+ allow sepgsql_database_type user_home_t : db_database { load_module }; -+') -diff -rpNU3 base/src/backend/storage/file/fd.c sepgsql-new/src/backend/storage/file/fd.c ---- base/src/backend/storage/file/fd.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/storage/file/fd.c 2009-03-13 18:14:33.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-new/src/backend/storage/ipc/ipci.c ---- base/src/backend/storage/ipc/ipci.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/storage/ipc/ipci.c 2009-03-13 18:14:33.000000000 +0900 -@@ -25,6 +25,7 @@ - #include "postmaster/autovacuum.h" - #include "postmaster/bgwriter.h" - #include "postmaster/postmaster.h" -+#include "security/sepgsql.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, sepgsqlShmemSize()); - - /* freeze the addin request size and include it */ - addin_request_allowed = false; -diff -rpNU3 base/src/backend/storage/large_object/inv_api.c sepgsql-new/src/backend/storage/large_object/inv_api.c ---- base/src/backend/storage/large_object/inv_api.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql-new/src/backend/storage/large_object/inv_api.c 2009-03-13 18:14:33.000000000 +0900 -@@ -39,6 +39,7 @@ - #include "catalog/pg_largeobject.h" - #include "commands/comment.h" - #include "libpq/libpq-fs.h" -+#include "security/sepgsql.h" - #include "storage/large_object.h" - #include "utils/fmgroids.h" - #include "utils/resowner.h" -@@ -134,12 +135,13 @@ close_lo_relation(bool isCommit) - * read with can be specified. - */ - static bool --myLargeObjectExists(Oid loid, Snapshot snapshot) -+myLargeObjectExists(LargeObjectDesc *lobj) - { - bool retval = false; - Relation pg_largeobject; - ScanKeyData skey[1]; - SysScanDesc sd; -+ HeapTuple tuple; - - /* - * See if we can find any tuples belonging to the specified LO -@@ -147,15 +149,19 @@ myLargeObjectExists(Oid loid, Snapshot s - ScanKeyInit(&skey[0], - Anum_pg_largeobject_loid, - BTEqualStrategyNumber, F_OIDEQ, -- ObjectIdGetDatum(loid)); -+ ObjectIdGetDatum(lobj->id)); - - pg_largeobject = heap_open(LargeObjectRelationId, AccessShareLock); - - sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndexId, true, -- snapshot, 1, skey); -+ lobj->snapshot, 1, skey); - -- if (systable_getnext(sd) != NULL) -+ tuple = systable_getnext(sd); -+ if (HeapTupleIsValid(tuple)) -+ { - retval = true; -+ lobj->secid = HeapTupleGetSecLabel(tuple); -+ } - - systable_endscan(sd); - -@@ -254,7 +260,7 @@ inv_open(Oid lobjId, int flags, MemoryCo - elog(ERROR, "invalid flags: %d", flags); - - /* Can't use LargeObjectExists here because it always uses SnapshotNow */ -- if (!myLargeObjectExists(lobjId, retval->snapshot)) -+ if (!myLargeObjectExists(retval)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("large object %u does not exist", lobjId))); -@@ -676,6 +682,8 @@ inv_write(LargeObjectDesc *obj_desc, con - values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno); - values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf); - newtup = heap_formtuple(lo_heap_r->rd_att, values, nulls); -+ if (HeapTupleHasSecLabel(newtup)) -+ HeapTupleSetSecLabel(newtup, obj_desc->secid); - simple_heap_insert(lo_heap_r, newtup); - CatalogIndexInsert(indstate, newtup); - heap_freetuple(newtup); -@@ -836,6 +844,8 @@ inv_truncate(LargeObjectDesc *obj_desc, - values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno); - values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf); - newtup = heap_formtuple(lo_heap_r->rd_att, values, nulls); -+ if (HeapTupleHasSecLabel(newtup)) -+ HeapTupleSetSecLabel(newtup, obj_desc->secid); - simple_heap_insert(lo_heap_r, newtup); - CatalogIndexInsert(indstate, newtup); - heap_freetuple(newtup); -@@ -859,3 +869,99 @@ inv_truncate(LargeObjectDesc *obj_desc, - */ - CommandCounterIncrement(); - } -+ -+Oid -+inv_get_security(Oid loid) -+{ -+ Relation rel; -+ ScanKeyData skey; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ Oid secid = InvalidOid; -+ -+ ScanKeyInit(&skey, -+ Anum_pg_largeobject_loid, -+ BTEqualStrategyNumber, -+ F_OIDEQ, ObjectIdGetDatum(loid)); -+ -+ rel = heap_open(LargeObjectRelationId, AccessShareLock); -+ -+ scan = systable_beginscan(rel, LargeObjectLOidPNIndexId, true, -+ SnapshotNow, 1, &skey); -+ tuple = systable_getnext(scan); -+ -+ if (HeapTupleIsValid(tuple)) -+ { -+ /* -+ * SELinux: check db_blob:{getattr} -+ */ -+ sepgsqlCheckBlobGetattr(tuple); -+ secid = HeapTupleGetSecLabel(tuple); -+ } -+ systable_endscan(scan); -+ -+ heap_close(rel, AccessShareLock); -+ -+ return secid; -+} -+ -+void -+inv_set_security(Oid loid, Oid secid) -+{ -+ Relation rel; -+ ScanKeyData skey; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ CatalogIndexState ind; -+ bool found = false; -+ -+ ScanKeyInit(&skey, -+ Anum_pg_largeobject_loid, -+ BTEqualStrategyNumber, -+ F_OIDEQ, ObjectIdGetDatum(loid)); -+ -+ rel = heap_open(LargeObjectRelationId, RowExclusiveLock); -+ -+ ind = CatalogOpenIndexes(rel); -+ -+ scan = systable_beginscan(rel, LargeObjectLOidPNIndexId, true, -+ SnapshotNow, 1, &skey); -+ while (HeapTupleIsValid(tuple = systable_getnext(scan))) -+ { -+ HeapTuple newtuple; -+ Datum values[Natts_pg_largeobject]; -+ bool nulls[Natts_pg_largeobject]; -+ bool replaces[Natts_pg_largeobject]; -+ -+ memset(replaces, false, sizeof(replaces)); -+ -+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), -+ values, nulls, replaces); -+ if (!HeapTupleHasSecLabel(newtuple)) -+ elog(ERROR, "Unable to assign security label on \"%s\"", -+ RelationGetRelationName(rel)); -+ HeapTupleSetSecLabel(newtuple, secid); -+ -+ /* -+ * SELinux: check db_blob:{setattr relabelfrom relabelto} -+ */ -+ if (!found) -+ sepgsqlCheckBlobRelabel(tuple, newtuple); -+ -+ simple_heap_update(rel, &tuple->t_self, newtuple); -+ CatalogUpdateIndexes(rel, newtuple); -+ found = true; -+ } -+ systable_endscan(scan); -+ -+ CatalogCloseIndexes(ind); -+ -+ heap_close(rel, RowExclusiveLock); -+ -+ CommandCounterIncrement(); -+ -+ if (!found) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_OBJECT), -+ errmsg("large object %u does not exist", loid))); -+} -diff -rpNU3 base/src/backend/tcop/pquery.c sepgsql-new/src/backend/tcop/pquery.c ---- base/src/backend/tcop/pquery.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/tcop/pquery.c 2009-03-13 18:14:33.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-new/src/backend/tcop/utility.c ---- base/src/backend/tcop/utility.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql-new/src/backend/tcop/utility.c 2009-03-13 18:14:33.000000000 +0900 -@@ -49,6 +49,7 @@ - #include "postmaster/bgwriter.h" - #include "rewrite/rewriteDefine.h" - #include "rewrite/rewriteRemove.h" -+#include "security/sepgsql.h" - #include "storage/fd.h" - #include "tcop/pquery.h" - #include "tcop/utility.h" -@@ -1022,6 +1023,10 @@ ProcessUtility(Node *parsetree, - LoadStmt *stmt = (LoadStmt *) parsetree; - - closeAllVfds(); /* probably not necessary... */ -+ -+ /* SELinux checks db_database:{install_module} priv */ -+ sepgsqlCheckDatabaseInstallModule(stmt->filename); -+ - /* Allowed names are restricted if you're not superuser */ - load_file(stmt->filename, !superuser()); - } -diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql-new/src/backend/utils/adt/ri_triggers.c ---- base/src/backend/utils/adt/ri_triggers.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql-new/src/backend/utils/adt/ri_triggers.c 2009-03-13 18:14:33.000000000 +0900 -@@ -37,6 +37,7 @@ - #include "parser/parse_coerce.h" - #include "parser/parse_relation.h" - #include "miscadmin.h" -+#include "security/rowlevel.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_rowlv_bahavior; - Datum vals[RI_MAX_NUMKEYS * 2]; - char nulls[RI_MAX_NUMKEYS * 2]; - -@@ -3336,11 +3338,29 @@ 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); -+ /* -+ * Switch internal state of row-level security features -+ * -+ * NOTE: when a user tries to update/delete a PK which -+ * is refered by invisible FKs, it need to be aborted -+ * due to the referencial integrity. -+ */ -+ save_rowlv_bahavior = rowlvBehaviorSwitchTo(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(); -+ { -+ rowlvBehaviorSwitchTo(save_rowlv_bahavior); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); - - /* Restore UID */ - SetUserIdAndContext(save_userid, save_secdefcxt); -diff -rpNU3 base/src/backend/utils/adt/varlena.c sepgsql-new/src/backend/utils/adt/varlena.c ---- base/src/backend/utils/adt/varlena.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql-new/src/backend/utils/adt/varlena.c 2009-03-13 13:09:47.000000000 +0900 -@@ -70,6 +70,103 @@ static text *text_substring(Datum str, - - static void appendStringInfoText(StringInfo str, const text *t); - -+/***************************************************************************** -+ * CONVERSION ROUTINES EXPORTED FOR USE BY C CODE * -+ *****************************************************************************/ -+ -+/* -+ * cstring_to_text -+ * -+ * Create a text value from a null-terminated C string. -+ * -+ * The new text value is freshly palloc'd with a full-size VARHDR. -+ */ -+text * -+cstring_to_text(const char *s) -+{ -+ return cstring_to_text_with_len(s, strlen(s)); -+} -+ -+/* -+ * cstring_to_text_with_len -+ * -+ * Same as cstring_to_text except the caller specifies the string length; -+ * the string need not be null_terminated. -+ */ -+text * -+cstring_to_text_with_len(const char *s, int len) -+{ -+ text *result = (text *) palloc(len + VARHDRSZ); -+ -+ SET_VARSIZE(result, len + VARHDRSZ); -+ memcpy(VARDATA(result), s, len); -+ -+ return result; -+} -+ -+/* -+ * text_to_cstring -+ * -+ * Create a palloc'd, null-terminated C string from a text value. -+ * -+ * We support being passed a compressed or toasted text value. -+ * This is a bit bogus since such values shouldn't really be referred to as -+ * "text *", but it seems useful for robustness. If we didn't handle that -+ * case here, we'd need another routine that did, anyway. -+ */ -+char * -+text_to_cstring(const text *t) -+{ -+ /* must cast away the const, unfortunately */ -+ text *tunpacked = pg_detoast_datum_packed((struct varlena *) t); -+ int len = VARSIZE_ANY_EXHDR(tunpacked); -+ char *result; -+ -+ result = (char *) palloc(len + 1); -+ memcpy(result, VARDATA_ANY(tunpacked), len); -+ result[len] = '\0'; -+ -+ if (tunpacked != t) -+ pfree(tunpacked); -+ -+ return result; -+} -+ -+/* -+ * text_to_cstring_buffer -+ * -+ * Copy a text value into a caller-supplied buffer of size dst_len. -+ * -+ * The text string is truncated if necessary to fit. The result is -+ * guaranteed null-terminated (unless dst_len == 0). -+ * -+ * We support being passed a compressed or toasted text value. -+ * This is a bit bogus since such values shouldn't really be referred to as -+ * "text *", but it seems useful for robustness. If we didn't handle that -+ * case here, we'd need another routine that did, anyway. -+ */ -+void -+text_to_cstring_buffer(const text *src, char *dst, size_t dst_len) -+{ -+ /* must cast away the const, unfortunately */ -+ text *srcunpacked = pg_detoast_datum_packed((struct varlena *) src); -+ size_t src_len = VARSIZE_ANY_EXHDR(srcunpacked); -+ -+ if (dst_len > 0) -+ { -+ dst_len--; -+ if (dst_len >= src_len) -+ dst_len = src_len; -+ else /* ensure truncation is encoding-safe */ -+ dst_len = pg_mbcliplen(VARDATA_ANY(srcunpacked), src_len, dst_len); -+ memcpy(dst, VARDATA_ANY(srcunpacked), dst_len); -+ dst[dst_len] = '\0'; -+ } -+ -+ if (srcunpacked != src) -+ pfree(srcunpacked); -+} -+ - - /***************************************************************************** - * USER I/O ROUTINES * -diff -rpNU3 base/src/backend/utils/cache/catcache.c sepgsql-new/src/backend/utils/cache/catcache.c ---- base/src/backend/utils/cache/catcache.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql-new/src/backend/utils/cache/catcache.c 2009-03-13 18:14:33.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-new/src/backend/utils/cache/plancache.c ---- base/src/backend/utils/cache/plancache.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/backend/utils/cache/plancache.c 2009-03-13 18:14:33.000000000 +0900 -@@ -880,12 +880,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; -@@ -896,13 +898,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-new/src/backend/utils/cache/relcache.c ---- base/src/backend/utils/cache/relcache.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/backend/utils/cache/relcache.c 2009-03-13 18:14:33.000000000 +0900 -@@ -46,6 +46,7 @@ - #include "catalog/pg_opclass.h" - #include "catalog/pg_proc.h" - #include "catalog/pg_rewrite.h" -+#include "catalog/pg_security.h" - #include "catalog/pg_type.h" - #include "commands/trigger.h" - #include "miscadmin.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->tdhasrowacl and tdhasseclabel -+ * have to 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 -+ = securityTupleDescHasSecLabel(relation); -+ - /* - * 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->tdhasrowacl and tdhasseclabel -+ */ -+ RelationGetDescr(relation)->tdhasseclabel -+ = securityTupleDescHasSecLabel(relation); -+ -+ /* - * 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->tdhasrowacl and tdhasseclabel -+ * don't give us any effect. -+ * We omit to invoke securityTupleDescHasSecLabel() 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->tdhassecurity -+ */ -+ rel->rd_att->tdhasseclabel -+ = securityTupleDescHasSecLabel(rel); -+ - /* mark not-null status */ - if (has_not_null) - { -diff -rpNU3 base/src/backend/utils/cache/syscache.c sepgsql-new/src/backend/utils/cache/syscache.c ---- base/src/backend/utils/cache/syscache.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/utils/cache/syscache.c 2009-03-13 18:14:33.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" -@@ -533,6 +534,30 @@ static const struct cachedesc cacheinfo[ - }, - 1024 - }, -+ {SecurityRelationId, /* SECURITYLABEL */ -+ SecuritySeclabelIndexId, -+ 0, -+ 1, -+ { -+ Anum_pg_security_seclabel, -+ 0, -+ 0, -+ 0 -+ }, -+ 128 -+ }, -+ {SecurityRelationId, /*SECURITYOID */ -+ SecurityOidIndexId, -+ 0, -+ 1, -+ { -+ ObjectIdAttributeNumber, -+ 0, -+ 0, -+ 0 -+ }, -+ 128 -+ }, - {StatisticRelationId, /* STATRELATT */ - StatisticRelidAttnumIndexId, - Anum_pg_statistic_starelid, -@@ -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-new/src/backend/utils/fmgr/dfmgr.c ---- base/src/backend/utils/fmgr/dfmgr.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/backend/utils/fmgr/dfmgr.c 2009-03-13 18:14:33.000000000 +0900 -@@ -22,6 +22,7 @@ - #include "port/dynloader/win32.h" - #endif - #include "miscadmin.h" -+#include "security/sepgsql.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); - -+ /* SELinux checks db_database:{load_module} permission */ -+ sepgsqlCheckDatabaseLoadModule(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); - -+ /* SELinux checks db_database:{load_module} */ -+ sepgsqlCheckDatabaseLoadModule(fullname); -+ - /* Unload the library if currently loaded */ - internal_unload_library(fullname); - -@@ -395,7 +401,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/fmgr/fmgr.c sepgsql-new/src/backend/utils/fmgr/fmgr.c ---- base/src/backend/utils/fmgr/fmgr.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/backend/utils/fmgr/fmgr.c 2009-03-13 18:14:33.000000000 +0900 -@@ -23,6 +23,7 @@ - #include "executor/spi.h" - #include "miscadmin.h" - #include "parser/parse_expr.h" -+#include "security/sepgsql.h" - #include "utils/builtins.h" - #include "utils/fmgrtab.h" - #include "utils/guc.h" -@@ -227,6 +228,12 @@ fmgr_info_cxt_security(Oid functionId, F - finfo->fn_addr = fmgr_security_definer; - finfo->fn_oid = functionId; - ReleaseSysCache(procedureTuple); -+ /* -+ * NOTE: It is not necessary to set up Trusted Procedure -+ * here, because fmgr_security_definer() invokes this -+ * function with ignore_security=true again. It is set up -+ * later. -+ */ - return; - } - -@@ -274,6 +281,7 @@ fmgr_info_cxt_security(Oid functionId, F - } - - finfo->fn_oid = functionId; -+ sepgsqlCheckProcedureEntrypoint(finfo, procedureTuple); - ReleaseSysCache(procedureTuple); - } - -diff -rpNU3 base/src/backend/utils/init/postinit.c sepgsql-new/src/backend/utils/init/postinit.c ---- base/src/backend/utils/init/postinit.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql-new/src/backend/utils/init/postinit.c 2009-03-13 18:14:33.000000000 +0900 -@@ -31,6 +31,7 @@ - #include "pgstat.h" - #include "postmaster/autovacuum.h" - #include "postmaster/postmaster.h" -+#include "security/sepgsql.h" - #include "storage/backendid.h" - #include "storage/fd.h" - #include "storage/ipc.h" -@@ -194,12 +195,9 @@ CheckMyDatabase(const char *name, bool a - name))); - - /* -- * Check privilege to connect to the database. (The am_superuser test -- * is redundant, but since we have the flag, might as well check it -- * and save a few cycles.) -+ * Check privilege to connect to the database. - */ -- if (!am_superuser && -- pg_database_aclcheck(MyDatabaseId, GetUserId(), -+ if (pg_database_aclcheck(MyDatabaseId, GetUserId(), - ACL_CONNECT) != ACLCHECK_OK) - ereport(FATAL, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -@@ -541,6 +539,9 @@ InitPostgres(const char *in_dbname, Oid - */ - RelationCacheInitializePhase2(); - -+ /* initialize SE-PostgreSQL feature */ -+ sepgsqlInitialize(); -+ - /* - * Figure out our postgres user id, and see if we are a superuser. - * -diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql-new/src/backend/utils/misc/guc.c ---- base/src/backend/utils/misc/guc.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql-new/src/backend/utils/misc/guc.c 2009-03-13 18:14:33.000000000 +0900 -@@ -54,6 +54,7 @@ - #include "postmaster/postmaster.h" - #include "postmaster/syslogger.h" - #include "postmaster/walwriter.h" -+#include "security/sepgsql.h" - #include "storage/fd.h" - #include "storage/freespace.h" - #include "tcop/tcopprot.h" -@@ -1091,6 +1092,24 @@ static struct config_bool ConfigureNames - &IgnoreSystemIndexes, - false, NULL, NULL - }, -+#ifdef HAVE_SELINUX -+ { -+ {"sepostgresql", PGC_POSTMASTER, CONN_AUTH_SECURITY, -+ gettext_noop("SE-PostgreSQL activation option to be turned on/off"), -+ NULL, -+ }, -+ &sepostgresql_is_enabled, -+ false, NULL, NULL -+ }, -+ { -+ {"sepostgresql_row_level", PGC_POSTMASTER, CONN_AUTH_SECURITY, -+ gettext_noop("Row-level access controls on SE-PostgreSQL"), -+ NULL, -+ }, -+ &sepostgresql_row_level, -+ true, NULL, NULL -+ }, -+#endif - - /* End-of-list marker */ - { -diff -rpNU3 base/src/backend/utils/misc/postgresql.conf.sample sepgsql-new/src/backend/utils/misc/postgresql.conf.sample ---- base/src/backend/utils/misc/postgresql.conf.sample 2008-02-03 01:11:28.000000000 +0900 -+++ sepgsql-new/src/backend/utils/misc/postgresql.conf.sample 2009-03-13 18:14:33.000000000 +0900 -@@ -48,7 +48,7 @@ - - - #------------------------------------------------------------------------------ --# CONNECTIONS AND AUTHENTICATION -+# CONNECTIONS, AUTHENTICATION AND SECURITY - #------------------------------------------------------------------------------ - - # - Connection Settings - -@@ -96,7 +96,7 @@ - # 0 selects the system default - #tcp_keepalives_count = 0 # TCP_KEEPCNT; - # 0 selects the system default -- -+#sepostgresql = off # SE-PostgreSQL support - - #------------------------------------------------------------------------------ - # RESOURCE USAGE (except WAL) -diff -rpNU3 base/src/include/access/heapam.h sepgsql-new/src/include/access/heapam.h ---- base/src/include/access/heapam.h 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql-new/src/include/access/heapam.h 2009-03-13 18:14:33.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 withseclabel, - Size structlen, void *structure); - - /* in heap/pruneheap.c */ -diff -rpNU3 base/src/include/access/htup.h sepgsql-new/src/include/access/htup.h ---- base/src/include/access/htup.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/access/htup.h 2009-03-13 18:14:33.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,13 @@ do { \ - #define MaxTransactionIdAttributeNumber (-5) - #define MaxCommandIdAttributeNumber (-6) - #define TableOidAttributeNumber (-7) --#define FirstLowInvalidHeapAttributeNumber (-8) -+#define SecurityLabelAttributeNumber (-8) -+#define FirstLowInvalidHeapAttributeNumber (-9) - -+/* -+ * Attribute names for the system-defined attributes -+ */ -+#define SecurityLabelAttributeName "security_context" - - /* - * MinimalTuple is an alternative representation that is used for transient -@@ -548,6 +584,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-new/src/include/access/tupdesc.h ---- base/src/include/access/tupdesc.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/access/tupdesc.h 2009-03-13 18:14:33.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-new/src/include/catalog/heap.h ---- base/src/include/catalog/heap.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/catalog/heap.h 2009-03-13 18:14:33.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 *selblList); - - 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, -+ Oid relselabel); - - 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-new/src/include/catalog/indexing.h ---- base/src/include/catalog/indexing.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/catalog/indexing.h 2009-03-13 18:14:33.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-new/src/include/catalog/pg_attribute.h ---- base/src/include/catalog/pg_attribute.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/catalog/pg_attribute.h 2009-03-13 18:14:33.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-new/src/include/catalog/pg_proc.h ---- base/src/include/catalog/pg_proc.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/catalog/pg_proc.h 2009-03-13 18:14:33.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, -+ Oid proselabel); - - extern bool function_parse_error_transpose(const char *prosrc); - -diff -rpNU3 base/src/include/catalog/pg_security.h sepgsql-new/src/include/catalog/pg_security.h ---- base/src/include/catalog/pg_security.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/include/catalog/pg_security.h 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,58 @@ -+/* -+ * src/include/catalog/pg_security.h -+ * Definition of the security label relation (pg_security) -+ * -+ * Copyright (c) 2006 - 2007 KaiGai Kohei -+ */ -+#ifndef PG_SECURITY_H -+#define PG_SECURITY_H -+ -+#include "access/htup.h" -+#include "utils/relcache.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 -+ -+/* -+ * functions to translate between security label and identifier -+ */ -+extern void -+securityPostBootstrapingMode(void); -+ -+extern bool -+securityTupleDescHasSecLabel(Relation rel); -+ -+extern Oid -+securityLookupSecurityId(const char *seclabel); -+ -+extern char * -+securityLookupSecurityLabel(Oid secid); -+ -+extern Oid -+securityTransSecLabelIn(char *seclabel); -+ -+extern char * -+securityTransSecLabelOut(Oid secid); -+ -+extern Datum -+securityHeapGetSecLabelSysattr(HeapTuple tuple); -+ -+#endif /* PG_SELINUX_H */ -diff -rpNU3 base/src/include/executor/executor.h sepgsql-new/src/include/executor/executor.h ---- base/src/include/executor/executor.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/executor/executor.h 2009-03-13 18:14:33.000000000 +0900 -@@ -117,7 +117,7 @@ extern TupleHashEntry FindTupleHashEntry - * prototypes from functions in execJunk.c - */ - extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid, -- TupleTableSlot *slot); -+ bool hasseclabel, TupleTableSlot *slot); - extern JunkFilter *ExecInitJunkFilterConversion(List *targetList, - TupleDesc cleanTupType, - TupleTableSlot *slot); -@@ -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-new/src/include/executor/tuptable.h ---- base/src/include/executor/tuptable.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/executor/tuptable.h 2009-03-13 18:14:33.000000000 +0900 -@@ -118,6 +118,9 @@ typedef struct TupleTableSlot - MinimalTuple tts_mintuple; /* set if it's a minimal tuple, else NULL */ - HeapTupleData tts_minhdr; /* workspace if it's a minimal tuple */ - long tts_off; /* saved state for slot_deform_tuple */ -+ -+ /* temporary storages for writable system columns */ -+ Oid tts_seclabel; - } TupleTableSlot; - - /* -diff -rpNU3 base/src/include/fmgr.h sepgsql-new/src/include/fmgr.h ---- base/src/include/fmgr.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/fmgr.h 2009-03-13 18:14:33.000000000 +0900 -@@ -52,6 +52,15 @@ 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 */ -+ -+#ifdef HAVE_SELINUX -+ /* -+ * Note: SELinux allows to switch the security context of client -+ * inside the specific functions labeled as trusted procedure. -+ */ -+ PGFunction sepgsql_addr; /* address of original pointer */ -+ char *sepgsql_label; /* temporary security context */ -+#endif - } FmgrInfo; - - /* -@@ -511,6 +520,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-new/src/include/libpq/be-fsstubs.h ---- base/src/include/libpq/be-fsstubs.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/libpq/be-fsstubs.h 2009-03-13 18:14:33.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/parsenodes.h sepgsql-new/src/include/nodes/parsenodes.h ---- base/src/include/nodes/parsenodes.h 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql-new/src/include/nodes/parsenodes.h 2009-03-15 17:38:39.000000000 +0900 -@@ -14,6 +14,7 @@ - #ifndef PARSENODES_H - #define PARSENODES_H - -+#include "nodes/bitmapset.h" - #include "nodes/primnodes.h" - #include "nodes/value.h" - -@@ -65,10 +66,11 @@ typedef uint32 AclMode; /* a bitmask o - #define ACL_CREATE (1<<9) /* for namespaces and databases */ - #define ACL_CREATE_TEMP (1<<10) /* for databases */ - #define ACL_CONNECT (1<<11) /* for databases */ --#define N_ACL_RIGHTS 12 /* 1 plus the last 1< */ - } AlterTableType; - - typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ -@@ -1108,6 +1114,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 *secLabel; /* explicitly specified security label */ - } CreateStmt; - - /* ---------- -diff -rpNU3 base/src/include/nodes/plannodes.h sepgsql-new/src/include/nodes/plannodes.h ---- base/src/include/nodes/plannodes.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/nodes/plannodes.h 2009-03-13 18:14:33.000000000 +0900 -@@ -16,6 +16,7 @@ - - #include "access/sdir.h" - #include "nodes/bitmapset.h" -+#include "nodes/parsenodes.h" - #include "nodes/primnodes.h" - - -@@ -73,6 +74,8 @@ typedef struct PlannedStmt - List *relationOids; /* OIDs of relations the plan depends on */ - - int nParamExec; /* number of PARAM_EXEC Params used */ -+ -+ List *selinuxItems; /* list of SelinuxEvalItem */ - } PlannedStmt; - - /* macro for fetching the Plan associated with a SubPlan node */ -@@ -216,6 +219,8 @@ typedef struct Scan - { - Plan plan; - Index scanrelid; /* relid is index into the range table */ -+ -+ AclMode requiredPerms; /* permissions in row-level access controls */ - } Scan; - - /* ---------------- -diff -rpNU3 base/src/include/nodes/relation.h sepgsql-new/src/include/nodes/relation.h ---- base/src/include/nodes/relation.h 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/include/nodes/relation.h 2009-03-13 18:14:33.000000000 +0900 -@@ -366,6 +366,15 @@ typedef struct RelOptInfo - * list just to avoid recomputing the best inner indexscan repeatedly for - * similar outer relations. See comments for InnerIndexscanInfo. - */ -+ -+ /* -+ * Row-level access controls (both DAC and MAC) requires tuplePerms -+ * holds proper required permissions for each fetched tuples. It is -+ * similar to conditional scan on relations so, optimizar have to -+ * check whether tuplePerms is zero, or not. The tuplePerms with zero -+ * means we have no row-level security in this relation. -+ */ -+ AclMode requiredPerms; - } RelOptInfo; - - /* -diff -rpNU3 base/src/include/parser/parse_node.h sepgsql-new/src/include/parser/parse_node.h ---- base/src/include/parser/parse_node.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/parser/parse_node.h 2009-03-13 13:09:47.000000000 +0900 -@@ -64,6 +64,7 @@ typedef struct ParseState - struct ParseState *parentParseState; /* stack link */ - const char *p_sourcetext; /* source text, or NULL if not available */ - List *p_rtable; /* range table so far */ -+ List *p_joinexprs; /* JoinExprs for RTE_JOIN p_rtable entries */ - List *p_joinlist; /* join items so far (will become FromExpr - * node's fromlist) */ - List *p_relnamespace; /* current namespace for relations */ -diff -rpNU3 base/src/include/parser/parse_relation.h sepgsql-new/src/include/parser/parse_relation.h ---- base/src/include/parser/parse_relation.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/parser/parse_relation.h 2009-03-13 13:09:47.000000000 +0900 -@@ -40,6 +40,8 @@ extern Node *qualifiedNameToVar(ParseSta - char *colname, - bool implicitRTEOK, - int location); -+extern void markVarForSelectPriv(ParseState *pstate, Var *var, -+ RangeTblEntry *rte); - extern RangeTblEntry *addRangeTableEntry(ParseState *pstate, - RangeVar *relation, - Alias *alias, -diff -rpNU3 base/src/include/pg_config.h.in sepgsql-new/src/include/pg_config.h.in ---- base/src/include/pg_config.h.in 2008-01-28 16:06:37.000000000 +0900 -+++ sepgsql-new/src/include/pg_config.h.in 2009-03-13 18:14:33.000000000 +0900 -@@ -366,6 +366,9 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_SECURITY_PAM_APPL_H - -+/* Define to 1 if you enable SELinux support */ -+#undef HAVE_SELINUX -+ - /* Define to 1 if you have the `setproctitle' function. */ - #undef HAVE_SETPROCTITLE - -diff -rpNU3 base/src/include/security/rowlevel.h sepgsql-new/src/include/security/rowlevel.h ---- base/src/include/security/rowlevel.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/include/security/rowlevel.h 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,34 @@ -+/* -+ * src/include/security/rowlevel.h -+ * Definition of the facility of row-level access controls -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#ifndef ROWLEVEL_H -+#define ROWLEVEL_H -+ -+#include "access/htup.h" -+#include "executor/tuptable.h" -+#include "nodes/plannodes.h" -+#include "utils/relcache.h" -+ -+extern bool -+rowlvBehaviorSwitchTo(bool new_abort); -+ -+extern bool -+rowlvExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort); -+ -+extern bool -+rowlvHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal); -+ -+extern bool -+rowlvHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup, bool internal); -+ -+extern bool -+rowlvHeapTupleDelete(Relation rel, ItemPointer otid, bool internal); -+ -+extern bool -+rowlvCopyToTuple(Relation rel, HeapTuple tuple); -+ -+#endif /* PG_SELINUX_H */ -diff -rpNU3 base/src/include/security/sepgsql.h sepgsql-new/src/include/security/sepgsql.h ---- base/src/include/security/sepgsql.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/include/security/sepgsql.h 2009-03-13 18:14:33.000000000 +0900 -@@ -0,0 +1,397 @@ -+/* -+ * src/include/utils/sepgsql.h -+ * Headers of SE-PostgreSQL -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+#ifndef SEPGSQL_H -+#define SEPGSQL_H -+ -+#include "access/htup.h" -+#include "commands/trigger.h" -+#include "executor/execdesc.h" -+#include "fmgr.h" -+#include "nodes/parsenodes.h" -+#include "storage/large_object.h" -+#include "utils/relcache.h" -+ -+typedef Oid sepgsql_sid_t; -+ -+#ifdef HAVE_SELINUX -+ -+#include -+ -+/* GUC parameter to turn on/off SE-PostgreSQL */ -+extern bool sepostgresql_is_enabled; -+ -+/* GUC parameter to turn on/off Row-level controls */ -+extern bool sepostgresql_row_level; -+ -+/* Objject classes and permissions internally used */ -+enum SepgsqlClasses -+{ -+ SEPG_CLASS_PROCESS = 0, -+ SEPG_CLASS_FILE, -+ SEPG_CLASS_DIR, -+ SEPG_CLASS_LNK_FILE, -+ SEPG_CLASS_CHR_FILE, -+ SEPG_CLASS_BLK_FILE, -+ SEPG_CLASS_SOCK_FILE, -+ SEPG_CLASS_FIFO_FILE, -+ SEPG_CLASS_DB_DATABASE, -+ SEPG_CLASS_DB_TABLE, -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_CLASS_DB_COLUMN, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_CLASS_MAX, -+}; -+ -+#define SEPG_PROCESS__TRANSITION (1<<0) -+ -+#define SEPG_FILE__READ (1<<0) -+#define SEPG_FILE__WRITE (1<<1) -+ -+#define SEPG_DIR__READ (SEPG_FILE__READ) -+#define SEPG_DIR__WRITE (SEPG_FILE__WRITE) -+ -+#define SEPG_LNK_FILE__READ (SEPG_FILE__READ) -+#define SEPG_LNK_FILE__WRITE (SEPG_FILE__WRITE) -+ -+#define SEPG_CHR_FILE__READ (SEPG_FILE__READ) -+#define SEPG_CHR_FILE__WRITE (SEPG_FILE__WRITE) -+ -+#define SEPG_BLK_FILE__READ (SEPG_FILE__READ) -+#define SEPG_BLK_FILE__WRITE (SEPG_FILE__WRITE) -+ -+#define SEPG_SOCK_FILE__READ (SEPG_FILE__READ) -+#define SEPG_SOCK_FILE__WRITE (SEPG_FILE__WRITE) -+ -+#define SEPG_FIFO_FILE__READ (SEPG_FILE__READ) -+#define SEPG_FIFO_FILE__WRITE (SEPG_FILE__WRITE) -+ -+#define SEPG_DB_DATABASE__CREATE (1<<0) -+#define SEPG_DB_DATABASE__DROP (1<<1) -+#define SEPG_DB_DATABASE__GETATTR (1<<2) -+#define SEPG_DB_DATABASE__SETATTR (1<<3) -+#define SEPG_DB_DATABASE__RELABELFROM (1<<4) -+#define SEPG_DB_DATABASE__RELABELTO (1<<5) -+#define SEPG_DB_DATABASE__ACCESS (1<<6) -+#define SEPG_DB_DATABASE__INSTALL_MODULE (1<<7) -+#define SEPG_DB_DATABASE__LOAD_MODULE (1<<8) -+#define SEPG_DB_DATABASE__SUPERUSER (1<<9) -+ -+#define SEPG_DB_TABLE__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_TABLE__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_TABLE__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_TABLE__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_TABLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_TABLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_TABLE__SELECT (1<<6) -+#define SEPG_DB_TABLE__UPDATE (1<<7) -+#define SEPG_DB_TABLE__INSERT (1<<8) -+#define SEPG_DB_TABLE__DELETE (1<<9) -+#define SEPG_DB_TABLE__LOCK (1<<10) -+ -+#define SEPG_DB_PROCEDURE__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_PROCEDURE__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_PROCEDURE__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_PROCEDURE__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_PROCEDURE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_PROCEDURE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_PROCEDURE__EXECUTE (1<<6) -+#define SEPG_DB_PROCEDURE__ENTRYPOINT (1<<7) -+#define SEPG_DB_PROCEDURE__INSTALL (1<<8) -+ -+#define SEPG_DB_COLUMN__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_COLUMN__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_COLUMN__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_COLUMN__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_COLUMN__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_COLUMN__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_COLUMN__SELECT (1<<6) -+#define SEPG_DB_COLUMN__UPDATE (1<<7) -+#define SEPG_DB_COLUMN__INSERT (1<<8) -+ -+#define SEPG_DB_TUPLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_TUPLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_TUPLE__SELECT (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_TUPLE__UPDATE (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_TUPLE__INSERT (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_TUPLE__DELETE (SEPG_DB_DATABASE__DROP) -+ -+#define SEPG_DB_BLOB__CREATE (SEPG_DB_DATABASE__CREATE) -+#define SEPG_DB_BLOB__DROP (SEPG_DB_DATABASE__DROP) -+#define SEPG_DB_BLOB__GETATTR (SEPG_DB_DATABASE__GETATTR) -+#define SEPG_DB_BLOB__SETATTR (SEPG_DB_DATABASE__SETATTR) -+#define SEPG_DB_BLOB__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+#define SEPG_DB_BLOB__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+#define SEPG_DB_BLOB__READ (1<<6) -+#define SEPG_DB_BLOB__WRITE (1<<7) -+#define SEPG_DB_BLOB__IMPORT (1<<8) -+#define SEPG_DB_BLOB__EXPORT (1<<9) -+ -+/* -+ * avc.c : userspace access vector cache -+ */ -+extern Size sepgsqlShmemSize(void); -+ -+extern void sepgsqlAvcInit(void); -+ -+extern pid_t sepgsqlStartupWorkerProcess(void); -+ -+extern void sepgsqlAvcSwitchClient(void); -+ -+extern bool -+sepgsqlClientHasPerms(sepgsql_sid_t tcontext, -+ security_class_t tclass, -+ access_vector_t required, -+ const char *audit_name, bool abort); -+extern sepgsql_sid_t -+sepgsqlClientCreate(sepgsql_sid_t tcontext, -+ security_class_t tclass); -+ -+extern security_context_t -+sepgsqlClientCreateLabel(sepgsql_sid_t tcontext, -+ security_class_t tclass); -+ -+extern bool -+sepgsqlComputePerms(security_context_t scontext, -+ security_context_t tcontext, -+ security_class_t tclass, -+ access_vector_t required, -+ const char *audit_name, bool abort); -+ -+extern security_context_t -+sepgsqlComputeCreate(security_context_t scontext, -+ security_context_t tcontext, -+ security_class_t tclass); -+ -+/* -+ * checker.c : pick up all the appeared objects and apply checks -+ */ -+extern void -+sepgsqlCheckRTEPerms(RangeTblEntry *rte); -+ -+extern void -+sepgsqlCheckCopyTable(Relation rel, List *attnumlist, bool is_from); -+ -+extern void -+sepgsqlCheckSelectInto(Oid relaionId); -+ -+extern bool -+sepgsqlExecScan(Relation rel, HeapTuple tuple, AclMode required, bool abort); -+ -+extern bool -+sepgsqlHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal); -+ -+extern bool -+sepgsqlHeapTupleUpdate(Relation rel, HeapTuple oldtup, HeapTuple newtup, bool internal); -+ -+extern bool -+sepgsqlHeapTupleDelete(Relation rel, HeapTuple oldtup, bool internal); -+ -+/* -+ * core.c : core facilities -+ */ -+extern security_context_t -+sepgsqlGetServerLabel(void); -+ -+extern security_context_t -+sepgsqlGetClientLabel(void); -+ -+extern security_context_t -+sepgsqlGetUnlabeledLabel(void); -+ -+extern security_context_t -+sepgsqlGetDatabaseLabel(void); -+ -+extern sepgsql_sid_t -+sepgsqlGetDatabaseSid(void); -+ -+extern security_context_t -+sepgsqlSwitchClient(security_context_t new_client); -+ -+extern bool -+sepgsqlIsEnabled(void); -+ -+extern void -+sepgsqlInitialize(void); -+ -+/* -+ * hooks.c : security hooks -+ */ -+extern bool -+sepgsqlCheckDatabaseAccess(Oid db_oid); -+ -+extern bool -+sepgsqlCheckDatabaseSuperuser(void); -+ -+extern void -+sepgsqlCheckDatabaseInstallModule(const char *filename); -+ -+extern void -+sepgsqlCheckDatabaseLoadModule(const char *filename); -+ -+extern bool -+sepgsqlCheckTableLock(Oid table_oid); -+ -+extern bool -+sepgsqlCheckTableTruncate(Relation rel); -+ -+extern bool -+sepgsqlCheckProcedureExecute(Oid proc_oid); -+ -+extern void -+sepgsqlCheckProcedureEntrypoint(FmgrInfo *finfo, HeapTuple protup); -+ -+extern void -+sepgsqlCheckProcedureInstall(Relation rel, HeapTuple newtup, HeapTuple oldtup); -+ -+extern void -+sepgsqlCheckBlobDrop(HeapTuple lotup); -+ -+extern void -+sepgsqlCheckBlobRead(LargeObjectDesc *lobj); -+ -+extern void -+sepgsqlCheckBlobWrite(LargeObjectDesc *lobj); -+ -+extern void -+sepgsqlCheckBlobGetattr(HeapTuple tuple); -+ -+extern void -+sepgsqlCheckBlobSetattr(HeapTuple tuple); -+ -+extern void -+sepgsqlCheckBlobExport(LargeObjectDesc *lobj, int fdesc, const char *filename); -+ -+extern void -+sepgsqlCheckBlobImport(LargeObjectDesc *lobj, int fdesc, const char *filename); -+ -+extern void -+sepgsqlCheckBlobRelabel(HeapTuple oldtup, HeapTuple newtup); -+ -+extern void -+sepgsqlCheckFileRead(int fdesc, const char *filename); -+ -+extern void -+sepgsqlCheckFileWrite(int fdesc, const char *filename); -+ -+extern bool -+sepgsqlAllowFunctionInlined(HeapTuple protup); -+ -+/* -+ * label.c : security label management -+ */ -+extern bool -+sepgsqlTupleDescHasSecLabel(Relation rel); -+ -+extern void -+sepgsqlSetDefaultSecLabel(Relation rel, HeapTuple tuple); -+ -+extern char * -+sepgsqlMetaSecurityLabel(void); -+ -+extern sepgsql_sid_t -+sepgsqlInputGivenSecLabel(DefElem *defel); -+ -+extern List * -+sepgsqlInputGivenSecLabelRelation(CreateStmt *stmt); -+ -+extern security_context_t -+sepgsqlSecurityLabelTransIn(security_context_t label); -+ -+extern security_context_t -+sepgsqlSecurityLabelTransOut(security_context_t label); -+ -+extern bool -+sepgsqlCheckValidSecurityLabel(security_context_t label); -+ -+/* -+ * perms.c : SE-PostgreSQL permission checks -+ */ -+extern const char * -+sepgsqlAuditName(Oid relid, HeapTuple tuple); -+ -+extern security_class_t -+sepgsqlFileObjectClass(int fdesc); -+ -+extern security_class_t -+sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple); -+ -+extern security_class_t -+sepgsqlTransToExternalClass(security_class_t tclass_in); -+ -+extern void -+sepgsqlTransToInternalPerms(security_class_t tclass_ex, struct av_decision *avd); -+ -+extern const char * -+sepgsqlGetClassString(security_class_t tclass); -+ -+extern const char * -+sepgsqlGetPermissionString(security_class_t tclass, access_vector_t av); -+ -+extern bool -+sepgsqlCheckObjectPerms(Relation rel, HeapTuple tuple, -+ access_vector_t required, bool abort); -+ -+#else /* HAVE_SELINUX */ -+ -+// avc.c -+#define sepgsqlShmemSize() (0) -+#define sepgsqlStartupWorkerProcess() (0) -+// checker.c -+#define sepgsqlCheckRTEPerms(a) do {} while(0) -+#define sepgsqlCheckSelectInto(a) do {} while(0) -+#define sepgsqlExecScan(a,b,c,d) (true) -+#define sepgsqlHeapTupleInsert(a,b,c) (true) -+#define sepgsqlHeapTupleUpdate(a,b,c,d) (true) -+#define sepgsqlHeapTupleDelete(a,b,c) (true) -+// core.c -+#define sepgsqlIsEnabled() (false) -+#define sepgsqlInitialize() do {} while(0) -+// hooks.c -+#define sepgsqlCheckDatabaseAccess(a) (true) -+#define sepgsqlCheckDatabaseSuperuser() (true) -+#define sepgsqlCheckDatabaseInstallModule(a) do {} while(0) -+#define sepgsqlCheckDatabaseLoadModule(a) do {} while(0) -+#define sepgsqlCheckTableLock(a) (true) -+#define sepgsqlCheckTableTruncate(a) (true) -+#define sepgsqlCheckProcedureExecute(a) (true) -+#define sepgsqlCheckProcedureEntrypoint(a,b) do {} while(0) -+#define sepgsqlCheckBlobDrop(a) do {} while(0) -+#define sepgsqlCheckBlobRead(a) do {} while(0) -+#define sepgsqlCheckBlobWrite(a) do {} while(0) -+#define sepgsqlCheckBlobGetattr(a) do {} while(0) -+#define sepgsqlCheckBlobSetattr(a) do {} while(0) -+#define sepgsqlCheckBlobExport(a,b,c) do {} while(0) -+#define sepgsqlCheckBlobImport(a,b,c) do {} while(0) -+#define sepgsqlCheckBlobRelabel(a,b) do {} while(0) -+#define sepgsqlCheckFileRead(a,b) do {} while(0) -+#define sepgsqlCheckFileWrite(a,b) do {} while(0) -+#define sepgsqlAllowFunctionInlined(a) (true) -+// label.c -+#define sepgsqlTupleDescHasSecLabel(a) (false) -+#define sepgsqlMetaSecurityLabel() (NULL) -+#define sepgsqlInputGivenSecLabel(a) (InvalidOid) -+#define sepgsqlInputGivenSecLabelRelation(a) (NIL) -+#define sepgsqlSecurityLabelTransIn(a) (a) -+#define sepgsqlSecurityLabelTransOut(a) (a) -+#define sepgsqlCheckValidSecurityLabel(a) (false) -+ -+#endif /* HAVE_SELINUX */ -+ -+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 /* SEPGSQL_H */ -diff -rpNU3 base/src/include/storage/fd.h sepgsql-new/src/include/storage/fd.h ---- base/src/include/storage/fd.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/storage/fd.h 2009-03-13 18:14:33.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/large_object.h sepgsql-new/src/include/storage/large_object.h ---- base/src/include/storage/large_object.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/storage/large_object.h 2009-03-13 18:14:33.000000000 +0900 -@@ -44,6 +44,7 @@ typedef struct LargeObjectDesc - #define IFS_RDLOCK (1 << 0) - #define IFS_WRLOCK (1 << 1) - -+ Oid secid; /* security id of the largeobject */ - } LargeObjectDesc; - - -@@ -79,5 +80,7 @@ extern int inv_tell(LargeObjectDesc *obj - extern int inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes); - extern int inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes); - extern void inv_truncate(LargeObjectDesc *obj_desc, int len); -+extern Oid inv_get_security(Oid loid); -+extern void inv_set_security(Oid loid, Oid secid); - - #endif /* LARGE_OBJECT_H */ -diff -rpNU3 base/src/include/storage/lwlock.h sepgsql-new/src/include/storage/lwlock.h ---- base/src/include/storage/lwlock.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/storage/lwlock.h 2009-03-13 18:14:33.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/builtins.h sepgsql-new/src/include/utils/builtins.h ---- base/src/include/utils/builtins.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/utils/builtins.h 2009-03-13 13:09:47.000000000 +0900 -@@ -617,6 +617,14 @@ extern Datum varchartypmodout(PG_FUNCTIO - extern Datum varchar(PG_FUNCTION_ARGS); - - /* varlena.c */ -+extern text *cstring_to_text(const char *s); -+extern text *cstring_to_text_with_len(const char *s, int len); -+extern char *text_to_cstring(const text *t); -+extern void text_to_cstring_buffer(const text *src, char *dst, size_t dst_len); -+ -+#define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s)) -+#define TextDatumGetCString(d) text_to_cstring((text *) DatumGetPointer(d)) -+ - extern Datum textin(PG_FUNCTION_ARGS); - extern Datum textout(PG_FUNCTION_ARGS); - extern Datum textrecv(PG_FUNCTION_ARGS); -diff -rpNU3 base/src/include/utils/catcache.h sepgsql-new/src/include/utils/catcache.h ---- base/src/include/utils/catcache.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/utils/catcache.h 2009-03-13 18:14:33.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-new/src/include/utils/errcodes.h ---- base/src/include/utils/errcodes.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/utils/errcodes.h 2009-03-13 18:14:33.000000000 +0900 -@@ -339,6 +339,11 @@ - #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 - SE-PostgreSQL Error */ -+#define ERRCODE_SELINUX_ERROR MAKE_SQLSTATE('S','E', '0','0','1') -+#define ERRCODE_SELINUX_AUDIT MAKE_SQLSTATE('S','E', '0','0','2') -+#define ERRCODE_SELINUX_INFO MAKE_SQLSTATE('S','E', '0','0','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-new/src/include/utils/syscache.h ---- base/src/include/utils/syscache.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/include/utils/syscache.h 2009-03-13 18:14:33.000000000 +0900 -@@ -64,18 +64,20 @@ - #define RELNAMENSP 33 - #define RELOID 34 - #define RULERELNAME 35 --#define STATRELATT 36 --#define TSCONFIGMAP 37 --#define TSCONFIGNAMENSP 38 --#define TSCONFIGOID 39 --#define TSDICTNAMENSP 40 --#define TSDICTOID 41 --#define TSPARSERNAMENSP 42 --#define TSPARSEROID 43 --#define TSTEMPLATENAMENSP 44 --#define TSTEMPLATEOID 45 --#define TYPENAMENSP 46 --#define TYPEOID 47 -+#define SECURITYLABEL 36 -+#define SECURITYOID 37 -+#define STATRELATT 38 -+#define TSCONFIGMAP 39 -+#define TSCONFIGNAMENSP 40 -+#define TSCONFIGOID 41 -+#define TSDICTNAMENSP 42 -+#define TSDICTOID 43 -+#define TSPARSERNAMENSP 44 -+#define TSPARSEROID 45 -+#define TSTEMPLATENAMENSP 46 -+#define TSTEMPLATEOID 47 -+#define TYPENAMENSP 48 -+#define TYPEOID 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 --git a/sepostgresql-fedora-prefix.patch b/sepostgresql-fedora-prefix.patch deleted file mode 100644 index a4ab652..0000000 --- a/sepostgresql-fedora-prefix.patch +++ /dev/null @@ -1,87 +0,0 @@ -Index: trunk/src/Makefile.global.in -=================================================================== ---- trunk/src/Makefile.global.in (revision 430) -+++ trunk/src/Makefile.global.in (working copy) -@@ -73,14 +73,14 @@ - datadir := @datadir@ - ifeq "$(findstring pgsql, $(datadir))" "" - ifeq "$(findstring postgres, $(datadir))" "" --override datadir := $(datadir)/postgresql -+override datadir := $(datadir)/sepgsql - endif - endif - - sysconfdir := @sysconfdir@ - ifeq "$(findstring pgsql, $(sysconfdir))" "" - ifeq "$(findstring postgres, $(sysconfdir))" "" --override sysconfdir := $(sysconfdir)/postgresql -+override sysconfdir := $(sysconfdir)/sepgsql - endif - endif - -@@ -89,7 +89,7 @@ - pkglibdir = $(libdir) - ifeq "$(findstring pgsql, $(pkglibdir))" "" - ifeq "$(findstring postgres, $(pkglibdir))" "" --override pkglibdir := $(pkglibdir)/postgresql -+override pkglibdir := $(pkglibdir)/sepgsql - endif - endif - -@@ -98,7 +98,7 @@ - pkgincludedir = $(includedir) - ifeq "$(findstring pgsql, $(pkgincludedir))" "" - ifeq "$(findstring postgres, $(pkgincludedir))" "" --override pkgincludedir := $(pkgincludedir)/postgresql -+override pkgincludedir := $(pkgincludedir)/sepgsql - endif - endif - -@@ -109,7 +109,7 @@ - ifneq (,$(docdir)) - ifeq "$(findstring pgsql, $(docdir))" "" - ifeq "$(findstring postgres, $(docdir))" "" --override docdir := $(docdir)/postgresql -+override docdir := $(docdir)/sepgsql - endif - endif - endif -Index: trunk/src/bin/pg_ctl/pg_ctl.c -=================================================================== ---- trunk/src/bin/pg_ctl/pg_ctl.c (revision 429) -+++ trunk/src/bin/pg_ctl/pg_ctl.c (working copy) -@@ -557,7 +557,7 @@ - - postmaster_path = pg_malloc(MAXPGPATH); - -- if ((ret = find_other_exec(argv0, "postgres", PM_VERSIONSTR, -+ if ((ret = find_other_exec(argv0, "sepostgres", PM_VERSIONSTR, - postmaster_path)) < 0) - { - char full_path[MAXPGPATH]; -Index: trunk/src/bin/initdb/initdb.c -=================================================================== ---- trunk/src/bin/initdb/initdb.c (revision 429) -+++ trunk/src/bin/initdb/initdb.c (working copy) -@@ -2646,7 +2646,7 @@ - sprintf(pgdenv, "PGDATA=%s", pg_data); - putenv(pgdenv); - -- if ((ret = find_other_exec(argv[0], "postgres", PG_VERSIONSTR, -+ if ((ret = find_other_exec(argv[0], "sepostgres", PG_VERSIONSTR, - backend_exec)) < 0) - { - char full_path[MAXPGPATH]; -Index: trunk/src/bin/pg_dump/pg_dumpall.c -=================================================================== ---- trunk/src/bin/pg_dump/pg_dumpall.c (revision 429) -+++ trunk/src/bin/pg_dump/pg_dumpall.c (working copy) -@@ -139,7 +139,7 @@ - } - } - -- if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR, -+ if ((ret = find_other_exec(argv[0], "sepg_dump", PGDUMP_VERSIONSTR, - pg_dump_bin)) < 0) - { - char full_path[MAXPGPATH]; diff --git a/sepostgresql-test-8.3.patch b/sepostgresql-test-8.3.patch deleted file mode 100644 index cdd91e8..0000000 --- a/sepostgresql-test-8.3.patch +++ /dev/null @@ -1,1730 +0,0 @@ -diff -rpNU3 base/src/test/regress/expected/sanity_check.out sepgsql-new/src/test/regress/expected/sanity_check.out ---- base/src/test/regress/expected/sanity_check.out 2007-11-25 12:49:12.000000000 +0900 -+++ sepgsql-new/src/test/regress/expected/sanity_check.out 2009-03-13 18:14:33.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 -diff -rpNU3 base/src/test/sepgsql/Makefile sepgsql-new/src/test/sepgsql/Makefile ---- base/src/test/sepgsql/Makefile 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/Makefile 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,65 @@ -+# ---------------------------------------------------- -+# Makefile for SE-PostgreSQL testcases -+# ---------------------------------------------------- -+PSQL := $(shell which psql) -+DIFF := $(shell which diff) -+RUNCON := $(shell which runcon) -+GETSEBOOL := $(shell which getsebool) -+DBNAME := test -+ -+TESTCASES = $(wildcard sql/*.sql) -+ -+test: init check setup results.diff -+ -+init: -+ rm -f results.diff results/*.out results/*.diff -+ -+clean: init -+ rm -f launch_psql -+ -+launch_psql: launch_psql.c -+ $(CC) $< -o $@ -lselinux -+ -+results.diff: $(TESTCASES:sql/%.sql=results/%.diff) -+ @for x in $^; do cat $$x >> $@; done -+ @test -s $@ && echo "HINT: See $@ to confirm errors" || : -+ -+results/%.diff: sql/%.sql -+ @./launch_psql $(PSQL) -a $(DBNAME) < $< >& $(@:%.diff=%.out) -+ @$(DIFF) -u $(<:sql/%.sql=expected/%.out) \ -+ $(<:sql/%.sql=results/%.out) >& $@ \ -+ && echo -n "PASS: " || echo -n "FAIL: " -+ @echo $(notdir $(@:.diff=)) -+ -+setup: launch_psql -+ @cp -f /dev/null /tmp/sepgsql_test_copy_1 -+ @cp -f /dev/null /tmp/sepgsql_test_copy_2 -+ @chcon -t postgresql_tmp_t -l s0 /tmp/sepgsql_test_copy_1 -+ @chcon -t postgresql_db_t -l s0 /tmp/sepgsql_test_copy_2 -+ @dd if=/dev/zero of=/tmp/sepgsql_test_blob1 bs=1024 count=20 >& /dev/null -+ @dd if=/dev/zero of=/tmp/sepgsql_test_blob2 bs=1024 count=20 >& /dev/null -+ @chcon -t postgresql_tmp_t -l s0 /tmp/sepgsql_test_blob1 -+ @chcon -t postgresql_db_t -l s0 /tmp/sepgsql_test_blob2 -+ @chmod 0666 /tmp/sepgsql_test_* -+ @echo "PASS: setup filesystem objects" -+ -+check: -+ @test -x $(PSQL) || \ -+ (echo "HINT: $(PSQL) is not available"; exit 1) -+ @$(PSQL) -qt -c 'SHOW sepostgresql' -d $(DBNAME) 2>/dev/null | grep -q on || \ -+ (echo "HINT: database \"$(DBNAME)\" is not available"; \ -+ echo "HINT: SE-PostgreSQL may not be available on server"; exit 1) -+ @$(GETSEBOOL) allow_user_postgresql_connect | grep -q on || \ -+ (echo "HINT: check allow_user_postgresql_connect boolean"; exit 1) -+ @$(GETSEBOOL) sepgsql_regression_test_mode | grep -q on || \ -+ (echo "HINT: check sepgsql_regression_test_mode boolean"; \ -+ echo "HINT: check sepostgresql-devel.pp installed"; exit 1) -+ @$(RUNCON) -t sepgsql_test_t -l s0-s0:c0.c15 \ -+ $(PSQL) -c 'SELECT sepgsql_getcon()' $(DBNAME) >& /dev/null || \ -+ (echo "HINT: /sbin/restorecon -R and restart"; \ -+ echo "HINT: user shell should have 's0-s0:c0.c15' range, at least"; \ -+ echo " semanage enables to set up it"; exit 1) -+ @test -x /etc/init.d/mcstrans && /etc/init.d/mcstrans status >& /dev/null && \ -+ (echo "HINT: stop mcstrans daemon"; exit 1) || \ -+ (test $$? -eq 3 && exit 0 || exit 1) -+ @echo "PASS: check runtime environment" -diff -rpNU3 base/src/test/sepgsql/expected/basic.out sepgsql-new/src/test/sepgsql/expected/basic.out ---- base/src/test/sepgsql/expected/basic.out 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/expected/basic.out 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,108 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+----------------------------------------------------- -+ unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+(1 row) -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+SET -+DROP TABLE IF EXISTS t4 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t1 CASCADE; -+DROP TABLE -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+DROP FUNCTION -+RESET client_min_messages; -+RESET -+-- SETUP -+CREATE TABLE t1 -+( -+ a int, -+ b text -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_ro_table_t:s0', -+ c bool -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0' -+); -+CREATE TABLE -+INSERT INTO t1 VALUES (1, 'aaa', false), (2, 'bbb', true); -+INSERT 0 2 -+CREATE TABLE t2 -+( -+ s int, -+ t int, -+ u int -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_table_t:s0:c0'; -+CREATE TABLE -+ALTER TABLE t2 DROP COLUMN t; -- disturbing factor -+ALTER TABLE -+CREATE TABLE t3 -+( -+ x text -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_table_t:s0:c1' -+) inherits(t2); -+CREATE TABLE -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+--------------------------------------------------- -+ unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 -+(1 row) -+ -+SELECT * FROM t1; -- to be denied -+ERROR: SELinux: denied { select } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_secret_table_t:s0 tclass=db_column name=t1.c -+SELECT a, b FROM t1; -+ a | b -+---+----- -+ 1 | aaa -+ 2 | bbb -+(2 rows) -+ -+SELECT COUNT(*) FROM t1 WHERE c; -- to be denied -+ERROR: SELinux: denied { select } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_secret_table_t:s0 tclass=db_column name=t1.c -+UPDATE t1 SET b = 'ccc'; -- to be denied -+ERROR: SELinux: denied { update } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_ro_table_t:s0 tclass=db_column name=t1.b -+UPDATE t1 SET a = a + 2; -+UPDATE 2 -+INSERT INTO t1 VALUES (5, 'eee', true); -- to be denied -+ERROR: SELinux: denied { insert } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_ro_table_t:s0 tclass=db_column name=t1.b -+INSERT INTO t1 VALUES (5); -+INSERT 0 1 -+SELECT * FROM t2; -+ s | u -+---+--- -+(0 rows) -+ -+SELECT t2 FROM t2; -+ t2 -+---- -+(0 rows) -+ -+SELECT t3 FROM t3; -- to be denied -+ERROR: SELinux: denied { select } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0:c1 tclass=db_column name=t3.x -+SELECT 1 FROM t3; -+ ?column? -+---------- -+(0 rows) -+ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c1 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+--------------------------------------------------- -+ unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c1 -+(1 row) -+ -+SELECT * FROM t2; -- to be denied -+ERROR: SELinux: denied { select } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c1 tcontext=unconfined_u:object_r:sepgsql_table_t:s0:c0 tclass=db_table name=t2 -+SELECT t2 FROM t2; -- to be denied -+ERROR: SELinux: denied { select } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c1 tcontext=unconfined_u:object_r:sepgsql_table_t:s0:c0 tclass=db_table name=t2 -+SELECT t3 FROM t3; -+ t3 -+---- -+(0 rows) -+ -diff -rpNU3 base/src/test/sepgsql/expected/copy_stmt.out sepgsql-new/src/test/sepgsql/expected/copy_stmt.out ---- base/src/test/sepgsql/expected/copy_stmt.out 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/expected/copy_stmt.out 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,90 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+----------------------------------------------------- -+ unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+(1 row) -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+SET -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t1 CASCADE; -+DROP TABLE -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+DROP FUNCTION -+RESET client_min_messages; -+RESET -+-- setup tables -+CREATE TABLE t1 -+( -+ a int, -+ b text -+); -+CREATE TABLE -+INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'); -+INSERT 0 2 -+CREATE TABLE t2 -+( -+ x int, -+ y text -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0' -+); -+CREATE TABLE -+SELECT security_context from pg_attribute where attrelid = 't2'::regclass and attname = 'y'; -+ security_context -+------------------------------------------------- -+ unconfined_u:object_r:sepgsql_secret_table_t:s0 -+(1 row) -+ -+INSERT INTO t2 VALUES (1, 'xxx'), (2, 'yyy'); -+INSERT 0 2 -+CREATE TABLE t3 -- read only table -+( -+ s int, -+ t text -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_ro_table_t:s0'; -+CREATE TABLE -+INSERT INTO t2 VALUES (1, 'sss'), (2, 'ttt'); -+INSERT 0 2 -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+--------------------------------------------------- -+ unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 -+(1 row) -+ -+COPY t1 TO stdout; -+1 aaa -+2 bbb -+COPY t1 FROM stdin; -+COPY t1 TO '/tmp/sepgsql_test_copy_1'; -+COPY 4 -+COPY t1 TO '/tmp/sepgsql_test_copy_2'; -- to be denied -+ERROR: SELinux: denied { write } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:postgresql_db_t:s0 tclass=file name=/tmp/sepgsql_test_copy_2 -+COPY t2 TO stdout; -- to be denied -+ERROR: SELinux: denied { select } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_secret_table_t:s0 tclass=db_column name=t2.y -+COPY t2 FROM stdin; -- to be denied -+ERROR: SELinux: denied { insert } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_secret_table_t:s0 tclass=db_column name=t2.y -+COPY t2 (x) TO stdout; -+1 -+2 -+1 -+2 -+COPY t3 TO stdout; -+COPY t3 FROM '/tmp/sepgsql_test_copy_1'; -- to be denied -+ERROR: SELinux: denied { insert } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_ro_table_t:s0 tclass=db_table name=t3 -+COPY t1 FROM '/tmp/sepgsql_test_copy_1'; -+COPY 4 -+COPY t1 TO stdout; -+1 aaa -+2 bbb -+3 ccc -+4 ddd -+1 aaa -+2 bbb -+3 ccc -+4 ddd -diff -rpNU3 base/src/test/sepgsql/expected/enhanced_ddl_stmt.out sepgsql-new/src/test/sepgsql/expected/enhanced_ddl_stmt.out ---- base/src/test/sepgsql/expected/enhanced_ddl_stmt.out 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/expected/enhanced_ddl_stmt.out 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,180 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+----------------------------------------------------- -+ unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+(1 row) -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+SET -+DROP TABLE IF EXISTS t4 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t1 CASCADE; -+DROP TABLE -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+DROP FUNCTION -+DROP FUNCTION IF EXISTS f2(int) CASCADE; -+DROP FUNCTION -+RESET client_min_messages; -+RESET -+-- CREATE TABLE with SECURITY_LABEL clause -+CREATE TABLE t1 ( -+ a int, -+ b text -+); -+CREATE TABLE -+SELECT relname, security_context FROM pg_class WHERE oid = 't1'::regclass; -+ relname | security_context -+---------+------------------------------------------ -+ t1 | unconfined_u:object_r:sepgsql_table_t:s0 -+(1 row) -+ -+SELECT attname, security_context FROM pg_attribute WHERE attrelid = 't1'::regclass and attnum > 0; -+ attname | security_context -+---------+------------------------------------------ -+ a | unconfined_u:object_r:sepgsql_table_t:s0 -+ b | unconfined_u:object_r:sepgsql_table_t:s0 -+(2 rows) -+ -+CREATE TABLE t2 ( -+ a int, -+ b text -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_ro_table_t:s0'; -+CREATE TABLE -+SELECT relname, security_context FROM pg_class WHERE oid = 't2'::regclass; -+ relname | security_context -+---------+--------------------------------------------- -+ t2 | unconfined_u:object_r:sepgsql_ro_table_t:s0 -+(1 row) -+ -+SELECT attname, security_context FROM pg_attribute WHERE attrelid = 't2'::regclass and attnum > 0; -+ attname | security_context -+---------+--------------------------------------------- -+ a | unconfined_u:object_r:sepgsql_ro_table_t:s0 -+ b | unconfined_u:object_r:sepgsql_ro_table_t:s0 -+(2 rows) -+ -+CREATE TABLE t3 ( -+ a int, -+ b text SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_fixed_table_t:s0', -+ c bool SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0', -+ d int -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_table_t:s0:c0'; -+CREATE TABLE -+SELECT relname, security_context FROM pg_class WHERE oid = 't3'::regclass; -+ relname | security_context -+---------+--------------------------------------------- -+ t3 | unconfined_u:object_r:sepgsql_table_t:s0:c0 -+(1 row) -+ -+SELECT attname, security_context FROM pg_attribute WHERE attrelid = 't3'::regclass and attnum > 0; -+ attname | security_context -+---------+------------------------------------------------- -+ a | unconfined_u:object_r:sepgsql_table_t:s0 -+ b | unconfined_u:object_r:sepgsql_fixed_table_t:s0 -+ c | unconfined_u:object_r:sepgsql_secret_table_t:s0 -+ d | unconfined_u:object_r:sepgsql_table_t:s0 -+(4 rows) -+ -+CREATE TABLE t4 ( -+ a int, -+ b text -+) SECURITY_CONTEXT = 'unconfined_u:object_r:invalid_label_t:s0'; -- to be failed -+ERROR: invalid security label: unconfined_u:object_r:invalid_label_t:s0 -+CREATE TABLE t4 ( -+ a int, -+ b text -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_proc_t:s0'; -- to be denied -+ERROR: SELinux: denied { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 tcontext=unconfined_u:object_r:sepgsql_proc_t:s0 tclass=db_table name=t4 -+-- ALTER TABLE with SECURITY_CONTEXT clause -+ALTER TABLE t2 SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0'; -+ALTER TABLE -+ALTER TABLE t2 ADD COLUMN c bool; -- it inherits table's one -+ALTER TABLE -+SELECT relname, security_context FROM pg_class WHERE oid = 't2'::regclass; -+ relname | security_context -+---------+------------------------------------------------- -+ t2 | unconfined_u:object_r:sepgsql_secret_table_t:s0 -+(1 row) -+ -+SELECT attname, security_context FROM pg_attribute WHERE attrelid = 't2'::regclass and attnum > 0; -+ attname | security_context -+---------+------------------------------------------------- -+ a | unconfined_u:object_r:sepgsql_ro_table_t:s0 -+ b | unconfined_u:object_r:sepgsql_ro_table_t:s0 -+ c | unconfined_u:object_r:sepgsql_secret_table_t:s0 -+(3 rows) -+ -+ALTER TABLE t3 ALTER b SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_table_t:s0'; -+ALTER TABLE -+SELECT relname, security_context FROM pg_class WHERE oid = 't3'::regclass; -+ relname | security_context -+---------+--------------------------------------------- -+ t3 | unconfined_u:object_r:sepgsql_table_t:s0:c0 -+(1 row) -+ -+SELECT attname, security_context FROM pg_attribute WHERE attrelid = 't3'::regclass and attnum > 0; -+ attname | security_context -+---------+------------------------------------------------- -+ a | unconfined_u:object_r:sepgsql_table_t:s0 -+ b | unconfined_u:object_r:sepgsql_table_t:s0 -+ c | unconfined_u:object_r:sepgsql_secret_table_t:s0 -+ d | unconfined_u:object_r:sepgsql_table_t:s0 -+(4 rows) -+ -+-- CREATE FUNCTION with SECURITY_CONTEXT clause -+CREATE FUNCTION f1 (int) RETURNS int -+ LANGUAGE 'sql' -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_proc_t:s0:c0' -+ AS 'SELECT $1 * 2'; -+CREATE FUNCTION -+SELECT proname, security_context FROM pg_proc WHERE oid = 'f1'::regproc; -+ proname | security_context -+---------+-------------------------------------------- -+ f1 | unconfined_u:object_r:sepgsql_proc_t:s0:c0 -+(1 row) -+ -+CREATE FUNCTION f2 (int) RETURNS int -+ LANGUAGE 'sql' -+ SECURITY_CONTEXT = 'unconfined_u:object_r:invalid_label_t:s0' -+ AS 'SELECT $1 + $1'; -- to be failed -+ERROR: invalid security label: unconfined_u:object_r:invalid_label_t:s0 -+CREATE FUNCTION f2 (int) RETURNS int -+ LANGUAGE 'sql' -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_proc_t:s0:c16' -+ AS 'SELECT $1 + $1'; -- to be denied -+ERROR: SELinux: denied { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 tcontext=unconfined_u:object_r:sepgsql_proc_t:s0:c16 tclass=db_procedure name=f2 -+CREATE FUNCTION f2 (int) RETURNS int -+ LANGUAGE 'sql' -+ AS 'SELECT $1 + $1'; -+CREATE FUNCTION -+SELECT proname, security_context FROM pg_proc WHERE oid = 'f2'::regproc; -+ proname | security_context -+---------+----------------------------------------- -+ f2 | unconfined_u:object_r:sepgsql_proc_t:s0 -+(1 row) -+ -+-- ALTER FUNCTION with SECURITY_CONTEXT clause -+ALTER FUNCTION f1(int) -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_proc_t:s0:c1'; -+ALTER FUNCTION -+SELECT proname, security_context FROM pg_proc WHERE oid = 'f1'::regproc; -+ proname | security_context -+---------+-------------------------------------------- -+ f1 | unconfined_u:object_r:sepgsql_proc_t:s0:c1 -+(1 row) -+ -+ALTER FUNCTION f2(int) -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_proc_t:s0:c16'; -- to be denied -+ERROR: SELinux: denied { relabelto } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 tcontext=unconfined_u:object_r:sepgsql_proc_t:s0:c16 tclass=db_procedure name=f2 -+SELECT proname, security_context FROM pg_proc WHERE oid = 'f2'::regproc; -+ proname | security_context -+---------+----------------------------------------- -+ f2 | unconfined_u:object_r:sepgsql_proc_t:s0 -+(1 row) -+ -diff -rpNU3 base/src/test/sepgsql/expected/join_query.out sepgsql-new/src/test/sepgsql/expected/join_query.out ---- base/src/test/sepgsql/expected/join_query.out 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/expected/join_query.out 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,85 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+----------------------------------------------------- -+ unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+(1 row) -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+SET -+DROP TABLE IF EXISTS t4 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t1 CASCADE; -+DROP TABLE -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+DROP FUNCTION -+RESET client_min_messages; -+RESET -+-- SETUP -+CREATE TABLE t1 -+( -+ a int, -+ b text, -+ c int -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0' -+); -+CREATE TABLE -+INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'), (3, 'ccc'); -+INSERT 0 3 -+CREATE TABLE t2 -+( -+ x int, -+ y text -+); -+CREATE TABLE -+INSERT INTO t2 VALUES (2, 'xxx'), (3, 'yyy'), (4,'zzz'); -+INSERT 0 3 -+CREATE TABLE t3 -+( -+ d int -+) INHERITS (t1); -+CREATE TABLE -+INSERT INTO t3 VALUES (4, 'ddd'), (5, 'eee'); -+INSERT 0 2 -+CREATE TABLE t4 -+( -+ z int -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0' -+) INHERITS (t2); -+CREATE TABLE -+INSERT INTO t2 VALUES (1, 'sss'), (5, 'ttt'); -+INSERT 0 2 -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+--------------------------------------------------- -+ unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 -+(1 row) -+ -+SELECT * FROM t1 JOIN t2 ON a = x; -- to be denied -+ERROR: SELinux: denied { select } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_secret_table_t:s0 tclass=db_column name=t1.c -+SELECT a, b, y FROM t1 JOIN t2 ON a = x; -+ a | b | y -+---+-----+----- -+ 1 | aaa | sss -+ 2 | bbb | xxx -+ 3 | ccc | yyy -+ 4 | ddd | zzz -+ 5 | eee | ttt -+(5 rows) -+ -+SELECT a, b, y FROM t1 JOIN t2 ON c = x; -- to be denied -+ERROR: SELinux: denied { select } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_secret_table_t:s0 tclass=db_column name=t1.c -+SELECT COUNT(*) FROM t1 JOIN t2 ON a = x; -+ count -+------- -+ 5 -+(1 row) -+ -+SELECT j FROM (t1 JOIN t2 ON a = x) AS j; -- to be denied -+ERROR: SELinux: denied { select } scontext=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 tcontext=unconfined_u:object_r:sepgsql_secret_table_t:s0 tclass=db_column name=t1.c -diff -rpNU3 base/src/test/sepgsql/expected/large_object.out sepgsql-new/src/test/sepgsql/expected/large_object.out ---- base/src/test/sepgsql/expected/large_object.out 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/expected/large_object.out 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,293 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+----------------------------------------------------- -+ unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+(1 row) -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+SET -+DROP TABLE IF EXISTS lolabel CASCADE; -+DROP TABLE -+DROP FUNCTION IF EXISTS lo_label(oid) CASCADE; -+DROP FUNCTION -+RESET client_min_messages; -+RESET -+CREATE TABLE lolabel( -+ loid oid, -+ label text -+); -+CREATE TABLE -+CREATE OR REPLACE FUNCTION lo_label(oid) -+ RETURNS TEXT LANGUAGE 'sql' -+ AS 'SELECT label FROM lolabel WHERE loid = $1'; -+CREATE FUNCTION -+INSERT INTO lolabel (SELECT lo_import('/tmp/sepgsql_test_blob1'), 'normal'); -+INSERT 0 1 -+INSERT INTO lolabel (SELECT lo_import('/tmp/sepgsql_test_blob1'), 'readonly'); -+INSERT 0 1 -+INSERT INTO lolabel (SELECT lo_import('/tmp/sepgsql_test_blob1'), 'secret'); -+INSERT 0 1 -+SELECT lo_set_security(loid, 'system_u:object_r:sepgsql_blob_t:s0') -+ FROM lolabel WHERE label = 'normal'; -+ lo_set_security -+----------------- -+ t -+(1 row) -+ -+SELECT lo_set_security(loid, 'system_u:object_r:sepgsql_ro_blob_t:s0') -+ FROM lolabel WHERE label = 'readonly'; -+ lo_set_security -+----------------- -+ t -+(1 row) -+ -+SELECT lo_set_security(loid, 'system_u:object_r:sepgsql_secret_blob_t:s0') -+ FROM lolabel WHERE label = 'secret'; -+ lo_set_security -+----------------- -+ t -+(1 row) -+ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0:c0 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+------------------------------------------------ -+ unconfined_u:unconfined_r:sepgsql_test_t:s0:c0 -+(1 row) -+ -+SELECT lo_get_security(loid) FROM lolabel; -+ lo_get_security -+-------------------------------------------- -+ system_u:object_r:sepgsql_blob_t:s0 -+ system_u:object_r:sepgsql_ro_blob_t:s0 -+ system_u:object_r:sepgsql_secret_blob_t:s0 -+(3 rows) -+ -+SELECT security_context, lo_label(loid) AS label, COUNT(*) -+ FROM pg_largeobject GROUP BY security_context, loid ORDER by label; -+ security_context | label | count -+--------------------------------------------+----------+------- -+ system_u:object_r:sepgsql_blob_t:s0 | normal | 10 -+ system_u:object_r:sepgsql_ro_blob_t:s0 | readonly | 10 -+ system_u:object_r:sepgsql_secret_blob_t:s0 | secret | 10 -+(3 rows) -+ -+-- read large object -+BEGIN; -+BEGIN -+SELECT lo_open(loid, x'40000'::int) FROM lolabel WHERE label = 'normal'; -+ lo_open -+--------- -+ 0 -+(1 row) -+ -+SELECT loread(0, 32); -+ loread -+---------------------------------------------------------------------------------------------------------------------------------- -+ \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 -+(1 row) -+ -+ROLLBACK; -+ROLLBACK -+BEGIN; -+BEGIN -+SELECT lo_open(loid, x'40000'::int) FROM lolabel WHERE label = 'readonly'; -+ lo_open -+--------- -+ 0 -+(1 row) -+ -+SELECT loread(0, 32); -+ loread -+---------------------------------------------------------------------------------------------------------------------------------- -+ \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 -+(1 row) -+ -+ROLLBACK; -+ROLLBACK -+BEGIN; -+BEGIN -+SELECT lo_open(loid, x'40000'::int) FROM lolabel WHERE label = 'secret'; -+ lo_open -+--------- -+ 0 -+(1 row) -+ -+SELECT loread(0, 32); -- to be denied -+ERROR: SELinux: security policy violation -+ROLLBACK; -+ROLLBACK -+-- write large object -+BEGIN; -+BEGIN -+SELECT lo_open(loid, x'20000'::int) FROM lolabel WHERE label = 'normal'; -+ lo_open -+--------- -+ 0 -+(1 row) -+ -+SELECT lowrite(0, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); -+ lowrite -+--------- -+ 26 -+(1 row) -+ -+ROLLBACK; -+ROLLBACK -+BEGIN; -+BEGIN -+SELECT lo_open(loid, x'20000'::int) FROM lolabel WHERE label = 'readonly'; -+ lo_open -+--------- -+ 0 -+(1 row) -+ -+SELECT lowrite(0, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); -- to be denied -+ERROR: SELinux: security policy violation -+ROLLBACK; -+ROLLBACK -+BEGIN; -+BEGIN -+SELECT lo_open(loid, x'20000'::int) FROM lolabel WHERE label = 'secret'; -+ lo_open -+--------- -+ 0 -+(1 row) -+ -+SELECT lowrite(0, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); -- to be denied -+ERROR: SELinux: security policy violation -+ROLLBACK; -+ROLLBACK -+-- create large object -+BEGIN; -+BEGIN -+INSERT INTO lolabel (SELECT lo_create(6004), 'local'); -+INSERT 0 1 -+SELECT lo_open(loid, x'20000'::int) FROM lolabel WHERE label = 'local'; -+ lo_open -+--------- -+ 0 -+(1 row) -+ -+SELECT lowrite(0, 'abcdefghijklmnopqrstuvwxyz'); -+ lowrite -+--------- -+ 26 -+(1 row) -+ -+SELECT lo_close(0); -+ lo_close -+---------- -+ 0 -+(1 row) -+ -+COMMIT; -+COMMIT -+-- getattr/setattr -+BEGIN; -+BEGIN -+SELECT lo_open(loid, x'20000'::int) FROM lolabel WHERE label = 'local'; -+ lo_open -+--------- -+ 0 -+(1 row) -+ -+SELECT lo_lseek(0, 0, 2); -- seek to end -+ lo_lseek -+---------- -+ 26 -+(1 row) -+ -+SELECT lowrite(0, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); -+ lowrite -+--------- -+ 26 -+(1 row) -+ -+SELECT lo_tell(0); -+ lo_tell -+--------- -+ 52 -+(1 row) -+ -+SELECT lo_lseek(0, 0, 0); -- seek to head -+ lo_lseek -+---------- -+ 0 -+(1 row) -+ -+SELECT loread(0, 50); -+ loread -+---------------------------------------------------- -+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX -+(1 row) -+ -+SELECT lo_close(0); -+ lo_close -+---------- -+ 0 -+(1 row) -+ -+COMMIT; -+COMMIT -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+----------------------------------------------------- -+ unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+(1 row) -+ -+-- change security label -+BEGIN; -+BEGIN -+SELECT lo_open(loid, x'40000'::int) FROM lolabel; -- a seed of trouble -+ lo_open -+--------- -+ 0 -+ 1 -+ 2 -+ 3 -+(4 rows) -+ -+SELECT lo_set_security(loid, 'system_u:object_r:sepgsql_blob_t:s0:c4') -+ FROM lolabel WHERE label in ('normal', 'readonly'); -+ lo_set_security -+----------------- -+ t -+ t -+(2 rows) -+ -+SELECT lo_get_security(loid) FROM lolabel; -+ lo_get_security -+--------------------------------------------------------- -+ system_u:object_r:sepgsql_blob_t:s0:c4 -+ system_u:object_r:sepgsql_blob_t:s0:c4 -+ system_u:object_r:sepgsql_secret_blob_t:s0 -+ unconfined_u:object_r:sepgsql_test_sepgsql_blob_t:s0:c0 -+(4 rows) -+ -+SELECT security_context, lo_label(loid) AS label, count(*) -+ FROM pg_largeobject WHERE loid in (SELECT loid FROM lolabel) -+ GROUP BY security_context, loid ORDER BY label; -+ security_context | label | count -+---------------------------------------------------------+----------+------- -+ unconfined_u:object_r:sepgsql_test_sepgsql_blob_t:s0:c0 | local | 1 -+ system_u:object_r:sepgsql_blob_t:s0:c4 | normal | 10 -+ system_u:object_r:sepgsql_blob_t:s0:c4 | readonly | 10 -+ system_u:object_r:sepgsql_secret_blob_t:s0 | secret | 10 -+(4 rows) -+ -+ROLLBACK; -+ROLLBACK -+-- cleanup -+SELECT lo_unlink(loid) FROM lolabel; -+ lo_unlink -+----------- -+ 1 -+ 1 -+ 1 -+ 1 -+(4 rows) -+ -diff -rpNU3 base/src/test/sepgsql/expected/row_level.out sepgsql-new/src/test/sepgsql/expected/row_level.out ---- base/src/test/sepgsql/expected/row_level.out 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/expected/row_level.out 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,131 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+----------------------------------------------------- -+ unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+(1 row) -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+SET -+DROP TABLE IF EXISTS t4 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t1 CASCADE; -+DROP TABLE -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+DROP FUNCTION -+DROP FUNCTION IF EXISTS f2(int) CASCADE; -+DROP FUNCTION -+RESET client_min_messages; -+RESET -+-- test begins here -+CREATE TABLE t1 ( -+ a int primary key, -+ b text -+); -+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t1_pkey" for table "t1" -+CREATE TABLE -+CREATE TABLE t2 ( -+ x int references t1 (a) on update cascade, -+ y text -+); -+CREATE TABLE -+INSERT INTO t1 (security_context, a, b) VALUES -+ ('system_u:object_r:sepgsql_table_t:s0', 1, 'aaa'), -+ ('system_u:object_r:sepgsql_table_t:s0:c0', 2, 'bbb'), -+ ('system_u:object_r:sepgsql_table_t:s0:c1', 3, 'ccc'), -+ ('system_u:object_r:sepgsql_ro_table_t:s0', 4, 'ddd'), -+ ('system_u:object_r:sepgsql_ro_table_t:s0:c0', 5, 'eee'), -+ ('system_u:object_r:sepgsql_ro_table_t:s0:c1', 6, 'fff'); -+INSERT 0 6 -+INSERT INTO t2 (security_context, x, y) VALUES -+ ('system_u:object_r:sepgsql_table_t:s0:c1', 1, 'xxx'), -+ ('system_u:object_r:sepgsql_table_t:s0:c0', 2, 'yyy'), -+ ('system_u:object_r:sepgsql_table_t:s0', 3, 'zzz'); -+INSERT 0 3 -+SELECT security_context, * FROM t1; -+ security_context | a | b -+--------------------------------------------+---+----- -+ system_u:object_r:sepgsql_table_t:s0 | 1 | aaa -+ system_u:object_r:sepgsql_table_t:s0:c0 | 2 | bbb -+ system_u:object_r:sepgsql_table_t:s0:c1 | 3 | ccc -+ system_u:object_r:sepgsql_ro_table_t:s0 | 4 | ddd -+ system_u:object_r:sepgsql_ro_table_t:s0:c0 | 5 | eee -+ system_u:object_r:sepgsql_ro_table_t:s0:c1 | 6 | fff -+(6 rows) -+ -+SELECT security_context, * FROM t2; -+ security_context | x | y -+-----------------------------------------+---+----- -+ system_u:object_r:sepgsql_table_t:s0:c1 | 1 | xxx -+ system_u:object_r:sepgsql_table_t:s0:c0 | 2 | yyy -+ system_u:object_r:sepgsql_table_t:s0 | 3 | zzz -+(3 rows) -+ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0:c0 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+------------------------------------------------ -+ unconfined_u:unconfined_r:sepgsql_test_t:s0:c0 -+(1 row) -+ -+SELECT security_context, * FROM t1; -+ security_context | a | b -+--------------------------------------------+---+----- -+ system_u:object_r:sepgsql_table_t:s0 | 1 | aaa -+ system_u:object_r:sepgsql_table_t:s0:c0 | 2 | bbb -+ system_u:object_r:sepgsql_ro_table_t:s0 | 4 | ddd -+ system_u:object_r:sepgsql_ro_table_t:s0:c0 | 5 | eee -+(4 rows) -+ -+SELECT security_context, * FROM t2; -+ security_context | x | y -+-----------------------------------------+---+----- -+ system_u:object_r:sepgsql_table_t:s0:c0 | 2 | yyy -+ system_u:object_r:sepgsql_table_t:s0 | 3 | zzz -+(2 rows) -+ -+COPY t1 TO stdout; -+1 aaa -+2 bbb -+4 ddd -+5 eee -+COPY t2 (security_context, x, y) TO stdout; -+system_u:object_r:sepgsql_table_t:s0:c0 2 yyy -+system_u:object_r:sepgsql_table_t:s0 3 zzz -+UPDATE t1 SET a = 99 WHERE a = 1 RETURNING *; -- to be failed -+ERROR: SELinux: security policy violation -+CONTEXT: SQL statement "UPDATE ONLY "public"."t2" SET "x" = $1 WHERE $2 OPERATOR(pg_catalog.=) "x"" -+UPDATE t1 SET a = 99 WHERE a = 2 RETURNING *; -+ a | b -+----+----- -+ 99 | bbb -+(1 row) -+ -+UPDATE 1 -+UPDATE t1 SET a = 99 WHERE a = 4 RETURNING *; -- to be denied -+ a | b -+---+--- -+(0 rows) -+ -+UPDATE 0 -+INSERT INTO t1 VALUES (3, 'ccc'); -- to be failed -+ERROR: duplicate key value violates unique constraint "t1_pkey" -+INSERT INTO t1 VALUES (7, 'ggg'); -+INSERT 0 1 -+INSERT INTO t2 VALUES (3, 'XXX'); -- to be failed -+ERROR: insert or update on table "t2" violates foreign key constraint "t2_x_fkey" -+DETAIL: Key (x)=(3) is not present in table "t1". -+INSERT INTO t2 VALUES (4, 'XXX'); -+INSERT 0 1 -+DELETE FROM t1; -- to be failed -+ERROR: SELinux: security policy violation -+CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."t2" x WHERE $1 OPERATOR(pg_catalog.=) "x" FOR SHARE OF x" -+DELETE FROM t1 WHERE a not in (SELECT x FROM t2); -- to be failed -+ERROR: SELinux: security policy violation -+DELETE FROM t1 WHERE a = 7; -+DELETE 1 -diff -rpNU3 base/src/test/sepgsql/expected/security_label.out sepgsql-new/src/test/sepgsql/expected/security_label.out ---- base/src/test/sepgsql/expected/security_label.out 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/expected/security_label.out 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,127 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+SELECT sepgsql_getcon(); -+ sepgsql_getcon -+----------------------------------------------------- -+ unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+(1 row) -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+SET -+DROP TABLE IF EXISTS t4 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE -+DROP TABLE IF EXISTS t1 CASCADE; -+DROP TABLE -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+DROP FUNCTION -+DROP FUNCTION IF EXISTS f2(int) CASCADE; -+DROP FUNCTION -+RESET client_min_messages; -+RESET -+-- test begins here -+CREATE TABLE t1 ( -+ a int, -+ b text -+); -+CREATE TABLE -+CREATE TABLE t2 ( -+ x int, -+ y text -+); -+CREATE TABLE -+CREATE TABLE t3 ( -+ s int, -+ t text -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_fixed_table_t:s0'; -+CREATE TABLE -+INSERT INTO t1 VALUES (1, 'aaa'); -+INSERT 0 1 -+INSERT INTO t1 (security_context, a, b) VALUES ('unconfined_u:object_r:sepgsql_ro_table_t:s0', 2, 'bbb'); -+INSERT 0 1 -+INSERT INTO t1 (security_context, a, b) VALUES ('unconfined_u:object_r:sepgsql_table_t:s0:c1', 3, 'ccc'); -+INSERT 0 1 -+INSERT INTO t1 VALUES (4, 'ddd'), (5, 'eee'); -+INSERT 0 2 -+INSERT INTO t1 (security_context, a, b) VALUES ('invalid security context', 6, 'fff'); -- to be failed -+ERROR: invalid security label: invalid security context -+INSERT INTO t1 (security_context, a, b) VALUES ('system_u:object_r:sepgsql_table_t:s0:c20', 6, 'fff'); -- to be denied -+INSERT 0 0 -+SELECT security_context, * FROM t1; -+ security_context | a | b -+---------------------------------------------+---+----- -+ unconfined_u:object_r:sepgsql_table_t:s0 | 1 | aaa -+ unconfined_u:object_r:sepgsql_ro_table_t:s0 | 2 | bbb -+ unconfined_u:object_r:sepgsql_table_t:s0:c1 | 3 | ccc -+ unconfined_u:object_r:sepgsql_table_t:s0 | 4 | ddd -+ unconfined_u:object_r:sepgsql_table_t:s0 | 5 | eee -+(5 rows) -+ -+INSERT INTO t2 (security_context, x, y) -+ (SELECT sepgsql_set_user(security_context, 'system_u'), a + 5, b || '_cpy' FROM t1); -+INSERT 0 5 -+SELECT security_context, * FROM t2; -+ security_context | x | y -+-----------------------------------------+----+--------- -+ system_u:object_r:sepgsql_table_t:s0 | 6 | aaa_cpy -+ system_u:object_r:sepgsql_ro_table_t:s0 | 7 | bbb_cpy -+ system_u:object_r:sepgsql_table_t:s0:c1 | 8 | ccc_cpy -+ system_u:object_r:sepgsql_table_t:s0 | 9 | ddd_cpy -+ system_u:object_r:sepgsql_table_t:s0 | 10 | eee_cpy -+(5 rows) -+ -+INSERT INTO t3 VALUES (98, 'xxx'); -+INSERT 0 1 -+INSERT INTO t3 (security_context, s, t) VALUES ('system_u:object_r:sepgsql_ro_table_t:s0', 99, 'yyy'); -+INSERT 0 1 -+INSERT INTO t3 (SELECT * FROM t1); -+INSERT 0 5 -+INSERT INTO t3 (security_context, s, t) (SELECT security_context, x, y FROM t2); -+INSERT 0 5 -+SELECT security_context, * FROM t3; -+ security_context | s | t -+------------------------------------------------+----+--------- -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0 | 98 | xxx -+ system_u:object_r:sepgsql_ro_table_t:s0 | 99 | yyy -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0 | 1 | aaa -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0 | 2 | bbb -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0 | 3 | ccc -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0 | 4 | ddd -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0 | 5 | eee -+ system_u:object_r:sepgsql_table_t:s0 | 6 | aaa_cpy -+ system_u:object_r:sepgsql_ro_table_t:s0 | 7 | bbb_cpy -+ system_u:object_r:sepgsql_table_t:s0:c1 | 8 | ccc_cpy -+ system_u:object_r:sepgsql_table_t:s0 | 9 | ddd_cpy -+ system_u:object_r:sepgsql_table_t:s0 | 10 | eee_cpy -+(12 rows) -+ -+SELECT sepgsql_set_range(security_context, 's0:c' || s) AS security_context, * INTO t4 FROM t3; -- partially denied -+SELECT -+SELECT security_context, * FROM t4; -+ security_context | s | t -+---------------------------------------------------+----+--------- -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0:c1 | 1 | aaa -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0:c2 | 2 | bbb -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0:c3 | 3 | ccc -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0:c4 | 4 | ddd -+ unconfined_u:object_r:sepgsql_fixed_table_t:s0:c5 | 5 | eee -+ system_u:object_r:sepgsql_table_t:s0:c6 | 6 | aaa_cpy -+ system_u:object_r:sepgsql_ro_table_t:s0:c7 | 7 | bbb_cpy -+ system_u:object_r:sepgsql_table_t:s0:c8 | 8 | ccc_cpy -+ system_u:object_r:sepgsql_table_t:s0:c9 | 9 | ddd_cpy -+ system_u:object_r:sepgsql_table_t:s0:c10 | 10 | eee_cpy -+(10 rows) -+ -+COPY t1 (security_context, a, b) FROM stdin; -- partially denied -+COPY t1 (security_context, a, b) TO stdout; -+unconfined_u:object_r:sepgsql_table_t:s0 1 aaa -+unconfined_u:object_r:sepgsql_ro_table_t:s0 2 bbb -+unconfined_u:object_r:sepgsql_table_t:s0:c1 3 ccc -+unconfined_u:object_r:sepgsql_table_t:s0 4 ddd -+unconfined_u:object_r:sepgsql_table_t:s0 5 eee -+system_u:object_r:sepgsql_table_t:s0:c2 10 kkk -+system_u:object_r:sepgsql_table_t:s0:c3 11 lll -+system_u:object_r:sepgsql_table_t:s0:c4 13 nnn -diff -rpNU3 base/src/test/sepgsql/launch_psql.c sepgsql-new/src/test/sepgsql/launch_psql.c ---- base/src/test/sepgsql/launch_psql.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/launch_psql.c 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,87 @@ -+/* -+ * launch_psql.c -+ * -+ * It invokes psql with proper security context. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define SETEXECCON_CMD "--@SECURITY_CONTEXT=" -+ -+int main(int argc, char *const argv[]) -+{ -+ char buffer[2048], cmd[512]; -+ FILE *filp = NULL; -+ int i, ofs; -+ -+ if (argc < 2) -+ { -+ fprintf(stderr, "usage: %s [ ...]\n", argv[0]); -+ return 1; -+ } -+ -+ for (i=1, ofs=0; argv[i] != NULL; i++) -+ ofs += snprintf(cmd + ofs, sizeof(cmd) - ofs, " %s", argv[i]); -+ -+ while (fgets(buffer, sizeof(buffer), stdin) != NULL) -+ { -+ if (strncasecmp(buffer, SETEXECCON_CMD, -+ sizeof(SETEXECCON_CMD) - 1) == 0) -+ { -+ security_context_t context = buffer + sizeof(SETEXECCON_CMD) - 1; -+ char *pos; -+ -+ /* set exec security context */ -+ pos = strchr(context, '#'); -+ if (pos) -+ *pos = '\0'; -+ pos = context + strlen(context) - 1; -+ while (isspace(*pos)) -+ *pos-- = '\0'; -+ if (setexeccon(context) < 0) -+ { -+ fprintf(stderr, "%s: setexeccon('%s') = %s\n", -+ argv[0], context, strerror(errno)); -+ return 1; -+ } -+ -+ if (filp != NULL) -+ { -+ pclose(filp); -+ filp = NULL; -+ } -+ -+ /* Inject a pseudo sepgsql_getcon() to confirm new context */ -+ ofs = strlen(buffer); -+ snprintf(buffer + ofs, sizeof(buffer) - ofs, -+ "\nSELECT sepgsql_getcon();\n"); -+ } -+ -+ if (filp == NULL) -+ { -+ filp = popen(cmd, "w"); -+ if (!filp) -+ { -+ fprintf(stderr, "%s: popen('%s', 'w') = %s\n", -+ argv[0], cmd, strerror(errno)); -+ return 1; -+ } -+ } -+ -+ if (fwrite(buffer, 1, strlen(buffer), filp) < 0) -+ { -+ fprintf(stderr, "%s: fwrite(...) = %s\n", -+ argv[0], strerror(errno)); -+ return 1; -+ } -+ } -+ -+ if (filp) -+ pclose(filp); -+ -+ return 0; -+} -diff -rpNU3 base/src/test/sepgsql/sql/basic.sql sepgsql-new/src/test/sepgsql/sql/basic.sql ---- base/src/test/sepgsql/sql/basic.sql 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/sql/basic.sql 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,59 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+ -+DROP TABLE IF EXISTS t4 CASCADE; -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE IF EXISTS t1 CASCADE; -+ -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+ -+RESET client_min_messages; -+ -+-- SETUP -+ -+CREATE TABLE t1 -+( -+ a int, -+ b text -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_ro_table_t:s0', -+ c bool -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0' -+); -+INSERT INTO t1 VALUES (1, 'aaa', false), (2, 'bbb', true); -+ -+CREATE TABLE t2 -+( -+ s int, -+ t int, -+ u int -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_table_t:s0:c0'; -+ALTER TABLE t2 DROP COLUMN t; -- disturbing factor -+ -+CREATE TABLE t3 -+( -+ x text -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_table_t:s0:c1' -+) inherits(t2); -+ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 -+ -+SELECT * FROM t1; -- to be denied -+SELECT a, b FROM t1; -+SELECT COUNT(*) FROM t1 WHERE c; -- to be denied -+UPDATE t1 SET b = 'ccc'; -- to be denied -+UPDATE t1 SET a = a + 2; -+INSERT INTO t1 VALUES (5, 'eee', true); -- to be denied -+INSERT INTO t1 VALUES (5); -+ -+SELECT * FROM t2; -+SELECT t2 FROM t2; -+SELECT t3 FROM t3; -- to be denied -+SELECT 1 FROM t3; -+ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c1 -+SELECT * FROM t2; -- to be denied -+SELECT t2 FROM t2; -- to be denied -+SELECT t3 FROM t3; -diff -rpNU3 base/src/test/sepgsql/sql/copy_stmt.sql sepgsql-new/src/test/sepgsql/sql/copy_stmt.sql ---- base/src/test/sepgsql/sql/copy_stmt.sql 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/sql/copy_stmt.sql 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,58 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+ -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE IF EXISTS t1 CASCADE; -+ -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+ -+RESET client_min_messages; -+ -+-- setup tables -+ -+CREATE TABLE t1 -+( -+ a int, -+ b text -+); -+ -+INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'); -+ -+CREATE TABLE t2 -+( -+ x int, -+ y text -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0' -+); -+SELECT security_context from pg_attribute where attrelid = 't2'::regclass and attname = 'y'; -+INSERT INTO t2 VALUES (1, 'xxx'), (2, 'yyy'); -+ -+CREATE TABLE t3 -- read only table -+( -+ s int, -+ t text -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_ro_table_t:s0'; -+INSERT INTO t2 VALUES (1, 'sss'), (2, 'ttt'); -+ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 -+COPY t1 TO stdout; -+COPY t1 FROM stdin; -+3 ccc -+4 ddd -+\. -+ -+COPY t1 TO '/tmp/sepgsql_test_copy_1'; -+COPY t1 TO '/tmp/sepgsql_test_copy_2'; -- to be denied -+ -+COPY t2 TO stdout; -- to be denied -+COPY t2 FROM stdin; -- to be denied -+COPY t2 (x) TO stdout; -+ -+COPY t3 TO stdout; -+COPY t3 FROM '/tmp/sepgsql_test_copy_1'; -- to be denied -+ -+COPY t1 FROM '/tmp/sepgsql_test_copy_1'; -+COPY t1 TO stdout; -diff -rpNU3 base/src/test/sepgsql/sql/enhanced_ddl_stmt.sql sepgsql-new/src/test/sepgsql/sql/enhanced_ddl_stmt.sql ---- base/src/test/sepgsql/sql/enhanced_ddl_stmt.sql 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/sql/enhanced_ddl_stmt.sql 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,89 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+ -+DROP TABLE IF EXISTS t4 CASCADE; -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE IF EXISTS t1 CASCADE; -+ -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+DROP FUNCTION IF EXISTS f2(int) CASCADE; -+ -+RESET client_min_messages; -+ -+-- CREATE TABLE with SECURITY_LABEL clause -+CREATE TABLE t1 ( -+ a int, -+ b text -+); -+SELECT relname, security_context FROM pg_class WHERE oid = 't1'::regclass; -+SELECT attname, security_context FROM pg_attribute WHERE attrelid = 't1'::regclass and attnum > 0; -+ -+CREATE TABLE t2 ( -+ a int, -+ b text -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_ro_table_t:s0'; -+SELECT relname, security_context FROM pg_class WHERE oid = 't2'::regclass; -+SELECT attname, security_context FROM pg_attribute WHERE attrelid = 't2'::regclass and attnum > 0; -+ -+CREATE TABLE t3 ( -+ a int, -+ b text SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_fixed_table_t:s0', -+ c bool SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0', -+ d int -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_table_t:s0:c0'; -+SELECT relname, security_context FROM pg_class WHERE oid = 't3'::regclass; -+SELECT attname, security_context FROM pg_attribute WHERE attrelid = 't3'::regclass and attnum > 0; -+ -+CREATE TABLE t4 ( -+ a int, -+ b text -+) SECURITY_CONTEXT = 'unconfined_u:object_r:invalid_label_t:s0'; -- to be failed -+ -+CREATE TABLE t4 ( -+ a int, -+ b text -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_proc_t:s0'; -- to be denied -+ -+-- ALTER TABLE with SECURITY_CONTEXT clause -+ALTER TABLE t2 SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0'; -+ALTER TABLE t2 ADD COLUMN c bool; -- it inherits table's one -+SELECT relname, security_context FROM pg_class WHERE oid = 't2'::regclass; -+SELECT attname, security_context FROM pg_attribute WHERE attrelid = 't2'::regclass and attnum > 0; -+ -+ALTER TABLE t3 ALTER b SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_table_t:s0'; -+SELECT relname, security_context FROM pg_class WHERE oid = 't3'::regclass; -+SELECT attname, security_context FROM pg_attribute WHERE attrelid = 't3'::regclass and attnum > 0; -+ -+-- CREATE FUNCTION with SECURITY_CONTEXT clause -+CREATE FUNCTION f1 (int) RETURNS int -+ LANGUAGE 'sql' -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_proc_t:s0:c0' -+ AS 'SELECT $1 * 2'; -+SELECT proname, security_context FROM pg_proc WHERE oid = 'f1'::regproc; -+ -+CREATE FUNCTION f2 (int) RETURNS int -+ LANGUAGE 'sql' -+ SECURITY_CONTEXT = 'unconfined_u:object_r:invalid_label_t:s0' -+ AS 'SELECT $1 + $1'; -- to be failed -+ -+CREATE FUNCTION f2 (int) RETURNS int -+ LANGUAGE 'sql' -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_proc_t:s0:c16' -+ AS 'SELECT $1 + $1'; -- to be denied -+ -+CREATE FUNCTION f2 (int) RETURNS int -+ LANGUAGE 'sql' -+ AS 'SELECT $1 + $1'; -+SELECT proname, security_context FROM pg_proc WHERE oid = 'f2'::regproc; -+ -+-- ALTER FUNCTION with SECURITY_CONTEXT clause -+ALTER FUNCTION f1(int) -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_proc_t:s0:c1'; -+SELECT proname, security_context FROM pg_proc WHERE oid = 'f1'::regproc; -+ -+ALTER FUNCTION f2(int) -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_proc_t:s0:c16'; -- to be denied -+SELECT proname, security_context FROM pg_proc WHERE oid = 'f2'::regproc; -diff -rpNU3 base/src/test/sepgsql/sql/join_query.sql sepgsql-new/src/test/sepgsql/sql/join_query.sql ---- base/src/test/sepgsql/sql/join_query.sql 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/sql/join_query.sql 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,50 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+ -+DROP TABLE IF EXISTS t4 CASCADE; -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE IF EXISTS t1 CASCADE; -+ -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+ -+RESET client_min_messages; -+ -+-- SETUP -+CREATE TABLE t1 -+( -+ a int, -+ b text, -+ c int -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0' -+); -+INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'), (3, 'ccc'); -+ -+CREATE TABLE t2 -+( -+ x int, -+ y text -+); -+INSERT INTO t2 VALUES (2, 'xxx'), (3, 'yyy'), (4,'zzz'); -+ -+CREATE TABLE t3 -+( -+ d int -+) INHERITS (t1); -+INSERT INTO t3 VALUES (4, 'ddd'), (5, 'eee'); -+ -+CREATE TABLE t4 -+( -+ z int -+ SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_secret_table_t:s0' -+) INHERITS (t2); -+INSERT INTO t2 VALUES (1, 'sss'), (5, 'ttt'); -+ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0-s0:c0 -+SELECT * FROM t1 JOIN t2 ON a = x; -- to be denied -+SELECT a, b, y FROM t1 JOIN t2 ON a = x; -+SELECT a, b, y FROM t1 JOIN t2 ON c = x; -- to be denied -+SELECT COUNT(*) FROM t1 JOIN t2 ON a = x; -+SELECT j FROM (t1 JOIN t2 ON a = x) AS j; -- to be denied -diff -rpNU3 base/src/test/sepgsql/sql/large_object.sql sepgsql-new/src/test/sepgsql/sql/large_object.sql ---- base/src/test/sepgsql/sql/large_object.sql 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/sql/large_object.sql 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,103 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+ -+DROP TABLE IF EXISTS lolabel CASCADE; -+DROP FUNCTION IF EXISTS lo_label(oid) CASCADE; -+ -+RESET client_min_messages; -+ -+CREATE TABLE lolabel( -+ loid oid, -+ label text -+); -+ -+CREATE OR REPLACE FUNCTION lo_label(oid) -+ RETURNS TEXT LANGUAGE 'sql' -+ AS 'SELECT label FROM lolabel WHERE loid = $1'; -+ -+INSERT INTO lolabel (SELECT lo_import('/tmp/sepgsql_test_blob1'), 'normal'); -+INSERT INTO lolabel (SELECT lo_import('/tmp/sepgsql_test_blob1'), 'readonly'); -+INSERT INTO lolabel (SELECT lo_import('/tmp/sepgsql_test_blob1'), 'secret'); -+ -+SELECT lo_set_security(loid, 'system_u:object_r:sepgsql_blob_t:s0') -+ FROM lolabel WHERE label = 'normal'; -+SELECT lo_set_security(loid, 'system_u:object_r:sepgsql_ro_blob_t:s0') -+ FROM lolabel WHERE label = 'readonly'; -+SELECT lo_set_security(loid, 'system_u:object_r:sepgsql_secret_blob_t:s0') -+ FROM lolabel WHERE label = 'secret'; -+ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0:c0 -+ -+SELECT lo_get_security(loid) FROM lolabel; -+ -+SELECT security_context, lo_label(loid) AS label, COUNT(*) -+ FROM pg_largeobject GROUP BY security_context, loid ORDER by label; -+ -+-- read large object -+BEGIN; -+SELECT lo_open(loid, x'40000'::int) FROM lolabel WHERE label = 'normal'; -+SELECT loread(0, 32); -+ROLLBACK; -+ -+BEGIN; -+SELECT lo_open(loid, x'40000'::int) FROM lolabel WHERE label = 'readonly'; -+SELECT loread(0, 32); -+ROLLBACK; -+ -+BEGIN; -+SELECT lo_open(loid, x'40000'::int) FROM lolabel WHERE label = 'secret'; -+SELECT loread(0, 32); -- to be denied -+ROLLBACK; -+ -+-- write large object -+BEGIN; -+SELECT lo_open(loid, x'20000'::int) FROM lolabel WHERE label = 'normal'; -+SELECT lowrite(0, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); -+ROLLBACK; -+ -+BEGIN; -+SELECT lo_open(loid, x'20000'::int) FROM lolabel WHERE label = 'readonly'; -+SELECT lowrite(0, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); -- to be denied -+ROLLBACK; -+ -+BEGIN; -+SELECT lo_open(loid, x'20000'::int) FROM lolabel WHERE label = 'secret'; -+SELECT lowrite(0, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); -- to be denied -+ROLLBACK; -+ -+-- create large object -+BEGIN; -+INSERT INTO lolabel (SELECT lo_create(6004), 'local'); -+SELECT lo_open(loid, x'20000'::int) FROM lolabel WHERE label = 'local'; -+SELECT lowrite(0, 'abcdefghijklmnopqrstuvwxyz'); -+SELECT lo_close(0); -+COMMIT; -+ -+-- getattr/setattr -+BEGIN; -+SELECT lo_open(loid, x'20000'::int) FROM lolabel WHERE label = 'local'; -+SELECT lo_lseek(0, 0, 2); -- seek to end -+SELECT lowrite(0, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); -+SELECT lo_tell(0); -+SELECT lo_lseek(0, 0, 0); -- seek to head -+SELECT loread(0, 50); -+SELECT lo_close(0); -+COMMIT; -+ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+ -+-- change security label -+BEGIN; -+SELECT lo_open(loid, x'40000'::int) FROM lolabel; -- a seed of trouble -+SELECT lo_set_security(loid, 'system_u:object_r:sepgsql_blob_t:s0:c4') -+ FROM lolabel WHERE label in ('normal', 'readonly'); -+SELECT lo_get_security(loid) FROM lolabel; -+SELECT security_context, lo_label(loid) AS label, count(*) -+ FROM pg_largeobject WHERE loid in (SELECT loid FROM lolabel) -+ GROUP BY security_context, loid ORDER BY label; -+ROLLBACK; -+ -+-- cleanup -+SELECT lo_unlink(loid) FROM lolabel; -diff -rpNU3 base/src/test/sepgsql/sql/row_level.sql sepgsql-new/src/test/sepgsql/sql/row_level.sql ---- base/src/test/sepgsql/sql/row_level.sql 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/sql/row_level.sql 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,61 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+ -+DROP TABLE IF EXISTS t4 CASCADE; -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE IF EXISTS t1 CASCADE; -+ -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+DROP FUNCTION IF EXISTS f2(int) CASCADE; -+ -+RESET client_min_messages; -+ -+-- test begins here -+CREATE TABLE t1 ( -+ a int primary key, -+ b text -+); -+ -+CREATE TABLE t2 ( -+ x int references t1 (a) on update cascade, -+ y text -+); -+ -+INSERT INTO t1 (security_context, a, b) VALUES -+ ('system_u:object_r:sepgsql_table_t:s0', 1, 'aaa'), -+ ('system_u:object_r:sepgsql_table_t:s0:c0', 2, 'bbb'), -+ ('system_u:object_r:sepgsql_table_t:s0:c1', 3, 'ccc'), -+ ('system_u:object_r:sepgsql_ro_table_t:s0', 4, 'ddd'), -+ ('system_u:object_r:sepgsql_ro_table_t:s0:c0', 5, 'eee'), -+ ('system_u:object_r:sepgsql_ro_table_t:s0:c1', 6, 'fff'); -+ -+INSERT INTO t2 (security_context, x, y) VALUES -+ ('system_u:object_r:sepgsql_table_t:s0:c1', 1, 'xxx'), -+ ('system_u:object_r:sepgsql_table_t:s0:c0', 2, 'yyy'), -+ ('system_u:object_r:sepgsql_table_t:s0', 3, 'zzz'); -+ -+SELECT security_context, * FROM t1; -+SELECT security_context, * FROM t2; -+ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:sepgsql_test_t:s0:c0 -+SELECT security_context, * FROM t1; -+SELECT security_context, * FROM t2; -+ -+COPY t1 TO stdout; -+COPY t2 (security_context, x, y) TO stdout; -+ -+UPDATE t1 SET a = 99 WHERE a = 1 RETURNING *; -- to be failed -+UPDATE t1 SET a = 99 WHERE a = 2 RETURNING *; -+UPDATE t1 SET a = 99 WHERE a = 4 RETURNING *; -- to be denied -+ -+INSERT INTO t1 VALUES (3, 'ccc'); -- to be failed -+INSERT INTO t1 VALUES (7, 'ggg'); -+INSERT INTO t2 VALUES (3, 'XXX'); -- to be failed -+INSERT INTO t2 VALUES (4, 'XXX'); -+ -+DELETE FROM t1; -- to be failed -+DELETE FROM t1 WHERE a not in (SELECT x FROM t2); -- to be failed -+DELETE FROM t1 WHERE a = 7; -diff -rpNU3 base/src/test/sepgsql/sql/security_label.sql sepgsql-new/src/test/sepgsql/sql/security_label.sql ---- base/src/test/sepgsql/sql/security_label.sql 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql-new/src/test/sepgsql/sql/security_label.sql 2009-03-15 17:38:39.000000000 +0900 -@@ -0,0 +1,60 @@ -+--@SECURITY_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c15 -+ -+-- cleanup previous tests -+SET client_min_messages TO 'error'; -+ -+DROP TABLE IF EXISTS t4 CASCADE; -+DROP TABLE IF EXISTS t3 CASCADE; -+DROP TABLE IF EXISTS t2 CASCADE; -+DROP TABLE IF EXISTS t1 CASCADE; -+ -+DROP FUNCTION IF EXISTS f1(int) CASCADE; -+DROP FUNCTION IF EXISTS f2(int) CASCADE; -+ -+RESET client_min_messages; -+ -+-- test begins here -+CREATE TABLE t1 ( -+ a int, -+ b text -+); -+ -+CREATE TABLE t2 ( -+ x int, -+ y text -+); -+ -+CREATE TABLE t3 ( -+ s int, -+ t text -+) SECURITY_CONTEXT = 'unconfined_u:object_r:sepgsql_fixed_table_t:s0'; -+ -+INSERT INTO t1 VALUES (1, 'aaa'); -+INSERT INTO t1 (security_context, a, b) VALUES ('unconfined_u:object_r:sepgsql_ro_table_t:s0', 2, 'bbb'); -+INSERT INTO t1 (security_context, a, b) VALUES ('unconfined_u:object_r:sepgsql_table_t:s0:c1', 3, 'ccc'); -+INSERT INTO t1 VALUES (4, 'ddd'), (5, 'eee'); -+INSERT INTO t1 (security_context, a, b) VALUES ('invalid security context', 6, 'fff'); -- to be failed -+INSERT INTO t1 (security_context, a, b) VALUES ('system_u:object_r:sepgsql_table_t:s0:c20', 6, 'fff'); -- to be denied -+SELECT security_context, * FROM t1; -+ -+INSERT INTO t2 (security_context, x, y) -+ (SELECT sepgsql_set_user(security_context, 'system_u'), a + 5, b || '_cpy' FROM t1); -+SELECT security_context, * FROM t2; -+ -+INSERT INTO t3 VALUES (98, 'xxx'); -+INSERT INTO t3 (security_context, s, t) VALUES ('system_u:object_r:sepgsql_ro_table_t:s0', 99, 'yyy'); -+INSERT INTO t3 (SELECT * FROM t1); -+INSERT INTO t3 (security_context, s, t) (SELECT security_context, x, y FROM t2); -+SELECT security_context, * FROM t3; -+ -+SELECT sepgsql_set_range(security_context, 's0:c' || s) AS security_context, * INTO t4 FROM t3; -- partially denied -+SELECT security_context, * FROM t4; -+ -+COPY t1 (security_context, a, b) FROM stdin; -- partially denied -+system_u:object_r:sepgsql_table_t:s0:c2 10 kkk -+system_u:object_r:sepgsql_table_t:s0:c3 11 lll -+system_u:object_r:sepgsql_table_t:s0:c20 12 mmm -+system_u:object_r:sepgsql_table_t:s0:c4 13 nnn -+\. -+ -+COPY t1 (security_context, a, b) TO stdout; diff --git a/sepostgresql-utils-8.3.patch b/sepostgresql-utils-8.3.patch deleted file mode 100644 index 7fab346..0000000 --- a/sepostgresql-utils-8.3.patch +++ /dev/null @@ -1,624 +0,0 @@ -diff -rpNU3 base/src/bin/initdb/initdb.c sepgsql-new/src/bin/initdb/initdb.c ---- base/src/bin/initdb/initdb.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql-new/src/bin/initdb/initdb.c 2009-03-13 18:14:33.000000000 +0900 -@@ -94,6 +94,7 @@ static bool debug = false; - static bool noclean = false; - static bool show_setting = false; - static char *xlog_dir = ""; -+static bool enable_selinux = false; - - - /* internal vars */ -@@ -1212,6 +1213,13 @@ setup_config(void) - "#default_text_search_config = 'pg_catalog.simple'", - repltok); - -+ if (enable_selinux) -+ { -+ strcpy(repltok, "sepostgresql = on"); -+ conflines = replace_token(conflines, -+ "#sepostgresql = off", repltok); -+ } -+ - snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); - - writefile(path, conflines); -@@ -2383,6 +2391,7 @@ usage(const char *progname) - printf(_(" -U, --username=NAME database superuser name\n")); - printf(_(" -W, --pwprompt prompt for a password for the new superuser\n")); - printf(_(" --pwfile=FILE read password for the new superuser from file\n")); -+ printf(_(" --enable-selinux enables SELinux support, if compiled\n")); - printf(_(" -?, --help show this help, then exit\n")); - printf(_(" -V, --version output version information, then exit\n")); - printf(_("\nLess commonly used options:\n")); -@@ -2417,6 +2426,7 @@ main(int argc, char *argv[]) - {"auth", required_argument, NULL, 'A'}, - {"pwprompt", no_argument, NULL, 'W'}, - {"pwfile", required_argument, NULL, 9}, -+ {"enable-selinux", no_argument, NULL, 10}, - {"username", required_argument, NULL, 'U'}, - {"help", no_argument, NULL, '?'}, - {"version", no_argument, NULL, 'V'}, -@@ -2531,6 +2541,9 @@ main(int argc, char *argv[]) - case 9: - pwfilename = xstrdup(optarg); - break; -+ case 10: -+ enable_selinux = true; -+ break; - case 's': - show_setting = true; - break; -diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql-new/src/bin/pg_dump/pg_dump.c ---- base/src/bin/pg_dump/pg_dump.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/bin/pg_dump/pg_dump.c 2009-03-13 18:14:33.000000000 +0900 -@@ -118,6 +118,8 @@ static int g_numNamespaces; - /* flag to turn on/off dollar quoting */ - static int disable_dollar_quoting = 0; - -+/* flag to turn on/off security context support */ -+static int enable_selinux = 0; - - static void help(const char *progname); - static void expand_schema_name_patterns(SimpleStringList *patterns, -@@ -267,6 +269,7 @@ main(int argc, char **argv) - {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1}, - {"disable-triggers", no_argument, &disable_triggers, 1}, - {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, -+ {"security-context", no_argument, &enable_selinux, 1}, - - {NULL, 0, NULL, 0} - }; -@@ -419,6 +422,8 @@ main(int argc, char **argv) - disable_triggers = 1; - else if (strcmp(optarg, "use-set-session-authorization") == 0) - use_setsessauth = 1; -+ else if (strcmp(optarg, "security-context") == 0) -+ enable_selinux = 1; - else - { - fprintf(stderr, -@@ -549,6 +554,24 @@ main(int argc, char **argv) - std_strings = PQparameterStatus(g_conn, "standard_conforming_strings"); - g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0); - -+ /* check availability of SE-PostgreSQL */ -+ if (enable_selinux > 0) -+ { -+ const char *sepostgresql -+ = PQparameterStatus(g_conn, "sepostgresql"); -+ -+ if (!sepostgresql) -+ { -+ write_msg(NULL, "could not obtain server status."); -+ exit(1); -+ } -+ if (strcmp(sepostgresql, "on") != 0) -+ { -+ write_msg(NULL, "SE-PostgreSQL is not available now."); -+ exit(1); -+ } -+ } -+ - /* Set the datestyle to ISO to ensure the dump's portability */ - do_sql_command(g_conn, "SET DATESTYLE = ISO"); - -@@ -771,6 +794,7 @@ help(const char *progname) - printf(_(" --use-set-session-authorization\n" - " use SESSION AUTHORIZATION commands instead of\n" - " ALTER OWNER commands to set ownership\n")); -+ printf(_(" --security-context enable to dump security context of SE-PostgreSQL\n")); - - printf(_("\nConnection options:\n")); - printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); -@@ -1171,7 +1195,8 @@ dumpTableData_insert(Archive *fout, void - if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " -- "SELECT * FROM ONLY %s", -+ "SELECT %s * FROM ONLY %s", -+ (enable_selinux > 0 ? "security_context," : ""), - fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, - classname)); - } -@@ -1785,11 +1810,29 @@ dumpBlobComments(Archive *AH, void *arg) - Oid blobOid; - char *comment; - -+ blobOid = atooid(PQgetvalue(res, i, 0)); -+ if (enable_selinux > 0) -+ { -+ char query[256]; -+ PGresult *sres; -+ -+ snprintf(query, sizeof(query), -+ "SELECT lo_get_security(%u)", blobOid); -+ sres = PQexec(g_conn, query); -+ if (sres) -+ { -+ if (PQresultStatus(res) == PGRES_TUPLES_OK -+ && PQntuples(res) == 1) -+ archprintf(AH, "SELECT lo_set_security(%u, '%s');\n", -+ blobOid, PQgetvalue(sres, 0, 0)); -+ PQclear(sres); -+ } -+ } -+ - /* ignore blobs without comments */ - if (PQgetisnull(res, i, 1)) - continue; - -- blobOid = atooid(PQgetvalue(res, i, 0)); - comment = PQgetvalue(res, i, 1); - - printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ", -@@ -2887,6 +2930,7 @@ getTables(int *numTables) - int i_owning_col; - int i_reltablespace; - int i_reloptions; -+ int i_relseclabel; - - /* Make sure we are in proper schema */ - selectSourceSchema("pg_catalog"); -@@ -2926,7 +2970,8 @@ getTables(int *numTables) - "d.refobjid as owning_tab, " - "d.refobjsubid as owning_col, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " -- "array_to_string(c.reloptions, ', ') as reloptions " -+ "array_to_string(c.reloptions, ', ') as reloptions, " -+ "%s as security_label " - "from pg_class c " - "left join pg_depend d on " - "(c.relkind = '%c' and " -@@ -2936,6 +2981,7 @@ getTables(int *numTables) - "where relkind in ('%c', '%c', '%c', '%c') " - "order by c.oid", - username_subquery, -+ (enable_selinux > 0 ? "c.security_context" : "NULL"), - RELKIND_SEQUENCE, - RELKIND_RELATION, RELKIND_SEQUENCE, - RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); -@@ -2955,7 +3001,8 @@ getTables(int *numTables) - "d.refobjid as owning_tab, " - "d.refobjsubid as owning_col, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " -- "NULL as reloptions " -+ "NULL as reloptions, " -+ "NULL as security_label " - "from pg_class c " - "left join pg_depend d on " - "(c.relkind = '%c' and " -@@ -2984,7 +3031,8 @@ getTables(int *numTables) - "d.refobjid as owning_tab, " - "d.refobjsubid as owning_col, " - "NULL as reltablespace, " -- "NULL as reloptions " -+ "NULL as reloptions, " -+ "NULL as security_label, " - "from pg_class c " - "left join pg_depend d on " - "(c.relkind = '%c' and " -@@ -3009,7 +3057,8 @@ getTables(int *numTables) - "NULL::oid as owning_tab, " - "NULL::int4 as owning_col, " - "NULL as reltablespace, " -- "NULL as reloptions " -+ "NULL as reloptions, " -+ "NULL as security_label, " - "from pg_class " - "where relkind in ('%c', '%c', '%c') " - "order by oid", -@@ -3029,7 +3078,8 @@ getTables(int *numTables) - "NULL::oid as owning_tab, " - "NULL::int4 as owning_col, " - "NULL as reltablespace, " -- "NULL as reloptions " -+ "NULL as reloptions, " -+ "NULL as security_label " - "from pg_class " - "where relkind in ('%c', '%c', '%c') " - "order by oid", -@@ -3059,7 +3109,8 @@ getTables(int *numTables) - "NULL::oid as owning_tab, " - "NULL::int4 as owning_col, " - "NULL as reltablespace, " -- "NULL as reloptions " -+ "NULL as reloptions, " -+ "NULL as security_label " - "from pg_class c " - "where relkind in ('%c', '%c') " - "order by oid", -@@ -3102,6 +3153,7 @@ getTables(int *numTables) - i_owning_col = PQfnumber(res, "owning_col"); - i_reltablespace = PQfnumber(res, "reltablespace"); - i_reloptions = PQfnumber(res, "reloptions"); -+ i_relseclabel = PQfnumber(res, "security_label"); - - for (i = 0; i < ntups; i++) - { -@@ -3132,6 +3184,7 @@ getTables(int *numTables) - } - tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace)); - tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions)); -+ tblinfo[i].relseclabel = strdup(PQgetvalue(res, i, i_relseclabel)); - - /* other fields were zeroed above */ - -@@ -4320,6 +4373,7 @@ getTableAttrs(TableInfo *tblinfo, int nu - int i_atthasdef; - int i_attisdropped; - int i_attislocal; -+ int i_attseclabel; - PGresult *res; - int ntups; - bool hasdefaults; -@@ -4362,12 +4416,14 @@ getTableAttrs(TableInfo *tblinfo, int nu - /* need left join here to not fail on dropped columns ... */ - appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, a.attstattarget, a.attstorage, t.typstorage, " - "a.attnotnull, a.atthasdef, a.attisdropped, a.attislocal, " -- "pg_catalog.format_type(t.oid,a.atttypmod) as atttypname " -+ "pg_catalog.format_type(t.oid,a.atttypmod) as atttypname, " -+ "%s as security_label " - "from pg_catalog.pg_attribute a left join pg_catalog.pg_type t " - "on a.atttypid = t.oid " - "where a.attrelid = '%u'::pg_catalog.oid " - "and a.attnum > 0::pg_catalog.int2 " - "order by a.attrelid, a.attnum", -+ (enable_selinux > 0 ? "a.security_context" : "NULL"), - tbinfo->dobj.catId.oid); - } - else if (g_fout->remoteVersion >= 70100) -@@ -4379,7 +4435,8 @@ getTableAttrs(TableInfo *tblinfo, int nu - */ - appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, -1 as attstattarget, a.attstorage, t.typstorage, " - "a.attnotnull, a.atthasdef, false as attisdropped, false as attislocal, " -- "format_type(t.oid,a.atttypmod) as atttypname " -+ "format_type(t.oid,a.atttypmod) as atttypname, " -+ "NULL as security_label " - "from pg_attribute a left join pg_type t " - "on a.atttypid = t.oid " - "where a.attrelid = '%u'::oid " -@@ -4392,7 +4449,8 @@ getTableAttrs(TableInfo *tblinfo, int nu - /* format_type not available before 7.1 */ - appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, -1 as attstattarget, attstorage, attstorage as typstorage, " - "attnotnull, atthasdef, false as attisdropped, false as attislocal, " -- "(select typname from pg_type where oid = atttypid) as atttypname " -+ "(select typname from pg_type where oid = atttypid) as atttypname, " -+ "NULL as security_label " - "from pg_attribute a " - "where attrelid = '%u'::oid " - "and attnum > 0::int2 " -@@ -4416,6 +4474,7 @@ getTableAttrs(TableInfo *tblinfo, int nu - i_atthasdef = PQfnumber(res, "atthasdef"); - i_attisdropped = PQfnumber(res, "attisdropped"); - i_attislocal = PQfnumber(res, "attislocal"); -+ i_attseclabel = PQfnumber(res, "attseclabel"); - - tbinfo->numatts = ntups; - tbinfo->attnames = (char **) malloc(ntups * sizeof(char *)); -@@ -4426,6 +4485,7 @@ getTableAttrs(TableInfo *tblinfo, int nu - tbinfo->typstorage = (char *) malloc(ntups * sizeof(char)); - tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool)); - tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool)); -+ tbinfo->attseclabel = (char **) malloc(ntups * sizeof(char *)); - tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool)); - tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *)); - tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool)); -@@ -4449,6 +4509,7 @@ getTableAttrs(TableInfo *tblinfo, int nu - tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage)); - tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't'); - tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't'); -+ tbinfo->attseclabel[j] = strdup(PQgetvalue(res, j, i_attseclabel)); - tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't'); - tbinfo->attrdefs[j] = NULL; /* fix below */ - if (PQgetvalue(res, j, i_atthasdef)[0] == 't') -@@ -6430,6 +6491,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - char *procost; - char *prorows; - char *lanname; -+ char *proseclabel; - char *rettypename; - int nallargs; - char **allargtypes = NULL; -@@ -6459,9 +6521,11 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "proallargtypes, proargmodes, proargnames, " - "provolatile, proisstrict, prosecdef, " - "proconfig, procost, prorows, " -- "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname " -+ "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname, " -+ "%s as security_label " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", -+ (enable_selinux > 0 ? "security_context" : "NULL"), - finfo->dobj.catId.oid); - } - else if (g_fout->remoteVersion >= 80100) -@@ -6471,7 +6535,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "proallargtypes, proargmodes, proargnames, " - "provolatile, proisstrict, prosecdef, " - "null as proconfig, 0 as procost, 0 as prorows, " -- "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname " -+ "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname, " -+ "NULL as security_label " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -@@ -6485,7 +6550,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "proargnames, " - "provolatile, proisstrict, prosecdef, " - "null as proconfig, 0 as procost, 0 as prorows, " -- "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname " -+ "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname, " -+ "NULL as security_label " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -@@ -6499,7 +6565,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "null as proargnames, " - "provolatile, proisstrict, prosecdef, " - "null as proconfig, 0 as procost, 0 as prorows, " -- "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname " -+ "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname, " -+ "NULL as security_label " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -@@ -6515,7 +6582,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "proisstrict, " - "'f'::boolean as prosecdef, " - "null as proconfig, 0 as procost, 0 as prorows, " -- "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname " -+ "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname, " -+ "NULL as security_label " - "FROM pg_proc " - "WHERE oid = '%u'::oid", - finfo->dobj.catId.oid); -@@ -6531,7 +6599,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - "'f'::boolean as proisstrict, " - "'f'::boolean as prosecdef, " - "null as proconfig, 0 as procost, 0 as prorows, " -- "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname " -+ "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname, " -+ "NULL as security_label " - "FROM pg_proc " - "WHERE oid = '%u'::oid", - finfo->dobj.catId.oid); -@@ -6562,6 +6631,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - procost = PQgetvalue(res, 0, PQfnumber(res, "procost")); - prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows")); - lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname")); -+ proseclabel = PQgetvalue(res, 0, PQfnumber(res, "security_label")); - - /* - * See backend/commands/define.c for details of how the 'AS' clause is -@@ -6699,6 +6769,9 @@ dumpFunc(Archive *fout, FuncInfo *finfo) - if (prosecdef[0] == 't') - appendPQExpBuffer(q, " SECURITY DEFINER"); - -+ if (proseclabel[0] != '\0') -+ appendPQExpBuffer(q, " SECURITY_CONTEXT = '%s'", proseclabel); -+ - /* - * COST and ROWS are emitted only if present and not default, so as not to - * break backwards-compatibility of the dump without need. Keep this code -@@ -8780,6 +8853,10 @@ dumpTableSchema(Archive *fout, TableInfo - if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j]) - appendPQExpBuffer(q, " NOT NULL"); - -+ if (tbinfo->attseclabel[j] != '\0' && -+ strcmp(tbinfo->attseclabel[j], tbinfo->relseclabel) != 0) -+ appendPQExpBuffer(q, " SECURITY_CONTEXT = '%s'", tbinfo->attseclabel[j]); -+ - actual_atts++; - } - } -@@ -8827,6 +8904,9 @@ dumpTableSchema(Archive *fout, TableInfo - if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) - appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions); - -+ if (tbinfo->relseclabel[0] != '\0') -+ appendPQExpBuffer(q, " SECURITY_CONTEXT = '%s'", tbinfo->relseclabel); -+ - appendPQExpBuffer(q, ";\n"); - - /* Loop dumping statistics and storage statements */ -@@ -10244,6 +10324,13 @@ fmtCopyColumnList(const TableInfo *ti) - - appendPQExpBuffer(q, "("); - needComma = false; -+ -+ if (enable_selinux > 0) -+ { -+ appendPQExpBuffer(q, "%s", "security_context"); -+ needComma = true; -+ } -+ - for (i = 0; i < numatts; i++) - { - if (attisdropped[i]) -diff -rpNU3 base/src/bin/pg_dump/pg_dump.h sepgsql-new/src/bin/pg_dump/pg_dump.h ---- base/src/bin/pg_dump/pg_dump.h 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql-new/src/bin/pg_dump/pg_dump.h 2009-03-13 18:14:33.000000000 +0900 -@@ -238,6 +238,7 @@ typedef struct _tableInfo - char relkind; - char *reltablespace; /* relation tablespace */ - char *reloptions; /* options specified by WITH (...) */ -+ char *relseclabel; /* security context of the relation */ - bool hasindex; /* does it have any indexes? */ - bool hasrules; /* does it have any rules? */ - bool hasoids; /* does it have OIDs? */ -@@ -262,6 +263,7 @@ typedef struct _tableInfo - char *typstorage; /* type storage scheme */ - bool *attisdropped; /* true if attr is dropped; don't dump it */ - bool *attislocal; /* true if attr has local definition */ -+ char **attseclabel; /* security context of attribute (column) */ - - /* - * Note: we need to store per-attribute notnull, default, and constraint -diff -rpNU3 base/src/bin/pg_dump/pg_dumpall.c sepgsql-new/src/bin/pg_dump/pg_dumpall.c ---- base/src/bin/pg_dump/pg_dumpall.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql-new/src/bin/pg_dump/pg_dumpall.c 2009-03-13 18:14:33.000000000 +0900 -@@ -67,6 +67,9 @@ static int disable_triggers = 0; - static int use_setsessauth = 0; - static int server_version; - -+/* flag to turn on/off security context support */ -+static int enable_selinux = 0; -+ - static FILE *OPF; - static char *filename = NULL; - -@@ -119,6 +122,7 @@ main(int argc, char *argv[]) - {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1}, - {"disable-triggers", no_argument, &disable_triggers, 1}, - {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, -+ {"security-context", no_argument, &enable_selinux, 1}, - - {NULL, 0, NULL, 0} - }; -@@ -290,6 +294,8 @@ main(int argc, char *argv[]) - appendPQExpBuffer(pgdumpopts, " --disable-triggers"); - else if (strcmp(optarg, "use-set-session-authorization") == 0) - /* no-op, still allowed for compatibility */ ; -+ else if (strcmp(optarg, "security-context") == 0) -+ enable_selinux = 1; - else - { - fprintf(stderr, -@@ -316,6 +322,8 @@ main(int argc, char *argv[]) - appendPQExpBuffer(pgdumpopts, " --disable-triggers"); - if (use_setsessauth) - appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization"); -+ if (enable_selinux) -+ appendPQExpBuffer(pgdumpopts, " --security-context"); - - if (optind < argc) - { -@@ -391,6 +399,24 @@ main(int argc, char *argv[]) - } - } - -+ /* check availability of SE-PostgreSQL */ -+ if (enable_selinux > 0) -+ { -+ const char *sepostgresql -+ = PQparameterStatus(conn, "sepostgresql"); -+ -+ if (!sepostgresql) -+ { -+ fprintf(stderr, "could not obtain server status."); -+ exit(1); -+ } -+ if (strcmp(sepostgresql, "on") != 0) -+ { -+ fprintf(stderr, "SE-PostgreSQL is not available now."); -+ exit(1); -+ } -+ } -+ - /* - * Open the output file if required, otherwise use stdout - */ -@@ -505,6 +531,7 @@ help(void) - printf(_(" --use-set-session-authorization\n" - " use SESSION AUTHORIZATION commands instead of\n" - " OWNER TO commands\n")); -+ printf(_(" --security-context enable to dump security context of SE-PostgreSQL\n")); - - printf(_("\nConnection options:\n")); - printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); -@@ -915,41 +942,46 @@ dumpCreateDB(PGconn *conn) - fprintf(OPF, "--\n-- Database creation\n--\n\n"); - - if (server_version >= 80100) -- res = executeQuery(conn, -+ appendPQExpBuffer(buf, - "SELECT datname, " - "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "datistemplate, datacl, datconnlimit, " -- "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " -+ "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace, " -+ "%s as security_label " - "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " -- "WHERE datallowconn ORDER BY 1"); -+ "WHERE datallowconn ORDER BY 1", -+ (enable_selinux > 0 ? "d.security_context" : "NULL")); - else if (server_version >= 80000) -- res = executeQuery(conn, -+ appendPQExpBuffer(buf, - "SELECT datname, " - "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "datistemplate, datacl, -1 as datconnlimit, " -- "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " -+ "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace, " -+ "NULL as security_label " - "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 70300) -- res = executeQuery(conn, -+ appendPQExpBuffer(buf, - "SELECT datname, " - "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "datistemplate, datacl, -1 as datconnlimit, " -- "'pg_default' AS dattablespace " -+ "'pg_default' AS dattablespace, " -+ "NULL as security_label " - "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 70100) -- res = executeQuery(conn, -+ appendPQExpBuffer(buf, - "SELECT datname, " - "coalesce(" - "(select usename from pg_shadow where usesysid=datdba), " - "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "datistemplate, '' as datacl, -1 as datconnlimit, " -- "'pg_default' AS dattablespace " -+ "'pg_default' AS dattablespace, " -+ "NULL as security_label " - "FROM pg_database d " - "WHERE datallowconn ORDER BY 1"); - else -@@ -958,16 +990,18 @@ dumpCreateDB(PGconn *conn) - * Note: 7.0 fails to cope with sub-select in COALESCE, so just deal - * with getting a NULL by not printing any OWNER clause. - */ -- res = executeQuery(conn, -+ appendPQExpBuffer(buf, - "SELECT datname, " - "(select usename from pg_shadow where usesysid=datdba), " - "pg_encoding_to_char(d.encoding), " - "'f' as datistemplate, " - "'' as datacl, -1 as datconnlimit, " -- "'pg_default' AS dattablespace " -+ "'pg_default' AS dattablespace, " -+ "NULL as security_label " - "FROM pg_database d " - "ORDER BY 1"); - } -+ res = executeQuery(conn, buf->data); - - for (i = 0; i < PQntuples(res); i++) - { -@@ -978,6 +1012,7 @@ dumpCreateDB(PGconn *conn) - char *dbacl = PQgetvalue(res, i, 4); - char *dbconnlimit = PQgetvalue(res, i, 5); - char *dbtablespace = PQgetvalue(res, i, 6); -+ char *dbseclabel = PQgetvalue(res, i, 7); - char *fdbname; - - fdbname = strdup(fmtId(dbname)); -@@ -1021,6 +1056,9 @@ dumpCreateDB(PGconn *conn) - appendPQExpBuffer(buf, " CONNECTION LIMIT = %s", - dbconnlimit); - -+ if (dbseclabel[0] != '\0') -+ appendPQExpBuffer(buf, " SECURITY_CONTEXT = '%s'", dbseclabel); -+ - appendPQExpBuffer(buf, ";\n"); - - if (strcmp(dbistemplate, "t") == 0) diff --git a/sepostgresql.8 b/sepostgresql.8 deleted file mode 100644 index 9c60ef5..0000000 --- a/sepostgresql.8 +++ /dev/null @@ -1,137 +0,0 @@ -.TH "sepostgresql" "8" "Jul 15 2007" "kaigai@kaigai.gr.jp" "Security-Enhanced PostgreSQL" - -.SH "NAME" -sepostgresql \- Security-Enhances PostgreSQL - -.SH "DESCRIPTION" -Security-Enhanced PostgreSQL (SE-PostgreSQL) is an enhancement of PostgreSQL, -to apply fine grained mandatory access control for database objects based on -the security policy of SELinux. -These features enable to apply flexible integrated access control policy -on both of operating system and database management system, during all -stages of the life of the information. -.PP -This document describes the way to customize SE-PostgreSQL on the default -security policy. - -.SH "BOOLEANS" -The SELinux policy is customizable via BOOLEAN variable. This variable has -two states, 1 (on) or 0 (off). We can validate or invalidate a part of the -security policy depending on the state of boolean variables. - -\fBsepgsql_enable_users_ddl\fP enables to toggle permissions of confined -users/applications to invoke DDL statement, like CREATE TABLE. It is set to -\fBon\fP in the default. -In most cases, DDL statements are used to set up initial database structure, -and permissions to invoke them are not necessary on operation phase. -You can turn off this boolean as follows: - -.EX -setsebool -P sepgsql_enable_users_ddl ( \fBon\fP | off ) -.EE - -Rest of booleans are provided by \fBselinux-devel.pp\fP policy module. -It provides developments/debugs related permissions. -You can install it as follows: - -.EX -semodule -i /usr/share/selinux/targeted/sepostgresql-devel.pp -.EE - -\fBsepgsql_enable_auditallow\fP toggles output of audit messages in the case -when required permission checks are allowed, except for tuples because it -easily make a flood of audit logs. -In the default, it is set to off. You can set it as follows: - -.EX -setsebool -P sepgsql_enable_auditallow ( on | \fBoff\fP ) -.EE - -\fBsepgsql_enable_auditdeny\fP toggles output of audit messages in the case -when required permission checks are denied, except for tuples because it -easily make a flood of audit logs. -In the default, it is set to on. You can set it as follows: - -.EX -setsebool -P sepgsql_enable_auditdeny ( \fBon\fP | off ) -.EE - -\fBsepgsql_regression_test_mode\fP allows to load shared libraries deployed -on user's home directory. We recommend you to keep \fBoff\fP in operation -phase to prevent to load malicious libraries. -However, typical PostgreSQL regression test requires to load it, so we -have to reduce several restriction during the test. -In the default, it is set to off. You can set it as follows: - -.EX -setsebool -P sepgsql_regression_test_mode ( on | \fBoff\fP ) -.EE - -.SH "TYPES" - -\fBsepgsql_db_t\fP is a only type for database itself. -It is attched for newly created databases in the default. - -\fBsepgsql_table_t\fP is a type for tables, columns and tuples. -It is the default type of newly created tables by unconfined or -non-roled domain. It allows confined clietns to access with any -kind of operations except for relabeling, so we can use this type -for compatible purpose. - -\fBsepgsql_secret_table_t\fP is a type for tables, columns and tuples. -It never allows confined clients to access, so we can use this type -to store sensitive information. We reccomend to apply trusted procedures -to access tables/columns/tuples with this type under safe operation. - -\fBsepgsql_ro_table_t\fP is a type for read-only tables, columns and tuples. -It does not allow confined clients to modify any objects with this type. - -\fBsepgsql_fixed_table_t\fP is a type for non-manupulatable tables, columns -and tuples. It does not allow confined clients to update or delete any -objects with this type. - -\fBsepgsql_ROLE_table_t\fP is a type for a role specific tables, columns -and tuples. It allows confined clients with its role to access with any -kind of operations except for relabeling. -It is the default type of newly created tables by confined clients with -its role, and we can use this type to describe role level separation. - -\fBsepgsql_proc_t\fP is a type for procedures. -It is attached for newly created procedures by unconfined clients. -It allows any clients to invoke procedures with this type. -All of PostgreSQL built-in functions are labeled as this type in the default. - -\fBsepgsql_ROLE_proc_t\fP is a type for a role specific procedure. -It is attached for newly created procedures by confined clients with its role. -It allows clients with same role to invoke procedure with this type. -Note that unconfined clients cannot invoke this type to avoid to execute -dangerous functions with unconfined authorities. They have to confirm its -contains and relabel to \fBsepgsql_proc_t\fP for its invocation. - -\fBsepgsql_trusted_proc_exec_t\fP is a type for trusted procedures. -To call procedures with this type invokes domain transition to -unconfined domain, so it can access any kind of database objects. -We can use this type to provide a secure method to access sensitive -information. - -\fBsepgsql_blob_t\fP is a type for binary large objects (blob). -It is attached for newly created blob in the default. -Non-administrative clients can read and write the blobs with this type. - -\fBsepgsql_ro_blob_t\fP is a type for read-only binary large objects (blob). -Non-administrative clients cannot write the blobs with this type. - -.SH "BACKUP and RESTORE" -\fI--enable-selinux\fP option in \fBsepg_dump\fP and \fBsepg_dumpall\fP enable to dump database image with security context. We can restore the dumped image using the standard \fIpg_restore\fP and so on. - -.EX -Example) -$ sepg_dump -Ft -b --enable-selinux postgres | gzip -c > postgres.tgz -.EE - -.SH AUTHOR -This manual page was written by KaiGai Kohei - -.SH "SEE ALSO" - -selinux(8), boolean(8) diff --git a/sepostgresql.init b/sepostgresql.init deleted file mode 100644 index 2cc58e1..0000000 --- a/sepostgresql.init +++ /dev/null @@ -1,213 +0,0 @@ -#!/bin/sh -# sepostgresql This is the init script for starting up SE-PostgreSQL -# -# chkconfig: - 62 38 -# description: Starts and stops the SE-PostgreSQL backend daemon -# processname: postmaster -# pidfile: /var/run/postmaster.pid -#--------------------------------------------------------------------- - -PGVERSION="8.3.7" -PGMAJORVERSION=`echo "$PGVERSION" | sed 's/^\([0-9]*\.[0-9a-z]*\).*$/\1/'` -SEPGVERSION="1771" - -# source function library -. /etc/rc.d/init.d/functions - -# get config -. /etc/sysconfig/network - -# find the name of the script -NAME=`basename $0` -if [ ${NAME:0:1} = "S" -o ${NAME:0:1} = "K" ]; then - NAME=${NAME:3} -fi - -# set defaults for configurable variables -SEPGSQL_BIN="/usr/bin" -SEPGSQL_DATA="/var/lib/sepgsql/data" -SEPGSQL_OPTS="-i -p 5432" -SEPGSQL_STARTUP_LOG="/var/lib/sepgsql/pgstartup.log" -SEPGSQL_LOG="/var/log/sepostgresql.log" -SEPGSQL_FALLBACK_CONTEXT="user_u:user_r:user_t" - -# override defaults from /etc/sysconfig/sepostgresql -test -f /etc/sysconfig/${NAME} && . /etc/sysconfig/${NAME} - -export SEPGSQL_FALLBACK_CONTEXT - -# Check that networking is up. -test "${NETWORKING}" = "no" && exit 0 -test -f "${SEPGSQL_BIN}/sepostgres" || exit 1 - -script_result=0 - -do_start() { - PSQL_START=$"Starting ${NAME} service: " - echo -n "$PSQL_START" - - # make sure startup-time log file is valid - if [ ! -e "${SEPGSQL_STARTUP_LOG}" -a ! -h "${SEPGSQL_STARTUP_LOG}" ]; then - touch "${SEPGSQL_STARTUP_LOG}" || exit 1 - chown sepgsql:sepgsql "${SEPGSQL_STARTUP_LOG}" - chmod 600 "${SEPGSQL_STARTUP_LOG}" - /sbin/restorecon "${SEPGSQL_STARTUP_LOG}" - fi - - # check for the SEPGSQL_DATA structure - if [ -f "${SEPGSQL_DATA}/PG_VERSION" ] && [ -d "${SEPGSQL_DATA}/base" ]; then - if [ x`cat "${SEPGSQL_DATA}/PG_VERSION"` != x"${PGMAJORVERSION}" ]; then - echo_failure - echo - echo "HINT: An old version of the database format was found." - echo "HINT: You need to upgrade the data format before using SE-PostgreSQL." - exit 1 - fi - else - echo_failure - echo - echo "HINT: ${SEPGSQL_DATA} is missing." - echo "HINT: Use '/etc/init.d/${NAME} initdb'" - echo "HINT: to initialize the database cluster first." - exit 1 - fi - - # make sure SEPGSQL_LOG - touch ${SEPGSQL_LOG} - chown sepgsql:sepgsql ${SEPGSQL_LOG} - chmod 600 ${SEPGSQL_LOG} - test -x /sbin/restorecon && /sbin/restorecon ${SEPGSQL_LOG} - - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -c "./sepg_ctl -l ${SEPGSQL_LOG} -D ${SEPGSQL_DATA} -o '${SEPGSQL_OPTS}' start" \ - >> ${SEPGSQL_STARTUP_LOG} 2>&1 < /dev/null - sleep 1 - PID=`/sbin/runuser sepgsql -c "./sepg_ctl -D ${SEPGSQL_DATA} status 2>/dev/null \ - | sed 's/^.*PID: //g' | sed 's/[^0-9].*$//g'"` - if [ ${PIPESTATUS[0]} -eq 0 ]; then - echo "$PID" > "/var/run/${NAME}.pid" - touch "/var/lock/subsys/${NAME}.lock" - echo_success - else - script_result=1 - echo_failure - fi - echo -} - -do_stop() { - echo -n $"Stopping ${NAME} service: " - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -c "./sepg_ctl -D ${SEPGSQL_DATA} stop" \ - >> ${SEPGSQL_STARTUP_LOG} 2>&1 < /dev/null - ret=$? - if [ $ret -eq 0 ]; then - echo_success - else - echo_failure - script_result=1 - fi - echo - rm -f "/var/run/${NAME}.pid" - rm -f "/var/lock/subsys/${NAME}.lock" -} - -do_status() { - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "./sepg_ctl -D ${SEPGSQL_DATA} status" 2>/dev/null \ - | head -1 | sed "s/^sepg_ctl:/${NAME}:/g" - - if [ ${PIPESTATUS[0]} -ne 0 ]; then - script_result=3 - test -e "/var/run/${NAME}.pid" && script_result=1 - test -e "/var/lock/subsys/${NAME}.lock" && script_result=2 - fi -} - -do_condrestart() { - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "./sepg_ctl -D ${SEPGSQL_DATA} status" &>/dev/null && do_stop && do_start -} - -do_condstop() { - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "./sepg_ctl -D ${SEPGSQL_DATA} status" &>/dev/null && do_stop -} - -do_reload() { - echo -n $"Reloading ${NAME} service: " - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "./sepg_ctl -D ${SEPGSQL_DATA} reload" &>/dev/null < /dev/null - if [ $? -eq 0 ]; then - echo_success - else - echo_failure - script_result=1 - fi - echo -} - -do_initdb() { - echo -n $"Initializing database: " - - if [ -f "${SEPGSQL_DATA}/PG_VERSION" ]; then - echo_failure - echo - echo "HINT: Data directory is not empty" - script_result=1 - else - if [ ! -e "${SEPGSQL_DATA}" -a ! -h "${SEPGSQL_DATA}" ]; then - mkdir -p "${SEPGSQL_DATA}" || exit 1 - chown sepgsql:sepgsql "${SEPGSQL_DATA}" - chmod 600 "${SEPGSQL_DATA}" - fi - # cleanup SELinux labeling for "${SEPGSQL_DATA}" - test -x /sbin/restorecon && /sbin/restorecon -R "${SEPGSQL_DATA}" - # Initialize the database - cd ${SEPGSQL_BIN} - /sbin/runuser -- sepgsql -c "./initdb.sepgsql --pgace-feature=selinux -A 'ident sameuser' ${SEPGSQL_DATA}" \ - >> "${SEPGSQL_STARTUP_LOG}" 2>&1 < /dev/null - if [ -f "${SEPGSQL_DATA}/PG_VERSION" ]; then - echo_success - else - echo_failure - script_result=1 - fi - echo - fi -} - -# see how we were called. -case "$1" in - start) - do_start - ;; - stop) - do_stop - ;; - status) - do_status - ;; - restart) - do_stop - do_start - ;; - condrestart) - do_condrestart - ;; - condstop) - do_condstop - ;; - reload|force-reload) - do_reload - ;; - initdb) - do_initdb - ;; - *) - echo $"Usage: $0 {start|stop|status|restart|condrestart|condstop|reload|force-reload|initdb}" - exit 1 - ;; -esac - -exit $script_result diff --git a/sepostgresql.logrotate b/sepostgresql.logrotate deleted file mode 100644 index 3ed7081..0000000 --- a/sepostgresql.logrotate +++ /dev/null @@ -1,11 +0,0 @@ -# logrotate configuration for SE-PostgreSQL - -/var/log/sepostgresql.log { - rotate 4 - compress - size 4M - notifempty - postrotate - /sbin/service sepostgresql restart >& /dev/null - endscript -} diff --git a/sepostgresql.spec b/sepostgresql.spec deleted file mode 100644 index e11d114..0000000 --- a/sepostgresql.spec +++ /dev/null @@ -1,448 +0,0 @@ -# -# Security Enhanced PostgreSQL (SE-PostgreSQL) -# -# Copyright 2007 KaiGai Kohei -# ----------------------------------------------------- - -# SE-PostgreSQL status extension -%define selinux_policy_stores targeted mls - -%{!?ssl:%define ssl 1} - -Summary: Security Enhanced PostgreSQL -Name: sepostgresql -Version: 8.3.7 -Release: 1771%{?dist} -License: BSD -Group: Applications/Databases -Url: http://code.google.com/p/sepgsql/ -Buildroot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) -Source0: ftp://ftp.postgresql.org/pub/source/v%{version}/postgresql-%{version}.tar.bz2 -Source1: sepostgresql.init -Source2: sepostgresql.8 -Source3: sepostgresql.logrotate -Patch0: sepostgresql-core-8.3.patch -Patch1: sepostgresql-utils-8.3.patch -Patch2: sepostgresql-test-8.3.patch -Patch3: sepostgresql-fedora-prefix.patch -BuildRequires: perl glibc-devel bison flex readline-devel zlib-devel >= 1.0.4 -BuildRequires: checkpolicy libselinux-devel >= 2.0.43 -BuildRequires: selinux-policy >= 3.4.2 -%if %{ssl} -BuildRequires: openssl-devel -%endif -Requires(pre): shadow-utils -Requires(post): policycoreutils /sbin/chkconfig -Requires(preun): /sbin/chkconfig /sbin/service -Requires(postun): policycoreutils -Requires: postgresql-server = %{version} -Requires: policycoreutils >= 2.0.16 libselinux >= 2.0.43 -Requires: selinux-policy >= 3.4.2 -Requires: tzdata logrotate - -%description -Security Enhanced PostgreSQL is an extension of PostgreSQL -based on SELinux security policy, that applies fine grained -mandatory access control to many objects within the database, -and takes advantage of user authorization integrated within -the operating system. SE-PostgreSQL works as a userspace -reference monitor to check any SQL query. - -%prep -%setup -q -n postgresql-%{version} -%patch0 -p1 -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 - -%build -CFLAGS="${CFLAGS:-%optflags}" ; export CFLAGS -CXXFLAGS="${CXXFLAGS:-%optflags}" ; export CXXFLAGS - -# build SE-PostgreSQL -%configure --disable-rpath \ - --enable-selinux \ -%if %{ssl} - --with-openssl \ -%endif - --enable-debug \ - --enable-cassert \ - --libdir=%{_libdir}/pgsql \ - --datadir=%{_datadir}/sepgsql \ - --with-system-tzdata=/usr/share/zoneinfo - -# parallel build, if possible -make %{?_smp_mflags} -touch src/backend/security/sepgsql/policy/sepostgresql-devel.fc -make -C src/backend/security/sepgsql/policy - -%install -rm -rf %{buildroot} - -make DESTDIR=%{buildroot} install - -for store in %{selinux_policy_stores} -do - install -d %{buildroot}%{_datadir}/selinux/${store} - install -p -m 644 src/backend/security/sepgsql/policy/sepostgresql-devel.pp.${store} \ - %{buildroot}%{_datadir}/selinux/${store}/sepostgresql-devel.pp -done - -# avoid to conflict with native postgresql package -mv %{buildroot}%{_bindir} %{buildroot}%{_bindir}.orig -install -d %{buildroot}%{_bindir} -mv %{buildroot}%{_bindir}.orig/initdb %{buildroot}%{_bindir}/initdb.sepgsql -mv %{buildroot}%{_bindir}.orig/pg_ctl %{buildroot}%{_bindir}/sepg_ctl -mv %{buildroot}%{_bindir}.orig/postgres %{buildroot}%{_bindir}/sepostgres -mv %{buildroot}%{_bindir}.orig/pg_dump %{buildroot}%{_bindir}/sepg_dump -mv %{buildroot}%{_bindir}.orig/pg_dumpall %{buildroot}%{_bindir}/sepg_dumpall - -# remove unnecessary files -rm -rf %{buildroot}%{_bindir}.orig -rm -rf %{buildroot}%{_libdir} -rm -rf %{buildroot}%{_includedir} -rm -rf %{buildroot}%{_usr}/doc -rm -rf %{buildroot}%{_datadir}/sepgsql/timezone -rm -rf %{buildroot}%{_mandir} - -# /var/lib/sepgsql -install -d -m 700 %{buildroot}%{_localstatedir}/lib/sepgsql -install -d -m 700 %{buildroot}%{_localstatedir}/lib/sepgsql/data -install -d -m 700 %{buildroot}%{_localstatedir}/lib/sepgsql/backups - -# /etc/rc.d/init.d/* -mkdir -p %{buildroot}%{_initrddir} -install -p -m 755 %{SOURCE1} %{buildroot}%{_initrddir}/sepostgresql - -# /usr/share/man/* -mkdir -p %{buildroot}%{_mandir}/man8 -install -p -m 644 %{SOURCE2} %{buildroot}%{_mandir}/man8 - -# /etc/logrotate.d/ -mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d -install -p -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/logrotate.d/sepostgresql - -%clean -rm -rf %{buildroot} - -%pre -getent group sepgsql >/dev/null || groupadd -r sepgsql -getent passwd sepgsql >/dev/null || \ - useradd -r -g sepgsql -d %{_localstatedir}/lib/sepgsql -s /bin/bash \ - -c "SE-PostgreSQL server" sepgsql -exit 0 - -%post -/sbin/chkconfig --add %{name} -/sbin/ldconfig - -for store in %{selinux_policy_stores} -do - # clean up legacy policy module (now it is unnecessary) - %{_sbindir}/semodule -s ${store} -r sepostgresql >& /dev/null || : - if %{_sbindir}/semodule -s ${store} -l 2>/dev/null | grep -Eq "^sepostgresql-devel"; then - %{_sbindir}/semodule -s ${store} \ - -i %{_datadir}/selinux/${store}/sepostgresql-devel.pp >& /dev/null || : - fi -done - -# Fix up non-standard file contexts -/sbin/fixfiles -R %{name} restore || : -/sbin/restorecon -R %{_localstatedir}/lib/sepgsql || : - -%preun -if [ $1 -eq 0 ]; then # rpm -e case - /sbin/service %{name} condstop >/dev/null 2>&1 - /sbin/chkconfig --del %{name} -fi - -%postun -/sbin/ldconfig -if [ $1 -ge 1 ]; then # rpm -U case - /sbin/service %{name} condrestart >/dev/null 2>&1 || : -fi -if [ $1 -eq 0 ]; then # rpm -e case - for store in %{selinux_policy_stores} - do - %{_sbindir}/semodule -s ${store} -r sepostgresql-devel >& /dev/null || : - done - /sbin/fixfiles -R %{name} restore || : - test -d %{_localstatedir}/lib/sepgsql && /sbin/restorecon -R %{_localstatedir}/lib/sepgsql || : -fi - -%files -%defattr(-,root,root,-) -%doc COPYRIGHT README -%{_initrddir}/sepostgresql -%{_sysconfdir}/logrotate.d/sepostgresql -%{_bindir}/initdb.sepgsql -%{_bindir}/sepg_ctl -%{_bindir}/sepostgres -%{_bindir}/sepg_dump -%{_bindir}/sepg_dumpall -%{_mandir}/man8/sepostgresql.* -%dir %{_datadir}/sepgsql -%{_datadir}/sepgsql/postgres.bki -%{_datadir}/sepgsql/postgres.description -%{_datadir}/sepgsql/postgres.shdescription -%{_datadir}/sepgsql/system_views.sql -%{_datadir}/sepgsql/*.sample -%{_datadir}/sepgsql/snowball_create.sql -%{_datadir}/sepgsql/timezonesets/ -%{_datadir}/sepgsql/tsearch_data/ -%{_datadir}/sepgsql/conversion_create.sql -%{_datadir}/sepgsql/information_schema.sql -%{_datadir}/sepgsql/sql_features.txt -%attr(644,root,root) %{_datadir}/selinux/*/sepostgresql-devel.pp -%attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql -%attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/data -%attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/backups - -%changelog -* Fri Mar 27 2009 KaiGai Kohei - 8.3.7-1770 -- upgrade base PostgreSQL versin 8.3.6->8.3.7 -- backport features from v8.4devel - -* Thu Feb 26 2009 KaiGai Kohei - 8.3.6-2.1635 -- bugfix: possible information leak by the order of permission checks - in row level permission checks. - -* Wed Feb 25 2009 Fedora Release Engineering - 8.3.6-3.1518 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild - -* Fri Feb 6 2009 - 8.3.6-2.1523 -- upgrade base PostgreSQL version 8.3.5->8.3.6 -- backport features from 8.4devel tree -- security policy fix for Fedora 9 - -* Sat Jan 17 2009 Tomas Mraz - 8.3.5-2.1183 -- rebuild with new openssl - -* Wed Nov 5 2008 - 8.3.5-2.1182 -- upgrade base PostgreSQL version 8.3.4->8.3.5 -- backport cumulative bugfixes from 8.4devel series - -* Thu Oct 2 2008 - 8.3.4-2.1076 -- bugfix: "(null)" audit logs for non-cached decision making. -- A hook is added for "COPY TO/FROM " cases. - -* Sat Sep 27 2008 - 8.3.4-2.1066 -- update base version to 8.3.4 -- sepostgresql.pp was marked as obsolute - -* Tue Sep 23 2008 - 8.3.3-2.1043 -- bugfix: a case when INSERT a FK reference to invisible PK - -* Wed Aug 13 2008 - 8.3.3-2.964 -- bugfix: trusted procedure invokation - -* Fri Jul 11 2008 - 8.3.3-2.952 -- Security policy module updates - -* Fri Jul 11 2008 - 8.3.3-2.945 -- Add OpenSSL support -- backport 8.4devel fixes - -* Sun Jun 15 2008 - 8.3.3-2.889 -- backport 8.4devel features. - -* Fri Jun 13 2008 - 8.3.3-2.869 -- upgrade base PostgreSQL 8.3.1 -> 8.3.3 - -* Wed Apr 30 2008 - 8.3.1-2.197 -- Inconsistent version number format at Changelogs - -* Wed Apr 30 2008 - 8.3.1-2.196 -- BUGFIX: ROW-level control did not work correctly on TRUNCATE - -* Sun Mar 9 2008 - 8.3.0-2.129 -- BUGFIX: more conprehensive fixes in "SELECT COUNT(*) ..." - -* Sun Mar 2 2008 - 8.3.0-2.120 -- BUGFIX: CREATE TABLE statement with explicit labeled columns -- BUGFIX: SELECT count(*) does not filter unallowed tuples - -* Wed Feb 27 2008 - 8.3.0-2.117 -- ".beta" removed. - -* Wed Feb 27 2008 - 8.3.0-2.114 -- Security policy updates - -* Tue Feb 26 2008 - 8.3.0-2.113 -- BUGFIX: CREATE/ALTER TABLE with CONTEXT='...' did nothing. - -* Thu Feb 7 2008 - 8.3.0-2.108 -- add /etc/logrotate.d/sepostgresql - -* Thu Feb 7 2008 - 8.3.0-2.105 -- update base version to stable 8.3.0 -- add tzdata dependency -- allow db_database:{get_param set_param} for generic domain -- error message cleanups -- Improve large object hooks in PGACE framework -- BUGFIX: db_blob:{drop} was checked at loread() -- BUGFIX: incorrect permission in DELETE with RETURNING clause -- incorrect permission when we read and update security_context in same time. - -* Fri Jan 25 2008 - 8.3RC2-2.62 -- BUGFIX: add handling to invalid contexts already stored - -* Tue Jan 22 2008 - 8.3RC2-2.56 -- BUGFIX: lack of locks when refering buffer pages at update/delete hooks -- BUGFIX: explicit labeling using SELECT ... INTO statement. - -* Sun Jan 20 2008 - 8.3RC2-2.52 -- shares /usr/lib/pgsql/*.so libraries, with original postgresql. - -* Thu Jan 10 2008 - 8.3RC1-2.37 -- add sepg_dump/sepg_dumpall support for 8.3base package. - -* Mon Nov 26 2007 - 8.3beta3-2.0 -- Branch from 8.2.x tree - -* Wed Nov 21 2007 - 8.2.5-1.66 -- Add a policy module hotfix for labeled networking - -* Thu Nov 1 2007 - 8.2.5-1.51 -- Re-organize repository to prepare to branch 8.3.x based tree. - (no differences from 8.2.5-1.33) - -* Wed Oct 17 2007 - 8.2.5-1.33 -- Fix bug: security context was not canonicalized - when irregular context (but interpretable) was inputed. - -* Mon Oct 15 2007 - 8.2.5-1.31 -- Fix bug: type definitions of security_label_to_text() - and text_to_security_label() are mismatched. - -* Sat Sep 22 2007 - 8.2.5-1.23 -- update base PostgreSQL to 8.2.5 - -* Mon Sep 1 2007 - 8.2.4-1.0 -- mark as SE-PostgreSQL 8.2.4-1.0 - -* Thu Aug 28 2007 - 8.2.4-0.434.beta -- add Requires: postgresql-server, instead of Conflicts: tag - (Some sharable files are removed from sepostgresql package) - -* Fri Aug 24 2007 - 8.2.4-0.429.beta -- add policycoreutils to Requires(post/postun) -- upstreamed selinux-policy got SE-PostgreSQL related object classes definition. - -* Sat Aug 18 2007 - 8.2.4-0.427.beta -- sepg_dumpall uses /usr/bin/sepg_dump - -* Fri Aug 17 2007 - 8.2.4-0.423.beta -- fix policy not to execute sepgsql_user_proc_t from administrative domain - -* Fri Aug 10 2007 - 8.2.4-0.418.beta -- object classes are renamed with "db_" prefix -- /etc/init.d/sepostgresql script is improved. - -* Thu Aug 2 2007 - 8.2.4-0.409.beta -- specfile updated based on the following comments - https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=249522#c5 - -* Mon Jul 30 2007 - 8.2.4-0.407.beta -- fix spec file based on Fedora reviewing process -- add rawhide support - -* Mon Jul 23 2007 - 8.2.4-0.402.beta -- add manpage of sepostgresql -- fix specfile convention for Fedora suitable - -* Sun Jul 15 2007 - 8.2.4-0.398.beta -- SECCLASS_DATABASE is updated (fc7->62, fc6->61) - -* Sun Jul 1 2007 - 8.2.4-0.391.beta -- Mark as a beta version. - -* Sat Jun 30 2007 - 8.2.4-0.384.alpha -- add fallback context support with $SEPGSQL_FALLBACK_CONTEXT -- add sepgsql_enable_users_ddl boolean to restrict sepgsql_sysobj_t -- BUGFIX: incorrect inherited attribute expanding for RECORD type (attno=0) -- BUGFIX: trigger functions were not checked in COPY FROM statement - -* Tue Jun 26 2007 - 8.2.4-0.376.alpha -- add pgaceExecutorStart() to hook ExecutorStart() - -* Mon Jun 25 2007 - 8.2.4-0.372.alpha -- add table name prefix for column name on audit messages -- use security_label_raw_in as an alternative for security_label_in -- add hook for query execution path with SPI_ interface -- add trigger function suppoer -- BUGFIX: remove unnecessary checks for COPY TO/FROM on non-table relation -- BUGFIX: remove unnecessary checks for LOCK on non-table relation -- BUGFIX: incorrect object id for tuples within pg_security -- BUGFIX: CommandCounterIncrement() might be called during heap_create_with_catalog. -- BUGFIX: correct self-deadlock -- update security policy: sepgsql_sysobj_t, sepgsql_user_proc_t, sepgsql_ro_blob_t - -* Tue Jun 19 2007 - 8.2.4-0.351.alpha -- BUGFIX: sepgsql_compute_avc_datum() accessed userspace AVC without - holding any lock. -- improve build scripts. - -* Sat Jun 16 2007 - 8.2.4-0.320.alpha -- update: sepostgresql.pp security policy fot strict/mls suitable -- BUGFIX: column:drop evaluation for ALTER TABLE tbl DROP col; statement -- add --enable-security option for pg_dumpall command -- add {use} permission for table/column/tuple object classes - -* Tue May 29 2007 - 8.2.4-0.306.alpha -- BUGFIX: RangeTblEntry->requiredPerms are polluted. - -* Sun May 27 2007 - 8.2.4-0.304.alpha -- add support for dynamic object class/access vector mapping -- BUGFIX: Lack of implicit labeling on COPY FROM statement for system catalogs -- BUGFIX: Incorrect security context handling for inherited tables - -* Fri May 25 2007 - 8.2.4-0.292.alpha -- add pg_dump/pg_dumpall/pg_restore with --enable-security option -- add support on OUTER JOIN by rewriting query. -- add security_context support on COPY TO/FROM statement -- add unlabeled security context support (enable to obtain /selinux/initial_contexts/*) -- BUGFIX: lack of checks on JOIN ON condition -- BUGFIX: pseudo relation object (sequence, toast, ...) are not handled as database obj. -- BUGFIX: lack of tuple:insert checks at COPY FROM statement -- BUGFIX: server crash when CREATE TABLE command with newly defined CONTEXT = '...'. - -* Wed May 16 2007 - 8.2.4-0.266.alpha -- BUGFIX: incorrect security context of newly generated system object. -- BUGFIX: missing error text when audit log is disabled. -- BUGFIX: incorrect Oid of newly generated tuples within pg_security. -- BUGFIX: sepgsql_enable_audittuple is misconditioned. -- add checks for T_RowExpr/T_RowCompareExpr/T_BooleanTest - T_DistinctExpr/T_ConvertRowtypeExpr -- add support CONTEXT = 'xxx' for CREATE TABLE/FUNCTION/DATABASE statement - -* Sun Apr 30 2007 - 8.2.4-0.240.alpha -- update base version 8.2.3 -> 8.2.4 -- BUGFIX: unexpected expose in OUTER JOIN statement. - add rewrite OUTER JOIN into SUBQUERY to ensure filtering violated tuples. -- BUGFIX: strange operation in text_to_security_label() -- BUGFIX: infinite recursive call on security label -> oid mapping -- BUGFIX: sepgsql_avc_init() is called in policy state monitoring process - to avoid nonsense initialization of avc_shmem. - -* Fri Apr 27 2007 - 8.2.3-0.232.alpha -- object class numbers were redefined. (SECCLASS_DATABASE got into 61) -- is_selinux_enabled() was cached on the shared memory segment. -- BUGFIX: server went into infinit loop on foreign key constraint. - -* Mon Apr 16 2007 - 8.2.3-0.226.alpha -- BUGFIX: cases when several variables with same type in a single table - -* Sat Apr 07 2007 - 8.2.3-0.214.alpha -- add the first implementation of SE-PostgreSQL on PGACE framework - -* Wed Mar 21 2007 - 8.2.3-0.212.alpha -- BUGFIX: SetOperation didn't handle its subquery correctly. - So, it caused server crash. - -* Wed Mar 07 2007 - 8.2.3-0.209.alpha -- BUGFIX: var->varlevelsup was ignored, so outer references - from subqueries cause a fault. - -* Tue Feb 27 2007 - 8.2.3-0.178.alpha -- Initial RPM build diff --git a/sources b/sources deleted file mode 100644 index 7a88da9..0000000 --- a/sources +++ /dev/null @@ -1 +0,0 @@ -7b7e91a2221e55fe1b167e663217a96d postgresql-8.3.7.tar.bz2