14377 lines
430 KiB
Diff
14377 lines
430 KiB
Diff
diff -Nrpc base/configure sepgsql/configure
|
|
*** base/configure Tue Jun 30 01:26:47 2009
|
|
--- sepgsql/configure Wed Jul 15 21:17:18 2009
|
|
*************** with_libxml
|
|
*** 710,715 ****
|
|
--- 710,716 ----
|
|
with_libxslt
|
|
with_system_tzdata
|
|
with_zlib
|
|
+ enable_selinux
|
|
GREP
|
|
EGREP
|
|
ELF_SYS
|
|
*************** Optional Features:
|
|
*** 1378,1383 ****
|
|
--- 1379,1385 ----
|
|
--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-float4-byval disable float4 passed by value
|
|
--disable-float8-byval disable float8 passed by value
|
|
--disable-largefile omit support for large files
|
|
*************** fi
|
|
*** 5532,5537 ****
|
|
--- 5534,5645 ----
|
|
|
|
|
|
#
|
|
+ # SELinux support
|
|
+ #
|
|
+
|
|
+ pgac_args="$pgac_args enable_selinux"
|
|
+
|
|
+ # Check whether --enable-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 avc_netlink_loop in -lselinux" >&5
|
|
+ echo $ECHO_N "checking for avc_netlink_loop in -lselinux... $ECHO_C" >&6; }
|
|
+ if test "${ac_cv_lib_selinux_avc_netlink_loop+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 GCC internal prototype to avoid an error.
|
|
+ Use char because int might match the return type of a GCC
|
|
+ builtin and then its argument prototype would still apply. */
|
|
+ #ifdef __cplusplus
|
|
+ extern "C"
|
|
+ #endif
|
|
+ char avc_netlink_loop ();
|
|
+ int
|
|
+ main ()
|
|
+ {
|
|
+ return avc_netlink_loop ();
|
|
+ ;
|
|
+ return 0;
|
|
+ }
|
|
+ _ACEOF
|
|
+ rm -f conftest.$ac_objext conftest$ac_exeext
|
|
+ if { (ac_try="$ac_link"
|
|
+ case "(($ac_try" in
|
|
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
|
+ *) ac_try_echo=$ac_try;;
|
|
+ esac
|
|
+ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
|
+ (eval "$ac_link") 2>conftest.er1
|
|
+ ac_status=$?
|
|
+ grep -v '^ *+' conftest.er1 >conftest.err
|
|
+ rm -f conftest.er1
|
|
+ cat conftest.err >&5
|
|
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
|
+ (exit $ac_status); } && {
|
|
+ test -z "$ac_c_werror_flag" ||
|
|
+ test ! -s conftest.err
|
|
+ } && test -s conftest$ac_exeext &&
|
|
+ $as_test_x conftest$ac_exeext; then
|
|
+ ac_cv_lib_selinux_avc_netlink_loop=yes
|
|
+ else
|
|
+ echo "$as_me: failed program was:" >&5
|
|
+ sed 's/^/| /' conftest.$ac_ext >&5
|
|
+
|
|
+ ac_cv_lib_selinux_avc_netlink_loop=no
|
|
+ fi
|
|
+
|
|
+ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
|
+ conftest$ac_exeext conftest.$ac_ext
|
|
+ LIBS=$ac_check_lib_save_LIBS
|
|
+ fi
|
|
+ { echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_avc_netlink_loop" >&5
|
|
+ echo "${ECHO_T}$ac_cv_lib_selinux_avc_netlink_loop" >&6; }
|
|
+ if test $ac_cv_lib_selinux_avc_netlink_loop = 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
|
|
#
|
|
|
|
*************** with_libxml!$with_libxml$ac_delim
|
|
*** 28137,28147 ****
|
|
with_libxslt!$with_libxslt$ac_delim
|
|
with_system_tzdata!$with_system_tzdata$ac_delim
|
|
with_zlib!$with_zlib$ac_delim
|
|
GREP!$GREP$ac_delim
|
|
EGREP!$EGREP$ac_delim
|
|
ELF_SYS!$ELF_SYS$ac_delim
|
|
LDFLAGS_SL!$LDFLAGS_SL$ac_delim
|
|
- LD!$LD$ac_delim
|
|
_ACEOF
|
|
|
|
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
|
|
--- 28245,28255 ----
|
|
with_libxslt!$with_libxslt$ac_delim
|
|
with_system_tzdata!$with_system_tzdata$ac_delim
|
|
with_zlib!$with_zlib$ac_delim
|
|
+ enable_selinux!$enable_selinux$ac_delim
|
|
GREP!$GREP$ac_delim
|
|
EGREP!$EGREP$ac_delim
|
|
ELF_SYS!$ELF_SYS$ac_delim
|
|
LDFLAGS_SL!$LDFLAGS_SL$ac_delim
|
|
_ACEOF
|
|
|
|
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
|
|
*************** _ACEOF
|
|
*** 28183,28188 ****
|
|
--- 28291,28297 ----
|
|
ac_delim='%!_!# '
|
|
for ac_last_try in false false false false false :; do
|
|
cat >conf$$subs.sed <<_ACEOF
|
|
+ LD!$LD$ac_delim
|
|
with_gnu_ld!$with_gnu_ld$ac_delim
|
|
ld_R_works!$ld_R_works$ac_delim
|
|
RANLIB!$RANLIB$ac_delim
|
|
*************** vpath_build!$vpath_build$ac_delim
|
|
*** 28245,28251 ****
|
|
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
|
_ACEOF
|
|
|
|
! if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 60; then
|
|
break
|
|
elif $ac_last_try; then
|
|
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
|
--- 28354,28360 ----
|
|
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
|
_ACEOF
|
|
|
|
! if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 61; then
|
|
break
|
|
elif $ac_last_try; then
|
|
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
|
diff -Nrpc base/configure.in sepgsql/configure.in
|
|
*** base/configure.in Tue Jun 30 01:26:47 2009
|
|
--- sepgsql/configure.in Wed Jul 15 19:35:52 2009
|
|
*************** PGAC_ARG_BOOL(with, zlib, yes,
|
|
*** 764,769 ****
|
|
--- 764,782 ----
|
|
AC_SUBST(with_zlib)
|
|
|
|
#
|
|
+ # SELinux support
|
|
+ #
|
|
+ PGAC_ARG_BOOL(enable, selinux, no,
|
|
+ [enable to build with SELinux support])
|
|
+ if test "$enable_selinux" = yes; then
|
|
+ AC_CHECK_LIB(selinux, avc_netlink_loop,
|
|
+ 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 -Nrpc base/src/Makefile.global.in sepgsql/src/Makefile.global.in
|
|
*** base/src/Makefile.global.in Tue Jun 30 01:26:47 2009
|
|
--- sepgsql/src/Makefile.global.in Wed Jul 15 19:35:52 2009
|
|
*************** enable_rpath = @enable_rpath@
|
|
*** 164,169 ****
|
|
--- 164,170 ----
|
|
enable_nls = @enable_nls@
|
|
enable_debug = @enable_debug@
|
|
enable_dtrace = @enable_dtrace@
|
|
+ enable_selinux = @enable_selinux@
|
|
enable_coverage = @enable_coverage@
|
|
enable_thread_safety = @enable_thread_safety@
|
|
|
|
diff -Nrpc base/src/backend/Makefile sepgsql/src/backend/Makefile
|
|
*** base/src/backend/Makefile Sat Jan 3 13:01:35 2009
|
|
--- sepgsql/src/backend/Makefile Wed Jul 15 19:35:52 2009
|
|
*************** include $(top_builddir)/src/Makefile.glo
|
|
*** 16,22 ****
|
|
|
|
SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \
|
|
main nodes optimizer port postmaster regex rewrite \
|
|
! storage tcop tsearch utils $(top_builddir)/src/timezone
|
|
|
|
include $(srcdir)/common.mk
|
|
|
|
--- 16,22 ----
|
|
|
|
SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \
|
|
main nodes optimizer port postmaster regex rewrite \
|
|
! security storage tcop tsearch utils $(top_builddir)/src/timezone
|
|
|
|
include $(srcdir)/common.mk
|
|
|
|
*************** LIBS := $(filter-out -lpgport, $(LIBS))
|
|
*** 34,39 ****
|
|
--- 34,44 ----
|
|
# 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 -Nrpc base/src/backend/access/common/heaptuple.c sepgsql/src/backend/access/common/heaptuple.c
|
|
*** base/src/backend/access/common/heaptuple.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/access/common/heaptuple.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 60,65 ****
|
|
--- 60,66 ----
|
|
#include "access/heapam.h"
|
|
#include "access/sysattr.h"
|
|
#include "access/tuptoaster.h"
|
|
+ #include "catalog/pg_security.h"
|
|
#include "executor/tuptable.h"
|
|
|
|
|
|
*************** heap_attisnull(HeapTuple tup, int attnum
|
|
*** 287,292 ****
|
|
--- 288,294 ----
|
|
case MinCommandIdAttributeNumber:
|
|
case MaxTransactionIdAttributeNumber:
|
|
case MaxCommandIdAttributeNumber:
|
|
+ case SecurityLabelAttributeNumber:
|
|
/* these are never null */
|
|
break;
|
|
|
|
*************** heap_getsysattr(HeapTuple tup, int attnu
|
|
*** 599,604 ****
|
|
--- 601,609 ----
|
|
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 */
|
|
*************** heap_form_tuple(TupleDesc tupleDescripto
|
|
*** 722,727 ****
|
|
--- 727,734 ----
|
|
|
|
if (tupleDescriptor->tdhasoid)
|
|
len += sizeof(Oid);
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ len += sizeof(Oid);
|
|
|
|
hoff = len = MAXALIGN(len); /* align user data safely */
|
|
|
|
*************** heap_form_tuple(TupleDesc tupleDescripto
|
|
*** 753,758 ****
|
|
--- 760,767 ----
|
|
|
|
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,
|
|
*************** heap_modify_tuple(HeapTuple tuple,
|
|
*** 864,869 ****
|
|
--- 873,880 ----
|
|
newTuple->t_tableOid = tuple->t_tableOid;
|
|
if (tupleDesc->tdhasoid)
|
|
HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
|
|
+ if (HeapTupleHasSecLabel(newTuple))
|
|
+ HeapTupleSetSecLabel(newTuple, HeapTupleGetSecLabel(tuple));
|
|
|
|
return newTuple;
|
|
}
|
|
*************** heap_form_minimal_tuple(TupleDesc tupleD
|
|
*** 1474,1479 ****
|
|
--- 1485,1492 ----
|
|
|
|
if (tupleDescriptor->tdhasoid)
|
|
len += sizeof(Oid);
|
|
+ if (tupleDescriptor->tdhasseclabel)
|
|
+ len += sizeof(Oid);
|
|
|
|
hoff = len = MAXALIGN(len); /* align user data safely */
|
|
|
|
*************** heap_form_minimal_tuple(TupleDesc tupleD
|
|
*** 1495,1500 ****
|
|
--- 1508,1515 ----
|
|
|
|
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,
|
|
diff -Nrpc base/src/backend/access/common/tupdesc.c sepgsql/src/backend/access/common/tupdesc.c
|
|
*** base/src/backend/access/common/tupdesc.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/access/common/tupdesc.c Wed Jul 15 19:30:50 2009
|
|
*************** CreateTemplateTupleDesc(int natts, bool
|
|
*** 88,93 ****
|
|
--- 88,94 ----
|
|
desc->tdtypeid = RECORDOID;
|
|
desc->tdtypmod = -1;
|
|
desc->tdhasoid = hasoid;
|
|
+ desc->tdhasseclabel = false;
|
|
desc->tdrefcount = -1; /* assume not reference-counted */
|
|
|
|
return desc;
|
|
*************** CreateTupleDesc(int natts, bool hasoid,
|
|
*** 121,126 ****
|
|
--- 122,128 ----
|
|
desc->tdtypeid = RECORDOID;
|
|
desc->tdtypmod = -1;
|
|
desc->tdhasoid = hasoid;
|
|
+ desc->tdhasseclabel = false;
|
|
desc->tdrefcount = -1; /* assume not reference-counted */
|
|
|
|
return desc;
|
|
*************** CreateTupleDescCopy(TupleDesc tupdesc)
|
|
*** 150,155 ****
|
|
--- 152,158 ----
|
|
|
|
desc->tdtypeid = tupdesc->tdtypeid;
|
|
desc->tdtypmod = tupdesc->tdtypmod;
|
|
+ desc->tdhasseclabel = tupdesc->tdhasseclabel;
|
|
|
|
return desc;
|
|
}
|
|
*************** CreateTupleDescCopyConstr(TupleDesc tupd
|
|
*** 208,213 ****
|
|
--- 211,217 ----
|
|
|
|
desc->tdtypeid = tupdesc->tdtypeid;
|
|
desc->tdtypmod = tupdesc->tdtypmod;
|
|
+ desc->tdhasseclabel = tupdesc->tdhasseclabel;
|
|
|
|
return desc;
|
|
}
|
|
*************** equalTupleDescs(TupleDesc tupdesc1, Tupl
|
|
*** 314,319 ****
|
|
--- 318,325 ----
|
|
return false;
|
|
if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
|
|
return false;
|
|
+ if (tupdesc1->tdhasseclabel != tupdesc2->tdhasseclabel)
|
|
+ return false;
|
|
|
|
for (i = 0; i < tupdesc1->natts; i++)
|
|
{
|
|
diff -Nrpc base/src/backend/access/heap/heapam.c sepgsql/src/backend/access/heap/heapam.c
|
|
*** base/src/backend/access/heap/heapam.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/access/heap/heapam.c Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 54,59 ****
|
|
--- 54,60 ----
|
|
#include "catalog/namespace.h"
|
|
#include "miscadmin.h"
|
|
#include "pgstat.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/freespace.h"
|
|
#include "storage/lmgr.h"
|
|
*************** heap_insert(Relation relation, HeapTuple
|
|
*** 2015,2020 ****
|
|
--- 2016,2027 ----
|
|
Oid
|
|
simple_heap_insert(Relation relation, HeapTuple tup)
|
|
{
|
|
+ /*
|
|
+ * SELinux assigns default security label for the tuple,
|
|
+ * but does not check permissions to the internal operations.
|
|
+ */
|
|
+ sepgsqlHeapTupleInsert(relation, tup, true);
|
|
+
|
|
return heap_insert(relation, tup, GetCurrentCommandId(true), 0, NULL);
|
|
}
|
|
|
|
*************** l2:
|
|
*** 2557,2562 ****
|
|
--- 2564,2574 ----
|
|
Assert(!(newtup->t_data->t_infomask & HEAP_HASOID));
|
|
}
|
|
|
|
+ /* Preserve SecLabel, if not changed */
|
|
+ if (HeapTupleHasSecLabel(newtup) &&
|
|
+ !OidIsValid(HeapTupleGetSecLabel(newtup)))
|
|
+ HeapTupleSetSecLabel(newtup, HeapTupleGetSecLabel(&oldtup));
|
|
+
|
|
newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
|
|
newtup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
|
|
newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED);
|
|
diff -Nrpc base/src/backend/access/heap/tuptoaster.c sepgsql/src/backend/access/heap/tuptoaster.c
|
|
*** base/src/backend/access/heap/tuptoaster.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/access/heap/tuptoaster.c Wed Jul 15 19:39:56 2009
|
|
*************** toast_insert_or_update(Relation rel, Hea
|
|
*** 591,596 ****
|
|
--- 591,598 ----
|
|
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 */
|
|
*************** toast_insert_or_update(Relation rel, Hea
|
|
*** 864,869 ****
|
|
--- 866,873 ----
|
|
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,
|
|
*************** toast_flatten_tuple_attribute(Datum valu
|
|
*** 1015,1020 ****
|
|
--- 1019,1026 ----
|
|
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,
|
|
*************** toast_save_datum(Relation rel, Datum val
|
|
*** 1213,1218 ****
|
|
--- 1219,1230 ----
|
|
memcpy(VARDATA(&chunk_data), data_p, chunk_size);
|
|
toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull);
|
|
|
|
+ /*
|
|
+ * NOTE: SE-PostgreSQL does not assign any security label
|
|
+ * for tuples within the TOASTVALUE relation, so we omit
|
|
+ * to put sepgsqlHeapTupleInsert() hook here.
|
|
+ */
|
|
+
|
|
heap_insert(toastrel, toasttup, mycid, options, NULL);
|
|
|
|
/*
|
|
diff -Nrpc base/src/backend/access/transam/xact.c sepgsql/src/backend/access/transam/xact.c
|
|
*** base/src/backend/access/transam/xact.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/access/transam/xact.c Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 36,41 ****
|
|
--- 36,42 ----
|
|
#include "libpq/be-fsstubs.h"
|
|
#include "miscadmin.h"
|
|
#include "pgstat.h"
|
|
+ #include "security/rowlevel.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/lmgr.h"
|
|
*************** typedef struct TransactionStateData
|
|
*** 140,145 ****
|
|
--- 141,147 ----
|
|
Oid prevUser; /* previous CurrentUserId setting */
|
|
bool prevSecDefCxt; /* previous SecurityDefinerContext setting */
|
|
bool prevXactReadOnly; /* entry-time xact r/o state */
|
|
+ int prevRowlv; /* previous Row-level control behavior */
|
|
struct TransactionStateData *parent; /* back link to parent */
|
|
} TransactionStateData;
|
|
|
|
*************** static TransactionStateData TopTransacti
|
|
*** 168,173 ****
|
|
--- 170,176 ----
|
|
InvalidOid, /* previous CurrentUserId setting */
|
|
false, /* previous SecurityDefinerContext setting */
|
|
false, /* entry-time xact r/o state */
|
|
+ ROWLV_FILTER_MODE, /* previous Row-level control behavior */
|
|
NULL /* link to parent state block */
|
|
};
|
|
|
|
*************** StartTransaction(void)
|
|
*** 1524,1529 ****
|
|
--- 1527,1533 ----
|
|
s->nChildXids = 0;
|
|
s->maxChildXids = 0;
|
|
GetUserIdAndContext(&s->prevUser, &s->prevSecDefCxt);
|
|
+ s->prevRowlv = rowlvGetPerformingMode();
|
|
/* SecurityDefinerContext should never be set outside a transaction */
|
|
Assert(!s->prevSecDefCxt);
|
|
|
|
*************** AbortTransaction(void)
|
|
*** 2030,2035 ****
|
|
--- 2034,2044 ----
|
|
SetUserIdAndContext(s->prevUser, s->prevSecDefCxt);
|
|
|
|
/*
|
|
+ * Reset behavior of row-level access controls
|
|
+ */
|
|
+ rowlvSetPerformingMode(s->prevRowlv);
|
|
+
|
|
+ /*
|
|
* do abort processing
|
|
*/
|
|
AfterTriggerEndXact(false);
|
|
*************** AbortSubTransaction(void)
|
|
*** 3873,3878 ****
|
|
--- 3882,3892 ----
|
|
SetUserIdAndContext(s->prevUser, s->prevSecDefCxt);
|
|
|
|
/*
|
|
+ * Reset behavior of row-level access controls
|
|
+ */
|
|
+ rowlvSetPerformingMode(s->prevRowlv);
|
|
+
|
|
+ /*
|
|
* We can skip all this stuff if the subxact failed before creating a
|
|
* ResourceOwner...
|
|
*/
|
|
*************** PushTransaction(void)
|
|
*** 4014,4019 ****
|
|
--- 4028,4034 ----
|
|
s->blockState = TBLOCK_SUBBEGIN;
|
|
GetUserIdAndContext(&s->prevUser, &s->prevSecDefCxt);
|
|
s->prevXactReadOnly = XactReadOnly;
|
|
+ s->prevRowlv = rowlvGetPerformingMode();
|
|
|
|
CurrentTransactionState = s;
|
|
|
|
diff -Nrpc base/src/backend/bootstrap/bootparse.y sepgsql/src/backend/bootstrap/bootparse.y
|
|
*** base/src/backend/bootstrap/bootparse.y Sat Jan 3 13:01:35 2009
|
|
--- sepgsql/src/backend/bootstrap/bootparse.y Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 42,47 ****
|
|
--- 42,48 ----
|
|
#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"
|
|
*************** Boot_CreateStmt:
|
|
*** 211,216 ****
|
|
--- 212,222 ----
|
|
else
|
|
{
|
|
Oid id;
|
|
+ Oid *secLabels =
|
|
+ sepgsqlCreateTableColumns(NULL,
|
|
+ LexIDStr($5),
|
|
+ PG_CATALOG_NAMESPACE,
|
|
+ tupdesc, RELKIND_RELATION);
|
|
|
|
id = heap_create_with_catalog(LexIDStr($5),
|
|
PG_CATALOG_NAMESPACE,
|
|
*************** Boot_CreateStmt:
|
|
*** 225,231 ****
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
(Datum) 0,
|
|
! true);
|
|
elog(DEBUG4, "relation created with oid %u", id);
|
|
}
|
|
do_end();
|
|
--- 231,238 ----
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
(Datum) 0,
|
|
! true,
|
|
! secLabels);
|
|
elog(DEBUG4, "relation created with oid %u", id);
|
|
}
|
|
do_end();
|
|
diff -Nrpc base/src/backend/bootstrap/bootstrap.c sepgsql/src/backend/bootstrap/bootstrap.c
|
|
*** base/src/backend/bootstrap/bootstrap.c Fri Feb 20 22:15:36 2009
|
|
--- sepgsql/src/backend/bootstrap/bootstrap.c Thu Jul 16 22:14:45 2009
|
|
***************
|
|
*** 26,31 ****
|
|
--- 26,32 ----
|
|
#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"
|
|
*************** BootstrapModeMain(void)
|
|
*** 497,502 ****
|
|
--- 498,508 ----
|
|
*/
|
|
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);
|
|
*************** InsertOneTuple(Oid objectid)
|
|
*** 794,799 ****
|
|
--- 800,807 ----
|
|
tupDesc = CreateTupleDesc(numattr,
|
|
RelationGetForm(boot_reldesc)->relhasoids,
|
|
attrtypes);
|
|
+ tupDesc->tdhasseclabel = RelationGetDescr(boot_reldesc)->tdhasseclabel;
|
|
+
|
|
tuple = heap_form_tuple(tupDesc, values, Nulls);
|
|
if (objectid != (Oid) 0)
|
|
HeapTupleSetOid(tuple, objectid);
|
|
diff -Nrpc base/src/backend/catalog/Makefile sepgsql/src/backend/catalog/Makefile
|
|
*** base/src/backend/catalog/Makefile Wed May 13 11:30:07 2009
|
|
--- sepgsql/src/backend/catalog/Makefile Wed Jul 15 19:30:50 2009
|
|
*************** include $(top_builddir)/src/Makefile.glo
|
|
*** 13,19 ****
|
|
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
|
|
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
|
|
pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \
|
|
! pg_shdepend.o pg_type.o storage.o toasting.o
|
|
|
|
BKIFILES = postgres.bki postgres.description postgres.shdescription
|
|
|
|
--- 13,19 ----
|
|
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
|
|
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
|
|
pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \
|
|
! pg_security.o pg_shdepend.o pg_type.o storage.o toasting.o
|
|
|
|
BKIFILES = postgres.bki postgres.description postgres.shdescription
|
|
|
|
*************** POSTGRES_BKI_SRCS = $(addprefix $(top_sr
|
|
*** 34,40 ****
|
|
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_ts_parser.h pg_ts_template.h \
|
|
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
|
|
toasting.h indexing.h \
|
|
--- 34,40 ----
|
|
pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
|
|
pg_database.h pg_tablespace.h pg_pltemplate.h \
|
|
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
|
|
! pg_security.h pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
|
|
pg_ts_parser.h pg_ts_template.h \
|
|
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
|
|
toasting.h indexing.h \
|
|
diff -Nrpc base/src/backend/catalog/aclchk.c sepgsql/src/backend/catalog/aclchk.c
|
|
*** base/src/backend/catalog/aclchk.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/catalog/aclchk.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 43,48 ****
|
|
--- 43,49 ----
|
|
#include "foreign/foreign.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"
|
|
*************** AclResult
|
|
*** 3045,3051 ****
|
|
--- 3046,3059 ----
|
|
pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
|
|
{
|
|
if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
|
|
+ {
|
|
+ /* SELinux: db_database:{connect} permission */
|
|
+ if ((mode & ACL_CONNECT) &&
|
|
+ !sepgsqlCheckDatabaseConnect(db_oid))
|
|
+ return ACLCHECK_NO_PRIV;
|
|
+
|
|
return ACLCHECK_OK;
|
|
+ }
|
|
else
|
|
return ACLCHECK_NO_PRIV;
|
|
}
|
|
*************** AclResult
|
|
*** 3057,3063 ****
|
|
--- 3065,3078 ----
|
|
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) &&
|
|
+ !sepgsqlCheckProcedureExecute(proc_oid))
|
|
+ return ACLCHECK_NO_PRIV;
|
|
+
|
|
return ACLCHECK_OK;
|
|
+ }
|
|
else
|
|
return ACLCHECK_NO_PRIV;
|
|
}
|
|
*************** AclResult
|
|
*** 3081,3087 ****
|
|
--- 3096,3109 ----
|
|
pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
|
|
{
|
|
if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
|
|
+ {
|
|
+ /* SELinux: db_schema:{usage} permission */
|
|
+ if ((mode & ACL_USAGE) &&
|
|
+ !sepgsqlCheckSchemaUsage(nsp_oid))
|
|
+ return ACLCHECK_NO_PRIV;
|
|
+
|
|
return ACLCHECK_OK;
|
|
+ }
|
|
else
|
|
return ACLCHECK_NO_PRIV;
|
|
}
|
|
diff -Nrpc base/src/backend/catalog/catalog.c sepgsql/src/backend/catalog/catalog.c
|
|
*** base/src/backend/catalog/catalog.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/catalog/catalog.c Wed Jul 15 19:30:50 2009
|
|
***************
|
|
*** 31,36 ****
|
|
--- 31,37 ----
|
|
#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"
|
|
*************** IsSharedRelation(Oid relationId)
|
|
*** 304,309 ****
|
|
--- 305,311 ----
|
|
relationId == AuthMemRelationId ||
|
|
relationId == DatabaseRelationId ||
|
|
relationId == PLTemplateRelationId ||
|
|
+ relationId == SecurityRelationId ||
|
|
relationId == SharedDescriptionRelationId ||
|
|
relationId == SharedDependRelationId ||
|
|
relationId == TableSpaceRelationId)
|
|
*************** IsSharedRelation(Oid relationId)
|
|
*** 316,321 ****
|
|
--- 318,325 ----
|
|
relationId == DatabaseNameIndexId ||
|
|
relationId == DatabaseOidIndexId ||
|
|
relationId == PLTemplateNameIndexId ||
|
|
+ relationId == SecuritySecidIndexId ||
|
|
+ relationId == SecuritySecattrIndexId ||
|
|
relationId == SharedDescriptionObjIndexId ||
|
|
relationId == SharedDependDependerIndexId ||
|
|
relationId == SharedDependReferenceIndexId ||
|
|
*************** IsSharedRelation(Oid relationId)
|
|
*** 327,332 ****
|
|
--- 331,338 ----
|
|
relationId == PgAuthidToastIndex ||
|
|
relationId == PgDatabaseToastTable ||
|
|
relationId == PgDatabaseToastIndex ||
|
|
+ relationId == PgSecurityToastTable ||
|
|
+ relationId == PgSecurityToastIndex ||
|
|
relationId == PgShdescriptionToastTable ||
|
|
relationId == PgShdescriptionToastIndex)
|
|
return true;
|
|
diff -Nrpc base/src/backend/catalog/dependency.c sepgsql/src/backend/catalog/dependency.c
|
|
*** base/src/backend/catalog/dependency.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/catalog/dependency.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 63,68 ****
|
|
--- 63,69 ----
|
|
#include "nodes/nodeFuncs.h"
|
|
#include "parser/parsetree.h"
|
|
#include "rewrite/rewriteRemove.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/lmgr.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
*************** static void reportDependentObjects(const
|
|
*** 157,163 ****
|
|
DropBehavior behavior,
|
|
int msglevel,
|
|
const ObjectAddress *origObject);
|
|
! static void deleteOneObject(const ObjectAddress *object, Relation depRel);
|
|
static void doDeletion(const ObjectAddress *object);
|
|
static void AcquireDeletionLock(const ObjectAddress *object);
|
|
static void ReleaseDeletionLock(const ObjectAddress *object);
|
|
--- 158,165 ----
|
|
DropBehavior behavior,
|
|
int msglevel,
|
|
const ObjectAddress *origObject);
|
|
! static void deleteOneObject(const ObjectAddress *object,
|
|
! Relation depRel, bool permission);
|
|
static void doDeletion(const ObjectAddress *object);
|
|
static void AcquireDeletionLock(const ObjectAddress *object);
|
|
static void ReleaseDeletionLock(const ObjectAddress *object);
|
|
*************** static void getOpFamilyDescription(Strin
|
|
*** 189,197 ****
|
|
* are variants on the same theme; if you change anything here you'll likely
|
|
* need to fix them too.
|
|
*/
|
|
! void
|
|
! performDeletion(const ObjectAddress *object,
|
|
! DropBehavior behavior)
|
|
{
|
|
Relation depRel;
|
|
ObjectAddresses *targetObjects;
|
|
--- 191,199 ----
|
|
* are variants on the same theme; if you change anything here you'll likely
|
|
* need to fix them too.
|
|
*/
|
|
! static void
|
|
! performDeletionInternal(const ObjectAddress *object,
|
|
! DropBehavior behavior, bool permission)
|
|
{
|
|
Relation depRel;
|
|
ObjectAddresses *targetObjects;
|
|
*************** performDeletion(const ObjectAddress *obj
|
|
*** 237,243 ****
|
|
{
|
|
ObjectAddress *thisobj = targetObjects->refs + i;
|
|
|
|
! deleteOneObject(thisobj, depRel);
|
|
}
|
|
|
|
/* And clean up */
|
|
--- 239,245 ----
|
|
{
|
|
ObjectAddress *thisobj = targetObjects->refs + i;
|
|
|
|
! deleteOneObject(thisobj, depRel, permission);
|
|
}
|
|
|
|
/* And clean up */
|
|
*************** performDeletion(const ObjectAddress *obj
|
|
*** 246,251 ****
|
|
--- 248,265 ----
|
|
heap_close(depRel, RowExclusiveLock);
|
|
}
|
|
|
|
+ void
|
|
+ performDeletion(const ObjectAddress *object, DropBehavior behavior)
|
|
+ {
|
|
+ performDeletionInternal(object, behavior, true);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ performDeletionNoPerms(const ObjectAddress *object, DropBehavior behavior)
|
|
+ {
|
|
+ performDeletionInternal(object, behavior, false);
|
|
+ }
|
|
+
|
|
/*
|
|
* performMultipleDeletions: Similar to performDeletion, but act on multiple
|
|
* objects at once.
|
|
*************** performMultipleDeletions(const ObjectAdd
|
|
*** 319,325 ****
|
|
{
|
|
ObjectAddress *thisobj = targetObjects->refs + i;
|
|
|
|
! deleteOneObject(thisobj, depRel);
|
|
}
|
|
|
|
/* And clean up */
|
|
--- 333,340 ----
|
|
{
|
|
ObjectAddress *thisobj = targetObjects->refs + i;
|
|
|
|
! /* currently, all the caller path need permission checks */
|
|
! deleteOneObject(thisobj, depRel, true);
|
|
}
|
|
|
|
/* And clean up */
|
|
*************** deleteWhatDependsOn(const ObjectAddress
|
|
*** 390,396 ****
|
|
if (thisextra->flags & DEPFLAG_ORIGINAL)
|
|
continue;
|
|
|
|
! deleteOneObject(thisobj, depRel);
|
|
}
|
|
|
|
/* And clean up */
|
|
--- 405,411 ----
|
|
if (thisextra->flags & DEPFLAG_ORIGINAL)
|
|
continue;
|
|
|
|
! deleteOneObject(thisobj, depRel, false);
|
|
}
|
|
|
|
/* And clean up */
|
|
*************** reportDependentObjects(const ObjectAddre
|
|
*** 939,951 ****
|
|
* depRel is the already-open pg_depend relation.
|
|
*/
|
|
static void
|
|
! deleteOneObject(const ObjectAddress *object, Relation depRel)
|
|
{
|
|
ScanKeyData key[3];
|
|
int nkeys;
|
|
SysScanDesc scan;
|
|
HeapTuple tup;
|
|
|
|
/*
|
|
* First remove any pg_depend records that link from this object to
|
|
* others. (Any records linking to this object should be gone already.)
|
|
--- 954,970 ----
|
|
* depRel is the already-open pg_depend relation.
|
|
*/
|
|
static void
|
|
! deleteOneObject(const ObjectAddress *object, Relation depRel, bool permission)
|
|
{
|
|
ScanKeyData key[3];
|
|
int nkeys;
|
|
SysScanDesc scan;
|
|
HeapTuple tup;
|
|
|
|
+ /* SELinux checks db_xxx:{drop}, if necessary */
|
|
+ if (permission)
|
|
+ sepgsqlCheckObjectDrop(object);
|
|
+
|
|
/*
|
|
* First remove any pg_depend records that link from this object to
|
|
* others. (Any records linking to this object should be gone already.)
|
|
diff -Nrpc base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c
|
|
*** base/src/backend/catalog/heap.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/catalog/heap.c Wed Jul 15 20:03:59 2009
|
|
***************
|
|
*** 43,48 ****
|
|
--- 43,49 ----
|
|
#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"
|
|
***************
|
|
*** 56,61 ****
|
|
--- 57,63 ----
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_expr.h"
|
|
#include "parser/parse_relation.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/freespace.h"
|
|
#include "storage/smgr.h"
|
|
*************** static void AddNewRelationTuple(Relation
|
|
*** 74,80 ****
|
|
Oid new_rel_oid, Oid new_type_oid,
|
|
Oid relowner,
|
|
char relkind,
|
|
! Datum reloptions);
|
|
static Oid AddNewRelationType(const char *typeName,
|
|
Oid typeNamespace,
|
|
Oid new_rel_oid,
|
|
--- 76,83 ----
|
|
Oid new_rel_oid, Oid new_type_oid,
|
|
Oid relowner,
|
|
char relkind,
|
|
! Datum reloptions,
|
|
! Oid *secLabels);
|
|
static Oid AddNewRelationType(const char *typeName,
|
|
Oid typeNamespace,
|
|
Oid new_rel_oid,
|
|
*************** static FormData_pg_attribute a7 = {
|
|
*** 158,164 ****
|
|
true, 'p', 'i', true, false, false, true, 0, {0}
|
|
};
|
|
|
|
! static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};
|
|
|
|
/*
|
|
* This function returns a Form_pg_attribute pointer for a system attribute.
|
|
--- 161,176 ----
|
|
true, 'p', 'i', true, false, false, true, 0, {0}
|
|
};
|
|
|
|
! /*
|
|
! * 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, {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.
|
|
*************** SystemAttributeByName(const char *attnam
|
|
*** 198,203 ****
|
|
--- 210,226 ----
|
|
return NULL;
|
|
}
|
|
|
|
+ /*
|
|
+ * If the given attribute number is writable, returns true.
|
|
+ */
|
|
+ bool
|
|
+ SystemAttributeIsWritable(AttrNumber attnum)
|
|
+ {
|
|
+ if (attnum == SecurityLabelAttributeNumber)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+ }
|
|
|
|
/* ----------------------------------------------------------------
|
|
* XXX END OF UGLY HARD CODED BADNESS XXX
|
|
*************** heap_create(const char *relname,
|
|
*** 293,298 ****
|
|
--- 316,326 ----
|
|
relid,
|
|
reltablespace,
|
|
shared_relation);
|
|
+ /*
|
|
+ * Does the relation have security attribute?
|
|
+ */
|
|
+ RelationGetDescr(rel)->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(relid, relkind);
|
|
|
|
/*
|
|
* Have the storage manager create the relation's disk file, if needed.
|
|
*************** CheckAttributeType(const char *attname,
|
|
*** 487,493 ****
|
|
void
|
|
InsertPgAttributeTuple(Relation pg_attribute_rel,
|
|
Form_pg_attribute new_attribute,
|
|
! CatalogIndexState indstate)
|
|
{
|
|
Datum values[Natts_pg_attribute];
|
|
bool nulls[Natts_pg_attribute];
|
|
--- 515,522 ----
|
|
void
|
|
InsertPgAttributeTuple(Relation pg_attribute_rel,
|
|
Form_pg_attribute new_attribute,
|
|
! CatalogIndexState indstate,
|
|
! Oid new_att_secid)
|
|
{
|
|
Datum values[Natts_pg_attribute];
|
|
bool nulls[Natts_pg_attribute];
|
|
*************** InsertPgAttributeTuple(Relation pg_attri
|
|
*** 520,525 ****
|
|
--- 549,557 ----
|
|
|
|
tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls);
|
|
|
|
+ if (HeapTupleHasSecLabel(tup))
|
|
+ HeapTupleSetSecLabel(tup, new_att_secid);
|
|
+
|
|
/* finally insert the new tuple, update the indexes, and clean up */
|
|
simple_heap_insert(pg_attribute_rel, tup);
|
|
|
|
*************** AddNewAttributeTuples(Oid new_rel_oid,
|
|
*** 543,555 ****
|
|
TupleDesc tupdesc,
|
|
char relkind,
|
|
bool oidislocal,
|
|
! int oidinhcount)
|
|
{
|
|
Form_pg_attribute attr;
|
|
int i;
|
|
Relation rel;
|
|
CatalogIndexState indstate;
|
|
int natts = tupdesc->natts;
|
|
ObjectAddress myself,
|
|
referenced;
|
|
|
|
--- 575,589 ----
|
|
TupleDesc tupdesc,
|
|
char relkind,
|
|
bool oidislocal,
|
|
! int oidinhcount,
|
|
! Oid *secLabels)
|
|
{
|
|
Form_pg_attribute attr;
|
|
int i;
|
|
Relation rel;
|
|
CatalogIndexState indstate;
|
|
int natts = tupdesc->natts;
|
|
+ Oid new_att_secid;
|
|
ObjectAddress myself,
|
|
referenced;
|
|
|
|
*************** AddNewAttributeTuples(Oid new_rel_oid,
|
|
*** 573,579 ****
|
|
attr->attstattarget = -1;
|
|
attr->attcacheoff = -1;
|
|
|
|
! InsertPgAttributeTuple(rel, attr, indstate);
|
|
|
|
/* Add dependency info */
|
|
myself.classId = RelationRelationId;
|
|
--- 607,617 ----
|
|
attr->attstattarget = -1;
|
|
attr->attcacheoff = -1;
|
|
|
|
! /* Security label of the column */
|
|
! new_att_secid = (!secLabels ? InvalidOid
|
|
! : secLabels[i - FirstLowInvalidHeapAttributeNumber]);
|
|
!
|
|
! InsertPgAttributeTuple(rel, attr, indstate, new_att_secid);
|
|
|
|
/* Add dependency info */
|
|
myself.classId = RelationRelationId;
|
|
*************** AddNewAttributeTuples(Oid new_rel_oid,
|
|
*** 613,619 ****
|
|
attStruct.attinhcount = oidinhcount;
|
|
}
|
|
|
|
! InsertPgAttributeTuple(rel, &attStruct, indstate);
|
|
}
|
|
}
|
|
|
|
--- 651,661 ----
|
|
attStruct.attinhcount = oidinhcount;
|
|
}
|
|
|
|
! /* Security label of the system column */
|
|
! new_att_secid = (!secLabels ? InvalidOid
|
|
! : secLabels[SysAtt[i]->attnum - FirstLowInvalidHeapAttributeNumber]);
|
|
!
|
|
! InsertPgAttributeTuple(rel, &attStruct, indstate, new_att_secid);
|
|
}
|
|
}
|
|
|
|
*************** void
|
|
*** 641,647 ****
|
|
InsertPgClassTuple(Relation pg_class_desc,
|
|
Relation new_rel_desc,
|
|
Oid new_rel_oid,
|
|
! Datum reloptions)
|
|
{
|
|
Form_pg_class rd_rel = new_rel_desc->rd_rel;
|
|
Datum values[Natts_pg_class];
|
|
--- 683,690 ----
|
|
InsertPgClassTuple(Relation pg_class_desc,
|
|
Relation new_rel_desc,
|
|
Oid new_rel_oid,
|
|
! Datum reloptions,
|
|
! Oid new_rel_secid)
|
|
{
|
|
Form_pg_class rd_rel = new_rel_desc->rd_rel;
|
|
Datum values[Natts_pg_class];
|
|
*************** InsertPgClassTuple(Relation pg_class_des
|
|
*** 690,695 ****
|
|
--- 733,741 ----
|
|
*/
|
|
HeapTupleSetOid(tup, new_rel_oid);
|
|
|
|
+ if (HeapTupleHasSecLabel(tup))
|
|
+ HeapTupleSetSecLabel(tup, new_rel_secid);
|
|
+
|
|
/* finally insert the new tuple, update the indexes, and clean up */
|
|
simple_heap_insert(pg_class_desc, tup);
|
|
|
|
*************** AddNewRelationTuple(Relation pg_class_de
|
|
*** 712,720 ****
|
|
Oid new_type_oid,
|
|
Oid relowner,
|
|
char relkind,
|
|
! Datum reloptions)
|
|
{
|
|
Form_pg_class new_rel_reltup;
|
|
|
|
/*
|
|
* first we update some of the information in our uncataloged relation's
|
|
--- 758,768 ----
|
|
Oid new_type_oid,
|
|
Oid relowner,
|
|
char relkind,
|
|
! Datum reloptions,
|
|
! Oid *secLabels)
|
|
{
|
|
Form_pg_class new_rel_reltup;
|
|
+ Oid new_rel_secid = InvalidOid;
|
|
|
|
/*
|
|
* first we update some of the information in our uncataloged relation's
|
|
*************** AddNewRelationTuple(Relation pg_class_de
|
|
*** 771,778 ****
|
|
|
|
new_rel_desc->rd_att->tdtypeid = new_type_oid;
|
|
|
|
/* Now build and insert the tuple */
|
|
! InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions);
|
|
}
|
|
|
|
|
|
--- 819,830 ----
|
|
|
|
new_rel_desc->rd_att->tdtypeid = new_type_oid;
|
|
|
|
+ if (secLabels)
|
|
+ new_rel_secid = secLabels[0];
|
|
+
|
|
/* Now build and insert the tuple */
|
|
! InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
|
|
! reloptions, new_rel_secid);
|
|
}
|
|
|
|
|
|
*************** heap_create_with_catalog(const char *rel
|
|
*** 843,849 ****
|
|
int oidinhcount,
|
|
OnCommitAction oncommit,
|
|
Datum reloptions,
|
|
! bool allow_system_table_mods)
|
|
{
|
|
Relation pg_class_desc;
|
|
Relation new_rel_desc;
|
|
--- 895,902 ----
|
|
int oidinhcount,
|
|
OnCommitAction oncommit,
|
|
Datum reloptions,
|
|
! bool allow_system_table_mods,
|
|
! Oid *secLabels)
|
|
{
|
|
Relation pg_class_desc;
|
|
Relation new_rel_desc;
|
|
*************** heap_create_with_catalog(const char *rel
|
|
*** 1019,1031 ****
|
|
new_type_oid,
|
|
ownerid,
|
|
relkind,
|
|
! reloptions);
|
|
|
|
/*
|
|
* now add tuples to pg_attribute for the attributes in our new relation.
|
|
*/
|
|
AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind,
|
|
! oidislocal, oidinhcount);
|
|
|
|
/*
|
|
* Make a dependency link to force the relation to be deleted if its
|
|
--- 1072,1085 ----
|
|
new_type_oid,
|
|
ownerid,
|
|
relkind,
|
|
! reloptions,
|
|
! secLabels);
|
|
|
|
/*
|
|
* now add tuples to pg_attribute for the attributes in our new relation.
|
|
*/
|
|
AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind,
|
|
! oidislocal, oidinhcount, secLabels);
|
|
|
|
/*
|
|
* Make a dependency link to force the relation to be deleted if its
|
|
*************** heap_drop_with_catalog(Oid relid)
|
|
*** 1484,1489 ****
|
|
--- 1538,1548 ----
|
|
* delete relation tuple
|
|
*/
|
|
DeleteRelationTuple(relid);
|
|
+
|
|
+ /*
|
|
+ * delete orphan pg_security entries
|
|
+ */
|
|
+ securityReclaimOnDropTable(relid);
|
|
}
|
|
|
|
|
|
diff -Nrpc base/src/backend/catalog/index.c sepgsql/src/backend/catalog/index.c
|
|
*** base/src/backend/catalog/index.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/catalog/index.c Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 48,53 ****
|
|
--- 48,54 ----
|
|
#include "nodes/nodeFuncs.h"
|
|
#include "optimizer/clauses.h"
|
|
#include "optimizer/var.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/lmgr.h"
|
|
#include "storage/procarray.h"
|
|
*************** static TupleDesc ConstructTupleDescripto
|
|
*** 81,87 ****
|
|
Oid *classObjectId);
|
|
static void InitializeAttributeOids(Relation indexRelation,
|
|
int numatts, Oid indexoid);
|
|
! static void AppendAttributeTuples(Relation indexRelation, int numatts);
|
|
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
|
|
IndexInfo *indexInfo,
|
|
Oid *classOids,
|
|
--- 82,88 ----
|
|
Oid *classObjectId);
|
|
static void InitializeAttributeOids(Relation indexRelation,
|
|
int numatts, Oid indexoid);
|
|
! static void AppendAttributeTuples(Relation indexRelation, int numatts, Oid *secLabels);
|
|
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
|
|
IndexInfo *indexInfo,
|
|
Oid *classOids,
|
|
*************** InitializeAttributeOids(Relation indexRe
|
|
*** 323,333 ****
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
static void
|
|
! AppendAttributeTuples(Relation indexRelation, int numatts)
|
|
{
|
|
Relation pg_attribute;
|
|
CatalogIndexState indstate;
|
|
TupleDesc indexTupDesc;
|
|
int i;
|
|
|
|
/*
|
|
--- 324,335 ----
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
static void
|
|
! AppendAttributeTuples(Relation indexRelation, int numatts, Oid *secLabels)
|
|
{
|
|
Relation pg_attribute;
|
|
CatalogIndexState indstate;
|
|
TupleDesc indexTupDesc;
|
|
+ Oid attsid = InvalidOid;
|
|
int i;
|
|
|
|
/*
|
|
*************** AppendAttributeTuples(Relation indexRela
|
|
*** 351,357 ****
|
|
Assert(indexTupDesc->attrs[i]->attnum == i + 1);
|
|
Assert(indexTupDesc->attrs[i]->attcacheoff == -1);
|
|
|
|
! InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], indstate);
|
|
}
|
|
|
|
CatalogCloseIndexes(indstate);
|
|
--- 353,363 ----
|
|
Assert(indexTupDesc->attrs[i]->attnum == i + 1);
|
|
Assert(indexTupDesc->attrs[i]->attcacheoff == -1);
|
|
|
|
! if (secLabels)
|
|
! attsid = secLabels[i - FirstLowInvalidHeapAttributeNumber];
|
|
!
|
|
! InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i],
|
|
! indstate, attsid);
|
|
}
|
|
|
|
CatalogCloseIndexes(indstate);
|
|
*************** index_create(Oid heapRelationId,
|
|
*** 519,524 ****
|
|
--- 525,532 ----
|
|
TupleDesc indexTupDesc;
|
|
bool shared_relation;
|
|
Oid namespaceId;
|
|
+ Oid *secLabels;
|
|
+ Oid relsid = InvalidOid;
|
|
int i;
|
|
|
|
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
|
|
*************** index_create(Oid heapRelationId,
|
|
*** 604,609 ****
|
|
--- 612,625 ----
|
|
classObjectId);
|
|
|
|
/*
|
|
+ * compute security labels to be assigned on index relation
|
|
+ */
|
|
+ secLabels = sepgsqlCreateTableColumns(NULL, indexRelationName, namespaceId,
|
|
+ indexTupDesc, RELKIND_INDEX);
|
|
+ if (secLabels)
|
|
+ relsid = secLabels[0];
|
|
+
|
|
+ /*
|
|
* Allocate an OID for the index, unless we were told what to use.
|
|
*
|
|
* The OID will be the relfilenode as well, so make sure it doesn't
|
|
*************** index_create(Oid heapRelationId,
|
|
*** 652,658 ****
|
|
*/
|
|
InsertPgClassTuple(pg_class, indexRelation,
|
|
RelationGetRelid(indexRelation),
|
|
! reloptions);
|
|
|
|
/* done with pg_class */
|
|
heap_close(pg_class, RowExclusiveLock);
|
|
--- 668,674 ----
|
|
*/
|
|
InsertPgClassTuple(pg_class, indexRelation,
|
|
RelationGetRelid(indexRelation),
|
|
! reloptions, relsid);
|
|
|
|
/* done with pg_class */
|
|
heap_close(pg_class, RowExclusiveLock);
|
|
*************** index_create(Oid heapRelationId,
|
|
*** 668,674 ****
|
|
/*
|
|
* append ATTRIBUTE tuples for the index
|
|
*/
|
|
! AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
|
|
|
|
/* ----------------
|
|
* update pg_index
|
|
--- 684,690 ----
|
|
/*
|
|
* append ATTRIBUTE tuples for the index
|
|
*/
|
|
! AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs, secLabels);
|
|
|
|
/* ----------------
|
|
* update pg_index
|
|
diff -Nrpc base/src/backend/catalog/namespace.c sepgsql/src/backend/catalog/namespace.c
|
|
*** base/src/backend/catalog/namespace.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/catalog/namespace.c Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 39,44 ****
|
|
--- 39,45 ----
|
|
#include "miscadmin.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/parse_func.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/backendid.h"
|
|
#include "storage/ipc.h"
|
|
#include "utils/acl.h"
|
|
*************** InitTempTableNamespace(void)
|
|
*** 2816,2821 ****
|
|
--- 2817,2823 ----
|
|
char namespaceName[NAMEDATALEN];
|
|
Oid namespaceId;
|
|
Oid toastspaceId;
|
|
+ Oid nspsecid;
|
|
|
|
Assert(!OidIsValid(myTempNamespace));
|
|
|
|
*************** InitTempTableNamespace(void)
|
|
*** 2836,2841 ****
|
|
--- 2838,2846 ----
|
|
errmsg("permission denied to create temporary tables in database \"%s\"",
|
|
get_database_name(MyDatabaseId))));
|
|
|
|
+ /* SELinux checks db_schema_temp:{create} */
|
|
+ nspsecid = sepgsqlCheckSchemaCreate(namespaceName, NULL, true);
|
|
+
|
|
snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
|
|
|
|
namespaceId = GetSysCacheOid(NAMESPACENAME,
|
|
*************** InitTempTableNamespace(void)
|
|
*** 2851,2857 ****
|
|
* temp tables. This works because the places that access the temp
|
|
* namespace for my own backend skip permissions checks on it.
|
|
*/
|
|
! namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID);
|
|
/* Advance command counter to make namespace visible */
|
|
CommandCounterIncrement();
|
|
}
|
|
--- 2856,2864 ----
|
|
* temp tables. This works because the places that access the temp
|
|
* namespace for my own backend skip permissions checks on it.
|
|
*/
|
|
! namespaceId = NamespaceCreate(namespaceName,
|
|
! BOOTSTRAP_SUPERUSERID,
|
|
! nspsecid);
|
|
/* Advance command counter to make namespace visible */
|
|
CommandCounterIncrement();
|
|
}
|
|
*************** InitTempTableNamespace(void)
|
|
*** 2877,2883 ****
|
|
0, 0, 0);
|
|
if (!OidIsValid(toastspaceId))
|
|
{
|
|
! toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID);
|
|
/* Advance command counter to make namespace visible */
|
|
CommandCounterIncrement();
|
|
}
|
|
--- 2884,2892 ----
|
|
0, 0, 0);
|
|
if (!OidIsValid(toastspaceId))
|
|
{
|
|
! toastspaceId = NamespaceCreate(namespaceName,
|
|
! BOOTSTRAP_SUPERUSERID,
|
|
! nspsecid);
|
|
/* Advance command counter to make namespace visible */
|
|
CommandCounterIncrement();
|
|
}
|
|
*************** RemoveTempRelations(Oid tempNamespaceId)
|
|
*** 3030,3035 ****
|
|
--- 3039,3051 ----
|
|
object.objectId = tempNamespaceId;
|
|
object.objectSubId = 0;
|
|
|
|
+ /*
|
|
+ * TODO:
|
|
+ * SELinux should not check db_xxx:{drop} permission during cleaning
|
|
+ * up all the temporary objects. It may be necessary a bool argument
|
|
+ * to control MAC permission check on deleteOneObject() called from
|
|
+ * deleteWhatDependsOn() and so on.
|
|
+ */
|
|
deleteWhatDependsOn(&object, false);
|
|
}
|
|
|
|
diff -Nrpc base/src/backend/catalog/pg_aggregate.c sepgsql/src/backend/catalog/pg_aggregate.c
|
|
*** base/src/backend/catalog/pg_aggregate.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/catalog/pg_aggregate.c Wed Jul 15 19:37:35 2009
|
|
*************** AggregateCreate(const char *aggName,
|
|
*** 231,237 ****
|
|
NIL, /* parameterDefaults */
|
|
PointerGetDatum(NULL), /* proconfig */
|
|
1, /* procost */
|
|
! 0); /* prorows */
|
|
|
|
/*
|
|
* Okay to create the pg_aggregate entry.
|
|
--- 231,238 ----
|
|
NIL, /* parameterDefaults */
|
|
PointerGetDatum(NULL), /* proconfig */
|
|
1, /* procost */
|
|
! 0, /* prorows */
|
|
! NULL); /* proseclabel*/
|
|
|
|
/*
|
|
* Okay to create the pg_aggregate entry.
|
|
diff -Nrpc base/src/backend/catalog/pg_largeobject.c sepgsql/src/backend/catalog/pg_largeobject.c
|
|
*** base/src/backend/catalog/pg_largeobject.c Sat Jan 3 13:01:35 2009
|
|
--- sepgsql/src/backend/catalog/pg_largeobject.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 18,23 ****
|
|
--- 18,24 ----
|
|
#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"
|
|
#include "utils/rel.h"
|
|
*************** LargeObjectCreate(Oid loid)
|
|
*** 59,64 ****
|
|
--- 60,68 ----
|
|
|
|
ntup = heap_form_tuple(pg_largeobject->rd_att, values, nulls);
|
|
|
|
+ /* SELinux checks db_blob:{create} */
|
|
+ sepgsqlCheckBlobCreate(pg_largeobject, ntup);
|
|
+
|
|
/*
|
|
* Insert it
|
|
*/
|
|
*************** LargeObjectDrop(Oid loid)
|
|
*** 93,98 ****
|
|
--- 97,105 ----
|
|
|
|
while ((tuple = systable_getnext(sd)) != NULL)
|
|
{
|
|
+ /* SELinux checks db_blob:{drop} */
|
|
+ if (!found)
|
|
+ sepgsqlCheckBlobDrop(pg_largeobject, tuple);
|
|
simple_heap_delete(pg_largeobject, &tuple->t_self);
|
|
found = true;
|
|
}
|
|
diff -Nrpc base/src/backend/catalog/pg_namespace.c sepgsql/src/backend/catalog/pg_namespace.c
|
|
*** base/src/backend/catalog/pg_namespace.c Sat Jan 3 13:01:35 2009
|
|
--- sepgsql/src/backend/catalog/pg_namespace.c Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 28,34 ****
|
|
* ---------------
|
|
*/
|
|
Oid
|
|
! NamespaceCreate(const char *nspName, Oid ownerId)
|
|
{
|
|
Relation nspdesc;
|
|
HeapTuple tup;
|
|
--- 28,34 ----
|
|
* ---------------
|
|
*/
|
|
Oid
|
|
! NamespaceCreate(const char *nspName, Oid ownerId, Oid nspsecid)
|
|
{
|
|
Relation nspdesc;
|
|
HeapTuple tup;
|
|
*************** NamespaceCreate(const char *nspName, Oid
|
|
*** 66,71 ****
|
|
--- 66,73 ----
|
|
tupDesc = nspdesc->rd_att;
|
|
|
|
tup = heap_form_tuple(tupDesc, values, nulls);
|
|
+ if (HeapTupleHasSecLabel(tup))
|
|
+ HeapTupleSetSecLabel(tup, nspsecid);
|
|
|
|
nspoid = simple_heap_insert(nspdesc, tup);
|
|
Assert(OidIsValid(nspoid));
|
|
diff -Nrpc base/src/backend/catalog/pg_proc.c sepgsql/src/backend/catalog/pg_proc.c
|
|
*** base/src/backend/catalog/pg_proc.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/catalog/pg_proc.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 29,34 ****
|
|
--- 29,35 ----
|
|
#include "miscadmin.h"
|
|
#include "nodes/nodeFuncs.h"
|
|
#include "parser/parse_type.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "tcop/pquery.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/acl.h"
|
|
*************** ProcedureCreate(const char *procedureNam
|
|
*** 78,84 ****
|
|
List *parameterDefaults,
|
|
Datum proconfig,
|
|
float4 procost,
|
|
! float4 prorows)
|
|
{
|
|
Oid retval;
|
|
int parameterCount;
|
|
--- 79,86 ----
|
|
List *parameterDefaults,
|
|
Datum proconfig,
|
|
float4 procost,
|
|
! float4 prorows,
|
|
! Node *proseclabel)
|
|
{
|
|
Oid retval;
|
|
int parameterCount;
|
|
*************** ProcedureCreate(const char *procedureNam
|
|
*** 96,101 ****
|
|
--- 98,104 ----
|
|
Datum values[Natts_pg_proc];
|
|
bool replaces[Natts_pg_proc];
|
|
Oid relid;
|
|
+ Oid prosecid = InvalidOid;
|
|
NameData procname;
|
|
TupleDesc tupDesc;
|
|
bool is_update;
|
|
*************** ProcedureCreate(const char *procedureNam
|
|
*** 357,362 ****
|
|
--- 360,377 ----
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
procedureName);
|
|
|
|
+ /* SELinux checks db_procedure:{setattr},
|
|
+ * and db_procedure:{relabelfrom relabelto} if necessary. */
|
|
+ if (!proseclabel)
|
|
+ sepgsqlCheckProcedureSetattr(HeapTupleGetOid(oldtup));
|
|
+ else
|
|
+ prosecid = sepgsqlCheckProcedureRelabel(HeapTupleGetOid(oldtup),
|
|
+ (DefElem *)proseclabel);
|
|
+
|
|
+ /* SELinux checks db_database:{install_module}, if necessary */
|
|
+ if (probin && languageObjectId == ClanguageId)
|
|
+ sepgsqlCheckDatabaseInstallModule(probin, oldtup);
|
|
+
|
|
/*
|
|
* Not okay to change the return type of the existing proc, since
|
|
* existing rules, views, etc may depend on the return type.
|
|
*************** ProcedureCreate(const char *procedureNam
|
|
*** 477,482 ****
|
|
--- 492,499 ----
|
|
|
|
/* Okay, do it... */
|
|
tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
|
|
+ if (HeapTupleHasSecLabel(tup) && OidIsValid(prosecid))
|
|
+ HeapTupleSetSecLabel(tup, prosecid);
|
|
simple_heap_update(rel, &tup->t_self, tup);
|
|
|
|
ReleaseSysCache(oldtup);
|
|
*************** ProcedureCreate(const char *procedureNam
|
|
*** 484,491 ****
|
|
--- 501,519 ----
|
|
}
|
|
else
|
|
{
|
|
+ /* SELinux checks db_procedure:{create} */
|
|
+ prosecid = sepgsqlCheckProcedureCreate(procedureName,
|
|
+ procNamespace,
|
|
+ (DefElem *)proseclabel);
|
|
+
|
|
+ /* SELinux checks db_database:{install_module}, if necessary */
|
|
+ if (probin && languageObjectId == ClanguageId)
|
|
+ sepgsqlCheckDatabaseInstallModule(probin, NULL);
|
|
+
|
|
/* Creating a new procedure */
|
|
tup = heap_form_tuple(tupDesc, values, nulls);
|
|
+ if (HeapTupleHasSecLabel(tup))
|
|
+ HeapTupleSetSecLabel(tup, prosecid);
|
|
simple_heap_insert(rel, tup);
|
|
is_update = false;
|
|
}
|
|
diff -Nrpc base/src/backend/catalog/pg_security.c sepgsql/src/backend/catalog/pg_security.c
|
|
*** base/src/backend/catalog/pg_security.c Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/catalog/pg_security.c Fri Jul 17 16:31:54 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,680 ----
|
|
+ /*
|
|
+ * 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/genam.h"
|
|
+ #include "access/heapam.h"
|
|
+ #include "access/sysattr.h"
|
|
+ #include "access/xact.h"
|
|
+ #include "catalog/catalog.h"
|
|
+ #include "catalog/indexing.h"
|
|
+ #include "catalog/pg_proc.h"
|
|
+ #include "catalog/pg_security.h"
|
|
+ #include "catalog/pg_type.h"
|
|
+ #include "executor/spi.h"
|
|
+ #include "miscadmin.h"
|
|
+ #include "security/rowlevel.h"
|
|
+ #include "security/sepgsql.h"
|
|
+ #include "utils/builtins.h"
|
|
+ #include "utils/fmgroids.h"
|
|
+ #include "utils/memutils.h"
|
|
+ #include "utils/rel.h"
|
|
+ #include "utils/lsyscache.h"
|
|
+ #include "utils/syscache.h"
|
|
+ #include "utils/tqual.h"
|
|
+
|
|
+ bool
|
|
+ securityTupleDescHasSecLabel(Oid relid, char relkind)
|
|
+ {
|
|
+ return sepgsqlTupleDescHasSecLabel(relid, relkind);
|
|
+ }
|
|
+
|
|
+ static char *
|
|
+ securityMetaSecurityLabel(void)
|
|
+ {
|
|
+ return sepgsqlMetaSecurityLabel();
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * security attribute management at the initdb phase.
|
|
+ */
|
|
+ typedef struct earlySecAttr
|
|
+ {
|
|
+ struct earlySecAttr *next;
|
|
+ Oid secid;
|
|
+ Oid datid;
|
|
+ Oid relid;
|
|
+ char seckind;
|
|
+ char secattr[1];
|
|
+ } earlySecAttr;
|
|
+
|
|
+ static earlySecAttr *earlySecAttrList = NULL;
|
|
+
|
|
+ static Oid
|
|
+ earlyInputSecurityAttr(Oid datid, Oid relid, char seckind, const char *secattr)
|
|
+ {
|
|
+ static Oid dummySecid = SecurityRelationId;
|
|
+ earlySecAttr *es;
|
|
+
|
|
+ for (es = earlySecAttrList; es; es = es->next)
|
|
+ {
|
|
+ if (es->datid == datid &&
|
|
+ es->relid == relid &&
|
|
+ es->seckind == seckind &&
|
|
+ strcmp(es->secattr, secattr) == 0)
|
|
+ return es->secid;
|
|
+ }
|
|
+ /* Not found */
|
|
+ es = MemoryContextAlloc(TopMemoryContext,
|
|
+ sizeof(*es) + strlen(secattr));
|
|
+ es->secid = --dummySecid;
|
|
+ es->datid = datid;
|
|
+ es->relid = relid;
|
|
+ es->seckind = seckind;
|
|
+ strcpy(es->secattr, secattr);
|
|
+
|
|
+ es->next = earlySecAttrList;
|
|
+ earlySecAttrList = es;
|
|
+
|
|
+ return es->secid;
|
|
+ }
|
|
+
|
|
+ static char *
|
|
+ earlyOutputSecurityAttr(Oid datid, Oid relid, char seckind, Oid secid)
|
|
+ {
|
|
+ earlySecAttr *es;
|
|
+
|
|
+ for (es = earlySecAttrList; es; es = es->next)
|
|
+ {
|
|
+ if (es->datid == datid &&
|
|
+ es->relid == relid &&
|
|
+ es->seckind == seckind &&
|
|
+ es->secid == secid)
|
|
+ return pstrdup(es->secattr);
|
|
+ }
|
|
+ return NULL; /* Not found */
|
|
+ }
|
|
+
|
|
+ void
|
|
+ securityPostBootstrapingMode(void)
|
|
+ {
|
|
+ Relation rel;
|
|
+ HeapTuple tuple;
|
|
+ earlySecAttr *es;
|
|
+ char *meta_label;
|
|
+ Oid meta_secid = InvalidOid;
|
|
+ Datum values[Natts_pg_security];
|
|
+ bool nulls[Natts_pg_security];
|
|
+
|
|
+ if (!earlySecAttrList)
|
|
+ return; /* do nothing */
|
|
+
|
|
+ StartTransactionCommand();
|
|
+
|
|
+ /* security_label on the pg_security */
|
|
+ meta_label = securityMetaSecurityLabel();
|
|
+ if (meta_label)
|
|
+ meta_secid = securityTransSecLabelIn(SecurityRelationId, meta_label);
|
|
+
|
|
+ /* flush all the cached entries */
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+ for (es = earlySecAttrList; es; es = es->next)
|
|
+ {
|
|
+ memset(nulls, false, sizeof(nulls));
|
|
+ values[Anum_pg_security_secid - 1] = ObjectIdGetDatum(es->secid);
|
|
+ values[Anum_pg_security_datid - 1] = ObjectIdGetDatum(es->datid);
|
|
+ values[Anum_pg_security_relid - 1] = ObjectIdGetDatum(es->relid);
|
|
+ values[Anum_pg_security_seckind - 1] = CharGetDatum(es->seckind);
|
|
+ values[Anum_pg_security_secattr - 1] = CStringGetTextDatum(es->secattr);
|
|
+
|
|
+ tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, meta_secid);
|
|
+
|
|
+ simple_heap_insert(rel, tuple);
|
|
+ CatalogUpdateIndexes(rel, tuple);
|
|
+ heap_freetuple(tuple);
|
|
+ }
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+
|
|
+ CommitTransactionCommand();
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * securityOnCreateDatabase
|
|
+ * copies all the entries refered by source database
|
|
+ */
|
|
+ void
|
|
+ securityOnCreateDatabase(Oid src_datid, Oid dst_datid)
|
|
+ {
|
|
+ Relation rel;
|
|
+ ScanKeyData keys[1];
|
|
+ SysScanDesc scan;
|
|
+ HeapTuple oldtup, newtup;
|
|
+ Datum values[Natts_pg_security];
|
|
+ bool nulls[Natts_pg_security];
|
|
+ bool replaces[Natts_pg_security];
|
|
+
|
|
+ /* Scan all entries with pg_security.datid = src_datid */
|
|
+ ScanKeyInit(&keys[0],
|
|
+ Anum_pg_security_datid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(src_datid));
|
|
+
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+
|
|
+ scan = systable_beginscan(rel, SecuritySecidIndexId, true,
|
|
+ SnapshotNow, 1, keys);
|
|
+
|
|
+ /* pg_security.datid shall be replaced */
|
|
+ memset(values, 0, sizeof(values));
|
|
+ memset(nulls, false, sizeof(nulls));
|
|
+ memset(replaces, false, sizeof(replaces));
|
|
+
|
|
+ values[Anum_pg_security_datid - 1] = ObjectIdGetDatum(dst_datid);
|
|
+ replaces[Anum_pg_security_datid - 1] = true;
|
|
+
|
|
+ while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
|
|
+ {
|
|
+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
|
|
+ values, nulls, replaces);
|
|
+ simple_heap_insert(rel, newtup);
|
|
+
|
|
+ CatalogUpdateIndexes(rel, newtup);
|
|
+
|
|
+ heap_freetuple(newtup);
|
|
+ }
|
|
+ systable_endscan(scan);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * securityOnDropDatabase
|
|
+ * drops all the entries refered by dropped database
|
|
+ */
|
|
+ void
|
|
+ securityOnDropDatabase(Oid datid)
|
|
+ {
|
|
+ Relation rel;
|
|
+ ScanKeyData keys[1];
|
|
+ SysScanDesc scan;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ /* Scan all entries with pg_security.datid = datid */
|
|
+ ScanKeyInit(&keys[0],
|
|
+ Anum_pg_security_datid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(datid));
|
|
+
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+
|
|
+ scan = systable_beginscan(rel, SecuritySecidIndexId, true,
|
|
+ SnapshotNow, 1, keys);
|
|
+
|
|
+ while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
|
+ {
|
|
+ simple_heap_delete(rel, &tuple->t_self);
|
|
+ }
|
|
+
|
|
+ systable_endscan(scan);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * InputSecurityAttr
|
|
+ */
|
|
+ static Oid
|
|
+ InputSecurityAttr(Oid relid, char seckind, const char *secattr)
|
|
+ {
|
|
+ Relation rel;
|
|
+ HeapTuple tuple;
|
|
+ Oid datid;
|
|
+ Oid secid;
|
|
+ char *meta_label;
|
|
+ Oid meta_secid = InvalidOid;
|
|
+ Datum values[Natts_pg_security];
|
|
+ bool nulls[Natts_pg_security];
|
|
+
|
|
+ datid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId);
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ return earlyInputSecurityAttr(datid, relid, seckind, secattr);
|
|
+
|
|
+ /*
|
|
+ * Lookup the syscache first
|
|
+ */
|
|
+ tuple = SearchSysCache(SECURITYATTR,
|
|
+ ObjectIdGetDatum(datid),
|
|
+ ObjectIdGetDatum(relid),
|
|
+ CharGetDatum(seckind),
|
|
+ CStringGetTextDatum(secattr));
|
|
+ if (HeapTupleIsValid(tuple))
|
|
+ {
|
|
+ secid = ((Form_pg_security) GETSTRUCT(tuple))->secid;
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return secid;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Insert a new tuple, if not exist
|
|
+ */
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+
|
|
+ memset(nulls, false, sizeof(nulls));
|
|
+ secid = GetNewOidWithIndex(rel, SecuritySecidIndexId,
|
|
+ Anum_pg_security_secid);
|
|
+ values[Anum_pg_security_secid - 1] = ObjectIdGetDatum(secid);
|
|
+ values[Anum_pg_security_datid - 1] = ObjectIdGetDatum(datid);
|
|
+ values[Anum_pg_security_relid - 1] = ObjectIdGetDatum(relid);
|
|
+ values[Anum_pg_security_seckind - 1] = CharGetDatum(seckind);
|
|
+ values[Anum_pg_security_secattr - 1] = CStringGetTextDatum(secattr);
|
|
+
|
|
+ meta_label = securityMetaSecurityLabel();
|
|
+ if (meta_label)
|
|
+ {
|
|
+ if (datid == InvalidOid &&
|
|
+ relid == SecurityRelationId &&
|
|
+ seckind == SECKIND_SECURITY_LABEL &&
|
|
+ strcmp(meta_label, secattr) == 0)
|
|
+ meta_secid = secid;
|
|
+ else
|
|
+ meta_secid = securityTransSecLabelIn(SecurityRelationId, meta_label);
|
|
+ }
|
|
+
|
|
+ tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, meta_secid);
|
|
+
|
|
+ simple_heap_insert(rel, tuple);
|
|
+ CatalogUpdateIndexes(rel, tuple);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+
|
|
+ /*
|
|
+ * Newly inserted security label needs to be visible by
|
|
+ * later operations in this transaction.
|
|
+ */
|
|
+ CommandCounterIncrement();
|
|
+
|
|
+ return secid;
|
|
+ }
|
|
+
|
|
+ static char *
|
|
+ OutputSecurityAttr(Oid relid, char seckind, Oid secid)
|
|
+ {
|
|
+ Form_pg_security secForm;
|
|
+ Oid datid;
|
|
+ HeapTuple tuple;
|
|
+ Datum datum;
|
|
+ bool isnull;
|
|
+ char *result;
|
|
+
|
|
+ datid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId);
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ return earlyOutputSecurityAttr(datid, relid, seckind, secid);
|
|
+
|
|
+ tuple = SearchSysCache(SECURITYSECID,
|
|
+ ObjectIdGetDatum(secid),
|
|
+ ObjectIdGetDatum(datid),
|
|
+ 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ return NULL;
|
|
+
|
|
+ /*
|
|
+ * Integrity checks
|
|
+ */
|
|
+ secForm = (Form_pg_security) GETSTRUCT(tuple);
|
|
+ if (secForm->relid != relid)
|
|
+ goto error;
|
|
+ if (secForm->seckind != seckind)
|
|
+ goto error;
|
|
+ datum = SysCacheGetAttr(SECURITYSECID, tuple,
|
|
+ Anum_pg_security_secattr,
|
|
+ &isnull);
|
|
+ if (isnull)
|
|
+ goto error;
|
|
+
|
|
+ result = TextDatumGetCString(datum);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return result;
|
|
+
|
|
+ error:
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ elog(NOTICE,
|
|
+ "invalid pg_security (secid=%u, datid=%u, relid=%u, seckind=%c)"
|
|
+ " for relid=%u, seckind=%c secid=%u",
|
|
+ secForm->secid, secForm->datid, secForm->relid, secForm->seckind,
|
|
+ relid, seckind, secid);
|
|
+
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * input/output handler
|
|
+ */
|
|
+ Oid
|
|
+ securityRawSecLabelIn(Oid relid, char *seclabel)
|
|
+ {
|
|
+ seclabel = sepgsqlRawSecLabelIn(seclabel);
|
|
+
|
|
+ return InputSecurityAttr(relid, SECKIND_SECURITY_LABEL, seclabel);
|
|
+ }
|
|
+
|
|
+ char *
|
|
+ securityRawSecLabelOut(Oid relid, Oid secid)
|
|
+ {
|
|
+ char *seclabel = OutputSecurityAttr(relid, SECKIND_SECURITY_LABEL, secid);
|
|
+
|
|
+ return sepgsqlRawSecLabelOut(seclabel);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ securityTransSecLabelIn(Oid relid, char *seclabel)
|
|
+ {
|
|
+ seclabel = sepgsqlTransSecLabelIn(seclabel);
|
|
+
|
|
+ return securityRawSecLabelIn(relid, seclabel);
|
|
+ }
|
|
+
|
|
+ char *
|
|
+ securityTransSecLabelOut(Oid relid, Oid secid)
|
|
+ {
|
|
+ char *seclabel = securityRawSecLabelOut(relid, secid);
|
|
+
|
|
+ return sepgsqlTransSecLabelOut(seclabel);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ securityMoveSecLabel(Oid dstid, Oid srcid, Oid secid)
|
|
+ {
|
|
+ char *seclabel = securityRawSecLabelOut(srcid, secid);
|
|
+
|
|
+ if (!seclabel)
|
|
+ return InvalidOid;
|
|
+
|
|
+ return securityRawSecLabelIn(dstid, seclabel);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Output handler for system columns
|
|
+ */
|
|
+ Datum
|
|
+ securityHeapGetSecLabelSysattr(HeapTuple tuple)
|
|
+ {
|
|
+ Oid secid = HeapTupleGetSecLabel(tuple);
|
|
+ char *seclabel;
|
|
+
|
|
+ seclabel = securityTransSecLabelOut(tuple->t_tableOid, secid);
|
|
+ if (!seclabel)
|
|
+ seclabel = pstrdup("unlabeled");
|
|
+
|
|
+ return CStringGetTextDatum(seclabel);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * securityReclaimOnDropTable
|
|
+ * drop orphan entries within pg_security on drop table
|
|
+ */
|
|
+ void
|
|
+ securityReclaimOnDropTable(Oid relid)
|
|
+ {
|
|
+ Relation rel;
|
|
+ SysScanDesc scan;
|
|
+ ScanKeyData key[2];
|
|
+ HeapTuple tuple;
|
|
+ Oid database_oid;
|
|
+
|
|
+ database_oid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId);
|
|
+ ScanKeyInit(&key[0],
|
|
+ Anum_pg_security_datid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(database_oid));
|
|
+ ScanKeyInit(&key[1],
|
|
+ Anum_pg_security_relid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(relid));
|
|
+
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+ scan = systable_beginscan(rel, SecuritySecattrIndexId, true,
|
|
+ SnapshotNow, 2, key);
|
|
+ while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
|
+ simple_heap_delete(rel, &tuple->t_self);
|
|
+
|
|
+ systable_endscan(scan);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * security_quote_relation
|
|
+ * returns palloc'de identifier with explicit namespace
|
|
+ */
|
|
+ static char *
|
|
+ security_quote_relation(Oid relid)
|
|
+ {
|
|
+ Oid nspoid = get_rel_namespace(relid);
|
|
+ char *nspname;
|
|
+ char *relname;
|
|
+
|
|
+ nspname = get_namespace_name(nspoid);
|
|
+ relname = get_rel_name(relid);
|
|
+
|
|
+ return quote_qualified_identifier(nspname, relname);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * security_reclaim_table
|
|
+ * reclaims orphan entries associated to a certain table
|
|
+ */
|
|
+ static int
|
|
+ security_reclaim_table(Oid relid, char seckind)
|
|
+ {
|
|
+ StringInfoData query;
|
|
+ SPIPlanPtr plan;
|
|
+ Oid types[2];
|
|
+ Datum values[2];
|
|
+ Oid proc_oid;
|
|
+ Oid database_oid;
|
|
+ char *relname_full;
|
|
+ char *attname_datid;
|
|
+ char *attname_relid;
|
|
+ char *attname_secid;
|
|
+ char *attname_seckind;
|
|
+ char *attname_secattr;
|
|
+ char *sec_proname;
|
|
+ char *sec_nspname;
|
|
+ Form_pg_proc proForm;
|
|
+ HeapTuple protup;
|
|
+
|
|
+ /*
|
|
+ * LOCK the target table
|
|
+ */
|
|
+ initStringInfo(&query);
|
|
+ relname_full = security_quote_relation(relid);
|
|
+ appendStringInfo(&query, "LOCK %s IN SHARE MODE", relname_full);
|
|
+ if (SPI_execute(query.data, false, 0) != SPI_OK_UTILITY)
|
|
+ elog(ERROR, "SPI_execute failed on %s", query.data);
|
|
+
|
|
+ /*
|
|
+ * DELETE orphan entries
|
|
+ */
|
|
+ initStringInfo(&query);
|
|
+ attname_secid = get_attname(SecurityRelationId, Anum_pg_security_secid);
|
|
+ attname_datid = get_attname(SecurityRelationId, Anum_pg_security_datid);
|
|
+ attname_relid = get_attname(SecurityRelationId, Anum_pg_security_relid);
|
|
+ attname_seckind = get_attname(SecurityRelationId, Anum_pg_security_seckind);
|
|
+ attname_secattr = get_attname(SecurityRelationId, Anum_pg_security_secattr);
|
|
+
|
|
+ appendStringInfo(&query,
|
|
+ "DELETE FROM %s "
|
|
+ "WHERE %s = $1 AND %s = $2 "
|
|
+ " AND %s = $3 AND %s NOT IN ",
|
|
+ security_quote_relation(SecurityRelationId),
|
|
+ quote_identifier(attname_datid),
|
|
+ quote_identifier(attname_relid),
|
|
+ quote_identifier(attname_seckind),
|
|
+ quote_identifier(attname_secid));
|
|
+ switch (seckind)
|
|
+ {
|
|
+ case SECKIND_SECURITY_LABEL:
|
|
+ proc_oid = F_SECURITY_LABEL_TO_SECID;
|
|
+ break;
|
|
+ default:
|
|
+ elog(ERROR, "unexpected seckind: %c", seckind);
|
|
+ proc_oid = InvalidOid; /* to compiler silent */
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ protup = SearchSysCache(PROCOID,
|
|
+ ObjectIdGetDatum(proc_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(protup))
|
|
+ elog(ERROR, "cache lookup failed for procedure: %u", proc_oid);
|
|
+ proForm = (Form_pg_proc) GETSTRUCT(protup);
|
|
+ sec_proname = NameStr(proForm->proname);
|
|
+ sec_nspname = get_namespace_name(proForm->pronamespace);
|
|
+
|
|
+ appendStringInfo(&query,
|
|
+ "(SELECT %s.%s(%s) FROM ONLY %s)",
|
|
+ quote_identifier(sec_nspname),
|
|
+ quote_identifier(sec_proname),
|
|
+ quote_identifier(get_rel_name(relid)),
|
|
+ relname_full);
|
|
+ ReleaseSysCache(protup);
|
|
+
|
|
+ /*
|
|
+ * Setup and execute query
|
|
+ */
|
|
+ types[0] = OIDOID;
|
|
+ types[1] = OIDOID;
|
|
+ types[2] = CHAROID;
|
|
+ plan = SPI_prepare(query.data, 3, types);
|
|
+ if (!plan)
|
|
+ elog(ERROR, "SPI_prepare failed on %s", query.data);
|
|
+
|
|
+ database_oid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId);
|
|
+
|
|
+ values[0] = ObjectIdGetDatum(database_oid);
|
|
+ values[1] = ObjectIdGetDatum(relid);
|
|
+ values[2] = CharGetDatum(seckind);
|
|
+ if (SPI_execute_plan(plan, values, NULL, false, 0) != SPI_OK_DELETE)
|
|
+ elog(ERROR, "SPI_execute_plan failed on %s", query.data);
|
|
+
|
|
+ SPI_freetuptable(SPI_tuptable);
|
|
+
|
|
+ return SPI_processed;
|
|
+ }
|
|
+
|
|
+ static int
|
|
+ security_reclaim_all_tables(char seckind)
|
|
+ {
|
|
+ StringInfoData query;
|
|
+ char *attname_datid;
|
|
+ char *attname_relid;
|
|
+ int index;
|
|
+ Datum datum;
|
|
+ bool isnull;
|
|
+ int count = 0;
|
|
+ List *relidList = NIL;
|
|
+ ListCell *l;
|
|
+
|
|
+ initStringInfo(&query);
|
|
+
|
|
+ attname_datid = get_attname(SecurityRelationId, Anum_pg_security_datid);
|
|
+ attname_relid = get_attname(SecurityRelationId, Anum_pg_security_relid);
|
|
+ appendStringInfo(&query,
|
|
+ "SELECT DISTINCT %s FROM %s WHERE %s IN (%u,%u)",
|
|
+ attname_relid,
|
|
+ security_quote_relation(SecurityRelationId),
|
|
+ attname_datid, InvalidOid, MyDatabaseId);
|
|
+
|
|
+ if (SPI_execute(query.data, true, 0) != SPI_OK_SELECT)
|
|
+ elog(ERROR, "SPI_execute failed on %s", query.data);
|
|
+
|
|
+ for (index = 0; index < SPI_processed; index++)
|
|
+ {
|
|
+ datum = SPI_getbinval(SPI_tuptable->vals[index],
|
|
+ SPI_tuptable->tupdesc, 1, &isnull);
|
|
+ if (isnull)
|
|
+ continue;
|
|
+ relidList = lappend_oid(relidList, DatumGetObjectId(datum));
|
|
+ }
|
|
+ SPI_freetuptable(SPI_tuptable);
|
|
+
|
|
+ foreach (l, relidList)
|
|
+ count += security_reclaim_table(lfirst_oid(l), seckind);
|
|
+
|
|
+ return count;
|
|
+ }
|
|
+
|
|
+ static int
|
|
+ security_reclaim(Oid relid, char seckind)
|
|
+ {
|
|
+ int saved_mode;
|
|
+ int count;
|
|
+
|
|
+ if (!superuser())
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
+ errmsg("must be superuser to reclaim security attributes")));
|
|
+ /*
|
|
+ * Disables SE-PostgreSQL temporary
|
|
+ */
|
|
+ saved_mode = sepgsqlSetEnforce(0);
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ if (SPI_connect() != SPI_OK_CONNECT)
|
|
+ elog(ERROR, "SPI_connect failed");
|
|
+
|
|
+ if (OidIsValid(relid))
|
|
+ count = security_reclaim_table(relid, seckind);
|
|
+ else
|
|
+ count = security_reclaim_all_tables(seckind);
|
|
+
|
|
+ if (SPI_finish() != SPI_OK_FINISH)
|
|
+ elog(ERROR, "SPI_finish failed");
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ sepgsqlSetEnforce(saved_mode);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ sepgsqlSetEnforce(saved_mode);
|
|
+
|
|
+ return count;
|
|
+ }
|
|
+
|
|
+ Datum
|
|
+ security_reclaim_label(PG_FUNCTION_ARGS)
|
|
+ {
|
|
+ PG_RETURN_INT32(security_reclaim(InvalidOid, SECKIND_SECURITY_LABEL));
|
|
+ }
|
|
+
|
|
+ Datum
|
|
+ security_reclaim_table_label(PG_FUNCTION_ARGS)
|
|
+ {
|
|
+ PG_RETURN_INT32(security_reclaim(PG_GETARG_OID(0), SECKIND_SECURITY_LABEL));
|
|
+ }
|
|
+
|
|
+ Datum
|
|
+ security_label_to_secid(PG_FUNCTION_ARGS)
|
|
+ {
|
|
+ HeapTupleHeader tuphdr = PG_GETARG_HEAPTUPLEHEADER(0);
|
|
+
|
|
+ PG_RETURN_OID(HeapTupleHeaderGetSecLabel(tuphdr));
|
|
+ }
|
|
diff -Nrpc base/src/backend/catalog/toasting.c sepgsql/src/backend/catalog/toasting.c
|
|
*** base/src/backend/catalog/toasting.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/catalog/toasting.c Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 28,33 ****
|
|
--- 28,34 ----
|
|
#include "catalog/toasting.h"
|
|
#include "miscadmin.h"
|
|
#include "nodes/makefuncs.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/syscache.h"
|
|
|
|
*************** create_toast_table(Relation rel, Oid toa
|
|
*** 125,130 ****
|
|
--- 126,132 ----
|
|
char toast_relname[NAMEDATALEN];
|
|
char toast_idxname[NAMEDATALEN];
|
|
IndexInfo *indexInfo;
|
|
+ Oid *secLabels;
|
|
Oid classObjectId[2];
|
|
int16 coloptions[2];
|
|
ObjectAddress baseobject,
|
|
*************** create_toast_table(Relation rel, Oid toa
|
|
*** 199,204 ****
|
|
--- 201,210 ----
|
|
else
|
|
namespaceid = PG_TOAST_NAMESPACE;
|
|
|
|
+ secLabels = sepgsqlCreateTableColumns(NULL,
|
|
+ toast_relname, namespaceid,
|
|
+ tupdesc, RELKIND_TOASTVALUE);
|
|
+
|
|
toast_relid = heap_create_with_catalog(toast_relname,
|
|
namespaceid,
|
|
rel->rd_rel->reltablespace,
|
|
*************** create_toast_table(Relation rel, Oid toa
|
|
*** 212,218 ****
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
reloptions,
|
|
! true);
|
|
|
|
/* make the toast relation visible, else index creation will fail */
|
|
CommandCounterIncrement();
|
|
--- 218,225 ----
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
reloptions,
|
|
! true,
|
|
! secLabels);
|
|
|
|
/* make the toast relation visible, else index creation will fail */
|
|
CommandCounterIncrement();
|
|
diff -Nrpc base/src/backend/commands/aggregatecmds.c sepgsql/src/backend/commands/aggregatecmds.c
|
|
*** base/src/backend/commands/aggregatecmds.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/aggregatecmds.c Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 32,37 ****
|
|
--- 32,38 ----
|
|
#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/lsyscache.h"
|
|
*************** RenameAggregate(List *name, List *args,
|
|
*** 311,316 ****
|
|
--- 312,320 ----
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
get_namespace_name(namespaceOid));
|
|
|
|
+ /* SELinux checks db_procedure:{setattr} */
|
|
+ sepgsqlCheckProcedureSetattr(procOid);
|
|
+
|
|
/* rename */
|
|
namestrcpy(&(((Form_pg_proc) GETSTRUCT(tup))->proname), newname);
|
|
simple_heap_update(rel, &tup->t_self, tup);
|
|
diff -Nrpc base/src/backend/commands/alter.c sepgsql/src/backend/commands/alter.c
|
|
*** base/src/backend/commands/alter.c Sat Jan 3 13:01:35 2009
|
|
--- sepgsql/src/backend/commands/alter.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 28,33 ****
|
|
--- 28,34 ----
|
|
#include "commands/user.h"
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_clause.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "tcop/utility.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/lsyscache.h"
|
|
*************** ExecRenameStmt(RenameStmt *stmt)
|
|
*** 117,122 ****
|
|
--- 118,126 ----
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
get_namespace_name(namespaceId));
|
|
|
|
+ /* SELinux checks db_table/db_sequence:{setattr} */
|
|
+ sepgsqlCheckTableSetattr(relid);
|
|
+
|
|
RenameRelation(relid, stmt->newname, stmt->renameType);
|
|
break;
|
|
}
|
|
*************** ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
|
|
*** 284,286 ****
|
|
--- 288,319 ----
|
|
(int) stmt->objectType);
|
|
}
|
|
}
|
|
+
|
|
+ void
|
|
+ ExecAlterSecLabelStmt(AlterSecLabelStmt *stmt)
|
|
+ {
|
|
+ DefElem *seclabel = (DefElem *)stmt->secLabel;
|
|
+
|
|
+ switch (stmt->objectType)
|
|
+ {
|
|
+ case OBJECT_DATABASE:
|
|
+ AlterDatabaseSecLabel(strVal(linitial(stmt->object)), seclabel);
|
|
+ break;
|
|
+ case OBJECT_SCHEMA:
|
|
+ AlterSchemaSecLabel(strVal(linitial(stmt->object)), seclabel);
|
|
+ break;
|
|
+ case OBJECT_TABLE:
|
|
+ case OBJECT_SEQUENCE:
|
|
+ case OBJECT_COLUMN:
|
|
+ CheckRelationOwnership(stmt->relation, true);
|
|
+ AlterRelationSecLabel(stmt->relation, stmt->subname,
|
|
+ stmt->objectType, seclabel);
|
|
+ break;
|
|
+ case OBJECT_FUNCTION:
|
|
+ AlterFunctionSecLabel(stmt->object, stmt->objarg, seclabel);
|
|
+ break;
|
|
+ default:
|
|
+ elog(ERROR, "unrecognized AlterSecLabelStmt type: %d",
|
|
+ (int) stmt->objectType);
|
|
+ }
|
|
+ }
|
|
diff -Nrpc base/src/backend/commands/cluster.c sepgsql/src/backend/commands/cluster.c
|
|
*** base/src/backend/commands/cluster.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/cluster.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 36,41 ****
|
|
--- 36,42 ----
|
|
#include "commands/trigger.h"
|
|
#include "commands/vacuum.h"
|
|
#include "miscadmin.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/procarray.h"
|
|
#include "utils/acl.h"
|
|
*************** rebuild_relation(Relation OldHeap, Oid i
|
|
*** 617,624 ****
|
|
/*
|
|
* The new relation is local to our transaction and we know nothing
|
|
* depends on it, so DROP_RESTRICT should be OK.
|
|
*/
|
|
! performDeletion(&object, DROP_RESTRICT);
|
|
|
|
/* performDeletion does CommandCounterIncrement at end */
|
|
|
|
--- 618,626 ----
|
|
/*
|
|
* The new relation is local to our transaction and we know nothing
|
|
* depends on it, so DROP_RESTRICT should be OK.
|
|
+ * SELinux does not check any permissions here.
|
|
*/
|
|
! performDeletionNoPerms(&object, DROP_RESTRICT);
|
|
|
|
/* performDeletion does CommandCounterIncrement at end */
|
|
|
|
*************** make_new_heap(Oid OIDOldHeap, const char
|
|
*** 712,718 ****
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
reloptions,
|
|
! allowSystemTableMods);
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
--- 714,721 ----
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
reloptions,
|
|
! allowSystemTableMods,
|
|
! sepgsqlCopyTableColumns(OldHeap));
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl
|
|
*** 924,929 ****
|
|
--- 927,936 ----
|
|
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 -Nrpc base/src/backend/commands/conversioncmds.c sepgsql/src/backend/commands/conversioncmds.c
|
|
*** base/src/backend/commands/conversioncmds.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/conversioncmds.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 24,29 ****
|
|
--- 24,30 ----
|
|
#include "mb/pg_wchar.h"
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_func.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
*************** CreateConversionCommand(CreateConversion
|
|
*** 96,101 ****
|
|
--- 97,105 ----
|
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
|
NameListToString(func_name));
|
|
|
|
+ /* SELinux checks db_procedure:{install} */
|
|
+ sepgsqlCheckProcedureInstall(funcoid);
|
|
+
|
|
/*
|
|
* Check that the conversion function is suitable for the requested source
|
|
* and target encodings. We do that by calling the function with an empty
|
|
diff -Nrpc base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c
|
|
*** base/src/backend/commands/copy.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/copy.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 21,28 ****
|
|
--- 21,31 ----
|
|
#include <arpa/inet.h>
|
|
|
|
#include "access/heapam.h"
|
|
+ #include "access/sysattr.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,39 ****
|
|
--- 37,44 ----
|
|
#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"
|
|
*************** typedef struct CopyStateData
|
|
*** 160,165 ****
|
|
--- 165,174 ----
|
|
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;
|
|
*************** static const char BinarySignature[11] =
|
|
*** 243,249 ****
|
|
/* non-export function prototypes */
|
|
static void DoCopyTo(CopyState cstate);
|
|
static void CopyTo(CopyState cstate);
|
|
! static void CopyOneRowTo(CopyState cstate, Oid tupleOid,
|
|
Datum *values, bool *nulls);
|
|
static void CopyFrom(CopyState cstate);
|
|
static bool CopyReadLine(CopyState cstate);
|
|
--- 252,258 ----
|
|
/* non-export function prototypes */
|
|
static void DoCopyTo(CopyState cstate);
|
|
static void CopyTo(CopyState cstate);
|
|
! static void CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid secLabelId,
|
|
Datum *values, bool *nulls);
|
|
static void CopyFrom(CopyState cstate);
|
|
static bool CopyReadLine(CopyState cstate);
|
|
*************** DoCopy(const CopyStmt *stmt, const char
|
|
*** 1090,1095 ****
|
|
--- 1099,1107 ----
|
|
|
|
num_phys_attrs = tupDesc->natts;
|
|
|
|
+ /* SELinux: check table/column level permission */
|
|
+ sepgsqlCheckCopyTable(cstate->rel, cstate->attnumlist, is_from);
|
|
+
|
|
/* Convert FORCE QUOTE name list to per-column flags, check validity */
|
|
cstate->force_quote_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
|
|
if (force_quote)
|
|
*************** DoCopy(const CopyStmt *stmt, const char
|
|
*** 1104,1114 ****
|
|
int attnum = lfirst_int(cur);
|
|
|
|
if (!list_member_int(cstate->attnumlist, attnum))
|
|
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;
|
|
}
|
|
}
|
|
|
|
--- 1116,1146 ----
|
|
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(attForm->attname))));
|
|
! }
|
|
!
|
|
! switch (attnum)
|
|
! {
|
|
! case SecurityLabelAttributeNumber:
|
|
! cstate->seclabel_force_quot = true;
|
|
! break;
|
|
! default:
|
|
! cstate->force_quote_flags[attnum - 1] = true;
|
|
! break;
|
|
! }
|
|
}
|
|
}
|
|
|
|
*************** DoCopy(const CopyStmt *stmt, const char
|
|
*** 1126,1135 ****
|
|
int attnum = lfirst_int(cur);
|
|
|
|
if (!list_member_int(cstate->attnumlist, attnum))
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY",
|
|
! NameStr(tupDesc->attrs[attnum - 1]->attname))));
|
|
cstate->force_notnull_flags[attnum - 1] = true;
|
|
}
|
|
}
|
|
--- 1158,1180 ----
|
|
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(attForm->attname))));
|
|
! }
|
|
! if (SystemAttributeIsWritable(attnum))
|
|
! continue; /* ignore, if specified */
|
|
cstate->force_notnull_flags[attnum - 1] = true;
|
|
}
|
|
}
|
|
*************** DoCopyTo(CopyState cstate)
|
|
*** 1258,1263 ****
|
|
--- 1303,1311 ----
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
errmsg("\"%s\" is a directory", cstate->filename)));
|
|
+
|
|
+ /* SELinux checks file:{write} permission */
|
|
+ sepgsqlCheckFileWrite(fileno(cstate->copy_file), cstate->filename);
|
|
}
|
|
|
|
PG_TRY();
|
|
*************** CopyTo(CopyState cstate)
|
|
*** 1321,1336 ****
|
|
int attnum = lfirst_int(cur);
|
|
Oid out_func_oid;
|
|
bool isvarlena;
|
|
|
|
if (cstate->binary)
|
|
! getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid,
|
|
&out_func_oid,
|
|
&isvarlena);
|
|
else
|
|
! getTypeOutputInfo(attr[attnum - 1]->atttypid,
|
|
&out_func_oid,
|
|
&isvarlena);
|
|
! fmgr_info(out_func_oid, &cstate->out_functions[attnum - 1]);
|
|
}
|
|
|
|
/*
|
|
--- 1369,1399 ----
|
|
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(attForm->atttypid,
|
|
&out_func_oid,
|
|
&isvarlena);
|
|
else
|
|
! getTypeOutputInfo(attForm->atttypid,
|
|
&out_func_oid,
|
|
&isvarlena);
|
|
! fmgr_info(out_func_oid, out_fmgr);
|
|
}
|
|
|
|
/*
|
|
*************** CopyTo(CopyState cstate)
|
|
*** 1385,1391 ****
|
|
CopySendChar(cstate, cstate->delim[0]);
|
|
hdr_delim = true;
|
|
|
|
! colname = NameStr(attr[attnum - 1]->attname);
|
|
|
|
CopyAttributeOutCSV(cstate, colname, false,
|
|
list_length(cstate->attnumlist) == 1);
|
|
--- 1448,1461 ----
|
|
CopySendChar(cstate, cstate->delim[0]);
|
|
hdr_delim = true;
|
|
|
|
! 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);
|
|
*************** CopyTo(CopyState cstate)
|
|
*** 1411,1421 ****
|
|
{
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
/* 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);
|
|
}
|
|
|
|
heap_endscan(scandesc);
|
|
--- 1481,1498 ----
|
|
{
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
+ /* check Row-level permission on the 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),
|
|
! HeapTupleGetSecLabel(tuple),
|
|
! values, nulls);
|
|
}
|
|
|
|
heap_endscan(scandesc);
|
|
*************** CopyTo(CopyState cstate)
|
|
*** 1441,1447 ****
|
|
* Emit one row during CopyTo().
|
|
*/
|
|
static void
|
|
! CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls)
|
|
{
|
|
bool need_delim = false;
|
|
FmgrInfo *out_functions = cstate->out_functions;
|
|
--- 1518,1525 ----
|
|
* Emit one row during CopyTo().
|
|
*/
|
|
static void
|
|
! CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid secLabelId,
|
|
! Datum *values, bool *nulls)
|
|
{
|
|
bool need_delim = false;
|
|
FmgrInfo *out_functions = cstate->out_functions;
|
|
*************** CopyOneRowTo(CopyState cstate, Oid tuple
|
|
*** 1480,1487 ****
|
|
foreach(cur, cstate->attnumlist)
|
|
{
|
|
int attnum = lfirst_int(cur);
|
|
! Datum value = values[attnum - 1];
|
|
! bool isnull = nulls[attnum - 1];
|
|
|
|
if (!cstate->binary)
|
|
{
|
|
--- 1558,1568 ----
|
|
foreach(cur, cstate->attnumlist)
|
|
{
|
|
int attnum = lfirst_int(cur);
|
|
! Oid relid;
|
|
! Datum value;
|
|
! bool isnull;
|
|
! bool force_quot;
|
|
! FmgrInfo *out_fmgr;
|
|
|
|
if (!cstate->binary)
|
|
{
|
|
*************** CopyOneRowTo(CopyState cstate, Oid tuple
|
|
*** 1490,1495 ****
|
|
--- 1571,1594 ----
|
|
need_delim = true;
|
|
}
|
|
|
|
+ switch (attnum)
|
|
+ {
|
|
+ case SecurityLabelAttributeNumber:
|
|
+ relid = RelationGetRelid(cstate->rel);
|
|
+ value = CStringGetTextDatum(securityTransSecLabelOut(relid, 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)
|
|
*************** CopyOneRowTo(CopyState cstate, Oid tuple
|
|
*** 1501,1511 ****
|
|
{
|
|
if (!cstate->binary)
|
|
{
|
|
! string = OutputFunctionCall(&out_functions[attnum - 1],
|
|
! value);
|
|
if (cstate->csv_mode)
|
|
! CopyAttributeOutCSV(cstate, string,
|
|
! cstate->force_quote_flags[attnum - 1],
|
|
list_length(cstate->attnumlist) == 1);
|
|
else
|
|
CopyAttributeOutText(cstate, string);
|
|
--- 1600,1608 ----
|
|
{
|
|
if (!cstate->binary)
|
|
{
|
|
! string = OutputFunctionCall(out_fmgr, value);
|
|
if (cstate->csv_mode)
|
|
! CopyAttributeOutCSV(cstate, string, force_quot,
|
|
list_length(cstate->attnumlist) == 1);
|
|
else
|
|
CopyAttributeOutText(cstate, string);
|
|
*************** CopyOneRowTo(CopyState cstate, Oid tuple
|
|
*** 1514,1521 ****
|
|
{
|
|
bytea *outputbytes;
|
|
|
|
! outputbytes = SendFunctionCall(&out_functions[attnum - 1],
|
|
! value);
|
|
CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);
|
|
CopySendData(cstate, VARDATA(outputbytes),
|
|
VARSIZE(outputbytes) - VARHDRSZ);
|
|
--- 1611,1617 ----
|
|
{
|
|
bytea *outputbytes;
|
|
|
|
! outputbytes = SendFunctionCall(out_fmgr, value);
|
|
CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);
|
|
CopySendData(cstate, VARDATA(outputbytes),
|
|
VARSIZE(outputbytes) - VARHDRSZ);
|
|
*************** CopyFrom(CopyState cstate)
|
|
*** 1649,1656 ****
|
|
--- 1745,1754 ----
|
|
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;
|
|
*************** CopyFrom(CopyState cstate)
|
|
*** 1753,1758 ****
|
|
--- 1851,1859 ----
|
|
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);
|
|
*************** CopyFrom(CopyState cstate)
|
|
*** 1888,1893 ****
|
|
--- 1989,2006 ----
|
|
fmgr_info(in_func_oid, &oid_in_function);
|
|
}
|
|
|
|
+ if (list_member_int(cstate->attnumlist,
|
|
+ SecurityLabelAttributeNumber))
|
|
+ {
|
|
+ if (!cstate->binary)
|
|
+ getTypeInputInfo(TEXTOID,
|
|
+ &in_func_oid, &seclabel_typioparam);
|
|
+ else
|
|
+ getTypeBinaryInputInfo(TEXTOID,
|
|
+ &in_func_oid, &seclabel_typioparam);
|
|
+ fmgr_info(in_func_oid, &seclabel_in_function);
|
|
+ }
|
|
+
|
|
values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
|
|
nulls = (bool *) palloc(num_phys_attrs * sizeof(bool));
|
|
|
|
*************** CopyFrom(CopyState cstate)
|
|
*** 1922,1927 ****
|
|
--- 2035,2041 ----
|
|
{
|
|
bool skip_tuple;
|
|
Oid loaded_oid = InvalidOid;
|
|
+ Oid loaded_seclabel = InvalidOid;
|
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
*************** CopyFrom(CopyState cstate)
|
|
*** 1993,2006 ****
|
|
/* Loop to read the user attributes on the line. */
|
|
foreach(cur, cstate->attnumlist)
|
|
{
|
|
int attnum = lfirst_int(cur);
|
|
int m = attnum - 1;
|
|
|
|
if (fieldno >= fldct)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
|
errmsg("missing data for column \"%s\"",
|
|
! NameStr(attr[m]->attname))));
|
|
string = field_strings[fieldno++];
|
|
|
|
if (cstate->csv_mode && string == NULL &&
|
|
--- 2107,2127 ----
|
|
/* 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(attForm->attname))));
|
|
string = field_strings[fieldno++];
|
|
|
|
if (cstate->csv_mode && string == NULL &&
|
|
*************** CopyFrom(CopyState cstate)
|
|
*** 2010,2023 ****
|
|
string = cstate->null_print;
|
|
}
|
|
|
|
! 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] = false;
|
|
cstate->cur_attname = NULL;
|
|
cstate->cur_attval = NULL;
|
|
}
|
|
--- 2131,2170 ----
|
|
string = cstate->null_print;
|
|
}
|
|
|
|
! cstate->cur_attname = NameStr(attForm->attname);
|
|
cstate->cur_attval = string;
|
|
!
|
|
! switch (attnum)
|
|
! {
|
|
! case SecurityLabelAttributeNumber:
|
|
! if (!string)
|
|
! break;
|
|
!
|
|
! dat = InputFunctionCall(&seclabel_in_function,
|
|
! string,
|
|
! seclabel_typioparam,
|
|
! attForm->atttypmod);
|
|
! loaded_seclabel
|
|
! = securityTransSecLabelIn(RelationGetRelid(cstate->rel),
|
|
! 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] = false;
|
|
! break;
|
|
! }
|
|
cstate->cur_attname = NULL;
|
|
cstate->cur_attval = NULL;
|
|
}
|
|
*************** CopyFrom(CopyState cstate)
|
|
*** 2063,2079 ****
|
|
i = 0;
|
|
foreach(cur, cstate->attnumlist)
|
|
{
|
|
int attnum = lfirst_int(cur);
|
|
int m = attnum - 1;
|
|
|
|
! cstate->cur_attname = NameStr(attr[m]->attname);
|
|
i++;
|
|
! values[m] = CopyReadBinaryAttribute(cstate,
|
|
! i,
|
|
! &in_functions[m],
|
|
! typioparams[m],
|
|
! attr[m]->atttypmod,
|
|
! &nulls[m]);
|
|
cstate->cur_attname = NULL;
|
|
}
|
|
}
|
|
--- 2210,2250 ----
|
|
i = 0;
|
|
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, false);
|
|
! else
|
|
! attForm = attr[m];
|
|
!
|
|
! cstate->cur_attname = NameStr(attForm->attname);
|
|
i++;
|
|
!
|
|
! switch (attnum)
|
|
! {
|
|
! case SecurityLabelAttributeNumber:
|
|
! dat = CopyReadBinaryAttribute(cstate, i,
|
|
! &seclabel_in_function,
|
|
! seclabel_typioparam,
|
|
! attForm->atttypmod,
|
|
! &isnull);
|
|
! if (!isnull)
|
|
! loaded_seclabel
|
|
! = securityTransSecLabelIn(RelationGetRelid(cstate->rel),
|
|
! TextDatumGetCString(dat));
|
|
! break;
|
|
!
|
|
! default:
|
|
! values[m] = CopyReadBinaryAttribute(cstate, i,
|
|
! &in_functions[m],
|
|
! typioparams[m],
|
|
! attr[m]->atttypmod,
|
|
! &nulls[m]);
|
|
! break;
|
|
! }
|
|
cstate->cur_attname = NULL;
|
|
}
|
|
}
|
|
*************** CopyFrom(CopyState cstate)
|
|
*** 2094,2099 ****
|
|
--- 2265,2272 ----
|
|
|
|
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);
|
|
*************** CopyFrom(CopyState cstate)
|
|
*** 2118,2123 ****
|
|
--- 2291,2299 ----
|
|
}
|
|
|
|
if (!skip_tuple)
|
|
+ sepgsqlHeapTupleInsert(cstate->rel, tuple, false);
|
|
+
|
|
+ if (!skip_tuple)
|
|
{
|
|
/* Place tuple in tuple slot */
|
|
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
|
|
*************** CopyGetAttnums(TupleDesc tupDesc, Relati
|
|
*** 3398,3403 ****
|
|
--- 3574,3586 ----
|
|
}
|
|
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),
|
|
*************** copy_dest_receive(TupleTableSlot *slot,
|
|
*** 3445,3451 ****
|
|
slot_getallattrs(slot);
|
|
|
|
/* And send the data */
|
|
! CopyOneRowTo(cstate, InvalidOid, slot->tts_values, slot->tts_isnull);
|
|
}
|
|
|
|
/*
|
|
--- 3628,3635 ----
|
|
slot_getallattrs(slot);
|
|
|
|
/* And send the data */
|
|
! CopyOneRowTo(cstate, InvalidOid, InvalidOid,
|
|
! slot->tts_values, slot->tts_isnull);
|
|
}
|
|
|
|
/*
|
|
diff -Nrpc base/src/backend/commands/dbcommands.c sepgsql/src/backend/commands/dbcommands.c
|
|
*** base/src/backend/commands/dbcommands.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/dbcommands.c Wed Jul 15 19:37:35 2009
|
|
***************
|
|
*** 33,38 ****
|
|
--- 33,39 ----
|
|
#include "catalog/indexing.h"
|
|
#include "catalog/pg_authid.h"
|
|
#include "catalog/pg_database.h"
|
|
+ #include "catalog/pg_security.h"
|
|
#include "catalog/pg_tablespace.h"
|
|
#include "commands/comment.h"
|
|
#include "commands/dbcommands.h"
|
|
***************
|
|
*** 41,46 ****
|
|
--- 42,48 ----
|
|
#include "miscadmin.h"
|
|
#include "pgstat.h"
|
|
#include "postmaster/bgwriter.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/lmgr.h"
|
|
*************** createdb(const CreatedbStmt *stmt)
|
|
*** 111,116 ****
|
|
--- 113,119 ----
|
|
bool new_record_nulls[Natts_pg_database];
|
|
Oid dboid;
|
|
Oid datdba;
|
|
+ Oid datsecid;
|
|
ListCell *option;
|
|
DefElem *dtablespacename = NULL;
|
|
DefElem *downer = NULL;
|
|
*************** createdb(const CreatedbStmt *stmt)
|
|
*** 119,124 ****
|
|
--- 122,128 ----
|
|
DefElem *dcollate = NULL;
|
|
DefElem *dctype = NULL;
|
|
DefElem *dconnlimit = NULL;
|
|
+ DefElem *dseclabel = NULL;
|
|
char *dbname = stmt->dbname;
|
|
char *dbowner = NULL;
|
|
const char *dbtemplate = NULL;
|
|
*************** createdb(const CreatedbStmt *stmt)
|
|
*** 200,205 ****
|
|
--- 204,217 ----
|
|
errmsg("LOCATION is not supported anymore"),
|
|
errhint("Consider using tablespaces instead.")));
|
|
}
|
|
+ else if (strcmp(defel->defname, "security_label") == 0)
|
|
+ {
|
|
+ if (dseclabel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ dseclabel = defel;
|
|
+ }
|
|
else
|
|
elog(ERROR, "option \"%s\" not recognized",
|
|
defel->defname);
|
|
*************** createdb(const CreatedbStmt *stmt)
|
|
*** 272,277 ****
|
|
--- 284,292 ----
|
|
|
|
check_is_member_of_role(GetUserId(), datdba);
|
|
|
|
+ /* SELinux checks db_database:{create} */
|
|
+ datsecid = sepgsqlCheckDatabaseCreate(dbname, dseclabel);
|
|
+
|
|
/*
|
|
* Lookup database (template) to be cloned, and obtain share lock on it.
|
|
* ShareLock allows two CREATE DATABASEs to work from the same template
|
|
*************** createdb(const CreatedbStmt *stmt)
|
|
*** 557,562 ****
|
|
--- 572,579 ----
|
|
new_record, new_record_nulls);
|
|
|
|
HeapTupleSetOid(tuple, dboid);
|
|
+ if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, datsecid);
|
|
|
|
simple_heap_insert(pg_database_rel, tuple);
|
|
|
|
*************** createdb(const CreatedbStmt *stmt)
|
|
*** 573,578 ****
|
|
--- 590,598 ----
|
|
/* Create pg_shdepend entries for objects within database */
|
|
copyTemplateDependencies(src_dboid, dboid);
|
|
|
|
+ /* Create pg_security entries for objects within database */
|
|
+ securityOnCreateDatabase(src_dboid, dboid);
|
|
+
|
|
/*
|
|
* Force a checkpoint before starting the copy. This will force dirty
|
|
* buffers out to disk, to ensure source database is up-to-date on disk
|
|
*************** dropdb(const char *dbname, bool missing_
|
|
*** 776,781 ****
|
|
--- 796,804 ----
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
|
|
dbname);
|
|
|
|
+ /* SELinux checks db_database:{drop} permission */
|
|
+ sepgsqlCheckDatabaseDrop(db_id);
|
|
+
|
|
/*
|
|
* Disallow dropping a DB that is marked istemplate. This is just to
|
|
* prevent people from accidentally dropping template0 or template1; they
|
|
*************** dropdb(const char *dbname, bool missing_
|
|
*** 829,834 ****
|
|
--- 852,862 ----
|
|
dropDatabaseDependencies(db_id);
|
|
|
|
/*
|
|
+ * Remove pg_security entries for the database.
|
|
+ */
|
|
+ securityOnDropDatabase(db_id);
|
|
+
|
|
+ /*
|
|
* Drop pages for this database that are in the shared buffer cache. This
|
|
* is important to ensure that no remaining backend tries to write out a
|
|
* dirty buffer to the dead database later...
|
|
*************** RenameDatabase(const char *oldname, cons
|
|
*** 913,918 ****
|
|
--- 941,949 ----
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
errmsg("permission denied to rename database")));
|
|
|
|
+ /* SELinux: check db_database:{setattr} */
|
|
+ sepgsqlCheckDatabaseSetattr(db_id);
|
|
+
|
|
/*
|
|
* Make sure the new name doesn't exist. See notes for same error in
|
|
* CREATE DATABASE.
|
|
*************** movedb(const char *dbname, const char *t
|
|
*** 1025,1030 ****
|
|
--- 1056,1064 ----
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
|
|
dbname);
|
|
|
|
+ /* SELinux checks db_database:{setattr} */
|
|
+ sepgsqlCheckDatabaseSetattr(db_id);
|
|
+
|
|
/*
|
|
* Obviously can't move the tables of my own database
|
|
*/
|
|
*************** AlterDatabase(AlterDatabaseStmt *stmt, b
|
|
*** 1377,1382 ****
|
|
--- 1411,1419 ----
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
|
|
stmt->dbname);
|
|
|
|
+ /* SELinux checks db_database:{setattr} */
|
|
+ sepgsqlCheckDatabaseSetattr(HeapTupleGetOid(tuple));
|
|
+
|
|
/*
|
|
* Build an updated tuple, perusing the information just obtained
|
|
*/
|
|
*************** AlterDatabaseSet(AlterDatabaseSetStmt *s
|
|
*** 1449,1454 ****
|
|
--- 1486,1494 ----
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
|
|
stmt->dbname);
|
|
|
|
+ /* SELinux checks db_database:{setattr} */
|
|
+ sepgsqlCheckDatabaseSetattr(HeapTupleGetOid(tuple));
|
|
+
|
|
memset(repl_repl, false, sizeof(repl_repl));
|
|
repl_repl[Anum_pg_database_datconfig - 1] = true;
|
|
|
|
*************** AlterDatabaseOwner(const char *dbname, O
|
|
*** 1571,1576 ****
|
|
--- 1611,1619 ----
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
errmsg("permission denied to change owner of database")));
|
|
|
|
+ /* SELinux checks db_database:{setattr} */
|
|
+ sepgsqlCheckDatabaseSetattr(HeapTupleGetOid(tuple));
|
|
+
|
|
memset(repl_null, false, sizeof(repl_null));
|
|
memset(repl_repl, false, sizeof(repl_repl));
|
|
|
|
*************** AlterDatabaseOwner(const char *dbname, O
|
|
*** 1615,1620 ****
|
|
--- 1658,1715 ----
|
|
*/
|
|
}
|
|
|
|
+ /*
|
|
+ * ALTER DATABASE name SECURITY_LABEL [=] newlabel
|
|
+ */
|
|
+ void
|
|
+ AlterDatabaseSecLabel(const char *dbname, DefElem *seclabel)
|
|
+ {
|
|
+ Relation rel;
|
|
+ HeapTuple oldtup;
|
|
+ HeapTuple newtup;
|
|
+ ScanKeyData scankey;
|
|
+ SysScanDesc scan;
|
|
+ Oid secid;
|
|
+ bool replaces[Natts_pg_database];
|
|
+
|
|
+ /* Fetch the old tuple */
|
|
+ rel = heap_open(DatabaseRelationId, RowExclusiveLock);
|
|
+ ScanKeyInit(&scankey,
|
|
+ Anum_pg_database_datname,
|
|
+ BTEqualStrategyNumber, F_NAMEEQ,
|
|
+ NameGetDatum(dbname));
|
|
+ scan = systable_beginscan(rel, DatabaseNameIndexId, true,
|
|
+ SnapshotNow, 1, &scankey);
|
|
+ oldtup = systable_getnext(scan);
|
|
+ if (!HeapTupleIsValid(oldtup))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_UNDEFINED_DATABASE),
|
|
+ errmsg("database \"%s\" does not exist", dbname)));
|
|
+
|
|
+ memset(replaces, false, sizeof(replaces));
|
|
+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
|
|
+ NULL, NULL, replaces);
|
|
+ systable_endscan(scan);
|
|
+
|
|
+ /* check DAC permission */
|
|
+ if (!pg_database_ownercheck(HeapTupleGetOid(newtup), GetUserId()))
|
|
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname);
|
|
+
|
|
+ /* SELinux checks db_database:{setattr relabelfrom relabelto} */
|
|
+ secid = sepgsqlCheckDatabaseRelabel(HeapTupleGetOid(newtup), seclabel);
|
|
+ if (!HeapTupleHasSecLabel(newtup))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to set security label on \"%s\"", dbname)));
|
|
+ HeapTupleSetSecLabel(newtup, secid);
|
|
+
|
|
+ simple_heap_update(rel, &newtup->t_self, newtup);
|
|
+ CatalogUpdateIndexes(rel, newtup);
|
|
+
|
|
+ heap_freetuple(newtup);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
|
|
/*
|
|
* Helper functions
|
|
diff -Nrpc base/src/backend/commands/foreigncmds.c sepgsql/src/backend/commands/foreigncmds.c
|
|
*** base/src/backend/commands/foreigncmds.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/foreigncmds.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 27,32 ****
|
|
--- 27,33 ----
|
|
#include "foreign/foreign.h"
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_func.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
*************** CreateForeignDataWrapper(CreateFdwStmt *
|
|
*** 380,385 ****
|
|
--- 381,389 ----
|
|
else
|
|
fdwvalidator = InvalidOid;
|
|
|
|
+ /* SELinux checks db_procedure:{install} */
|
|
+ sepgsqlCheckProcedureInstall(fdwvalidator);
|
|
+
|
|
values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = fdwvalidator;
|
|
|
|
nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
|
|
*************** AlterForeignDataWrapper(AlterFdwStmt *st
|
|
*** 473,478 ****
|
|
--- 477,485 ----
|
|
ereport(WARNING,
|
|
(errmsg("changing the foreign-data wrapper validator can cause "
|
|
"the options for dependent objects to become invalid")));
|
|
+
|
|
+ /* SELinux checks db_procedure:{install} */
|
|
+ sepgsqlCheckProcedureInstall(fdwvalidator);
|
|
}
|
|
else
|
|
{
|
|
diff -Nrpc base/src/backend/commands/functioncmds.c sepgsql/src/backend/commands/functioncmds.c
|
|
*** base/src/backend/commands/functioncmds.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/functioncmds.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 53,58 ****
|
|
--- 53,59 ----
|
|
#include "parser/parse_expr.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"
|
|
*************** compute_attributes_sql_style(List *optio
|
|
*** 517,523 ****
|
|
bool *security_definer,
|
|
ArrayType **proconfig,
|
|
float4 *procost,
|
|
! float4 *prorows)
|
|
{
|
|
ListCell *option;
|
|
DefElem *as_item = NULL;
|
|
--- 518,525 ----
|
|
bool *security_definer,
|
|
ArrayType **proconfig,
|
|
float4 *procost,
|
|
! float4 *prorows,
|
|
! Node **proseclabel)
|
|
{
|
|
ListCell *option;
|
|
DefElem *as_item = NULL;
|
|
*************** compute_attributes_sql_style(List *optio
|
|
*** 529,534 ****
|
|
--- 531,537 ----
|
|
List *set_items = NIL;
|
|
DefElem *cost_item = NULL;
|
|
DefElem *rows_item = NULL;
|
|
+ DefElem *seclabel_item = NULL;
|
|
|
|
foreach(option, options)
|
|
{
|
|
*************** compute_attributes_sql_style(List *optio
|
|
*** 558,563 ****
|
|
--- 561,574 ----
|
|
errmsg("conflicting or redundant options")));
|
|
windowfunc_item = defel;
|
|
}
|
|
+ else if (strcmp(defel->defname, "security_label") == 0)
|
|
+ {
|
|
+ if (seclabel_item)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ seclabel_item = defel;
|
|
+ }
|
|
else if (compute_common_attribute(defel,
|
|
&volatility_item,
|
|
&strict_item,
|
|
*************** compute_attributes_sql_style(List *optio
|
|
*** 622,627 ****
|
|
--- 633,640 ----
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
errmsg("ROWS must be positive")));
|
|
}
|
|
+ if (seclabel_item)
|
|
+ *proseclabel = (Node *)seclabel_item;
|
|
}
|
|
|
|
|
|
*************** CreateFunction(CreateFunctionStmt *stmt,
|
|
*** 762,767 ****
|
|
--- 775,781 ----
|
|
ArrayType *proconfig;
|
|
float4 procost;
|
|
float4 prorows;
|
|
+ Node *proseclabel;
|
|
HeapTuple languageTuple;
|
|
Form_pg_language languageStruct;
|
|
List *as_clause;
|
|
*************** CreateFunction(CreateFunctionStmt *stmt,
|
|
*** 784,796 ****
|
|
proconfig = NULL;
|
|
procost = -1; /* indicates not set */
|
|
prorows = -1; /* indicates not set */
|
|
|
|
/* override attributes from explicit list */
|
|
compute_attributes_sql_style(stmt->options,
|
|
&as_clause, &language,
|
|
&isWindowFunc, &volatility,
|
|
&isStrict, &security,
|
|
! &proconfig, &procost, &prorows);
|
|
|
|
/* Convert language name to canonical case */
|
|
languageName = case_translate_language_name(language);
|
|
--- 798,811 ----
|
|
proconfig = NULL;
|
|
procost = -1; /* indicates not set */
|
|
prorows = -1; /* indicates not set */
|
|
+ proseclabel = NULL;
|
|
|
|
/* override attributes from explicit list */
|
|
compute_attributes_sql_style(stmt->options,
|
|
&as_clause, &language,
|
|
&isWindowFunc, &volatility,
|
|
&isStrict, &security,
|
|
! &proconfig, &procost, &prorows, &proseclabel);
|
|
|
|
/* Convert language name to canonical case */
|
|
languageName = case_translate_language_name(language);
|
|
*************** CreateFunction(CreateFunctionStmt *stmt,
|
|
*** 926,932 ****
|
|
parameterDefaults,
|
|
PointerGetDatum(proconfig),
|
|
procost,
|
|
! prorows);
|
|
}
|
|
|
|
|
|
--- 941,948 ----
|
|
parameterDefaults,
|
|
PointerGetDatum(proconfig),
|
|
procost,
|
|
! prorows,
|
|
! proseclabel);
|
|
}
|
|
|
|
|
|
*************** RenameFunction(List *name, List *argtype
|
|
*** 1112,1117 ****
|
|
--- 1128,1136 ----
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
get_namespace_name(namespaceOid));
|
|
|
|
+ /* SELinux checks db_procedure:{setattr} */
|
|
+ sepgsqlCheckProcedureSetattr(procOid);
|
|
+
|
|
/* rename */
|
|
namestrcpy(&(procForm->proname), newname);
|
|
simple_heap_update(rel, &tup->t_self, tup);
|
|
*************** AlterFunctionOwner_internal(Relation rel
|
|
*** 1220,1225 ****
|
|
--- 1239,1246 ----
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
get_namespace_name(procForm->pronamespace));
|
|
}
|
|
+ /* SELinux checks db_procedure:{setattr} */
|
|
+ sepgsqlCheckProcedureSetattr(procOid);
|
|
|
|
memset(repl_null, false, sizeof(repl_null));
|
|
memset(repl_repl, false, sizeof(repl_repl));
|
|
*************** AlterFunctionOwner_internal(Relation rel
|
|
*** 1258,1263 ****
|
|
--- 1279,1336 ----
|
|
}
|
|
|
|
/*
|
|
+ * ALTER FUNCTION name(args,...) SECURITY_LABEL [=] newlabel
|
|
+ */
|
|
+ void
|
|
+ AlterFunctionSecLabel(List *name, List *argtypes, DefElem *seclabel)
|
|
+ {
|
|
+ Relation rel;
|
|
+ HeapTuple oldtup;
|
|
+ HeapTuple newtup;
|
|
+ Oid proc_oid;
|
|
+ Oid secid;
|
|
+ bool replaces[Natts_pg_proc];
|
|
+
|
|
+ /* open pg_proc system catalog */
|
|
+ rel = heap_open(ProcedureRelationId, RowExclusiveLock);
|
|
+
|
|
+ proc_oid = LookupFuncNameTypeNames(name, argtypes, false);
|
|
+
|
|
+ oldtup = SearchSysCache(PROCOID,
|
|
+ ObjectIdGetDatum(proc_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(oldtup))
|
|
+ elog(ERROR, "cache lookup failed for function %u", proc_oid);
|
|
+
|
|
+ memset(replaces, false, sizeof(replaces));
|
|
+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
|
|
+ NULL, NULL, replaces);
|
|
+ ReleaseSysCache(oldtup);
|
|
+
|
|
+ /* DAC permission checks */
|
|
+ if (!pg_proc_ownercheck(HeapTupleGetOid(newtup), GetUserId()))
|
|
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
+ get_func_name(HeapTupleGetOid(newtup)));
|
|
+
|
|
+ /* SELinux checks db_procedure:{setattr relabelfrom relabelto} */
|
|
+ secid = sepgsqlCheckProcedureRelabel(HeapTupleGetOid(newtup), seclabel);
|
|
+
|
|
+ if (!HeapTupleHasSecLabel(newtup))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to set security label on \"%s\"",
|
|
+ get_func_name(HeapTupleGetOid(newtup)))));
|
|
+ HeapTupleSetSecLabel(newtup, secid);
|
|
+
|
|
+ simple_heap_update(rel, &newtup->t_self, newtup);
|
|
+ CatalogUpdateIndexes(rel, newtup);
|
|
+
|
|
+ heap_freetuple(newtup);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
+
|
|
+ /*
|
|
* Implements the ALTER FUNCTION utility command (except for the
|
|
* RENAME and OWNER clauses, which are handled as part of the generic
|
|
* ALTER framework).
|
|
*************** AlterFunction(AlterFunctionStmt *stmt)
|
|
*** 1296,1301 ****
|
|
--- 1369,1377 ----
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
NameListToString(stmt->func->funcname));
|
|
|
|
+ /* SELinux checks db_procedure:{setattr} */
|
|
+ sepgsqlCheckProcedureSetattr(funcOid);
|
|
+
|
|
if (procForm->proisagg)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
*************** CreateCast(CreateCastStmt *stmt)
|
|
*** 1580,1585 ****
|
|
--- 1656,1664 ----
|
|
errmsg("cast function must not return a set")));
|
|
|
|
ReleaseSysCache(tuple);
|
|
+
|
|
+ /* SELinux checks db_procedure:{install} */
|
|
+ sepgsqlCheckProcedureInstall(funcid);
|
|
}
|
|
else
|
|
{
|
|
*************** AlterFunctionNamespace(List *name, List
|
|
*** 1854,1859 ****
|
|
--- 1933,1941 ----
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
NameListToString(name));
|
|
|
|
+ /* SELinux checks db_procedure:{setattr} */
|
|
+ sepgsqlCheckProcedureSetattr(procOid);
|
|
+
|
|
tup = SearchSysCacheCopy(PROCOID,
|
|
ObjectIdGetDatum(procOid),
|
|
0, 0, 0);
|
|
diff -Nrpc base/src/backend/commands/lockcmds.c sepgsql/src/backend/commands/lockcmds.c
|
|
*** base/src/backend/commands/lockcmds.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/lockcmds.c Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 20,25 ****
|
|
--- 20,26 ----
|
|
#include "commands/lockcmds.h"
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_clause.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/lmgr.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/lsyscache.h"
|
|
*************** LockTableRecurse(Oid reloid, RangeVar *r
|
|
*** 140,145 ****
|
|
--- 141,149 ----
|
|
errmsg("\"%s\" is not a table",
|
|
RelationGetRelationName(rel))));
|
|
|
|
+ /* SELinux: check db_table:{lock} permission */
|
|
+ sepgsqlCheckTableLock(reloid);
|
|
+
|
|
/*
|
|
* If requested, recurse to children. We use find_inheritance_children
|
|
* not find_all_inheritors to avoid taking locks far in advance of
|
|
diff -Nrpc base/src/backend/commands/proclang.c sepgsql/src/backend/commands/proclang.c
|
|
*** base/src/backend/commands/proclang.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/proclang.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 30,35 ****
|
|
--- 30,36 ----
|
|
#include "miscadmin.h"
|
|
#include "parser/gramparse.h"
|
|
#include "parser/parse_func.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
*************** CreateProceduralLanguage(CreatePLangStmt
|
|
*** 151,157 ****
|
|
NIL,
|
|
PointerGetDatum(NULL),
|
|
1,
|
|
! 0);
|
|
}
|
|
|
|
/*
|
|
--- 152,159 ----
|
|
NIL,
|
|
PointerGetDatum(NULL),
|
|
1,
|
|
! 0,
|
|
! NULL);
|
|
}
|
|
|
|
/*
|
|
*************** CreateProceduralLanguage(CreatePLangStmt
|
|
*** 186,197 ****
|
|
NIL,
|
|
PointerGetDatum(NULL),
|
|
1,
|
|
! 0);
|
|
}
|
|
}
|
|
else
|
|
valOid = InvalidOid;
|
|
|
|
/* ok, create it */
|
|
create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
|
|
pltemplate->tmpltrusted);
|
|
--- 188,204 ----
|
|
NIL,
|
|
PointerGetDatum(NULL),
|
|
1,
|
|
! 0,
|
|
! NULL);
|
|
}
|
|
}
|
|
else
|
|
valOid = InvalidOid;
|
|
|
|
+ /* SELinux checks db_procedure:{install} */
|
|
+ sepgsqlCheckProcedureInstall(handlerOid);
|
|
+ sepgsqlCheckProcedureInstall(valOid);
|
|
+
|
|
/* ok, create it */
|
|
create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
|
|
pltemplate->tmpltrusted);
|
|
*************** CreateProceduralLanguage(CreatePLangStmt
|
|
*** 256,261 ****
|
|
--- 263,272 ----
|
|
else
|
|
valOid = InvalidOid;
|
|
|
|
+ /* SELinux checks db_procedure:{install} */
|
|
+ sepgsqlCheckProcedureInstall(handlerOid);
|
|
+ sepgsqlCheckProcedureInstall(valOid);
|
|
+
|
|
/* ok, create it */
|
|
create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
|
|
stmt->pltrusted);
|
|
diff -Nrpc base/src/backend/commands/schemacmds.c sepgsql/src/backend/commands/schemacmds.c
|
|
*** base/src/backend/commands/schemacmds.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/schemacmds.c Wed Jul 15 19:37:35 2009
|
|
***************
|
|
*** 25,30 ****
|
|
--- 25,31 ----
|
|
#include "commands/schemacmds.h"
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_utilcmd.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "tcop/utility.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
*************** CreateSchemaCommand(CreateSchemaStmt *st
|
|
*** 48,53 ****
|
|
--- 49,55 ----
|
|
ListCell *parsetree_item;
|
|
Oid owner_uid;
|
|
Oid saved_uid;
|
|
+ Oid nspsecid;
|
|
bool saved_secdefcxt;
|
|
AclResult aclresult;
|
|
|
|
*************** CreateSchemaCommand(CreateSchemaStmt *st
|
|
*** 75,80 ****
|
|
--- 77,86 ----
|
|
|
|
check_is_member_of_role(saved_uid, owner_uid);
|
|
|
|
+ /* SELinux checks db_schema:{create} */
|
|
+ nspsecid = sepgsqlCheckSchemaCreate(schemaName,
|
|
+ (DefElem *)stmt->secLabel, false);
|
|
+
|
|
/* Additional check to protect reserved schema names */
|
|
if (!allowSystemTableMods && IsReservedName(schemaName))
|
|
ereport(ERROR,
|
|
*************** CreateSchemaCommand(CreateSchemaStmt *st
|
|
*** 94,100 ****
|
|
SetUserIdAndContext(owner_uid, true);
|
|
|
|
/* Create the schema's namespace */
|
|
! namespaceId = NamespaceCreate(schemaName, owner_uid);
|
|
|
|
/* Advance cmd counter to make the namespace visible */
|
|
CommandCounterIncrement();
|
|
--- 100,106 ----
|
|
SetUserIdAndContext(owner_uid, true);
|
|
|
|
/* Create the schema's namespace */
|
|
! namespaceId = NamespaceCreate(schemaName, owner_uid, nspsecid);
|
|
|
|
/* Advance cmd counter to make the namespace visible */
|
|
CommandCounterIncrement();
|
|
*************** RenameSchema(const char *oldname, const
|
|
*** 286,291 ****
|
|
--- 292,300 ----
|
|
aclcheck_error(aclresult, ACL_KIND_DATABASE,
|
|
get_database_name(MyDatabaseId));
|
|
|
|
+ /* SELinux checks db_schema:{setattr} */
|
|
+ sepgsqlCheckSchemaSetattr(HeapTupleGetOid(tup));
|
|
+
|
|
if (!allowSystemTableMods && IsReservedName(newname))
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_RESERVED_NAME),
|
|
*************** AlterSchemaOwner_internal(HeapTuple tup,
|
|
*** 397,402 ****
|
|
--- 406,414 ----
|
|
aclcheck_error(aclresult, ACL_KIND_DATABASE,
|
|
get_database_name(MyDatabaseId));
|
|
|
|
+ /* SELinux checks db_schema:{setattr} */
|
|
+ sepgsqlCheckSchemaSetattr(HeapTupleGetOid(tup));
|
|
+
|
|
memset(repl_null, false, sizeof(repl_null));
|
|
memset(repl_repl, false, sizeof(repl_repl));
|
|
|
|
*************** AlterSchemaOwner_internal(HeapTuple tup,
|
|
*** 431,433 ****
|
|
--- 443,491 ----
|
|
}
|
|
|
|
}
|
|
+
|
|
+ /*
|
|
+ * ALTER SCHEMA name SECURITY_LABEL [=] newlabel
|
|
+ */
|
|
+ void
|
|
+ AlterSchemaSecLabel(const char *name, DefElem *seclabel)
|
|
+ {
|
|
+ Relation rel;
|
|
+ HeapTuple oldtup;
|
|
+ HeapTuple newtup;
|
|
+ Oid secid;
|
|
+ bool replaces[Natts_pg_namespace];
|
|
+
|
|
+ /* open pg_namespace relation */
|
|
+ rel = heap_open(NamespaceRelationId, RowExclusiveLock);
|
|
+ oldtup = SearchSysCache(NAMESPACENAME,
|
|
+ CStringGetDatum(name),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(oldtup))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_UNDEFINED_SCHEMA),
|
|
+ errmsg("schema \"%s\" does not exist", name)));
|
|
+
|
|
+ memset(replaces, false, sizeof(replaces));
|
|
+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
|
|
+ NULL, NULL, replaces);
|
|
+ ReleaseSysCache(oldtup);
|
|
+
|
|
+ /* DAC permission check */
|
|
+ if (!pg_namespace_ownercheck(HeapTupleGetOid(newtup), GetUserId()))
|
|
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, name);
|
|
+ /* SELinux checks db_schema:{setattr relabelfrom relabelto} */
|
|
+ secid = sepgsqlCheckSchemaRelabel(HeapTupleGetOid(newtup), seclabel);
|
|
+ if (!HeapTupleHasSecLabel(newtup))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to set security label on \"%s\"", name)));
|
|
+ HeapTupleSetSecLabel(newtup, secid);
|
|
+
|
|
+ simple_heap_update(rel, &newtup->t_self, newtup);
|
|
+ CatalogUpdateIndexes(rel, newtup);
|
|
+
|
|
+ heap_freetuple(newtup);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
diff -Nrpc base/src/backend/commands/sequence.c sepgsql/src/backend/commands/sequence.c
|
|
*** base/src/backend/commands/sequence.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/sequence.c Wed Jul 15 19:37:35 2009
|
|
***************
|
|
*** 26,31 ****
|
|
--- 26,32 ----
|
|
#include "commands/tablecmds.h"
|
|
#include "miscadmin.h"
|
|
#include "nodes/makefuncs.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/lmgr.h"
|
|
#include "storage/proc.h"
|
|
*************** DefineSequence(CreateSeqStmt *seq)
|
|
*** 201,206 ****
|
|
--- 202,208 ----
|
|
stmt->options = list_make1(defWithOids(false));
|
|
stmt->oncommit = ONCOMMIT_NOOP;
|
|
stmt->tablespacename = NULL;
|
|
+ stmt->secLabel = seq->secLabel;
|
|
|
|
seqoid = DefineRelation(stmt, RELKIND_SEQUENCE);
|
|
|
|
*************** AlterSequence(AlterSeqStmt *stmt)
|
|
*** 328,333 ****
|
|
--- 330,337 ----
|
|
if (!pg_class_ownercheck(relid, GetUserId()))
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
|
|
stmt->sequence->relname);
|
|
+ /* SELinux checks db_sequence:{setattr} */
|
|
+ sepgsqlCheckTableSetattr(relid);
|
|
|
|
/* do the work */
|
|
AlterSequenceInternal(relid, stmt->options);
|
|
*************** nextval_internal(Oid relid)
|
|
*** 467,472 ****
|
|
--- 471,479 ----
|
|
errmsg("permission denied for sequence %s",
|
|
RelationGetRelationName(seqrel))));
|
|
|
|
+ /* SELinux check db_sequence:{next_value} */
|
|
+ sepgsqlCheckSequenceNextValue(elm->relid);
|
|
+
|
|
if (elm->last != elm->cached) /* some numbers were cached */
|
|
{
|
|
Assert(elm->last_valid);
|
|
*************** currval_oid(PG_FUNCTION_ARGS)
|
|
*** 662,667 ****
|
|
--- 669,677 ----
|
|
errmsg("permission denied for sequence %s",
|
|
RelationGetRelationName(seqrel))));
|
|
|
|
+ /* SELinux check db_sequence:{get_value} */
|
|
+ sepgsqlCheckSequenceGetValue(elm->relid);
|
|
+
|
|
if (!elm->last_valid)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
*************** lastval(PG_FUNCTION_ARGS)
|
|
*** 706,711 ****
|
|
--- 716,724 ----
|
|
errmsg("permission denied for sequence %s",
|
|
RelationGetRelationName(seqrel))));
|
|
|
|
+ /* SELinux check db_sequence:{get_value} */
|
|
+ sepgsqlCheckSequenceGetValue(last_used_seq->relid);
|
|
+
|
|
result = last_used_seq->last;
|
|
relation_close(seqrel, NoLock);
|
|
|
|
*************** do_setval(Oid relid, int64 next, bool is
|
|
*** 742,747 ****
|
|
--- 755,763 ----
|
|
errmsg("permission denied for sequence %s",
|
|
RelationGetRelationName(seqrel))));
|
|
|
|
+ /* SELinux check db_sequence:{set_value} */
|
|
+ sepgsqlCheckSequenceSetValue(elm->relid);
|
|
+
|
|
/* lock page' buffer and read tuple */
|
|
seq = read_info(elm, seqrel, &buf);
|
|
|
|
diff -Nrpc base/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/tablecmds.c
|
|
*** base/src/backend/commands/tablecmds.c Fri Jun 19 13:40:37 2009
|
|
--- sepgsql/src/backend/commands/tablecmds.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 62,67 ****
|
|
--- 62,68 ----
|
|
#include "parser/parser.h"
|
|
#include "rewrite/rewriteDefine.h"
|
|
#include "rewrite/rewriteHandler.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/lmgr.h"
|
|
#include "storage/smgr.h"
|
|
*************** DefineRelation(CreateStmt *stmt, char re
|
|
*** 351,356 ****
|
|
--- 352,358 ----
|
|
List *rawDefaults;
|
|
List *cookedDefaults;
|
|
Datum reloptions;
|
|
+ Oid *secLabels;
|
|
ListCell *listptr;
|
|
AttrNumber attnum;
|
|
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
|
*************** DefineRelation(CreateStmt *stmt, char re
|
|
*** 494,499 ****
|
|
--- 496,505 ----
|
|
}
|
|
}
|
|
|
|
+ /* SELinux checks db_table:{create} and db_column:{create} */
|
|
+ secLabels = sepgsqlCreateTableColumns(stmt, relname, namespaceId,
|
|
+ descriptor, relkind);
|
|
+
|
|
/*
|
|
* Create the relation. Inherited defaults and constraints are passed in
|
|
* for immediate handling --- since they don't need parsing, they can be
|
|
*************** DefineRelation(CreateStmt *stmt, char re
|
|
*** 513,519 ****
|
|
parentOidCount,
|
|
stmt->oncommit,
|
|
reloptions,
|
|
! allowSystemTableMods);
|
|
|
|
StoreCatalogInheritance(relationId, inheritOids);
|
|
|
|
--- 519,526 ----
|
|
parentOidCount,
|
|
stmt->oncommit,
|
|
reloptions,
|
|
! allowSystemTableMods,
|
|
! secLabels);
|
|
|
|
StoreCatalogInheritance(relationId, inheritOids);
|
|
|
|
*************** truncate_check_rel(Relation rel)
|
|
*** 1042,1047 ****
|
|
--- 1049,1057 ----
|
|
errmsg("permission denied: \"%s\" is a system catalog",
|
|
RelationGetRelationName(rel))));
|
|
|
|
+ /* SELinux: check db_table:{delete} permission */
|
|
+ sepgsqlCheckTableTruncate(rel);
|
|
+
|
|
/*
|
|
* We can never allow truncation of shared or nailed-in-cache relations,
|
|
* because we can't support changing their relfilenode values.
|
|
*************** renameatt(Oid myrelid,
|
|
*** 1921,1926 ****
|
|
--- 1931,1939 ----
|
|
errmsg("cannot rename system column \"%s\"",
|
|
oldattname)));
|
|
|
|
+ /* SELinux checks db_column:{setattr} */
|
|
+ sepgsqlCheckColumnSetattr(myrelid, attnum);
|
|
+
|
|
/*
|
|
* if the attribute is inherited, forbid the renaming, unless we are
|
|
* already inside a recursive rename.
|
|
*************** ATRewriteTables(List **wqueue)
|
|
*** 2850,2857 ****
|
|
/*
|
|
* The new relation is local to our transaction and we know
|
|
* nothing depends on it, so DROP_RESTRICT should be OK.
|
|
*/
|
|
! performDeletion(&object, DROP_RESTRICT);
|
|
/* performDeletion does CommandCounterIncrement at end */
|
|
|
|
/*
|
|
--- 2863,2871 ----
|
|
/*
|
|
* The new relation is local to our transaction and we know
|
|
* nothing depends on it, so DROP_RESTRICT should be OK.
|
|
+ * SELinux does not apply any permission checks here.
|
|
*/
|
|
! performDeletionNoPerms(&object, DROP_RESTRICT);
|
|
/* performDeletion does CommandCounterIncrement at end */
|
|
|
|
/*
|
|
*************** ATRewriteTable(AlteredTableInfo *tab, Oi
|
|
*** 3076,3086 ****
|
|
--- 3090,3103 ----
|
|
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)
|
|
*************** ATRewriteTable(AlteredTableInfo *tab, Oi
|
|
*** 3112,3117 ****
|
|
--- 3129,3137 ----
|
|
/* 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 */
|
|
*************** ATSimplePermissions(Relation rel, bool a
|
|
*** 3242,3247 ****
|
|
--- 3262,3270 ----
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
errmsg("permission denied: \"%s\" is a system catalog",
|
|
RelationGetRelationName(rel))));
|
|
+
|
|
+ /* SELinux checks db_table:{setattr} */
|
|
+ sepgsqlCheckTableSetattr(RelationGetRelid(rel));
|
|
}
|
|
|
|
/*
|
|
*************** ATSimplePermissionsRelationOrIndex(Relat
|
|
*** 3271,3276 ****
|
|
--- 3294,3302 ----
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
errmsg("permission denied: \"%s\" is a system catalog",
|
|
RelationGetRelationName(rel))));
|
|
+
|
|
+ /* SELinux checks db_table:{setattr} */
|
|
+ sepgsqlCheckTableSetattr(RelationGetRelid(rel));
|
|
}
|
|
|
|
/*
|
|
*************** ATExecAddColumn(AlteredTableInfo *tab, R
|
|
*** 3509,3514 ****
|
|
--- 3535,3541 ----
|
|
HeapTuple typeTuple;
|
|
Oid typeOid;
|
|
int32 typmod;
|
|
+ Oid attsecid;
|
|
Form_pg_type tform;
|
|
Expr *defval;
|
|
|
|
*************** ATExecAddColumn(AlteredTableInfo *tab, R
|
|
*** 3546,3551 ****
|
|
--- 3573,3581 ----
|
|
errmsg("child table \"%s\" has a conflicting \"%s\" column",
|
|
RelationGetRelationName(rel), colDef->colname)));
|
|
|
|
+ /* SELinux checks db_column:{setattr} */
|
|
+ sepgsqlCheckColumnSetattr(myrelid, childatt->attnum);
|
|
+
|
|
/* Bump the existing child att's inhcount */
|
|
childatt->attinhcount++;
|
|
simple_heap_update(attrdesc, &tuple->t_self, tuple);
|
|
*************** ATExecAddColumn(AlteredTableInfo *tab, R
|
|
*** 3585,3590 ****
|
|
--- 3615,3624 ----
|
|
errmsg("column \"%s\" of relation \"%s\" already exists",
|
|
colDef->colname, RelationGetRelationName(rel))));
|
|
|
|
+ /* SELinux checks db_column:{create} */
|
|
+ attsecid = sepgsqlCheckColumnCreate(myrelid, colDef->colname,
|
|
+ (DefElem *)colDef->secLabel);
|
|
+
|
|
/* Determine the new attribute's number */
|
|
if (isOid)
|
|
newattnum = ObjectIdAttributeNumber;
|
|
*************** ATExecAddColumn(AlteredTableInfo *tab, R
|
|
*** 3627,3633 ****
|
|
|
|
ReleaseSysCache(typeTuple);
|
|
|
|
! InsertPgAttributeTuple(attrdesc, &attribute, NULL);
|
|
|
|
heap_close(attrdesc, RowExclusiveLock);
|
|
|
|
--- 3661,3667 ----
|
|
|
|
ReleaseSysCache(typeTuple);
|
|
|
|
! InsertPgAttributeTuple(attrdesc, &attribute, NULL, attsecid);
|
|
|
|
heap_close(attrdesc, RowExclusiveLock);
|
|
|
|
*************** ATExecDropNotNull(Relation rel, const ch
|
|
*** 3832,3837 ****
|
|
--- 3866,3874 ----
|
|
errmsg("cannot alter system column \"%s\"",
|
|
colName)));
|
|
|
|
+ /* SELinux checks db_column:{setattr} */
|
|
+ sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attnum);
|
|
+
|
|
/*
|
|
* Check that the attribute is not in a primary key
|
|
*/
|
|
*************** ATExecSetNotNull(AlteredTableInfo *tab,
|
|
*** 3924,3929 ****
|
|
--- 3961,3969 ----
|
|
errmsg("cannot alter system column \"%s\"",
|
|
colName)));
|
|
|
|
+ /* SELinux checks db_column:{setattr} */
|
|
+ sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attnum);
|
|
+
|
|
/*
|
|
* Okay, actually perform the catalog change ... if needed
|
|
*/
|
|
*************** ATExecColumnDefault(Relation rel, const
|
|
*** 3969,3974 ****
|
|
--- 4009,4017 ----
|
|
errmsg("cannot alter system column \"%s\"",
|
|
colName)));
|
|
|
|
+ /* SELinux checks db_column:{setattr} */
|
|
+ sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attnum);
|
|
+
|
|
/*
|
|
* Remove any old default for the column. We use RESTRICT here for
|
|
* safety, but at present we do not expect anything to depend on the
|
|
*************** ATPrepSetStatistics(Relation rel, const
|
|
*** 4016,4021 ****
|
|
--- 4059,4066 ----
|
|
if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
|
|
RelationGetRelationName(rel));
|
|
+ /* SELinux checks db_table:{setatr} */
|
|
+ sepgsqlCheckTableSetattr(RelationGetRelid(rel));
|
|
}
|
|
|
|
static void
|
|
*************** ATExecSetStatistics(Relation rel, const
|
|
*** 4065,4070 ****
|
|
--- 4110,4118 ----
|
|
errmsg("cannot alter system column \"%s\"",
|
|
colName)));
|
|
|
|
+ /* SELinux checks db_column:{setattr} */
|
|
+ sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attrtuple->attnum);
|
|
+
|
|
attrtuple->attstattarget = newtarget;
|
|
|
|
simple_heap_update(attrelation, &tuple->t_self, tuple);
|
|
*************** ATExecSetStorage(Relation rel, const cha
|
|
*** 4126,4131 ****
|
|
--- 4174,4182 ----
|
|
errmsg("cannot alter system column \"%s\"",
|
|
colName)));
|
|
|
|
+ /* SELinux checks db_column:{setattr} */
|
|
+ sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attrtuple->attnum);
|
|
+
|
|
/*
|
|
* safety check: do not allow toasted storage modes unless column datatype
|
|
* is TOAST-aware.
|
|
*************** ATExecDropColumn(List **wqueue, Relation
|
|
*** 4202,4207 ****
|
|
--- 4253,4261 ----
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
+ /* SELinux checks db_column:{drop} */
|
|
+ sepgsqlCheckColumnDrop(RelationGetRelid(rel), attnum);
|
|
+
|
|
/*
|
|
* Propagate to children as appropriate. Unlike most other ALTER
|
|
* routines, we have to do this one level of recursion at a time; we can't
|
|
*************** checkFkeyPermissions(Relation rel, int16
|
|
*** 5102,5108 ****
|
|
aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
|
|
ACL_REFERENCES);
|
|
if (aclresult == ACLCHECK_OK)
|
|
! return;
|
|
/* Else we must have REFERENCES on each column */
|
|
for (i = 0; i < natts; i++)
|
|
{
|
|
--- 5156,5162 ----
|
|
aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
|
|
ACL_REFERENCES);
|
|
if (aclresult == ACLCHECK_OK)
|
|
! goto ok;
|
|
/* Else we must have REFERENCES on each column */
|
|
for (i = 0; i < natts; i++)
|
|
{
|
|
*************** checkFkeyPermissions(Relation rel, int16
|
|
*** 5112,5117 ****
|
|
--- 5166,5174 ----
|
|
aclcheck_error(aclresult, ACL_KIND_CLASS,
|
|
RelationGetRelationName(rel));
|
|
}
|
|
+ ok:
|
|
+ /* SELinux: check db_table/db_column:{reference} */
|
|
+ sepgsqlCheckTableReference(rel, attnums, natts);
|
|
}
|
|
|
|
/*
|
|
*************** ATExecAlterColumnType(AlteredTableInfo *
|
|
*** 5715,5720 ****
|
|
--- 5772,5780 ----
|
|
errmsg("cannot alter type of column \"%s\" twice",
|
|
colName)));
|
|
|
|
+ /* SELinux checks db_column:{setattr} */
|
|
+ sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attnum);
|
|
+
|
|
/* Look up the target type (should not fail, since prep found it) */
|
|
typeTuple = typenameType(NULL, typename, &targettypmod);
|
|
tform = (Form_pg_type) GETSTRUCT(typeTuple);
|
|
*************** ATExecChangeOwner(Oid relationOid, Oid n
|
|
*** 6300,6305 ****
|
|
--- 6360,6367 ----
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
get_namespace_name(namespaceOid));
|
|
}
|
|
+ /* SELinux checks db_table:{setattr} */
|
|
+ sepgsqlCheckTableSetattr(relationOid);
|
|
}
|
|
|
|
memset(repl_null, false, sizeof(repl_null));
|
|
*************** AlterSeqNamespaces(Relation classRel, Re
|
|
*** 7754,7759 ****
|
|
--- 7816,7943 ----
|
|
relation_close(depRel, AccessShareLock);
|
|
}
|
|
|
|
+ /*
|
|
+ * ALTER TABLE/SEQUENCE name SECURITY_LABEL [=] newlabel
|
|
+ * ALTER TABLE/SEQUENCE name ALTER column SECURITY_LABEL [=] newlabel
|
|
+ */
|
|
+ static void
|
|
+ ExecRelationSetSecLabel(Oid relid, DefElem *seclabel)
|
|
+ {
|
|
+ Relation rel;
|
|
+ HeapTuple oldtup;
|
|
+ HeapTuple newtup;
|
|
+ Oid secid;
|
|
+ bool replaces[Natts_pg_class];
|
|
+
|
|
+ rel = heap_open(RelationRelationId, RowExclusiveLock);
|
|
+ oldtup = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(oldtup))
|
|
+ elog(ERROR, "cache lookup failed for relation: %u", relid);
|
|
+
|
|
+ memset(replaces, false, sizeof(replaces));
|
|
+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
|
|
+ NULL, NULL, replaces);
|
|
+ ReleaseSysCache(oldtup);
|
|
+
|
|
+ /* SELinux checks db_table:{setattr relabelfrom relabelto} */
|
|
+ secid = sepgsqlCheckTableRelabel(relid, seclabel);
|
|
+ if (!HeapTupleHasSecLabel(newtup))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to set security label on \"%s\"",
|
|
+ get_rel_name(relid))));
|
|
+ HeapTupleSetSecLabel(newtup, secid);
|
|
+
|
|
+ simple_heap_update(rel, &newtup->t_self, newtup);
|
|
+ CatalogUpdateIndexes(rel, newtup);
|
|
+
|
|
+ heap_freetuple(newtup);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
+
|
|
+ static void
|
|
+ ExecAttributeSetSecLabel(Oid relid, const char *attname, DefElem *seclabel)
|
|
+ {
|
|
+ Relation rel;
|
|
+ HeapTuple oldtup;
|
|
+ HeapTuple newtup;
|
|
+ AttrNumber attnum;
|
|
+ Oid secid;
|
|
+ bool replaces[Natts_pg_attribute];
|
|
+
|
|
+ rel = heap_open(AttributeRelationId, RowExclusiveLock);
|
|
+ oldtup = SearchSysCacheAttName(relid, attname);
|
|
+ if (!HeapTupleIsValid(oldtup))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
|
|
+ attname, get_rel_name(relid))));
|
|
+ attnum = ((Form_pg_attribute) GETSTRUCT(oldtup))->attnum;
|
|
+
|
|
+ memset(replaces, false, sizeof(replaces));
|
|
+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
|
|
+ NULL, NULL, replaces);
|
|
+ ReleaseSysCache(oldtup);
|
|
+
|
|
+ /* SELinux checks db_column:{setattr relabelfrom relabelto} */
|
|
+ secid = sepgsqlCheckColumnRelabel(relid, attnum, seclabel);
|
|
+ if (!HeapTupleHasSecLabel(newtup))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to set security label on \"%s.%s\"",
|
|
+ get_rel_name(relid), attname)));
|
|
+ HeapTupleSetSecLabel(newtup, secid);
|
|
+
|
|
+ simple_heap_update(rel, &newtup->t_self, newtup);
|
|
+ CatalogUpdateIndexes(rel, newtup);
|
|
+
|
|
+ heap_freetuple(newtup);
|
|
+
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ AlterRelationSecLabel(RangeVar *relation, const char *attname,
|
|
+ ObjectType objtype, DefElem *seclabel)
|
|
+ {
|
|
+ Oid relid;
|
|
+ char relkind;
|
|
+
|
|
+ /* Check relation type against type specified in the ALTER command */
|
|
+ relid = RangeVarGetRelid(relation, false);
|
|
+ relkind = get_rel_relkind(relid);
|
|
+
|
|
+ switch (objtype)
|
|
+ {
|
|
+ case OBJECT_TABLE:
|
|
+ case OBJECT_COLUMN:
|
|
+ if (relkind != RELKIND_RELATION)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
+ errmsg("\"%s\" is not a table", get_rel_name(relid))));
|
|
+ break;
|
|
+
|
|
+ case OBJECT_SEQUENCE:
|
|
+ if (relkind != RELKIND_SEQUENCE)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
+ errmsg("\"%s\" is not a sequence", get_rel_name(relid))));
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ elog(ERROR, "unrecognized object type: %d", (int)objtype);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Exec set security label */
|
|
+ if (objtype != OBJECT_COLUMN)
|
|
+ ExecRelationSetSecLabel(relid, seclabel);
|
|
+ else
|
|
+ ExecAttributeSetSecLabel(relid, attname, seclabel);
|
|
+ }
|
|
|
|
/*
|
|
* This code supports
|
|
diff -Nrpc base/src/backend/commands/trigger.c sepgsql/src/backend/commands/trigger.c
|
|
*** base/src/backend/commands/trigger.c Fri Jun 19 13:40:37 2009
|
|
--- sepgsql/src/backend/commands/trigger.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 33,38 ****
|
|
--- 33,39 ----
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/parse_func.h"
|
|
#include "pgstat.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "tcop/utility.h"
|
|
#include "utils/acl.h"
|
|
*************** CreateTrigger(CreateTrigStmt *stmt, Oid
|
|
*** 182,187 ****
|
|
--- 183,191 ----
|
|
NameListToString(stmt->funcname))));
|
|
}
|
|
|
|
+ /* SELinux checks db_procedure:{install} */
|
|
+ sepgsqlCheckProcedureInstall(funcoid);
|
|
+
|
|
/*
|
|
* If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
|
|
* references one of the built-in RI_FKey trigger functions, assume it is
|
|
diff -Nrpc base/src/backend/commands/tsearchcmds.c sepgsql/src/backend/commands/tsearchcmds.c
|
|
*** base/src/backend/commands/tsearchcmds.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/tsearchcmds.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 35,40 ****
|
|
--- 35,41 ----
|
|
#include "miscadmin.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/parse_func.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "tsearch/ts_cache.h"
|
|
#include "tsearch/ts_public.h"
|
|
#include "tsearch/ts_utils.h"
|
|
*************** get_ts_parser_func(DefElem *defel, int a
|
|
*** 110,115 ****
|
|
--- 111,119 ----
|
|
func_signature_string(funcName, nargs, typeId),
|
|
format_type_be(retTypeId))));
|
|
|
|
+ /* SELinux checks db_procedure:{install} */
|
|
+ sepgsqlCheckProcedureInstall(procOid);
|
|
+
|
|
return ObjectIdGetDatum(procOid);
|
|
}
|
|
|
|
*************** get_ts_template_func(DefElem *defel, int
|
|
*** 948,953 ****
|
|
--- 952,960 ----
|
|
func_signature_string(funcName, nargs, typeId),
|
|
format_type_be(retTypeId))));
|
|
|
|
+ /* SELinux checks db_procedure:{install} */
|
|
+ sepgsqlCheckProcedureInstall(procOid);
|
|
+
|
|
return ObjectIdGetDatum(procOid);
|
|
}
|
|
|
|
diff -Nrpc base/src/backend/commands/typecmds.c sepgsql/src/backend/commands/typecmds.c
|
|
*** base/src/backend/commands/typecmds.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/commands/typecmds.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 56,61 ****
|
|
--- 56,62 ----
|
|
#include "parser/parse_expr.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"
|
|
*************** DefineType(List *names, List *parameters
|
|
*** 521,526 ****
|
|
--- 522,535 ----
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
NameListToString(analyzeName));
|
|
#endif
|
|
+ /* SELinux checks db_procedure:{install} */
|
|
+ sepgsqlCheckProcedureInstall(inputOid);
|
|
+ sepgsqlCheckProcedureInstall(outputOid);
|
|
+ sepgsqlCheckProcedureInstall(receiveOid);
|
|
+ sepgsqlCheckProcedureInstall(sendOid);
|
|
+ sepgsqlCheckProcedureInstall(typmodinOid);
|
|
+ sepgsqlCheckProcedureInstall(typmodoutOid);
|
|
+ sepgsqlCheckProcedureInstall(analyzeOid);
|
|
|
|
/* Preassign array type OID so we can insert it in pg_type.typarray */
|
|
pg_type = heap_open(TypeRelationId, AccessShareLock);
|
|
diff -Nrpc base/src/backend/executor/execJunk.c sepgsql/src/backend/executor/execJunk.c
|
|
*** base/src/backend/executor/execJunk.c Sat Jan 3 13:01:35 2009
|
|
--- sepgsql/src/backend/executor/execJunk.c Wed Jul 15 19:30:50 2009
|
|
***************
|
|
*** 60,66 ****
|
|
* An optional resultSlot can be passed as well.
|
|
*/
|
|
JunkFilter *
|
|
! ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
|
|
{
|
|
JunkFilter *junkfilter;
|
|
TupleDesc cleanTupType;
|
|
--- 60,67 ----
|
|
* An optional resultSlot can be passed as well.
|
|
*/
|
|
JunkFilter *
|
|
! ExecInitJunkFilter(List *targetList, bool hasoid, bool hasseclabel,
|
|
! TupleTableSlot *slot)
|
|
{
|
|
JunkFilter *junkfilter;
|
|
TupleDesc cleanTupType;
|
|
*************** ExecInitJunkFilter(List *targetList, boo
|
|
*** 72,78 ****
|
|
/*
|
|
* Compute the tuple descriptor for the cleaned tuple.
|
|
*/
|
|
! cleanTupType = ExecCleanTypeFromTL(targetList, hasoid);
|
|
|
|
/*
|
|
* Use the given slot, or make a new slot if we weren't given one.
|
|
--- 73,79 ----
|
|
/*
|
|
* Compute the tuple descriptor for the cleaned tuple.
|
|
*/
|
|
! cleanTupType = ExecCleanTypeFromTL(targetList, hasoid, hasseclabel);
|
|
|
|
/*
|
|
* Use the given slot, or make a new slot if we weren't given one.
|
|
diff -Nrpc base/src/backend/executor/execMain.c sepgsql/src/backend/executor/execMain.c
|
|
*** base/src/backend/executor/execMain.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/executor/execMain.c Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 39,44 ****
|
|
--- 39,45 ----
|
|
#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"
|
|
***************
|
|
*** 50,55 ****
|
|
--- 51,57 ----
|
|
#include "optimizer/clauses.h"
|
|
#include "parser/parse_clause.h"
|
|
#include "parser/parsetree.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/lmgr.h"
|
|
#include "storage/smgr.h"
|
|
*************** ExecCheckRTPerms(List *rangeTable)
|
|
*** 442,448 ****
|
|
|
|
foreach(l, rangeTable)
|
|
{
|
|
! ExecCheckRTEPerms((RangeTblEntry *) lfirst(l));
|
|
}
|
|
}
|
|
|
|
--- 444,453 ----
|
|
|
|
foreach(l, rangeTable)
|
|
{
|
|
! RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
|
!
|
|
! ExecCheckRTEPerms(rte);
|
|
! sepgsqlCheckRTEPerms(rte);
|
|
}
|
|
}
|
|
|
|
*************** InitPlan(QueryDesc *queryDesc, int eflag
|
|
*** 901,916 ****
|
|
for (i = 0; i < as_nplans; i++)
|
|
{
|
|
PlanState *subplan = appendplans[i];
|
|
JunkFilter *j;
|
|
|
|
if (operation == CMD_UPDATE)
|
|
! ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
|
|
! subplan->plan->targetlist);
|
|
|
|
j = ExecInitJunkFilter(subplan->plan->targetlist,
|
|
! resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
|
|
! ExecAllocTableSlot(estate->es_tupleTable));
|
|
!
|
|
/*
|
|
* Since it must be UPDATE/DELETE, there had better be a
|
|
* "ctid" junk attribute in the tlist ... but ctid could
|
|
--- 906,921 ----
|
|
for (i = 0; i < as_nplans; i++)
|
|
{
|
|
PlanState *subplan = appendplans[i];
|
|
+ Relation resultRel = resultRelInfo->ri_RelationDesc;
|
|
JunkFilter *j;
|
|
|
|
if (operation == CMD_UPDATE)
|
|
! ExecCheckPlanOutput(resultRel, subplan->plan->targetlist);
|
|
|
|
j = ExecInitJunkFilter(subplan->plan->targetlist,
|
|
! RelationGetDescr(resultRel)->tdhasoid,
|
|
! RelationGetDescr(resultRel)->tdhasseclabel,
|
|
! ExecAllocTableSlot(estate->es_tupleTable));
|
|
/*
|
|
* Since it must be UPDATE/DELETE, there had better be a
|
|
* "ctid" junk attribute in the tlist ... but ctid could
|
|
*************** InitPlan(QueryDesc *queryDesc, int eflag
|
|
*** 953,958 ****
|
|
--- 958,964 ----
|
|
|
|
j = ExecInitJunkFilter(planstate->plan->targetlist,
|
|
tupType->tdhasoid,
|
|
+ tupType->tdhasseclabel,
|
|
ExecAllocTableSlot(estate->es_tupleTable));
|
|
estate->es_junkFilter = j;
|
|
if (estate->es_result_relation_info)
|
|
*************** InitPlan(QueryDesc *queryDesc, int eflag
|
|
*** 1023,1029 ****
|
|
* We assume all the sublists will generate the same output tupdesc.
|
|
*/
|
|
tupType = ExecTypeFromTL((List *) linitial(plannedstmt->returningLists),
|
|
! false);
|
|
|
|
/* Set up a slot for the output of the RETURNING projection(s) */
|
|
slot = ExecAllocTableSlot(estate->es_tupleTable);
|
|
--- 1029,1035 ----
|
|
* We assume all the sublists will generate the same output tupdesc.
|
|
*/
|
|
tupType = ExecTypeFromTL((List *) linitial(plannedstmt->returningLists),
|
|
! false, false);
|
|
|
|
/* Set up a slot for the output of the RETURNING projection(s) */
|
|
slot = ExecAllocTableSlot(estate->es_tupleTable);
|
|
*************** ExecContextForcesOids(PlanState *plansta
|
|
*** 1346,1351 ****
|
|
--- 1352,1388 ----
|
|
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(InvalidOid,
|
|
+ RELKIND_RELATION);
|
|
+ return true;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ResultRelInfo *ri = planstate->state->es_result_relation_info;
|
|
+
|
|
+ if (ri && ri->ri_RelationDesc)
|
|
+ {
|
|
+ Oid relid = RelationGetRelid(ri->ri_RelationDesc);
|
|
+ char relkind = RelationGetForm(ri->ri_RelationDesc)->relkind;
|
|
+
|
|
+ *hassecurity = securityTupleDescHasSecLabel(relid, relkind);
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
/* ----------------------------------------------------------------
|
|
* ExecEndPlan
|
|
*
|
|
*************** ExecEndPlan(PlanState *planstate, EState
|
|
*** 1426,1431 ****
|
|
--- 1463,1520 ----
|
|
}
|
|
}
|
|
|
|
+ /*
|
|
+ * fetchWritableSystemAttribute() fetches writable system column data
|
|
+ * using Junkfilter, and saves them at TupleTableSlot temporary.
|
|
+ *
|
|
+ * storeWritableSystemAttribute() copies these fetched data into
|
|
+ * header structure of HeapTuple.
|
|
+ */
|
|
+ static void
|
|
+ fetchWritableSystemAttribute(JunkFilter *junkfilter, TupleTableSlot *slot,
|
|
+ Datum *tts_seclabel)
|
|
+ {
|
|
+ AttrNumber attno;
|
|
+ Datum datum;
|
|
+ bool isnull;
|
|
+
|
|
+ /* for Security Label */
|
|
+ attno = ExecFindJunkAttribute(junkfilter, SecurityLabelAttributeName);
|
|
+ if (attno != InvalidAttrNumber)
|
|
+ {
|
|
+ datum = ExecGetJunkAttribute(slot, attno, &isnull);
|
|
+ if (isnull)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to set NULL on \"%s\"",
|
|
+ SecurityLabelAttributeName)));
|
|
+ *tts_seclabel = datum;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static void
|
|
+ storeWritableSystemAttribute(Relation rel, TupleTableSlot *slot, HeapTuple tuple)
|
|
+ {
|
|
+ Oid relid = RelationGetRelid(rel);
|
|
+ Oid secid;
|
|
+
|
|
+ /* "security_label" */
|
|
+ if (DatumGetPointer(slot->tts_seclabel) != NULL)
|
|
+ {
|
|
+ char *seclabel = TextDatumGetCString(slot->tts_seclabel);
|
|
+
|
|
+ if (!HeapTupleHasSecLabel(tuple))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to assign security label on \"%s\"",
|
|
+ RelationGetRelationName(rel))));
|
|
+ secid = securityTransSecLabelIn(relid, seclabel);
|
|
+ HeapTupleSetSecLabel(tuple, secid);
|
|
+ }
|
|
+ else if (HeapTupleHasSecLabel(tuple))
|
|
+ HeapTupleSetSecLabel(tuple, InvalidOid);
|
|
+ }
|
|
+
|
|
/* ----------------------------------------------------------------
|
|
* ExecutePlan
|
|
*
|
|
*************** ExecutePlan(EState *estate,
|
|
*** 1487,1492 ****
|
|
--- 1576,1583 ----
|
|
*/
|
|
for (;;)
|
|
{
|
|
+ Datum tts_seclabel = PointerGetDatum(NULL);
|
|
+
|
|
/* Reset the per-output-tuple exprcontext */
|
|
ResetPerTupleExprContext(estate);
|
|
|
|
*************** lnext: ;
|
|
*** 1631,1636 ****
|
|
--- 1722,1732 ----
|
|
}
|
|
|
|
/*
|
|
+ * extract writable system attribute
|
|
+ */
|
|
+ fetchWritableSystemAttribute(junkfilter, slot, &tts_seclabel);
|
|
+
|
|
+ /*
|
|
* extract the 'ctid' junk attribute.
|
|
*/
|
|
if (operation == CMD_UPDATE || operation == CMD_DELETE)
|
|
*************** lnext: ;
|
|
*** 1657,1662 ****
|
|
--- 1753,1759 ----
|
|
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
|
|
*************** ExecInsert(TupleTableSlot *slot,
|
|
*** 1781,1786 ****
|
|
--- 1878,1885 ----
|
|
if (resultRelationDesc->rd_rel->relhasoids)
|
|
HeapTupleSetOid(tuple, InvalidOid);
|
|
|
|
+ storeWritableSystemAttribute(resultRelationDesc, slot, tuple);
|
|
+
|
|
/* BEFORE ROW INSERT Triggers */
|
|
if (resultRelInfo->ri_TrigDesc &&
|
|
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
|
|
*************** ExecInsert(TupleTableSlot *slot,
|
|
*** 1811,1816 ****
|
|
--- 1910,1921 ----
|
|
}
|
|
|
|
/*
|
|
+ * SELinux assigns default security label, and
|
|
+ * it also checks db_tuple:{insert} permission
|
|
+ */
|
|
+ sepgsqlHeapTupleInsert(resultRelationDesc, tuple, false);
|
|
+
|
|
+ /*
|
|
* Check the constraints of the tuple
|
|
*/
|
|
if (resultRelationDesc->rd_att->constr)
|
|
*************** ExecUpdate(TupleTableSlot *slot,
|
|
*** 2018,2023 ****
|
|
--- 2123,2130 ----
|
|
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)
|
|
*************** ExecUpdate(TupleTableSlot *slot,
|
|
*** 2048,2053 ****
|
|
--- 2155,2163 ----
|
|
}
|
|
}
|
|
|
|
+ /* SELinux checks db_tuple:{relabelfrom relabelto}, if needed */
|
|
+ sepgsqlHeapTupleUpdate(resultRelationDesc, tupleid, tuple);
|
|
+
|
|
/*
|
|
* Check the constraints of the tuple
|
|
*
|
|
*************** OpenIntoRel(QueryDesc *queryDesc)
|
|
*** 2843,2848 ****
|
|
--- 2953,2959 ----
|
|
Oid namespaceId;
|
|
Oid tablespaceId;
|
|
Datum reloptions;
|
|
+ Oid *secLabels;
|
|
AclResult aclresult;
|
|
Oid intoRelationId;
|
|
TupleDesc tupdesc;
|
|
*************** OpenIntoRel(QueryDesc *queryDesc)
|
|
*** 2871,2876 ****
|
|
--- 2982,2991 ----
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
get_namespace_name(namespaceId));
|
|
|
|
+ /* SELinux checks db_table:{create} and db_column:{create} */
|
|
+ secLabels = sepgsqlCreateTableColumns(NULL, intoName, namespaceId,
|
|
+ queryDesc->tupDesc, RELKIND_RELATION);
|
|
+
|
|
/*
|
|
* Select tablespace to use. If not specified, use default tablespace
|
|
* (which may in turn default to database's default).
|
|
*************** OpenIntoRel(QueryDesc *queryDesc)
|
|
*** 2929,2935 ****
|
|
0,
|
|
into->onCommit,
|
|
reloptions,
|
|
! allowSystemTableMods);
|
|
|
|
FreeTupleDesc(tupdesc);
|
|
|
|
--- 3044,3051 ----
|
|
0,
|
|
into->onCommit,
|
|
reloptions,
|
|
! allowSystemTableMods,
|
|
! secLabels);
|
|
|
|
FreeTupleDesc(tupdesc);
|
|
|
|
*************** OpenIntoRel(QueryDesc *queryDesc)
|
|
*** 2956,2961 ****
|
|
--- 3072,3082 ----
|
|
AlterTableCreateToastTable(intoRelationId, InvalidOid, reloptions, false);
|
|
|
|
/*
|
|
+ * SELinux: checks db_table/column:{insert} permission
|
|
+ */
|
|
+ sepgsqlCheckSelectInto(intoRelationId);
|
|
+
|
|
+ /*
|
|
* And open the constructed table for writing.
|
|
*/
|
|
intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock);
|
|
*************** intorel_receive(TupleTableSlot *slot, De
|
|
*** 3054,3059 ****
|
|
--- 3175,3184 ----
|
|
if (myState->rel->rd_rel->relhasoids)
|
|
HeapTupleSetOid(tuple, InvalidOid);
|
|
|
|
+ storeWritableSystemAttribute(myState->rel, slot, tuple);
|
|
+ /* SELinux checks db_tuple:{insert} */
|
|
+ sepgsqlHeapTupleInsert(myState->rel, tuple, false);
|
|
+
|
|
heap_insert(myState->rel,
|
|
tuple,
|
|
myState->estate->es_output_cid,
|
|
diff -Nrpc base/src/backend/executor/execScan.c sepgsql/src/backend/executor/execScan.c
|
|
*** base/src/backend/executor/execScan.c Thu Apr 9 00:13:21 2009
|
|
--- sepgsql/src/backend/executor/execScan.c Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 20,25 ****
|
|
--- 20,26 ----
|
|
|
|
#include "executor/executor.h"
|
|
#include "miscadmin.h"
|
|
+ #include "security/rowlevel.h"
|
|
#include "utils/memutils.h"
|
|
|
|
|
|
*************** ExecScan(ScanState *node,
|
|
*** 53,58 ****
|
|
--- 54,60 ----
|
|
ProjectionInfo *projInfo;
|
|
ExprDoneCond isDone;
|
|
TupleTableSlot *resultSlot;
|
|
+ Scan *scan = (Scan *)node->ps.plan;
|
|
|
|
/*
|
|
* Fetch data from node
|
|
*************** ExecScan(ScanState *node,
|
|
*** 64,70 ****
|
|
* 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)
|
|
return (*accessMtd) (node);
|
|
|
|
/*
|
|
--- 66,72 ----
|
|
* 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 && !scan->rowlvPerms)
|
|
return (*accessMtd) (node);
|
|
|
|
/*
|
|
*************** ExecScan(ScanState *node,
|
|
*** 128,136 ****
|
|
* when the qual is nil ... saves only a few cycles, but they add up
|
|
* ...
|
|
*/
|
|
! if (!qual || ExecQual(qual, econtext, false))
|
|
{
|
|
/*
|
|
* Found a satisfactory scan tuple.
|
|
*/
|
|
if (projInfo)
|
|
--- 130,147 ----
|
|
* when the qual is nil ... saves only a few cycles, but they add up
|
|
* ...
|
|
*/
|
|
! if (rowlvExecScanFilter(scan, node->ss_currentRelation, slot)
|
|
! && (!qual || ExecQual(qual, econtext, false)))
|
|
{
|
|
/*
|
|
+ * NOTE: On FK checks, the Row-level feature needs to raise
|
|
+ * an error after evaluation of all the given quals to avoid
|
|
+ * incorrect error reporting. We assume FK implementation
|
|
+ * does not use malicious functions as the quals.
|
|
+ */
|
|
+ rowlvExecScanAbort(scan, node->ss_currentRelation, slot);
|
|
+
|
|
+ /*
|
|
* Found a satisfactory scan tuple.
|
|
*/
|
|
if (projInfo)
|
|
*************** tlist_matches_tupdesc(PlanState *ps, Lis
|
|
*** 197,202 ****
|
|
--- 208,214 ----
|
|
int numattrs = tupdesc->natts;
|
|
int attrno;
|
|
bool hasoid;
|
|
+ bool hasseclabel;
|
|
ListCell *tlist_item = list_head(tlist);
|
|
|
|
/* Check the tlist attributes */
|
|
*************** tlist_matches_tupdesc(PlanState *ps, Lis
|
|
*** 240,251 ****
|
|
return false; /* tlist too long */
|
|
|
|
/*
|
|
! * If the plan context requires a particular hasoid setting, then that has
|
|
! * to match, too.
|
|
*/
|
|
if (ExecContextForcesOids(ps, &hasoid) &&
|
|
hasoid != tupdesc->tdhasoid)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
--- 252,267 ----
|
|
return false; /* tlist too long */
|
|
|
|
/*
|
|
! * If the plan context requires a particular hasoid or 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 -Nrpc base/src/backend/executor/execTuples.c sepgsql/src/backend/executor/execTuples.c
|
|
*** base/src/backend/executor/execTuples.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/executor/execTuples.c Wed Jul 15 19:30:50 2009
|
|
***************
|
|
*** 100,106 ****
|
|
|
|
|
|
static TupleDesc ExecTypeFromTLInternal(List *targetList,
|
|
! bool hasoid, bool skipjunk);
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
--- 100,106 ----
|
|
|
|
|
|
static TupleDesc ExecTypeFromTLInternal(List *targetList,
|
|
! bool hasoid, bool hasseclabel, bool skipjunk);
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
*************** ExecInitNullTupleSlot(EState *estate, Tu
|
|
*** 968,976 ****
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
TupleDesc
|
|
! ExecTypeFromTL(List *targetList, bool hasoid)
|
|
{
|
|
! return ExecTypeFromTLInternal(targetList, hasoid, false);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
--- 968,976 ----
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
TupleDesc
|
|
! ExecTypeFromTL(List *targetList, bool hasoid, bool hasseclabel)
|
|
{
|
|
! return ExecTypeFromTLInternal(targetList, hasoid, hasseclabel, false);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
*************** ExecTypeFromTL(List *targetList, bool ha
|
|
*** 980,992 ****
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
TupleDesc
|
|
! ExecCleanTypeFromTL(List *targetList, bool hasoid)
|
|
{
|
|
! return ExecTypeFromTLInternal(targetList, hasoid, true);
|
|
}
|
|
|
|
static TupleDesc
|
|
! ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk)
|
|
{
|
|
TupleDesc typeInfo;
|
|
ListCell *l;
|
|
--- 980,993 ----
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
TupleDesc
|
|
! ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hasseclabel)
|
|
{
|
|
! return ExecTypeFromTLInternal(targetList, hasoid, hasseclabel, true);
|
|
}
|
|
|
|
static TupleDesc
|
|
! ExecTypeFromTLInternal(List *targetList, bool hasoid,
|
|
! bool hasseclabel, bool skipjunk)
|
|
{
|
|
TupleDesc typeInfo;
|
|
ListCell *l;
|
|
*************** ExecTypeFromTLInternal(List *targetList,
|
|
*** 998,1003 ****
|
|
--- 999,1005 ----
|
|
else
|
|
len = ExecTargetListLength(targetList);
|
|
typeInfo = CreateTemplateTupleDesc(len, hasoid);
|
|
+ typeInfo->tdhasseclabel = hasseclabel;
|
|
|
|
foreach(l, targetList)
|
|
{
|
|
diff -Nrpc base/src/backend/executor/execUtils.c sepgsql/src/backend/executor/execUtils.c
|
|
*** base/src/backend/executor/execUtils.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/executor/execUtils.c Wed Jul 15 19:30:50 2009
|
|
*************** void
|
|
*** 506,511 ****
|
|
--- 506,512 ----
|
|
ExecAssignResultTypeFromTL(PlanState *planstate)
|
|
{
|
|
bool hasoid;
|
|
+ bool hasseclabel;
|
|
TupleDesc tupDesc;
|
|
|
|
if (ExecContextForcesOids(planstate, &hasoid))
|
|
*************** ExecAssignResultTypeFromTL(PlanState *pl
|
|
*** 518,529 ****
|
|
hasoid = 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);
|
|
ExecAssignResultType(planstate, tupDesc);
|
|
}
|
|
|
|
--- 519,533 ----
|
|
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, hasseclabel);
|
|
ExecAssignResultType(planstate, tupDesc);
|
|
}
|
|
|
|
diff -Nrpc base/src/backend/executor/functions.c sepgsql/src/backend/executor/functions.c
|
|
*** base/src/backend/executor/functions.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/executor/functions.c Wed Jul 15 19:30:50 2009
|
|
*************** check_sql_fn_retval(Oid func_id, Oid ret
|
|
*** 1135,1141 ****
|
|
|
|
/* Set up junk filter if needed */
|
|
if (junkFilter)
|
|
! *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
|
|
}
|
|
else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
|
|
{
|
|
--- 1135,1141 ----
|
|
|
|
/* Set up junk filter if needed */
|
|
if (junkFilter)
|
|
! *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL);
|
|
}
|
|
else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
|
|
{
|
|
*************** check_sql_fn_retval(Oid func_id, Oid ret
|
|
*** 1167,1173 ****
|
|
COERCE_DONTCARE);
|
|
/* Set up junk filter if needed */
|
|
if (junkFilter)
|
|
! *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
|
|
return false; /* NOT returning whole tuple */
|
|
}
|
|
}
|
|
--- 1167,1173 ----
|
|
COERCE_DONTCARE);
|
|
/* Set up junk filter if needed */
|
|
if (junkFilter)
|
|
! *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL);
|
|
return false; /* NOT returning whole tuple */
|
|
}
|
|
}
|
|
*************** check_sql_fn_retval(Oid func_id, Oid ret
|
|
*** 1180,1186 ****
|
|
* what the caller expects will happen at runtime.
|
|
*/
|
|
if (junkFilter)
|
|
! *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
|
|
return true;
|
|
}
|
|
Assert(tupdesc);
|
|
--- 1180,1186 ----
|
|
* what the caller expects will happen at runtime.
|
|
*/
|
|
if (junkFilter)
|
|
! *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL);
|
|
return true;
|
|
}
|
|
Assert(tupdesc);
|
|
diff -Nrpc base/src/backend/executor/nodeSubplan.c sepgsql/src/backend/executor/nodeSubplan.c
|
|
*** base/src/backend/executor/nodeSubplan.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/executor/nodeSubplan.c Wed Jul 15 19:30:50 2009
|
|
*************** ExecInitSubPlan(SubPlan *subplan, PlanSt
|
|
*** 869,875 ****
|
|
* (hack alert!). The righthand expressions will be evaluated in our
|
|
* own innerecontext.
|
|
*/
|
|
! tupDesc = ExecTypeFromTL(leftptlist, false);
|
|
slot = ExecAllocTableSlot(tupTable);
|
|
ExecSetSlotDescriptor(slot, tupDesc);
|
|
sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
|
|
--- 869,875 ----
|
|
* (hack alert!). The righthand expressions will be evaluated in our
|
|
* own innerecontext.
|
|
*/
|
|
! tupDesc = ExecTypeFromTL(leftptlist, false, false);
|
|
slot = ExecAllocTableSlot(tupTable);
|
|
ExecSetSlotDescriptor(slot, tupDesc);
|
|
sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
|
|
*************** ExecInitSubPlan(SubPlan *subplan, PlanSt
|
|
*** 877,883 ****
|
|
slot,
|
|
NULL);
|
|
|
|
! tupDesc = ExecTypeFromTL(rightptlist, false);
|
|
slot = ExecAllocTableSlot(tupTable);
|
|
ExecSetSlotDescriptor(slot, tupDesc);
|
|
sstate->projRight = ExecBuildProjectionInfo(righttlist,
|
|
--- 877,883 ----
|
|
slot,
|
|
NULL);
|
|
|
|
! tupDesc = ExecTypeFromTL(rightptlist, false, false);
|
|
slot = ExecAllocTableSlot(tupTable);
|
|
ExecSetSlotDescriptor(slot, tupDesc);
|
|
sstate->projRight = ExecBuildProjectionInfo(righttlist,
|
|
diff -Nrpc base/src/backend/executor/spi.c sepgsql/src/backend/executor/spi.c
|
|
*** base/src/backend/executor/spi.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/executor/spi.c Wed Jul 15 19:30:50 2009
|
|
*************** SPI_modifytuple(Relation rel, HeapTuple
|
|
*** 705,710 ****
|
|
--- 705,712 ----
|
|
mtuple->t_tableOid = tuple->t_tableOid;
|
|
if (rel->rd_att->tdhasoid)
|
|
HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
|
|
+ if (HeapTupleHasSecLabel(mtuple))
|
|
+ HeapTupleSetSecLabel(mtuple, HeapTupleGetSecLabel(tuple));
|
|
}
|
|
else
|
|
{
|
|
diff -Nrpc base/src/backend/libpq/be-fsstubs.c sepgsql/src/backend/libpq/be-fsstubs.c
|
|
*** base/src/backend/libpq/be-fsstubs.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/libpq/be-fsstubs.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 42,50 ****
|
|
--- 42,53 ----
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
+ #include "catalog/pg_largeobject.h"
|
|
+ #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"
|
|
*************** lo_read(int fd, char *buf, int len)
|
|
*** 156,161 ****
|
|
--- 159,167 ----
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
errmsg("invalid large-object descriptor: %d", fd)));
|
|
|
|
+ /* SELinux checks db_blob:{read} */
|
|
+ sepgsqlCheckBlobRead(cookies[fd]);
|
|
+
|
|
status = inv_read(cookies[fd], buf, len);
|
|
|
|
return status;
|
|
*************** lo_write(int fd, const char *buf, int le
|
|
*** 177,182 ****
|
|
--- 183,191 ----
|
|
errmsg("large object descriptor %d was not opened for writing",
|
|
fd)));
|
|
|
|
+ /* SELinux checks db_blob:{write} */
|
|
+ sepgsqlCheckBlobWrite(cookies[fd]);
|
|
+
|
|
status = inv_write(cookies[fd], buf, len);
|
|
|
|
return status;
|
|
*************** lo_import_internal(text *filename, Oid l
|
|
*** 381,386 ****
|
|
--- 390,398 ----
|
|
*/
|
|
lobj = inv_open(oid, INV_WRITE, fscxt);
|
|
|
|
+ /* SELinux checks db_blob:{write import} and file:{read} */
|
|
+ sepgsqlCheckBlobImport(lobj, FileRawDescriptor(fd), fnamebuf);
|
|
+
|
|
while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0)
|
|
{
|
|
tmp = inv_write(lobj, buf, nbytes);
|
|
*************** lo_export(PG_FUNCTION_ARGS)
|
|
*** 448,453 ****
|
|
--- 460,468 ----
|
|
errmsg("could not create server file \"%s\": %m",
|
|
fnamebuf)));
|
|
|
|
+ /* SELinux checks db_blob:{read export} and file:{write} */
|
|
+ sepgsqlCheckBlobExport(lobj, FileRawDescriptor(fd), fnamebuf);
|
|
+
|
|
/*
|
|
* read in from the inversion file and write to the filesystem
|
|
*/
|
|
*************** lo_truncate(PG_FUNCTION_ARGS)
|
|
*** 482,493 ****
|
|
--- 497,560 ----
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
errmsg("invalid large-object descriptor: %d", fd)));
|
|
|
|
+ /* SELinux checks db_blob:{write} */
|
|
+ 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;
|
|
+ char *seclabel;
|
|
+
|
|
+ secid = inv_get_security(loid);
|
|
+ seclabel = securityTransSecLabelOut(LargeObjectRelationId, secid);
|
|
+
|
|
+ return CStringGetTextDatum(seclabel);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 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(LargeObjectRelationId, 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 -Nrpc base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfuncs.c
|
|
*** base/src/backend/nodes/copyfuncs.c Fri Jun 19 13:40:37 2009
|
|
--- sepgsql/src/backend/nodes/copyfuncs.c Wed Jul 15 19:39:56 2009
|
|
*************** CopyScanFields(Scan *from, Scan *newnode
|
|
*** 259,264 ****
|
|
--- 259,265 ----
|
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
|
|
|
COPY_SCALAR_FIELD(scanrelid);
|
|
+ COPY_SCALAR_FIELD(rowlvPerms);
|
|
}
|
|
|
|
/*
|
|
*************** _copyColumnDef(ColumnDef *from)
|
|
*** 2075,2080 ****
|
|
--- 2076,2082 ----
|
|
COPY_NODE_FIELD(raw_default);
|
|
COPY_STRING_FIELD(cooked_default);
|
|
COPY_NODE_FIELD(constraints);
|
|
+ COPY_NODE_FIELD(secLabel);
|
|
|
|
return newnode;
|
|
}
|
|
*************** _copyCreateStmt(CreateStmt *from)
|
|
*** 2414,2419 ****
|
|
--- 2416,2422 ----
|
|
COPY_NODE_FIELD(options);
|
|
COPY_SCALAR_FIELD(oncommit);
|
|
COPY_STRING_FIELD(tablespacename);
|
|
+ COPY_NODE_FIELD(secLabel);
|
|
|
|
return newnode;
|
|
}
|
|
*************** _copyAlterOwnerStmt(AlterOwnerStmt *from
|
|
*** 2638,2643 ****
|
|
--- 2641,2661 ----
|
|
return newnode;
|
|
}
|
|
|
|
+ static AlterSecLabelStmt *
|
|
+ _copyAlterSecLabelStmt(AlterSecLabelStmt *from)
|
|
+ {
|
|
+ AlterSecLabelStmt *newnode = makeNode(AlterSecLabelStmt);
|
|
+
|
|
+ COPY_SCALAR_FIELD(objectType);
|
|
+ COPY_NODE_FIELD(relation);
|
|
+ COPY_NODE_FIELD(object);
|
|
+ COPY_NODE_FIELD(objarg);
|
|
+ COPY_STRING_FIELD(subname);
|
|
+ COPY_NODE_FIELD(secLabel);
|
|
+
|
|
+ return newnode;
|
|
+ }
|
|
+
|
|
static RuleStmt *
|
|
_copyRuleStmt(RuleStmt *from)
|
|
{
|
|
*************** _copyCreateSeqStmt(CreateSeqStmt *from)
|
|
*** 2887,2892 ****
|
|
--- 2905,2911 ----
|
|
|
|
COPY_NODE_FIELD(sequence);
|
|
COPY_NODE_FIELD(options);
|
|
+ COPY_NODE_FIELD(secLabel);
|
|
|
|
return newnode;
|
|
}
|
|
*************** copyObject(void *from)
|
|
*** 3819,3824 ****
|
|
--- 3838,3846 ----
|
|
case T_AlterOwnerStmt:
|
|
retval = _copyAlterOwnerStmt(from);
|
|
break;
|
|
+ case T_AlterSecLabelStmt:
|
|
+ retval = _copyAlterSecLabelStmt(from);
|
|
+ break;
|
|
case T_RuleStmt:
|
|
retval = _copyRuleStmt(from);
|
|
break;
|
|
diff -Nrpc base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalfuncs.c
|
|
*** base/src/backend/nodes/equalfuncs.c Fri Jun 19 13:40:37 2009
|
|
--- sepgsql/src/backend/nodes/equalfuncs.c Wed Jul 15 19:37:35 2009
|
|
*************** _equalCreateStmt(CreateStmt *a, CreateSt
|
|
*** 1078,1083 ****
|
|
--- 1078,1084 ----
|
|
COMPARE_NODE_FIELD(options);
|
|
COMPARE_SCALAR_FIELD(oncommit);
|
|
COMPARE_STRING_FIELD(tablespacename);
|
|
+ COMPARE_NODE_FIELD(secLabel);
|
|
|
|
return true;
|
|
}
|
|
*************** _equalAlterOwnerStmt(AlterOwnerStmt *a,
|
|
*** 1271,1276 ****
|
|
--- 1272,1290 ----
|
|
}
|
|
|
|
static bool
|
|
+ _equalAlterSecLabelStmt(AlterSecLabelStmt *a, AlterSecLabelStmt *b)
|
|
+ {
|
|
+ COMPARE_SCALAR_FIELD(objectType);
|
|
+ COMPARE_NODE_FIELD(relation);
|
|
+ COMPARE_NODE_FIELD(object);
|
|
+ COMPARE_NODE_FIELD(objarg);
|
|
+ COMPARE_STRING_FIELD(subname);
|
|
+ COMPARE_NODE_FIELD(secLabel);
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ static bool
|
|
_equalRuleStmt(RuleStmt *a, RuleStmt *b)
|
|
{
|
|
COMPARE_NODE_FIELD(relation);
|
|
*************** _equalCreateSeqStmt(CreateSeqStmt *a, Cr
|
|
*** 1477,1482 ****
|
|
--- 1491,1497 ----
|
|
{
|
|
COMPARE_NODE_FIELD(sequence);
|
|
COMPARE_NODE_FIELD(options);
|
|
+ COMPARE_NODE_FIELD(secLabel);
|
|
|
|
return true;
|
|
}
|
|
*************** _equalColumnDef(ColumnDef *a, ColumnDef
|
|
*** 2054,2059 ****
|
|
--- 2069,2075 ----
|
|
COMPARE_NODE_FIELD(raw_default);
|
|
COMPARE_STRING_FIELD(cooked_default);
|
|
COMPARE_NODE_FIELD(constraints);
|
|
+ COMPARE_NODE_FIELD(secLabel);
|
|
|
|
return true;
|
|
}
|
|
*************** equal(void *a, void *b)
|
|
*** 2596,2601 ****
|
|
--- 2612,2620 ----
|
|
case T_AlterOwnerStmt:
|
|
retval = _equalAlterOwnerStmt(a, b);
|
|
break;
|
|
+ case T_AlterSecLabelStmt:
|
|
+ retval = _equalAlterSecLabelStmt(a, b);
|
|
+ break;
|
|
case T_RuleStmt:
|
|
retval = _equalRuleStmt(a, b);
|
|
break;
|
|
diff -Nrpc base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs.c
|
|
*** base/src/backend/nodes/outfuncs.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/nodes/outfuncs.c Wed Jul 15 19:39:56 2009
|
|
*************** _outScanInfo(StringInfo str, Scan *node)
|
|
*** 285,290 ****
|
|
--- 285,291 ----
|
|
_outPlanInfo(str, (Plan *) node);
|
|
|
|
WRITE_UINT_FIELD(scanrelid);
|
|
+ WRITE_UINT_FIELD(rowlvPerms);
|
|
}
|
|
|
|
/*
|
|
*************** _outRelOptInfo(StringInfo str, RelOptInf
|
|
*** 1534,1539 ****
|
|
--- 1535,1541 ----
|
|
WRITE_BOOL_FIELD(has_eclass_joins);
|
|
WRITE_BITMAPSET_FIELD(index_outer_relids);
|
|
WRITE_NODE_FIELD(index_inner_paths);
|
|
+ WRITE_UINT_FIELD(rowlvPerms);
|
|
}
|
|
|
|
static void
|
|
*************** _outCreateStmt(StringInfo str, CreateStm
|
|
*** 1717,1722 ****
|
|
--- 1719,1725 ----
|
|
WRITE_NODE_FIELD(options);
|
|
WRITE_ENUM_FIELD(oncommit, OnCommitAction);
|
|
WRITE_STRING_FIELD(tablespacename);
|
|
+ WRITE_NODE_FIELD(secLabel);
|
|
}
|
|
|
|
static void
|
|
*************** _outColumnDef(StringInfo str, ColumnDef
|
|
*** 1839,1844 ****
|
|
--- 1842,1848 ----
|
|
WRITE_NODE_FIELD(raw_default);
|
|
WRITE_STRING_FIELD(cooked_default);
|
|
WRITE_NODE_FIELD(constraints);
|
|
+ WRITE_NODE_FIELD(secLabel);
|
|
}
|
|
|
|
static void
|
|
diff -Nrpc base/src/backend/optimizer/plan/createplan.c sepgsql/src/backend/optimizer/plan/createplan.c
|
|
*** base/src/backend/optimizer/plan/createplan.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/optimizer/plan/createplan.c Wed Jul 15 19:39:56 2009
|
|
*************** create_scan_plan(PlannerInfo *root, Path
|
|
*** 305,310 ****
|
|
--- 305,313 ----
|
|
break;
|
|
}
|
|
|
|
+ /* Copy of row-level permissions to Scan node */
|
|
+ ((Scan *)plan)->rowlvPerms = rel->rowlvPerms;
|
|
+
|
|
/*
|
|
* If there are any pseudoconstant clauses attached to this node, insert a
|
|
* gating Result node that evaluates the pseudoconstants as one-time
|
|
diff -Nrpc base/src/backend/optimizer/util/clauses.c sepgsql/src/backend/optimizer/util/clauses.c
|
|
*** base/src/backend/optimizer/util/clauses.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/optimizer/util/clauses.c Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 38,43 ****
|
|
--- 38,44 ----
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_func.h"
|
|
#include "rewrite/rewriteManip.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
*************** inline_function(Oid funcid, Oid result_t
|
|
*** 3502,3507 ****
|
|
--- 3503,3509 ----
|
|
funcform->prosecdef ||
|
|
funcform->proretset ||
|
|
!heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
|
|
+ !sepgsqlAllowFunctionInlined(func_tuple) ||
|
|
funcform->pronargs != list_length(args))
|
|
return NULL;
|
|
|
|
*************** inline_set_returning_function(PlannerInf
|
|
*** 3970,3975 ****
|
|
--- 3972,3978 ----
|
|
funcform->prosecdef ||
|
|
!funcform->proretset ||
|
|
!heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
|
|
+ !sepgsqlAllowFunctionInlined(func_tuple) ||
|
|
funcform->pronargs != list_length(fexpr->args))
|
|
{
|
|
ReleaseSysCache(func_tuple);
|
|
diff -Nrpc base/src/backend/optimizer/util/relnode.c sepgsql/src/backend/optimizer/util/relnode.c
|
|
*** base/src/backend/optimizer/util/relnode.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/optimizer/util/relnode.c Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 21,26 ****
|
|
--- 21,27 ----
|
|
#include "optimizer/plancat.h"
|
|
#include "optimizer/restrictinfo.h"
|
|
#include "parser/parsetree.h"
|
|
+ #include "security/rowlevel.h"
|
|
#include "utils/hsearch.h"
|
|
|
|
|
|
*************** build_simple_rel(PlannerInfo *root, int
|
|
*** 91,96 ****
|
|
--- 92,98 ----
|
|
rel->has_eclass_joins = false;
|
|
rel->index_outer_relids = NULL;
|
|
rel->index_inner_paths = NIL;
|
|
+ rel->rowlvPerms = rowlvSetupPermissions(rte);
|
|
|
|
/* Check type of rtable entry */
|
|
switch (rte->rtekind)
|
|
diff -Nrpc base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze.c
|
|
*** base/src/backend/parser/analyze.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/parser/analyze.c Wed Jul 15 19:38:52 2009
|
|
***************
|
|
*** 25,30 ****
|
|
--- 25,31 ----
|
|
#include "postgres.h"
|
|
|
|
#include "access/sysattr.h"
|
|
+ #include "catalog/heap.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "nodes/nodeFuncs.h"
|
|
*************** transformInsertStmt(ParseState *pstate,
|
|
*** 653,659 ****
|
|
tle = makeTargetEntry(expr,
|
|
attr_num,
|
|
col->name,
|
|
! false);
|
|
qry->targetList = lappend(qry->targetList, tle);
|
|
|
|
rte->modifiedCols = bms_add_member(rte->modifiedCols,
|
|
--- 654,660 ----
|
|
tle = makeTargetEntry(expr,
|
|
attr_num,
|
|
col->name,
|
|
! attr_num < 0 ? true : false);
|
|
qry->targetList = lappend(qry->targetList, tle);
|
|
|
|
rte->modifiedCols = bms_add_member(rte->modifiedCols,
|
|
*************** transformInsertRow(ParseState *pstate, L
|
|
*** 768,773 ****
|
|
--- 769,816 ----
|
|
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,
|
|
+ -1);
|
|
+ }
|
|
+ tle->resjunk = true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
|
|
/*
|
|
* transformSelectStmt -
|
|
*************** transformSelectStmt(ParseState *pstate,
|
|
*** 871,876 ****
|
|
--- 914,920 ----
|
|
if (stmt->intoClause)
|
|
{
|
|
qry->intoClause = stmt->intoClause;
|
|
+ transformSelectIntoSystemColumn(pstate, qry);
|
|
if (stmt->intoClause->colNames)
|
|
applyColumnNames(qry->targetList, stmt->intoClause->colNames);
|
|
}
|
|
diff -Nrpc base/src/backend/parser/gram.y sepgsql/src/backend/parser/gram.y
|
|
*** base/src/backend/parser/gram.y Fri Jun 19 13:40:37 2009
|
|
--- sepgsql/src/backend/parser/gram.y Wed Jul 15 19:37:35 2009
|
|
***************
|
|
*** 58,63 ****
|
|
--- 58,64 ----
|
|
#include "nodes/makefuncs.h"
|
|
#include "nodes/nodeFuncs.h"
|
|
#include "parser/gramparse.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/lmgr.h"
|
|
#include "utils/date.h"
|
|
#include "utils/datetime.h"
|
|
*************** static TypeName *TableFuncTypeName(List
|
|
*** 184,190 ****
|
|
%type <node> stmt schema_stmt
|
|
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterFdwStmt
|
|
AlterForeignServerStmt AlterGroupStmt
|
|
! AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
|
|
AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
|
|
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
|
|
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
|
|
--- 185,191 ----
|
|
%type <node> stmt schema_stmt
|
|
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterFdwStmt
|
|
AlterForeignServerStmt AlterGroupStmt
|
|
! AlterObjectSchemaStmt AlterOwnerStmt AlterSecLabelStmt AlterSeqStmt AlterTableStmt
|
|
AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
|
|
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
|
|
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
|
|
*************** static TypeName *TableFuncTypeName(List
|
|
*** 401,406 ****
|
|
--- 402,409 ----
|
|
%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
|
|
%type <list> opt_check_option
|
|
|
|
+ %type <defelt> OptSecLabel SecLabelItem
|
|
+
|
|
%type <target> xml_attribute_el
|
|
%type <list> xml_attribute_list xml_attributes
|
|
%type <node> xml_root_version opt_xml_root_standalone
|
|
*************** stmt :
|
|
*** 607,612 ****
|
|
--- 610,616 ----
|
|
| AlterGroupStmt
|
|
| AlterObjectSchemaStmt
|
|
| AlterOwnerStmt
|
|
+ | AlterSecLabelStmt
|
|
| AlterSeqStmt
|
|
| AlterTableStmt
|
|
| AlterRoleSetStmt
|
|
*************** DropGroupStmt:
|
|
*** 1041,1047 ****
|
|
*****************************************************************************/
|
|
|
|
CreateSchemaStmt:
|
|
! CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
|
|
{
|
|
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
|
|
/* One can omit the schema name or the authorization id. */
|
|
--- 1045,1051 ----
|
|
*****************************************************************************/
|
|
|
|
CreateSchemaStmt:
|
|
! CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSecLabel OptSchemaEltList
|
|
{
|
|
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
|
|
/* One can omit the schema name or the authorization id. */
|
|
*************** CreateSchemaStmt:
|
|
*** 1050,1065 ****
|
|
else
|
|
n->schemaname = $5;
|
|
n->authid = $5;
|
|
! n->schemaElts = $6;
|
|
$$ = (Node *)n;
|
|
}
|
|
! | CREATE SCHEMA ColId OptSchemaEltList
|
|
{
|
|
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
|
|
/* ...but not both */
|
|
n->schemaname = $3;
|
|
n->authid = NULL;
|
|
! n->schemaElts = $4;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
--- 1054,1071 ----
|
|
else
|
|
n->schemaname = $5;
|
|
n->authid = $5;
|
|
! n->secLabel = (Node *)$6;
|
|
! n->schemaElts = $7;
|
|
$$ = (Node *)n;
|
|
}
|
|
! | CREATE SCHEMA ColId OptSecLabel OptSchemaEltList
|
|
{
|
|
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
|
|
/* ...but not both */
|
|
n->schemaname = $3;
|
|
n->authid = NULL;
|
|
! n->secLabel = (Node *)$4;
|
|
! n->schemaElts = $5;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
*************** opt_using:
|
|
*** 2036,2042 ****
|
|
*****************************************************************************/
|
|
|
|
CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
|
|
! OptInherit OptWith OnCommitOption OptTableSpace
|
|
{
|
|
CreateStmt *n = makeNode(CreateStmt);
|
|
$4->istemp = $2;
|
|
--- 2042,2048 ----
|
|
*****************************************************************************/
|
|
|
|
CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
|
|
! OptInherit OptWith OnCommitOption OptTableSpace OptSecLabel
|
|
{
|
|
CreateStmt *n = makeNode(CreateStmt);
|
|
$4->istemp = $2;
|
|
*************** CreateStmt: CREATE OptTemp TABLE qualifi
|
|
*** 2047,2056 ****
|
|
n->options = $9;
|
|
n->oncommit = $10;
|
|
n->tablespacename = $11;
|
|
$$ = (Node *)n;
|
|
}
|
|
| CREATE OptTemp TABLE qualified_name OF qualified_name
|
|
! '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace
|
|
{
|
|
/* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
|
|
* by our inheritance capabilities. Let's try it...
|
|
--- 2053,2063 ----
|
|
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 OptSecLabel
|
|
{
|
|
/* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
|
|
* by our inheritance capabilities. Let's try it...
|
|
*************** CreateStmt: CREATE OptTemp TABLE qualifi
|
|
*** 2064,2069 ****
|
|
--- 2071,2077 ----
|
|
n->options = $10;
|
|
n->oncommit = $11;
|
|
n->tablespacename = $12;
|
|
+ n->secLabel = (Node *) $13;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
*************** TableElement:
|
|
*** 2106,2118 ****
|
|
| TableConstraint { $$ = $1; }
|
|
;
|
|
|
|
! columnDef: ColId Typename ColQualList
|
|
{
|
|
ColumnDef *n = makeNode(ColumnDef);
|
|
n->colname = $1;
|
|
n->typename = $2;
|
|
n->constraints = $3;
|
|
n->is_local = true;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
--- 2114,2127 ----
|
|
| TableConstraint { $$ = $1; }
|
|
;
|
|
|
|
! columnDef: ColId Typename ColQualList OptSecLabel
|
|
{
|
|
ColumnDef *n = makeNode(ColumnDef);
|
|
n->colname = $1;
|
|
n->typename = $2;
|
|
n->constraints = $3;
|
|
n->is_local = true;
|
|
+ n->secLabel = (Node *) $4;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
*************** opt_with_data:
|
|
*** 2584,2595 ****
|
|
*****************************************************************************/
|
|
|
|
CreateSeqStmt:
|
|
! CREATE OptTemp SEQUENCE qualified_name OptSeqOptList
|
|
{
|
|
CreateSeqStmt *n = makeNode(CreateSeqStmt);
|
|
$4->istemp = $2;
|
|
n->sequence = $4;
|
|
n->options = $5;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
--- 2593,2605 ----
|
|
*****************************************************************************/
|
|
|
|
CreateSeqStmt:
|
|
! CREATE OptTemp SEQUENCE qualified_name OptSeqOptList OptSecLabel
|
|
{
|
|
CreateSeqStmt *n = makeNode(CreateSeqStmt);
|
|
$4->istemp = $2;
|
|
n->sequence = $4;
|
|
n->options = $5;
|
|
+ n->secLabel = (Node *)$6;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
*************** createfunc_opt_item:
|
|
*** 4885,4890 ****
|
|
--- 4895,4904 ----
|
|
{
|
|
$$ = makeDefElem("window", (Node *)makeInteger(TRUE));
|
|
}
|
|
+ | SecLabelItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
| common_func_opt_item
|
|
{
|
|
$$ = $1;
|
|
*************** AlterOwnerStmt: ALTER AGGREGATE func_nam
|
|
*** 5591,5596 ****
|
|
--- 5605,5679 ----
|
|
}
|
|
;
|
|
|
|
+ /*****************************************************************************
|
|
+ *
|
|
+ * ALTER THING name SECURITY_LABEL [=] <newlabel>
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+
|
|
+ AlterSecLabelStmt: ALTER DATABASE database_name SecLabelItem
|
|
+ {
|
|
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
|
|
+ n->objectType = OBJECT_DATABASE;
|
|
+ n->object = list_make1(makeString($3));
|
|
+ n->secLabel = (Node *)$4;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
+ | ALTER SCHEMA name SecLabelItem
|
|
+ {
|
|
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
|
|
+ n->objectType = OBJECT_SCHEMA;
|
|
+ n->object = list_make1(makeString($3));
|
|
+ n->secLabel = (Node *)$4;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
+ | ALTER TABLE relation_expr SecLabelItem
|
|
+ {
|
|
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
|
|
+ n->objectType = OBJECT_TABLE;
|
|
+ n->relation = $3;
|
|
+ n->secLabel = (Node *)$4;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
+ | ALTER TABLE relation_expr ALTER opt_column ColId SecLabelItem
|
|
+ {
|
|
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
|
|
+ n->objectType = OBJECT_COLUMN;
|
|
+ n->relation = $3;
|
|
+ n->subname = $6;
|
|
+ n->secLabel = (Node *)$7;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
+ | ALTER SEQUENCE relation_expr SecLabelItem
|
|
+ {
|
|
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
|
|
+ n->objectType = OBJECT_SEQUENCE;
|
|
+ n->relation = $3;
|
|
+ n->secLabel = (Node *)$4;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
+ | ALTER FUNCTION function_with_argtypes SecLabelItem
|
|
+ {
|
|
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
|
|
+ n->objectType = OBJECT_FUNCTION;
|
|
+ n->object = $3->funcname;
|
|
+ n->objarg = $3->funcargs;
|
|
+ n->secLabel = (Node *)$4;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
+ ;
|
|
+
|
|
+ OptSecLabel: SecLabelItem { $$ = $1; }
|
|
+ | /* EMPTY */ { $$ = NULL; }
|
|
+ ;
|
|
+
|
|
+ SecLabelItem: IDENT opt_equal Sconst
|
|
+ {
|
|
+ if (strcmp("security_label", $1) != 0)
|
|
+ yyerror("syntax error");
|
|
+ $$ = makeDefElem($1, (Node *) makeString($3));
|
|
+ }
|
|
+ ;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
*************** createdb_opt_item:
|
|
*** 6033,6038 ****
|
|
--- 6116,6125 ----
|
|
{
|
|
$$ = makeDefElem("owner", NULL);
|
|
}
|
|
+ | SecLabelItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
;
|
|
|
|
/*
|
|
diff -Nrpc base/src/backend/parser/parse_target.c sepgsql/src/backend/parser/parse_target.c
|
|
*** base/src/backend/parser/parse_target.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/parser/parse_target.c Wed Jul 15 19:38:52 2009
|
|
***************
|
|
*** 14,19 ****
|
|
--- 14,20 ----
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
+ #include "catalog/heap.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "commands/dbcommands.h"
|
|
#include "funcapi.h"
|
|
*************** transformAssignedExpr(ParseState *pstate
|
|
*** 361,376 ****
|
|
Oid attrtype; /* type of target column */
|
|
int32 attrtypmod;
|
|
Relation rd = pstate->p_target_relation;
|
|
|
|
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 the expression is a DEFAULT placeholder, insert the attribute's
|
|
--- 362,394 ----
|
|
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)
|
|
! {
|
|
! attrtype = attnumTypeId(rd, attrno);
|
|
! attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
|
|
! }
|
|
! else
|
|
! {
|
|
! Form_pg_attribute attForm
|
|
! = SystemAttributeDefinition(attrno, relhasoids);
|
|
! if (attForm && SystemAttributeIsWritable(attrno))
|
|
! {
|
|
! attrtype = attForm->atttypid;
|
|
! attrtypmod = attForm->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
|
|
*************** updateTargetListEntry(ParseState *pstate
|
|
*** 515,520 ****
|
|
--- 533,541 ----
|
|
*/
|
|
tle->resno = (AttrNumber) attrno;
|
|
tle->resname = colname;
|
|
+
|
|
+ if (SystemAttributeIsWritable(attrno))
|
|
+ tle->resjunk = true;
|
|
}
|
|
|
|
|
|
*************** checkInsertTargets(ParseState *pstate, L
|
|
*** 789,794 ****
|
|
--- 810,816 ----
|
|
Bitmapset *wholecols = NULL;
|
|
Bitmapset *partialcols = NULL;
|
|
ListCell *tl;
|
|
+ uint32 system_attrs = 0UL;
|
|
|
|
foreach(tl, cols)
|
|
{
|
|
*************** checkInsertTargets(ParseState *pstate, L
|
|
*** 797,810 ****
|
|
int attrno;
|
|
|
|
/* Lookup column name, ereport on failure */
|
|
! attrno = attnameAttNum(pstate->p_target_relation, name, false);
|
|
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)));
|
|
|
|
/*
|
|
* Check for duplicates, but only of whole columns --- we allow
|
|
--- 819,855 ----
|
|
int attrno;
|
|
|
|
/* Lookup column name, ereport on failure */
|
|
! attrno = attnameAttNum(pstate->p_target_relation, name, true);
|
|
if (attrno == InvalidAttrNumber)
|
|
+ {
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
errmsg("column \"%s\" of relation \"%s\" does not exist",
|
|
name,
|
|
RelationGetRelationName(pstate->p_target_relation)),
|
|
parser_errposition(pstate, col->location)));
|
|
+ }
|
|
+ else if (attrno < 0)
|
|
+ {
|
|
+ if (SystemAttributeIsWritable(attrno))
|
|
+ {
|
|
+ uint32 mask = (1<<(-attrno));
|
|
+
|
|
+ if ((system_attrs & mask) != 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_DUPLICATE_COLUMN),
|
|
+ errmsg("column \"%s\" specified more than once", name),
|
|
+ parser_errposition(pstate, col->location)));
|
|
+ system_attrs |= mask;
|
|
+ *attrnos = lappend_int(*attrnos, attrno);
|
|
+ continue;
|
|
+ }
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
+ errmsg("column \"%s\" of relation \"%s\" is system column",
|
|
+ name, RelationGetRelationName(pstate->p_target_relation)),
|
|
+ parser_errposition(pstate, col->location)));
|
|
+ }
|
|
|
|
/*
|
|
* Check for duplicates, but only of whole columns --- we allow
|
|
diff -Nrpc base/src/backend/postmaster/autovacuum.c sepgsql/src/backend/postmaster/autovacuum.c
|
|
*** base/src/backend/postmaster/autovacuum.c Fri Jun 19 13:40:37 2009
|
|
--- sepgsql/src/backend/postmaster/autovacuum.c Thu Jul 16 17:22:29 2009
|
|
*************** do_autovacuum(void)
|
|
*** 2004,2010 ****
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relid;
|
|
object.objectSubId = 0;
|
|
! performDeletion(&object, DROP_CASCADE);
|
|
}
|
|
else
|
|
{
|
|
--- 2004,2010 ----
|
|
object.classId = RelationRelationId;
|
|
object.objectId = relid;
|
|
object.objectSubId = 0;
|
|
! performDeletionNoPerms(&object, DROP_CASCADE);
|
|
}
|
|
else
|
|
{
|
|
diff -Nrpc base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmaster/postmaster.c
|
|
*** base/src/backend/postmaster/postmaster.c Tue Jun 30 01:26:47 2009
|
|
--- sepgsql/src/backend/postmaster/postmaster.c Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 108,113 ****
|
|
--- 108,114 ----
|
|
#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"
|
|
*************** static pid_t StartupPID = 0,
|
|
*** 209,215 ****
|
|
AutoVacPID = 0,
|
|
PgArchPID = 0,
|
|
PgStatPID = 0,
|
|
! SysLoggerPID = 0;
|
|
|
|
/* Startup/shutdown state */
|
|
#define NoShutdown 0
|
|
--- 210,217 ----
|
|
AutoVacPID = 0,
|
|
PgArchPID = 0,
|
|
PgStatPID = 0,
|
|
! SysLoggerPID = 0,
|
|
! sepgsqlWorkerPID = 0;
|
|
|
|
/* Startup/shutdown state */
|
|
#define NoShutdown 0
|
|
*************** ServerLoop(void)
|
|
*** 1393,1398 ****
|
|
--- 1395,1404 ----
|
|
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
|
|
*************** SIGHUP_handler(SIGNAL_ARGS)
|
|
*** 2002,2007 ****
|
|
--- 2008,2015 ----
|
|
signal_child(SysLoggerPID, SIGHUP);
|
|
if (PgStatPID != 0)
|
|
signal_child(PgStatPID, SIGHUP);
|
|
+ if (sepgsqlWorkerPID != 0)
|
|
+ signal_child(sepgsqlWorkerPID, SIGHUP);
|
|
|
|
/* Reload authentication config files too */
|
|
if (!load_hba())
|
|
*************** pmdie(SIGNAL_ARGS)
|
|
*** 2062,2067 ****
|
|
--- 2070,2078 ----
|
|
/* 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_BACKUP;
|
|
}
|
|
|
|
*************** pmdie(SIGNAL_ARGS)
|
|
*** 2108,2113 ****
|
|
--- 2119,2127 ----
|
|
/* and the walwriter too */
|
|
if (WalWriterPID != 0)
|
|
signal_child(WalWriterPID, SIGTERM);
|
|
+ /* and the sepgsqlWorker too */
|
|
+ if (sepgsqlWorkerPID != 0)
|
|
+ signal_child(sepgsqlWorkerPID, SIGTERM);
|
|
pmState = PM_WAIT_BACKENDS;
|
|
}
|
|
|
|
*************** pmdie(SIGNAL_ARGS)
|
|
*** 2141,2146 ****
|
|
--- 2155,2162 ----
|
|
signal_child(PgArchPID, SIGQUIT);
|
|
if (PgStatPID != 0)
|
|
signal_child(PgStatPID, SIGQUIT);
|
|
+ if (sepgsqlWorkerPID != 0)
|
|
+ signal_child(sepgsqlWorkerPID, SIGQUIT);
|
|
ExitPostmaster(0);
|
|
break;
|
|
}
|
|
*************** reaper(SIGNAL_ARGS)
|
|
*** 2403,2408 ****
|
|
--- 2419,2434 ----
|
|
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.
|
|
*/
|
|
*************** HandleChildCrash(int pid, int exitstatus
|
|
*** 2594,2599 ****
|
|
--- 2620,2637 ----
|
|
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
|
|
*************** PostmasterStateMachine(void)
|
|
*** 2726,2732 ****
|
|
StartupPID == 0 &&
|
|
(BgWriterPID == 0 || !FatalError) &&
|
|
WalWriterPID == 0 &&
|
|
! AutoVacPID == 0)
|
|
{
|
|
if (FatalError)
|
|
{
|
|
--- 2764,2771 ----
|
|
StartupPID == 0 &&
|
|
(BgWriterPID == 0 || !FatalError) &&
|
|
WalWriterPID == 0 &&
|
|
! AutoVacPID == 0 &&
|
|
! sepgsqlWorkerPID == 0)
|
|
{
|
|
if (FatalError)
|
|
{
|
|
diff -Nrpc base/src/backend/security/Makefile sepgsql/src/backend/security/Makefile
|
|
*** base/src/backend/security/Makefile Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/Makefile Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,13 ----
|
|
+ #
|
|
+ # Makefile for the enhanced security subsystem
|
|
+ #
|
|
+
|
|
+ subdir = src/backend/security
|
|
+ top_builddir = ../../..
|
|
+ include $(top_builddir)/src/Makefile.global
|
|
+
|
|
+ SUBDIRS = sepgsql
|
|
+
|
|
+ OBJS = rowlevel.o
|
|
+
|
|
+ include $(top_srcdir)/src/backend/common.mk
|
|
diff -Nrpc base/src/backend/security/rowlevel.c sepgsql/src/backend/security/rowlevel.c
|
|
*** base/src/backend/security/rowlevel.c Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/rowlevel.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,121 ----
|
|
+ /*
|
|
+ * 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 "catalog/pg_security.h"
|
|
+ #include "security/rowlevel.h"
|
|
+ #include "security/sepgsql.h"
|
|
+ #include "storage/bufmgr.h"
|
|
+ #include "storage/bufpage.h"
|
|
+ #include "utils/rel.h"
|
|
+ #include "utils/tqual.h"
|
|
+
|
|
+ /*
|
|
+ * rowlvGetPerformingMode
|
|
+ * rowlvSetPerformingMode
|
|
+ * enables to control the behavior of row-level features
|
|
+ * when violated tuples are detected.
|
|
+ * The default is ROWLV_FILTER_MODE which filters out
|
|
+ * violated tuples from result set, ROWLV_ABORT_MODE
|
|
+ * raises an error and ROWLV_BYPASS_MODE do nothing.
|
|
+ */
|
|
+ static int rowlv_mode = ROWLV_FILTER_MODE;
|
|
+
|
|
+ int rowlvGetPerformingMode(void)
|
|
+ {
|
|
+ return rowlv_mode;
|
|
+ }
|
|
+
|
|
+ int rowlvSetPerformingMode(int new_mode)
|
|
+ {
|
|
+ int old_mode = new_mode;
|
|
+
|
|
+ rowlv_mode = new_mode;
|
|
+
|
|
+ return old_mode;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * rowlvSetupPermissions
|
|
+ * setups permissions for row-level access controls.
|
|
+ */
|
|
+ uint32
|
|
+ rowlvSetupPermissions(RangeTblEntry *rte)
|
|
+ {
|
|
+ return sepgsqlSetupTuplePerms(rte);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * rowlvExecScan
|
|
+ * a hook to filter out invisible/untouchable tuples.
|
|
+ */
|
|
+ static bool
|
|
+ rowlvExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ uint32 perms = scan->rowlvPerms;
|
|
+
|
|
+ if (!perms)
|
|
+ return true;
|
|
+
|
|
+ tuple = ExecMaterializeSlot(slot);
|
|
+
|
|
+ return sepgsqlExecScan(rel, tuple, perms, abort);
|
|
+ }
|
|
+
|
|
+ bool
|
|
+ rowlvExecScanFilter(Scan *scan, Relation rel, TupleTableSlot *slot)
|
|
+ {
|
|
+ if (!rel || !scan->rowlvPerms || rowlv_mode != ROWLV_FILTER_MODE)
|
|
+ return true;
|
|
+
|
|
+ return rowlvExecScan(scan, rel, slot, false);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ rowlvExecScanAbort(Scan *scan, Relation rel, TupleTableSlot *slot)
|
|
+ {
|
|
+ if (!rel || !scan->rowlvPerms || rowlv_mode != ROWLV_ABORT_MODE)
|
|
+ return;
|
|
+
|
|
+ rowlvExecScan(scan, rel, slot, true);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * rowlvCopyToTuple
|
|
+ * checks permission on fetched tuple
|
|
+ */
|
|
+ bool
|
|
+ rowlvCopyToTuple(Relation rel, HeapTuple tuple)
|
|
+ {
|
|
+ if (!sepgsqlExecScan(rel, tuple, SEPG_DB_TUPLE__SELECT, false))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * rowlvHeapTupleInsert
|
|
+ * assign default security attribute, and check permission
|
|
+ * if necessary.
|
|
+ */
|
|
+ void
|
|
+ rowlvHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal)
|
|
+ {
|
|
+ sepgsqlHeapTupleInsert(rel, newtup, internal);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * rowlvHeapTupleUpdate
|
|
+ * check permission to change security attribute, if necesary
|
|
+ */
|
|
+ void
|
|
+ rowlvHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup)
|
|
+ {
|
|
+ sepgsqlHeapTupleUpdate(rel, otid, newtup);
|
|
+ }
|
|
diff -Nrpc base/src/backend/security/sepgsql/Makefile sepgsql/src/backend/security/sepgsql/Makefile
|
|
*** base/src/backend/security/sepgsql/Makefile Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/Makefile Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,16 ----
|
|
+ #
|
|
+ # Makefile
|
|
+ # Makefile for utils/sepgsql : SE-PostgreSQL
|
|
+ #
|
|
+
|
|
+ subdir = src/backend/security/sepgsql
|
|
+ top_builddir = ../../../..
|
|
+ include $(top_builddir)/src/Makefile.global
|
|
+
|
|
+ ifeq ($(enable_selinux), yes)
|
|
+ OBJS = avc.o checker.o hooks.o label.o misc.o perms.o
|
|
+ else
|
|
+ OBJS = dummy.o
|
|
+ endif
|
|
+
|
|
+ include $(top_srcdir)/src/backend/common.mk
|
|
diff -Nrpc base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security/sepgsql/avc.c
|
|
*** base/src/backend/security/sepgsql/avc.c Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/avc.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,889 ----
|
|
+ /*
|
|
+ * 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 "miscadmin.h"
|
|
+ #include "postmaster/postmaster.h"
|
|
+ #include "security/sepgsql.h"
|
|
+ #include "storage/ipc.h"
|
|
+ #include "storage/lwlock.h"
|
|
+ #include "utils/memutils.h"
|
|
+ #include <signal.h>
|
|
+ #include <unistd.h>
|
|
+ #include <selinux/avc.h>
|
|
+
|
|
+ /*
|
|
+ * AVC: userspace access vector cache
|
|
+ *
|
|
+ * SE-PostgreSQL asks in-kernel SELinux to make its decision whether
|
|
+ * the required accesses should be allowed, or not, based on the unified
|
|
+ * security policy. It needs a system call invocation to communicate
|
|
+ * a kernel feature, such as SELinux, but it is a heavy task in most cases
|
|
+ * due to the context switching.
|
|
+ *
|
|
+ * The userspace avc enables to minimize the number of system call
|
|
+ * invocations, using a chache mechanim for the certain pair of security
|
|
+ * contexts and object classes (it means the kind of actions).
|
|
+ * It enables to hold recently fetched results from the in-kernel SELinux,
|
|
+ * and make a decision without context switching, if the cache hit.
|
|
+ *
|
|
+ * When the state of security policy is changed, the cached results
|
|
+ * shall to be invalidated. The state monitoring process launched by
|
|
+ * postmaster can receives the notification messages from the kernel
|
|
+ * space, and invalidate the current version of avc.
|
|
+ */
|
|
+ static MemoryContext AvcMemCtx;
|
|
+
|
|
+ #define AVC_HASH_NUM_SLOTS 256
|
|
+ #define AVC_HASH_NUM_NODES 180
|
|
+
|
|
+ typedef struct
|
|
+ {
|
|
+ Oid relid;
|
|
+ Oid secid;
|
|
+ } sepgsql_sid_t;
|
|
+
|
|
+ #define AVC_DATUM_NSID_SLOTS 19
|
|
+ typedef struct
|
|
+ {
|
|
+ uint32 hash_key;
|
|
+
|
|
+ security_class_t tclass;
|
|
+ sepgsql_sid_t tsid;
|
|
+ sepgsql_sid_t nsid[AVC_DATUM_NSID_SLOTS];
|
|
+
|
|
+ access_vector_t allowed;
|
|
+ access_vector_t decided;
|
|
+ access_vector_t auditallow;
|
|
+ access_vector_t auditdeny;
|
|
+
|
|
+ bool hot_cache;
|
|
+ bool permissive;
|
|
+
|
|
+ char ncontext[1];
|
|
+ } avc_datum;
|
|
+
|
|
+ typedef struct avc_page
|
|
+ {
|
|
+ struct avc_page *next;
|
|
+
|
|
+ security_context_t scontext;
|
|
+
|
|
+ List *slot[AVC_HASH_NUM_SLOTS];
|
|
+
|
|
+ uint32 avc_count;
|
|
+ uint32 lru_hint;
|
|
+ } avc_page;
|
|
+
|
|
+ static avc_page *current_page = NULL;
|
|
+
|
|
+ static int avc_version;
|
|
+
|
|
+ /*
|
|
+ * selinux_state
|
|
+ *
|
|
+ * It is deployed on the shared memory region, to show the system
|
|
+ * state of SELinux and its security policy.
|
|
+ *
|
|
+ * The selinux_state->version should be checked prior to avc accesses.
|
|
+ * If it does not match with the local avc_version, it means that
|
|
+ * system security policy was reloaded or system state (enforcing
|
|
+ * or permissive) was changed.
|
|
+ *
|
|
+ * The state monitoring worker process receives messages from the
|
|
+ * kernel using libselinux, and it updates the selinux_state.
|
|
+ */
|
|
+ struct
|
|
+ {
|
|
+ int version;
|
|
+
|
|
+ bool enforcing;
|
|
+
|
|
+ } *selinux_state = NULL;
|
|
+
|
|
+ Size
|
|
+ sepgsqlShmemSize(void)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return 0;
|
|
+
|
|
+ return sizeof(*selinux_state);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsql_shmem_init
|
|
+ * attaches shared memory segment.
|
|
+ */
|
|
+ static void
|
|
+ sepgsqlShmemInit(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);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlAvcCheckValid
|
|
+ *
|
|
+ * It checks whether the current AVC pages are valid, or not.
|
|
+ * If state monitoring process already received an invalidation
|
|
+ * message from the kernel, it clears current AVC pages and
|
|
+ * returns false.
|
|
+ */
|
|
+ static bool
|
|
+ sepgsqlAvcCheckValid(void)
|
|
+ {
|
|
+ bool result = true;
|
|
+
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
|
|
+ if (avc_version != selinux_state->version)
|
|
+ {
|
|
+ /* reset invalid avc pages, and makes an empty one */
|
|
+ MemoryContextReset(AvcMemCtx);
|
|
+
|
|
+ current_page = NULL;
|
|
+
|
|
+ sepgsqlAvcSwitchClient(sepgsqlGetClientLabel());
|
|
+
|
|
+ /* copy current version to local */
|
|
+ avc_version = selinux_state->version;
|
|
+
|
|
+ result = false;
|
|
+ }
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlAvcInitialize
|
|
+ *
|
|
+ * It allocates a memory context for userspace AVC,
|
|
+ * map shared memory segment, and initialize avc_page
|
|
+ * for the current client's privilege.
|
|
+ *
|
|
+ * If the current backend is not associated with a certain
|
|
+ * client process, it switches to permissive mode to avoid
|
|
+ * to prevent any internal processes.
|
|
+ */
|
|
+ void
|
|
+ sepgsqlAvcInitialize(void)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ /*
|
|
+ * local memory context
|
|
+ */
|
|
+ AvcMemCtx = AllocSetContextCreate(TopMemoryContext,
|
|
+ "SE-PostgreSQL userspace avc",
|
|
+ ALLOCSET_DEFAULT_MINSIZE,
|
|
+ ALLOCSET_DEFAULT_INITSIZE,
|
|
+ ALLOCSET_DEFAULT_MAXSIZE);
|
|
+ sepgsqlShmemInit();
|
|
+
|
|
+ /*
|
|
+ * Switch to local permissive mode
|
|
+ */
|
|
+ if (!MyProcPort)
|
|
+ sepgsqlSetEnforce(0);
|
|
+
|
|
+ /*
|
|
+ * selinux_state->version is never negative value,
|
|
+ * so this call always reset local avc.
|
|
+ */
|
|
+ avc_version = -1;
|
|
+ sepgsqlAvcCheckValid();
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlGetEnforce
|
|
+ * sepgsqlSetEnforce
|
|
+ *
|
|
+ * SELinux has two working mode called Enforcing/Permissive.
|
|
+ * In enforcing mode, it checks security policy and actually
|
|
+ * applies its access controls. In permissive mode, it also
|
|
+ * checks security policy, but does not apply any access
|
|
+ * controls. It is used to collect access denied logs to
|
|
+ * debug security policy.
|
|
+ *
|
|
+ * sepgsqlGetEnforce() returns the current working mode, and
|
|
+ * sepgsqlSetEnforce() switches the current working mode
|
|
+ * temporary. When we switches the mode, any errors have to
|
|
+ * be acquired, and it should be restored correctly.
|
|
+ */
|
|
+ static int local_enforce = -1; /* undefined */
|
|
+
|
|
+ bool
|
|
+ sepgsqlGetEnforce(void)
|
|
+ {
|
|
+ bool rc;
|
|
+
|
|
+ if (local_enforce < 0)
|
|
+ {
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
|
|
+ rc = selinux_state->enforcing;
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return (local_enforce > 0 ? true : false);
|
|
+ }
|
|
+
|
|
+ int
|
|
+ sepgsqlSetEnforce(int new_mode)
|
|
+ {
|
|
+ int old_mode = local_enforce;
|
|
+
|
|
+ local_enforce = new_mode;
|
|
+
|
|
+ return old_mode;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlAvcAudit
|
|
+ *
|
|
+ * It write out audit message, when auditdeny or auditallow
|
|
+ * matches the required permission bits.
|
|
+ * If external module support sepgsqlAvcAuditHook, it allows
|
|
+ * to write audit logs to external log manager, such as system
|
|
+ * auditd.
|
|
+ */
|
|
+
|
|
+ PGDLLIMPORT sepgsqlAvcAuditHook_t sepgsqlAvcAuditHook = NULL;
|
|
+
|
|
+ static void
|
|
+ sepgsqlAvcAudit(bool denied, char *scontext, char *tcontext,
|
|
+ uint16 tclass, uint32 audited, const char *audit_name)
|
|
+ {
|
|
+ StringInfoData buf;
|
|
+ uint32 mask;
|
|
+ const char *tclass_name;
|
|
+
|
|
+ /* translate to human readable form */
|
|
+ scontext = sepgsqlTransSecLabelOut(scontext);
|
|
+ tcontext = sepgsqlTransSecLabelOut(tcontext);
|
|
+
|
|
+ /* permissions in text representation */
|
|
+ initStringInfo(&buf);
|
|
+ appendStringInfo(&buf, "{");
|
|
+ for (mask = 1; audited != 0; mask <<= 1)
|
|
+ {
|
|
+ if (audited & mask)
|
|
+ appendStringInfo(&buf, " %s", sepgsqlGetPermString(tclass, mask));
|
|
+
|
|
+ audited &= ~mask;
|
|
+ }
|
|
+ appendStringInfo(&buf, " }");
|
|
+
|
|
+ tclass_name = sepgsqlGetClassString(tclass);
|
|
+
|
|
+ /* call external audit module, if loaded */
|
|
+ if (sepgsqlAvcAuditHook)
|
|
+ (*sepgsqlAvcAuditHook) (denied, scontext, tcontext,
|
|
+ tclass_name, buf.data, audit_name);
|
|
+ else
|
|
+ {
|
|
+ appendStringInfo(&buf, " scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext, tclass_name);
|
|
+ if (audit_name)
|
|
+ appendStringInfo(&buf, " name=%s", audit_name);
|
|
+
|
|
+ ereport(LOG,
|
|
+ (errcode(ERRCODE_SELINUX_AUDIT),
|
|
+ errmsg("SELinux: %s %s",
|
|
+ denied ? "denied" : "granted", buf.data)));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlAvcReclaim
|
|
+ *
|
|
+ * It wipes recently unused AVC entries, when the number of entries
|
|
+ * reaches AVC_HASH_NUM_NODES..
|
|
+ */
|
|
+ static void
|
|
+ sepgsqlAvcReclaim(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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlAvcMakeEntry
|
|
+ *
|
|
+ * It makes a new AVC entry and insert it on the avc_page.
|
|
+ * If is hold more than AVC_HASH_NUM_NODES entries, recently unused
|
|
+ * avc_datum shall be reclaimed.
|
|
+ */
|
|
+ #define avc_hash_key(trelid,tsecid,tclass) \
|
|
+ (hash_uint32((trelid) ^ (tsecid) ^ ((tclass) << 3)))
|
|
+
|
|
+ static avc_datum *
|
|
+ sepgsqlAvcMakeEntry(avc_page *page, Oid relid, Oid secid, uint16 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(relid, secid, tclass);
|
|
+ index = hash_key % AVC_HASH_NUM_SLOTS;
|
|
+
|
|
+ scontext = page->scontext;
|
|
+ tcontext = securityRawSecLabelOut(relid, secid);
|
|
+
|
|
+ /*
|
|
+ * Compute SELinux permission
|
|
+ */
|
|
+ tclass_ex = sepgsqlTransToExternalClass(tclass);
|
|
+ if (tclass_ex > 0)
|
|
+ {
|
|
+ if (security_compute_av_flags_raw(scontext, tcontext,
|
|
+ tclass_ex, 0, &avd) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: unable to compute av_decision: "
|
|
+ "scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext,
|
|
+ sepgsqlGetClassString(tclass))));
|
|
+ sepgsqlTransToInternalPerms(tclass, &avd);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* fill it up as undefined class */
|
|
+ avd.allowed = (security_deny_unknown() ? 0 : ~0UL);
|
|
+ avd.decided = ~0UL;
|
|
+ avd.auditallow = 0UL;
|
|
+ avd.auditdeny = ~0UL;
|
|
+ avd.flags = 0;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Compute New security context
|
|
+ */
|
|
+ if (security_compute_create_raw(scontext, tcontext,
|
|
+ tclass_ex, &ncontext) < 0)
|
|
+ {
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: unable to compute new context: "
|
|
+ "scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext, sepgsqlGetClassString(tclass))));
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Copy them to avc_datum
|
|
+ */
|
|
+ oldctx = MemoryContextSwitchTo(AvcMemCtx);
|
|
+ PG_TRY();
|
|
+ {
|
|
+ cache = palloc0(sizeof(avc_datum) + strlen(ncontext));
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(ncontext);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ cache->hash_key = hash_key;
|
|
+ cache->tclass = tclass;
|
|
+ cache->tsid.relid = relid;
|
|
+ cache->tsid.secid = secid;
|
|
+ /* cache->nsid shall be set later */
|
|
+
|
|
+ cache->allowed = avd.allowed;
|
|
+ cache->decided = avd.decided;
|
|
+ cache->auditallow = avd.auditallow;
|
|
+ cache->auditdeny = avd.auditdeny;
|
|
+
|
|
+ cache->hot_cache = true;
|
|
+ if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE)
|
|
+ cache->permissive = true;
|
|
+ strcpy(cache->ncontext, ncontext);
|
|
+ freecon(ncontext);
|
|
+
|
|
+ sepgsqlAvcReclaim(page);
|
|
+
|
|
+ page->slot[index] = lcons(cache, page->slot[index]);
|
|
+ page->avc_count++;
|
|
+
|
|
+ MemoryContextSwitchTo(oldctx);
|
|
+
|
|
+ return cache;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlAvcLookup
|
|
+ *
|
|
+ * It lookups required AVC entry.
|
|
+ */
|
|
+ static avc_datum *
|
|
+ sepgsqlAvcLookup(avc_page *page, Oid trelid, Oid tsecid, uint16 tclass)
|
|
+ {
|
|
+ avc_datum *cache = NULL;
|
|
+ uint32 hash_key, index;
|
|
+ ListCell *l;
|
|
+
|
|
+ hash_key = avc_hash_key(trelid, tsecid, 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.relid == trelid
|
|
+ && cache->tsid.secid == tsecid)
|
|
+ {
|
|
+ cache->hot_cache = true;
|
|
+ return cache;
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlAvcSwitchClientLabel()
|
|
+ *
|
|
+ * It switches the current avc_page.
|
|
+ * An avc_page is a set of cached access control decisions associated
|
|
+ * with a certain privilege of the client. This structure enables to
|
|
+ * lookup required avc_datum without any comparison to the subject
|
|
+ * label.
|
|
+ */
|
|
+ void
|
|
+ sepgsqlAvcSwitchClient(const char *scontext)
|
|
+ {
|
|
+ MemoryContext oldctx;
|
|
+ avc_page *new_page;
|
|
+ int i;
|
|
+
|
|
+ if (current_page)
|
|
+ {
|
|
+ new_page = current_page;
|
|
+ do {
|
|
+ if (strcmp(new_page->scontext, scontext) == 0)
|
|
+ {
|
|
+ current_page = new_page;
|
|
+ return;
|
|
+ }
|
|
+ new_page = new_page->next;
|
|
+ } while (new_page != current_page);
|
|
+ }
|
|
+
|
|
+ /* Not found, 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;
|
|
+
|
|
+ if (!current_page)
|
|
+ new_page->next = new_page;
|
|
+ else
|
|
+ {
|
|
+ new_page->next = current_page->next;
|
|
+ current_page->next = new_page;
|
|
+ }
|
|
+
|
|
+ current_page = new_page;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlClientHasPerms
|
|
+ * checks client's privileges on given objects via uAVC.
|
|
+ */
|
|
+ bool
|
|
+ sepgsqlClientHasPermsSid(Oid relid, Oid secid,
|
|
+ uint16 tclass, uint32 required,
|
|
+ const char *audit_name, bool abort)
|
|
+ {
|
|
+ avc_datum *cache;
|
|
+ uint32 denied, audited;
|
|
+ bool result = true;
|
|
+
|
|
+ Assert(required != 0);
|
|
+
|
|
+ do {
|
|
+ cache = sepgsqlAvcLookup(current_page, relid, secid, tclass);
|
|
+ if (!cache)
|
|
+ cache = sepgsqlAvcMakeEntry(current_page, relid, secid, tclass);
|
|
+ } while (!sepgsqlAvcCheckValid());
|
|
+
|
|
+ denied = required & ~cache->allowed;
|
|
+ audited = denied ? (denied & cache->auditdeny)
|
|
+ : (required & cache->auditallow);
|
|
+ if (audited)
|
|
+ {
|
|
+ sepgsqlAvcAudit(!!denied,
|
|
+ current_page->scontext,
|
|
+ securityRawSecLabelOut(relid, secid),
|
|
+ cache->tclass, audited, audit_name);
|
|
+ }
|
|
+
|
|
+ if (denied)
|
|
+ {
|
|
+ if (!sepgsqlGetEnforce() || cache->permissive)
|
|
+ cache->allowed |= required; /* prevent flood of audit log */
|
|
+ else
|
|
+ {
|
|
+ if (abort)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: security policy violation")));
|
|
+ result = false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ bool
|
|
+ sepgsqlClientHasPermsTup(Oid relid, HeapTuple tuple,
|
|
+ uint16 tclass, uint32 required, bool abort)
|
|
+ {
|
|
+ const char *audit_name = sepgsqlAuditName(relid, tuple);
|
|
+
|
|
+ return sepgsqlClientHasPermsSid(relid, HeapTupleGetSecLabel(tuple),
|
|
+ tclass, required, audit_name, abort);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlClientCreateSecid
|
|
+ * sepgsqlClientCreateLabel
|
|
+ */
|
|
+ Oid
|
|
+ sepgsqlClientCreateSecid(Oid trelid, Oid tsecid, uint16 tclass, Oid nrelid)
|
|
+ {
|
|
+ avc_datum *cache;
|
|
+ int index;
|
|
+ Oid nsecid;
|
|
+
|
|
+ do {
|
|
+ cache = sepgsqlAvcLookup(current_page, trelid, tsecid, tclass);
|
|
+ if (!cache)
|
|
+ cache = sepgsqlAvcMakeEntry(current_page, trelid, tsecid, tclass);
|
|
+
|
|
+ index = (nrelid % AVC_DATUM_NSID_SLOTS);
|
|
+ if (cache->nsid[index].relid != nrelid)
|
|
+ {
|
|
+ cache->nsid[index].secid
|
|
+ = securityRawSecLabelIn(nrelid, cache->ncontext);
|
|
+ cache->nsid[index].relid = nrelid;
|
|
+ }
|
|
+ nsecid = cache->nsid[index].secid;
|
|
+ } while (!sepgsqlAvcCheckValid());
|
|
+
|
|
+ return nsecid;
|
|
+ }
|
|
+
|
|
+ security_context_t
|
|
+ sepgsqlClientCreateLabel(Oid trelid, Oid tsecid, uint16 tclass)
|
|
+ {
|
|
+ avc_datum *cache;
|
|
+
|
|
+ do {
|
|
+ cache = sepgsqlAvcLookup(current_page, trelid, tsecid, tclass);
|
|
+ if (!cache)
|
|
+ cache = sepgsqlAvcMakeEntry(current_page, trelid, tsecid, tclass);
|
|
+ } while (!sepgsqlAvcCheckValid());
|
|
+
|
|
+ return cache->ncontext;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 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(char *scontext, char *tcontext,
|
|
+ uint16 tclass_in, uint32 required,
|
|
+ const char *audit_name, bool abort)
|
|
+ {
|
|
+ access_vector_t denied, audited;
|
|
+ security_class_t tclass_ex;
|
|
+ struct av_decision avd;
|
|
+
|
|
+ Assert(required != 0);
|
|
+
|
|
+ tclass_ex = sepgsqlTransToExternalClass(tclass_in);
|
|
+ if (tclass_ex > 0)
|
|
+ {
|
|
+ /*
|
|
+ * security_compute_av_flags_raw() is a SELinux's API that
|
|
+ * returns its access control decision based on the security
|
|
+ * policy, to the given combination of user's privilege
|
|
+ * (scontext; security label of the client process),
|
|
+ * target's attribute (tcontext; security label of the
|
|
+ * object) and type of actions (tclass; object classes).
|
|
+ *
|
|
+ * The returned avd.allowed is a bitmap of allowed actions.
|
|
+ */
|
|
+ if (security_compute_av_flags_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_in))));
|
|
+ sepgsqlTransToInternalPerms(tclass_in, &avd);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /*
|
|
+ * If security policy does not support database related
|
|
+ * permissions, it fulls up permission bits by dummy
|
|
+ * data.
|
|
+ * If security_deny_unknown() returns positive value,
|
|
+ * undefined permissions should not be allowed.
|
|
+ * Otherwise, it shall be allowed.
|
|
+ */
|
|
+ avd.allowed = (security_deny_unknown() > 0 ? 0 : ~0UL);
|
|
+ avd.decided = ~0UL;
|
|
+ avd.auditallow = 0UL;
|
|
+ avd.auditdeny = ~0UL;
|
|
+ avd.flags = 0;
|
|
+ }
|
|
+
|
|
+ denied = required & ~avd.allowed;
|
|
+ audited = denied ? (denied & avd.auditdeny)
|
|
+ : (required & avd.auditallow);
|
|
+ if (audited)
|
|
+ {
|
|
+ /*
|
|
+ * If security policy requires to generate an audit log
|
|
+ * record for the given request, it should be logged.
|
|
+ */
|
|
+ sepgsqlAvcAudit(!!denied, scontext, tcontext,
|
|
+ tclass_in, audited, audit_name);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * If any required permissions are not allowed, and
|
|
+ * SE-PgSQL performs in enforcing mode, and the given
|
|
+ * combination of subject, object and action does not
|
|
+ * have special flag to be handled as permission,
|
|
+ * SE-PgSQL returns false or raises an error.
|
|
+ * Otherwise, it returns true that means required
|
|
+ * actions are allowed.
|
|
+ */
|
|
+ if (!denied || /* no policy violation */
|
|
+ !sepgsqlGetEnforce() || /* permissive mode */
|
|
+ (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) != 0) /* permissive domain */
|
|
+ return true;
|
|
+
|
|
+ if (abort)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: security policy violation")));
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ char *
|
|
+ sepgsqlComputeCreate(char *scontext, char *tcontext, uint16 tclass_in)
|
|
+ {
|
|
+ security_context_t ncontext, result;
|
|
+ security_class_t tclass_ex;
|
|
+
|
|
+ tclass_ex = sepgsqlTransToExternalClass(tclass_in);
|
|
+ /*
|
|
+ * security_compute_create_raw() is a SELinux's API that
|
|
+ * returns a default security context to be assigned on
|
|
+ * a new object (categorized by object class) when a client
|
|
+ * labeled as scontext tries to create a new one under the
|
|
+ * parent object labeled as tcontext.
|
|
+ */
|
|
+ if (security_compute_create_raw(scontext, tcontext,
|
|
+ tclass_ex, &ncontext) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: could not compute a new context "
|
|
+ "scontext=%s tcontext=%s tclass=%s",
|
|
+ scontext, tcontext, sepgsqlGetClassString(tclass_in))));
|
|
+ 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
|
|
+ sepgsql_cb_log(int type, const char *fmt, ...)
|
|
+ {
|
|
+ char *c, buffer[1024];
|
|
+ va_list ap;
|
|
+
|
|
+ va_start(ap, fmt);
|
|
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
|
+ va_end(ap);
|
|
+
|
|
+ c = strrchr(buffer, '\n');
|
|
+ if (c)
|
|
+ *c = '\0';
|
|
+
|
|
+ ereport(LOG,
|
|
+ (errcode(ERRCODE_SELINUX_INFO),
|
|
+ errmsg("%s", buffer)));
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ static int
|
|
+ sepgsql_cb_setenforce(int enforce)
|
|
+ {
|
|
+ /* switch enforcing/permissive */
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
|
|
+ selinux_state->version = selinux_state->version + 1;
|
|
+ selinux_state->enforcing = (enforce ? true : false);
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ static int
|
|
+ sepgsql_cb_policyload(int seqno)
|
|
+ {
|
|
+ /* invalidate local avc */
|
|
+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
|
|
+ selinux_state->version = selinux_state->version + 1;
|
|
+ LWLockRelease(SepgsqlAvcLock);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ static int
|
|
+ sepgsqlWorkerMain(void)
|
|
+ {
|
|
+ union selinux_callback cb;
|
|
+
|
|
+ ClosePostmasterPorts(false);
|
|
+
|
|
+ on_exit_reset();
|
|
+
|
|
+ /*
|
|
+ * map shared memory segment
|
|
+ */
|
|
+ sepgsqlShmemInit();
|
|
+
|
|
+ /*
|
|
+ * 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(LOG,
|
|
+ (errcode(ERRCODE_SELINUX_INFO),
|
|
+ errmsg("SELinux: security policy monitor (pid=%u)", getpid())));
|
|
+ /*
|
|
+ * setup callback functions from avc_netlink_loop()
|
|
+ */
|
|
+ cb.func_log = sepgsql_cb_log;
|
|
+ selinux_set_callback(SELINUX_CB_LOG, cb);
|
|
+ cb.func_setenforce = sepgsql_cb_setenforce;
|
|
+ selinux_set_callback(SELINUX_CB_SETENFORCE, cb);
|
|
+ cb.func_policyload = sepgsql_cb_policyload;
|
|
+ selinux_set_callback(SELINUX_CB_POLICYLOAD, cb);
|
|
+
|
|
+ /*
|
|
+ * open netlink socket and wait for messages
|
|
+ */
|
|
+ avc_netlink_open(1);
|
|
+
|
|
+ avc_netlink_loop();
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ pid_t
|
|
+ sepgsqlStartupWorkerProcess(void)
|
|
+ {
|
|
+ pid_t chld;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return (pid_t) 0;
|
|
+
|
|
+ chld = fork();
|
|
+ if (chld == 0)
|
|
+ exit(sepgsqlWorkerMain());
|
|
+ else if (chld > 0)
|
|
+ return chld;
|
|
+
|
|
+ return (pid_t) 0;
|
|
+ }
|
|
diff -Nrpc base/src/backend/security/sepgsql/checker.c sepgsql/src/backend/security/sepgsql/checker.c
|
|
*** base/src/backend/security/sepgsql/checker.c Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/checker.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,420 ----
|
|
+ /*
|
|
+ * 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 "access/sysattr.h"
|
|
+ #include "catalog/catalog.h"
|
|
+ #include "miscadmin.h"
|
|
+ #include "security/sepgsql.h"
|
|
+ #include "storage/bufmgr.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;
|
|
+ security_class_t tclass;
|
|
+
|
|
+ /*
|
|
+ * Hardwired Policy:
|
|
+ * SE-PostgreSQL enforces that clients cannot modify system
|
|
+ * catalogs and access toast values using DML statements,
|
|
+ * except initial setting up phase.
|
|
+ */
|
|
+ if (sepgsqlGetEnforce())
|
|
+ {
|
|
+ if (IsSystemNamespace(get_rel_namespace(relid)) &&
|
|
+ (required & (SEPG_DB_TABLE__UPDATE |
|
|
+ SEPG_DB_TABLE__INSERT |
|
|
+ SEPG_DB_TABLE__DELETE)) != 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SE-PostgreSQL prevents to modidy \"%s\"",
|
|
+ get_rel_name(relid))));
|
|
+ if (get_rel_relkind(relid) == RELKIND_TOASTVALUE)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SE-PostgreSQL prevents to access \"%s\"",
|
|
+ get_rel_name(relid))));
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Check db_table:{...} or db_sequence permissions
|
|
+ */
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "SELinux: cache lookup failed for relation %u", relid);
|
|
+
|
|
+ tclass = sepgsqlTupleObjectClass(RelationRelationId, tuple);
|
|
+
|
|
+ if (tclass != SEPG_CLASS_DB_TABLE)
|
|
+ {
|
|
+ /* check db_sequence:{xxx} permission */
|
|
+ if (tclass == SEPG_CLASS_DB_SEQUENCE)
|
|
+ {
|
|
+ if (required & SEPG_DB_TABLE__SELECT)
|
|
+ {
|
|
+ sepgsqlClientHasPermsTup(RelationRelationId, tuple,
|
|
+ SEPG_CLASS_DB_SEQUENCE,
|
|
+ SEPG_DB_SEQUENCE__GET_VALUE,
|
|
+ true);
|
|
+ }
|
|
+ }
|
|
+ ReleaseSysCache(tuple);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ sepgsqlClientHasPermsTup(RelationRelationId, tuple,
|
|
+ SEPG_CLASS_DB_TABLE,
|
|
+ required, 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);
|
|
+
|
|
+ sepgsqlClientHasPermsTup(AttributeRelationId, tuple,
|
|
+ SEPG_CLASS_DB_COLUMN,
|
|
+ attperms, 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)
|
|
+ {
|
|
+ /*
|
|
+ * ACL_SELECT_FOR_UPDATE is defined as an aliase of ACL_UPDATE,
|
|
+ * so we cannot determine whether the given relation is accessed
|
|
+ * with UPDATE statement or SELECT FOR SHARE/UPDATE immediately.
|
|
+ * UPDATE statements set a bit on rte->modifiedCols at least,
|
|
+ * so we use it as a watermark.
|
|
+ */
|
|
+ if (!bms_is_empty(rte->modifiedCols))
|
|
+ required |= SEPG_DB_TABLE__UPDATE;
|
|
+ else
|
|
+ required |= SEPG_DB_TABLE__LOCK;
|
|
+ }
|
|
+ if (rte->requiredPerms & ACL_DELETE)
|
|
+ required |= SEPG_DB_TABLE__DELETE;
|
|
+
|
|
+ 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);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlExecScan
|
|
+ * makes a decision on the given tuple.
|
|
+ */
|
|
+ bool
|
|
+ sepgsqlExecScan(Relation rel, HeapTuple tuple, uint32 required, bool abort)
|
|
+ {
|
|
+ security_class_t tclass;
|
|
+
|
|
+ if (!sepgsqlIsEnabled() ||
|
|
+ !required ||
|
|
+ RelationGetForm(rel)->relkind != RELKIND_RELATION)
|
|
+ return true;
|
|
+
|
|
+ tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple);
|
|
+ return sepgsqlClientHasPermsTup(RelationGetRelid(rel), tuple,
|
|
+ tclass, required, abort);
|
|
+ }
|
|
+
|
|
+ uint32
|
|
+ sepgsqlSetupTuplePerms(RangeTblEntry *rte)
|
|
+ {
|
|
+ AclMode perms = 0;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return 0;
|
|
+
|
|
+ if (rte->rtekind != RTE_RELATION)
|
|
+ return 0;
|
|
+
|
|
+ if (rte->requiredPerms & ACL_SELECT)
|
|
+ perms |= SEPG_DB_TUPLE__SELECT;
|
|
+ if (rte->requiredPerms & ACL_UPDATE && !bms_is_empty(rte->modifiedCols))
|
|
+ perms |= SEPG_DB_TUPLE__UPDATE;
|
|
+ if (rte->requiredPerms & ACL_DELETE)
|
|
+ perms |= SEPG_DB_TUPLE__DELETE;
|
|
+
|
|
+ return perms;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlHeapTupleInsert
|
|
+ * It assigns a default security label, if no explicit security labels
|
|
+ * were given. In addition, it also checks db_tuple:{insert} for the
|
|
+ * tuple newly inserted, when it invoked from user's query.
|
|
+ */
|
|
+ void
|
|
+ sepgsqlHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal)
|
|
+ {
|
|
+ security_class_t tclass;
|
|
+ Oid relid = RelationGetRelid(rel);
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ /*
|
|
+ * assigns a default security label, if not explicit one
|
|
+ */
|
|
+ if (!OidIsValid(HeapTupleGetSecLabel(newtup)))
|
|
+ {
|
|
+ if (HeapTupleHasSecLabel(newtup))
|
|
+ sepgsqlSetDefaultSecLabel(rel, newtup);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * It does not check permission for the new tuples
|
|
+ * inserted by system internal stuff using
|
|
+ * simple_heap_insert();
|
|
+ */
|
|
+ if (internal)
|
|
+ return;
|
|
+
|
|
+ tclass = sepgsqlTupleObjectClass(relid, newtup);
|
|
+ sepgsqlClientHasPermsTup(relid, newtup, tclass,
|
|
+ SEPG_DB_TUPLE__INSERT, true);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlHeapTupleUpdate
|
|
+ * It checks db_tuple:{relabelfrom relabelto} permission on
|
|
+ * the user queries. (Please note that it does not check
|
|
+ * system internal stuff via simple_heap_update)
|
|
+ */
|
|
+ void
|
|
+ sepgsqlHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup)
|
|
+ {
|
|
+ Oid relid = RelationGetRelid(rel);
|
|
+ Oid secid;
|
|
+ HeapTupleData oldtup;
|
|
+ Buffer oldbuf;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ /*
|
|
+ * heap_update() preserves the original security label
|
|
+ * of the given tuple, if no explicit security label
|
|
+ * is assigned on the newer version.
|
|
+ * In this case, db_tuple:{update} is already checked
|
|
+ * at the sepgsqlExecScan() hook, so we don't need to
|
|
+ * check anything more.
|
|
+ */
|
|
+ secid = HeapTupleGetSecLabel(newtup);
|
|
+ if (!OidIsValid(secid))
|
|
+ return;
|
|
+
|
|
+ /*
|
|
+ * User gave an explicit security label
|
|
+ */
|
|
+ ItemPointerCopy(otid, &oldtup.t_self);
|
|
+ if (!heap_fetch(rel, SnapshotAny, &oldtup, &oldbuf, false, NULL))
|
|
+ elog(ERROR, "failed to fetch old version of the tuple");
|
|
+
|
|
+ if (secid != HeapTupleGetSecLabel(&oldtup))
|
|
+ {
|
|
+ security_class_t tclass
|
|
+ = sepgsqlTupleObjectClass(relid, newtup);
|
|
+
|
|
+ /* db_tuple:{relabelfrom} for older security label */
|
|
+ sepgsqlClientHasPermsTup(relid, &oldtup, tclass,
|
|
+ SEPG_DB_TUPLE__RELABELFROM, true);
|
|
+
|
|
+ /* db_tuple:{relabelto} for newer security label */
|
|
+ sepgsqlClientHasPermsTup(relid, newtup, tclass,
|
|
+ SEPG_DB_TUPLE__RELABELTO, true);
|
|
+ }
|
|
+ ReleaseBuffer(oldbuf);
|
|
+ }
|
|
diff -Nrpc base/src/backend/security/sepgsql/dummy.c sepgsql/src/backend/security/sepgsql/dummy.c
|
|
*** base/src/backend/security/sepgsql/dummy.c Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/dummy.c Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 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_server_getcon(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 -Nrpc base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/security/sepgsql/hooks.c
|
|
*** base/src/backend/security/sepgsql/hooks.c Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/hooks.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,1170 ----
|
|
+ /*
|
|
+ * 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 "catalog/indexing.h"
|
|
+ #include "catalog/namespace.h"
|
|
+ #include "catalog/pg_database.h"
|
|
+ #include "catalog/pg_foreign_data_wrapper.h"
|
|
+ #include "catalog/pg_language.h"
|
|
+ #include "catalog/pg_largeobject.h"
|
|
+ #include "catalog/pg_namespace.h"
|
|
+ #include "catalog/pg_opclass.h"
|
|
+ #include "catalog/pg_operator.h"
|
|
+ #include "catalog/pg_opfamily.h"
|
|
+ #include "catalog/pg_proc.h"
|
|
+ #include "catalog/pg_security.h"
|
|
+ #include "catalog/pg_trigger.h"
|
|
+ #include "catalog/pg_ts_dict.h"
|
|
+ #include "catalog/pg_ts_parser.h"
|
|
+ #include "catalog/pg_ts_template.h"
|
|
+ #include "catalog/pg_type.h"
|
|
+ #include "catalog/pg_security.h"
|
|
+ #include "commands/dbcommands.h"
|
|
+ #include "miscadmin.h"
|
|
+ #include "security/sepgsql.h"
|
|
+ #include "utils/builtins.h"
|
|
+ #include "utils/fmgroids.h"
|
|
+ #include "utils/lsyscache.h"
|
|
+ #include "utils/syscache.h"
|
|
+ #include "utils/tqual.h"
|
|
+
|
|
+ /*
|
|
+ * ------------------------------------------------------------
|
|
+ * Hooks corresponding to db_database object class
|
|
+ * ------------------------------------------------------------
|
|
+ *
|
|
+ * sepgsqlCheckDatabaseInstallModule
|
|
+ * checks db_database:{install_module} permission when the client
|
|
+ * tries to install a dynamic link library on the current databse.
|
|
+ *
|
|
+ * sepgsqlCheckDatabaseLoadModule
|
|
+ * checks capability of the database when it loads a certain DLL
|
|
+ * into its process address space.
|
|
+ */
|
|
+ Oid
|
|
+ sepgsqlCheckDatabaseCreate(const char *datname, DefElem *new_label)
|
|
+ {
|
|
+ Oid datsid;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return InvalidOid;
|
|
+
|
|
+ if (!new_label)
|
|
+ datsid = sepgsqlGetDefaultDatabaseSecLabel();
|
|
+ else
|
|
+ datsid = securityTransSecLabelIn(DatabaseRelationId,
|
|
+ strVal(new_label->arg));
|
|
+
|
|
+ sepgsqlClientHasPermsSid(DatabaseRelationId, datsid,
|
|
+ SEPG_CLASS_DB_DATABASE,
|
|
+ SEPG_DB_DATABASE__CREATE,
|
|
+ datname, true);
|
|
+ return datsid;
|
|
+ }
|
|
+
|
|
+ static bool
|
|
+ checkDatabaseCommon(Oid datoid, access_vector_t perms, bool abort)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ bool rc;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(datoid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for database: %u", datoid);
|
|
+
|
|
+ rc = sepgsqlClientHasPermsTup(DatabaseRelationId, tuple,
|
|
+ SEPG_CLASS_DB_DATABASE,
|
|
+ perms, abort);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckDatabaseDrop(Oid database_oid)
|
|
+ {
|
|
+ checkDatabaseCommon(database_oid,
|
|
+ SEPG_DB_DATABASE__DROP, true);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckDatabaseSetattr(Oid database_oid)
|
|
+ {
|
|
+ checkDatabaseCommon(database_oid,
|
|
+ SEPG_DB_DATABASE__SETATTR, true);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlCheckDatabaseRelabel(Oid database_oid, DefElem *new_label)
|
|
+ {
|
|
+ Oid datsid;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ {
|
|
+ if (new_label)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux is disabled now")));
|
|
+ return InvalidOid;
|
|
+ }
|
|
+ datsid = securityTransSecLabelIn(DatabaseRelationId,
|
|
+ strVal(new_label->arg));
|
|
+ /* db_database:{setattr relabelfrom} for older seclabel */
|
|
+ checkDatabaseCommon(database_oid,
|
|
+ SEPG_DB_DATABASE__SETATTR |
|
|
+ SEPG_DB_DATABASE__RELABELFROM, true);
|
|
+ /* db_database:{relabelto} for newer seclabel */
|
|
+ sepgsqlClientHasPermsSid(DatabaseRelationId, datsid,
|
|
+ SEPG_CLASS_DB_DATABASE,
|
|
+ SEPG_DB_DATABASE__RELABELTO,
|
|
+ get_database_name(database_oid), true);
|
|
+ return datsid;
|
|
+ }
|
|
+
|
|
+ bool
|
|
+ sepgsqlCheckDatabaseConnect(Oid database_oid)
|
|
+ {
|
|
+ return checkDatabaseCommon(database_oid,
|
|
+ SEPG_DB_DATABASE__CONNECT, false);
|
|
+ }
|
|
+
|
|
+ bool
|
|
+ sepgsqlCheckDatabaseSuperuser(void)
|
|
+ {
|
|
+ return checkDatabaseCommon(MyDatabaseId,
|
|
+ SEPG_DB_DATABASE__SUPERUSER, false);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckDatabaseInstallModule(const char *probin, HeapTuple protup)
|
|
+ {
|
|
+ Datum oldbin;
|
|
+ bool isnull;
|
|
+
|
|
+ if (HeapTupleIsValid(protup))
|
|
+ {
|
|
+ oldbin = SysCacheGetAttr(PROCOID, protup,
|
|
+ Anum_pg_proc_probin,
|
|
+ &isnull);
|
|
+ if (!isnull &&
|
|
+ strcmp(probin, TextDatumGetCString(oldbin)))
|
|
+ return; /* unchanged */
|
|
+ }
|
|
+ checkDatabaseCommon(MyDatabaseId,
|
|
+ SEPG_DB_DATABASE__INSTALL_MODULE, true);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckDatabaseLoadModule(const char *filename)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ security_context_t filecon;
|
|
+ security_context_t dbcon;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+ /*
|
|
+ * It assumes preloaded libraries are secure,
|
|
+ * because it can be set up using guc variable
|
|
+ * not any SQL statements.
|
|
+ */
|
|
+ if (GetProcessingMode() == InitProcessing)
|
|
+ return;
|
|
+
|
|
+ /* Get database context */
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for database: %u", MyDatabaseId);
|
|
+
|
|
+ dbcon = securityRawSecLabelOut(DatabaseRelationId,
|
|
+ HeapTupleGetSecLabel(tuple));
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ /* Get library context */
|
|
+ if (getfilecon_raw(filename, &filecon) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode_for_file_access(),
|
|
+ errmsg("could not access file \"%s\": %m", filename)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ sepgsqlComputePerms(dbcon,
|
|
+ filecon,
|
|
+ SEPG_CLASS_DB_DATABASE,
|
|
+ SEPG_DB_DATABASE__LOAD_MODULE,
|
|
+ filename, true);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(filecon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(filecon);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * ------------------------------------------------------------
|
|
+ * Hooks corresponding to db_schema object class
|
|
+ * ------------------------------------------------------------
|
|
+ *
|
|
+ * sepgsqlCheckSchemaAddRemove
|
|
+ * checks db_schema:{add_object} and db_schema:{remove_object}
|
|
+ * permission when a database object within a certain schema
|
|
+ * is added or removed.
|
|
+ */
|
|
+ Oid
|
|
+ sepgsqlCheckSchemaCreate(const char *nspname, DefElem *new_label, bool temp_schema)
|
|
+ {
|
|
+ Oid nspsid;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return InvalidOid;
|
|
+
|
|
+ if (!new_label)
|
|
+ nspsid = (!temp_schema
|
|
+ ? sepgsqlGetDefaultSchemaSecLabel(MyDatabaseId)
|
|
+ : sepgsqlGetDefaultSchemaTempSecLabel(MyDatabaseId));
|
|
+ else
|
|
+ nspsid = securityTransSecLabelIn(NamespaceRelationId,
|
|
+ strVal(new_label->arg));
|
|
+
|
|
+ sepgsqlClientHasPermsSid(NamespaceRelationId, nspsid,
|
|
+ (!temp_schema
|
|
+ ? SEPG_CLASS_DB_SCHEMA
|
|
+ : SEPG_CLASS_DB_SCHEMA_TEMP),
|
|
+ SEPG_DB_SCHEMA__CREATE,
|
|
+ nspname, true);
|
|
+ return nspsid;
|
|
+ }
|
|
+
|
|
+ static bool
|
|
+ sepgsqlCheckSchemaCommon(Oid namespace_oid, access_vector_t required, bool abort)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ bool rc;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+
|
|
+ tuple = SearchSysCache(NAMESPACEOID,
|
|
+ ObjectIdGetDatum(namespace_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for namespace: %u", namespace_oid);
|
|
+
|
|
+ rc = sepgsqlClientHasPermsTup(NamespaceRelationId, tuple,
|
|
+ (!isAnyTempNamespace(namespace_oid)
|
|
+ ? SEPG_CLASS_DB_SCHEMA
|
|
+ : SEPG_CLASS_DB_SCHEMA_TEMP),
|
|
+ required, abort);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckSchemaDrop(Oid namespace_oid)
|
|
+ {
|
|
+ sepgsqlCheckSchemaCommon(namespace_oid,
|
|
+ SEPG_DB_SCHEMA__DROP, true);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckSchemaSetattr(Oid namespace_oid)
|
|
+ {
|
|
+ sepgsqlCheckSchemaCommon(namespace_oid,
|
|
+ SEPG_DB_SCHEMA__SETATTR, true);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlCheckSchemaRelabel(Oid namespace_oid, DefElem *new_label)
|
|
+ {
|
|
+ Oid nspsid;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ {
|
|
+ if (new_label)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux is disabled now")));
|
|
+ return InvalidOid;
|
|
+ }
|
|
+ nspsid = securityTransSecLabelIn(NamespaceRelationId,
|
|
+ strVal(new_label->arg));
|
|
+
|
|
+ /* db_schema:{setattr relabelfrom} for older seclabel */
|
|
+ sepgsqlCheckSchemaCommon(namespace_oid,
|
|
+ SEPG_DB_SCHEMA__SETATTR |
|
|
+ SEPG_DB_SCHEMA__RELABELFROM, true);
|
|
+ /* db_schema:{relabelto} for newer seclabel */
|
|
+ sepgsqlClientHasPermsSid(NamespaceRelationId, nspsid,
|
|
+ !isAnyTempNamespace(namespace_oid)
|
|
+ ? SEPG_CLASS_DB_SCHEMA
|
|
+ : SEPG_CLASS_DB_SCHEMA_TEMP,
|
|
+ SEPG_DB_SCHEMA__RELABELTO,
|
|
+ get_namespace_name(namespace_oid), true);
|
|
+ return nspsid;
|
|
+ }
|
|
+
|
|
+ bool
|
|
+ sepgsqlCheckSchemaUsage(Oid namespace_oid)
|
|
+ {
|
|
+ return sepgsqlCheckSchemaCommon(namespace_oid,
|
|
+ SEPG_DB_SCHEMA__USAGE, false);
|
|
+ }
|
|
+
|
|
+ /* ------------------------------------------------------------ *
|
|
+ * Hooks corresponding to db_table object class
|
|
+ * ------------------------------------------------------------ */
|
|
+
|
|
+ /*
|
|
+ * NOTE: db_table/db_sequence:{create} permission is checked
|
|
+ * at sepgsqlCreateTableColumns() due to the reason
|
|
+ * for implementation.
|
|
+ *
|
|
+ * sepgsqlCheckTableReference
|
|
+ * checks db_table:{reference} and db_column:{reference} permission
|
|
+ * when the client tries to set up a foreign key constraint on the
|
|
+ * certain tables and columns.
|
|
+ */
|
|
+
|
|
+ static void
|
|
+ checkTableCommon(Oid table_oid, access_vector_t required)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ char relkind;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(table_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for relation %u", table_oid);
|
|
+
|
|
+ relkind = ((Form_pg_class) GETSTRUCT(tuple))->relkind;
|
|
+ switch (relkind)
|
|
+ {
|
|
+ case RELKIND_RELATION:
|
|
+ sepgsqlClientHasPermsTup(RelationRelationId, tuple,
|
|
+ SEPG_CLASS_DB_TABLE,
|
|
+ required, true);
|
|
+ break;
|
|
+
|
|
+ case RELKIND_SEQUENCE:
|
|
+ sepgsqlClientHasPermsTup(RelationRelationId, tuple,
|
|
+ SEPG_CLASS_DB_SEQUENCE,
|
|
+ required, true);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ /* do nothing in this version */
|
|
+ break;
|
|
+ }
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckTableDrop(Oid table_oid)
|
|
+ {
|
|
+ Form_pg_attribute attr;
|
|
+ Relation attrel;
|
|
+ SysScanDesc scan;
|
|
+ ScanKeyData key[1];
|
|
+ HeapTuple atttup;
|
|
+ char relkind;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ checkTableCommon(table_oid, SEPG_DB_TABLE__DROP);
|
|
+
|
|
+ relkind = get_rel_relkind(table_oid);
|
|
+ if (relkind != RELKIND_RELATION)
|
|
+ return; /* no need to check anymore */
|
|
+
|
|
+ /* Also checks db_column:{drop} */
|
|
+ attrel = heap_open(AttributeRelationId, AccessShareLock);
|
|
+
|
|
+ ScanKeyInit(&key[0],
|
|
+ Anum_pg_attribute_attrelid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(table_oid));
|
|
+
|
|
+ scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
|
|
+ SnapshotNow, 1, key);
|
|
+ while(HeapTupleIsValid(atttup = systable_getnext(scan)))
|
|
+ {
|
|
+ attr = (Form_pg_attribute) GETSTRUCT(atttup);
|
|
+ if (attr->attisdropped)
|
|
+ continue;
|
|
+
|
|
+ sepgsqlClientHasPermsTup(AttributeRelationId, atttup,
|
|
+ SEPG_CLASS_DB_COLUMN,
|
|
+ SEPG_DB_COLUMN__DROP,
|
|
+ true);
|
|
+ }
|
|
+ systable_endscan(scan);
|
|
+
|
|
+ heap_close(attrel, AccessShareLock);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckTableSetattr(Oid table_oid)
|
|
+ {
|
|
+ checkTableCommon(table_oid, SEPG_DB_TABLE__SETATTR);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlCheckTableRelabel(Oid table_oid, DefElem *new_label)
|
|
+ {
|
|
+ Oid relsid;
|
|
+ char relkind;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ {
|
|
+ if (new_label)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux is disabled now")));
|
|
+ return InvalidOid;
|
|
+ }
|
|
+
|
|
+ relkind = get_rel_relkind(table_oid);
|
|
+ if (relkind != RELKIND_RELATION && relkind != RELKIND_SEQUENCE)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to set security label on \"%s\"",
|
|
+ get_rel_name(table_oid))));
|
|
+
|
|
+ relsid = securityTransSecLabelIn(RelationRelationId,
|
|
+ strVal(new_label->arg));
|
|
+
|
|
+ /* db_table/db_sequence:{setattr relabelfrom} for older seclabel */
|
|
+ checkTableCommon(table_oid,
|
|
+ SEPG_DB_TABLE__SETATTR |
|
|
+ SEPG_DB_TABLE__RELABELFROM);
|
|
+
|
|
+ /* db_table/db_sequence:{relabelto} for newer seclabel */
|
|
+ sepgsqlClientHasPermsSid(RelationRelationId, relsid,
|
|
+ (relkind == RELKIND_RELATION
|
|
+ ? SEPG_CLASS_DB_TABLE
|
|
+ : SEPG_CLASS_DB_SEQUENCE),
|
|
+ SEPG_DB_TABLE__RELABELTO,
|
|
+ get_rel_name(table_oid), true);
|
|
+ return relsid;
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckTableLock(Oid table_oid)
|
|
+ {
|
|
+ checkTableCommon(table_oid, SEPG_DB_TABLE__LOCK);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckTableTruncate(Relation rel)
|
|
+ {
|
|
+ HeapScanDesc scan;
|
|
+ HeapTuple tuple;
|
|
+ security_class_t tclass;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ /* check db_table:{delete} permission */
|
|
+ checkTableCommon(RelationGetRelid(rel), SEPG_DB_TABLE__DELETE);
|
|
+
|
|
+ /* check db_tuple:{delete} permission */
|
|
+ scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
|
|
+
|
|
+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
+ {
|
|
+ tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple);
|
|
+ sepgsqlClientHasPermsTup(RelationGetRelid(rel), tuple, tclass,
|
|
+ SEPG_DB_TUPLE__DELETE, true);
|
|
+ }
|
|
+ heap_endscan(scan);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckTableReference(Relation rel, int16 *attnums, int natts)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ int i;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ checkTableCommon(RelationGetRelid(rel), SEPG_DB_TABLE__REFERENCE);
|
|
+
|
|
+ for (i=0; i < natts; i++)
|
|
+ {
|
|
+ tuple = SearchSysCache(ATTNUM,
|
|
+ ObjectIdGetDatum(RelationGetRelid(rel)),
|
|
+ Int16GetDatum(attnums[i]),
|
|
+ 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for attribute %u of %s",
|
|
+ attnums[i], RelationGetRelationName(rel));
|
|
+
|
|
+ sepgsqlClientHasPermsTup(AttributeRelationId, tuple,
|
|
+ SEPG_CLASS_DB_COLUMN,
|
|
+ SEPG_DB_COLUMN__REFERENCE,
|
|
+ true);
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* ------------------------------------------------------------ *
|
|
+ * Hooks corresponding to db_sequence object class
|
|
+ * ------------------------------------------------------------ */
|
|
+ static void
|
|
+ sepgsqlCheckSequenceCommon(Oid seqid, access_vector_t required)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(seqid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for sequence: %u", seqid);
|
|
+
|
|
+ sepgsqlClientHasPermsTup(RelationRelationId, tuple,
|
|
+ SEPG_CLASS_DB_SEQUENCE,
|
|
+ required, true);
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ void sepgsqlCheckSequenceGetValue(Oid seqid)
|
|
+ {
|
|
+ sepgsqlCheckSequenceCommon(seqid, SEPG_DB_SEQUENCE__GET_VALUE);
|
|
+ }
|
|
+
|
|
+ void sepgsqlCheckSequenceNextValue(Oid seqid)
|
|
+ {
|
|
+ sepgsqlCheckSequenceCommon(seqid, SEPG_DB_SEQUENCE__NEXT_VALUE);
|
|
+ }
|
|
+
|
|
+ void sepgsqlCheckSequenceSetValue(Oid seqid)
|
|
+ {
|
|
+ sepgsqlCheckSequenceCommon(seqid, SEPG_DB_SEQUENCE__SET_VALUE);
|
|
+ }
|
|
+
|
|
+ /* ------------------------------------------------------------ *
|
|
+ * Hooks corresponding to db_column object class
|
|
+ * ------------------------------------------------------------ */
|
|
+
|
|
+ /*
|
|
+ * NOTE: db_column:{create} is checked on sepgsqlCreateTableColumns()
|
|
+ * which is invoked on CREATE TABLE statement.
|
|
+ * The sepgsqlCheckColumnCreate() is called on the ALTER TABLE
|
|
+ * ... ADD COLUMN path.
|
|
+ */
|
|
+ Oid
|
|
+ sepgsqlCheckColumnCreate(Oid table_oid, const char *attname, DefElem *new_label)
|
|
+ {
|
|
+ Oid secid;
|
|
+ char relkind;
|
|
+ char buffer[NAMEDATALEN * 2 + 3];
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ {
|
|
+ if (new_label)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux is disabled now")));
|
|
+ return InvalidOid;
|
|
+ }
|
|
+
|
|
+ relkind = get_rel_relkind(table_oid);
|
|
+ if (relkind != RELKIND_RELATION)
|
|
+ {
|
|
+ if (new_label)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("Unable to assign security label")));
|
|
+ return InvalidOid;
|
|
+ }
|
|
+
|
|
+ if (!new_label)
|
|
+ secid = sepgsqlGetDefaultColumnSecLabel(table_oid);
|
|
+ else
|
|
+ secid = securityTransSecLabelIn(AttributeRelationId,
|
|
+ strVal(new_label->arg));
|
|
+
|
|
+ sprintf(buffer, "%s.%s", get_rel_name(table_oid), attname);
|
|
+ sepgsqlClientHasPermsSid(AttributeRelationId, secid,
|
|
+ SEPG_CLASS_DB_COLUMN,
|
|
+ SEPG_DB_COLUMN__CREATE,
|
|
+ buffer, true);
|
|
+ return secid;
|
|
+ }
|
|
+
|
|
+ static void
|
|
+ sepgsqlCheckColumnCommon(Oid table_oid, AttrNumber attno,
|
|
+ access_vector_t required)
|
|
+ {
|
|
+ Form_pg_attribute attr;
|
|
+ HeapTuple tuple;
|
|
+ char relkind;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ relkind = get_rel_relkind(table_oid);
|
|
+ if (relkind != RELKIND_RELATION)
|
|
+ return;
|
|
+
|
|
+ tuple = SearchSysCache(ATTNUM,
|
|
+ ObjectIdGetDatum(table_oid),
|
|
+ Int16GetDatum(attno),
|
|
+ 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
|
|
+ attno, table_oid);
|
|
+
|
|
+ attr = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ if (!attr->attisdropped)
|
|
+ sepgsqlClientHasPermsTup(AttributeRelationId, tuple,
|
|
+ SEPG_CLASS_DB_COLUMN,
|
|
+ required, true);
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckColumnDrop(Oid table_oid, AttrNumber attno)
|
|
+ {
|
|
+ sepgsqlCheckColumnCommon(table_oid, attno, SEPG_DB_COLUMN__DROP);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckColumnSetattr(Oid table_oid, AttrNumber attno)
|
|
+ {
|
|
+ sepgsqlCheckColumnCommon(table_oid, attno, SEPG_DB_COLUMN__SETATTR);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlCheckColumnRelabel(Oid table_oid, AttrNumber attno, DefElem *new_label)
|
|
+ {
|
|
+ Oid attsid;
|
|
+ char relkind;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ {
|
|
+ if (new_label)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux is disabled now")));
|
|
+ return InvalidOid;
|
|
+ }
|
|
+
|
|
+ relkind = get_rel_relkind(table_oid);
|
|
+ if (relkind != RELKIND_RELATION)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to set security label on \"%s.%s\"",
|
|
+ get_rel_name(table_oid),
|
|
+ get_attname(table_oid, attno))));
|
|
+
|
|
+ attsid = securityTransSecLabelIn(AttributeRelationId,
|
|
+ strVal(new_label->arg));
|
|
+
|
|
+ /* db_column:{setattr relabelfrom} for older seclabel */
|
|
+ sepgsqlCheckColumnCommon(table_oid, attno,
|
|
+ SEPG_DB_COLUMN__SETATTR |
|
|
+ SEPG_DB_COLUMN__RELABELFROM);
|
|
+
|
|
+ /* db_column:{relabelto} for newer seclabel */
|
|
+ sepgsqlClientHasPermsSid(AttributeRelationId, attsid,
|
|
+ SEPG_CLASS_DB_COLUMN,
|
|
+ SEPG_DB_COLUMN__RELABELTO,
|
|
+ get_attname(table_oid, attno), true);
|
|
+ return attsid;
|
|
+ }
|
|
+
|
|
+ /* ------------------------------------------------------------ *
|
|
+ * Hooks corresponding to db_procedure object class
|
|
+ * ------------------------------------------------------------ */
|
|
+ Oid
|
|
+ sepgsqlCheckProcedureCreate(const char *proname,
|
|
+ Oid namespace_oid, DefElem *new_label)
|
|
+ {
|
|
+ Oid prosid;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return InvalidOid;
|
|
+
|
|
+ if (!new_label)
|
|
+ prosid = sepgsqlGetDefaultProcedureSecLabel(namespace_oid);
|
|
+ else
|
|
+ prosid = securityTransSecLabelIn(ProcedureRelationId,
|
|
+ strVal(new_label->arg));
|
|
+
|
|
+ sepgsqlClientHasPermsSid(ProcedureRelationId, prosid,
|
|
+ SEPG_CLASS_DB_PROCEDURE,
|
|
+ SEPG_DB_PROCEDURE__CREATE,
|
|
+ proname, true);
|
|
+
|
|
+ return prosid;
|
|
+ }
|
|
+
|
|
+ static bool
|
|
+ sepgsqlCheckProcedureCommon(Oid proc_oid, access_vector_t required, bool abort)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ bool rc;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+
|
|
+ tuple = SearchSysCache(PROCOID,
|
|
+ ObjectIdGetDatum(proc_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for procedure: %u", proc_oid);
|
|
+
|
|
+ rc = sepgsqlClientHasPermsTup(ProcedureRelationId, tuple,
|
|
+ SEPG_CLASS_DB_PROCEDURE,
|
|
+ required, abort);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckProcedureDrop(Oid proc_oid)
|
|
+ {
|
|
+ sepgsqlCheckProcedureCommon(proc_oid, SEPG_DB_PROCEDURE__DROP, true);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckProcedureSetattr(Oid proc_oid)
|
|
+ {
|
|
+ sepgsqlCheckProcedureCommon(proc_oid, SEPG_DB_PROCEDURE__SETATTR, true);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlCheckProcedureRelabel(Oid proc_oid, DefElem *new_label)
|
|
+ {
|
|
+ Oid prosid;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ {
|
|
+ if (new_label)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux is disabled now")));
|
|
+ return InvalidOid;
|
|
+ }
|
|
+
|
|
+ prosid = securityTransSecLabelIn(ProcedureRelationId,
|
|
+ strVal(new_label->arg));
|
|
+
|
|
+ /* db_procedure:{setattr relabelfrom} for older seclabel */
|
|
+ sepgsqlCheckProcedureCommon(proc_oid,
|
|
+ SEPG_DB_PROCEDURE__SETATTR |
|
|
+ SEPG_DB_PROCEDURE__RELABELFROM, true);
|
|
+ /* db_procedure:{relabelto} for newer seclabel */
|
|
+ sepgsqlClientHasPermsSid(ProcedureRelationId, prosid,
|
|
+ SEPG_CLASS_DB_PROCEDURE,
|
|
+ SEPG_DB_PROCEDURE__RELABELTO,
|
|
+ get_func_name(proc_oid), true);
|
|
+ return prosid;
|
|
+ }
|
|
+
|
|
+ bool
|
|
+ sepgsqlCheckProcedureExecute(Oid proc_oid)
|
|
+ {
|
|
+ return sepgsqlCheckProcedureCommon(proc_oid, SEPG_DB_PROCEDURE__EXECUTE, false);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckProcedureInstall
|
|
+ *
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckProcedureInstall(Oid proc_oid)
|
|
+ {
|
|
+ if (OidIsValid(proc_oid))
|
|
+ sepgsqlCheckProcedureCommon(proc_oid, SEPG_DB_PROCEDURE__INSTALL, true);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 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.
|
|
+ */
|
|
+ struct TrustedProcedureCache
|
|
+ {
|
|
+ FmgrInfo flinfo;
|
|
+ char newcon[1];
|
|
+ };
|
|
+
|
|
+ static Datum
|
|
+ sepgsqlTrustedProcedure(PG_FUNCTION_ARGS)
|
|
+ {
|
|
+ struct TrustedProcedureCache *tcache;
|
|
+ security_context_t save_context;
|
|
+ FmgrInfo *save_flinfo;
|
|
+ Datum result;
|
|
+
|
|
+ tcache = fcinfo->flinfo->fn_extra;
|
|
+ Assert(tcache != NULL);
|
|
+
|
|
+ save_context = sepgsqlSwitchClient(tcache->newcon);
|
|
+ save_flinfo = fcinfo->flinfo;
|
|
+ fcinfo->flinfo = &tcache->flinfo;
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = FunctionCallInvoke(fcinfo);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ sepgsqlSwitchClient(save_context);
|
|
+ fcinfo->flinfo = save_flinfo;
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ sepgsqlSwitchClient(save_context);
|
|
+ fcinfo->flinfo = save_flinfo;
|
|
+
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckProcedureEntrypoint(FmgrInfo *flinfo, HeapTuple protup)
|
|
+ {
|
|
+ struct TrustedProcedureCache *tcache;
|
|
+ security_context_t newcon;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ newcon = sepgsqlClientCreateLabel(ProcedureRelationId,
|
|
+ HeapTupleGetSecLabel(protup),
|
|
+ SEPG_CLASS_PROCESS);
|
|
+
|
|
+ /* Do nothing, if it is not a trusted procedure */
|
|
+ if (strcmp(newcon, sepgsqlGetClientLabel()) == 0)
|
|
+ return;
|
|
+
|
|
+ /* check db_procedure:{entrypoint} */
|
|
+ sepgsqlClientHasPermsTup(ProcedureRelationId, protup,
|
|
+ SEPG_CLASS_DB_PROCEDURE,
|
|
+ SEPG_DB_PROCEDURE__ENTRYPOINT,
|
|
+ true);
|
|
+
|
|
+ /* check process:{transition} */
|
|
+ sepgsqlComputePerms(sepgsqlGetClientLabel(),
|
|
+ newcon,
|
|
+ SEPG_CLASS_PROCESS,
|
|
+ SEPG_PROCESS__TRANSITION,
|
|
+ NULL, true);
|
|
+
|
|
+ /* setup trusted procedure */
|
|
+ tcache = MemoryContextAllocZero(flinfo->fn_mcxt,
|
|
+ sizeof(*tcache) + strlen(newcon));
|
|
+ memcpy(&tcache->flinfo, flinfo, sizeof(*flinfo));
|
|
+ strcpy(tcache->newcon, newcon);
|
|
+ flinfo->fn_addr = sepgsqlTrustedProcedure;
|
|
+ flinfo->fn_extra = tcache;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckBlobCreate
|
|
+ * assigns a default security label and checks db_blob:{create}
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckBlobCreate(Relation rel, HeapTuple lotup)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ /* set a default security context */
|
|
+ sepgsqlSetDefaultSecLabel(rel, lotup);
|
|
+ sepgsqlClientHasPermsTup(RelationGetRelid(rel), lotup,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__CREATE,
|
|
+ true);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckBlobDrop
|
|
+ * checks db_blob:{drop} permission
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckBlobDrop(Relation rel, HeapTuple lotup)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ sepgsqlClientHasPermsTup(RelationGetRelid(rel), lotup,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__DROP,
|
|
+ true);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckBlobRead
|
|
+ * checks db_blob:{read} permission
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckBlobRead(LargeObjectDesc *lobj)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ sepgsqlClientHasPermsSid(LargeObjectRelationId,
|
|
+ lobj->secid,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__READ,
|
|
+ NULL, true);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckBlobWrite
|
|
+ * check db_blob:{write} permission
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckBlobWrite(LargeObjectDesc *lobj)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ sepgsqlClientHasPermsSid(LargeObjectRelationId,
|
|
+ lobj->secid,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__WRITE,
|
|
+ NULL, true);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckBlobGetattr
|
|
+ * check db_blob:{getattr} permission
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckBlobGetattr(HeapTuple tuple)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ sepgsqlClientHasPermsTup(LargeObjectRelationId, tuple,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__GETATTR,
|
|
+ true);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckBlobSetattr
|
|
+ * check db_blob:{setattr} permission
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckBlobSetattr(HeapTuple tuple)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ sepgsqlClientHasPermsTup(LargeObjectRelationId, tuple,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__SETATTR,
|
|
+ true);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckBlobExport
|
|
+ * check db_blob:{read export} and file:{write} permission
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckBlobExport(LargeObjectDesc *lobj,
|
|
+ int fdesc, const char *filename)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ /* db_blob:{read export} */
|
|
+ sepgsqlClientHasPermsSid(LargeObjectRelationId,
|
|
+ lobj->secid,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__READ | SEPG_DB_BLOB__EXPORT,
|
|
+ NULL, true);
|
|
+ /* file:{write} */
|
|
+ sepgsqlCheckFileWrite(fdesc, filename);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckBlobImport
|
|
+ * check db_blob:{write import} and file:{read} permission
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckBlobImport(LargeObjectDesc *lobj,
|
|
+ int fdesc, const char *filename)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ /* db_blob:{write import} */
|
|
+ sepgsqlClientHasPermsSid(LargeObjectRelationId,
|
|
+ lobj->secid,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__WRITE | SEPG_DB_BLOB__IMPORT,
|
|
+ NULL, true);
|
|
+ /* file:{read} */
|
|
+ sepgsqlCheckFileRead(fdesc, filename);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckBlobRelabel
|
|
+ * check db_blob:{setattr relabelfrom relabelto}
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckBlobRelabel(HeapTuple oldtup, HeapTuple newtup)
|
|
+ {
|
|
+ access_vector_t required = SEPG_DB_BLOB__SETATTR;
|
|
+
|
|
+ if (HeapTupleGetSecLabel(oldtup) != HeapTupleGetSecLabel(newtup))
|
|
+ required |= SEPG_DB_BLOB__RELABELFROM;
|
|
+
|
|
+ sepgsqlClientHasPermsTup(LargeObjectRelationId, oldtup,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ required,
|
|
+ true);
|
|
+ if ((required & SEPG_DB_BLOB__RELABELFROM) == 0)
|
|
+ return;
|
|
+
|
|
+ sepgsqlClientHasPermsTup(LargeObjectRelationId, newtup,
|
|
+ SEPG_CLASS_DB_BLOB,
|
|
+ SEPG_DB_BLOB__RELABELTO,
|
|
+ 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);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCheckObjectDrop
|
|
+ * It checks db_xxx:{drop} permission on the given opaque
|
|
+ * object, invoked from deleteOneObject()
|
|
+ */
|
|
+ void
|
|
+ sepgsqlCheckObjectDrop(const ObjectAddress *object)
|
|
+ {
|
|
+ switch (object->classId)
|
|
+ {
|
|
+ case NamespaceRelationId:
|
|
+ sepgsqlCheckSchemaDrop(object->objectId);
|
|
+ break;
|
|
+
|
|
+ case RelationRelationId:
|
|
+ sepgsqlCheckTableDrop(object->objectId);
|
|
+ break;
|
|
+
|
|
+ case AttributeRelationId:
|
|
+ sepgsqlCheckColumnDrop(object->objectId, object->objectSubId);
|
|
+ break;
|
|
+
|
|
+ case ProcedureRelationId:
|
|
+ sepgsqlCheckProcedureDrop(object->objectId);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ /* do nothing in this version */
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 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 protup)
|
|
+ {
|
|
+ security_context_t newcon;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+
|
|
+ newcon = sepgsqlClientCreateLabel(ProcedureRelationId,
|
|
+ HeapTupleGetSecLabel(protup),
|
|
+ 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(), newcon) == 0)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+ }
|
|
diff -Nrpc base/src/backend/security/sepgsql/label.c sepgsql/src/backend/security/sepgsql/label.c
|
|
*** base/src/backend/security/sepgsql/label.c Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/label.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,685 ----
|
|
+ /*
|
|
+ * 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/sysattr.h"
|
|
+ #include "access/xact.h"
|
|
+ #include "catalog/catalog.h"
|
|
+ #include "catalog/heap.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_namespace.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 "storage/fd.h"
|
|
+ #include "utils/syscache.h"
|
|
+
|
|
+ /* GUC: to turn on/off row level controls in SE-PostgreSQL */
|
|
+ bool sepostgresql_row_level;
|
|
+
|
|
+ /* GUC parameter to turn on/off mcstrans */
|
|
+ bool sepostgresql_use_mcstrans;
|
|
+
|
|
+ /*
|
|
+ * sepgsqlTupleDescHasSecLabel
|
|
+ *
|
|
+ * returns a hint whether we should allocate a field to store
|
|
+ * security label on the given relation, or not.
|
|
+ */
|
|
+ bool
|
|
+ sepgsqlTupleDescHasSecLabel(Oid relid, char relkind)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return false;
|
|
+
|
|
+ if (!OidIsValid(relid))
|
|
+ return sepostgresql_row_level; /* Target of SELECT INTO */
|
|
+
|
|
+ if (relid == DatabaseRelationId ||
|
|
+ relid == NamespaceRelationId ||
|
|
+ relid == RelationRelationId ||
|
|
+ relid == AttributeRelationId ||
|
|
+ relid == ProcedureRelationId)
|
|
+ return true;
|
|
+
|
|
+ return sepostgresql_row_level;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlMetaSecurityLabel
|
|
+ * It returns a security label of tuples within pg_security system
|
|
+ * catalog. The purpose of this special handling is to avoid infinite
|
|
+ * function invocations to insert new entry for meta security labels.
|
|
+ */
|
|
+ security_context_t
|
|
+ sepgsqlMetaSecurityLabel(void)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ security_context_t tcontext;
|
|
+ Oid tblsid;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return NULL;
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(SecurityRelationId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for relation: \"pg_security\"");
|
|
+
|
|
+ tblsid = HeapTupleGetSecLabel(tuple);
|
|
+ tcontext = securityRawSecLabelOut(RelationRelationId, tblsid);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return sepgsqlComputeCreate(sepgsqlGetServerLabel(),
|
|
+ tcontext, SEPG_CLASS_DB_TUPLE);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlGetDefaultDatabaseSecLabel
|
|
+ * It returns the default security label of a database object.
|
|
+ */
|
|
+ Oid
|
|
+ sepgsqlGetDefaultDatabaseSecLabel(void)
|
|
+ {
|
|
+ security_context_t seclabel;
|
|
+ char filename[MAXPGPATH];
|
|
+ char buffer[1024], *policy_type, *tmp;
|
|
+ FILE *filp;
|
|
+
|
|
+ /*
|
|
+ * NOTE: when the security policy provide a configuration to
|
|
+ * specify the default security context of database object,
|
|
+ * we apply is as a default one.
|
|
+ * If the configuration is unavailable, we compute the
|
|
+ * default security context without any parent object.
|
|
+ */
|
|
+ if (selinux_getpolicytype(&policy_type) < 0)
|
|
+ goto fallback;
|
|
+
|
|
+ snprintf(filename, sizeof(filename),
|
|
+ "%s%s/contexts/sepgsql_context", selinux_path(), policy_type);
|
|
+ filp = AllocateFile(filename, PG_BINARY_R);
|
|
+ if (!filp)
|
|
+ goto fallback;
|
|
+
|
|
+ while (fgets(buffer, sizeof(buffer), filp) != NULL)
|
|
+ {
|
|
+ tmp = strchr(buffer, '#');
|
|
+ if (tmp)
|
|
+ *tmp = '\0';
|
|
+
|
|
+ seclabel = strtok(buffer, " \t\n\r");
|
|
+ if (!seclabel)
|
|
+ continue;
|
|
+
|
|
+ /* An entry found */
|
|
+ FreeFile(filp);
|
|
+ return securityTransSecLabelIn(DatabaseRelationId, seclabel);
|
|
+ }
|
|
+ FreeFile(filp);
|
|
+
|
|
+ fallback:
|
|
+ seclabel = sepgsqlComputeCreate(sepgsqlGetClientLabel(),
|
|
+ sepgsqlGetClientLabel(),
|
|
+ SEPG_CLASS_DB_DATABASE);
|
|
+ return securityTransSecLabelIn(DatabaseRelationId, seclabel);
|
|
+ }
|
|
+
|
|
+ static Oid
|
|
+ defaultSecLabelWithDatabase(Oid relid, Oid datoid, security_class_t tclass)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ Oid datsid;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ {
|
|
+ static Oid cached = InvalidOid;
|
|
+
|
|
+ if (!OidIsValid(cached))
|
|
+ cached = sepgsqlGetDefaultDatabaseSecLabel();
|
|
+ datsid = cached;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(datoid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for database: %u", datoid);
|
|
+ datsid = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ return sepgsqlClientCreateSecid(DatabaseRelationId, datsid,
|
|
+ tclass, relid);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlGetDefaultSchemaSecLabel(Oid database_oid)
|
|
+ {
|
|
+ return defaultSecLabelWithDatabase(NamespaceRelationId,
|
|
+ database_oid, SEPG_CLASS_DB_SCHEMA);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlGetDefaultSchemaTempSecLabel(Oid database_oid)
|
|
+ {
|
|
+ return defaultSecLabelWithDatabase(NamespaceRelationId,
|
|
+ database_oid, SEPG_CLASS_DB_SCHEMA_TEMP);
|
|
+ }
|
|
+
|
|
+ static Oid
|
|
+ defaultSecLabelWithSchema(Oid relid, Oid nspoid, security_class_t tclass)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ Oid nspsid;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ {
|
|
+ static Oid cached = InvalidOid;
|
|
+
|
|
+ if (!OidIsValid(cached))
|
|
+ cached = sepgsqlGetDefaultSchemaSecLabel(MyDatabaseId);
|
|
+ nspsid = cached;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ tuple = SearchSysCache(NAMESPACEOID,
|
|
+ ObjectIdGetDatum(nspoid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for namespace: %u", nspoid);
|
|
+
|
|
+ nspsid = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ return sepgsqlClientCreateSecid(NamespaceRelationId, nspsid,
|
|
+ tclass, relid);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlGetDefaultTableSecLabel(Oid namespace_oid)
|
|
+ {
|
|
+ return defaultSecLabelWithSchema(RelationRelationId,
|
|
+ namespace_oid,
|
|
+ SEPG_CLASS_DB_TABLE);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlGetDefaultSequenceSecLabel(Oid namespace_oid)
|
|
+ {
|
|
+ return defaultSecLabelWithSchema(RelationRelationId,
|
|
+ namespace_oid,
|
|
+ SEPG_CLASS_DB_SEQUENCE);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlGetDefaultProcedureSecLabel(Oid namespace_oid)
|
|
+ {
|
|
+ return defaultSecLabelWithSchema(ProcedureRelationId,
|
|
+ namespace_oid,
|
|
+ SEPG_CLASS_DB_PROCEDURE);
|
|
+ }
|
|
+
|
|
+ static Oid
|
|
+ defaultSecLabelWithTable(Oid relid, Oid tbloid, security_class_t tclass)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ Oid tblsid;
|
|
+
|
|
+ if (IsBootstrapProcessingMode()
|
|
+ && (tbloid == TypeRelationId ||
|
|
+ tbloid == ProcedureRelationId ||
|
|
+ tbloid == AttributeRelationId ||
|
|
+ tbloid == RelationRelationId))
|
|
+ {
|
|
+ static Oid cached = InvalidOid;
|
|
+
|
|
+ if (!OidIsValid(cached))
|
|
+ cached = sepgsqlGetDefaultTableSecLabel(PG_CATALOG_NAMESPACE);
|
|
+ tblsid = cached;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(tbloid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for relation: %u", tbloid);
|
|
+
|
|
+ tblsid = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ return sepgsqlClientCreateSecid(RelationRelationId, tblsid,
|
|
+ tclass, relid);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlGetDefaultColumnSecLabel(Oid table_oid)
|
|
+ {
|
|
+ return defaultSecLabelWithTable(AttributeRelationId,
|
|
+ table_oid,
|
|
+ SEPG_CLASS_DB_COLUMN);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlGetDefaultTupleSecLabel(Oid table_oid)
|
|
+ {
|
|
+ return defaultSecLabelWithTable(table_oid,
|
|
+ table_oid,
|
|
+ SEPG_CLASS_DB_TUPLE);
|
|
+ }
|
|
+
|
|
+ Oid
|
|
+ sepgsqlGetDefaultBlobSecLabel(Oid database_oid)
|
|
+ {
|
|
+ return defaultSecLabelWithDatabase(LargeObjectRelationId,
|
|
+ MyDatabaseId,
|
|
+ SEPG_CLASS_DB_BLOB);
|
|
+ }
|
|
+
|
|
+ void
|
|
+ sepgsqlSetDefaultSecLabel(Relation rel, HeapTuple tuple)
|
|
+ {
|
|
+ Oid relid = RelationGetRelid(rel);
|
|
+ Oid newsid, nspoid, tbloid;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ if (!HeapTupleHasSecLabel(tuple))
|
|
+ return;
|
|
+
|
|
+ switch (sepgsqlTupleObjectClass(relid, tuple))
|
|
+ {
|
|
+ case SEPG_CLASS_DB_DATABASE:
|
|
+ newsid = sepgsqlGetDefaultDatabaseSecLabel();
|
|
+ break;
|
|
+ case SEPG_CLASS_DB_SCHEMA:
|
|
+ newsid = sepgsqlGetDefaultSchemaSecLabel(MyDatabaseId);
|
|
+ break;
|
|
+ case SEPG_CLASS_DB_SCHEMA_TEMP:
|
|
+ newsid = sepgsqlGetDefaultSchemaTempSecLabel(MyDatabaseId);
|
|
+ break;
|
|
+ case SEPG_CLASS_DB_TABLE:
|
|
+ nspoid = ((Form_pg_class) GETSTRUCT(tuple))->relnamespace;
|
|
+ newsid = sepgsqlGetDefaultTableSecLabel(nspoid);
|
|
+ break;
|
|
+ case SEPG_CLASS_DB_SEQUENCE:
|
|
+ nspoid = ((Form_pg_class) GETSTRUCT(tuple))->relnamespace;
|
|
+ newsid = sepgsqlGetDefaultSequenceSecLabel(nspoid);
|
|
+ break;
|
|
+ case SEPG_CLASS_DB_PROCEDURE:
|
|
+ nspoid = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace;
|
|
+ newsid = sepgsqlGetDefaultProcedureSecLabel(nspoid);
|
|
+ break;
|
|
+ case SEPG_CLASS_DB_COLUMN:
|
|
+ tbloid = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid;
|
|
+ newsid = sepgsqlGetDefaultColumnSecLabel(tbloid);
|
|
+ break;
|
|
+ case SEPG_CLASS_DB_BLOB:
|
|
+ newsid = sepgsqlGetDefaultBlobSecLabel(MyDatabaseId);
|
|
+ break;
|
|
+ default:
|
|
+ newsid = sepgsqlGetDefaultTupleSecLabel(relid);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ HeapTupleSetSecLabel(tuple, newsid);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCreateTableColumn
|
|
+ * It returns an array of security identifier for the new table
|
|
+ * and columns to be assigned. The corresponding security labels
|
|
+ * are already checked for db_table/db_sequence/db_column:{create}
|
|
+ * permission.
|
|
+ * In the default labeling rule, a column inherits the security
|
|
+ * label of its table, but we cannot refer it using system caches,
|
|
+ * because the command counter is not incremented under the
|
|
+ * heap_create_with_catalog(). Thus, we need to compute and check
|
|
+ * them prior to the actual creation of table and columns.
|
|
+ */
|
|
+ Oid *
|
|
+ sepgsqlCreateTableColumns(CreateStmt *stmt,
|
|
+ const char *relname, Oid namespace_oid,
|
|
+ TupleDesc tupdesc, char relkind)
|
|
+ {
|
|
+ Oid *secLabels = NULL;
|
|
+ Oid relsid = InvalidOid;
|
|
+ int index;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return NULL;
|
|
+
|
|
+ /*
|
|
+ * In the current version, we don't assign any certain security
|
|
+ * labels on relations except for tables/sequences.
|
|
+ */
|
|
+ if (relkind != RELKIND_RELATION && relkind != RELKIND_SEQUENCE)
|
|
+ return NULL;
|
|
+
|
|
+ /*
|
|
+ * The secLabels array stores security identifiers to be assigned
|
|
+ * on the new table and columns.
|
|
+ *
|
|
+ * secLabels[0] is security identifier of the table.
|
|
+ * secLabels[attnum - FirstLowInvalidHeapAttributeNumber]
|
|
+ * is security identifier of columns.
|
|
+ */
|
|
+ secLabels = palloc0(sizeof(Oid) * (tupdesc->natts
|
|
+ - FirstLowInvalidHeapAttributeNumber));
|
|
+
|
|
+ /*
|
|
+ * SELinux checks db_table/db_sequence:{create}
|
|
+ */
|
|
+ switch (relkind)
|
|
+ {
|
|
+ case RELKIND_RELATION:
|
|
+ if (!stmt || !stmt->secLabel)
|
|
+ relsid = sepgsqlGetDefaultTableSecLabel(namespace_oid);
|
|
+ else
|
|
+ relsid = securityTransSecLabelIn(RelationRelationId,
|
|
+ strVal(((DefElem *)stmt->secLabel)->arg));
|
|
+ sepgsqlClientHasPermsSid(RelationRelationId, relsid,
|
|
+ SEPG_CLASS_DB_TABLE,
|
|
+ SEPG_DB_TABLE__CREATE,
|
|
+ relname, true);
|
|
+ break;
|
|
+
|
|
+ case RELKIND_SEQUENCE:
|
|
+ if (!stmt || !stmt->secLabel)
|
|
+ relsid = sepgsqlGetDefaultSequenceSecLabel(namespace_oid);
|
|
+ else
|
|
+ relsid = securityTransSecLabelIn(RelationRelationId,
|
|
+ strVal(((DefElem *)stmt->secLabel)->arg));
|
|
+ sepgsqlClientHasPermsSid(RelationRelationId, relsid,
|
|
+ SEPG_CLASS_DB_SEQUENCE,
|
|
+ SEPG_DB_SEQUENCE__CREATE,
|
|
+ relname, true);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ if (stmt && stmt->secLabel)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to set security label on \"%s\"", relname)));
|
|
+ relsid = sepgsqlGetDefaultTupleSecLabel(RelationRelationId);
|
|
+ break;
|
|
+ }
|
|
+ /* table's security identifier to be assigned on */
|
|
+ secLabels[0] = relsid;
|
|
+
|
|
+ /*
|
|
+ * SELinux checks db_column:{create}
|
|
+ */
|
|
+ for (index = FirstLowInvalidHeapAttributeNumber + 1;
|
|
+ index < tupdesc->natts;
|
|
+ index++)
|
|
+ {
|
|
+ Form_pg_attribute attr;
|
|
+ char attname[NAMEDATALEN * 2 + 3];
|
|
+ Oid attsid = InvalidOid;
|
|
+
|
|
+ /* skip unnecessary attributes */
|
|
+ if (index < 0 && (relkind == RELKIND_VIEW ||
|
|
+ relkind == RELKIND_COMPOSITE_TYPE))
|
|
+ continue;
|
|
+ if (index == ObjectIdAttributeNumber && !tupdesc->tdhasoid)
|
|
+ continue;
|
|
+
|
|
+ if (index < 0)
|
|
+ attr = SystemAttributeDefinition(index, tupdesc->tdhasoid);
|
|
+ else
|
|
+ attr = tupdesc->attrs[index];
|
|
+
|
|
+ /* Is there any given security label? */
|
|
+ if (stmt)
|
|
+ {
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, stmt->tableElts)
|
|
+ {
|
|
+ ColumnDef *colDef = lfirst(l);
|
|
+
|
|
+ if (colDef->secLabel &&
|
|
+ strcmp(colDef->colname, NameStr(attr->attname)) == 0)
|
|
+ {
|
|
+ attsid = securityTransSecLabelIn(AttributeRelationId,
|
|
+ strVal(((DefElem *)colDef->secLabel)->arg));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ switch (relkind)
|
|
+ {
|
|
+ case RELKIND_RELATION:
|
|
+ /* compute default column's label if necessary */
|
|
+ if (!OidIsValid(attsid))
|
|
+ attsid = sepgsqlClientCreateSecid(RelationRelationId, relsid,
|
|
+ SEPG_CLASS_DB_COLUMN,
|
|
+ AttributeRelationId);
|
|
+
|
|
+ sprintf(attname, "%s.%s", relname, NameStr(attr->attname));
|
|
+ sepgsqlClientHasPermsSid(AttributeRelationId, attsid,
|
|
+ SEPG_CLASS_DB_COLUMN,
|
|
+ SEPG_DB_COLUMN__CREATE,
|
|
+ attname, true);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ if (OidIsValid(attsid))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("Unable to set security label on \"%s.%s\"",
|
|
+ relname, NameStr(attr->attname))));
|
|
+ attsid = sepgsqlGetDefaultTupleSecLabel(AttributeRelationId);
|
|
+ break;
|
|
+ }
|
|
+ /* column's security identifier to be assigend on */
|
|
+ secLabels[index - FirstLowInvalidHeapAttributeNumber] = attsid;
|
|
+ }
|
|
+ return secLabels;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlCopyTableColumns
|
|
+ * It returns an array of security identifier of table and columns
|
|
+ * to be copied on make_new_heap(). It actually create a new temporary
|
|
+ * relation and insert all the tuples within original one into the
|
|
+ * temporary one, but swap_relation_files() swaps their file nodes.
|
|
+ * Thus, there are no changes from the viewpoint of users.
|
|
+ * SE-PostgreSQL also does not check and change anything. It simply
|
|
+ * copies security identifier of the source relation to the destination
|
|
+ * relation.
|
|
+ */
|
|
+ Oid *
|
|
+ sepgsqlCopyTableColumns(Relation source)
|
|
+ {
|
|
+ HeapTuple tuple;
|
|
+ Oid *secLabels;
|
|
+ Oid relid = RelationGetRelid(source);
|
|
+ int index;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return PointerGetDatum(NULL);
|
|
+
|
|
+ /* see the comment at sepgsqlCreateTableColumn*/
|
|
+ secLabels = palloc0(sizeof(Oid) * (RelationGetDescr(source)->natts
|
|
+ - FirstLowInvalidHeapAttributeNumber));
|
|
+
|
|
+ /* copy table's security identifier */
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ elog(ERROR, "cache lookup failed for relation \"%s\"",
|
|
+ RelationGetRelationName(source));
|
|
+
|
|
+ secLabels[0] = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ /* copy column's security identifier */
|
|
+ for (index = FirstLowInvalidHeapAttributeNumber + 1;
|
|
+ index < RelationGetDescr(source)->natts;
|
|
+ index++)
|
|
+ {
|
|
+ Form_pg_attribute attr;
|
|
+
|
|
+ if (index < 0)
|
|
+ attr = SystemAttributeDefinition(index, true);
|
|
+ else
|
|
+ attr = RelationGetDescr(source)->attrs[index];
|
|
+
|
|
+ tuple = SearchSysCache(ATTNUM,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ Int16GetDatum(attr->attnum),
|
|
+ 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ continue;
|
|
+
|
|
+ secLabels[index - FirstLowInvalidHeapAttributeNumber]
|
|
+ = HeapTupleGetSecLabel(tuple);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ return secLabels;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlRawSecLabelIn
|
|
+ * correctness checks for the given security context
|
|
+ */
|
|
+ char *
|
|
+ sepgsqlRawSecLabelIn(char *seclabel)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return seclabel;
|
|
+
|
|
+ if (!seclabel || security_check_context_raw(seclabel) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("Invalid security context: \"%s\"", seclabel)));
|
|
+
|
|
+ return seclabel;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlRawSecLabelOut
|
|
+ * correctness checks for the given security context,
|
|
+ * and replace it if invalid security context
|
|
+ */
|
|
+ char *
|
|
+ sepgsqlRawSecLabelOut(char *seclabel)
|
|
+ {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return seclabel;
|
|
+
|
|
+ if (!seclabel || security_check_context_raw(seclabel) < 0)
|
|
+ {
|
|
+ security_context_t unlabeledcon;
|
|
+
|
|
+ if (security_get_initial_context_raw("unlabeled",
|
|
+ &unlabeledcon) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("Unabled to get unlabeled security context")));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ seclabel = pstrdup(unlabeledcon);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(unlabeledcon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(unlabeledcon);
|
|
+ }
|
|
+ return seclabel;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * sepgsqlTransSecLabelIn
|
|
+ * sepgsqlTransSecLabelOut
|
|
+ * translation between human-readable and raw format
|
|
+ */
|
|
+ char *
|
|
+ sepgsqlTransSecLabelIn(char *seclabel)
|
|
+ {
|
|
+ security_context_t rawlabel;
|
|
+ security_context_t result;
|
|
+
|
|
+ if (!sepgsqlIsEnabled() ||
|
|
+ !sepostgresql_use_mcstrans)
|
|
+ return seclabel;
|
|
+
|
|
+ if (selinux_trans_to_raw_context(seclabel, &rawlabel) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: failed to translate \"%s\"", seclabel)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(rawlabel);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(rawlabel);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(rawlabel);
|
|
+
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ char *
|
|
+ sepgsqlTransSecLabelOut(char *seclabel)
|
|
+ {
|
|
+ security_context_t translabel;
|
|
+ security_context_t result;
|
|
+
|
|
+ if (!sepgsqlIsEnabled() ||
|
|
+ !sepostgresql_use_mcstrans)
|
|
+ return seclabel;
|
|
+
|
|
+ if (selinux_raw_to_trans_context(seclabel, &translabel) < 0)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: failed to translate \"%s\"", seclabel)));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(translabel);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(translabel);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(translabel);
|
|
+
|
|
+ return result;
|
|
+ }
|
|
diff -Nrpc base/src/backend/security/sepgsql/misc.c sepgsql/src/backend/security/sepgsql/misc.c
|
|
*** base/src/backend/security/sepgsql/misc.c Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/misc.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,304 ----
|
|
+ /*
|
|
+ * src/backend/security/sepgsql/misc.c
|
|
+ * Miscellaneous facilities in 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 "libpq/libpq-be.h"
|
|
+ #include "miscadmin.h"
|
|
+ #include "security/sepgsql.h"
|
|
+ #include "utils/builtins.h"
|
|
+
|
|
+ static security_context_t clientLabel = NULL;
|
|
+ static security_context_t serverLabel = 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(clientLabel);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ clientLabel = old_client;
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ return new_client;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 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;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 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 = sepgsqlTransSecLabelOut(context);
|
|
+ return CStringGetTextDatum(context);
|
|
+ }
|
|
+
|
|
+ Datum
|
|
+ sepgsql_server_getcon(PG_FUNCTION_ARGS)
|
|
+ {
|
|
+ security_context_t context;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SELINUX_ERROR),
|
|
+ errmsg("SELinux: disabled now")));
|
|
+
|
|
+ context = sepgsqlGetServerLabel();
|
|
+ context = sepgsqlTransSecLabelOut(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)
|
|
+ {
|
|
+ security_context_t 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)
|
|
+ {
|
|
+ security_context_t 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)
|
|
+ {
|
|
+ security_context_t 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)
|
|
+ {
|
|
+ security_context_t 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(sepgsqlTransSecLabelOut(newcon.data));
|
|
+ }
|
|
+
|
|
+ Datum
|
|
+ sepgsql_set_user(PG_FUNCTION_ARGS)
|
|
+ {
|
|
+ security_context_t 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)
|
|
+ {
|
|
+ security_context_t 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)
|
|
+ {
|
|
+ security_context_t 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)
|
|
+ {
|
|
+ security_context_t 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 -Nrpc base/src/backend/security/sepgsql/perms.c sepgsql/src/backend/security/sepgsql/perms.c
|
|
*** base/src/backend/security/sepgsql/perms.c Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/perms.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,463 ----
|
|
+ /*
|
|
+ * 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/pg_database.h"
|
|
+ #include "catalog/pg_proc.h"
|
|
+ #include "catalog/pg_largeobject.h"
|
|
+ #include "catalog/pg_namespace.h"
|
|
+ #include "catalog/pg_type.h"
|
|
+ #include "miscadmin.h"
|
|
+ #include "security/sepgsql.h"
|
|
+ #include "utils/lsyscache.h"
|
|
+
|
|
+ /*
|
|
+ * 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 },
|
|
+ { "connect", SEPG_DB_DATABASE__CONNECT },
|
|
+ { "install_module", SEPG_DB_DATABASE__INSTALL_MODULE },
|
|
+ { "load_module", SEPG_DB_DATABASE__LOAD_MODULE },
|
|
+ { "superuser", SEPG_DB_DATABASE__SUPERUSER },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_schema", SEPG_CLASS_DB_SCHEMA,
|
|
+ {
|
|
+ { "create", SEPG_DB_SCHEMA__CREATE },
|
|
+ { "drop", SEPG_DB_SCHEMA__DROP },
|
|
+ { "getattr", SEPG_DB_SCHEMA__GETATTR },
|
|
+ { "setattr", SEPG_DB_SCHEMA__SETATTR },
|
|
+ { "relabelfrom", SEPG_DB_SCHEMA__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_SCHEMA__RELABELTO },
|
|
+ { "search", SEPG_DB_SCHEMA__USAGE },
|
|
+ { "add_object", SEPG_DB_SCHEMA__ADD_OBJECT },
|
|
+ { "remove_object", SEPG_DB_SCHEMA__REMOVE_OBJECT },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_schema_temp", SEPG_CLASS_DB_SCHEMA_TEMP,
|
|
+ {
|
|
+ { "create", SEPG_DB_SCHEMA_TEMP__CREATE },
|
|
+ { "drop", SEPG_DB_SCHEMA_TEMP__DROP},
|
|
+ { "getattr", SEPG_DB_SCHEMA_TEMP__GETATTR },
|
|
+ { "setattr", SEPG_DB_SCHEMA_TEMP__SETATTR },
|
|
+ { "relabelfrom", SEPG_DB_SCHEMA_TEMP__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_SCHEMA_TEMP__RELABELTO },
|
|
+ { "usage", SEPG_DB_SCHEMA_TEMP__USAGE },
|
|
+ { "add_object", SEPG_DB_SCHEMA_TEMP__ADD_OBJECT },
|
|
+ { "remove_object", SEPG_DB_SCHEMA_TEMP__REMOVE_OBJECT },
|
|
+ { 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 },
|
|
+ { "reference", SEPG_DB_TABLE__REFERENCE },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_sequence", SEPG_CLASS_DB_SEQUENCE,
|
|
+ {
|
|
+ { "create", SEPG_DB_SEQUENCE__CREATE },
|
|
+ { "drop", SEPG_DB_SEQUENCE__DROP },
|
|
+ { "getattr", SEPG_DB_SEQUENCE__GETATTR },
|
|
+ { "setattr", SEPG_DB_SEQUENCE__SETATTR },
|
|
+ { "relabelfrom", SEPG_DB_SEQUENCE__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_SEQUENCE__RELABELTO },
|
|
+ { "get_value", SEPG_DB_SEQUENCE__GET_VALUE },
|
|
+ { "next_value", SEPG_DB_SEQUENCE__NEXT_VALUE },
|
|
+ { "set_value", SEPG_DB_SEQUENCE__SET_VALUE },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_procedure", SEPG_CLASS_DB_PROCEDURE,
|
|
+ {
|
|
+ { "create", SEPG_DB_PROCEDURE__CREATE },
|
|
+ { "drop", SEPG_DB_PROCEDURE__DROP },
|
|
+ { "getattr", SEPG_DB_PROCEDURE__GETATTR },
|
|
+ { "setattr", SEPG_DB_PROCEDURE__SETATTR },
|
|
+ { "relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_PROCEDURE__RELABELTO },
|
|
+ { "execute", SEPG_DB_PROCEDURE__EXECUTE },
|
|
+ { "entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT },
|
|
+ { "install", SEPG_DB_PROCEDURE__INSTALL },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ "db_column", SEPG_CLASS_DB_COLUMN,
|
|
+ {
|
|
+ { "create", SEPG_DB_COLUMN__CREATE },
|
|
+ { "drop", SEPG_DB_COLUMN__DROP },
|
|
+ { "getattr", SEPG_DB_COLUMN__GETATTR },
|
|
+ { "setattr", SEPG_DB_COLUMN__SETATTR },
|
|
+ { "relabelfrom", SEPG_DB_COLUMN__RELABELFROM },
|
|
+ { "relabelto", SEPG_DB_COLUMN__RELABELTO },
|
|
+ { "select", SEPG_DB_COLUMN__SELECT },
|
|
+ { "update", SEPG_DB_COLUMN__UPDATE },
|
|
+ { "insert", SEPG_DB_COLUMN__INSERT },
|
|
+ { "reference", SEPG_DB_COLUMN__REFERENCE },
|
|
+ { 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)
|
|
+ {
|
|
+ Assert(tclass < SEPG_CLASS_MAX);
|
|
+
|
|
+ return string_to_security_class(selinux_catalog[tclass].class_name);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 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, deny_unknown;
|
|
+
|
|
+ Assert(tclass < SEPG_CLASS_MAX);
|
|
+
|
|
+ memset(&i_avd, 0, sizeof(struct av_decision));
|
|
+
|
|
+ deny_unknown = security_deny_unknown();
|
|
+
|
|
+ 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)
|
|
+ {
|
|
+ /* fill up undefined permission */
|
|
+ if (!deny_unknown)
|
|
+ i_avd.allowed |= perm_code;
|
|
+ i_avd.decided |= perm_code;
|
|
+ i_avd.auditdeny |= 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(uint16 tclass)
|
|
+ {
|
|
+ Assert(tclass < SEPG_CLASS_MAX);
|
|
+
|
|
+ return selinux_catalog[tclass].class_name;
|
|
+ }
|
|
+
|
|
+ const char *
|
|
+ sepgsqlGetPermString(uint16 tclass, uint32 permission)
|
|
+ {
|
|
+ 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 == permission)
|
|
+ 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 NamespaceRelationId:
|
|
+ return NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname);
|
|
+
|
|
+ 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_namespace nspForm;
|
|
+ Form_pg_class clsForm;
|
|
+ Form_pg_attribute attForm;
|
|
+
|
|
+ switch (relid)
|
|
+ {
|
|
+ case DatabaseRelationId:
|
|
+ return SEPG_CLASS_DB_DATABASE;
|
|
+
|
|
+ case NamespaceRelationId:
|
|
+ nspForm = (Form_pg_namespace) GETSTRUCT(tuple);
|
|
+ if (strncmp(NameStr(nspForm->nspname), "pg_temp_", 8) == 0 ||
|
|
+ strncmp(NameStr(nspForm->nspname), "pg_toast_temp_", 14) == 0)
|
|
+ return SEPG_CLASS_DB_SCHEMA_TEMP;
|
|
+ return SEPG_CLASS_DB_SCHEMA;
|
|
+
|
|
+ case RelationRelationId:
|
|
+ clsForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+ if (clsForm->relkind == RELKIND_RELATION)
|
|
+ return SEPG_CLASS_DB_TABLE;
|
|
+ if (clsForm->relkind == RELKIND_SEQUENCE)
|
|
+ return SEPG_CLASS_DB_SEQUENCE;
|
|
+ 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 -Nrpc base/src/backend/security/sepgsql/policy/Makefile sepgsql/src/backend/security/sepgsql/policy/Makefile
|
|
*** base/src/backend/security/sepgsql/policy/Makefile Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/policy/Makefile Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 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_INSTDIR := $(POLICY_BASEDIR)/packages
|
|
+ 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: sepostgresql-devel.pp
|
|
+
|
|
+ install: all
|
|
+ test -d $(POLICY_INSTDIR) || mkdir -p $(POLICY_INSTDIR)
|
|
+ install -p -m 0644 sepostgresql-devel.pp $(POLICY_INSTDIR)
|
|
+
|
|
+ sepostgresql-devel.pp: sepostgresql-devel.te sepostgresql-devel.fc
|
|
+ $(MAKE) -f $(POLICY_MAKEFILE)
|
|
+
|
|
+ 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 *.fc
|
|
diff -Nrpc base/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template
|
|
*** base/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 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 -Nrpc base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te
|
|
*** base/src/backend/security/sepgsql/policy/sepostgresql-devel.te Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,119 ----
|
|
+ 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)
|
|
+ postgresql_role(sepgsql_test_r, sepgsql_test_t)
|
|
+
|
|
+ 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
|
|
+ #
|
|
+
|
|
+ ## <desc>
|
|
+ ## <p>
|
|
+ ## Allow to generate auditallow logs
|
|
+ ## </p>
|
|
+ ## </desc>
|
|
+ gen_tunable(sepgsql_enable_auditallow, false)
|
|
+
|
|
+ ## <desc>
|
|
+ ## <p>
|
|
+ ## Allow to generate auditdeny logs
|
|
+ ## </p>
|
|
+ ## </desc>
|
|
+ gen_tunable(sepgsql_enable_auditdeny, true)
|
|
+
|
|
+ ## <desc>
|
|
+ ## <p>
|
|
+ ## Allow widespread permissions for regression test
|
|
+ ## Don't set TRUE on operation phase
|
|
+ ## </p>
|
|
+ ## </desc>
|
|
+ gen_tunable(sepgsql_regression_test_mode, false)
|
|
+
|
|
+ ########################################
|
|
+ #
|
|
+ # SE-PostgreSQL audit switch for debugging
|
|
+ #
|
|
+ tunable_policy(`sepgsql_enable_auditallow',`
|
|
+ auditallow domain sepgsql_database_type : db_database *;
|
|
+ auditallow domain sepgsql_table_type : db_table *;
|
|
+ auditallow domain sepgsql_table_type : db_column *;
|
|
+ auditallow domain sepgsql_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 -Nrpc base/src/backend/storage/file/fd.c sepgsql/src/backend/storage/file/fd.c
|
|
*** base/src/backend/storage/file/fd.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/storage/file/fd.c Wed Jul 15 19:48:58 2009
|
|
*************** FileTruncate(File file, off_t offset)
|
|
*** 1319,1324 ****
|
|
--- 1319,1331 ----
|
|
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 -Nrpc base/src/backend/storage/ipc/ipci.c sepgsql/src/backend/storage/ipc/ipci.c
|
|
*** base/src/backend/storage/ipc/ipci.c Thu May 7 08:49:32 2009
|
|
--- sepgsql/src/backend/storage/ipc/ipci.c Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 25,30 ****
|
|
--- 25,31 ----
|
|
#include "postmaster/autovacuum.h"
|
|
#include "postmaster/bgwriter.h"
|
|
#include "postmaster/postmaster.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/pg_shmem.h"
|
|
*************** CreateSharedMemoryAndSemaphores(bool mak
|
|
*** 119,124 ****
|
|
--- 120,126 ----
|
|
#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 -Nrpc base/src/backend/storage/large_object/inv_api.c sepgsql/src/backend/storage/large_object/inv_api.c
|
|
*** base/src/backend/storage/large_object/inv_api.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/storage/large_object/inv_api.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 39,44 ****
|
|
--- 39,45 ----
|
|
#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/rel.h"
|
|
*************** close_lo_relation(bool isCommit)
|
|
*** 137,148 ****
|
|
* read with can be specified.
|
|
*/
|
|
static bool
|
|
! myLargeObjectExists(Oid loid, Snapshot snapshot)
|
|
{
|
|
bool retval = false;
|
|
Relation pg_largeobject;
|
|
ScanKeyData skey[1];
|
|
SysScanDesc sd;
|
|
|
|
/*
|
|
* See if we can find any tuples belonging to the specified LO
|
|
--- 138,150 ----
|
|
* read with can be specified.
|
|
*/
|
|
static bool
|
|
! 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
|
|
*************** myLargeObjectExists(Oid loid, Snapshot s
|
|
*** 150,164 ****
|
|
ScanKeyInit(&skey[0],
|
|
Anum_pg_largeobject_loid,
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
! ObjectIdGetDatum(loid));
|
|
|
|
pg_largeobject = heap_open(LargeObjectRelationId, AccessShareLock);
|
|
|
|
sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndexId, true,
|
|
! snapshot, 1, skey);
|
|
|
|
! if (systable_getnext(sd) != NULL)
|
|
retval = true;
|
|
|
|
systable_endscan(sd);
|
|
|
|
--- 152,170 ----
|
|
ScanKeyInit(&skey[0],
|
|
Anum_pg_largeobject_loid,
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
! ObjectIdGetDatum(lobj->id));
|
|
|
|
pg_largeobject = heap_open(LargeObjectRelationId, AccessShareLock);
|
|
|
|
sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndexId, true,
|
|
! lobj->snapshot, 1, skey);
|
|
|
|
! tuple = systable_getnext(sd);
|
|
! if (HeapTupleIsValid(tuple))
|
|
! {
|
|
retval = true;
|
|
+ lobj->secid = HeapTupleGetSecLabel(tuple);
|
|
+ }
|
|
|
|
systable_endscan(sd);
|
|
|
|
*************** inv_open(Oid lobjId, int flags, MemoryCo
|
|
*** 260,266 ****
|
|
elog(ERROR, "invalid flags: %d", flags);
|
|
|
|
/* Can't use LargeObjectExists here because it always uses SnapshotNow */
|
|
! if (!myLargeObjectExists(lobjId, retval->snapshot))
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
errmsg("large object %u does not exist", lobjId)));
|
|
--- 266,272 ----
|
|
elog(ERROR, "invalid flags: %d", flags);
|
|
|
|
/* Can't use LargeObjectExists here because it always uses SnapshotNow */
|
|
! if (!myLargeObjectExists(retval))
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
errmsg("large object %u does not exist", lobjId)));
|
|
*************** inv_write(LargeObjectDesc *obj_desc, con
|
|
*** 642,647 ****
|
|
--- 648,655 ----
|
|
replace[Anum_pg_largeobject_data - 1] = true;
|
|
newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r),
|
|
values, nulls, replace);
|
|
+ if (HeapTupleHasSecLabel(newtup))
|
|
+ HeapTupleSetSecLabel(newtup, obj_desc->secid);
|
|
simple_heap_update(lo_heap_r, &newtup->t_self, newtup);
|
|
CatalogIndexInsert(indstate, newtup);
|
|
heap_freetuple(newtup);
|
|
*************** inv_write(LargeObjectDesc *obj_desc, con
|
|
*** 685,690 ****
|
|
--- 693,700 ----
|
|
values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
|
|
values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
|
|
newtup = heap_form_tuple(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);
|
|
*************** inv_truncate(LargeObjectDesc *obj_desc,
|
|
*** 845,850 ****
|
|
--- 855,862 ----
|
|
values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
|
|
values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
|
|
newtup = heap_form_tuple(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);
|
|
*************** inv_truncate(LargeObjectDesc *obj_desc,
|
|
*** 868,870 ****
|
|
--- 880,978 ----
|
|
*/
|
|
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 -Nrpc base/src/backend/tcop/pquery.c sepgsql/src/backend/tcop/pquery.c
|
|
*** base/src/backend/tcop/pquery.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/tcop/pquery.c Wed Jul 15 19:30:50 2009
|
|
*************** PortalStart(Portal portal, ParamListInfo
|
|
*** 573,579 ****
|
|
Assert(pstmt->returningLists);
|
|
portal->tupDesc =
|
|
ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
|
|
! false);
|
|
}
|
|
|
|
/*
|
|
--- 573,579 ----
|
|
Assert(pstmt->returningLists);
|
|
portal->tupDesc =
|
|
ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
|
|
! false, false);
|
|
}
|
|
|
|
/*
|
|
diff -Nrpc base/src/backend/tcop/utility.c sepgsql/src/backend/tcop/utility.c
|
|
*** base/src/backend/tcop/utility.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/tcop/utility.c Wed Jul 15 21:17:18 2009
|
|
***************
|
|
*** 50,55 ****
|
|
--- 50,56 ----
|
|
#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"
|
|
*************** check_xact_readonly(Node *parsetree)
|
|
*** 162,167 ****
|
|
--- 163,169 ----
|
|
case T_AlterRoleSetStmt:
|
|
case T_AlterObjectSchemaStmt:
|
|
case T_AlterOwnerStmt:
|
|
+ case T_AlterSecLabelStmt:
|
|
case T_AlterSeqStmt:
|
|
case T_AlterTableStmt:
|
|
case T_RenameStmt:
|
|
*************** ProcessUtility(Node *parsetree,
|
|
*** 612,617 ****
|
|
--- 614,623 ----
|
|
ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
|
|
break;
|
|
|
|
+ case T_AlterSecLabelStmt:
|
|
+ ExecAlterSecLabelStmt((AlterSecLabelStmt *) parsetree);
|
|
+ break;
|
|
+
|
|
case T_AlterTableStmt:
|
|
{
|
|
List *stmts;
|
|
*************** ProcessUtility(Node *parsetree,
|
|
*** 893,898 ****
|
|
--- 899,905 ----
|
|
LoadStmt *stmt = (LoadStmt *) parsetree;
|
|
|
|
closeAllVfds(); /* probably not necessary... */
|
|
+
|
|
/* Allowed names are restricted if you're not superuser */
|
|
load_file(stmt->filename, !superuser());
|
|
}
|
|
*************** CreateCommandTag(Node *parsetree)
|
|
*** 1635,1640 ****
|
|
--- 1642,1672 ----
|
|
}
|
|
break;
|
|
|
|
+ case T_AlterSecLabelStmt:
|
|
+ switch (((AlterSecLabelStmt *) parsetree)->objectType)
|
|
+ {
|
|
+ case OBJECT_DATABASE:
|
|
+ tag = "ALTER DATABASE";
|
|
+ break;
|
|
+ case OBJECT_SCHEMA:
|
|
+ tag = "ALTER SCHEMA";
|
|
+ break;
|
|
+ case OBJECT_TABLE:
|
|
+ case OBJECT_COLUMN:
|
|
+ tag = "ALTER TABLE";
|
|
+ break;
|
|
+ case OBJECT_SEQUENCE:
|
|
+ tag = "ALTER SEQUENCE";
|
|
+ break;
|
|
+ case OBJECT_FUNCTION:
|
|
+ tag = "ALTER FUNCTION";
|
|
+ break;
|
|
+ default:
|
|
+ tag = "???";
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+
|
|
case T_AlterTableStmt:
|
|
switch (((AlterTableStmt *) parsetree)->relkind)
|
|
{
|
|
*************** GetCommandLogLevel(Node *parsetree)
|
|
*** 2213,2218 ****
|
|
--- 2245,2254 ----
|
|
lev = LOGSTMT_DDL;
|
|
break;
|
|
|
|
+ case T_AlterSecLabelStmt:
|
|
+ lev = LOGSTMT_DDL;
|
|
+ break;
|
|
+
|
|
case T_AlterTableStmt:
|
|
lev = LOGSTMT_DDL;
|
|
break;
|
|
diff -Nrpc base/src/backend/utils/adt/genfile.c sepgsql/src/backend/utils/adt/genfile.c
|
|
*** base/src/backend/utils/adt/genfile.c Sat Jan 3 13:01:35 2009
|
|
--- sepgsql/src/backend/utils/adt/genfile.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 24,29 ****
|
|
--- 24,30 ----
|
|
#include "funcapi.h"
|
|
#include "miscadmin.h"
|
|
#include "postmaster/syslogger.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/fd.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/memutils.h"
|
|
*************** pg_read_file(PG_FUNCTION_ARGS)
|
|
*** 105,110 ****
|
|
--- 106,114 ----
|
|
errmsg("could not open file \"%s\" for reading: %m",
|
|
filename)));
|
|
|
|
+ /* SELinux: check file:{read} permission */
|
|
+ sepgsqlCheckFileRead(fileno(file), filename);
|
|
+
|
|
if (fseeko(file, (off_t) seek_offset,
|
|
(seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0)
|
|
ereport(ERROR,
|
|
diff -Nrpc base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/adt/ri_triggers.c
|
|
*** base/src/backend/utils/adt/ri_triggers.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/utils/adt/ri_triggers.c Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 39,44 ****
|
|
--- 39,45 ----
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_relation.h"
|
|
#include "miscadmin.h"
|
|
+ #include "security/rowlevel.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
*************** RI_Initial_Check(Trigger *trigger, Relat
|
|
*** 2627,2632 ****
|
|
--- 2628,2634 ----
|
|
const char *sep;
|
|
int i;
|
|
int old_work_mem;
|
|
+ int save_rowlv;
|
|
char workmembuf[32];
|
|
int spi_result;
|
|
SPIPlanPtr qplan;
|
|
*************** RI_Initial_Check(Trigger *trigger, Relat
|
|
*** 2759,2764 ****
|
|
--- 2761,2771 ----
|
|
SPI_result, querybuf.data);
|
|
|
|
/*
|
|
+ * Disables the Row-level stuff during the internal consistency checks.
|
|
+ */
|
|
+ save_rowlv = rowlvSetPerformingMode(ROWLV_BYPASS_MODE);
|
|
+
|
|
+ /*
|
|
* Run the plan. For safety we force a current snapshot to be used. (In
|
|
* serializable mode, this arguably violates serializability, but we
|
|
* really haven't got much choice.) We don't need to register the
|
|
*************** RI_Initial_Check(Trigger *trigger, Relat
|
|
*** 2771,2776 ****
|
|
--- 2778,2786 ----
|
|
InvalidSnapshot,
|
|
true, false, 1);
|
|
|
|
+ /* Restore Row-level stuff */
|
|
+ rowlvSetPerformingMode(save_rowlv);
|
|
+
|
|
/* Check result */
|
|
if (spi_result != SPI_OK_SELECT)
|
|
elog(ERROR, "SPI_execute_snapshot returned %d", spi_result);
|
|
*************** ri_PerformCheck(RI_QueryKey *qkey, SPIPl
|
|
*** 3264,3269 ****
|
|
--- 3274,3280 ----
|
|
int spi_result;
|
|
Oid save_userid;
|
|
bool save_secdefcxt;
|
|
+ int save_rowlv, temp_rowlv;
|
|
Datum vals[RI_MAX_NUMKEYS * 2];
|
|
char nulls[RI_MAX_NUMKEYS * 2];
|
|
|
|
*************** ri_PerformCheck(RI_QueryKey *qkey, SPIPl
|
|
*** 3346,3357 ****
|
|
--- 3357,3375 ----
|
|
GetUserIdAndContext(&save_userid, &save_secdefcxt);
|
|
SetUserIdAndContext(RelationGetForm(query_rel)->relowner, true);
|
|
|
|
+ /* Switch Row-level stuff behavior on FK checks, if necessary */
|
|
+ temp_rowlv = (detectNewRows ? ROWLV_ABORT_MODE : ROWLV_FILTER_MODE);
|
|
+ save_rowlv = rowlvSetPerformingMode(temp_rowlv);
|
|
+
|
|
/* Finally we can run the query. */
|
|
spi_result = SPI_execute_snapshot(qplan,
|
|
vals, nulls,
|
|
test_snapshot, crosscheck_snapshot,
|
|
false, false, limit);
|
|
|
|
+ /* Restore Row-level stuff behavior */
|
|
+ rowlvSetPerformingMode(save_rowlv);
|
|
+
|
|
/* Restore UID */
|
|
SetUserIdAndContext(save_userid, save_secdefcxt);
|
|
|
|
diff -Nrpc base/src/backend/utils/adt/trigfuncs.c sepgsql/src/backend/utils/adt/trigfuncs.c
|
|
*** base/src/backend/utils/adt/trigfuncs.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/utils/adt/trigfuncs.c Wed Jul 15 19:30:50 2009
|
|
*************** suppress_redundant_updates_trigger(PG_FU
|
|
*** 76,81 ****
|
|
--- 76,85 ----
|
|
!OidIsValid(HeapTupleHeaderGetOid(newheader)))
|
|
HeapTupleHeaderSetOid(newheader, HeapTupleHeaderGetOid(oldheader));
|
|
|
|
+ if (HeapTupleHeaderHasSecLabel(newheader) &&
|
|
+ !OidIsValid(HeapTupleHeaderGetSecLabel(newheader)))
|
|
+ HeapTupleHeaderSetSecLabel(newheader, HeapTupleHeaderGetSecLabel(oldheader));
|
|
+
|
|
/* if the tuple payload is the same ... */
|
|
if (newtuple->t_len == oldtuple->t_len &&
|
|
newheader->t_hoff == oldheader->t_hoff &&
|
|
diff -Nrpc base/src/backend/utils/cache/plancache.c sepgsql/src/backend/utils/cache/plancache.c
|
|
*** base/src/backend/utils/cache/plancache.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/utils/cache/plancache.c Wed Jul 15 19:30:50 2009
|
|
*************** PlanCacheComputeResultDesc(List *stmt_li
|
|
*** 847,858 ****
|
|
if (IsA(node, Query))
|
|
{
|
|
query = (Query *) node;
|
|
! return ExecCleanTypeFromTL(query->targetList, false);
|
|
}
|
|
if (IsA(node, PlannedStmt))
|
|
{
|
|
pstmt = (PlannedStmt *) node;
|
|
! return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false);
|
|
}
|
|
/* other cases shouldn't happen, but return NULL */
|
|
break;
|
|
--- 847,858 ----
|
|
if (IsA(node, Query))
|
|
{
|
|
query = (Query *) node;
|
|
! return ExecCleanTypeFromTL(query->targetList, false, false);
|
|
}
|
|
if (IsA(node, PlannedStmt))
|
|
{
|
|
pstmt = (PlannedStmt *) node;
|
|
! return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false, false);
|
|
}
|
|
/* other cases shouldn't happen, but return NULL */
|
|
break;
|
|
*************** PlanCacheComputeResultDesc(List *stmt_li
|
|
*** 863,875 ****
|
|
{
|
|
query = (Query *) node;
|
|
Assert(query->returningList);
|
|
! return ExecCleanTypeFromTL(query->returningList, false);
|
|
}
|
|
if (IsA(node, PlannedStmt))
|
|
{
|
|
pstmt = (PlannedStmt *) node;
|
|
Assert(pstmt->returningLists);
|
|
! return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), false);
|
|
}
|
|
/* other cases shouldn't happen, but return NULL */
|
|
break;
|
|
--- 863,876 ----
|
|
{
|
|
query = (Query *) node;
|
|
Assert(query->returningList);
|
|
! return ExecCleanTypeFromTL(query->returningList, false, false);
|
|
}
|
|
if (IsA(node, PlannedStmt))
|
|
{
|
|
pstmt = (PlannedStmt *) node;
|
|
Assert(pstmt->returningLists);
|
|
! return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
|
|
! false, false);
|
|
}
|
|
/* other cases shouldn't happen, but return NULL */
|
|
break;
|
|
diff -Nrpc base/src/backend/utils/cache/relcache.c sepgsql/src/backend/utils/cache/relcache.c
|
|
*** base/src/backend/utils/cache/relcache.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/utils/cache/relcache.c Wed Jul 15 19:30:50 2009
|
|
***************
|
|
*** 47,52 ****
|
|
--- 47,53 ----
|
|
#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"
|
|
*************** RelationBuildDesc(Oid targetRelId, Relat
|
|
*** 865,870 ****
|
|
--- 866,875 ----
|
|
/* extract reloptions if any */
|
|
RelationParseRelOptions(relation, pg_class_tuple);
|
|
|
|
+ /* Fixup relation->rd_att->tdhasseclabel */
|
|
+ RelationGetDescr(relation)->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(relid, relp->relkind);
|
|
+
|
|
/*
|
|
* initialize the relation lock manager information
|
|
*/
|
|
*************** formrdesc(const char *relationName, Oid
|
|
*** 1458,1463 ****
|
|
--- 1463,1473 ----
|
|
RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
|
|
relation->rd_rel->relfilenode = RelationGetRelid(relation);
|
|
|
|
+ /* Fixup relation->rd_att->tdhasseclabel */
|
|
+ RelationGetDescr(relation)->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(RelationGetRelid(relation),
|
|
+ RELKIND_RELATION);
|
|
+
|
|
/*
|
|
* initialize the relation lock manager information
|
|
*/
|
|
*************** BuildHardcodedDescriptor(int natts, Form
|
|
*** 2699,2704 ****
|
|
--- 2709,2721 ----
|
|
result = CreateTemplateTupleDesc(natts, hasoids);
|
|
result->tdtypeid = RECORDOID; /* not right, but we don't care */
|
|
result->tdtypmod = -1;
|
|
+ /*
|
|
+ * NOTE: we assume the returned TupleDesc is only used for
|
|
+ * references to toast'ed data, and it is not delivered to
|
|
+ * heap_form_tuple(), so TupleDesc->tdhasseclabel don't give us
|
|
+ * any effect.
|
|
+ * We omit to invoke securityTupleDescHasSecLabel() here.
|
|
+ */
|
|
|
|
for (i = 0; i < natts; i++)
|
|
{
|
|
*************** load_relcache_init_file(void)
|
|
*** 3453,3458 ****
|
|
--- 3470,3480 ----
|
|
rel->rd_options = NULL;
|
|
}
|
|
|
|
+ /* Fixup rel->rd_att->tdhasseclabel */
|
|
+ RelationGetDescr(rel)->tdhasseclabel
|
|
+ = securityTupleDescHasSecLabel(RelationGetRelid(rel),
|
|
+ RelationGetForm(rel)->relkind);
|
|
+
|
|
/* mark not-null status */
|
|
if (has_not_null)
|
|
{
|
|
diff -Nrpc base/src/backend/utils/cache/syscache.c sepgsql/src/backend/utils/cache/syscache.c
|
|
*** base/src/backend/utils/cache/syscache.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/utils/cache/syscache.c Thu Jul 16 23:18:11 2009
|
|
***************
|
|
*** 41,46 ****
|
|
--- 41,47 ----
|
|
#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"
|
|
*************** static const struct cachedesc cacheinfo[
|
|
*** 584,589 ****
|
|
--- 585,614 ----
|
|
},
|
|
1024
|
|
},
|
|
+ {SecurityRelationId, /* SECURITYATTR */
|
|
+ SecuritySecattrIndexId,
|
|
+ Anum_pg_security_relid,
|
|
+ 4,
|
|
+ {
|
|
+ Anum_pg_security_datid,
|
|
+ Anum_pg_security_relid,
|
|
+ Anum_pg_security_seckind,
|
|
+ Anum_pg_security_secattr
|
|
+ },
|
|
+ 128,
|
|
+ },
|
|
+ {SecurityRelationId, /* SECURITYSECID */
|
|
+ SecuritySecidIndexId,
|
|
+ Anum_pg_security_relid,
|
|
+ 2,
|
|
+ {
|
|
+ Anum_pg_security_secid,
|
|
+ Anum_pg_security_datid,
|
|
+ 0,
|
|
+ 0
|
|
+ },
|
|
+ 128
|
|
+ },
|
|
{StatisticRelationId, /* STATRELATT */
|
|
StatisticRelidAttnumIndexId,
|
|
Anum_pg_statistic_starelid,
|
|
diff -Nrpc base/src/backend/utils/fmgr/dfmgr.c sepgsql/src/backend/utils/fmgr/dfmgr.c
|
|
*** base/src/backend/utils/fmgr/dfmgr.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/utils/fmgr/dfmgr.c Wed Jul 15 19:48:58 2009
|
|
***************
|
|
*** 23,28 ****
|
|
--- 23,29 ----
|
|
#endif
|
|
#include "lib/stringinfo.h"
|
|
#include "miscadmin.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "utils/dynamic_loader.h"
|
|
#include "utils/hsearch.h"
|
|
|
|
*************** load_external_function(char *filename, c
|
|
*** 109,114 ****
|
|
--- 110,118 ----
|
|
/* Expand the possibly-abbreviated filename to an exact path name */
|
|
fullname = expand_dynamic_library_name(filename);
|
|
|
|
+ /* SELinux checks db_database:{load_module} */
|
|
+ sepgsqlCheckDatabaseLoadModule(fullname);
|
|
+
|
|
/* Load the shared library, unless we already did */
|
|
lib_handle = internal_load_library(fullname);
|
|
|
|
*************** load_file(const char *filename, bool res
|
|
*** 149,154 ****
|
|
--- 153,161 ----
|
|
/* 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);
|
|
|
|
diff -Nrpc base/src/backend/utils/fmgr/fmgr.c sepgsql/src/backend/utils/fmgr/fmgr.c
|
|
*** base/src/backend/utils/fmgr/fmgr.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/utils/fmgr/fmgr.c Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 24,29 ****
|
|
--- 24,30 ----
|
|
#include "miscadmin.h"
|
|
#include "nodes/nodeFuncs.h"
|
|
#include "pgstat.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgrtab.h"
|
|
#include "utils/guc.h"
|
|
*************** fmgr_info_cxt_security(Oid functionId, F
|
|
*** 289,294 ****
|
|
--- 290,296 ----
|
|
}
|
|
|
|
finfo->fn_oid = functionId;
|
|
+ sepgsqlCheckProcedureEntrypoint(finfo, procedureTuple);
|
|
ReleaseSysCache(procedureTuple);
|
|
}
|
|
|
|
diff -Nrpc base/src/backend/utils/init/postinit.c sepgsql/src/backend/utils/init/postinit.c
|
|
*** base/src/backend/utils/init/postinit.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/utils/init/postinit.c Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 32,37 ****
|
|
--- 32,38 ----
|
|
#include "pgstat.h"
|
|
#include "postmaster/autovacuum.h"
|
|
#include "postmaster/postmaster.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/backendid.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/fd.h"
|
|
*************** CheckMyDatabase(const char *name, bool a
|
|
*** 200,211 ****
|
|
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.)
|
|
*/
|
|
! if (!am_superuser &&
|
|
! pg_database_aclcheck(MyDatabaseId, GetUserId(),
|
|
ACL_CONNECT) != ACLCHECK_OK)
|
|
ereport(FATAL,
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
--- 201,209 ----
|
|
name)));
|
|
|
|
/*
|
|
! * Check privilege to connect to the database.
|
|
*/
|
|
! if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
|
|
ACL_CONNECT) != ACLCHECK_OK)
|
|
ereport(FATAL,
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
*************** InitPostgres(const char *in_dbname, Oid
|
|
*** 574,579 ****
|
|
--- 572,580 ----
|
|
*/
|
|
RelationCacheInitializePhase2();
|
|
|
|
+ /* Initialize SE-PostgreSQL internal facilities */
|
|
+ sepgsqlAvcInitialize();
|
|
+
|
|
/*
|
|
* Figure out our postgres user id, and see if we are a superuser.
|
|
*
|
|
diff -Nrpc base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc.c
|
|
*** base/src/backend/utils/misc/guc.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/backend/utils/misc/guc.c Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 56,61 ****
|
|
--- 56,62 ----
|
|
#include "postmaster/syslogger.h"
|
|
#include "postmaster/walwriter.h"
|
|
#include "regex/regex.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/fd.h"
|
|
#include "tcop/tcopprot.h"
|
|
*************** static struct config_bool ConfigureNames
|
|
*** 1220,1225 ****
|
|
--- 1221,1252 ----
|
|
&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
|
|
+ },
|
|
+ {
|
|
+ {"sepostgresql_mcstrans", PGC_USERSET, CONN_AUTH_SECURITY,
|
|
+ gettext_noop("SE-PostgreSQL uses mcstrans on printing security labels"),
|
|
+ NULL,
|
|
+ },
|
|
+ &sepostgresql_use_mcstrans,
|
|
+ true, NULL, NULL
|
|
+ },
|
|
+ #endif
|
|
|
|
/* End-of-list marker */
|
|
{
|
|
diff -Nrpc base/src/backend/utils/misc/postgresql.conf.sample sepgsql/src/backend/utils/misc/postgresql.conf.sample
|
|
*** base/src/backend/utils/misc/postgresql.conf.sample Tue Apr 28 16:52:59 2009
|
|
--- sepgsql/src/backend/utils/misc/postgresql.conf.sample Thu Jul 16 23:18:11 2009
|
|
***************
|
|
*** 51,57 ****
|
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
! # CONNECTIONS AND AUTHENTICATION
|
|
#------------------------------------------------------------------------------
|
|
|
|
# - Connection Settings -
|
|
--- 51,57 ----
|
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
! # CONNECTIONS, AUTHENTICATION AND SECURITY
|
|
#------------------------------------------------------------------------------
|
|
|
|
# - Connection Settings -
|
|
***************
|
|
*** 95,101 ****
|
|
# 0 selects the system default
|
|
#tcp_keepalives_count = 0 # TCP_KEEPCNT;
|
|
# 0 selects the system default
|
|
!
|
|
|
|
#------------------------------------------------------------------------------
|
|
# RESOURCE USAGE (except WAL)
|
|
--- 95,101 ----
|
|
# 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 -Nrpc base/src/backend/utils/misc/superuser.c sepgsql/src/backend/utils/misc/superuser.c
|
|
*** base/src/backend/utils/misc/superuser.c Sat Jan 3 13:01:35 2009
|
|
--- sepgsql/src/backend/utils/misc/superuser.c Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 21,26 ****
|
|
--- 21,27 ----
|
|
#include "postgres.h"
|
|
|
|
#include "catalog/pg_authid.h"
|
|
+ #include "security/sepgsql.h"
|
|
#include "utils/inval.h"
|
|
#include "utils/syscache.h"
|
|
#include "miscadmin.h"
|
|
*************** superuser_arg(Oid roleid)
|
|
*** 60,70 ****
|
|
|
|
/* Quick out for cache hit */
|
|
if (OidIsValid(last_roleid) && last_roleid == roleid)
|
|
! return last_roleid_is_super;
|
|
|
|
/* Special escape path in case you deleted all your users. */
|
|
if (!IsUnderPostmaster && roleid == BOOTSTRAP_SUPERUSERID)
|
|
! return true;
|
|
|
|
/* OK, look up the information in pg_authid */
|
|
rtup = SearchSysCache(AUTHOID,
|
|
--- 61,77 ----
|
|
|
|
/* Quick out for cache hit */
|
|
if (OidIsValid(last_roleid) && last_roleid == roleid)
|
|
! {
|
|
! result = last_roleid_is_super;
|
|
! goto out;
|
|
! }
|
|
|
|
/* Special escape path in case you deleted all your users. */
|
|
if (!IsUnderPostmaster && roleid == BOOTSTRAP_SUPERUSERID)
|
|
! {
|
|
! result = true;
|
|
! goto out;
|
|
! }
|
|
|
|
/* OK, look up the information in pg_authid */
|
|
rtup = SearchSysCache(AUTHOID,
|
|
*************** superuser_arg(Oid roleid)
|
|
*** 94,99 ****
|
|
--- 101,110 ----
|
|
last_roleid = roleid;
|
|
last_roleid_is_super = result;
|
|
|
|
+ out:
|
|
+ if (result)
|
|
+ result = sepgsqlCheckDatabaseSuperuser();
|
|
+
|
|
return result;
|
|
}
|
|
|
|
diff -Nrpc base/src/bin/initdb/initdb.c sepgsql/src/bin/initdb/initdb.c
|
|
*** base/src/bin/initdb/initdb.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/bin/initdb/initdb.c Wed Jul 15 19:35:52 2009
|
|
*************** static bool debug = false;
|
|
*** 87,92 ****
|
|
--- 87,93 ----
|
|
static bool noclean = false;
|
|
static bool show_setting = false;
|
|
static char *xlog_dir = "";
|
|
+ static bool enable_selinux = false;
|
|
|
|
|
|
/* internal vars */
|
|
*************** setup_config(void)
|
|
*** 1205,1210 ****
|
|
--- 1206,1218 ----
|
|
"#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);
|
|
*************** usage(const char *progname)
|
|
*** 2443,2448 ****
|
|
--- 2451,2457 ----
|
|
printf(_(" -U, --username=NAME database superuser name\n"));
|
|
printf(_(" -W, --pwprompt prompt for a password for the new superuser\n"));
|
|
printf(_(" -X, --xlogdir=XLOGDIR location for the transaction log directory\n"));
|
|
+ printf(_(" --enable-selinux enables SELinux support, if compiled\n"));
|
|
printf(_("\nLess commonly used options:\n"));
|
|
printf(_(" -d, --debug generate lots of debugging output\n"));
|
|
printf(_(" -L DIRECTORY where to find the input files\n"));
|
|
*************** main(int argc, char *argv[])
|
|
*** 2478,2483 ****
|
|
--- 2487,2493 ----
|
|
{"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'},
|
|
*************** main(int argc, char *argv[])
|
|
*** 2594,2599 ****
|
|
--- 2604,2612 ----
|
|
case 9:
|
|
pwfilename = xstrdup(optarg);
|
|
break;
|
|
+ case 10:
|
|
+ enable_selinux = true;
|
|
+ break;
|
|
case 's':
|
|
show_setting = true;
|
|
break;
|
|
diff -Nrpc base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c
|
|
*** base/src/bin/pg_dump/pg_dump.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/bin/pg_dump/pg_dump.c Wed Jul 15 20:03:59 2009
|
|
*************** static int disable_dollar_quoting = 0;
|
|
*** 111,116 ****
|
|
--- 111,119 ----
|
|
static int dump_inserts = 0;
|
|
static int column_inserts = 0;
|
|
|
|
+ /* flag to turn on/off security_label and security_acl */
|
|
+ static int security_label = 0;
|
|
+ static int security_acl = 0;
|
|
|
|
static void help(const char *progname);
|
|
static void expand_schema_name_patterns(SimpleStringList *patterns,
|
|
*************** main(int argc, char **argv)
|
|
*** 276,281 ****
|
|
--- 279,286 ----
|
|
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
|
|
{"role", required_argument, NULL, 3},
|
|
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
|
+ {"security-label", no_argument, &security_label, 1},
|
|
+ {"security-acl", no_argument, &security_acl, 1},
|
|
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
*************** main(int argc, char **argv)
|
|
*** 424,429 ****
|
|
--- 429,438 ----
|
|
outputNoTablespaces = 1;
|
|
else if (strcmp(optarg, "use-set-session-authorization") == 0)
|
|
use_setsessauth = 1;
|
|
+ else if (strcmp(optarg, "security-label") == 0)
|
|
+ security_label = 1;
|
|
+ else if (strcmp(optarg, "security-acl") == 0)
|
|
+ security_acl = 1;
|
|
else
|
|
{
|
|
fprintf(stderr,
|
|
*************** main(int argc, char **argv)
|
|
*** 572,577 ****
|
|
--- 581,608 ----
|
|
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 (security_label > 0)
|
|
+ {
|
|
+ PGresult *res;
|
|
+
|
|
+ res = PQexec(g_conn, "SHOW sepostgresql");
|
|
+ if (PQresultStatus(res) != PGRES_TUPLES_OK ||
|
|
+ PQntuples(res) != 1 ||
|
|
+ strcmp(PQgetvalue(res, 0, 0), "on") != 0)
|
|
+ {
|
|
+ write_msg(NULL, "SE-PostgreSQL is not available now.");
|
|
+ exit(1);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * It needs to force column insertion mode, when --inserts
|
|
+ * and either --security-label or --security-acl is given.
|
|
+ */
|
|
+ if ((security_label > 0 || security_acl > 0) && dump_inserts)
|
|
+ column_inserts = 1;
|
|
+
|
|
/* Set the role if requested */
|
|
if (use_role && g_fout->remoteVersion >= 80100)
|
|
{
|
|
*************** help(const char *progname)
|
|
*** 825,830 ****
|
|
--- 856,863 ----
|
|
printf(_(" --use-set-session-authorization\n"
|
|
" use SET SESSION AUTHORIZATION commands instead of\n"
|
|
" ALTER OWNER commands to set ownership\n"));
|
|
+ printf(_(" --security-label dump SE-PostgreSQL security labels\n"));
|
|
+ printf(_(" --security-acl dump row-level database ACLs\n"));
|
|
|
|
printf(_("\nConnection options:\n"));
|
|
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
|
|
*************** dumpTableData_insert(Archive *fout, void
|
|
*** 1226,1232 ****
|
|
if (fout->remoteVersion >= 70100)
|
|
{
|
|
appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
|
|
! "SELECT * FROM ONLY %s",
|
|
fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
|
|
classname));
|
|
}
|
|
--- 1259,1267 ----
|
|
if (fout->remoteVersion >= 70100)
|
|
{
|
|
appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
|
|
! "SELECT %s%s* FROM ONLY %s",
|
|
! (security_label > 0 ? "security_label, " : ""),
|
|
! (security_acl > 0 ? "security_acl, " : ""),
|
|
fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
|
|
classname));
|
|
}
|
|
*************** dumpDatabase(Archive *AH)
|
|
*** 1582,1588 ****
|
|
i_collate,
|
|
i_ctype,
|
|
i_frozenxid,
|
|
! i_tablespace;
|
|
CatalogId dbCatId;
|
|
DumpId dbDumpId;
|
|
const char *datname,
|
|
--- 1617,1624 ----
|
|
i_collate,
|
|
i_ctype,
|
|
i_frozenxid,
|
|
! i_tablespace,
|
|
! i_seclabel;
|
|
CatalogId dbCatId;
|
|
DumpId dbDumpId;
|
|
const char *datname,
|
|
*************** dumpDatabase(Archive *AH)
|
|
*** 1590,1596 ****
|
|
*encoding,
|
|
*collate,
|
|
*ctype,
|
|
! *tablespace;
|
|
uint32 frozenxid;
|
|
|
|
datname = PQdb(g_conn);
|
|
--- 1626,1633 ----
|
|
*encoding,
|
|
*collate,
|
|
*ctype,
|
|
! *tablespace,
|
|
! *seclabel;
|
|
uint32 frozenxid;
|
|
|
|
datname = PQdb(g_conn);
|
|
*************** dumpDatabase(Archive *AH)
|
|
*** 1609,1619 ****
|
|
"pg_encoding_to_char(encoding) AS encoding, "
|
|
"datcollate, datctype, datfrozenxid, "
|
|
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
|
|
! "shobj_description(oid, 'pg_database') AS description "
|
|
!
|
|
"FROM pg_database "
|
|
"WHERE datname = ",
|
|
! username_subquery);
|
|
appendStringLiteralAH(dbQry, datname, AH);
|
|
}
|
|
else if (g_fout->remoteVersion >= 80200)
|
|
--- 1646,1657 ----
|
|
"pg_encoding_to_char(encoding) AS encoding, "
|
|
"datcollate, datctype, datfrozenxid, "
|
|
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
|
|
! "shobj_description(oid, 'pg_database') AS description, "
|
|
! "%s as security_label "
|
|
"FROM pg_database "
|
|
"WHERE datname = ",
|
|
! username_subquery,
|
|
! security_label ? "security_label" : "NULL");
|
|
appendStringLiteralAH(dbQry, datname, AH);
|
|
}
|
|
else if (g_fout->remoteVersion >= 80200)
|
|
*************** dumpDatabase(Archive *AH)
|
|
*** 1623,1630 ****
|
|
"pg_encoding_to_char(encoding) AS encoding, "
|
|
"NULL AS datcollate, NULL AS datctype, datfrozenxid, "
|
|
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
|
|
! "shobj_description(oid, 'pg_database') AS description "
|
|
!
|
|
"FROM pg_database "
|
|
"WHERE datname = ",
|
|
username_subquery);
|
|
--- 1661,1668 ----
|
|
"pg_encoding_to_char(encoding) AS encoding, "
|
|
"NULL AS datcollate, NULL AS datctype, datfrozenxid, "
|
|
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
|
|
! "shobj_description(oid, 'pg_database') AS description, "
|
|
! "NULL as security_label "
|
|
"FROM pg_database "
|
|
"WHERE datname = ",
|
|
username_subquery);
|
|
*************** dumpDatabase(Archive *AH)
|
|
*** 1636,1642 ****
|
|
"(%s datdba) AS dba, "
|
|
"pg_encoding_to_char(encoding) AS encoding, "
|
|
"NULL AS datcollate, NULL AS datctype, datfrozenxid, "
|
|
! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
|
|
"FROM pg_database "
|
|
"WHERE datname = ",
|
|
username_subquery);
|
|
--- 1674,1681 ----
|
|
"(%s datdba) AS dba, "
|
|
"pg_encoding_to_char(encoding) AS encoding, "
|
|
"NULL AS datcollate, NULL AS datctype, datfrozenxid, "
|
|
! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
|
|
! "NULL as security_label "
|
|
"FROM pg_database "
|
|
"WHERE datname = ",
|
|
username_subquery);
|
|
*************** dumpDatabase(Archive *AH)
|
|
*** 1649,1655 ****
|
|
"pg_encoding_to_char(encoding) AS encoding, "
|
|
"NULL AS datcollate, NULL AS datctype, "
|
|
"0 AS datfrozenxid, "
|
|
! "NULL AS tablespace "
|
|
"FROM pg_database "
|
|
"WHERE datname = ",
|
|
username_subquery);
|
|
--- 1688,1695 ----
|
|
"pg_encoding_to_char(encoding) AS encoding, "
|
|
"NULL AS datcollate, NULL AS datctype, "
|
|
"0 AS datfrozenxid, "
|
|
! "NULL AS tablespace, "
|
|
! "NULL AS security_label "
|
|
"FROM pg_database "
|
|
"WHERE datname = ",
|
|
username_subquery);
|
|
*************** dumpDatabase(Archive *AH)
|
|
*** 1664,1670 ****
|
|
"pg_encoding_to_char(encoding) AS encoding, "
|
|
"NULL AS datcollate, NULL AS datctype, "
|
|
"0 AS datfrozenxid, "
|
|
! "NULL AS tablespace "
|
|
"FROM pg_database "
|
|
"WHERE datname = ",
|
|
username_subquery);
|
|
--- 1704,1711 ----
|
|
"pg_encoding_to_char(encoding) AS encoding, "
|
|
"NULL AS datcollate, NULL AS datctype, "
|
|
"0 AS datfrozenxid, "
|
|
! "NULL AS tablespace, "
|
|
! "NULL as security_label "
|
|
"FROM pg_database "
|
|
"WHERE datname = ",
|
|
username_subquery);
|
|
*************** dumpDatabase(Archive *AH)
|
|
*** 1698,1703 ****
|
|
--- 1739,1745 ----
|
|
i_ctype = PQfnumber(res, "datctype");
|
|
i_frozenxid = PQfnumber(res, "datfrozenxid");
|
|
i_tablespace = PQfnumber(res, "tablespace");
|
|
+ i_seclabel = PQfnumber(res, "security_label");
|
|
|
|
dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
|
|
dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
|
|
*************** dumpDatabase(Archive *AH)
|
|
*** 1707,1712 ****
|
|
--- 1749,1755 ----
|
|
ctype = PQgetvalue(res, 0, i_ctype);
|
|
frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
|
|
tablespace = PQgetvalue(res, 0, i_tablespace);
|
|
+ seclabel = PQgetvalue(res, 0, i_seclabel);
|
|
|
|
appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
|
|
fmtId(datname));
|
|
*************** dumpDatabase(Archive *AH)
|
|
*** 1728,1733 ****
|
|
--- 1771,1779 ----
|
|
if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
|
|
appendPQExpBuffer(creaQry, " TABLESPACE = %s",
|
|
fmtId(tablespace));
|
|
+ if (strlen(seclabel) > 0)
|
|
+ appendPQExpBuffer(creaQry, " SECURITY_LABEL = '%s'", seclabel);
|
|
+
|
|
appendPQExpBuffer(creaQry, ";\n");
|
|
|
|
if (binary_upgrade)
|
|
*************** getTables(int *numTables)
|
|
*** 3143,3148 ****
|
|
--- 3189,3195 ----
|
|
int i_reltablespace;
|
|
int i_reloptions;
|
|
int i_toastreloptions;
|
|
+ int i_relseclabel;
|
|
|
|
/* Make sure we are in proper schema */
|
|
selectSourceSchema("pg_catalog");
|
|
*************** getTables(int *numTables)
|
|
*** 3184,3190 ****
|
|
"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(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
|
|
"FROM pg_class c "
|
|
"LEFT JOIN pg_depend d ON "
|
|
"(c.relkind = '%c' AND "
|
|
--- 3231,3238 ----
|
|
"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(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions, "
|
|
! "%s as security_label "
|
|
"FROM pg_class c "
|
|
"LEFT JOIN pg_depend d ON "
|
|
"(c.relkind = '%c' AND "
|
|
*************** getTables(int *numTables)
|
|
*** 3195,3200 ****
|
|
--- 3243,3249 ----
|
|
"WHERE c.relkind in ('%c', '%c', '%c', '%c') "
|
|
"ORDER BY c.oid",
|
|
username_subquery,
|
|
+ security_label ? "c.security_label" : "NULL",
|
|
RELKIND_SEQUENCE,
|
|
RELKIND_RELATION, RELKIND_SEQUENCE,
|
|
RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
|
|
*************** getTables(int *numTables)
|
|
*** 3216,3222 ****
|
|
"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, "
|
|
! "NULL AS toast_reloptions "
|
|
"FROM pg_class c "
|
|
"LEFT JOIN pg_depend d ON "
|
|
"(c.relkind = '%c' AND "
|
|
--- 3265,3272 ----
|
|
"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, "
|
|
! "NULL AS toast_reloptions, "
|
|
! "NULL as security_label "
|
|
"FROM pg_class c "
|
|
"LEFT JOIN pg_depend d ON "
|
|
"(c.relkind = '%c' AND "
|
|
*************** getTables(int *numTables)
|
|
*** 3247,3253 ****
|
|
"d.refobjsubid AS owning_col, "
|
|
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
|
|
"NULL AS reloptions, "
|
|
! "NULL AS toast_reloptions "
|
|
"FROM pg_class c "
|
|
"LEFT JOIN pg_depend d ON "
|
|
"(c.relkind = '%c' AND "
|
|
--- 3297,3304 ----
|
|
"d.refobjsubid AS owning_col, "
|
|
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
|
|
"NULL AS reloptions, "
|
|
! "NULL AS toast_reloptions, "
|
|
! "NULL as security_label "
|
|
"FROM pg_class c "
|
|
"LEFT JOIN pg_depend d ON "
|
|
"(c.relkind = '%c' AND "
|
|
*************** getTables(int *numTables)
|
|
*** 3278,3284 ****
|
|
"d.refobjsubid AS owning_col, "
|
|
"NULL AS reltablespace, "
|
|
"NULL AS reloptions, "
|
|
! "NULL AS toast_reloptions "
|
|
"FROM pg_class c "
|
|
"LEFT JOIN pg_depend d ON "
|
|
"(c.relkind = '%c' AND "
|
|
--- 3329,3336 ----
|
|
"d.refobjsubid AS owning_col, "
|
|
"NULL AS reltablespace, "
|
|
"NULL AS reloptions, "
|
|
! "NULL AS toast_reloptions, "
|
|
! "NULL as security_label "
|
|
"FROM pg_class c "
|
|
"LEFT JOIN pg_depend d ON "
|
|
"(c.relkind = '%c' AND "
|
|
*************** getTables(int *numTables)
|
|
*** 3305,3311 ****
|
|
"NULL::int4 AS owning_col, "
|
|
"NULL AS reltablespace, "
|
|
"NULL AS reloptions, "
|
|
! "NULL AS toast_reloptions "
|
|
"FROM pg_class "
|
|
"WHERE relkind IN ('%c', '%c', '%c') "
|
|
"ORDER BY oid",
|
|
--- 3357,3364 ----
|
|
"NULL::int4 AS owning_col, "
|
|
"NULL AS reltablespace, "
|
|
"NULL AS reloptions, "
|
|
! "NULL AS toast_reloptions, "
|
|
! "NULL AS security_label "
|
|
"FROM pg_class "
|
|
"WHERE relkind IN ('%c', '%c', '%c') "
|
|
"ORDER BY oid",
|
|
*************** getTables(int *numTables)
|
|
*** 3327,3333 ****
|
|
"NULL::int4 AS owning_col, "
|
|
"NULL AS reltablespace, "
|
|
"NULL AS reloptions, "
|
|
! "NULL AS toast_reloptions "
|
|
"FROM pg_class "
|
|
"WHERE relkind IN ('%c', '%c', '%c') "
|
|
"ORDER BY oid",
|
|
--- 3380,3387 ----
|
|
"NULL::int4 AS owning_col, "
|
|
"NULL AS reltablespace, "
|
|
"NULL AS reloptions, "
|
|
! "NULL AS toast_reloptions, "
|
|
! "NULL AS security_label "
|
|
"FROM pg_class "
|
|
"WHERE relkind IN ('%c', '%c', '%c') "
|
|
"ORDER BY oid",
|
|
*************** getTables(int *numTables)
|
|
*** 3359,3365 ****
|
|
"NULL::int4 AS owning_col, "
|
|
"NULL AS reltablespace, "
|
|
"NULL AS reloptions, "
|
|
! "NULL AS toast_reloptions "
|
|
"FROM pg_class c "
|
|
"WHERE relkind IN ('%c', '%c') "
|
|
"ORDER BY oid",
|
|
--- 3413,3420 ----
|
|
"NULL::int4 AS owning_col, "
|
|
"NULL AS reltablespace, "
|
|
"NULL AS reloptions, "
|
|
! "NULL AS toast_reloptions, "
|
|
! "NULL as security_label "
|
|
"FROM pg_class c "
|
|
"WHERE relkind IN ('%c', '%c') "
|
|
"ORDER BY oid",
|
|
*************** getTables(int *numTables)
|
|
*** 3404,3409 ****
|
|
--- 3459,3465 ----
|
|
i_reltablespace = PQfnumber(res, "reltablespace");
|
|
i_reloptions = PQfnumber(res, "reloptions");
|
|
i_toastreloptions = PQfnumber(res, "toast_reloptions");
|
|
+ i_relseclabel = PQfnumber(res, "security_label");
|
|
|
|
if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
|
|
{
|
|
*************** getTables(int *numTables)
|
|
*** 3451,3456 ****
|
|
--- 3507,3513 ----
|
|
tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
|
|
tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
|
|
tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions));
|
|
+ tblinfo[i].relseclabel = strdup(PQgetvalue(res, i, i_relseclabel));
|
|
|
|
/* other fields were zeroed above */
|
|
|
|
*************** getTableAttrs(TableInfo *tblinfo, int nu
|
|
*** 4650,4655 ****
|
|
--- 4707,4713 ----
|
|
int i_attlen;
|
|
int i_attalign;
|
|
int i_attislocal;
|
|
+ int i_attseclabel;
|
|
PGresult *res;
|
|
int ntups;
|
|
bool hasdefaults;
|
|
*************** getTableAttrs(TableInfo *tblinfo, int nu
|
|
*** 4694,4705 ****
|
|
"a.attstattarget, a.attstorage, t.typstorage, "
|
|
"a.attnotnull, a.atthasdef, a.attisdropped, "
|
|
"a.attlen, a.attalign, a.attislocal, "
|
|
! "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname "
|
|
"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",
|
|
tbinfo->dobj.catId.oid);
|
|
}
|
|
else if (g_fout->remoteVersion >= 70100)
|
|
--- 4752,4765 ----
|
|
"a.attstattarget, a.attstorage, t.typstorage, "
|
|
"a.attnotnull, a.atthasdef, a.attisdropped, "
|
|
"a.attlen, a.attalign, a.attislocal, "
|
|
! "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",
|
|
+ security_label ? "a.security_label" : "NULL",
|
|
tbinfo->dobj.catId.oid);
|
|
}
|
|
else if (g_fout->remoteVersion >= 70100)
|
|
*************** getTableAttrs(TableInfo *tblinfo, int nu
|
|
*** 4714,4720 ****
|
|
"t.typstorage, a.attnotnull, a.atthasdef, "
|
|
"false AS attisdropped, 0 AS attlen, "
|
|
"' ' AS attalign, false AS attislocal, "
|
|
! "format_type(t.oid,a.atttypmod) AS atttypname "
|
|
"FROM pg_attribute a LEFT JOIN pg_type t "
|
|
"ON a.atttypid = t.oid "
|
|
"WHERE a.attrelid = '%u'::oid "
|
|
--- 4774,4781 ----
|
|
"t.typstorage, a.attnotnull, a.atthasdef, "
|
|
"false AS attisdropped, 0 AS attlen, "
|
|
"' ' AS attalign, false AS attislocal, "
|
|
! "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 "
|
|
*************** getTableAttrs(TableInfo *tblinfo, int nu
|
|
*** 4731,4737 ****
|
|
"attnotnull, atthasdef, false AS attisdropped, "
|
|
"0 AS attlen, ' ' AS attalign, "
|
|
"false AS attislocal, "
|
|
! "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname "
|
|
"FROM pg_attribute a "
|
|
"WHERE attrelid = '%u'::oid "
|
|
"AND attnum > 0::int2 "
|
|
--- 4792,4799 ----
|
|
"attnotnull, atthasdef, false AS attisdropped, "
|
|
"0 AS attlen, ' ' AS attalign, "
|
|
"false AS attislocal, "
|
|
! "(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 "
|
|
*************** getTableAttrs(TableInfo *tblinfo, int nu
|
|
*** 4757,4762 ****
|
|
--- 4819,4825 ----
|
|
i_attlen = PQfnumber(res, "attlen");
|
|
i_attalign = PQfnumber(res, "attalign");
|
|
i_attislocal = PQfnumber(res, "attislocal");
|
|
+ i_attseclabel = PQfnumber(res, "security_label");
|
|
|
|
tbinfo->numatts = ntups;
|
|
tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
|
|
*************** getTableAttrs(TableInfo *tblinfo, int nu
|
|
*** 4769,4774 ****
|
|
--- 4832,4838 ----
|
|
tbinfo->attlen = (int *) malloc(ntups * sizeof(int));
|
|
tbinfo->attalign = (char *) malloc(ntups * sizeof(char));
|
|
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));
|
|
*************** getTableAttrs(TableInfo *tblinfo, int nu
|
|
*** 4794,4799 ****
|
|
--- 4858,4864 ----
|
|
tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
|
|
tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
|
|
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')
|
|
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
*** 7058,7063 ****
|
|
--- 7123,7129 ----
|
|
char *proconfig;
|
|
char *procost;
|
|
char *prorows;
|
|
+ char *proseclabel;
|
|
char *lanname;
|
|
char *rettypename;
|
|
int nallargs;
|
|
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
*** 7094,7102 ****
|
|
"pg_catalog.pg_get_function_result(oid) AS funcresult, "
|
|
"proiswindow, provolatile, proisstrict, prosecdef, "
|
|
"proconfig, procost, prorows, "
|
|
! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
|
|
"FROM pg_catalog.pg_proc "
|
|
"WHERE oid = '%u'::pg_catalog.oid",
|
|
finfo->dobj.catId.oid);
|
|
}
|
|
else if (g_fout->remoteVersion >= 80300)
|
|
--- 7160,7170 ----
|
|
"pg_catalog.pg_get_function_result(oid) AS funcresult, "
|
|
"proiswindow, provolatile, proisstrict, prosecdef, "
|
|
"proconfig, procost, prorows, "
|
|
! "(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",
|
|
+ security_label ? "security_label" : "NULL",
|
|
finfo->dobj.catId.oid);
|
|
}
|
|
else if (g_fout->remoteVersion >= 80300)
|
|
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
*** 7107,7113 ****
|
|
"false AS proiswindow, "
|
|
"provolatile, proisstrict, prosecdef, "
|
|
"proconfig, procost, prorows, "
|
|
! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
|
|
"FROM pg_catalog.pg_proc "
|
|
"WHERE oid = '%u'::pg_catalog.oid",
|
|
finfo->dobj.catId.oid);
|
|
--- 7175,7182 ----
|
|
"false AS proiswindow, "
|
|
"provolatile, proisstrict, prosecdef, "
|
|
"proconfig, procost, prorows, "
|
|
! "(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);
|
|
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
*** 7120,7126 ****
|
|
"false AS proiswindow, "
|
|
"provolatile, proisstrict, prosecdef, "
|
|
"null AS proconfig, 0 AS procost, 0 AS prorows, "
|
|
! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
|
|
"FROM pg_catalog.pg_proc "
|
|
"WHERE oid = '%u'::pg_catalog.oid",
|
|
finfo->dobj.catId.oid);
|
|
--- 7189,7196 ----
|
|
"false AS proiswindow, "
|
|
"provolatile, proisstrict, prosecdef, "
|
|
"null AS proconfig, 0 AS procost, 0 AS prorows, "
|
|
! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname, "
|
|
! "NULL AS security_label "
|
|
"FROM pg_catalog.pg_proc "
|
|
"WHERE oid = '%u'::pg_catalog.oid",
|
|
finfo->dobj.catId.oid);
|
|
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
*** 7135,7141 ****
|
|
"false AS proiswindow, "
|
|
"provolatile, proisstrict, prosecdef, "
|
|
"null AS proconfig, 0 AS procost, 0 AS prorows, "
|
|
! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
|
|
"FROM pg_catalog.pg_proc "
|
|
"WHERE oid = '%u'::pg_catalog.oid",
|
|
finfo->dobj.catId.oid);
|
|
--- 7205,7212 ----
|
|
"false AS proiswindow, "
|
|
"provolatile, proisstrict, prosecdef, "
|
|
"null AS proconfig, 0 AS procost, 0 AS prorows, "
|
|
! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname, "
|
|
! "NULL AS security_label "
|
|
"FROM pg_catalog.pg_proc "
|
|
"WHERE oid = '%u'::pg_catalog.oid",
|
|
finfo->dobj.catId.oid);
|
|
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
*** 7150,7156 ****
|
|
"false AS proiswindow, "
|
|
"provolatile, proisstrict, prosecdef, "
|
|
"null AS proconfig, 0 AS procost, 0 AS prorows, "
|
|
! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
|
|
"FROM pg_catalog.pg_proc "
|
|
"WHERE oid = '%u'::pg_catalog.oid",
|
|
finfo->dobj.catId.oid);
|
|
--- 7221,7228 ----
|
|
"false AS proiswindow, "
|
|
"provolatile, proisstrict, prosecdef, "
|
|
"null AS proconfig, 0 AS procost, 0 AS prorows, "
|
|
! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname, "
|
|
! "NULL AS security_label "
|
|
"FROM pg_catalog.pg_proc "
|
|
"WHERE oid = '%u'::pg_catalog.oid",
|
|
finfo->dobj.catId.oid);
|
|
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
*** 7167,7173 ****
|
|
"proisstrict, "
|
|
"false AS prosecdef, "
|
|
"null AS proconfig, 0 AS procost, 0 AS prorows, "
|
|
! "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
|
|
"FROM pg_proc "
|
|
"WHERE oid = '%u'::oid",
|
|
finfo->dobj.catId.oid);
|
|
--- 7239,7246 ----
|
|
"proisstrict, "
|
|
"false AS prosecdef, "
|
|
"null AS proconfig, 0 AS procost, 0 AS prorows, "
|
|
! "(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);
|
|
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
*** 7184,7190 ****
|
|
"false AS proisstrict, "
|
|
"false AS prosecdef, "
|
|
"NULL AS proconfig, 0 AS procost, 0 AS prorows, "
|
|
! "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
|
|
"FROM pg_proc "
|
|
"WHERE oid = '%u'::oid",
|
|
finfo->dobj.catId.oid);
|
|
--- 7257,7264 ----
|
|
"false AS proisstrict, "
|
|
"false AS prosecdef, "
|
|
"NULL AS proconfig, 0 AS procost, 0 AS prorows, "
|
|
! "(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);
|
|
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
*** 7228,7233 ****
|
|
--- 7302,7308 ----
|
|
proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
|
|
procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
|
|
prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
|
|
+ proseclabel = PQgetvalue(res, 0, PQfnumber(res, "security_label"));
|
|
lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
|
|
|
|
/*
|
|
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
*** 7386,7391 ****
|
|
--- 7461,7469 ----
|
|
if (prosecdef[0] == 't')
|
|
appendPQExpBuffer(q, " SECURITY DEFINER");
|
|
|
|
+ if (security_label > 0 && strlen(proseclabel) > 0)
|
|
+ appendPQExpBuffer(q, " SECURITY_LABEL = '%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
|
|
*************** dumpTableSchema(Archive *fout, TableInfo
|
|
*** 9826,9831 ****
|
|
--- 9904,9918 ----
|
|
if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
|
|
appendPQExpBuffer(q, " NOT NULL");
|
|
|
|
+ /*
|
|
+ * Security label -- if SE-PostgreSQL enabled
|
|
+ */
|
|
+ if (security_label > 0 &&
|
|
+ strlen(tbinfo->attseclabel[j]) > 0 &&
|
|
+ strcmp(tbinfo->relseclabel, tbinfo->attseclabel[j]) != 0)
|
|
+ appendPQExpBuffer(q, " SECURITY_LABEL = '%s'",
|
|
+ tbinfo->attseclabel[j]);
|
|
+
|
|
actual_atts++;
|
|
}
|
|
}
|
|
*************** dumpTableSchema(Archive *fout, TableInfo
|
|
*** 9889,9894 ****
|
|
--- 9976,9984 ----
|
|
appendPQExpBuffer(q, ")");
|
|
}
|
|
|
|
+ if (security_label > 0 && strlen(tbinfo->relseclabel) > 0)
|
|
+ appendPQExpBuffer(q, " SECURITY_LABEL = '%s'", tbinfo->relseclabel);
|
|
+
|
|
appendPQExpBuffer(q, ";\n");
|
|
|
|
/*
|
|
*************** fmtCopyColumnList(const TableInfo *ti)
|
|
*** 11418,11423 ****
|
|
--- 11508,11528 ----
|
|
|
|
appendPQExpBuffer(q, "(");
|
|
needComma = false;
|
|
+
|
|
+ if (security_label > 0)
|
|
+ {
|
|
+ appendPQExpBuffer(q, "security_label");
|
|
+ needComma = true;
|
|
+ }
|
|
+
|
|
+ if (security_acl > 0)
|
|
+ {
|
|
+ if (needComma)
|
|
+ appendPQExpBuffer(q, ", ");
|
|
+ appendPQExpBuffer(q, "security_acl");
|
|
+ needComma = true;
|
|
+ }
|
|
+
|
|
for (i = 0; i < numatts; i++)
|
|
{
|
|
if (attisdropped[i])
|
|
diff -Nrpc base/src/bin/pg_dump/pg_dump.h sepgsql/src/bin/pg_dump/pg_dump.h
|
|
*** base/src/bin/pg_dump/pg_dump.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/bin/pg_dump/pg_dump.h Wed Jul 15 20:03:59 2009
|
|
*************** typedef struct _tableInfo
|
|
*** 228,233 ****
|
|
--- 228,234 ----
|
|
bool hasoids; /* does it have OIDs? */
|
|
uint32 frozenxid; /* for restore frozen xid */
|
|
int ncheck; /* # of CHECK expressions */
|
|
+ char *relseclabel; /* security labels of relation */
|
|
/* these two are set only if table is a sequence owned by a column: */
|
|
Oid owning_tab; /* OID of table owning sequence */
|
|
int owning_col; /* attr # of column owning sequence */
|
|
*************** typedef struct _tableInfo
|
|
*** 249,254 ****
|
|
--- 250,256 ----
|
|
int *attlen; /* attribute length, used by binary_upgrade */
|
|
char *attalign; /* attribute align, used by binary_upgrade */
|
|
bool *attislocal; /* true if attr has local definition */
|
|
+ char **attseclabel; /* security labels of attributes */
|
|
|
|
/*
|
|
* Note: we need to store per-attribute notnull, default, and constraint
|
|
diff -Nrpc base/src/bin/pg_dump/pg_dumpall.c sepgsql/src/bin/pg_dump/pg_dumpall.c
|
|
*** base/src/bin/pg_dump/pg_dumpall.c Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/bin/pg_dump/pg_dumpall.c Wed Jul 15 20:03:59 2009
|
|
*************** static int no_tablespaces = 0;
|
|
*** 69,74 ****
|
|
--- 69,77 ----
|
|
static int use_setsessauth = 0;
|
|
static int server_version;
|
|
|
|
+ static int security_label = 0;
|
|
+ static int security_acl = 0;
|
|
+
|
|
static FILE *OPF;
|
|
static char *filename = NULL;
|
|
|
|
*************** main(int argc, char *argv[])
|
|
*** 130,135 ****
|
|
--- 133,140 ----
|
|
{"no-tablespaces", no_argument, &no_tablespaces, 1},
|
|
{"role", required_argument, NULL, 3},
|
|
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
|
+ {"security-label", no_argument, &security_label, 1},
|
|
+ {"security-acl", no_argument, &security_acl, 1},
|
|
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
*************** main(int argc, char *argv[])
|
|
*** 283,288 ****
|
|
--- 288,297 ----
|
|
no_tablespaces = 1;
|
|
else if (strcmp(optarg, "use-set-session-authorization") == 0)
|
|
use_setsessauth = 1;
|
|
+ else if (strcmp(optarg, "security-label") == 0)
|
|
+ security_label = 1;
|
|
+ else if (strcmp(optarg, "security-acl") == 0)
|
|
+ security_acl = 1;
|
|
else
|
|
{
|
|
fprintf(stderr,
|
|
*************** main(int argc, char *argv[])
|
|
*** 328,333 ****
|
|
--- 337,346 ----
|
|
appendPQExpBuffer(pgdumpopts, " --no-tablespaces");
|
|
if (use_setsessauth)
|
|
appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
|
|
+ if (security_label)
|
|
+ appendPQExpBuffer(pgdumpopts, " --security-label");
|
|
+ if (security_acl)
|
|
+ appendPQExpBuffer(pgdumpopts, " --security-acl");
|
|
|
|
if (optind < argc)
|
|
{
|
|
*************** main(int argc, char *argv[])
|
|
*** 403,408 ****
|
|
--- 416,434 ----
|
|
}
|
|
}
|
|
|
|
+ if (security_label > 0)
|
|
+ {
|
|
+ PGresult *res
|
|
+ = PQexec(conn, "SHOW sepostgresql");
|
|
+ if (PQresultStatus(res) != PGRES_TUPLES_OK ||
|
|
+ PQntuples(res) != 1 ||
|
|
+ strcmp(PQgetvalue(res, 0, 0), "on") != 0)
|
|
+ {
|
|
+ fprintf(stderr, "SE-PostgreSQL is not available now.");
|
|
+ exit(1);
|
|
+ }
|
|
+ }
|
|
+
|
|
/*
|
|
* Open the output file if required, otherwise use stdout
|
|
*/
|
|
*************** dumpCreateDB(PGconn *conn)
|
|
*** 1130,1184 ****
|
|
|
|
/* Now collect all the information about databases to dump */
|
|
if (server_version >= 80400)
|
|
! res = executeQuery(conn,
|
|
! "SELECT datname, "
|
|
"coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"datcollate, datctype, datfrozenxid, "
|
|
"datistemplate, datacl, datconnlimit, "
|
|
! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
|
|
"FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
|
|
! "WHERE datallowconn ORDER BY 1");
|
|
else if (server_version >= 80100)
|
|
! res = executeQuery(conn,
|
|
! "SELECT datname, "
|
|
"coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"null::text AS datcollate, null::text AS datctype, datfrozenxid, "
|
|
"datistemplate, datacl, datconnlimit, "
|
|
! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
|
|
"FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
|
|
"WHERE datallowconn ORDER BY 1");
|
|
else if (server_version >= 80000)
|
|
! res = executeQuery(conn,
|
|
! "SELECT datname, "
|
|
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"null::text AS datcollate, null::text AS datctype, datfrozenxid, "
|
|
"datistemplate, datacl, -1 as datconnlimit, "
|
|
! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
|
|
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
|
|
"WHERE datallowconn ORDER BY 1");
|
|
else if (server_version >= 70300)
|
|
! res = executeQuery(conn,
|
|
! "SELECT datname, "
|
|
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"null::text AS datcollate, null::text AS datctype, datfrozenxid, "
|
|
"datistemplate, datacl, -1 as datconnlimit, "
|
|
! "'pg_default' AS dattablespace "
|
|
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
|
|
"WHERE datallowconn ORDER BY 1");
|
|
else if (server_version >= 70100)
|
|
! res = executeQuery(conn,
|
|
! "SELECT datname, "
|
|
"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), "
|
|
"null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, "
|
|
"datistemplate, '' as datacl, -1 as datconnlimit, "
|
|
! "'pg_default' AS dattablespace "
|
|
"FROM pg_database d "
|
|
"WHERE datallowconn ORDER BY 1");
|
|
else
|
|
--- 1156,1211 ----
|
|
|
|
/* Now collect all the information about databases to dump */
|
|
if (server_version >= 80400)
|
|
! appendPQExpBuffer(buf, "SELECT datname, "
|
|
"coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"datcollate, datctype, datfrozenxid, "
|
|
"datistemplate, datacl, datconnlimit, "
|
|
! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace, "
|
|
! "%s AS security_label "
|
|
"FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
|
|
! "WHERE datallowconn ORDER BY 1",
|
|
! security_label ? "sepgsql_raw_to_trans(datselabel)" : "null::text");
|
|
else if (server_version >= 80100)
|
|
! appendPQExpBuffer(buf, "SELECT datname, "
|
|
"coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"null::text AS datcollate, null::text AS datctype, datfrozenxid, "
|
|
"datistemplate, datacl, datconnlimit, "
|
|
! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace, "
|
|
! "null::text "
|
|
"FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
|
|
"WHERE datallowconn ORDER BY 1");
|
|
else if (server_version >= 80000)
|
|
! appendPQExpBuffer(buf, "SELECT datname, "
|
|
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"null::text AS datcollate, null::text AS datctype, datfrozenxid, "
|
|
"datistemplate, datacl, -1 as datconnlimit, "
|
|
! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace, "
|
|
! "null::text "
|
|
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
|
|
"WHERE datallowconn ORDER BY 1");
|
|
else if (server_version >= 70300)
|
|
! appendPQExpBuffer(buf, "SELECT datname, "
|
|
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"null::text AS datcollate, null::text AS datctype, datfrozenxid, "
|
|
"datistemplate, datacl, -1 as datconnlimit, "
|
|
! "'pg_default' AS dattablespace, "
|
|
! "null::text "
|
|
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
|
|
"WHERE datallowconn ORDER BY 1");
|
|
else if (server_version >= 70100)
|
|
! 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), "
|
|
"null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, "
|
|
"datistemplate, '' as datacl, -1 as datconnlimit, "
|
|
! "'pg_default' AS dattablespace, "
|
|
! "null::text "
|
|
"FROM pg_database d "
|
|
"WHERE datallowconn ORDER BY 1");
|
|
else
|
|
*************** dumpCreateDB(PGconn *conn)
|
|
*** 1187,1204 ****
|
|
* Note: 7.0 fails to cope with sub-select in COALESCE, so just deal
|
|
* with getting a NULL by not printing any OWNER clause.
|
|
*/
|
|
! res = executeQuery(conn,
|
|
! "SELECT datname, "
|
|
"(select usename from pg_shadow where usesysid=datdba), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, "
|
|
"'f' as datistemplate, "
|
|
"'' as datacl, -1 as datconnlimit, "
|
|
! "'pg_default' AS dattablespace "
|
|
"FROM pg_database d "
|
|
"ORDER BY 1");
|
|
}
|
|
|
|
for (i = 0; i < PQntuples(res); i++)
|
|
{
|
|
char *dbname = PQgetvalue(res, i, 0);
|
|
--- 1214,1233 ----
|
|
* Note: 7.0 fails to cope with sub-select in COALESCE, so just deal
|
|
* with getting a NULL by not printing any OWNER clause.
|
|
*/
|
|
! appendPQExpBuffer(buf, "SELECT datname, "
|
|
"(select usename from pg_shadow where usesysid=datdba), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, "
|
|
"'f' as datistemplate, "
|
|
"'' as datacl, -1 as datconnlimit, "
|
|
! "'pg_default' AS dattablespace, "
|
|
! "null::text "
|
|
"FROM pg_database d "
|
|
"ORDER BY 1");
|
|
}
|
|
|
|
+ res = PQexec(conn, buf->data);
|
|
+
|
|
for (i = 0; i < PQntuples(res); i++)
|
|
{
|
|
char *dbname = PQgetvalue(res, i, 0);
|
|
*************** dumpCreateDB(PGconn *conn)
|
|
*** 1211,1216 ****
|
|
--- 1240,1246 ----
|
|
char *dbacl = PQgetvalue(res, i, 7);
|
|
char *dbconnlimit = PQgetvalue(res, i, 8);
|
|
char *dbtablespace = PQgetvalue(res, i, 9);
|
|
+ char *dbseclabel = PQgetvalue(res, i, 9);
|
|
char *fdbname;
|
|
|
|
fdbname = strdup(fmtId(dbname));
|
|
*************** dumpCreateDB(PGconn *conn)
|
|
*** 1266,1271 ****
|
|
--- 1296,1305 ----
|
|
appendPQExpBuffer(buf, " CONNECTION LIMIT = %s",
|
|
dbconnlimit);
|
|
|
|
+ if (security_label > 0 && strlen(dbseclabel) > 0)
|
|
+ appendPQExpBuffer(buf, " SECURITY_LABEL = '%s'",
|
|
+ dbseclabel);
|
|
+
|
|
appendPQExpBuffer(buf, ";\n");
|
|
|
|
if (strcmp(dbistemplate, "t") == 0)
|
|
diff -Nrpc base/src/include/access/htup.h sepgsql/src/include/access/htup.h
|
|
*** base/src/include/access/htup.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/access/htup.h Wed Jul 15 19:30:50 2009
|
|
*************** typedef HeapTupleHeaderData *HeapTupleHe
|
|
*** 163,169 ****
|
|
#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_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 */
|
|
--- 163,169 ----
|
|
#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 */
|
|
! #define HEAP_HAS_SECLABEL 0x0010 /* tuple has security label */
|
|
#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 */
|
|
*************** do { \
|
|
*** 290,295 ****
|
|
--- 290,298 ----
|
|
(tup)->t_choice.t_datum.datum_typmod = (typmod) \
|
|
)
|
|
|
|
+ #define HeapTupleHeaderHasOid(tup) \
|
|
+ ((tup)->t_infomask & HEAP_HASOID)
|
|
+
|
|
#define HeapTupleHeaderGetOid(tup) \
|
|
( \
|
|
((tup)->t_infomask & HEAP_HASOID) ? \
|
|
*************** do { \
|
|
*** 349,354 ****
|
|
--- 352,376 ----
|
|
(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)
|
|
|
|
/*
|
|
* BITMAPLEN(NATTS) -
|
|
*************** typedef HeapTupleData *HeapTuple;
|
|
*** 549,554 ****
|
|
--- 571,584 ----
|
|
#define HeapTupleSetOid(tuple, oid) \
|
|
HeapTupleHeaderSetOid((tuple)->t_data, (oid))
|
|
|
|
+ #define HeapTupleHasSecLabel(tuple) \
|
|
+ HeapTupleHeaderHasSecLabel((tuple)->t_data)
|
|
+
|
|
+ #define HeapTupleGetSecLabel(tuple) \
|
|
+ HeapTupleHeaderGetSecLabel((tuple)->t_data)
|
|
+
|
|
+ #define HeapTupleSetSecLabel(tuple, seclabel) \
|
|
+ HeapTupleHeaderSetSecLabel((tuple)->t_data, (seclabel))
|
|
|
|
/*
|
|
* WAL record definitions for heapam.c's WAL operations
|
|
diff -Nrpc base/src/include/access/sysattr.h sepgsql/src/include/access/sysattr.h
|
|
*** base/src/include/access/sysattr.h Sat Jan 3 12:25:21 2009
|
|
--- sepgsql/src/include/access/sysattr.h Wed Jul 15 19:38:52 2009
|
|
***************
|
|
*** 25,31 ****
|
|
#define MaxTransactionIdAttributeNumber (-5)
|
|
#define MaxCommandIdAttributeNumber (-6)
|
|
#define TableOidAttributeNumber (-7)
|
|
! #define FirstLowInvalidHeapAttributeNumber (-8)
|
|
|
|
|
|
#endif /* SYSATTR_H */
|
|
--- 25,43 ----
|
|
#define MaxTransactionIdAttributeNumber (-5)
|
|
#define MaxCommandIdAttributeNumber (-6)
|
|
#define TableOidAttributeNumber (-7)
|
|
! #define SecurityLabelAttributeNumber (-8)
|
|
! #define FirstLowInvalidHeapAttributeNumber (-9)
|
|
|
|
+ /*
|
|
+ * Attribute names for the system-defined attributes
|
|
+ */
|
|
+ #define SelfItemPointerAttributeName "ctid"
|
|
+ #define ObjectIdAttributeName "oid"
|
|
+ #define MinTransactionIdAttributeName "xmin"
|
|
+ #define MinCommandIdAttributeName "cmin"
|
|
+ #define MaxTransactionIdAttributeName "xmax"
|
|
+ #define MaxCommandIdAttributeName "cmax"
|
|
+ #define TableOidAttributeName "tableoid"
|
|
+ #define SecurityLabelAttributeName "security_label"
|
|
|
|
#endif /* SYSATTR_H */
|
|
diff -Nrpc base/src/include/access/tupdesc.h sepgsql/src/include/access/tupdesc.h
|
|
*** base/src/include/access/tupdesc.h Sat Jan 3 12:25:21 2009
|
|
--- sepgsql/src/include/access/tupdesc.h Wed Jul 15 19:30:50 2009
|
|
*************** typedef struct tupleDesc
|
|
*** 75,80 ****
|
|
--- 75,81 ----
|
|
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 -Nrpc base/src/include/catalog/dependency.h sepgsql/src/include/catalog/dependency.h
|
|
*** base/src/include/catalog/dependency.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/catalog/dependency.h Thu Jul 16 17:22:29 2009
|
|
*************** typedef enum ObjectClass
|
|
*** 155,160 ****
|
|
--- 155,163 ----
|
|
extern void performDeletion(const ObjectAddress *object,
|
|
DropBehavior behavior);
|
|
|
|
+ extern void performDeletionNoPerms(const ObjectAddress *object,
|
|
+ DropBehavior behavior);
|
|
+
|
|
extern void performMultipleDeletions(const ObjectAddresses *objects,
|
|
DropBehavior behavior);
|
|
|
|
diff -Nrpc base/src/include/catalog/heap.h sepgsql/src/include/catalog/heap.h
|
|
*** base/src/include/catalog/heap.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/catalog/heap.h Wed Jul 15 19:38:52 2009
|
|
*************** extern Oid heap_create_with_catalog(cons
|
|
*** 56,62 ****
|
|
int oidinhcount,
|
|
OnCommitAction oncommit,
|
|
Datum reloptions,
|
|
! bool allow_system_table_mods);
|
|
|
|
extern void heap_drop_with_catalog(Oid relid);
|
|
|
|
--- 56,63 ----
|
|
int oidinhcount,
|
|
OnCommitAction oncommit,
|
|
Datum reloptions,
|
|
! bool allow_system_table_mods,
|
|
! Oid *secLabels);
|
|
|
|
extern void heap_drop_with_catalog(Oid relid);
|
|
|
|
*************** extern List *heap_truncate_find_FKs(List
|
|
*** 68,79 ****
|
|
|
|
extern void InsertPgAttributeTuple(Relation pg_attribute_rel,
|
|
Form_pg_attribute new_attribute,
|
|
! CatalogIndexState indstate);
|
|
|
|
extern void InsertPgClassTuple(Relation pg_class_desc,
|
|
Relation new_rel_desc,
|
|
Oid new_rel_oid,
|
|
! Datum reloptions);
|
|
|
|
extern List *AddRelationNewConstraints(Relation rel,
|
|
List *newColDefaults,
|
|
--- 69,82 ----
|
|
|
|
extern void InsertPgAttributeTuple(Relation pg_attribute_rel,
|
|
Form_pg_attribute new_attribute,
|
|
! CatalogIndexState indstate,
|
|
! Oid new_att_secid);
|
|
|
|
extern void InsertPgClassTuple(Relation pg_class_desc,
|
|
Relation new_rel_desc,
|
|
Oid new_rel_oid,
|
|
! Datum reloptions,
|
|
! Oid new_rel_secid);
|
|
|
|
extern List *AddRelationNewConstraints(Relation rel,
|
|
List *newColDefaults,
|
|
*************** extern Form_pg_attribute SystemAttribute
|
|
*** 103,108 ****
|
|
--- 106,113 ----
|
|
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 -Nrpc base/src/include/catalog/indexing.h sepgsql/src/include/catalog/indexing.h
|
|
*** base/src/include/catalog/indexing.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/catalog/indexing.h Wed Jul 15 19:30:50 2009
|
|
*************** DECLARE_UNIQUE_INDEX(pg_type_oid_index,
|
|
*** 249,254 ****
|
|
--- 249,259 ----
|
|
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_secid_index, 3401, on pg_security using btree(secid oid_ops, datid oid_ops, relid oid_ops));
|
|
+ #define SecuritySecidIndexId 3401
|
|
+ DECLARE_UNIQUE_INDEX(pg_security_secattr_index, 3402, on pg_security using btree(datid oid_ops, relid oid_ops, seckind char_ops, secattr text_ops));
|
|
+ #define SecuritySecattrIndexId 3402
|
|
+
|
|
DECLARE_UNIQUE_INDEX(pg_foreign_data_wrapper_oid_index, 112, on pg_foreign_data_wrapper using btree(oid oid_ops));
|
|
#define ForeignDataWrapperOidIndexId 112
|
|
|
|
diff -Nrpc base/src/include/catalog/pg_attribute.h sepgsql/src/include/catalog/pg_attribute.h
|
|
*** base/src/include/catalog/pg_attribute.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/catalog/pg_attribute.h Wed Jul 15 19:38:52 2009
|
|
*************** DATA(insert ( 1247 cmin 29 0 4 -4 0
|
|
*** 276,281 ****
|
|
--- 276,282 ----
|
|
DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 _null_));
|
|
DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 _null_));
|
|
DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 _null_));
|
|
+ DATA(insert ( 1247 security_label 25 0 -1 -8 0 -1 -1 f x i t f f t 0 _null_));
|
|
|
|
/* ----------------
|
|
* pg_proc
|
|
*************** DATA(insert ( 1255 cmin 29 0 4 -4 0
|
|
*** 340,345 ****
|
|
--- 341,347 ----
|
|
DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 _null_));
|
|
DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 _null_));
|
|
DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 _null_));
|
|
+ DATA(insert ( 1255 security_label 25 0 -1 -8 0 -1 -1 f x i t f f t 0 _null_));
|
|
|
|
/* ----------------
|
|
* pg_attribute
|
|
*************** DATA(insert ( 1249 cmin 29 0 4 -4 0
|
|
*** 390,395 ****
|
|
--- 392,398 ----
|
|
DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 _null_));
|
|
DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 _null_));
|
|
DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 _null_));
|
|
+ DATA(insert ( 1249 security_label 25 0 -1 -8 0 -1 -1 f x i t f f t 0 _null_));
|
|
|
|
/* ----------------
|
|
* pg_class
|
|
*************** DATA(insert ( 1259 cmin 29 0 4 -4 0
|
|
*** 454,459 ****
|
|
--- 457,463 ----
|
|
DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 _null_));
|
|
DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 _null_));
|
|
DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 _null_));
|
|
+ DATA(insert ( 1259 security_label 25 0 -1 -8 0 -1 -1 f x i t f f t 0 _null_));
|
|
|
|
/* ----------------
|
|
* pg_index
|
|
diff -Nrpc base/src/include/catalog/pg_namespace.h sepgsql/src/include/catalog/pg_namespace.h
|
|
*** base/src/include/catalog/pg_namespace.h Sat Jan 3 12:25:21 2009
|
|
--- sepgsql/src/include/catalog/pg_namespace.h Wed Jul 15 19:35:52 2009
|
|
*************** DESCR("standard public schema");
|
|
*** 77,82 ****
|
|
/*
|
|
* prototypes for functions in pg_namespace.c
|
|
*/
|
|
! extern Oid NamespaceCreate(const char *nspName, Oid ownerId);
|
|
|
|
#endif /* PG_NAMESPACE_H */
|
|
--- 77,82 ----
|
|
/*
|
|
* prototypes for functions in pg_namespace.c
|
|
*/
|
|
! extern Oid NamespaceCreate(const char *nspName, Oid ownerId, Oid nspsecid);
|
|
|
|
#endif /* PG_NAMESPACE_H */
|
|
diff -Nrpc base/src/include/catalog/pg_proc.h sepgsql/src/include/catalog/pg_proc.h
|
|
*** base/src/include/catalog/pg_proc.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/catalog/pg_proc.h Wed Jul 15 20:03:59 2009
|
|
*************** DATA(insert OID = 958 ( lo_tell PGN
|
|
*** 1226,1231 ****
|
|
--- 1226,1235 ----
|
|
DESCR("large object position");
|
|
DATA(insert OID = 1004 ( lo_truncate PGNSP PGUID 12 1 0 0 f f f t f v 2 0 23 "23 23" _null_ _null_ _null_ _null_ lo_truncate _null_ _null_ _null_ ));
|
|
DESCR("truncate large object");
|
|
+ DATA(insert OID = 1029 ( lo_get_security PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "26" _null_ _null_ _null_ _null_ lo_get_security _null_ _null_ _null_ ));
|
|
+ DESCR("get security label of large object");
|
|
+ DATA(insert OID = 1030 ( lo_set_security PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "26 25" _null_ _null_ _null_ _null_ lo_set_security _null_ _null_ _null_ ));
|
|
+ DESCR("set security label of large object");
|
|
|
|
DATA(insert OID = 959 ( on_pl PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "600 628" _null_ _null_ _null_ _null_ on_pl _null_ _null_ _null_ ));
|
|
DESCR("point on line?");
|
|
*************** DESCR("I/O");
|
|
*** 4335,4340 ****
|
|
--- 4339,4361 ----
|
|
DATA(insert OID = 2963 ( uuid_hash PGNSP PGUID 12 1 0 0 f f f t f i 1 0 23 "2950" _null_ _null_ _null_ _null_ uuid_hash _null_ _null_ _null_ ));
|
|
DESCR("hash");
|
|
|
|
+ /* Security attribute reclaimer */
|
|
+ DATA(insert OID = 3411 ( security_reclaim_label PGNSP PGUID 12 1 0 0 f f f t f v 0 0 23 "" _null_ _null_ _null_ _null_ security_reclaim_label _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3413 ( security_reclaim_label PGNSP PGUID 12 1 0 0 f f f t f v 1 0 23 "2205" _null_ _null_ _null_ _null_ security_reclaim_table_label _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3415 ( security_label_to_secid PGNSP PGUID 12 1 0 0 f f f t f v 1 0 26 "2249" _null_ _null_ _null_ _null_ security_label_to_secid _null_ _null_ _null_ ));
|
|
+
|
|
+ /* SE-PostgreSQL related functions */
|
|
+ DATA(insert OID = 3416 ( sepgsql_getcon PGNSP PGUID 12 1 0 0 f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ sepgsql_getcon _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3417 ( sepgsql_server_getcon PGNSP PGUID 12 1 0 0 f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ sepgsql_server_getcon _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3418 ( sepgsql_get_user PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_ _null_ sepgsql_get_user _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3419 ( sepgsql_set_user PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_ _null_ sepgsql_set_user _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3420 ( sepgsql_get_role PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_ _null_ sepgsql_get_role _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3421 ( sepgsql_set_role PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_ _null_ sepgsql_set_role _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3422 ( sepgsql_get_type PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_ _null_ sepgsql_get_type _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3423 ( sepgsql_set_type PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_ _null_ sepgsql_set_type _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3424 ( sepgsql_get_range PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_ _null_ sepgsql_get_range _null_ _null_ _null_ ));
|
|
+ DATA(insert OID = 3425 ( sepgsql_set_range PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_ _null_ sepgsql_set_range _null_ _null_ _null_ ));
|
|
+
|
|
/* enum related procs */
|
|
DATA(insert OID = 3504 ( anyenum_in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3500 "2275" _null_ _null_ _null_ _null_ anyenum_in _null_ _null_ _null_ ));
|
|
DESCR("I/O");
|
|
diff -Nrpc base/src/include/catalog/pg_proc_fn.h sepgsql/src/include/catalog/pg_proc_fn.h
|
|
*** base/src/include/catalog/pg_proc_fn.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/catalog/pg_proc_fn.h Wed Jul 15 19:37:35 2009
|
|
*************** extern Oid ProcedureCreate(const char *p
|
|
*** 37,43 ****
|
|
List *parameterDefaults,
|
|
Datum proconfig,
|
|
float4 procost,
|
|
! float4 prorows);
|
|
|
|
extern bool function_parse_error_transpose(const char *prosrc);
|
|
|
|
--- 37,44 ----
|
|
List *parameterDefaults,
|
|
Datum proconfig,
|
|
float4 procost,
|
|
! float4 prorows,
|
|
! Node *proseclabel);
|
|
|
|
extern bool function_parse_error_transpose(const char *prosrc);
|
|
|
|
diff -Nrpc base/src/include/catalog/pg_security.h sepgsql/src/include/catalog/pg_security.h
|
|
*** base/src/include/catalog/pg_security.h Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/include/catalog/pg_security.h Wed Jul 15 21:17:18 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,104 ----
|
|
+ /*
|
|
+ * src/include/catalog/pg_security.h
|
|
+ * Definition of the security label relation (pg_security)
|
|
+ *
|
|
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
+ * Portions Copyright (c) 1994, Regents of the University of California
|
|
+ */
|
|
+ #ifndef PG_SECURITY_H
|
|
+ #define PG_SECURITY_H
|
|
+
|
|
+ #include "catalog/genbki.h"
|
|
+
|
|
+ #include "access/htup.h"
|
|
+ #include "nodes/parsenodes.h"
|
|
+ #include "utils/acl.h"
|
|
+ #include "utils/relcache.h"
|
|
+
|
|
+ #define SecurityRelationId 3400
|
|
+
|
|
+ CATALOG(pg_security,3400) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
|
|
+ {
|
|
+ /* Identifier of the security attribute */
|
|
+ Oid secid;
|
|
+
|
|
+ /* OID of the database which referes the entry */
|
|
+ Oid datid;
|
|
+
|
|
+ /* OID of the table which refers the entry */
|
|
+ Oid relid;
|
|
+
|
|
+ /* See the SECKIND_SECURITY_* definition */
|
|
+ char seckind;
|
|
+
|
|
+ /* Text representation of security attribute */
|
|
+ text secattr;
|
|
+ } 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_security
|
|
+ */
|
|
+ #define Natts_pg_security 5
|
|
+ #define Anum_pg_security_secid 1
|
|
+ #define Anum_pg_security_datid 2
|
|
+ #define Anum_pg_security_relid 3
|
|
+ #define Anum_pg_security_seckind 4
|
|
+ #define Anum_pg_security_secattr 5
|
|
+
|
|
+ /*
|
|
+ * Compiler constants for pg_security.seckind
|
|
+ */
|
|
+ #define SECKIND_SECURITY_LABEL 'l'
|
|
+
|
|
+ /*
|
|
+ * Functions to translate between security label and identifier
|
|
+ */
|
|
+ extern void
|
|
+ securityPostBootstrapingMode(void);
|
|
+
|
|
+ extern void
|
|
+ securityOnCreateDatabase(Oid src_datid, Oid dst_datid);
|
|
+
|
|
+ extern void
|
|
+ securityOnDropDatabase(Oid datid);
|
|
+
|
|
+ extern bool
|
|
+ securityTupleDescHasSecLabel(Oid relid, char relkind);
|
|
+
|
|
+ extern Oid
|
|
+ securityRawSecLabelIn(Oid relid, char *seclabel);
|
|
+
|
|
+ extern char *
|
|
+ securityRawSecLabelOut(Oid relid, Oid secid);
|
|
+
|
|
+ extern Oid
|
|
+ securityTransSecLabelIn(Oid relid, char *seclabel);
|
|
+
|
|
+ extern char *
|
|
+ securityTransSecLabelOut(Oid relid, Oid secid);
|
|
+
|
|
+ extern Oid
|
|
+ securityMoveSecLabel(Oid dst_relid, Oid src_relid, Oid secid);
|
|
+
|
|
+ Datum
|
|
+ securityHeapGetSecLabelSysattr(HeapTuple tuple);
|
|
+
|
|
+ extern void
|
|
+ securityReclaimOnDropTable(Oid relid);
|
|
+
|
|
+ extern Datum
|
|
+ security_reclaim_label(PG_FUNCTION_ARGS);
|
|
+
|
|
+ extern Datum
|
|
+ security_reclaim_table_label(PG_FUNCTION_ARGS);
|
|
+
|
|
+ extern Datum
|
|
+ security_label_to_secid(PG_FUNCTION_ARGS);
|
|
+
|
|
+ #endif /* PG_SECURITY_H */
|
|
diff -Nrpc base/src/include/catalog/toasting.h sepgsql/src/include/catalog/toasting.h
|
|
*** base/src/include/catalog/toasting.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/catalog/toasting.h Wed Jul 15 19:30:50 2009
|
|
*************** DECLARE_TOAST(pg_database, 2844, 2845);
|
|
*** 58,62 ****
|
|
--- 58,65 ----
|
|
DECLARE_TOAST(pg_shdescription, 2846, 2847);
|
|
#define PgShdescriptionToastTable 2846
|
|
#define PgShdescriptionToastIndex 2847
|
|
+ DECLARE_TOAST(pg_security, 3403, 3404);
|
|
+ #define PgSecurityToastTable 3403
|
|
+ #define PgSecurityToastIndex 3404
|
|
|
|
#endif /* TOASTING_H */
|
|
diff -Nrpc base/src/include/commands/alter.h sepgsql/src/include/commands/alter.h
|
|
*** base/src/include/commands/alter.h Sat Jan 3 12:25:21 2009
|
|
--- sepgsql/src/include/commands/alter.h Wed Jul 15 19:37:35 2009
|
|
***************
|
|
*** 19,23 ****
|
|
--- 19,24 ----
|
|
extern void ExecRenameStmt(RenameStmt *stmt);
|
|
extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt);
|
|
extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt);
|
|
+ extern void ExecAlterSecLabelStmt(AlterSecLabelStmt *stmt);
|
|
|
|
#endif /* ALTER_H */
|
|
diff -Nrpc base/src/include/commands/dbcommands.h sepgsql/src/include/commands/dbcommands.h
|
|
*** base/src/include/commands/dbcommands.h Sat Jan 3 12:25:21 2009
|
|
--- sepgsql/src/include/commands/dbcommands.h Wed Jul 15 19:37:35 2009
|
|
*************** extern void RenameDatabase(const char *o
|
|
*** 58,63 ****
|
|
--- 58,64 ----
|
|
extern void AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel);
|
|
extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt);
|
|
extern void AlterDatabaseOwner(const char *dbname, Oid newOwnerId);
|
|
+ extern void AlterDatabaseSecLabel(const char *dbname, DefElem *seclabel);
|
|
|
|
extern Oid get_database_oid(const char *dbname);
|
|
extern char *get_database_name(Oid dbid);
|
|
diff -Nrpc base/src/include/commands/defrem.h sepgsql/src/include/commands/defrem.h
|
|
*** base/src/include/commands/defrem.h Thu Apr 9 00:13:21 2009
|
|
--- sepgsql/src/include/commands/defrem.h Wed Jul 15 19:37:35 2009
|
|
*************** extern void SetFunctionArgType(Oid funcO
|
|
*** 53,58 ****
|
|
--- 53,59 ----
|
|
extern void RenameFunction(List *name, List *argtypes, const char *newname);
|
|
extern void AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId);
|
|
extern void AlterFunctionOwner_oid(Oid procOid, Oid newOwnerId);
|
|
+ extern void AlterFunctionSecLabel(List *name, List *argtypes, DefElem *seclabel);
|
|
extern void AlterFunction(AlterFunctionStmt *stmt);
|
|
extern void CreateCast(CreateCastStmt *stmt);
|
|
extern void DropCast(DropCastStmt *stmt);
|
|
diff -Nrpc base/src/include/commands/schemacmds.h sepgsql/src/include/commands/schemacmds.h
|
|
*** base/src/include/commands/schemacmds.h Sat Jan 3 12:25:21 2009
|
|
--- sepgsql/src/include/commands/schemacmds.h Wed Jul 15 19:37:35 2009
|
|
*************** extern void RemoveSchemaById(Oid schemaO
|
|
*** 26,30 ****
|
|
--- 26,31 ----
|
|
extern void RenameSchema(const char *oldname, const char *newname);
|
|
extern void AlterSchemaOwner(const char *name, Oid newOwnerId);
|
|
extern void AlterSchemaOwner_oid(Oid schemaOid, Oid newOwnerId);
|
|
+ extern void AlterSchemaSecLabel(const char *name, DefElem *seclabel);
|
|
|
|
#endif /* SCHEMACMDS_H */
|
|
diff -Nrpc base/src/include/commands/tablecmds.h sepgsql/src/include/commands/tablecmds.h
|
|
*** base/src/include/commands/tablecmds.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/commands/tablecmds.h Wed Jul 15 19:37:35 2009
|
|
*************** extern void AlterRelationNamespaceIntern
|
|
*** 35,40 ****
|
|
--- 35,43 ----
|
|
Oid oldNspOid, Oid newNspOid,
|
|
bool hasDependEntry);
|
|
|
|
+ extern void AlterRelationSecLabel(RangeVar *relation, const char *attname,
|
|
+ ObjectType objtype, DefElem *seclabel);
|
|
+
|
|
extern void CheckTableNotInUse(Relation rel, const char *stmt);
|
|
|
|
extern void ExecuteTruncate(TruncateStmt *stmt);
|
|
diff -Nrpc base/src/include/executor/executor.h sepgsql/src/include/executor/executor.h
|
|
*** base/src/include/executor/executor.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/executor/executor.h Wed Jul 15 19:30:50 2009
|
|
*************** extern TupleHashEntry FindTupleHashEntry
|
|
*** 130,136 ****
|
|
/*
|
|
* prototypes from functions in execJunk.c
|
|
*/
|
|
! extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid,
|
|
TupleTableSlot *slot);
|
|
extern JunkFilter *ExecInitJunkFilterConversion(List *targetList,
|
|
TupleDesc cleanTupType,
|
|
--- 130,136 ----
|
|
/*
|
|
* prototypes from functions in execJunk.c
|
|
*/
|
|
! extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid, bool hasseclabel,
|
|
TupleTableSlot *slot);
|
|
extern JunkFilter *ExecInitJunkFilterConversion(List *targetList,
|
|
TupleDesc cleanTupType,
|
|
*************** extern void InitResultRelInfo(ResultRelI
|
|
*** 163,168 ****
|
|
--- 163,169 ----
|
|
bool doInstrument);
|
|
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,
|
|
*************** extern void ExecInitScanTupleSlot(EState
|
|
*** 216,223 ****
|
|
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 ExecTypeFromExprList(List *exprList);
|
|
extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);
|
|
|
|
--- 217,224 ----
|
|
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
|
|
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
|
|
TupleDesc tupType);
|
|
! 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 -Nrpc base/src/include/executor/tuptable.h sepgsql/src/include/executor/tuptable.h
|
|
*** base/src/include/executor/tuptable.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/executor/tuptable.h Wed Jul 15 19:38:52 2009
|
|
*************** typedef struct TupleTableSlot
|
|
*** 127,132 ****
|
|
--- 127,133 ----
|
|
MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */
|
|
HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */
|
|
long tts_off; /* saved state for slot_deform_tuple */
|
|
+ Datum tts_seclabel; /* temp storage for the given security_label */
|
|
} TupleTableSlot;
|
|
|
|
#define TTS_HAS_PHYSICAL_TUPLE(slot) \
|
|
diff -Nrpc base/src/include/libpq/be-fsstubs.h sepgsql/src/include/libpq/be-fsstubs.h
|
|
*** base/src/include/libpq/be-fsstubs.h Sat Jan 3 12:25:21 2009
|
|
--- sepgsql/src/include/libpq/be-fsstubs.h Wed Jul 15 19:48:58 2009
|
|
*************** extern Datum lo_tell(PG_FUNCTION_ARGS);
|
|
*** 37,42 ****
|
|
--- 37,45 ----
|
|
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 -Nrpc base/src/include/nodes/nodes.h sepgsql/src/include/nodes/nodes.h
|
|
*** base/src/include/nodes/nodes.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/nodes/nodes.h Wed Jul 15 19:37:35 2009
|
|
*************** typedef enum NodeTag
|
|
*** 337,342 ****
|
|
--- 337,343 ----
|
|
T_CreateUserMappingStmt,
|
|
T_AlterUserMappingStmt,
|
|
T_DropUserMappingStmt,
|
|
+ T_AlterSecLabelStmt,
|
|
|
|
/*
|
|
* TAGS FOR PARSE TREE NODES (parsenodes.h)
|
|
diff -Nrpc base/src/include/nodes/parsenodes.h sepgsql/src/include/nodes/parsenodes.h
|
|
*** base/src/include/nodes/parsenodes.h Fri Jun 19 13:40:37 2009
|
|
--- sepgsql/src/include/nodes/parsenodes.h Wed Jul 15 19:37:35 2009
|
|
*************** typedef struct ColumnDef
|
|
*** 464,469 ****
|
|
--- 464,470 ----
|
|
Node *raw_default; /* default value (untransformed parse tree) */
|
|
char *cooked_default; /* nodeToString representation */
|
|
List *constraints; /* other constraints on column */
|
|
+ Node *secLabel; /* security label of column */
|
|
} ColumnDef;
|
|
|
|
/*
|
|
*************** typedef struct CreateSchemaStmt
|
|
*** 1070,1075 ****
|
|
--- 1071,1077 ----
|
|
NodeTag type;
|
|
char *schemaname; /* the name of the schema to create */
|
|
char *authid; /* the owner of the created schema */
|
|
+ Node *secLabel; /* explicitly specified security label */
|
|
List *schemaElts; /* schema components (list of parsenodes) */
|
|
} CreateSchemaStmt;
|
|
|
|
*************** typedef struct CreateStmt
|
|
*** 1335,1340 ****
|
|
--- 1337,1343 ----
|
|
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;
|
|
|
|
/* ----------
|
|
*************** typedef struct CreateSeqStmt
|
|
*** 1639,1644 ****
|
|
--- 1642,1648 ----
|
|
NodeTag type;
|
|
RangeVar *sequence; /* the sequence to create */
|
|
List *options;
|
|
+ Node *secLabel;
|
|
} CreateSeqStmt;
|
|
|
|
typedef struct AlterSeqStmt
|
|
*************** typedef struct AlterOwnerStmt
|
|
*** 1993,1998 ****
|
|
--- 1997,2016 ----
|
|
char *newowner; /* the new owner */
|
|
} AlterOwnerStmt;
|
|
|
|
+ /* ----------------------
|
|
+ * Alter Object Security Label Statement
|
|
+ * ----------------------
|
|
+ */
|
|
+ typedef struct AlterSecLabelStmt
|
|
+ {
|
|
+ NodeTag type;
|
|
+ ObjectType objectType; /* OBJECT_TABLE, OBJECT_COLUMN, etc */
|
|
+ RangeVar *relation; /* in case it's a table */
|
|
+ List *object; /* in case it's some other object */
|
|
+ List *objarg; /* argument types, if applicable */
|
|
+ char *subname; /* column name, if needed */
|
|
+ Node *secLabel; /* the new security label */
|
|
+ } AlterSecLabelStmt;
|
|
|
|
/* ----------------------
|
|
* Create Rule Statement
|
|
diff -Nrpc base/src/include/nodes/plannodes.h sepgsql/src/include/nodes/plannodes.h
|
|
*** base/src/include/nodes/plannodes.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/nodes/plannodes.h Wed Jul 15 19:39:56 2009
|
|
***************
|
|
*** 16,21 ****
|
|
--- 16,22 ----
|
|
|
|
#include "access/sdir.h"
|
|
#include "nodes/bitmapset.h"
|
|
+ #include "nodes/parsenodes.h"
|
|
#include "nodes/primnodes.h"
|
|
#include "storage/itemptr.h"
|
|
|
|
*************** typedef struct Scan
|
|
*** 239,244 ****
|
|
--- 240,251 ----
|
|
{
|
|
Plan plan;
|
|
Index scanrelid; /* relid is index into the range table */
|
|
+
|
|
+ /*
|
|
+ * Row-level access control stuff. Zero means we don't need
|
|
+ * to apply row-level access control on the Scan.
|
|
+ */
|
|
+ uint32 rowlvPerms;
|
|
} Scan;
|
|
|
|
/* ----------------
|
|
diff -Nrpc base/src/include/nodes/relation.h sepgsql/src/include/nodes/relation.h
|
|
*** base/src/include/nodes/relation.h Thu Jun 18 10:20:52 2009
|
|
--- sepgsql/src/include/nodes/relation.h Wed Jul 15 19:39:56 2009
|
|
*************** typedef struct RelOptInfo
|
|
*** 383,388 ****
|
|
--- 383,397 ----
|
|
* list just to avoid recomputing the best inner indexscan repeatedly for
|
|
* similar outer relations. See comments for InnerIndexscanInfo.
|
|
*/
|
|
+
|
|
+ /*
|
|
+ * Permissions used in Row-level access control features both of DAC
|
|
+ * and MAC. The lower 16bit is used for DAC, and rest of upper bits
|
|
+ * are used for MAC. When rowlvPerms is zero, so it means we don't need
|
|
+ * to apply the row-level stuff on the relation in both of levels.
|
|
+ * It can be used as a hint for optimization stuff.
|
|
+ */
|
|
+ uint32 rowlvPerms;
|
|
} RelOptInfo;
|
|
|
|
/*
|
|
diff -Nrpc base/src/include/pg_config.h.in sepgsql/src/include/pg_config.h.in
|
|
*** base/src/include/pg_config.h.in Thu Apr 9 00:13:21 2009
|
|
--- sepgsql/src/include/pg_config.h.in Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 391,396 ****
|
|
--- 391,399 ----
|
|
/* Define to 1 if you have the <security/pam_appl.h> header file. */
|
|
#undef HAVE_SECURITY_PAM_APPL_H
|
|
|
|
+ /* Define to 1 if you enable SELinux support */
|
|
+ #undef HAVE_SELINUX
|
|
+
|
|
/* Define to 1 if you have the `setproctitle' function. */
|
|
#undef HAVE_SETPROCTITLE
|
|
|
|
diff -Nrpc base/src/include/security/rowlevel.h sepgsql/src/include/security/rowlevel.h
|
|
*** base/src/include/security/rowlevel.h Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/include/security/rowlevel.h Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,44 ----
|
|
+ /*
|
|
+ * 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"
|
|
+
|
|
+ #define ROWLV_BYPASS_MODE 1
|
|
+ #define ROWLV_FILTER_MODE 2
|
|
+ #define ROWLV_ABORT_MODE 3
|
|
+
|
|
+ extern int
|
|
+ rowlvGetPerformingMode(void);
|
|
+
|
|
+ extern int
|
|
+ rowlvSetPerformingMode(int mode);
|
|
+
|
|
+ extern uint32
|
|
+ rowlvSetupPermissions(RangeTblEntry *rte);
|
|
+
|
|
+ extern bool
|
|
+ rowlvExecScanFilter(Scan *scan, Relation rel, TupleTableSlot *slot);
|
|
+
|
|
+ extern void
|
|
+ rowlvExecScanAbort(Scan *scan, Relation rel, TupleTableSlot *slot);
|
|
+
|
|
+ extern void
|
|
+ rowlvHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal);
|
|
+
|
|
+ extern void
|
|
+ rowlvHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup);
|
|
+
|
|
+ extern bool
|
|
+ rowlvCopyToTuple(Relation rel, HeapTuple tuple);
|
|
+
|
|
+ #endif /* ROWLEVEL_H */
|
|
diff -Nrpc base/src/include/security/sepgsql.h sepgsql/src/include/security/sepgsql.h
|
|
*** base/src/include/security/sepgsql.h Thu Jan 1 09:00:00 1970
|
|
--- sepgsql/src/include/security/sepgsql.h Thu Jul 16 17:22:29 2009
|
|
***************
|
|
*** 0 ****
|
|
--- 1,514 ----
|
|
+ /*
|
|
+ * src/include/security/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 "catalog/dependency.h"
|
|
+ #include "executor/execdesc.h"
|
|
+ #include "fmgr.h"
|
|
+ #include "nodes/parsenodes.h"
|
|
+ #include "storage/large_object.h"
|
|
+ #include "utils/relcache.h"
|
|
+
|
|
+ #ifdef HAVE_SELINUX
|
|
+
|
|
+ #include <selinux/selinux.h>
|
|
+
|
|
+ /* 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;
|
|
+
|
|
+ /* GUC parameter to turn on/off mcstrans */
|
|
+ extern bool sepostgresql_use_mcstrans;
|
|
+
|
|
+ /* Objject classes and permissions internally used */
|
|
+ enum SepgsqlClasses
|
|
+ {
|
|
+ SEPG_CLASS_PROCESS = 0,
|
|
+ SEPG_CLASS_FILE,
|
|
+ SEPG_CLASS_DIR,
|
|
+ SEPG_CLASS_LNK_FILE,
|
|
+ SEPG_CLASS_CHR_FILE,
|
|
+ SEPG_CLASS_BLK_FILE,
|
|
+ SEPG_CLASS_SOCK_FILE,
|
|
+ SEPG_CLASS_FIFO_FILE,
|
|
+ SEPG_CLASS_DB_DATABASE,
|
|
+ SEPG_CLASS_DB_SCHEMA,
|
|
+ SEPG_CLASS_DB_SCHEMA_TEMP,
|
|
+ SEPG_CLASS_DB_TABLE,
|
|
+ SEPG_CLASS_DB_SEQUENCE,
|
|
+ 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__CONNECT (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_SCHEMA__CREATE (SEPG_DB_DATABASE__CREATE)
|
|
+ #define SEPG_DB_SCHEMA__DROP (SEPG_DB_DATABASE__DROP)
|
|
+ #define SEPG_DB_SCHEMA__GETATTR (SEPG_DB_DATABASE__GETATTR)
|
|
+ #define SEPG_DB_SCHEMA__SETATTR (SEPG_DB_DATABASE__SETATTR)
|
|
+ #define SEPG_DB_SCHEMA__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
|
|
+ #define SEPG_DB_SCHEMA__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
|
|
+ #define SEPG_DB_SCHEMA__USAGE (1<<6)
|
|
+ #define SEPG_DB_SCHEMA__ADD_OBJECT (1<<7)
|
|
+ #define SEPG_DB_SCHEMA__REMOVE_OBJECT (1<<8)
|
|
+
|
|
+ #define SEPG_DB_SCHEMA_TEMP__CREATE (SEPG_DB_DATABASE__CREATE)
|
|
+ #define SEPG_DB_SCHEMA_TEMP__DROP (SEPG_DB_DATABASE__DROP)
|
|
+ #define SEPG_DB_SCHEMA_TEMP__GETATTR (SEPG_DB_DATABASE__GETATTR)
|
|
+ #define SEPG_DB_SCHEMA_TEMP__SETATTR (SEPG_DB_DATABASE__SETATTR)
|
|
+ #define SEPG_DB_SCHEMA_TEMP__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
|
|
+ #define SEPG_DB_SCHEMA_TEMP__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
|
|
+ #define SEPG_DB_SCHEMA_TEMP__USAGE (SEPG_DB_SCHEMA__USAGE)
|
|
+ #define SEPG_DB_SCHEMA_TEMP__ADD_OBJECT (SEPG_DB_SCHEMA__ADD_OBJECT)
|
|
+ #define SEPG_DB_SCHEMA_TEMP__REMOVE_OBJECT (SEPG_DB_SCHEMA__REMOVE_OBJECT)
|
|
+
|
|
+ #define SEPG_DB_TABLE__CREATE (SEPG_DB_DATABASE__CREATE)
|
|
+ #define SEPG_DB_TABLE__DROP (SEPG_DB_DATABASE__DROP)
|
|
+ #define SEPG_DB_TABLE__GETATTR (SEPG_DB_DATABASE__GETATTR)
|
|
+ #define SEPG_DB_TABLE__SETATTR (SEPG_DB_DATABASE__SETATTR)
|
|
+ #define SEPG_DB_TABLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
|
|
+ #define SEPG_DB_TABLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
|
|
+ #define SEPG_DB_TABLE__SELECT (1<<6)
|
|
+ #define SEPG_DB_TABLE__UPDATE (1<<7)
|
|
+ #define SEPG_DB_TABLE__INSERT (1<<8)
|
|
+ #define SEPG_DB_TABLE__DELETE (1<<9)
|
|
+ #define SEPG_DB_TABLE__LOCK (1<<10)
|
|
+ #define SEPG_DB_TABLE__REFERENCE (1<<11)
|
|
+
|
|
+ #define SEPG_DB_SEQUENCE__CREATE (SEPG_DB_DATABASE__CREATE)
|
|
+ #define SEPG_DB_SEQUENCE__DROP (SEPG_DB_DATABASE__DROP)
|
|
+ #define SEPG_DB_SEQUENCE__GETATTR (SEPG_DB_DATABASE__GETATTR)
|
|
+ #define SEPG_DB_SEQUENCE__SETATTR (SEPG_DB_DATABASE__SETATTR)
|
|
+ #define SEPG_DB_SEQUENCE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
|
|
+ #define SEPG_DB_SEQUENCE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
|
|
+ #define SEPG_DB_SEQUENCE__GET_VALUE (1<<6)
|
|
+ #define SEPG_DB_SEQUENCE__NEXT_VALUE (1<<7)
|
|
+ #define SEPG_DB_SEQUENCE__SET_VALUE (1<<8)
|
|
+
|
|
+ #define SEPG_DB_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_COLUMN__REFERENCE (1<<9)
|
|
+
|
|
+ #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 caches
|
|
+ */
|
|
+
|
|
+ /* Hook to record audit logs */
|
|
+ typedef void (*sepgsqlAvcAuditHook_t)(bool denied,
|
|
+ const char *scontext,
|
|
+ const char *tcontext,
|
|
+ const char *tclass,
|
|
+ const char *permissions,
|
|
+ const char *audit_name);
|
|
+ extern PGDLLIMPORT sepgsqlAvcAuditHook_t sepgsqlAvcAuditHook;
|
|
+
|
|
+ extern Size sepgsqlShmemSize(void);
|
|
+ extern void sepgsqlAvcInitialize(void);
|
|
+
|
|
+ extern bool sepgsqlGetEnforce(void);
|
|
+ extern int sepgsqlSetEnforce(int new_mode);
|
|
+ extern void sepgsqlAvcSwitchClient(const char *scontext);
|
|
+
|
|
+ extern bool
|
|
+ sepgsqlClientHasPermsSid(Oid relid, Oid secid,
|
|
+ uint16 tclass, uint32 required,
|
|
+ const char *audit_name, bool abort);
|
|
+ extern bool
|
|
+ sepgsqlClientHasPermsTup(Oid relid, HeapTuple tuple,
|
|
+ uint16 tclass, uint32 required, bool abort);
|
|
+ extern Oid
|
|
+ sepgsqlClientCreateSecid(Oid trelid, Oid tsecid, uint16 tclass, Oid nrelid);
|
|
+
|
|
+ extern security_context_t
|
|
+ sepgsqlClientCreateLabel(Oid trelid, Oid tsecid,
|
|
+ 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);
|
|
+
|
|
+ extern pid_t sepgsqlStartupWorkerProcess(void);
|
|
+
|
|
+ /*
|
|
+ * checker.c : check permission on given queries
|
|
+ */
|
|
+ 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, uint32 required, bool abort);
|
|
+
|
|
+ extern uint32
|
|
+ sepgsqlSetupTuplePerms(RangeTblEntry *rte);
|
|
+
|
|
+ extern void
|
|
+ sepgsqlHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal);
|
|
+
|
|
+ extern void
|
|
+ sepgsqlHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup);
|
|
+
|
|
+ /*
|
|
+ * core.c : core facilities
|
|
+ */
|
|
+ extern security_context_t
|
|
+ sepgsqlGetServerLabel(void);
|
|
+
|
|
+ extern security_context_t
|
|
+ sepgsqlGetClientLabel(void);
|
|
+
|
|
+ extern security_context_t
|
|
+ sepgsqlSwitchClient(security_context_t new_client);
|
|
+
|
|
+ extern bool
|
|
+ sepgsqlIsEnabled(void);
|
|
+
|
|
+ extern void
|
|
+ sepgsqlInitialize(void);
|
|
+
|
|
+ /*
|
|
+ * hooks.c : routines to check certain permissions
|
|
+ */
|
|
+ extern Oid
|
|
+ sepgsqlCheckDatabaseCreate(const char *datname, DefElem *new_label);
|
|
+ extern void
|
|
+ sepgsqlCheckDatabaseDrop(Oid database_oid);
|
|
+ extern void
|
|
+ sepgsqlCheckDatabaseSetattr(Oid database_oid);
|
|
+ extern Oid
|
|
+ sepgsqlCheckDatabaseRelabel(Oid database_oid, DefElem *new_label);
|
|
+ extern bool
|
|
+ sepgsqlCheckDatabaseConnect(Oid database_oid);
|
|
+ extern bool
|
|
+ sepgsqlCheckDatabaseSuperuser(void);
|
|
+ extern void
|
|
+ sepgsqlCheckDatabaseInstallModule(const char *probin, HeapTuple protup);
|
|
+ extern void
|
|
+ sepgsqlCheckDatabaseLoadModule(const char *filename);
|
|
+
|
|
+ extern Oid
|
|
+ sepgsqlCheckSchemaCreate(const char *nspname, DefElem *new_label, bool temp_schame);
|
|
+ extern void
|
|
+ sepgsqlCheckSchemaDrop(Oid namespace_oid);
|
|
+ extern void
|
|
+ sepgsqlCheckSchemaSetattr(Oid namespace_oid);
|
|
+ extern Oid
|
|
+ sepgsqlCheckSchemaRelabel(Oid namespace_oid, DefElem *new_label);
|
|
+ extern bool
|
|
+ sepgsqlCheckSchemaUsage(Oid nsid);
|
|
+
|
|
+ extern void
|
|
+ sepgsqlCheckTableDrop(Oid table_oid);
|
|
+ extern void
|
|
+ sepgsqlCheckTableSetattr(Oid table_oid);
|
|
+ extern Oid
|
|
+ sepgsqlCheckTableRelabel(Oid table_oid, DefElem *new_label);
|
|
+ extern void
|
|
+ sepgsqlCheckTableLock(Oid table_oid);
|
|
+ extern void
|
|
+ sepgsqlCheckTableTruncate(Relation rel);
|
|
+ extern void
|
|
+ sepgsqlCheckTableReference(Relation rel, int16 *attnums, int natts);
|
|
+
|
|
+ extern void
|
|
+ sepgsqlCheckSequenceGetValue(Oid seqid);
|
|
+ extern void
|
|
+ sepgsqlCheckSequenceNextValue(Oid seqid);
|
|
+ extern void
|
|
+ sepgsqlCheckSequenceSetValue(Oid seqid);
|
|
+
|
|
+ extern Oid
|
|
+ sepgsqlCheckColumnCreate(Oid table_oid, const char *attname, DefElem *new_label);
|
|
+ extern void
|
|
+ sepgsqlCheckColumnDrop(Oid table_oid, AttrNumber attno);
|
|
+ extern void
|
|
+ sepgsqlCheckColumnSetattr(Oid table_oid, AttrNumber attno);
|
|
+ extern Oid
|
|
+ sepgsqlCheckColumnRelabel(Oid table_oid, AttrNumber attno, DefElem *new_label);
|
|
+
|
|
+ extern Oid
|
|
+ sepgsqlCheckProcedureCreate(const char *proname, Oid namespace_oid, DefElem *new_label);
|
|
+ extern void
|
|
+ sepgsqlCheckProcedureDrop(Oid proc_oid);
|
|
+ extern void
|
|
+ sepgsqlCheckProcedureSetattr(Oid proc_oid);
|
|
+ extern Oid
|
|
+ sepgsqlCheckProcedureRelabel(Oid proc_oid, DefElem *new_label);
|
|
+ extern bool
|
|
+ sepgsqlCheckProcedureExecute(Oid proc_oid);
|
|
+ extern void
|
|
+ sepgsqlCheckProcedureEntrypoint(FmgrInfo *finfo, HeapTuple protup);
|
|
+ extern void
|
|
+ sepgsqlCheckProcedureInstall(Oid proc_oid);
|
|
+
|
|
+ extern void
|
|
+ sepgsqlCheckBlobCreate(Relation rel, HeapTuple lotup);
|
|
+ extern void
|
|
+ sepgsqlCheckBlobDrop(Relation rel, 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);
|
|
+
|
|
+ void
|
|
+ sepgsqlCheckObjectDrop(const ObjectAddress *object);
|
|
+
|
|
+ /* optimizar hints */
|
|
+ extern bool
|
|
+ sepgsqlAllowFunctionInlined(HeapTuple protup);
|
|
+
|
|
+ /*
|
|
+ * label.c : security label management
|
|
+ */
|
|
+ extern bool
|
|
+ sepgsqlTupleDescHasSecLabel(Oid relid, char relkind);
|
|
+ extern security_context_t
|
|
+ sepgsqlMetaSecurityLabel(void);
|
|
+ extern void
|
|
+ sepgsqlSetDefaultSecLabel(Relation rel, HeapTuple tuple);
|
|
+
|
|
+ extern Oid sepgsqlGetDefaultDatabaseSecLabel(void);
|
|
+ extern Oid sepgsqlGetDefaultSchemaSecLabel(Oid database_oid);
|
|
+ extern Oid sepgsqlGetDefaultSchemaTempSecLabel(Oid database_oid);
|
|
+ extern Oid sepgsqlGetDefaultTableSecLabel(Oid namespace_oid);
|
|
+ extern Oid sepgsqlGetDefaultSequenceSecLabel(Oid namespace_oid);
|
|
+ extern Oid sepgsqlGetDefaultProcedureSecLabel(Oid namespace_oid);
|
|
+ extern Oid sepgsqlGetDefaultColumnSecLabel(Oid table_oid);
|
|
+ extern Oid sepgsqlGetDefaultTupleSecLabel(Oid table_oid);
|
|
+ extern Oid sepgsqlGetDefaultBlobSecLabel(Oid database_oid);
|
|
+
|
|
+ extern Oid *sepgsqlCreateTableColumns(CreateStmt *stmt,
|
|
+ const char *relname, Oid namespace_oid,
|
|
+ TupleDesc tupdesc, char relkind);
|
|
+ extern Oid *sepgsqlCopyTableColumns(Relation source);
|
|
+
|
|
+ extern char *sepgsqlTransSecLabelIn(char *seclabel);
|
|
+ extern char *sepgsqlTransSecLabelOut(char *seclabel);
|
|
+ extern char *sepgsqlRawSecLabelIn(char *seclabel);
|
|
+ extern char *sepgsqlRawSecLabelOut(char *seclabel);
|
|
+
|
|
+ /*
|
|
+ * perms.c : SELinux permission related stuff
|
|
+ */
|
|
+ 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(uint16 tclass);
|
|
+ extern const char *sepgsqlGetPermString(uint16 tclass, uint32 permission);
|
|
+
|
|
+ #else /* HAVE_SELINUX */
|
|
+
|
|
+ /* avc.c */
|
|
+ #define sepgsqlShmemSize() (0)
|
|
+ #define sepgsqlStartupWorkerProcess() (0)
|
|
+
|
|
+ /* checker.c */
|
|
+ #define sepgsqlCheckRTEPerms(a) do {} while(0)
|
|
+ #define sepgsqlCheckCopyTable(a,b,c) do {} while(0)
|
|
+ #define sepgsqlCheckSelectInto(a) do {} while(0)
|
|
+ #define sepgsqlExecScan(a,b,c) (true)
|
|
+ #define sepgsqlSetupTuplePerms(a) (0)
|
|
+ #define sepgsqlHeapTupleInsert(a,b,c) do {} while(0)
|
|
+ #define sepgsqlHeapTupleUpdate(a,b,c) do {} while(0)
|
|
+
|
|
+ /* core.c */
|
|
+ #define sepgsqlIsEnabled() (false)
|
|
+ #define sepgsqlInitialize() do {} while(0)
|
|
+
|
|
+ /* hooks.c */
|
|
+ #define sepgsqlCheckDatabaseCreate(a,b) (InvalidOid)
|
|
+ #define sepgsqlCheckDatabaseDrop(a) do {} while(0)
|
|
+ #define sepgsqlCheckDatabaseSetattr(a) do {} while(0)
|
|
+ #define sepgsqlCheckDatabaseRelabel(a,b) (InvalidOid)
|
|
+ #define sepgsqlCheckDatabaseAccess(a) (true)
|
|
+ #define sepgsqlCheckDatabaseSuperuser() (true)
|
|
+ #define sepgsqlCheckDatabaseInstallModule(a,b) do {} while(0)
|
|
+ #define sepgsqlCheckDatabaseLoadModule(a) do {} while(0)
|
|
+
|
|
+ #define sepgsqlCheckSchemaCreate(a,b,c) (InvalidOid)
|
|
+ #define sepgsqlCheckSchemaDrop(a) do {} while(0)
|
|
+ #define sepgsqlCheckSchemaSetattr(a) do {} while(0)
|
|
+ #define sepgsqlCheckSchemaRelabel(a,b) (InvalidOid)
|
|
+ #define sepgsqlCheckSchemaUsage(a) (true)
|
|
+
|
|
+ #define sepgsqlCheckTableDrop(a) do {} while(0)
|
|
+ #define sepgsqlCheckTableSetattr(a) do {} while(0)
|
|
+ #define sepgsqlCheckTableRelabel(a,b) (InvalidOid)
|
|
+ #define sepgsqlCheckTableLock(a) do {} while(0)
|
|
+ #define sepgsqlCheckTableTruncate(a) do {} while(0)
|
|
+ #define sepgsqlCheckTableReference(a,b,c) do {} while(0)
|
|
+
|
|
+ #define sepgsqlCheckSequenceGetValue(a) do {} while(0)
|
|
+ #define sepgsqlCheckSequenceNextValue(a) do {} while(0)
|
|
+ #define sepgsqlCheckSequenceSetValue(a) do {} while(0)
|
|
+
|
|
+ #define sepgsqlCheckColumnCreate(a,b,c) (InvalidOid)
|
|
+ #define sepgsqlCheckColumnDrop(a,b) do {} while(0)
|
|
+ #define sepgsqlCheckColumnSetattr(a,b) do {} while(0)
|
|
+ #define sepgsqlCheckColumnRelabel(a,b,c) (InvalidOid)
|
|
+
|
|
+ #define sepgsqlCheckProcedureCreate(a,b,c) (InvalidOid)
|
|
+ #define sepgsqlCheckProcedureDrop(a) do {} while(0)
|
|
+ #define sepgsqlCheckProcedureSetattr(a) do {} while(0)
|
|
+ #define sepgsqlCheckProcedureRelabel(a,b) (InvalidOid)
|
|
+ #define sepgsqlCheckProcedureExecute(a) (true)
|
|
+ #define sepgsqlCheckProcedureEntrypoint(a,b) do {} while(0)
|
|
+ #define sepgsqlCheckProcedureInstall(a) do {} while(0)
|
|
+
|
|
+ #define sepgsqlCheckBlobCreate(a,b) do {} while(0)
|
|
+ #define sepgsqlCheckBlobDrop(a,b) 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 sepgsqlCheckObjectDrop(a) do {} while(0)
|
|
+
|
|
+ #define sepgsqlAllowFunctionInlined(a) (true)
|
|
+
|
|
+ /* label.c */
|
|
+ #define sepgsqlTupleDescHasSecLabel(a,b) (false)
|
|
+ #define sepgsqlSetDefaultSecLabel(a,b) do {} while(0)
|
|
+ #define sepgsqlCreateTableColumns(a,b,c,d,e) (NULL)
|
|
+ #define sepgsqlCopyTableColumns(a) (NULL)
|
|
+ #define sepgsqlMetaSecurityLabel() (NULL)
|
|
+ #define sepgsqlTransSecLabelIn(a) (a)
|
|
+ #define sepgsqlTransSecLabelOut(a) (a)
|
|
+ #define sepgsqlRawSecLabelIn(a) (a)
|
|
+ #define sepgsqlRawSecLabelOut(a) (a)
|
|
+
|
|
+ #endif /* HAVE_SELINUX */
|
|
+
|
|
+ extern Datum sepgsql_getcon(PG_FUNCTION_ARGS);
|
|
+ extern Datum sepgsql_server_getcon(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 -Nrpc base/src/include/storage/fd.h sepgsql/src/include/storage/fd.h
|
|
*** base/src/include/storage/fd.h Tue Jan 13 09:22:28 2009
|
|
--- sepgsql/src/include/storage/fd.h Wed Jul 15 19:48:58 2009
|
|
*************** extern int FileWrite(File file, char *bu
|
|
*** 68,73 ****
|
|
--- 68,74 ----
|
|
extern int FileSync(File file);
|
|
extern off_t FileSeek(File file, off_t offset, int whence);
|
|
extern int FileTruncate(File file, off_t 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 -Nrpc base/src/include/storage/large_object.h sepgsql/src/include/storage/large_object.h
|
|
*** base/src/include/storage/large_object.h Sat Jan 3 12:25:21 2009
|
|
--- sepgsql/src/include/storage/large_object.h Wed Jul 15 19:48:58 2009
|
|
*************** typedef struct LargeObjectDesc
|
|
*** 44,49 ****
|
|
--- 44,50 ----
|
|
#define IFS_RDLOCK (1 << 0)
|
|
#define IFS_WRLOCK (1 << 1)
|
|
|
|
+ Oid secid; /* security identifier of largeobject */
|
|
} LargeObjectDesc;
|
|
|
|
|
|
*************** extern int inv_tell(LargeObjectDesc *obj
|
|
*** 79,83 ****
|
|
--- 80,86 ----
|
|
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 -Nrpc base/src/include/storage/lwlock.h sepgsql/src/include/storage/lwlock.h
|
|
*** base/src/include/storage/lwlock.h Fri Mar 6 09:45:33 2009
|
|
--- sepgsql/src/include/storage/lwlock.h Wed Jul 15 19:35:52 2009
|
|
*************** typedef enum LWLockId
|
|
*** 67,72 ****
|
|
--- 67,73 ----
|
|
AutovacuumLock,
|
|
AutovacuumScheduleLock,
|
|
SyncScanLock,
|
|
+ SepgsqlAvcLock,
|
|
/* Individual lock IDs end here */
|
|
FirstBufMappingLock,
|
|
FirstLockMgrLock = FirstBufMappingLock + NUM_BUFFER_PARTITIONS,
|
|
diff -Nrpc base/src/include/utils/errcodes.h sepgsql/src/include/utils/errcodes.h
|
|
*** base/src/include/utils/errcodes.h Fri Mar 6 09:45:33 2009
|
|
--- sepgsql/src/include/utils/errcodes.h Wed Jul 15 19:35:52 2009
|
|
***************
|
|
*** 347,352 ****
|
|
--- 347,357 ----
|
|
#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 -Nrpc base/src/include/utils/syscache.h sepgsql/src/include/utils/syscache.h
|
|
*** base/src/include/utils/syscache.h Sat Jan 3 12:25:21 2009
|
|
--- sepgsql/src/include/utils/syscache.h Thu Jul 16 23:18:11 2009
|
|
*************** enum SysCacheIdentifier
|
|
*** 69,74 ****
|
|
--- 69,76 ----
|
|
RELNAMENSP,
|
|
RELOID,
|
|
RULERELNAME,
|
|
+ SECURITYATTR,
|
|
+ SECURITYSECID,
|
|
STATRELATT,
|
|
TSCONFIGMAP,
|
|
TSCONFIGNAMENSP,
|
|
diff -Nrpc base/src/test/regress/expected/sanity_check.out sepgsql/src/test/regress/expected/sanity_check.out
|
|
*** base/src/test/regress/expected/sanity_check.out Tue Feb 10 10:10:02 2009
|
|
--- sepgsql/src/test/regress/expected/sanity_check.out Thu Jul 16 23:18:11 2009
|
|
*************** SELECT relname, relhasindex
|
|
*** 112,117 ****
|
|
--- 112,118 ----
|
|
pg_pltemplate | t
|
|
pg_proc | t
|
|
pg_rewrite | t
|
|
+ pg_security | t
|
|
pg_shdepend | t
|
|
pg_shdescription | t
|
|
pg_statistic | t
|
|
*************** SELECT relname, relhasindex
|
|
*** 151,157 ****
|
|
timetz_tbl | f
|
|
tinterval_tbl | f
|
|
varchar_tbl | f
|
|
! (140 rows)
|
|
|
|
--
|
|
-- another sanity check: every system catalog that has OIDs should have
|
|
--- 152,158 ----
|
|
timetz_tbl | f
|
|
tinterval_tbl | f
|
|
varchar_tbl | f
|
|
! (141 rows)
|
|
|
|
--
|
|
-- another sanity check: every system catalog that has OIDs should have
|