sepostgresql/sepostgresql-8.4.patch
KaiGai Kohei 478ff226fa - rework: backport features from v8.5devel tree
- fixbug: selinux netlink receiver process didn't have correct ps display
2009-12-08 06:00:14 +00:00

19116 lines
564 KiB
Diff

diff -Nrpc base/configure sepgsql/configure
*** base/configure Sun Sep 6 19:40:49 2009
--- sepgsql/configure Sun Sep 6 19:53:10 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 Sun Sep 6 19:40:49 2009
--- sepgsql/configure.in Sun Sep 6 19:53:10 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 Thu Sep 10 15:18:03 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 SecurityAttributeNumber:
/* these are never null */
break;
*************** heap_getsysattr(HeapTuple tup, int attnu
*** 599,604 ****
--- 601,609 ----
case TableOidAttributeNumber:
result = ObjectIdGetDatum(tup->t_tableOid);
break;
+ case SecurityAttributeNumber:
+ result = securitySysattSecLabelOut(tup->t_tableOid, 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->tdhassecid)
+ 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->tdhassecid)
+ td->t_infomask |= HEAP_HASSECID;
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 (HeapTupleHasSecid(newTuple))
+ HeapTupleSetSecid(newTuple, HeapTupleGetSecid(tuple));
return newTuple;
}
*************** heap_form_minimal_tuple(TupleDesc tupleD
*** 1474,1479 ****
--- 1485,1492 ----
if (tupleDescriptor->tdhasoid)
len += sizeof(Oid);
+ if (tupleDescriptor->tdhassecid)
+ 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->tdhassecid)
+ tuple->t_infomask |= HEAP_HASSECID;
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 Sep 9 13:14:37 2009
*************** CreateTemplateTupleDesc(int natts, bool
*** 88,93 ****
--- 88,94 ----
desc->tdtypeid = RECORDOID;
desc->tdtypmod = -1;
desc->tdhasoid = hasoid;
+ desc->tdhassecid = 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->tdhassecid = 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->tdhassecid = tupdesc->tdhassecid;
return desc;
}
*************** CreateTupleDescCopyConstr(TupleDesc tupd
*** 208,213 ****
--- 211,217 ----
desc->tdtypeid = tupdesc->tdtypeid;
desc->tdtypmod = tupdesc->tdtypmod;
+ desc->tdhassecid = tupdesc->tdhassecid;
return desc;
}
*************** equalTupleDescs(TupleDesc tupdesc1, Tupl
*** 314,319 ****
--- 318,325 ----
return false;
if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
return false;
+ if (tupdesc1->tdhassecid != tupdesc2->tdhassecid)
+ 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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/access/heap/heapam.c Tue Dec 8 14:53:28 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
*** 2016,2021 ****
--- 2017,2028 ----
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:
*** 2558,2563 ****
--- 2565,2575 ----
Assert(!(newtup->t_data->t_infomask & HEAP_HASOID));
}
+ /* Preserve SecurityId, if not changed */
+ if (HeapTupleHasSecid(newtup) &&
+ !OidIsValid(HeapTupleGetSecid(newtup)))
+ HeapTupleSetSecid(newtup, HeapTupleGetSecid(&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 Tue Sep 8 23:55:48 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 (HeapTupleHasSecid(newtup))
+ hoff += sizeof(Oid);
hoff = MAXALIGN(hoff);
Assert(hoff == newtup->t_data->t_hoff);
/* now convert to a limit on the tuple data size */
*************** 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 (HeapTupleHeaderHasSecid(olddata))
+ new_len += sizeof(Oid);
new_len = MAXALIGN(new_len);
Assert(new_len == olddata->t_hoff);
new_data_len = heap_compute_data_size(tupleDesc,
*************** 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 (HeapTupleHeaderHasSecid(olddata))
+ new_len += sizeof(Oid);
new_len = MAXALIGN(new_len);
Assert(new_len == olddata->t_hoff);
new_data_len = heap_compute_data_size(tupleDesc,
*************** 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 Sun Sep 6 19:31:39 2009
***************
*** 36,41 ****
--- 36,43 ----
#include "libpq/be-fsstubs.h"
#include "miscadmin.h"
#include "pgstat.h"
+ #include "security/rowlevel.h"
+ #include "security/sepgsql.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/lmgr.h"
*************** typedef struct TransactionStateData
*** 140,145 ****
--- 142,148 ----
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 ****
--- 171,177 ----
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 ****
--- 1528,1534 ----
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 ****
--- 2035,2050 ----
SetUserIdAndContext(s->prevUser, s->prevSecDefCxt);
/*
+ * Reset behavior of row-level access controls
+ */
+ rowlvSetPerformingMode(s->prevRowlv);
+
+ /*
+ * Reset access vector cache on error
+ */
+ sepgsqlAvcReset();
+
+ /*
* do abort processing
*/
AfterTriggerEndXact(false);
*************** AbortSubTransaction(void)
*** 3873,3878 ****
--- 3888,3903 ----
SetUserIdAndContext(s->prevUser, s->prevSecDefCxt);
/*
+ * Reset behavior of row-level access controls
+ */
+ rowlvSetPerformingMode(s->prevRowlv);
+
+ /*
+ * Reset access vector cache on error
+ */
+ sepgsqlAvcReset();
+
+ /*
* We can skip all this stuff if the subxact failed before creating a
* ResourceOwner...
*/
*************** PushTransaction(void)
*** 4014,4019 ****
--- 4039,4045 ----
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 Thu Oct 8 09:29:32 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,224 ----
else
{
Oid id;
+ Oid *secLabels =
+ sepgsql_relation_create(LexIDStr($5),
+ RELKIND_RELATION,
+ tupdesc,
+ PG_CATALOG_NAMESPACE,
+ NULL, NIL,
+ false, false);
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();
--- 233,240 ----
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 Tue Dec 8 14:04:25 2009
***************
*** 26,37 ****
--- 26,39 ----
#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"
#include "nodes/makefuncs.h"
#include "postmaster/bgwriter.h"
#include "postmaster/walwriter.h"
+ #include "security/sepgsql.h"
#include "storage/bufmgr.h"
#include "storage/ipc.h"
#include "storage/proc.h"
*************** AuxiliaryProcessMain(int argc, char *arg
*** 338,343 ****
--- 340,350 ----
case WalWriterProcess:
statmsg = "wal writer process";
break;
+ #ifdef HAVE_SELINUX
+ case SelinuxReceiverProcess:
+ statmsg = "selinux netlink receiver";
+ break;
+ #endif
default:
statmsg = "??? process";
break;
*************** AuxiliaryProcessMain(int argc, char *arg
*** 430,435 ****
--- 437,448 ----
WalWriterMain();
proc_exit(1); /* should never return */
+ #ifdef HAVE_SELINUX
+ case SelinuxReceiverProcess:
+ sepgsqlReceiverMain();
+ proc_exit(1); /* should nener return */
+ #endif
+
default:
elog(PANIC, "unrecognized process type: %d", auxType);
proc_exit(1);
*************** BootstrapModeMain(void)
*** 497,502 ****
--- 510,520 ----
*/
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 ****
--- 812,819 ----
tupDesc = CreateTupleDesc(numattr,
RelationGetForm(boot_reldesc)->relhasoids,
attrtypes);
+ tupDesc->tdhassecid = RelationGetDescr(boot_reldesc)->tdhassecid;
+
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 Fri Sep 18 14:51:00 2009
***************
*** 35,40 ****
--- 35,41 ----
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
+ #include "catalog/pg_security.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
#include "catalog/pg_ts_config.h"
***************
*** 43,48 ****
--- 44,50 ----
#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"
*************** expand_all_col_privileges(Oid table_oid,
*** 672,677 ****
--- 674,685 ----
if (curr_att == ObjectIdAttributeNumber && !classForm->relhasoids)
continue;
+ /* Skip OID column, if it doesn't exist */
+ if (curr_att == SecurityAttributeNumber &&
+ (classForm->relkind != RELKIND_RELATION ||
+ table_oid == SecurityRelationId))
+ continue;
+
/* Views don't have any system columns at all */
if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
continue;
*************** ExecGrant_Attribute(InternalGrant *istmt
*** 774,779 ****
--- 782,789 ----
relOid, grantorId, ACL_KIND_COLUMN,
relname, attnum,
NameStr(pg_attribute_tuple->attname));
+ /* SELinux checks */
+ sepgsql_attribute_grant(relOid, attnum);
/*
* Generate new ACL.
*************** ExecGrant_Relation(InternalGrant *istmt)
*** 1029,1034 ****
--- 1039,1046 ----
? ACL_KIND_SEQUENCE : ACL_KIND_CLASS,
NameStr(pg_class_tuple->relname),
0, NULL);
+ /* SELinux checks */
+ sepgsql_relation_grant(relOid);
/*
* Generate new ACL.
*************** ExecGrant_Database(InternalGrant *istmt)
*** 1217,1222 ****
--- 1229,1236 ----
datId, grantorId, ACL_KIND_DATABASE,
NameStr(pg_database_tuple->datname),
0, NULL);
+ /* SELinux permission checks */
+ sepgsql_database_grant(datId);
/*
* Generate new ACL.
*************** ExecGrant_Fdw(InternalGrant *istmt)
*** 1335,1340 ****
--- 1349,1356 ----
fdwid, grantorId, ACL_KIND_FDW,
NameStr(pg_fdw_tuple->fdwname),
0, NULL);
+ /* SELinux permission checks */
+ sepgsql_fdw_grant(fdwid);
/*
* Generate new ACL.
*************** ExecGrant_ForeignServer(InternalGrant *i
*** 1454,1459 ****
--- 1470,1477 ----
srvid, grantorId, ACL_KIND_FOREIGN_SERVER,
NameStr(pg_server_tuple->srvname),
0, NULL);
+ /* SELinux checks */
+ sepgsql_foreign_server_grant(srvid);
/*
* Generate new ACL.
*************** ExecGrant_Function(InternalGrant *istmt)
*** 1572,1577 ****
--- 1590,1597 ----
funcId, grantorId, ACL_KIND_PROC,
NameStr(pg_proc_tuple->proname),
0, NULL);
+ /* SELinux: db_procedure:{setattr} */
+ sepgsql_proc_grant(funcId);
/*
* Generate new ACL.
*************** ExecGrant_Language(InternalGrant *istmt)
*** 1696,1701 ****
--- 1716,1723 ----
langId, grantorId, ACL_KIND_LANGUAGE,
NameStr(pg_language_tuple->lanname),
0, NULL);
+ /* SELinux checks */
+ sepgsql_language_grant(langId);
/*
* Generate new ACL.
*************** ExecGrant_Namespace(InternalGrant *istmt
*** 1815,1820 ****
--- 1837,1845 ----
NameStr(pg_namespace_tuple->nspname),
0, NULL);
+ /* SELinux: db_schema:{setattr} */
+ sepgsql_schema_grant(nspid);
+
/*
* Generate new ACL.
*
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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/catalog/dependency.c Thu Sep 17 23:44:07 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
*** 160,166 ****
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);
--- 161,168 ----
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
*** 192,200 ****
* 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;
--- 194,202 ----
* 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
*** 240,246 ****
{
ObjectAddress *thisobj = targetObjects->refs + i;
! deleteOneObject(thisobj, depRel);
}
/* And clean up */
--- 242,248 ----
{
ObjectAddress *thisobj = targetObjects->refs + i;
! deleteOneObject(thisobj, depRel, permission);
}
/* And clean up */
*************** performDeletion(const ObjectAddress *obj
*** 249,254 ****
--- 251,268 ----
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
*** 322,328 ****
{
ObjectAddress *thisobj = targetObjects->refs + i;
! deleteOneObject(thisobj, depRel);
}
/* And clean up */
--- 336,343 ----
{
ObjectAddress *thisobj = targetObjects->refs + i;
! /* currently, all the caller path need permission checks */
! deleteOneObject(thisobj, depRel, true);
}
/* And clean up */
*************** deleteWhatDependsOn(const ObjectAddress
*** 393,399 ****
if (thisextra->flags & DEPFLAG_ORIGINAL)
continue;
! deleteOneObject(thisobj, depRel);
}
/* And clean up */
--- 408,414 ----
if (thisextra->flags & DEPFLAG_ORIGINAL)
continue;
! deleteOneObject(thisobj, depRel, false);
}
/* And clean up */
*************** reportDependentObjects(const ObjectAddre
*** 942,954 ****
* 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.)
--- 957,973 ----
* 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)
+ sepgsql_sysobj_drop(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 Sep 9 16:47:01 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, {SecurityAttributeName}, TEXTOID, 0, -1,
! SecurityAttributeNumber, 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 == SecurityAttributeNumber)
+ 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)->tdhassecid
+ = securityTupleDescHasSecid(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 (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(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,
*** 601,606 ****
--- 639,650 ----
SysAtt[i]->attnum == ObjectIdAttributeNumber)
continue;
+ /* skip Secid where appropriate */
+ if (SysAtt[i]->attnum == SecurityAttributeNumber &&
+ (relkind != RELKIND_RELATION ||
+ new_rel_oid == SecurityRelationId))
+ continue;
+
memcpy(&attStruct, (char *) SysAtt[i], sizeof(FormData_pg_attribute));
/* Fill in the correct relation OID in the copied tuple */
*************** AddNewAttributeTuples(Oid new_rel_oid,
*** 613,619 ****
attStruct.attinhcount = oidinhcount;
}
! InsertPgAttributeTuple(rel, &attStruct, indstate);
}
}
--- 657,667 ----
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];
--- 689,696 ----
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 ****
--- 739,747 ----
*/
HeapTupleSetOid(tup, new_rel_oid);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(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
--- 764,774 ----
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);
}
--- 825,836 ----
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;
--- 901,908 ----
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
--- 1078,1091 ----
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 ****
--- 1544,1554 ----
* 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 Fri Sep 18 17:02:48 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"
*************** 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);
--- 352,359 ----
Assert(indexTupDesc->attrs[i]->attnum == i + 1);
Assert(indexTupDesc->attrs[i]->attcacheoff == -1);
! InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i],
! indstate, InvalidOid);
}
CatalogCloseIndexes(indstate);
*************** index_create(Oid heapRelationId,
*** 652,658 ****
*/
InsertPgClassTuple(pg_class, indexRelation,
RelationGetRelid(indexRelation),
! reloptions);
/* done with pg_class */
heap_close(pg_class, RowExclusiveLock);
--- 654,660 ----
*/
InsertPgClassTuple(pg_class, indexRelation,
RelationGetRelid(indexRelation),
! reloptions, InvalidOid);
/* done with pg_class */
heap_close(pg_class, RowExclusiveLock);
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 Thu Sep 17 17:04:16 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"
*************** LookupExplicitNamespace(const char *nspn
*** 2105,2111 ****
--- 2106,2115 ----
if (strcmp(nspname, "pg_temp") == 0)
{
if (OidIsValid(myTempNamespace))
+ {
+ sepgsql_schema_search(myTempNamespace, true);
return myTempNamespace;
+ }
/*
* Since this is used only for looking up existing objects, there is
*************** LookupExplicitNamespace(const char *nspn
*** 2127,2132 ****
--- 2131,2137 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
nspname);
+ sepgsql_schema_search(namespaceId, true);
return namespaceId;
}
*************** recomputeNamespacePath(void)
*** 2722,2728 ****
if (OidIsValid(namespaceId) &&
!list_member_oid(oidlist, namespaceId) &&
pg_namespace_aclcheck(namespaceId, roleid,
! ACL_USAGE) == ACLCHECK_OK)
oidlist = lappend_oid(oidlist, namespaceId);
}
}
--- 2727,2734 ----
if (OidIsValid(namespaceId) &&
!list_member_oid(oidlist, namespaceId) &&
pg_namespace_aclcheck(namespaceId, roleid,
! ACL_USAGE) == ACLCHECK_OK &&
! sepgsql_schema_search(namespaceId, false))
oidlist = lappend_oid(oidlist, namespaceId);
}
}
*************** recomputeNamespacePath(void)
*** 2731,2737 ****
/* pg_temp --- substitute temp namespace, if any */
if (OidIsValid(myTempNamespace))
{
! if (!list_member_oid(oidlist, myTempNamespace))
oidlist = lappend_oid(oidlist, myTempNamespace);
}
else
--- 2737,2744 ----
/* pg_temp --- substitute temp namespace, if any */
if (OidIsValid(myTempNamespace))
{
! if (!list_member_oid(oidlist, myTempNamespace) &&
! sepgsql_schema_search(myTempNamespace, false))
oidlist = lappend_oid(oidlist, myTempNamespace);
}
else
*************** recomputeNamespacePath(void)
*** 2750,2756 ****
if (OidIsValid(namespaceId) &&
!list_member_oid(oidlist, namespaceId) &&
pg_namespace_aclcheck(namespaceId, roleid,
! ACL_USAGE) == ACLCHECK_OK)
oidlist = lappend_oid(oidlist, namespaceId);
}
}
--- 2757,2764 ----
if (OidIsValid(namespaceId) &&
!list_member_oid(oidlist, namespaceId) &&
pg_namespace_aclcheck(namespaceId, roleid,
! ACL_USAGE) == ACLCHECK_OK &&
! sepgsql_schema_search(namespaceId, false))
oidlist = lappend_oid(oidlist, namespaceId);
}
}
*************** InitTempTableNamespace(void)
*** 2816,2821 ****
--- 2824,2830 ----
char namespaceName[NAMEDATALEN];
Oid namespaceId;
Oid toastspaceId;
+ Oid nspsecid;
Assert(!OidIsValid(myTempNamespace));
*************** InitTempTableNamespace(void)
*** 2836,2841 ****
--- 2845,2853 ----
errmsg("permission denied to create temporary tables in database \"%s\"",
get_database_name(MyDatabaseId))));
+ /* SELinux checks permission to create temp schema */
+ nspsecid = sepgsql_schema_create(namespaceName, true, NULL);
+
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();
}
--- 2863,2871 ----
* 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();
}
--- 2891,2899 ----
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 ****
--- 3046,3058 ----
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_conversion.c sepgsql/src/backend/catalog/pg_conversion.c
*** base/src/backend/catalog/pg_conversion.c Sat Jan 3 13:01:35 2009
--- sepgsql/src/backend/catalog/pg_conversion.c Thu Sep 17 22:10:19 2009
*************** Oid
*** 40,46 ****
ConversionCreate(const char *conname, Oid connamespace,
Oid conowner,
int32 conforencoding, int32 contoencoding,
! Oid conproc, bool def)
{
int i;
Relation rel;
--- 40,46 ----
ConversionCreate(const char *conname, Oid connamespace,
Oid conowner,
int32 conforencoding, int32 contoencoding,
! Oid conproc, Oid consecid, bool def)
{
int i;
Relation rel;
*************** ConversionCreate(const char *conname, Oi
*** 104,109 ****
--- 104,111 ----
values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
tup = heap_form_tuple(tupDesc, values, nulls);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, consecid);
/* insert a new tuple */
oid = simple_heap_insert(rel, tup);
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 Tue Sep 8 23:55:48 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 (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, nspsecid);
nspoid = simple_heap_insert(nspdesc, tup);
Assert(OidIsValid(nspoid));
diff -Nrpc base/src/backend/catalog/pg_operator.c sepgsql/src/backend/catalog/pg_operator.c
*** base/src/backend/catalog/pg_operator.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/backend/catalog/pg_operator.c Thu Sep 17 22:10:19 2009
***************
*** 28,33 ****
--- 28,34 ----
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "parser/parse_oper.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
*************** OperatorShellMake(const char *operatorNa
*** 204,209 ****
--- 205,211 ----
{
Relation pg_operator_desc;
Oid operatorObjectId;
+ Oid secid;
int i;
HeapTuple tup;
Datum values[Natts_pg_operator];
*************** OperatorShellMake(const char *operatorNa
*** 220,225 ****
--- 222,231 ----
errmsg("\"%s\" is not a valid operator name",
operatorName)));
+ /* SELinux permission check */
+ secid = sepgsql_operator_create(operatorName, InvalidOid,
+ operatorNamespace,
+ InvalidOid, InvalidOid, InvalidOid);
/*
* initialize our *nulls and *values arrays
*/
*************** OperatorShellMake(const char *operatorNa
*** 260,265 ****
--- 266,273 ----
* create a new operator tuple
*/
tup = heap_form_tuple(tupDesc, values, nulls);
+ if (HeapTupleHasSecid(tup) && OidIsValid(secid))
+ HeapTupleSetSecid(tup, secid);
/*
* insert our "shell" operator tuple
*************** OperatorCreate(const char *operatorName,
*** 347,352 ****
--- 355,361 ----
bool selfCommutator = false;
NameData oname;
TupleDesc tupDesc;
+ Oid secid;
int i;
/*
*************** OperatorCreate(const char *operatorName,
*** 476,481 ****
--- 485,494 ----
else
negatorId = InvalidOid;
+ /* SELinux permission checks */
+ secid = sepgsql_operator_create(operatorName, operatorObjectId,
+ operatorNamespace,
+ procedureId, restrictionId, joinId);
/*
* set up values in the operator tuple
*/
*************** OperatorCreate(const char *operatorName,
*** 523,528 ****
--- 536,543 ----
values,
nulls,
replaces);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, secid);
simple_heap_update(pg_operator_desc, &tup->t_self, tup);
}
*************** OperatorCreate(const char *operatorName,
*** 530,535 ****
--- 545,552 ----
{
tupDesc = pg_operator_desc->rd_att;
tup = heap_form_tuple(tupDesc, values, nulls);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, secid);
operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
}
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 Fri Sep 18 17:39:46 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
*** 343,348 ****
--- 346,356 ----
ObjectIdGetDatum(procNamespace),
0);
+ /* Check permission to create/replace a function */
+ prosecid = sepgsql_proc_create(procedureName, oldtup,
+ procNamespace, languageObjectId,
+ (DefElem *)proseclabel);
+
if (HeapTupleIsValid(oldtup))
{
/* There is one; okay to replace it? */
*************** ProcedureCreate(const char *procedureNam
*** 477,482 ****
--- 485,492 ----
/* Okay, do it... */
tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, prosecid);
simple_heap_update(rel, &tup->t_self, tup);
ReleaseSysCache(oldtup);
*************** ProcedureCreate(const char *procedureNam
*** 486,491 ****
--- 496,503 ----
{
/* Creating a new procedure */
tup = heap_form_tuple(tupDesc, values, nulls);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(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 Thu Sep 10 15:18:03 2009
***************
*** 0 ****
--- 1,637 ----
+ /*
+ * 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
+ securityTupleDescHasSecid(Oid relid, char relkind)
+ {
+ return sepgsqlTupleDescHasSecid(relid, relkind);
+ }
+
+ /*
+ * 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;
+ Datum values[Natts_pg_security];
+ bool nulls[Natts_pg_security];
+
+ if (!earlySecAttrList)
+ return; /* do nothing */
+
+ StartTransactionCommand();
+
+ /* 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);
+
+ 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;
+ 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);
+
+ tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
+
+ 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);
+ }
+
+ /*
+ * Output handler for system columns
+ */
+ Datum
+ securitySysattSecLabelOut(Oid relid, HeapTuple tuple)
+ {
+ char *seclabel;
+
+ seclabel = sepgsqlSysattSecLabelOut(relid, tuple);
+ if (!seclabel)
+ seclabel = "unlabled";
+
+ 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(HeapTupleHeaderGetSecid(tuphdr));
+ }
diff -Nrpc base/src/backend/catalog/pg_shdepend.c sepgsql/src/backend/catalog/pg_shdepend.c
*** base/src/backend/catalog/pg_shdepend.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/backend/catalog/pg_shdepend.c Fri Sep 18 14:51:00 2009
***************
*** 36,41 ****
--- 36,42 ----
#include "commands/schemacmds.h"
#include "commands/tablecmds.h"
#include "commands/typecmds.h"
+ #include "security/sepgsql.h"
#include "storage/lmgr.h"
#include "miscadmin.h"
#include "utils/acl.h"
*************** shdepReassignOwned(List *roleids, Oid ne
*** 1336,1341 ****
--- 1337,1344 ----
break;
case TypeRelationId:
+ /* SELinux checks */
+ sepgsql_type_alter(sdepForm->objid, NULL, InvalidOid);
AlterTypeOwnerInternal(sdepForm->objid, newrole, true);
break;
*************** shdepReassignOwned(List *roleids, Oid ne
*** 1348,1354 ****
break;
case RelationRelationId:
!
/*
* Pass recursing = true so that we don't fail on indexes,
* owned sequences, etc when we happen to visit them
--- 1351,1358 ----
break;
case RelationRelationId:
! /* SELinux checks */
! sepgsql_relation_alter(sdepForm->objid, NULL, InvalidOid);
/*
* Pass recursing = true so that we don't fail on indexes,
* owned sequences, etc when we happen to visit them
diff -Nrpc base/src/backend/catalog/pg_type.c sepgsql/src/backend/catalog/pg_type.c
*** base/src/backend/catalog/pg_type.c Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/catalog/pg_type.c Fri Sep 18 17:39:46 2009
***************
*** 25,30 ****
--- 25,31 ----
#include "commands/typecmds.h"
#include "miscadmin.h"
#include "parser/scansup.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
*************** TypeShellMake(const char *typeName, Oid
*** 56,65 ****
--- 57,73 ----
Datum values[Natts_pg_type];
bool nulls[Natts_pg_type];
Oid typoid;
+ Oid typsid;
NameData name;
Assert(PointerIsValid(typeName));
+ /* SELinux check permission to create a shell type */
+ typsid = sepgsql_type_create(typeName, InvalidOid, typeNamespace,
+ F_SHELL_IN, F_SHELL_OUT,
+ InvalidOid, InvalidOid,
+ InvalidOid, InvalidOid, InvalidOid);
+
/*
* open pg_type
*/
*************** TypeCreate(Oid newTypeOid,
*** 201,206 ****
--- 209,215 ----
{
Relation pg_type_desc;
Oid typeObjectId;
+ Oid typeSecid = InvalidOid;
bool rebuildDeps = false;
HeapTuple tup;
bool nulls[Natts_pg_type];
*************** TypeCreate(Oid newTypeOid,
*** 367,372 ****
--- 376,390 ----
CStringGetDatum(typeName),
ObjectIdGetDatum(typeNamespace),
0, 0);
+
+ /* SELinux checks to create/replace type */
+ if (!isImplicitArray && typeType != TYPTYPE_COMPOSITE)
+ typeSecid = sepgsql_type_create(typeName, tup, typeNamespace,
+ inputProcedure, outputProcedure,
+ receiveProcedure, sendProcedure,
+ typmodinProcedure, typmodoutProcedure,
+ analyzeProcedure);
+
if (HeapTupleIsValid(tup))
{
/*
*************** TypeCreate(Oid newTypeOid,
*** 412,417 ****
--- 430,437 ----
/* Force the OID if requested by caller, else heap_insert does it */
if (OidIsValid(newTypeOid))
HeapTupleSetOid(tup, newTypeOid);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, typeSecid);
typeObjectId = simple_heap_insert(pg_type_desc, tup);
}
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 Thu Oct 8 09:29:32 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,211 ----
else
namespaceid = PG_TOAST_NAMESPACE;
+ secLabels = sepgsql_relation_create(toast_relname,
+ RELKIND_TOASTVALUE,
+ tupdesc, namespaceid,
+ NULL, NIL, false, false);
+
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();
--- 219,226 ----
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 Thu Sep 17 22:10:19 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 permission checks */
+ sepgsql_proc_alter(procOid, newname, InvalidOid);
+
/* 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 Fri Sep 18 14:51:00 2009
*************** ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
*** 284,286 ****
--- 284,315 ----
(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 Fri Sep 18 14:51:00 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,
! sepgsql_relation_copy(OldHeap));
ReleaseSysCache(tuple);
*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl
*** 924,929 ****
--- 927,936 ----
if (NewHeap->rd_rel->relhasoids)
HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple));
+ /* Preserve SID, if any */
+ if (HeapTupleHasSecid(copiedTuple))
+ HeapTupleSetSecid(copiedTuple, HeapTupleGetSecid(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 Thu Sep 17 22:10:19 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
*** 45,50 ****
--- 46,52 ----
int from_encoding;
int to_encoding;
Oid funcoid;
+ Oid secid;
const char *from_encoding_name = stmt->for_encoding_name;
const char *to_encoding_name = stmt->to_encoding_name;
List *func_name = stmt->func_name;
*************** CreateConversionCommand(CreateConversion
*** 96,101 ****
--- 98,106 ----
aclcheck_error(aclresult, ACL_KIND_PROC,
NameListToString(func_name));
+ /* SELinux checks */
+ secid = sepgsql_conversion_create(conversion_name, namespaceId, funcoid);
+
/*
* Check that the conversion function is suitable for the requested source
* and target encodings. We do that by calling the function with an empty
*************** CreateConversionCommand(CreateConversion
*** 114,120 ****
* name)
*/
ConversionCreate(conversion_name, namespaceId, GetUserId(),
! from_encoding, to_encoding, funcoid, stmt->def);
}
/*
--- 119,125 ----
* name)
*/
ConversionCreate(conversion_name, namespaceId, GetUserId(),
! from_encoding, to_encoding, funcoid, secid, stmt->def);
}
/*
*************** RenameConversion(List *name, const char
*** 240,245 ****
--- 245,253 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
+ /* SELinux checks */
+ sepgsql_conversion_alter(conversionOid, newname);
+
/* rename */
namestrcpy(&(((Form_pg_conversion) GETSTRUCT(tup))->conname), newname);
simple_heap_update(rel, &tup->t_self, tup);
*************** AlterConversionOwner_internal(Relation r
*** 336,341 ****
--- 344,351 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(convForm->connamespace));
}
+ /* SELinux checks */
+ sepgsql_conversion_alter(HeapTupleGetOid(tup), NULL);
/*
* Modify the owner --- okay to scribble on tup because it's a copy
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 Mon Sep 28 09:29:32 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,250 ****
/* 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);
static bool CopyReadLineText(CopyState cstate);
--- 252,259 ----
/* non-export function prototypes */
static void DoCopyTo(CopyState cstate);
static void CopyTo(CopyState cstate);
! static void CopyOneRowTo(CopyState cstate, HeapTuple tuple,
! Datum *values, bool *nulls);
static void CopyFrom(CopyState cstate);
static bool CopyReadLine(CopyState cstate);
static bool CopyReadLineText(CopyState cstate);
*************** DoCopy(const CopyStmt *stmt, const char
*** 958,969 ****
errmsg("CSV quote character must not appear in the NULL specification")));
/* Disallow file COPY except to superusers. */
! if (!pipe && !superuser())
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser to COPY to or from a file"),
! errhint("Anyone can COPY to stdout or from stdin. "
! "psql's \\copy command also works for anyone.")));
if (stmt->relation)
{
--- 967,985 ----
errmsg("CSV quote character must not appear in the NULL specification")));
/* Disallow file COPY except to superusers. */
! if (!pipe)
! {
! if (!superuser())
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser to COPY to or from a file"),
! errhint("Anyone can COPY to stdout or from stdin. "
! "psql's \\copy command also works for anyone.")));
! if (is_from)
! sepgsql_file_read(stmt->filename);
! else
! sepgsql_file_write(stmt->filename);
! }
if (stmt->relation)
{
*************** DoCopy(const CopyStmt *stmt, const char
*** 1090,1095 ****
--- 1106,1114 ----
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;
}
}
--- 1123,1153 ----
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 SecurityAttributeNumber:
! 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;
}
}
--- 1165,1187 ----
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;
}
}
*************** 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]);
}
/*
--- 1373,1403 ----
int attnum = lfirst_int(cur);
Oid out_func_oid;
bool isvarlena;
+ FmgrInfo *out_fmgr;
+ Form_pg_attribute attForm;
+
+ switch (attnum)
+ {
+ case SecurityAttributeNumber:
+ 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);
--- 1452,1465 ----
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);
--- 1485,1499 ----
{
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, 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;
--- 1519,1526 ----
* Emit one row during CopyTo().
*/
static void
! CopyOneRowTo(CopyState cstate, HeapTuple tuple,
! Datum *values, bool *nulls)
{
bool need_delim = false;
FmgrInfo *out_functions = cstate->out_functions;
*************** CopyOneRowTo(CopyState cstate, Oid tuple
*** 1461,1467 ****
{
/* Hack --- assume Oid is same size as int32 */
CopySendInt32(cstate, sizeof(int32));
! CopySendInt32(cstate, tupleOid);
}
}
else
--- 1540,1546 ----
{
/* Hack --- assume Oid is same size as int32 */
CopySendInt32(cstate, sizeof(int32));
! CopySendInt32(cstate, HeapTupleGetOid(tuple));
}
}
else
*************** CopyOneRowTo(CopyState cstate, Oid tuple
*** 1471,1477 ****
if (cstate->oids)
{
string = DatumGetCString(DirectFunctionCall1(oidout,
! ObjectIdGetDatum(tupleOid)));
CopySendString(cstate, string);
need_delim = true;
}
--- 1550,1556 ----
if (cstate->oids)
{
string = DatumGetCString(DirectFunctionCall1(oidout,
! ObjectIdGetDatum(HeapTupleGetOid(tuple))));
CopySendString(cstate, string);
need_delim = true;
}
*************** 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)
{
--- 1559,1569 ----
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 ****
--- 1572,1595 ----
need_delim = true;
}
+ switch (attnum)
+ {
+ case SecurityAttributeNumber:
+ relid = RelationGetRelid(cstate->rel);
+ value = securitySysattSecLabelOut(relid, tuple);
+ 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);
--- 1601,1609 ----
{
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);
--- 1612,1618 ----
{
bytea *outputbytes;
! outputbytes = SendFunctionCall(out_fmgr, value);
CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);
CopySendData(cstate, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ);
*************** CopyFrom(CopyState cstate)
*** 1649,1656 ****
--- 1746,1755 ----
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)
*** 1888,1893 ****
--- 1987,2004 ----
fmgr_info(in_func_oid, &oid_in_function);
}
+ if (list_member_int(cstate->attnumlist,
+ SecurityAttributeNumber))
+ {
+ 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 ****
--- 2033,2039 ----
{
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 &&
--- 2105,2125 ----
/* 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;
}
--- 2129,2168 ----
string = cstate->null_print;
}
! cstate->cur_attname = NameStr(attForm->attname);
cstate->cur_attval = string;
!
! switch (attnum)
! {
! case SecurityAttributeNumber:
! 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;
}
}
--- 2208,2248 ----
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 SecurityAttributeNumber:
! 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 ****
--- 2263,2270 ----
if (cstate->oids && file_has_oids)
HeapTupleSetOid(tuple, loaded_oid);
+ if (HeapTupleHasSecid(tuple))
+ HeapTupleSetSecid(tuple, loaded_seclabel);
/* Triggers and stuff need to be invoked in query context. */
MemoryContextSwitchTo(oldcontext);
*************** CopyFrom(CopyState cstate)
*** 2118,2123 ****
--- 2289,2297 ----
}
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 ****
--- 3572,3584 ----
}
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);
}
/*
--- 3626,3633 ----
slot_getallattrs(slot);
/* And send the data */
! CopyOneRowTo(cstate, slot->tts_tuple,
! 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 Thu Sep 17 17:04:16 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_context") == 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 = sepgsql_database_create(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 (HeapTupleHasSecid(tuple))
+ HeapTupleSetSecid(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 */
+ sepgsql_database_drop(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} */
+ sepgsql_database_alter(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} */
+ sepgsql_database_alter(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} */
+ sepgsql_database_alter(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} */
+ sepgsql_database_alter(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} */
+ sepgsql_database_alter(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);
+ if (!HeapTupleHasSecid(newtup))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Unable to set security label on \"%s\"", dbname)));
+ 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 = sepgsql_database_relabel(HeapTupleGetOid(newtup), seclabel);
+ HeapTupleSetSecid(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 Thu Sep 17 22:10:19 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"
*************** AlterForeignDataWrapperOwner(const char
*** 233,238 ****
--- 234,242 ----
if (form->fdwowner != newOwnerId)
{
+ /* SELinux permission check */
+ sepgsql_fdw_alter(fdwId, InvalidOid);
+
form->fdwowner = newOwnerId;
simple_heap_update(rel, &tup->t_self, tup);
*************** AlterForeignServerOwner(const char *name
*** 297,302 ****
--- 301,308 ----
aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
}
}
+ /* SELinux permission checks */
+ sepgsql_foreign_server_alter(srvId);
form->srvowner = newOwnerId;
*************** CreateForeignDataWrapper(CreateFdwStmt *
*** 342,347 ****
--- 348,354 ----
Oid fdwvalidator;
Datum fdwoptions;
Oid ownerId;
+ Oid secid;
/* Must be super user */
if (!superuser())
*************** CreateForeignDataWrapper(CreateFdwStmt *
*** 380,385 ****
--- 387,395 ----
else
fdwvalidator = InvalidOid;
+ /* SELinux permission checks */
+ secid = sepgsql_fdw_create(stmt->fdwname, fdwvalidator);
+
values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = fdwvalidator;
nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
*************** CreateForeignDataWrapper(CreateFdwStmt *
*** 393,398 ****
--- 403,410 ----
nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
tuple = heap_form_tuple(rel->rd_att, values, nulls);
+ if (HeapTupleHasSecid(tuple))
+ HeapTupleSetSecid(tuple, secid);
fdwId = simple_heap_insert(rel, tuple);
CatalogUpdateIndexes(rel, tuple);
*************** AlterForeignDataWrapper(AlterFdwStmt *st
*** 487,492 ****
--- 499,507 ----
fdwvalidator = DatumGetObjectId(datum);
}
+ /* SELinux permission checks */
+ sepgsql_fdw_alter(fdwId, fdwvalidator);
+
/*
* Options specified, validate and update.
*/
*************** CreateForeignServer(CreateForeignServerS
*** 609,614 ****
--- 624,630 ----
HeapTuple tuple;
Oid srvId;
Oid ownerId;
+ Oid secid;
AclResult aclresult;
ObjectAddress myself;
ObjectAddress referenced;
*************** CreateForeignServer(CreateForeignServerS
*** 636,641 ****
--- 652,659 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
+ secid = sepgsql_foreign_server_create(stmt->fdwname);
+
/*
* Insert tuple into pg_foreign_server.
*/
*************** CreateForeignServer(CreateForeignServerS
*** 676,681 ****
--- 694,701 ----
nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
tuple = heap_form_tuple(rel->rd_att, values, nulls);
+ if (HeapTupleHasSecid(tuple))
+ HeapTupleSetSecid(tuple, secid);
srvId = simple_heap_insert(rel, tuple);
*************** AlterForeignServer(AlterForeignServerStm
*** 732,737 ****
--- 752,760 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
stmt->servername);
+ /* SELinux permission checks */
+ sepgsql_foreign_server_alter(srvId);
+
memset(repl_val, 0, sizeof(repl_val));
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
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 Thu Sep 17 17:04:16 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_context") == 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 permission checks */
+ sepgsql_proc_alter(procOid, newname, InvalidOid);
+
/* 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 permission checks */
+ sepgsql_proc_alter(procOid, NULL, InvalidOid);
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
*************** AlterFunctionOwner_internal(Relation rel
*** 1258,1263 ****
--- 1279,1337 ----
}
/*
+ * ALTER FUNCTION name(args,...) SECURITY_LABEL [=] newlabel
+ */
+ void
+ AlterFunctionSecLabel(List *name, List *argtypes, DefElem *seclabel)
+ {
+ Relation rel;
+ HeapTuple oldtup;
+ HeapTuple newtup;
+ Oid procOid;
+ Oid secid;
+ bool replaces[Natts_pg_proc];
+
+ /* open pg_proc system catalog */
+ rel = heap_open(ProcedureRelationId, RowExclusiveLock);
+
+ procOid = LookupFuncNameTypeNames(name, argtypes, false);
+
+ oldtup = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(procOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(oldtup))
+ elog(ERROR, "cache lookup failed for function %u", procOid);
+
+ memset(replaces, false, sizeof(replaces));
+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
+ NULL, NULL, replaces);
+
+ if (!HeapTupleHasSecid(newtup))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Unable to set security label on \"%s\"",
+ get_func_name(procOid))));
+
+ 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 permission checks */
+ secid = sepgsql_proc_relabel(procOid, seclabel);
+ HeapTupleSetSecid(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 ****
--- 1370,1378 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(stmt->func->funcname));
+ /* SELinux checks permissions */
+ sepgsql_proc_alter(funcOid, NULL, InvalidOid);
+
if (procForm->proisagg)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
*************** CreateCast(CreateCastStmt *stmt)
*** 1473,1478 ****
--- 1550,1556 ----
char sourcetyptype;
char targettyptype;
Oid funcid;
+ Oid secid;
int nargs;
char castcontext;
char castmethod;
*************** CreateCast(CreateCastStmt *stmt)
*** 1674,1679 ****
--- 1752,1759 ----
castcontext = 0; /* keep compiler quiet */
break;
}
+ /* SELinux permission check */
+ secid = sepgsql_cast_create(sourcetypeid, targettypeid, funcid);
relation = heap_open(CastRelationId, RowExclusiveLock);
*************** CreateCast(CreateCastStmt *stmt)
*** 1704,1709 ****
--- 1784,1792 ----
tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
+ if (HeapTupleHasSecid(tuple))
+ HeapTupleSetSecid(tuple, secid);
+
simple_heap_insert(relation, tuple);
CatalogUpdateIndexes(relation, tuple);
*************** AlterFunctionNamespace(List *name, List
*** 1897,1902 ****
--- 1980,1988 ----
NameStr(proc->proname),
newschema)));
+ /* SELinux checks permissions */
+ sepgsql_proc_alter(procOid, NULL, nspOid);
+
/* OK, modify the pg_proc row */
/* tup is a copy, so we can scribble directly on it */
diff -Nrpc base/src/backend/commands/indexcmds.c sepgsql/src/backend/commands/indexcmds.c
*** base/src/backend/commands/indexcmds.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/backend/commands/indexcmds.c Fri Sep 18 17:02:48 2009
***************
*** 37,42 ****
--- 37,43 ----
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
#include "parser/parsetree.h"
+ #include "security/sepgsql.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "storage/procarray.h"
*************** DefineIndex(RangeVar *heapRelation,
*** 258,263 ****
--- 259,267 ----
}
}
+ /* SELinux checks */
+ sepgsql_index_create(relationId, namespaceId, check_rights);
+
/*
* look up the access method, verify it can handle the requested features
*/
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 Fri Sep 18 14:51:00 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 */
+ sepgsql_relation_lock(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/opclasscmds.c sepgsql/src/backend/commands/opclasscmds.c
*** base/src/backend/commands/opclasscmds.c Sat Jan 3 13:01:35 2009
--- sepgsql/src/backend/commands/opclasscmds.c Thu Sep 17 17:04:16 2009
***************
*** 35,40 ****
--- 35,41 ----
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
*************** CreateOpFamily(char *amname, char *opfna
*** 177,182 ****
--- 178,184 ----
HeapTuple tup;
Datum values[Natts_pg_opfamily];
bool nulls[Natts_pg_opfamily];
+ Oid opfSecid;
NameData opfName;
ObjectAddress myself,
referenced;
*************** CreateOpFamily(char *amname, char *opfna
*** 197,202 ****
--- 199,207 ----
errmsg("operator family \"%s\" for access method \"%s\" already exists",
opfname, amname)));
+ /* SELinux check permission */
+ opfSecid = sepgsql_opfamily_create(opfname, namespaceoid);
+
/*
* Okay, let's create the pg_opfamily entry.
*/
*************** CreateOpFamily(char *amname, char *opfna
*** 210,215 ****
--- 215,222 ----
values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
tup = heap_form_tuple(rel->rd_att, values, nulls);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, opfSecid);
opfamilyoid = simple_heap_insert(rel, tup);
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 265,270 ****
--- 272,278 ----
Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
+ Oid opcSecid;
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 353,358 ****
--- 361,369 ----
NameListToString(stmt->opfamilyname), stmt->amname)));
opfamilyoid = HeapTupleGetOid(tup);
+ /* SELinux checks permission */
+ sepgsql_opfamily_alter(opfamilyoid, NULL);
+
/*
* XXX given the superuser check above, there's no need for an
* ownership check here
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 371,376 ****
--- 382,390 ----
{
opfamilyoid = HeapTupleGetOid(tup);
+ /* SELinux checks permission */
+ sepgsql_opfamily_alter(opfamilyoid, NULL);
+
/*
* XXX given the superuser check above, there's no need for an
* ownership check here
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 441,446 ****
--- 455,462 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
get_func_name(funcOid));
#endif
+ /* SELinux check permission */
+ sepgsql_opfamily_add_operator(opfamilyoid, operOid);
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 465,470 ****
--- 481,488 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
get_func_name(funcOid));
#endif
+ /* SELinux check permission */
+ sepgsql_opfamily_add_procedure(opfamilyoid, funcOid);
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 531,536 ****
--- 549,557 ----
errmsg("operator class \"%s\" for access method \"%s\" already exists",
opcname, stmt->amname)));
+ /* SELinux permission check */
+ opcSecid = sepgsql_opclass_create(opcname, namespaceoid);
+
/*
* If we are creating a default opclass, check there isn't one already.
* (Note we do not restrict this test to visible opclasses; this ensures
*************** DefineOpFamily(CreateOpFamilyStmt *stmt)
*** 657,662 ****
--- 678,684 ----
HeapTuple tup;
Datum values[Natts_pg_opfamily];
bool nulls[Natts_pg_opfamily];
+ Oid opfSecid;
AclResult aclresult;
NameData opfName;
ObjectAddress myself,
*************** DefineOpFamily(CreateOpFamilyStmt *stmt)
*** 699,704 ****
--- 721,729 ----
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to create an operator family")));
+ /* SELinux permission check */
+ opfSecid = sepgsql_opfamily_create(opfname, namespaceoid);
+
rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
/*
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 773,778 ****
--- 798,804 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
+ Oid opfSecid;
Form_pg_am pg_am;
/* Get necessary info about access method */
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 805,810 ****
--- 831,837 ----
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
NameListToString(stmt->opfamilyname), stmt->amname)));
opfamilyoid = HeapTupleGetOid(tup);
+ opfSecid = HeapTupleGetSecid(tup);
ReleaseSysCache(tup);
/*
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 817,822 ****
--- 844,852 ----
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter an operator family")));
+ /* SELinux permission checks */
+ sepgsql_opfamily_alter(opfamilyoid, NULL);
+
/*
* ADD and DROP cases need separate code from here on down.
*/
*************** AlterOpFamilyAdd(List *opfamilyname, Oid
*** 893,898 ****
--- 923,930 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
get_func_name(funcOid));
#endif
+ /* SELinux permission check */
+ sepgsql_opfamily_add_operator(opfamilyoid, operOid);
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
*************** AlterOpFamilyAdd(List *opfamilyname, Oid
*** 917,922 ****
--- 949,956 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
get_func_name(funcOid));
#endif
+ /* SELinux permission check */
+ sepgsql_opfamily_add_procedure(opfamilyoid, funcOid);
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
*************** RenameOpClass(List *name, const char *ac
*** 1815,1820 ****
--- 1849,1857 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
+ /* SELinux permission checks */
+ sepgsql_opclass_alter(opcOid, newname);
+
/* rename */
namestrcpy(&(((Form_pg_opclass) GETSTRUCT(tup))->opcname), newname);
simple_heap_update(rel, &tup->t_self, tup);
*************** RenameOpFamily(List *name, const char *a
*** 1915,1920 ****
--- 1952,1960 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
+ /* SELinux check permissions */
+ sepgsql_opfamily_alter(opfOid, newname);
+
/* rename */
namestrcpy(&(((Form_pg_opfamily) GETSTRUCT(tup))->opfname), newname);
simple_heap_update(rel, &tup->t_self, tup);
*************** AlterOpClassOwner_internal(Relation rel,
*** 2035,2040 ****
--- 2075,2082 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
}
+ /* SELinux permission check */
+ sepgsql_opclass_alter(HeapTupleGetOid(tup), NULL);
/*
* Modify the owner --- okay to scribble on tup because it's a copy
*************** AlterOpFamilyOwner_internal(Relation rel
*** 2162,2167 ****
--- 2204,2211 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
}
+ /* SELinux permission checks */
+ sepgsql_opfamily_alter(HeapTupleGetOid(tup), NULL);
/*
* Modify the owner --- okay to scribble on tup because it's a copy
diff -Nrpc base/src/backend/commands/operatorcmds.c sepgsql/src/backend/commands/operatorcmds.c
*** base/src/backend/commands/operatorcmds.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/backend/commands/operatorcmds.c Thu Sep 17 22:10:19 2009
***************
*** 45,50 ****
--- 45,51 ----
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
*************** AlterOperatorOwner_internal(Relation rel
*** 432,437 ****
--- 433,440 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(oprForm->oprnamespace));
}
+ /* SELinux permission check */
+ sepgsql_operator_alter(operOid);
/*
* Modify the owner --- okay to scribble on tup because it's a copy
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 Thu Sep 17 22:10:19 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,192 ****
NIL,
PointerGetDatum(NULL),
1,
! 0);
}
}
else
--- 188,195 ----
NIL,
PointerGetDatum(NULL),
1,
! 0,
! NULL);
}
}
else
*************** create_proc_lang(const char *languageNam
*** 275,284 ****
--- 278,293 ----
bool nulls[Natts_pg_language];
NameData langname;
HeapTuple tup;
+ Oid langSecid;
ObjectAddress myself,
referenced;
/*
+ * SELinux permission checks
+ */
+ langSecid = sepgsql_language_create(languageName, handlerOid, valOid);
+
+ /*
* Insert the new language into pg_language
*/
rel = heap_open(LanguageRelationId, RowExclusiveLock);
*************** create_proc_lang(const char *languageNam
*** 297,302 ****
--- 306,313 ----
nulls[Anum_pg_language_lanacl - 1] = true;
tup = heap_form_tuple(tupDesc, values, nulls);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, langSecid);
simple_heap_insert(rel, tup);
*************** RenameLanguage(const char *oldname, cons
*** 518,523 ****
--- 529,537 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
oldname);
+ /* SELinux permission checks */
+ sepgsql_language_alter(HeapTupleGetOid(tup));
+
/* rename */
namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname);
simple_heap_update(rel, &tup->t_self, tup);
*************** AlterLanguageOwner_internal(HeapTuple tu
*** 613,618 ****
--- 627,635 ----
/* Must be able to become new owner */
check_is_member_of_role(GetUserId(), newOwnerId);
+ /* SELinux permission checks */
+ sepgsql_language_alter(HeapTupleGetOid(tup));
+
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
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 Thu Sep 17 17:04:16 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 = sepgsql_schema_create(schemaName, false,
+ (DefElem *)stmt->secLabel);
+
/* 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
*** 267,274 ****
errmsg("schema \"%s\" does not exist", oldname)));
/* make sure the new name doesn't exist */
! if (HeapTupleIsValid(
! SearchSysCache(NAMESPACENAME,
CStringGetDatum(newname),
0, 0, 0)))
ereport(ERROR,
--- 273,279 ----
errmsg("schema \"%s\" does not exist", oldname)));
/* make sure the new name doesn't exist */
! if (HeapTupleIsValid(SearchSysCache(NAMESPACENAME,
CStringGetDatum(newname),
0, 0, 0)))
ereport(ERROR,
*************** RenameSchema(const char *oldname, const
*** 286,291 ****
--- 291,299 ----
aclcheck_error(aclresult, ACL_KIND_DATABASE,
get_database_name(MyDatabaseId));
+ /* SELinux checks db_schema:{setattr} */
+ sepgsql_schema_alter(HeapTupleGetOid(tup));
+
if (!allowSystemTableMods && IsReservedName(newname))
ereport(ERROR,
(errcode(ERRCODE_RESERVED_NAME),
*************** AlterSchemaOwner_internal(HeapTuple tup,
*** 397,402 ****
--- 405,413 ----
aclcheck_error(aclresult, ACL_KIND_DATABASE,
get_database_name(MyDatabaseId));
+ /* SELinux checks db_schema:{setattr} */
+ sepgsql_schema_alter(HeapTupleGetOid(tup));
+
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
*************** AlterSchemaOwner_internal(HeapTuple tup,
*** 431,433 ****
--- 442,492 ----
}
}
+
+ /*
+ * 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);
+ if (!HeapTupleHasSecid(newtup))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Unable to set security label on \"%s\"", name)));
+
+ 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 = sepgsql_schema_relabel(HeapTupleGetOid(newtup), secLabel);
+ HeapTupleSetSecid(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 Fri Sep 18 14:51:00 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} */
+ sepgsql_relation_alter(relid, NULL, InvalidOid);
/* 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} */
+ sepgsql_sequence_next_value(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} */
+ sepgsql_sequence_get_value(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} */
+ sepgsql_sequence_get_value(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} */
+ sepgsql_sequence_set_value(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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/commands/tablecmds.c Thu Oct 8 09:29:32 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"
*************** static void ATExecCmd(List **wqueue, Alt
*** 260,267 ****
static void ATRewriteTables(List **wqueue);
static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap);
static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
! static void ATSimplePermissions(Relation rel, bool allowView);
! static void ATSimplePermissionsRelationOrIndex(Relation rel);
static void ATSimpleRecursion(List **wqueue, Relation rel,
AlterTableCmd *cmd, bool recurse);
static void ATOneLevelRecursion(List **wqueue, Relation rel,
--- 261,268 ----
static void ATRewriteTables(List **wqueue);
static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap);
static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
! static void ATSimplePermissions(Relation rel, const char *colname, bool allowView);
! static void ATSimplePermissionsRelationOrIndex(Relation rel, const char *colname);
static void ATSimpleRecursion(List **wqueue, Relation rel,
AlterTableCmd *cmd, bool recurse);
static void ATOneLevelRecursion(List **wqueue, Relation rel,
*************** 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
*** 444,449 ****
--- 446,461 ----
localHasOids = interpretOidsOption(stmt->options);
descriptor->tdhasoid = (localHasOids || parentOidCount > 0);
+ /* SELinux checks db_table:{create} and db_column:{create} */
+ secLabels = sepgsql_relation_create(relname,
+ relkind,
+ descriptor,
+ namespaceId,
+ (DefElem *)stmt->secLabel,
+ schema,
+ false,
+ true);
+
/*
* Find columns with default values and prepare for insertion of the
* defaults. Pre-cooked (that is, inherited) defaults go into a list of
*************** DefineRelation(CreateStmt *stmt, char re
*** 513,519 ****
parentOidCount,
stmt->oncommit,
reloptions,
! allowSystemTableMods);
StoreCatalogInheritance(relationId, inheritOids);
--- 525,532 ----
parentOidCount,
stmt->oncommit,
reloptions,
! allowSystemTableMods,
! secLabels);
StoreCatalogInheritance(relationId, inheritOids);
*************** ExecuteTruncate(TruncateStmt *stmt)
*** 887,892 ****
--- 900,907 ----
if (!pg_class_ownercheck(seq_relid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(seq_rel));
+ /* SELinux checks */
+ sepgsql_relation_alter(seq_relid, NULL, InvalidOid);
seq_relids = lappend_oid(seq_relids, seq_relid);
*************** truncate_check_rel(Relation rel)
*** 1042,1047 ****
--- 1057,1065 ----
errmsg("permission denied: \"%s\" is a system catalog",
RelationGetRelationName(rel))));
+ /* SELinux: check db_table:{delete} permission */
+ sepgsql_relation_truncate(rel);
+
/*
* We can never allow truncation of shared or nailed-in-cache relations,
* because we can't support changing their relfilenode values.
*************** MergeAttributes(List *schema, List *supe
*** 1216,1221 ****
--- 1234,1241 ----
if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(relation));
+ /* SELinux checks db_table:{setattr} */
+ sepgsql_relation_alter(RelationGetRelid(relation), NULL, InvalidOid);
/*
* Reject duplications in the list of parents.
*************** renameatt(Oid myrelid,
*** 1921,1926 ****
--- 1941,1949 ----
errmsg("cannot rename system column \"%s\"",
oldattname)));
+ /* SELinux checks db_column:{setattr} */
+ sepgsql_attribute_alter(myrelid, oldattname);
+
/*
* if the attribute is inherited, forbid the renaming, unless we are
* already inside a recursive rename.
*************** RenameRelation(Oid myrelid, const char *
*** 2026,2031 ****
--- 2049,2057 ----
Oid namespaceId;
char relkind;
+ /* SELinux checks */
+ sepgsql_relation_alter(myrelid, newrelname, InvalidOid);
+
/*
* Grab an exclusive lock on the target table, index, sequence or view,
* which we will NOT release until end of transaction.
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2359,2372 ****
switch (cmd->subtype)
{
case AT_AddColumn: /* ADD COLUMN */
! ATSimplePermissions(rel, false);
/* Performs own recursion */
ATPrepAddColumn(wqueue, rel, recurse, cmd);
pass = AT_PASS_ADD_COL;
break;
case AT_AddColumnToView: /* add column via CREATE OR REPLACE
* VIEW */
! ATSimplePermissions(rel, true);
/* Performs own recursion */
ATPrepAddColumn(wqueue, rel, recurse, cmd);
pass = AT_PASS_ADD_COL;
--- 2385,2398 ----
switch (cmd->subtype)
{
case AT_AddColumn: /* ADD COLUMN */
! ATSimplePermissions(rel, NULL, false);
/* Performs own recursion */
ATPrepAddColumn(wqueue, rel, recurse, cmd);
pass = AT_PASS_ADD_COL;
break;
case AT_AddColumnToView: /* add column via CREATE OR REPLACE
* VIEW */
! ATSimplePermissions(rel, NULL, true);
/* Performs own recursion */
ATPrepAddColumn(wqueue, rel, recurse, cmd);
pass = AT_PASS_ADD_COL;
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2379,2397 ****
* substitutes default values into INSERTs before it expands
* rules.
*/
! ATSimplePermissions(rel, true);
ATSimpleRecursion(wqueue, rel, cmd, recurse);
/* No command-specific prep needed */
pass = cmd->def ? AT_PASS_ADD_CONSTR : AT_PASS_DROP;
break;
case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
! ATSimplePermissions(rel, false);
ATSimpleRecursion(wqueue, rel, cmd, recurse);
/* No command-specific prep needed */
pass = AT_PASS_DROP;
break;
case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
! ATSimplePermissions(rel, false);
ATSimpleRecursion(wqueue, rel, cmd, recurse);
/* No command-specific prep needed */
pass = AT_PASS_ADD_CONSTR;
--- 2405,2423 ----
* substitutes default values into INSERTs before it expands
* rules.
*/
! ATSimplePermissions(rel, cmd->name, true);
ATSimpleRecursion(wqueue, rel, cmd, recurse);
/* No command-specific prep needed */
pass = cmd->def ? AT_PASS_ADD_CONSTR : AT_PASS_DROP;
break;
case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
! ATSimplePermissions(rel, cmd->name, false);
ATSimpleRecursion(wqueue, rel, cmd, recurse);
/* No command-specific prep needed */
pass = AT_PASS_DROP;
break;
case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
! ATSimplePermissions(rel, cmd->name, false);
ATSimpleRecursion(wqueue, rel, cmd, recurse);
/* No command-specific prep needed */
pass = AT_PASS_ADD_CONSTR;
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2403,2415 ****
pass = AT_PASS_COL_ATTRS;
break;
case AT_SetStorage: /* ALTER COLUMN STORAGE */
! ATSimplePermissions(rel, false);
ATSimpleRecursion(wqueue, rel, cmd, recurse);
/* No command-specific prep needed */
pass = AT_PASS_COL_ATTRS;
break;
case AT_DropColumn: /* DROP COLUMN */
! ATSimplePermissions(rel, false);
/* Recursion occurs during execution phase */
/* No command-specific prep needed except saving recurse flag */
if (recurse)
--- 2429,2441 ----
pass = AT_PASS_COL_ATTRS;
break;
case AT_SetStorage: /* ALTER COLUMN STORAGE */
! ATSimplePermissions(rel, cmd->name, false);
ATSimpleRecursion(wqueue, rel, cmd, recurse);
/* No command-specific prep needed */
pass = AT_PASS_COL_ATTRS;
break;
case AT_DropColumn: /* DROP COLUMN */
! ATSimplePermissions(rel, NULL, false);
/* Recursion occurs during execution phase */
/* No command-specific prep needed except saving recurse flag */
if (recurse)
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2417,2429 ****
pass = AT_PASS_DROP;
break;
case AT_AddIndex: /* ADD INDEX */
! ATSimplePermissions(rel, false);
/* This command never recurses */
/* No command-specific prep needed */
pass = AT_PASS_ADD_INDEX;
break;
case AT_AddConstraint: /* ADD CONSTRAINT */
! ATSimplePermissions(rel, false);
/* Recursion occurs during execution phase */
/* No command-specific prep needed except saving recurse flag */
if (recurse)
--- 2443,2455 ----
pass = AT_PASS_DROP;
break;
case AT_AddIndex: /* ADD INDEX */
! ATSimplePermissions(rel, NULL, false);
/* This command never recurses */
/* No command-specific prep needed */
pass = AT_PASS_ADD_INDEX;
break;
case AT_AddConstraint: /* ADD CONSTRAINT */
! ATSimplePermissions(rel, NULL, false);
/* Recursion occurs during execution phase */
/* No command-specific prep needed except saving recurse flag */
if (recurse)
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2431,2437 ****
pass = AT_PASS_ADD_CONSTR;
break;
case AT_DropConstraint: /* DROP CONSTRAINT */
! ATSimplePermissions(rel, false);
/* Recursion occurs during execution phase */
/* No command-specific prep needed except saving recurse flag */
if (recurse)
--- 2457,2463 ----
pass = AT_PASS_ADD_CONSTR;
break;
case AT_DropConstraint: /* DROP CONSTRAINT */
! ATSimplePermissions(rel, NULL, false);
/* Recursion occurs during execution phase */
/* No command-specific prep needed except saving recurse flag */
if (recurse)
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2439,2445 ****
pass = AT_PASS_DROP;
break;
case AT_AlterColumnType: /* ALTER COLUMN TYPE */
! ATSimplePermissions(rel, false);
/* Performs own recursion */
ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd);
pass = AT_PASS_ALTER_TYPE;
--- 2465,2471 ----
pass = AT_PASS_DROP;
break;
case AT_AlterColumnType: /* ALTER COLUMN TYPE */
! ATSimplePermissions(rel, cmd->name, false);
/* Performs own recursion */
ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd);
pass = AT_PASS_ALTER_TYPE;
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2451,2470 ****
break;
case AT_ClusterOn: /* CLUSTER ON */
case AT_DropCluster: /* SET WITHOUT CLUSTER */
! ATSimplePermissions(rel, false);
/* These commands never recurse */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_AddOids: /* SET WITH OIDS */
! ATSimplePermissions(rel, false);
/* Performs own recursion */
if (!rel->rd_rel->relhasoids || recursing)
ATPrepAddOids(wqueue, rel, recurse, cmd);
pass = AT_PASS_ADD_COL;
break;
case AT_DropOids: /* SET WITHOUT OIDS */
! ATSimplePermissions(rel, false);
/* Performs own recursion */
if (rel->rd_rel->relhasoids)
{
--- 2477,2496 ----
break;
case AT_ClusterOn: /* CLUSTER ON */
case AT_DropCluster: /* SET WITHOUT CLUSTER */
! ATSimplePermissions(rel, NULL, false);
/* These commands never recurse */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
case AT_AddOids: /* SET WITH OIDS */
! ATSimplePermissions(rel, NULL, false);
/* Performs own recursion */
if (!rel->rd_rel->relhasoids || recursing)
ATPrepAddOids(wqueue, rel, recurse, cmd);
pass = AT_PASS_ADD_COL;
break;
case AT_DropOids: /* SET WITHOUT OIDS */
! ATSimplePermissions(rel, NULL, false);
/* Performs own recursion */
if (rel->rd_rel->relhasoids)
{
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2478,2491 ****
pass = AT_PASS_DROP;
break;
case AT_SetTableSpace: /* SET TABLESPACE */
! ATSimplePermissionsRelationOrIndex(rel);
/* This command never recurses */
ATPrepSetTableSpace(tab, rel, cmd->name);
pass = AT_PASS_MISC; /* doesn't actually matter */
break;
case AT_SetRelOptions: /* SET (...) */
case AT_ResetRelOptions: /* RESET (...) */
! ATSimplePermissionsRelationOrIndex(rel);
/* This command never recurses */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
--- 2504,2517 ----
pass = AT_PASS_DROP;
break;
case AT_SetTableSpace: /* SET TABLESPACE */
! ATSimplePermissionsRelationOrIndex(rel, NULL);
/* This command never recurses */
ATPrepSetTableSpace(tab, rel, cmd->name);
pass = AT_PASS_MISC; /* doesn't actually matter */
break;
case AT_SetRelOptions: /* SET (...) */
case AT_ResetRelOptions: /* RESET (...) */
! ATSimplePermissionsRelationOrIndex(rel, NULL);
/* This command never recurses */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2504,2510 ****
case AT_DisableRule:
case AT_AddInherit: /* INHERIT / NO INHERIT */
case AT_DropInherit:
! ATSimplePermissions(rel, false);
/* These commands never recurse */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
--- 2530,2536 ----
case AT_DisableRule:
case AT_AddInherit: /* INHERIT / NO INHERIT */
case AT_DropInherit:
! ATSimplePermissions(rel, NULL, false);
/* These commands never recurse */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
*************** 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 */
/*
--- 2876,2884 ----
/*
* 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 ****
--- 3103,3116 ----
if (newrel)
{
Oid tupOid = InvalidOid;
+ Oid tupSecid = InvalidOid;
/* Extract data from old tuple */
heap_deform_tuple(tuple, oldTupDesc, values, isnull);
if (oldTupDesc->tdhasoid)
tupOid = HeapTupleGetOid(tuple);
+ if (HeapTupleHasSecid(tuple))
+ tupSecid = HeapTupleGetSecid(tuple);
/* Set dropped attributes to null in new tuple */
foreach(lc, dropped_attrs)
*************** ATRewriteTable(AlteredTableInfo *tab, Oi
*** 3112,3117 ****
--- 3142,3150 ----
/* Preserve OID, if any */
if (newTupDesc->tdhasoid)
HeapTupleSetOid(tuple, tupOid);
+ /* Preserve SID, if any */
+ if (HeapTupleHasSecid(tuple))
+ HeapTupleSetSecid(tuple, tupSecid);
}
/* Now check any constraints on the possibly-changed tuple */
*************** ATGetQueueEntry(List **wqueue, Relation
*** 3213,3219 ****
* - Ensure that it is not a system table
*/
static void
! ATSimplePermissions(Relation rel, bool allowView)
{
if (rel->rd_rel->relkind != RELKIND_RELATION)
{
--- 3246,3252 ----
* - Ensure that it is not a system table
*/
static void
! ATSimplePermissions(Relation rel, const char *colName, bool allowView)
{
if (rel->rd_rel->relkind != RELKIND_RELATION)
{
*************** ATSimplePermissions(Relation rel, bool a
*** 3237,3242 ****
--- 3270,3281 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(rel));
+ /* SELinux checks */
+ if (!colName)
+ sepgsql_relation_alter(RelationGetRelid(rel), NULL, InvalidOid);
+ else
+ sepgsql_attribute_alter(RelationGetRelid(rel), colName);
+
if (!allowSystemTableMods && IsSystemRelation(rel))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
*************** ATSimplePermissions(Relation rel, bool a
*** 3252,3258 ****
* - Ensure that it is not a system table
*/
static void
! ATSimplePermissionsRelationOrIndex(Relation rel)
{
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_INDEX)
--- 3291,3297 ----
* - Ensure that it is not a system table
*/
static void
! ATSimplePermissionsRelationOrIndex(Relation rel, const char *colName)
{
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_INDEX)
*************** ATSimplePermissionsRelationOrIndex(Relat
*** 3266,3271 ****
--- 3305,3316 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(rel));
+ /* SELinux checks */
+ if (!colName)
+ sepgsql_relation_alter(RelationGetRelid(rel), NULL, InvalidOid);
+ else
+ sepgsql_attribute_alter(RelationGetRelid(rel), colName);
+
if (!allowSystemTableMods && IsSystemRelation(rel))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
*************** ATExecAddColumn(AlteredTableInfo *tab, R
*** 3509,3514 ****
--- 3554,3560 ----
HeapTuple typeTuple;
Oid typeOid;
int32 typmod;
+ Oid attsecid;
Form_pg_type tform;
Expr *defval;
*************** ATExecAddColumn(AlteredTableInfo *tab, R
*** 3546,3551 ****
--- 3592,3600 ----
errmsg("child table \"%s\" has a conflicting \"%s\" column",
RelationGetRelationName(rel), colDef->colname)));
+ /* SELinux checks db_column:{setattr} */
+ sepgsql_attribute_alter(myrelid, colDef->colname);
+
/* Bump the existing child att's inhcount */
childatt->attinhcount++;
simple_heap_update(attrdesc, &tuple->t_self, tuple);
*************** ATExecAddColumn(AlteredTableInfo *tab, R
*** 3585,3590 ****
--- 3634,3642 ----
errmsg("column \"%s\" of relation \"%s\" already exists",
colDef->colname, RelationGetRelationName(rel))));
+ /* SELinux checks db_column:{create} */
+ attsecid = sepgsql_attribute_create(myrelid, colDef);
+
/* 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);
--- 3679,3685 ----
ReleaseSysCache(typeTuple);
! InsertPgAttributeTuple(attrdesc, &attribute, NULL, attsecid);
heap_close(attrdesc, RowExclusiveLock);
*************** ATPrepSetStatistics(Relation rel, const
*** 4016,4021 ****
--- 4068,4075 ----
if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(rel));
+ /* SELinux checks */
+ sepgsql_attribute_alter(RelationGetRelid(rel), colName);
}
static void
*************** ATExecDropColumn(List **wqueue, Relation
*** 4171,4177 ****
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
! ATSimplePermissions(rel, false);
/*
* get the number of the attribute
--- 4225,4231 ----
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
! ATSimplePermissions(rel, NULL, false);
/*
* get the number of the attribute
*************** ATAddCheckConstraint(List **wqueue, Alte
*** 4473,4479 ****
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
! ATSimplePermissions(rel, false);
/*
* Call AddRelationNewConstraints to do the work, making sure it works on
--- 4527,4533 ----
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
! ATSimplePermissions(rel, NULL, false);
/*
* Call AddRelationNewConstraints to do the work, making sure it works on
*************** 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} */
+ sepgsql_relation_references(rel, attnums, natts);
}
/*
*************** ATExecDropConstraint(Relation rel, const
*** 5375,5381 ****
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
! ATSimplePermissions(rel, false);
conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
--- 5432,5438 ----
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
! ATSimplePermissions(rel, NULL, false);
conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
*************** ATExecChangeOwner(Oid relationOid, Oid n
*** 6308,6313 ****
--- 6365,6372 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
}
+ /* SELinux checks db_table:{setattr} */
+ sepgsql_relation_alter(relationOid, NULL, InvalidOid);
}
memset(repl_null, false, sizeof(repl_null));
*************** ATExecAddInherit(Relation child_rel, Ran
*** 6912,6918 ****
* Must be owner of both parent and child -- child was checked by
* ATSimplePermissions call in ATPrepCmd
*/
! ATSimplePermissions(parent_rel, false);
/* Permanent rels cannot inherit from temporary ones */
if (parent_rel->rd_istemp && !child_rel->rd_istemp)
--- 6971,6977 ----
* Must be owner of both parent and child -- child was checked by
* ATSimplePermissions call in ATPrepCmd
*/
! ATSimplePermissions(parent_rel, NULL, false);
/* Permanent rels cannot inherit from temporary ones */
if (parent_rel->rd_istemp && !child_rel->rd_istemp)
*************** AlterTableNamespace(RangeVar *relation,
*** 7570,7575 ****
--- 7629,7637 ----
RelationGetRelationName(rel),
newschema)));
+ /* SELinux checks */
+ sepgsql_relation_alter(relid, NULL, nspOid);
+
/* disallow renaming into or out of temp schemas */
if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
ereport(ERROR,
*************** AlterSeqNamespaces(Relation classRel, Re
*** 7762,7767 ****
--- 7824,7957 ----
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);
+ if (!HeapTupleHasSecid(newtup))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Unable to set security label on \"%s\"",
+ get_rel_name(relid))));
+
+ ReleaseSysCache(oldtup);
+
+ /* SELinux checks db_table:{setattr relabelfrom relabelto} */
+ secid = sepgsql_relation_relabel(relid, seclabel);
+
+ HeapTupleSetSecid(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);
+ if (!HeapTupleHasSecid(newtup))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Unable to set security context on \"%s.%s\"",
+ get_rel_name(relid), attname)));
+
+ ReleaseSysCache(oldtup);
+
+ /* SELinux checks db_column:{setattr relabelfrom relabelto} */
+ secid = sepgsql_attribute_relabel(relid, attnum, seclabel);
+
+ HeapTupleSetSecid(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 Sep 17 22:10:19 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,192 ----
NameListToString(stmt->funcname))));
}
+ /* SELinux checks */
+ if (checkPermissions)
+ sepgsql_trigger_create(RelationGetRelid(rel), stmt->trigname, 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
*************** DropTrigger(Oid relid, const char *trign
*** 746,751 ****
--- 751,757 ----
if (!pg_class_ownercheck(relid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
get_rel_name(relid));
+ sepgsql_trigger_drop(relid, trigname);
object.classId = TriggerRelationId;
object.objectId = HeapTupleGetOid(tup);
*************** renametrig(Oid relid,
*** 862,867 ****
--- 868,876 ----
*/
targetrel = heap_open(relid, AccessExclusiveLock);
+ /* SELinux checks */
+ sepgsql_trigger_alter(relid, oldname);
+
/*
* Scan pg_trigger twice for existing triggers on relation. We do this in
* order to ensure a trigger does not exist with newname (The unique index
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 Thu Sep 17 23:44:07 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"
*************** DefineTSParser(List *names, List *parame
*** 171,176 ****
--- 172,178 ----
NameData pname;
Oid prsOid;
Oid namespaceoid;
+ Oid secid;
if (!superuser())
ereport(ERROR,
*************** DefineTSParser(List *names, List *parame
*** 250,261 ****
--- 252,273 ----
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("text search parser lextypes method is required")));
+ /* Permission checks */
+ secid = sepgsql_ts_parser_create(prsname, namespaceoid,
+ DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1]),
+ DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1]),
+ DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1]),
+ DatumGetObjectId(values[Anum_pg_ts_parser_prsheadline - 1]),
+ DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1]));
+
/*
* Looks good, insert
*/
prsRel = heap_open(TSParserRelationId, RowExclusiveLock);
tup = heap_form_tuple(prsRel->rd_att, values, nulls);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, secid);
prsOid = simple_heap_insert(prsRel, tup);
*************** RenameTSParser(List *oldname, const char
*** 372,377 ****
--- 384,392 ----
prsId = TSParserGetPrsid(oldname, false);
+ /* SELinux checks */
+ sepgsql_ts_parser_alter(prsId, newname);
+
tup = SearchSysCacheCopy(TSPARSEROID,
ObjectIdGetDatum(prsId),
0, 0, 0);
*************** DefineTSDictionary(List *names, List *pa
*** 503,508 ****
--- 518,524 ----
List *dictoptions = NIL;
Oid dictOid;
Oid namespaceoid;
+ Oid secid;
AclResult aclresult;
char *dictname;
*************** DefineTSDictionary(List *names, List *pa
*** 515,520 ****
--- 531,539 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceoid));
+ /* SELinux check */
+ secid = sepgsql_ts_dict_create(dictname, namespaceoid);
+
/*
* loop over the definition list and extract the information we need.
*/
*************** DefineTSDictionary(List *names, List *pa
*** 563,568 ****
--- 582,589 ----
dictRel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
tup = heap_form_tuple(dictRel->rd_att, values, nulls);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, secid);
dictOid = simple_heap_insert(dictRel, tup);
*************** RenameTSDictionary(List *oldname, const
*** 621,626 ****
--- 642,650 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
+ /* SELinux checks */
+ sepgsql_ts_dict_alter(dictId, newname);
+
namestrcpy(&(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname), newname);
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
*************** AlterTSDictionary(AlterTSDictionaryStmt
*** 762,767 ****
--- 786,794 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
NameListToString(stmt->dictname));
+ /* SELinux checks */
+ sepgsql_ts_dict_alter(dictId, NULL);
+
/* deserialize the existing set of options */
opt = SysCacheGetAttr(TSDICTOID, tup,
Anum_pg_ts_dict_dictinitoption,
*************** AlterTSDictionaryOwner(List *name, Oid n
*** 889,894 ****
--- 916,923 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
}
+ /* SELinux checks */
+ sepgsql_ts_dict_alter(dictId, NULL);
form->dictowner = newOwnerId;
*************** DefineTSTemplate(List *names, List *para
*** 999,1004 ****
--- 1028,1034 ----
NameData dname;
int i;
Oid dictOid;
+ Oid dictSecid;
Oid namespaceoid;
char *tmplname;
*************** DefineTSTemplate(List *names, List *para
*** 1054,1059 ****
--- 1084,1094 ----
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("text search template lexize method is required")));
+ /* SELinux checks */
+ dictSecid = sepgsql_ts_template_create(tmplname, namespaceoid,
+ DatumGetObjectId(values[Anum_pg_ts_template_tmplinit - 1]),
+ DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1]));
+
/*
* Looks good, insert
*/
*************** DefineTSTemplate(List *names, List *para
*** 1061,1066 ****
--- 1096,1103 ----
tmplRel = heap_open(TSTemplateRelationId, RowExclusiveLock);
tup = heap_form_tuple(tmplRel->rd_att, values, nulls);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, dictSecid);
dictOid = simple_heap_insert(tmplRel, tup);
*************** RenameTSTemplate(List *oldname, const ch
*** 1093,1098 ****
--- 1130,1138 ----
tmplId = TSTemplateGetTmplid(oldname, false);
+ /* Permission checks */
+ sepgsql_ts_template_alter(tmplId, newname);
+
tup = SearchSysCacheCopy(TSTEMPLATEOID,
ObjectIdGetDatum(tmplId),
0, 0, 0);
*************** DefineTSConfiguration(List *names, List
*** 1335,1340 ****
--- 1375,1381 ----
Oid sourceOid = InvalidOid;
Oid prsOid = InvalidOid;
Oid cfgOid;
+ Oid cfgSecid;
ListCell *pl;
/* Convert list of names to a name and namespace */
*************** DefineTSConfiguration(List *names, List
*** 1399,1404 ****
--- 1440,1448 ----
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("text search parser is required")));
+ /* SELinux checks */
+ cfgSecid = sepgsql_ts_config_create(cfgname, namespaceoid);
+
/*
* Looks good, build tuple and insert
*/
*************** DefineTSConfiguration(List *names, List
*** 1414,1419 ****
--- 1458,1465 ----
cfgRel = heap_open(TSConfigRelationId, RowExclusiveLock);
tup = heap_form_tuple(cfgRel->rd_att, values, nulls);
+ if (HeapTupleHasSecid(tup))
+ HeapTupleSetSecid(tup, cfgSecid);
cfgOid = simple_heap_insert(cfgRel, tup);
*************** RenameTSConfiguration(List *oldname, con
*** 1519,1524 ****
--- 1565,1573 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
+ /* permission checks */
+ sepgsql_ts_config_alter(cfgId, newname);
+
namestrcpy(&(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname), newname);
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
*************** AlterTSConfigurationOwner(List *name, Oi
*** 1690,1695 ****
--- 1739,1746 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
}
+ /* SELinux checks */
+ sepgsql_ts_config_alter(cfgId, NULL);
form->cfgowner = newOwnerId;
*************** AlterTSConfiguration(AlterTSConfiguratio
*** 1727,1732 ****
--- 1778,1786 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
NameListToString(stmt->cfgname));
+ /* SELinux checks */
+ sepgsql_ts_config_alter(HeapTupleGetOid(tup), NULL);
+
relMap = heap_open(TSConfigMapRelationId, RowExclusiveLock);
/* Add or drop mappings */
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 Thu Sep 17 22:10:19 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"
*************** AlterDomainDefault(List *names, Node *de
*** 1543,1548 ****
--- 1544,1550 ----
/* Check it's a domain and check user has permission for ALTER DOMAIN */
checkDomainOwner(tup, typename);
+ sepgsql_type_alter(domainoid, NULL, InvalidOid);
/* Setup new tuple */
MemSet(new_record, (Datum) 0, sizeof(new_record));
*************** AlterDomainNotNull(List *names, bool not
*** 1671,1676 ****
--- 1673,1679 ----
/* Check it's a domain and check user has permission for ALTER DOMAIN */
checkDomainOwner(tup, typename);
+ sepgsql_type_alter(domainoid, NULL, InvalidOid);
/* Is the domain already set to the desired constraint? */
if (typTup->typnotnull == notNull)
*************** AlterDomainDropConstraint(List *names, c
*** 1772,1777 ****
--- 1775,1781 ----
/* Check it's a domain and check user has permission for ALTER DOMAIN */
checkDomainOwner(tup, typename);
+ sepgsql_type_alter(domainoid, NULL, InvalidOid);
/* Grab an appropriate lock on the pg_constraint relation */
conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
*************** AlterDomainAddConstraint(List *names, No
*** 1848,1853 ****
--- 1852,1858 ----
/* Check it's a domain and check user has permission for ALTER DOMAIN */
checkDomainOwner(tup, typename);
+ sepgsql_type_alter(domainoid, NULL, InvalidOid);
/* Check for unsupported constraint types */
if (IsA(newConstraint, FkConstraint))
*************** RenameType(List *names, const char *newT
*** 2470,2475 ****
--- 2475,2483 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
format_type_be(typeOid));
+ /* SELinux check permission */
+ sepgsql_type_alter(typeOid, newTypeName, InvalidOid);
+
/*
* If it's a composite type, we need to check that it really is a
* free-standing composite type, and not a table's rowtype. We want people
*************** AlterTypeOwner(List *names, Oid newOwner
*** 2590,2595 ****
--- 2598,2605 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(typTup->typnamespace));
}
+ /* SELinux checks permissions */
+ sepgsql_type_alter(HeapTupleGetOid(tup), NULL, InvalidOid);
/*
* If it's a composite type, invoke ATExecChangeOwner so that we fix
*************** AlterTypeNamespace(List *names, const ch
*** 2706,2711 ****
--- 2716,2724 ----
errhint("You can alter type %s, which will alter the array type as well.",
format_type_be(elemOid))));
+ /* SELinux checks permissions */
+ sepgsql_type_alter(typeOid, NULL, nspOid);
+
/* and do the work */
AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
}
diff -Nrpc base/src/backend/commands/view.c sepgsql/src/backend/commands/view.c
*** base/src/backend/commands/view.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/backend/commands/view.c Fri Sep 18 14:51:00 2009
***************
*** 28,33 ****
--- 28,34 ----
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rewriteSupport.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
*************** DefineVirtualRelation(const RangeVar *re
*** 166,171 ****
--- 167,175 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(rel));
+ /* SELinux checks */
+ sepgsql_view_replace(viewOid);
+
/* Also check it's not in use already */
CheckTableNotInUse(rel, "CREATE OR REPLACE VIEW");
diff -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 Thu Oct 8 09:29:32 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)->tdhassecid,
! 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->tdhassecid,
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;
}
+ /*
+ * ExecContextForcesSecids
+ *
+ * We need to ensure that result tuples have space for security identifier.
+ * if the security feature need to store it within the given relation.
+ */
+ bool ExecContextForcesSecids(PlanState *planstate, bool *hassecid)
+ {
+ if (planstate->state->es_select_into)
+ {
+ *hassecid = securityTupleDescHasSecid(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;
+
+ *hassecid = securityTupleDescHasSecid(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, SecurityAttributeName);
+ if (attno != InvalidAttrNumber)
+ {
+ datum = ExecGetJunkAttribute(slot, attno, &isnull);
+ if (isnull)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Unable to set NULL on \"%s\"",
+ SecurityAttributeName)));
+ *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 (!HeapTupleHasSecid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Unable to assign security label on \"%s\"",
+ RelationGetRelationName(rel))));
+ secid = securityTransSecLabelIn(relid, seclabel);
+ HeapTupleSetSecid(tuple, secid);
+ }
+ else if (HeapTupleHasSecid(tuple))
+ HeapTupleSetSecid(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,2995 ----
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceId));
+ /* SELinux checks */
+ secLabels = sepgsql_relation_create(intoName,
+ RELKIND_RELATION,
+ queryDesc->tupDesc,
+ namespaceId,
+ NULL, NIL,
+ true, true);
+
/*
* 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);
--- 3048,3055 ----
0,
into->onCommit,
reloptions,
! allowSystemTableMods,
! secLabels);
FreeTupleDesc(tupdesc);
*************** intorel_receive(TupleTableSlot *slot, De
*** 3054,3059 ****
--- 3174,3183 ----
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/execQual.c sepgsql/src/backend/executor/execQual.c
*** base/src/backend/executor/execQual.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/backend/executor/execQual.c Thu Sep 17 17:04:16 2009
***************
*** 47,52 ****
--- 47,53 ----
#include "nodes/nodeFuncs.h"
#include "optimizer/planner.h"
#include "pgstat.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
*************** init_fcache(Oid foid, FuncExprState *fca
*** 1034,1039 ****
--- 1035,1041 ----
aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid));
+ sepgsql_proc_execute(foid);
/*
* Safety check on nargs. Under normal circumstances this should never
*************** ExecEvalArrayCoerceExpr(ArrayCoerceExprS
*** 4032,4037 ****
--- 4034,4040 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(acoerce->elemfuncid));
+ sepgsql_proc_execute(acoerce->elemfuncid);
/* Set up the primary fmgr lookup information */
fmgr_info_cxt(acoerce->elemfuncid, &(astate->elemfunc),
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 Sep 9 13:14:37 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 hassecid;
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 hassecid setting,
! * then that has to match, too.
*/
if (ExecContextForcesOids(ps, &hasoid) &&
hasoid != tupdesc->tdhasoid)
return false;
+ if (ExecContextForcesSecids(ps, &hassecid) &&
+ hassecid != tupdesc->tdhassecid)
+ 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 Sep 9 13:14:37 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 hassecid)
{
! return ExecTypeFromTLInternal(targetList, hasoid, hassecid, 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 hassecid)
{
! return ExecTypeFromTLInternal(targetList, hasoid, hassecid, true);
}
static TupleDesc
! ExecTypeFromTLInternal(List *targetList, bool hasoid,
! bool hassecid, bool skipjunk)
{
TupleDesc typeInfo;
ListCell *l;
*************** ExecTypeFromTLInternal(List *targetList,
*** 998,1003 ****
--- 999,1005 ----
else
len = ExecTargetListLength(targetList);
typeInfo = CreateTemplateTupleDesc(len, hasoid);
+ typeInfo->tdhassecid = hassecid;
foreach(l, targetList)
{
diff -Nrpc base/src/backend/executor/execUtils.c sepgsql/src/backend/executor/execUtils.c
*** base/src/backend/executor/execUtils.c Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/executor/execUtils.c Wed Sep 9 13:14:37 2009
*************** void
*** 512,517 ****
--- 512,518 ----
ExecAssignResultTypeFromTL(PlanState *planstate)
{
bool hasoid;
+ bool hassecid;
TupleDesc tupDesc;
if (ExecContextForcesOids(planstate, &hasoid))
*************** ExecAssignResultTypeFromTL(PlanState *pl
*** 524,535 ****
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);
}
--- 525,539 ----
hasoid = false;
}
+ if (!ExecContextForcesSecids(planstate, &hassecid))
+ hassecid = false;
+
/*
* ExecTypeFromTL needs the parse-time representation of the tlist, not a
* list of ExprStates. This is good because some plan nodes don't bother
* to set up planstate->targetlist ...
*/
! tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid, hassecid);
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/nodeAgg.c sepgsql/src/backend/executor/nodeAgg.c
*** base/src/backend/executor/nodeAgg.c Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/executor/nodeAgg.c Thu Sep 17 17:04:16 2009
***************
*** 81,86 ****
--- 81,87 ----
#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
#include "parser/parse_oper.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
*************** ExecInitAgg(Agg *node, EState *estate, i
*** 1431,1436 ****
--- 1432,1438 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(aggref->aggfnoid));
+ sepgsql_proc_execute(aggref->aggfnoid);
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
*************** ExecInitAgg(Agg *node, EState *estate, i
*** 1454,1459 ****
--- 1456,1462 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(transfn_oid));
+ sepgsql_proc_execute(transfn_oid);
if (OidIsValid(finalfn_oid))
{
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
*************** ExecInitAgg(Agg *node, EState *estate, i
*** 1461,1466 ****
--- 1464,1470 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(finalfn_oid));
+ sepgsql_proc_execute(finalfn_oid);
}
}
diff -Nrpc base/src/backend/executor/nodeMergejoin.c sepgsql/src/backend/executor/nodeMergejoin.c
*** base/src/backend/executor/nodeMergejoin.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/backend/executor/nodeMergejoin.c Thu Sep 17 17:04:16 2009
***************
*** 98,103 ****
--- 98,104 ----
#include "executor/execdefs.h"
#include "executor/nodeMergejoin.h"
#include "miscadmin.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
*************** MJExamineQuals(List *mergeclauses,
*** 215,220 ****
--- 216,222 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(cmpproc));
+ sepgsql_proc_execute(cmpproc);
/* Set up the fmgr lookup information */
fmgr_info(cmpproc, &(clause->cmpfinfo));
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/nodeWindowAgg.c sepgsql/src/backend/executor/nodeWindowAgg.c
*** base/src/backend/executor/nodeWindowAgg.c Tue Jun 23 11:09:47 2009
--- sepgsql/src/backend/executor/nodeWindowAgg.c Thu Sep 17 17:04:16 2009
***************
*** 43,48 ****
--- 43,49 ----
#include "optimizer/clauses.h"
#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/datum.h"
*************** ExecInitWindowAgg(WindowAgg *node, EStat
*** 1224,1229 ****
--- 1225,1231 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(wfunc->winfnoid));
+ sepgsql_proc_execute(wfunc->winfnoid);
/* Fill in the perfuncstate data */
perfuncstate->wfuncstate = wfuncstate;
*************** initialize_peragg(WindowAggState *winsta
*** 1418,1423 ****
--- 1420,1426 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(transfn_oid));
+ sepgsql_proc_execute(transfn_oid);
if (OidIsValid(finalfn_oid))
{
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
*************** initialize_peragg(WindowAggState *winsta
*** 1425,1430 ****
--- 1428,1434 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(finalfn_oid));
+ sepgsql_proc_execute(finalfn_oid);
}
}
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 Tue Sep 8 23:55:48 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 (HeapTupleHasSecid(mtuple))
+ HeapTupleSetSecid(mtuple, HeapTupleGetSecid(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 Mon Sep 28 10:07:19 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
*** 364,369 ****
--- 373,381 ----
* open the file to be read in
*/
text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
+ /* SELinux checks db_blob:{write import} and file:{read} */
+ //sepgsqlCheckBlobImport(lobj, fnamebuf);
+
fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666);
if (fd < 0)
ereport(ERROR,
*************** lo_export(PG_FUNCTION_ARGS)
*** 439,444 ****
--- 451,459 ----
* world-writable export files doesn't seem wise.
*/
text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
+ /* SELinux checks db_blob:{read export} and file:{write} */
+ //sepgsqlCheckBlobExport(lobj, fnamebuf);
+
oumask = umask((mode_t) 0022);
fd = PathNameOpenFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666);
umask(oumask);
*************** lo_export(PG_FUNCTION_ARGS)
*** 447,453 ****
(errcode_for_file_access(),
errmsg("could not create server file \"%s\": %m",
fnamebuf)));
-
/*
* read in from the inversion file and write to the filesystem
*/
--- 462,467 ----
*************** lo_truncate(PG_FUNCTION_ARGS)
*** 482,493 ****
--- 496,559 ----
(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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/optimizer/plan/createplan.c Sun Sep 6 19:53:10 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 Thu Sep 17 17:04:16 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) ||
+ !sepgsql_proc_hint_inlined(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) ||
+ !sepgsql_proc_hint_inlined(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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/parser/analyze.c Sun Sep 6 19:53:10 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,
*** 872,877 ****
--- 915,921 ----
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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/parser/gram.y Tue Sep 8 17:13:41 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> OptSecCxt SecCxtItem
+
%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 OptSecCxt 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 OptSecCxt 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 OptSecCxt
{
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 OptSecCxt
{
/* 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 OptSecCxt
{
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 OptSecCxt
{
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));
}
+ | SecCxtItem
+ {
+ $$ = $1;
+ }
| common_func_opt_item
{
$$ = $1;
*************** AlterOwnerStmt: ALTER AGGREGATE func_nam
*** 5591,5596 ****
--- 5605,5680 ----
}
;
+ /*****************************************************************************
+ *
+ * ALTER THING name SECURITY_CONTEXT [=] <newlabel>
+ *
+ *****************************************************************************/
+
+ AlterSecLabelStmt: ALTER DATABASE database_name SecCxtItem
+ {
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
+ n->objectType = OBJECT_DATABASE;
+ n->object = list_make1(makeString($3));
+ n->secLabel = (Node *)$4;
+ $$ = (Node *) n;
+ }
+ | ALTER SCHEMA name SecCxtItem
+ {
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
+ n->objectType = OBJECT_SCHEMA;
+ n->object = list_make1(makeString($3));
+ n->secLabel = (Node *)$4;
+ $$ = (Node *) n;
+ }
+ | ALTER TABLE relation_expr SecCxtItem
+ {
+ 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 SecCxtItem
+ {
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
+ n->objectType = OBJECT_COLUMN;
+ n->relation = $3;
+ n->subname = $6;
+ n->secLabel = (Node *)$7;
+ $$ = (Node *) n;
+ }
+ | ALTER SEQUENCE relation_expr SecCxtItem
+ {
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
+ n->objectType = OBJECT_SEQUENCE;
+ n->relation = $3;
+ n->secLabel = (Node *)$4;
+ $$ = (Node *) n;
+ }
+ | ALTER FUNCTION function_with_argtypes SecCxtItem
+ {
+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt);
+ n->objectType = OBJECT_FUNCTION;
+ n->object = $3->funcname;
+ n->objarg = $3->funcargs;
+ n->secLabel = (Node *)$4;
+ $$ = (Node *) n;
+ }
+ ;
+
+ OptSecCxt: SecCxtItem { $$ = $1; }
+ | /* EMPTY */ { $$ = NULL; }
+ ;
+
+ SecCxtItem: IDENT opt_equal Sconst
+ {
+ if (strcmp("security_context", $1) != 0)
+ yyerror("syntax error");
+ $$ = makeDefElem($1, (Node *) makeString($3));
+ }
+ ;
+
/*****************************************************************************
*
*************** createdb_opt_item:
*** 6033,6038 ****
--- 6117,6126 ----
{
$$ = makeDefElem("owner", NULL);
}
+ | SecCxtItem
+ {
+ $$ = $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/parser/parse_utilcmd.c sepgsql/src/backend/parser/parse_utilcmd.c
*** base/src/backend/parser/parse_utilcmd.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/backend/parser/parse_utilcmd.c Fri Sep 18 14:51:00 2009
***************
*** 49,54 ****
--- 49,55 ----
#include "parser/parse_type.h"
#include "parser/parse_utilcmd.h"
#include "rewrite/rewriteManip.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
*************** transformInhRelation(ParseState *pstate,
*** 565,570 ****
--- 566,573 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_CLASS,
RelationGetRelationName(relation));
+ /* SELinux checks */
+ sepgsql_relation_copy_definition(RelationGetRelid(relation));
tupleDesc = RelationGetDescr(relation);
constr = tupleDesc->constr;
diff -Nrpc base/src/backend/postmaster/autovacuum.c sepgsql/src/backend/postmaster/autovacuum.c
*** base/src/backend/postmaster/autovacuum.c Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/postmaster/autovacuum.c Sun Sep 6 19:53:10 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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/postmaster/postmaster.c Tue Dec 8 14:04:25 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,
! sepgsqlReceiverPID = 0;
/* Startup/shutdown state */
#define NoShutdown 0
*************** static void ShmemBackendArrayRemove(Back
*** 445,450 ****
--- 447,453 ----
#define StartupDataBase() StartChildProcess(StartupProcess)
#define StartBackgroundWriter() StartChildProcess(BgWriterProcess)
#define StartWalWriter() StartChildProcess(WalWriterProcess)
+ #define StartSELinuxReceiver() StartChildProcess(SelinuxReceiverProcess)
/* Macros to check exit status of a child process */
#define EXIT_STATUS_0(st) ((st) == 0)
*************** ServerLoop(void)
*** 1436,1441 ****
--- 1439,1449 ----
if (PgStatPID == 0 && pmState == PM_RUN)
PgStatPID = pgstat_start();
+ /* if we have lost the selinux netlink receiver, try to start */
+ if (sepgsqlIsEnabled() &&
+ sepgsqlReceiverPID == 0 && pmState == PM_RUN)
+ sepgsqlReceiverPID = StartSELinuxReceiver();
+
/* If we need to signal the autovacuum launcher, do so now */
if (avlauncher_needs_signal)
{
*************** SIGHUP_handler(SIGNAL_ARGS)
*** 2053,2058 ****
--- 2061,2068 ----
signal_child(SysLoggerPID, SIGHUP);
if (PgStatPID != 0)
signal_child(PgStatPID, SIGHUP);
+ if (sepgsqlReceiverPID != 0)
+ signal_child(sepgsqlReceiverPID, SIGHUP);
/* Reload authentication config files too */
if (!load_hba())
*************** pmdie(SIGNAL_ARGS)
*** 2113,2118 ****
--- 2123,2131 ----
/* and the walwriter too */
if (WalWriterPID != 0)
signal_child(WalWriterPID, SIGTERM);
+ /* and the selinux netlink receiver too */
+ if (sepgsqlReceiverPID != 0)
+ signal_child(sepgsqlReceiverPID, SIGTERM);
pmState = PM_WAIT_BACKUP;
}
*************** pmdie(SIGNAL_ARGS)
*** 2160,2165 ****
--- 2173,2181 ----
/* and the walwriter too */
if (WalWriterPID != 0)
signal_child(WalWriterPID, SIGTERM);
+ /* and the selinux netlink receiver too */
+ if (sepgsqlReceiverPID != 0)
+ signal_child(sepgsqlReceiverPID, SIGTERM);
pmState = PM_WAIT_BACKENDS;
}
*************** pmdie(SIGNAL_ARGS)
*** 2193,2198 ****
--- 2209,2216 ----
signal_child(PgArchPID, SIGQUIT);
if (PgStatPID != 0)
signal_child(PgStatPID, SIGQUIT);
+ if (sepgsqlReceiverPID != 0)
+ signal_child(sepgsqlReceiverPID, SIGQUIT);
ExitPostmaster(0);
break;
}
*************** reaper(SIGNAL_ARGS)
*** 2455,2460 ****
--- 2473,2488 ----
continue;
}
+ /* Was it the selinux netlink receiver process? */
+ if (pid == sepgsqlReceiverPID)
+ {
+ sepgsqlReceiverPID = 0;
+ if (!EXIT_STATUS_0(exitstatus))
+ LogChildExit(LOG, _("SELinux netlink receiver process"),
+ pid, exitstatus);
+ continue;
+ }
+
/*
* Else do standard backend child cleanup.
*/
*************** HandleChildCrash(int pid, int exitstatus
*** 2646,2651 ****
--- 2674,2691 ----
signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
}
+ /* Take care of the selinux netlink receiver too */
+ if (pid == sepgsqlReceiverPID)
+ sepgsqlReceiverPID = 0;
+ else if (sepgsqlReceiverPID != 0 && !FatalError)
+ {
+ ereport(DEBUG2,
+ (errmsg_internal("sending %s to process %d",
+ (SendStop ? "SIGSTOP" : "SIGQUIT"),
+ (int) sepgsqlReceiverPID)));
+ signal_child(sepgsqlReceiverPID, (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)
*** 2778,2784 ****
StartupPID == 0 &&
(BgWriterPID == 0 || !FatalError) &&
WalWriterPID == 0 &&
! AutoVacPID == 0)
{
if (FatalError)
{
--- 2818,2825 ----
StartupPID == 0 &&
(BgWriterPID == 0 || !FatalError) &&
WalWriterPID == 0 &&
! AutoVacPID == 0 &&
! sepgsqlReceiverPID == 0)
{
if (FatalError)
{
*************** StartChildProcess(AuxProcType type)
*** 4321,4326 ****
--- 4362,4373 ----
ereport(LOG,
(errmsg("could not fork WAL writer process: %m")));
break;
+ #ifdef HAVE_SELINUX
+ case SelinuxReceiverProcess:
+ ereport(LOG,
+ (errmsg("could not fork selinux receiver process: %m")));
+ break;
+ #endif
default:
ereport(LOG,
(errmsg("could not fork process: %m")));
diff -Nrpc base/src/backend/rewrite/rewriteDefine.c sepgsql/src/backend/rewrite/rewriteDefine.c
*** base/src/backend/rewrite/rewriteDefine.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/backend/rewrite/rewriteDefine.c Fri Sep 18 14:51:00 2009
***************
*** 27,32 ****
--- 27,33 ----
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rewriteSupport.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/inval.h"
*************** DefineQueryRewrite(char *rulename,
*** 266,271 ****
--- 267,275 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(event_relation));
+ /* SELinux checks */
+ sepgsql_rule_create(event_relid, rulename);
+
/*
* No rule actions that modify OLD or NEW
*/
diff -Nrpc base/src/backend/rewrite/rewriteRemove.c sepgsql/src/backend/rewrite/rewriteRemove.c
*** base/src/backend/rewrite/rewriteRemove.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/backend/rewrite/rewriteRemove.c Fri Sep 18 14:51:00 2009
***************
*** 22,27 ****
--- 22,28 ----
#include "catalog/pg_rewrite.h"
#include "miscadmin.h"
#include "rewrite/rewriteRemove.h"
+ #include "security/sepgsql.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
*************** RemoveRewriteRule(Oid owningRel, const c
*** 78,83 ****
--- 79,87 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
get_rel_name(eventRelationOid));
+ /* SELinux checks */
+ sepgsql_rule_drop(eventRelationOid, ruleName);
+
/*
* Do the deletion
*/
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 Sep 17 17:04:16 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 bridge.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 Tue Dec 8 14:16:15 2009
***************
*** 0 ****
--- 1,880 ----
+ /*
+ * 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
+
+ #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);
+ }
+ }
+
+ /*
+ * sepgsqlAvcReset
+ *
+ * It invalidate access vector cache. It has to be called on errors,
+ * because avc entries for newly created context is uncertain whether
+ * it is still valid, or not.
+ */
+ void
+ sepgsqlAvcReset(void)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ MemoryContextReset(AvcMemCtx);
+
+ current_page = NULL;
+
+ sepgsqlAvcSwitchClient(sepgsqlGetClientLabel());
+ }
+
+ /*
+ * 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, sepgsql_sid_t tsid, 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(tsid.relid, tsid.secid, tclass);
+ index = hash_key % AVC_HASH_NUM_SLOTS;
+
+ scontext = page->scontext;
+ tcontext = securityRawSecLabelOut(tsid.relid, tsid.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 = tsid.relid;
+ cache->tsid.secid = tsid.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, sepgsql_sid_t tsid, uint16 tclass)
+ {
+ avc_datum *cache = NULL;
+ uint32 hash_key, index;
+ ListCell *l;
+
+ hash_key = avc_hash_key(tsid.relid, tsid.secid, 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 == tsid.relid
+ && cache->tsid.secid == tsid.secid)
+ {
+ 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
+ *
+ * It checks client's privileges on the given object using avc.
+ */
+ bool
+ sepgsqlClientHasPerms(sepgsql_sid_t tsid,
+ 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, tsid, tclass);
+ if (!cache)
+ cache = sepgsqlAvcMakeEntry(current_page, tsid, tclass);
+ } while (!sepgsqlAvcCheckValid());
+
+ denied = required & ~cache->allowed;
+ audited = denied ? (denied & cache->auditdeny)
+ : (required & cache->auditallow);
+ if (audited)
+ {
+ sepgsqlAvcAudit(!!denied,
+ current_page->scontext,
+ securityRawSecLabelOut(tsid.relid, tsid.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;
+ }
+
+ /*
+ * sepgsqlClientCreateSecid
+ * sepgsqlClientCreateLabel
+ */
+ sepgsql_sid_t
+ sepgsqlClientCreateSecid(sepgsql_sid_t tsid, uint16 tclass, Oid nrelid)
+ {
+ sepgsql_sid_t nsid;
+ avc_datum *cache;
+ int index;
+
+ do {
+ cache = sepgsqlAvcLookup(current_page, tsid, tclass);
+ if (!cache)
+ cache = sepgsqlAvcMakeEntry(current_page, tsid, 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;
+ }
+ nsid = cache->nsid[index];
+ } while (!sepgsqlAvcCheckValid());
+
+ return nsid;
+ }
+
+ security_context_t
+ sepgsqlClientCreateLabel(sepgsql_sid_t tsid, uint16 tclass)
+ {
+ avc_datum *cache;
+
+ do {
+ cache = sepgsqlAvcLookup(current_page, tsid, tclass);
+ if (!cache)
+ cache = sepgsqlAvcMakeEntry(current_page, tsid, 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->enforcing = (enforce ? true : false);
+ selinux_state->version++;
+ LWLockRelease(SepgsqlAvcLock);
+
+ return 0;
+ }
+
+ static int
+ sepgsql_cb_policyload(int seqno)
+ {
+ /* invalidate local avc */
+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
+ selinux_state->version++;
+ LWLockRelease(SepgsqlAvcLock);
+
+ return 0;
+ }
+
+ void
+ sepgsqlReceiverMain(void)
+ {
+ union selinux_callback cb;
+
+ Assert(sepgsqlIsEnabled());
+
+ #ifdef HAVE_SETSID
+ if (setsid() < 0)
+ elog(FATAL, "setsid() failed: %m");
+ #endif
+
+ /*
+ * setup the signal handler
+ */
+ pqinitmask();
+ pqsignal(SIGHUP, SIG_IGN);
+ pqsignal(SIGINT, SIG_IGN);
+ pqsignal(SIGTERM, exit);
+ pqsignal(SIGQUIT, exit);
+ pqsignal(SIGUSR1, SIG_IGN);
+ pqsignal(SIGUSR2, SIG_IGN);
+ pqsignal(SIGCHLD, SIG_DFL);
+ PG_SETMASK(&UnBlockSig);
+
+ /*
+ * map shared memory segment
+ */
+ sepgsqlShmemInit();
+
+ 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();
+
+ exit(0);
+ }
diff -Nrpc base/src/backend/security/sepgsql/bridge.c sepgsql/src/backend/security/sepgsql/bridge.c
*** base/src/backend/security/sepgsql/bridge.c Thu Jan 1 09:00:00 1970
--- sepgsql/src/backend/security/sepgsql/bridge.c Tue Dec 1 17:11:40 2009
***************
*** 0 ****
--- 1,2876 ----
+ /*
+ * src/backend/security/sepgsql/bridge.c
+ *
+ * New style security hooks for SE-PostgreSQL
+ *
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ */
+ #include "postgres.h"
+
+ #include "access/sysattr.h"
+ #include "catalog/heap.h"
+ #include "catalog/indexing.h"
+ #include "catalog/pg_authid.h"
+ #include "catalog/pg_cast.h"
+ #include "catalog/pg_conversion.h"
+ #include "catalog/pg_database.h"
+ #include "catalog/pg_foreign_data_wrapper.h"
+ #include "catalog/pg_foreign_server.h"
+ #include "catalog/pg_language.h"
+ #include "catalog/pg_namespace.h"
+ #include "catalog/pg_operator.h"
+ #include "catalog/pg_opclass.h"
+ #include "catalog/pg_opfamily.h"
+ #include "catalog/pg_proc.h"
+ #include "catalog/pg_rewrite.h"
+ #include "catalog/pg_security.h"
+ #include "catalog/pg_tablespace.h"
+ #include "catalog/pg_ts_parser.h"
+ #include "catalog/pg_ts_dict.h"
+ #include "catalog/pg_ts_template.h"
+ #include "catalog/pg_ts_config.h"
+ #include "catalog/pg_type.h"
+ #include "catalog/pg_user_mapping.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"
+
+ #include <libgen.h>
+
+ /* ------------------------------------------------------------ *
+ * Common Helper Routines
+ * ------------------------------------------------------------ */
+ static bool sepgsql_database_common(Oid datOid, uint32 required, bool abort);
+ static bool sepgsql_schema_common(Oid nspOid, uint32 required, bool abort);
+ static bool sepgsql_attribute_common(Oid relOid, AttrNumber attnum,
+ uint32 required, bool abort);
+ static bool sepgsql_relation_common(Oid relOid, uint32 required, bool abort);
+ static bool sepgsql_proc_common(Oid procOid, uint32 required, bool abort);
+ static bool sepgsql_fdw_common(Oid fdwOid, uint32 required, bool abort);
+ static bool sepgsql_foreign_server_common(Oid fsrvOid, uint32 required, bool abort);
+ static bool sepgsql_language_common(Oid langOid, uint32 required, bool abort);
+ static bool sepgsql_operator_common(Oid oprOid, uint32 required, bool abort);
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_database related security hooks
+ *
+ * ------------------------------------------------------------ */
+ static bool
+ sepgsql_database_common(Oid datOid, uint32 required, bool abort)
+ {
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+ const char *auname;
+ bool rc;
+
+ tuple = SearchSysCache(DATABASEOID,
+ ObjectIdGetDatum(datOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for database: %u", datOid);
+
+ auname = NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname);
+
+ sid = sepgsqlGetTupleSecid(DatabaseRelationId, tuple, &tclass);
+
+ rc = sepgsqlClientHasPerms(sid, tclass, required, auname, abort);
+
+ ReleaseSysCache(tuple);
+
+ return rc;
+ }
+
+ Oid
+ sepgsql_database_create(const char *datName, DefElem *newLabel)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ if (!newLabel)
+ sid = sepgsqlGetDefaultDatabaseSecid();
+ else
+ {
+ sid.relid = DatabaseRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid,
+ strVal(newLabel->arg));
+ }
+
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__CREATE,
+ datName, true);
+ return sid.secid;
+ }
+
+ void
+ sepgsql_database_alter(Oid datOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_database_common(datOid, SEPG_DB_DATABASE__SETATTR, true);
+ }
+
+ void
+ sepgsql_database_drop(Oid datOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_database_common(datOid, SEPG_DB_DATABASE__DROP, true);
+ }
+
+ Oid
+ sepgsql_database_relabel(Oid datOid, DefElem *newLabel)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ {
+ if (newLabel)
+ ereport(ERROR,
+ (errcode(ERRCODE_SELINUX_ERROR),
+ errmsg("SELinux is disabled now")));
+
+ return InvalidOid;
+ }
+ sid.relid = DatabaseRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg));
+
+ /* db_database:{setattr relabelfrom} to older seclabel */
+ sepgsql_database_common(datOid,
+ SEPG_DB_DATABASE__SETATTR |
+ SEPG_DB_DATABASE__RELABELFROM, true);
+
+ /* db_database:{relabelto} to newer seclabel */
+ sepgsqlClientHasPerms(sid,
+ SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__RELABELTO,
+ get_database_name(datOid), true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_database_grant(Oid datOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_database_common(datOid, SEPG_DB_DATABASE__SETATTR, true);
+ }
+
+ void
+ sepgsql_database_access(Oid datOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_database_common(datOid, SEPG_DB_DATABASE__ACCESS, true);
+ }
+
+ bool
+ sepgsql_database_superuser(Oid datOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return true;
+
+ return sepgsql_database_common(datOid, SEPG_DB_DATABASE__SUPERUSER, false);
+ }
+
+ void
+ sepgsql_database_load_module(Oid datOid, const char *filename)
+ {
+ HeapTuple tuple;
+ security_context_t filecon;
+ security_context_t datcon;
+
+ 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(datOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for database: %u", datOid);
+
+ datcon = securityRawSecLabelOut(DatabaseRelationId,
+ HeapTupleGetSecid(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(datcon,
+ filecon,
+ SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__LOAD_MODULE,
+ filename, true);
+ }
+ PG_CATCH();
+ {
+ freecon(filecon);
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
+ freecon(filecon);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_namespace related security hooks
+ *
+ * ------------------------------------------------------------ */
+ static bool
+ sepgsql_schema_common(Oid nspOid, uint32 required, bool abort)
+ {
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+ const char *auname;
+ bool rc;
+
+ tuple = SearchSysCache(NAMESPACEOID,
+ ObjectIdGetDatum(nspOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for namespace: %u", nspOid);
+
+ sid = sepgsqlGetTupleSecid(NamespaceRelationId, tuple, &tclass);
+
+ auname = NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname);
+
+ rc = sepgsqlClientHasPerms(sid, tclass, required, auname, abort);
+
+ ReleaseSysCache(tuple);
+
+ return rc;
+ }
+
+ Oid
+ sepgsql_schema_create(const char *nspName, bool isTemp, DefElem *newLabel)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ if (!newLabel)
+ sid = sepgsqlGetDefaultSchemaSecid(MyDatabaseId);
+ else
+ {
+ sid.relid = NamespaceRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg));
+ }
+
+ sepgsqlClientHasPerms(sid,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__CREATE,
+ nspName, true);
+ return sid.secid;
+ }
+
+ void
+ sepgsql_schema_alter(Oid nspOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__SETATTR, true);
+ }
+
+ void
+ sepgsql_schema_drop(Oid nspOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__DROP, true);
+ }
+
+ Oid
+ sepgsql_schema_relabel(Oid nspOid, DefElem *newLabel)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ {
+ if (newLabel)
+ ereport(ERROR,
+ (errcode(ERRCODE_SELINUX_ERROR),
+ errmsg("SELinux is disabled now")));
+ return InvalidOid;
+ }
+ sid.relid = NamespaceRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg));
+
+ /* db_schema:{setattr relabelfrom} for older seclabel */
+ sepgsql_schema_common(nspOid,
+ SEPG_DB_SCHEMA__SETATTR |
+ SEPG_DB_SCHEMA__RELABELFROM, true);
+
+ /* db_schema:{relabelto} for newer seclabel */
+ sepgsqlClientHasPerms(sid,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__RELABELTO,
+ get_namespace_name(nspOid), true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_schema_grant(Oid nspOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__SETATTR, true);
+ }
+
+ bool
+ sepgsql_schema_search(Oid nspOid, bool abort)
+ {
+ if (!sepgsqlIsEnabled())
+ return true;
+
+ return sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__SEARCH, abort);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_attribute related security hooks
+ *
+ * ------------------------------------------------------------ */
+ static bool
+ sepgsql_attribute_common(Oid relOid, AttrNumber attnum,
+ uint32 required, bool abort)
+ {
+ Form_pg_attribute attForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+ char auname[NAMEDATALEN * 2 + 3];
+ bool rc = true;
+
+ /* Caller prevent case when relkind != RELKIND_RELATION */
+ Assert(get_rel_relkind(relOid) == RELKIND_RELATION);
+
+ tuple = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relOid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+ attnum, relOid);
+ attForm = (Form_pg_attribute) GETSTRUCT(tuple);
+
+ /*
+ * NOTE: when a table to be dropped, corresponding attributes
+ * are also removed. Some of them can be already logically
+ * dropped using ALTER TABLE ... DROP statement.
+ * In this case, SE-PostgreSQL does not check anything.
+ * If any other situation touches dropped column, it is a bug.
+ */
+ if (attForm->attisdropped)
+ goto skip;
+
+ sprintf(auname, "%s.%s", get_rel_name(relOid), NameStr(attForm->attname));
+
+ sid = sepgsqlGetTupleSecid(AttributeRelationId, tuple, &tclass);
+
+ rc = sepgsqlClientHasPerms(sid, tclass, required, auname, abort);
+
+ skip:
+ ReleaseSysCache(tuple);
+
+ return rc;
+ }
+
+ Oid
+ sepgsql_attribute_create(Oid relOid, ColumnDef *cdef)
+ {
+ sepgsql_sid_t sid;
+ char relkind;
+
+ if (!sepgsqlIsEnabled())
+ {
+ if (cdef->secLabel)
+ ereport(ERROR,
+ (errcode(ERRCODE_SELINUX_ERROR),
+ errmsg("SELinux is disabled now")));
+ return InvalidOid;
+ }
+
+ relkind = get_rel_relkind(relOid);
+ if (relkind == RELKIND_RELATION)
+ {
+ char auname[NAMEDATALEN * 2 + 3];
+
+ if (!cdef->secLabel)
+ sid = sepgsqlGetDefaultColumnSecid(relOid);
+ else
+ {
+ char *label = strVal(((DefElem *)cdef->secLabel)->arg);
+
+ sid.relid = AttributeRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid, label);
+ }
+
+ sprintf(auname, "%s.%s", get_rel_name(relOid), cdef->colname);
+ sepgsqlClientHasPerms(sid,
+ SEPG_CLASS_DB_COLUMN,
+ SEPG_DB_COLUMN__CREATE,
+ auname, true);
+ }
+ else
+ {
+ /* no need to check for toast relation */
+ if (relkind != RELKIND_TOASTVALUE)
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true);
+ return InvalidOid;
+ }
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_attribute_alter(Oid relOid, const char *attname)
+ {
+ AttrNumber attno;
+ char relkind;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /*
+ * If the target attribute does not exist, an error
+ * shall be raised later.
+ */
+ attno = get_attnum(relOid, attname);
+ if (attno == InvalidAttrNumber)
+ return;
+
+ relkind = get_rel_relkind(relOid);
+ if (relkind == RELKIND_RELATION)
+ {
+ sepgsql_attribute_common(relOid, attno, SEPG_DB_COLUMN__SETATTR, true);
+ }
+ else if (relkind != RELKIND_TOASTVALUE)
+ {
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true);
+ }
+ }
+
+ void
+ sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /*
+ * We only need to check db_column:{drop} when relkind equals
+ * RELKIND_RELATION, because db_xxx:{drop} permission is already
+ * checked in other cases. (e.g DROP SEQUENCE, ...)
+ */
+ if (get_rel_relkind(relOid) == RELKIND_RELATION)
+ sepgsql_attribute_common(relOid, attnum,
+ SEPG_DB_COLUMN__DROP, true);
+ }
+
+ void
+ sepgsql_attribute_grant(Oid relOid, AttrNumber attnum)
+ {
+ char relkind;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ relkind = get_rel_relkind(relOid);
+ if (relkind == RELKIND_RELATION)
+ {
+ sepgsql_attribute_common(relOid, attnum, SEPG_DB_COLUMN__SETATTR, true);
+ }
+ else if (relkind != RELKIND_TOASTVALUE)
+ {
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true);
+ }
+ }
+
+ Oid
+ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, DefElem *newLabel)
+ {
+ sepgsql_sid_t sid;
+ char auname[NAMEDATALEN * 2 + 3];
+
+ if (!sepgsqlIsEnabled())
+ {
+ if (!newLabel)
+ ereport(ERROR,
+ (errcode(ERRCODE_SELINUX_ERROR),
+ errmsg("SELinux is disabled now")));
+ return InvalidOid;
+ }
+
+ Assert(get_rel_relkind(relOid) == RELKIND_RELATION);
+
+ sid.relid = AttributeRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg));
+
+ /* db_column:{setattr relabelfrom} */
+ sepgsql_attribute_common(relOid, attnum,
+ SEPG_DB_COLUMN__SETATTR |
+ SEPG_DB_COLUMN__RELABELFROM, true);
+
+ /* db_column:{relabelto} */
+ sprintf(auname, "%s.%s",
+ get_rel_name(relOid),
+ get_attname(relOid, attnum));
+ sepgsqlClientHasPerms(sid,
+ SEPG_CLASS_DB_COLUMN,
+ SEPG_DB_COLUMN__RELABELTO,
+ auname, true);
+
+ return sid.secid;
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_class related security hooks
+ *
+ * ------------------------------------------------------------ */
+ static bool
+ sepgsql_relation_common(Oid relOid, uint32 required, bool abort)
+ {
+ Form_pg_class relForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+ bool rc;
+
+ tuple = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relOid);
+ relForm = (Form_pg_class) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(RelationRelationId, tuple, &tclass);
+ rc = sepgsqlClientHasPerms(sid, tclass, required,
+ NameStr(relForm->relname), abort);
+
+ ReleaseSysCache(tuple);
+
+ return rc;
+ }
+
+ /*
+ * sepgsql_relation_create
+ * 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 *
+ sepgsql_relation_create(const char *relName,
+ char relkind,
+ TupleDesc tupDesc,
+ Oid nspOid,
+ DefElem *relLabel,
+ List *colList,
+ bool createAs,
+ bool permission)
+ {
+ Oid *secLabels;
+ sepgsql_sid_t relsid;
+ uint16 tclass;
+ uint32 required;
+ int index;
+
+ if (!sepgsqlIsEnabled())
+ return NULL;
+
+ switch (relkind)
+ {
+ case RELKIND_RELATION:
+ if (!relLabel)
+ relsid = sepgsqlGetDefaultTableSecid(nspOid);
+ else
+ {
+ relsid.relid = RelationRelationId;
+ relsid.secid = securityTransSecLabelIn(relsid.relid,
+ strVal(relLabel->arg));
+ }
+ tclass = SEPG_CLASS_DB_TABLE;
+ required = SEPG_DB_TABLE__CREATE;
+ if (createAs)
+ required |= SEPG_DB_TABLE__INSERT;
+ break;
+
+ case RELKIND_SEQUENCE:
+ if (!relLabel)
+ relsid = sepgsqlGetDefaultSequenceSecid(nspOid);
+ else
+ {
+ relsid.relid = RelationRelationId;
+ relsid.secid = securityTransSecLabelIn(relsid.relid,
+ strVal(relLabel->arg));
+ }
+ tclass = SEPG_CLASS_DB_SEQUENCE;
+ required = SEPG_DB_SEQUENCE__CREATE;
+ break;
+
+ default:
+ if (!relLabel)
+ relsid = sepgsqlGetDefaultTupleSecid(RelationRelationId);
+ else
+ {
+ /* should not be happen */
+ relsid.relid = RelationRelationId;
+ relsid.secid = securityTransSecLabelIn(relsid.relid,
+ strVal(relLabel->arg));
+ }
+ tclass = SEPG_CLASS_DB_TUPLE;
+ required = SEPG_DB_TUPLE__INSERT;
+ break;
+ }
+
+ /*
+ * The secLabeld 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 (if necessary).
+ */
+ secLabels = palloc0(sizeof(Oid) * (tupDesc->natts
+ - FirstLowInvalidHeapAttributeNumber));
+
+ /* relation's security identifier to be assigned on */
+ secLabels[0] = relsid.secid;
+
+ /*
+ * Note that this hook can be called during initdb processes.
+ * It is an exception of access controls, so we skip any checks.
+ *
+ * And, we don't need any checks for toast relations, because
+ * it is a quite internal stuff.
+ */
+ if (permission)
+ {
+ /* db_schema:{add_name} */
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+
+ /* db_table:{create}, db_sequence:{create} or db_tuple:{insert} */
+ sepgsqlClientHasPerms(relsid, tclass, required, relName, true);
+ }
+
+ /* no individual security context expect for RELKIND_RELATION */
+ if (relkind != RELKIND_RELATION)
+ return secLabels;
+
+ /*
+ * db_column:{create} permission
+ */
+ for (index = FirstLowInvalidHeapAttributeNumber + 1;
+ index < tupDesc->natts;
+ index++)
+ {
+ Form_pg_attribute attr;
+ sepgsql_sid_t attsid = { InvalidOid, InvalidOid };
+ char attname[NAMEDATALEN * 2 + 3];
+ ListCell *l;
+
+ /* skip unnecessary attributes */
+ if (index == ObjectIdAttributeNumber && !tupDesc->tdhasoid)
+ continue;
+
+ if (index < 0)
+ attr = SystemAttributeDefinition(index, tupDesc->tdhasoid);
+ else
+ attr = tupDesc->attrs[index];
+
+ /* Is there any given security context? */
+ foreach (l, colList)
+ {
+ ColumnDef *cdef = lfirst(l);
+
+ if (cdef->secLabel &&
+ strcmp(cdef->colname, NameStr(attr->attname)) == 0)
+ {
+ attsid.relid = AttributeRelationId;
+ attsid.secid = securityTransSecLabelIn(attsid.relid,
+ strVal(((DefElem *)cdef->secLabel)->arg));
+ break;
+ }
+ }
+
+ /* default security context, if not given */
+ if (!SidIsValid(attsid))
+ attsid = sepgsqlClientCreateSecid(relsid,
+ SEPG_CLASS_DB_COLUMN,
+ AttributeRelationId);
+ if (permission)
+ {
+ required = SEPG_DB_COLUMN__CREATE;
+
+ if (createAs)
+ required |= SEPG_DB_COLUMN__INSERT;
+
+ /* db_column:{create (insert)} */
+ sprintf(attname, "%s.%s", relName, NameStr(attr->attname));
+ sepgsqlClientHasPerms(attsid,
+ SEPG_CLASS_DB_COLUMN,
+ required, attname, true);
+ }
+ /* column's security identifier to be assigend on */
+ secLabels[index - FirstLowInvalidHeapAttributeNumber] = attsid.secid;
+ }
+
+ return secLabels;
+ }
+
+ /*
+ * sepgsql_relation_copy
+ * 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 *
+ sepgsql_relation_copy(Relation src)
+ {
+ Oid *secLabels;
+ HeapTuple tuple;
+ Oid relOid = RelationGetRelid(src);
+ int index;
+
+ if (!sepgsqlIsEnabled())
+ return NULL;
+
+ /* see the comment at sepgsqlCreateTableColumn*/
+ secLabels = palloc0(sizeof(Oid) * (RelationGetDescr(src)->natts
+ - FirstLowInvalidHeapAttributeNumber));
+
+ /* copy table's security identifier */
+ tuple = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation \"%s\"",
+ RelationGetRelationName(src));
+
+ secLabels[0] = HeapTupleGetSecid(tuple);
+
+ ReleaseSysCache(tuple);
+
+ /* copy column's security identifier */
+ for (index = FirstLowInvalidHeapAttributeNumber + 1;
+ index < RelationGetDescr(src)->natts;
+ index++)
+ {
+ Form_pg_attribute attr;
+
+ if (index < 0)
+ attr = SystemAttributeDefinition(index, true);
+ else
+ attr = RelationGetDescr(src)->attrs[index];
+
+ tuple = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relOid),
+ Int16GetDatum(attr->attnum),
+ 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ continue;
+
+ secLabels[index - FirstLowInvalidHeapAttributeNumber]
+ = HeapTupleGetSecid(tuple);
+
+ ReleaseSysCache(tuple);
+ }
+
+ return secLabels;
+ }
+
+ void
+ sepgsql_relation_alter(Oid relOid, const char *newName, Oid newNsp)
+ {
+ Form_pg_class relForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relOid);
+ relForm = (Form_pg_class) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(RelationRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TABLE__SETATTR,
+ NameStr(relForm->relname), true);
+
+ /* db_schema:{add_name remove_name}, if necessary */
+ if (newName || OidIsValid(newNsp))
+ {
+ if (!OidIsValid(newNsp))
+ sepgsql_schema_common(relForm->relnamespace,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ else
+ {
+ sepgsql_schema_common(relForm->relnamespace,
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ sepgsql_schema_common(newNsp, SEPG_DB_SCHEMA__ADD_NAME, true);
+ }
+ }
+ ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsql_relation_drop(Oid relOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ if (get_rel_relkind(relOid) == RELKIND_TOASTVALUE)
+ return;
+
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__DROP, true);
+ }
+
+ void
+ sepgsql_relation_grant(Oid relOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true);
+ }
+
+ Oid
+ sepgsql_relation_relabel(Oid relOid, DefElem *newLabel)
+ {
+ sepgsql_sid_t sid;
+ char relkind;
+
+ if (!sepgsqlIsEnabled())
+ {
+ if (newLabel)
+ ereport(ERROR,
+ (errcode(ERRCODE_SELINUX_ERROR),
+ errmsg("SELinux is disabled now")));
+ return InvalidOid;
+ }
+
+ relkind = get_rel_relkind(relOid);
+ 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(relOid))));
+
+ /* input security context */
+ sid.relid = RelationRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg));
+
+ /* db_table/db_sequence:{setattr relabelfrom} */
+ sepgsql_relation_common(relOid,
+ SEPG_DB_TABLE__SETATTR |
+ SEPG_DB_TABLE__RELABELFROM, true);
+
+ /* db_table/db_sequence:{relabelto} */
+ sepgsqlClientHasPerms(sid,
+ (relkind == RELKIND_RELATION
+ ? SEPG_CLASS_DB_TABLE
+ : SEPG_CLASS_DB_SEQUENCE),
+ SEPG_DB_TABLE__RELABELTO,
+ get_rel_name(relOid), true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_relation_get_transaction_id(Oid relOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__GETATTR, true);
+ }
+
+ void
+ sepgsql_relation_copy_definition(Oid relOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__GETATTR, true);
+ }
+
+ void
+ sepgsql_relation_truncate(Relation rel)
+ {
+ HeapScanDesc scan;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ Assert(RelationGetForm(rel)->relkind == RELKIND_RELATION);
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /* check db_table:{delete} permission */
+ sepgsql_relation_common(RelationGetRelid(rel),
+ SEPG_DB_TABLE__DELETE, true);
+
+ /* row-level access control is enabled? */
+ if (!sepostgresql_row_level)
+ return;
+
+ /* check db_tuple:{delete} permission */
+ scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
+
+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+ {
+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel), tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__DELETE,
+ NULL, true);
+ }
+ heap_endscan(scan);
+ }
+
+ void
+ sepgsql_relation_references(Relation rel, int16 *attnums, int natts)
+ {
+ Oid relOid = RelationGetRelid(rel);
+ int i;
+
+ Assert(RelationGetForm(rel)->relkind == RELKIND_RELATION);
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /* db_table:{reference} */
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__REFERENCE, true);
+
+ for (i=0; i < natts; i++)
+ sepgsql_attribute_common(relOid, attnums[i],
+ SEPG_DB_COLUMN__REFERENCE, true);
+ }
+
+ void
+ sepgsql_relation_lock(Oid relOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ if (get_rel_relkind(relOid) != RELKIND_RELATION)
+ return;
+
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__LOCK, true);
+ }
+
+ void
+ sepgsql_view_replace(Oid viewOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ Assert(get_rel_relkind(viewOid) == RELKIND_VIEW);
+
+ sepgsql_relation_common(viewOid, SEPG_DB_TABLE__SETATTR, true);
+ }
+
+ void
+ sepgsql_index_create(Oid relOid, Oid nspOid, bool check_rights)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ if (check_rights)
+ {
+ /* db_table:{setattr} */
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true);
+
+ /* db_schema:{add_name} */
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+ }
+ }
+
+ void
+ sepgsql_sequence_get_value(Oid seqOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ Assert(get_rel_relkind(seqOid) == RELKIND_SEQUENCE);
+
+ sepgsql_relation_common(seqOid, SEPG_DB_SEQUENCE__GET_VALUE, true);
+ }
+
+ void
+ sepgsql_sequence_next_value(Oid seqOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ Assert(get_rel_relkind(seqOid) == RELKIND_SEQUENCE);
+
+ sepgsql_relation_common(seqOid, SEPG_DB_SEQUENCE__NEXT_VALUE, true);
+ }
+
+ void
+ sepgsql_sequence_set_value(Oid seqOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ Assert(get_rel_relkind(seqOid) == RELKIND_SEQUENCE);
+
+ sepgsql_relation_common(seqOid, SEPG_DB_SEQUENCE__SET_VALUE, true);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_proc related security hooks
+ *
+ * ------------------------------------------------------------ */
+ static bool
+ sepgsql_proc_common(Oid procOid, uint32 required, bool abort)
+ {
+ sepgsql_sid_t sid;
+ HeapTuple tuple;
+ uint16 tclass;
+ const char *auname;
+ bool rc;
+
+ tuple = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(procOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for procedure: %u", procOid);
+
+ auname = NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname);
+ sid = sepgsqlGetTupleSecid(ProcedureRelationId, tuple, &tclass);
+
+ rc = sepgsqlClientHasPerms(sid, tclass, required, auname, abort);
+
+ ReleaseSysCache(tuple);
+
+ return rc;
+ }
+
+ Oid
+ sepgsql_proc_create(const char *procName, HeapTuple oldTup,
+ Oid nspOid, Oid langOid, DefElem *newLabel)
+ {
+ sepgsql_sid_t sid;
+ HeapTuple tuple;
+ uint32 required;
+ bool trusted;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ if (!HeapTupleIsValid(oldTup))
+ {
+ /* create a new function */
+ required = SEPG_DB_PROCEDURE__CREATE;
+ if (!newLabel)
+ sid = sepgsqlGetDefaultProcedureSecid(nspOid);
+ else
+ {
+ sid.relid = ProcedureRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg));
+ }
+ }
+ else if (!newLabel)
+ {
+ /* replace an existing function, without any label */
+ required = SEPG_DB_PROCEDURE__SETATTR;
+ sid = sepgsqlGetTupleSecid(ProcedureRelationId, oldTup, NULL);
+ }
+ else
+ {
+ /* replace an existing function, with relabeling */
+ sepgsql_proc_common(HeapTupleGetOid(oldTup),
+ SEPG_DB_PROCEDURE__SETATTR |
+ SEPG_DB_PROCEDURE__RELABELFROM, true);
+
+ required = SEPG_DB_PROCEDURE__RELABELTO;
+ sid = sepgsqlGetTupleSecid(ProcedureRelationId, oldTup, NULL);
+ }
+
+ /* Procedural language is trusted? */
+ tuple = SearchSysCache(LANGOID,
+ ObjectIdGetDatum(langOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for procedural langugage: %u", langOid);
+
+ trusted = ((Form_pg_language) GETSTRUCT(tuple))->lanpltrusted;
+ if (!trusted)
+ required |= SEPG_DB_PROCEDURE__UNTRUSTED;
+
+ ReleaseSysCache(tuple);
+
+ /* check it */
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_PROCEDURE,
+ required, procName, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_proc_alter(Oid procOid, const char *newName, Oid newNsp)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true);
+ if (newName || OidIsValid(newNsp))
+ {
+ HeapTuple tuple;
+ Oid oldNsp;
+
+ tuple = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(procOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for function %u", procOid);
+
+ oldNsp = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace;
+
+ ReleaseSysCache(tuple);
+
+ if (!OidIsValid(newNsp))
+ {
+ sepgsql_schema_common(oldNsp,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ }
+ else
+ {
+ sepgsql_schema_common(oldNsp, SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ sepgsql_schema_common(newNsp, SEPG_DB_SCHEMA__ADD_NAME, true);
+ }
+ }
+ }
+
+ void
+ sepgsql_proc_drop(Oid procOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__DROP, true);
+ }
+
+ void
+ sepgsql_proc_grant(Oid procOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true);
+ }
+
+ Oid
+ sepgsql_proc_relabel(Oid procOid, DefElem *newLabel)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ {
+ if (newLabel)
+ ereport(ERROR,
+ (errcode(ERRCODE_SELINUX_ERROR),
+ errmsg("SELinux is disabled now")));
+ return InvalidOid;
+ }
+
+ sid.relid = ProcedureRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg));
+
+ /* db_procedure:{setattr relabelfrom} for older seclabel */
+ sepgsql_proc_common(procOid,
+ SEPG_DB_PROCEDURE__SETATTR |
+ SEPG_DB_PROCEDURE__RELABELFROM, true);
+ /* db_procedure:{relabelto} for newer seclabel */
+ sepgsqlClientHasPerms(sid,
+ SEPG_CLASS_DB_PROCEDURE,
+ SEPG_DB_PROCEDURE__RELABELTO,
+ get_func_name(procOid), true);
+ return sid.secid;
+ }
+
+ void
+ sepgsql_proc_execute(Oid procOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__EXECUTE, true);
+ }
+
+ bool
+ sepgsql_proc_hint_inlined(HeapTuple protup)
+ {
+ security_context_t newcon;
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return true;
+
+ if (!sepgsql_proc_common(HeapTupleGetOid(protup),
+ SEPG_DB_PROCEDURE__EXECUTE, false))
+ return false;
+ /*
+ * 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.
+ */
+ sid = sepgsqlGetTupleSecid(ProcedureRelationId, protup, NULL);
+
+ newcon = sepgsqlClientCreateLabel(sid, SEPG_CLASS_PROCESS);
+
+ if (strcmp(sepgsqlGetClientLabel(), newcon) == 0)
+ return true;
+
+ return false;
+ }
+
+ /*
+ * 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
+ sepgsql_proc_entrypoint(FmgrInfo *flinfo, HeapTuple protup)
+ {
+ struct TrustedProcedureCache *tcache;
+ security_context_t newcon;
+ sepgsql_sid_t proSid;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ proSid = sepgsqlGetTupleSecid(ProcedureRelationId,
+ protup, NULL);
+
+ newcon = sepgsqlClientCreateLabel(proSid, SEPG_CLASS_PROCESS);
+
+ /* Do nothing, if it is not a trusted procedure */
+ if (strcmp(newcon, sepgsqlGetClientLabel()) == 0)
+ return;
+
+ /* check db_procedure:{entrypoint} */
+ sepgsqlClientHasPerms(proSid,
+ SEPG_CLASS_DB_PROCEDURE,
+ SEPG_DB_PROCEDURE__ENTRYPOINT,
+ NULL, 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;
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_cast related security hooks
+ *
+ * ------------------------------------------------------------ */
+ Oid
+ sepgsql_cast_create(Oid sourceTypOid, Oid targetTypOid, Oid funcOid)
+ {
+ sepgsql_sid_t sid;
+ char audit_buffer[2*NAMEDATALEN+10];
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(CastRelationId);
+
+ snprintf(audit_buffer, sizeof(audit_buffer), "%s::%s",
+ format_type_be(sourceTypOid), format_type_be(targetTypOid));
+
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT,
+ audit_buffer, true);
+
+ if (OidIsValid(funcOid))
+ sepgsql_proc_common(funcOid, SEPG_DB_PROCEDURE__INSTALL, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_cast_drop(Oid castOid)
+ {
+ Form_pg_cast castForm;
+ Relation rel;
+ HeapTuple tuple;
+ ScanKeyData skey;
+ SysScanDesc scan;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+ char audit_buffer[2*NAMEDATALEN+10];
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ rel = heap_open(CastRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(castOid));
+
+ scan = systable_beginscan(rel, CastOidIndexId, true,
+ SnapshotNow, 1, &skey);
+ tuple = systable_getnext(scan);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for cast: %u", castOid);
+
+ castForm = (Form_pg_cast) GETSTRUCT(tuple);
+
+ snprintf(audit_buffer, sizeof(audit_buffer), "%s::%s",
+ format_type_be(castForm->castsource),
+ format_type_be(castForm->casttarget));
+
+ sid = sepgsqlGetTupleSecid(CastRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__DELETE,
+ audit_buffer, true);
+
+ systable_endscan(scan);
+
+ heap_close(rel, AccessShareLock);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_conversion related security hooks
+ *
+ * ------------------------------------------------------------ */
+ Oid
+ sepgsql_conversion_create(const char *convName, Oid nspOid, Oid procOid)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(ConversionRelationId);
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT,
+ convName, true);
+
+ /* db_schema:{add_name} */
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+
+ /* db_procedure:{install} */
+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__INSTALL, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_conversion_alter(Oid convOid, const char *newName)
+ {
+ Form_pg_conversion convForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(CONVOID,
+ ObjectIdGetDatum(convOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for conversion %u", convOid);
+ convForm = (Form_pg_conversion) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(ConversionRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__UPDATE,
+ NameStr(convForm->conname), true);
+ if (newName)
+ {
+ Oid nspOid = convForm->connamespace;
+
+ sepgsql_schema_common(nspOid,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ }
+ ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsql_conversion_drop(Oid convOid)
+ {
+ Form_pg_conversion convForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(CONVOID,
+ ObjectIdGetDatum(convOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for conversion %u", convOid);
+ convForm = (Form_pg_conversion) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(ConversionRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__UPDATE,
+ NameStr(convForm->conname), true);
+
+ /* db_schema:{remove_name} */
+ sepgsql_schema_common(convForm->connamespace,
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+
+ ReleaseSysCache(tuple);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_foreign_data_wrapper related security hooks
+ *
+ * ------------------------------------------------------------ */
+ static bool
+ sepgsql_fdw_common(Oid fdwOid, uint32 required, bool abort)
+ {
+ Form_pg_foreign_data_wrapper fdwForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+ bool rc;
+
+ tuple = SearchSysCache(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(fdwOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for FDW: %u", fdwOid);
+ fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(ForeignDataWrapperRelationId, tuple, &tclass);
+ rc = sepgsqlClientHasPerms(sid, tclass, required,
+ NameStr(fdwForm->fdwname), abort);
+ ReleaseSysCache(tuple);
+
+ return rc;
+ }
+
+ Oid
+ sepgsql_fdw_create(const char *fdwName, Oid fdwValidator)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(ForeignDataWrapperRelationId);
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT,
+ fdwName, true);
+
+ /* db_procedure:{install} */
+ if (OidIsValid(fdwValidator))
+ sepgsql_proc_common(fdwValidator, SEPG_DB_PROCEDURE__INSTALL, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_fdw_alter(Oid fdwOid, Oid newValidator)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__UPDATE, true);
+
+ /* db_procedure:{install} */
+ if (OidIsValid(newValidator))
+ sepgsql_proc_common(newValidator, SEPG_DB_PROCEDURE__INSTALL, true);
+ }
+
+ void
+ sepgsql_fdw_drop(Oid fdwOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__DELETE, true);
+ }
+
+ void
+ sepgsql_fdw_grant(Oid fdwOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__UPDATE, true);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_foreign_server related security hooks
+ *
+ * ------------------------------------------------------------ */
+ static bool
+ sepgsql_foreign_server_common(Oid fsrvOid, uint32 required, bool abort)
+ {
+ Form_pg_foreign_server fsrvForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+ bool rc;
+
+ tuple = SearchSysCache(FOREIGNSERVEROID,
+ ObjectIdGetDatum(fsrvOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for foreign server %u", fsrvOid);
+ fsrvForm = (Form_pg_foreign_server) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(ForeignServerRelationId, tuple, &tclass);
+ rc = sepgsqlClientHasPerms(sid, tclass, required,
+ NameStr(fsrvForm->srvname), abort);
+ ReleaseSysCache(tuple);
+
+ return rc;
+ }
+
+ Oid
+ sepgsql_foreign_server_create(const char *fsrvName)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(ForeignServerRelationId);
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT,
+ fsrvName, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_foreign_server_alter(Oid fsrvOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_foreign_server_common(fsrvOid, SEPG_DB_TUPLE__UPDATE, true);
+ }
+
+ void
+ sepgsql_foreign_server_drop(Oid fsrvOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_foreign_server_common(fsrvOid, SEPG_DB_TUPLE__DELETE, true);
+ }
+
+ void
+ sepgsql_foreign_server_grant(Oid fsrvOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_foreign_server_common(fsrvOid, SEPG_DB_TUPLE__UPDATE, true);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_language related security hooks
+ *
+ * ------------------------------------------------------------ */
+ static bool
+ sepgsql_language_common(Oid langOid, uint32 required, bool abort)
+ {
+ Form_pg_language langForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+ bool rc;
+
+ tuple = SearchSysCache(LANGOID,
+ ObjectIdGetDatum(langOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for language %u", langOid);
+ langForm = (Form_pg_language) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(LanguageRelationId, tuple, &tclass);
+ rc = sepgsqlClientHasPerms(sid, tclass, required,
+ NameStr(langForm->lanname), abort);
+
+ ReleaseSysCache(tuple);
+
+ return rc;
+ }
+
+ Oid
+ sepgsql_language_create(const char *langName, Oid handlerOid, Oid validatorOid)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(LanguageRelationId);
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT, langName, true);
+
+ /* db_procedure:{install} */
+ if (OidIsValid(handlerOid))
+ sepgsql_proc_common(handlerOid, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(validatorOid))
+ sepgsql_proc_common(validatorOid, SEPG_DB_PROCEDURE__INSTALL, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_language_alter(Oid langOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_language_common(langOid, SEPG_DB_TUPLE__UPDATE, true);
+ }
+
+ void
+ sepgsql_language_drop(Oid langOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_language_common(langOid, SEPG_DB_TUPLE__DELETE, true);
+ }
+
+ void
+ sepgsql_language_grant(Oid langOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_language_common(langOid, SEPG_DB_TUPLE__UPDATE, true);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_largeobject related security hooks
+ * (need to backport v8.5 feature)
+ * ------------------------------------------------------------ */
+ Oid
+ sepgsql_largeobject_create(Oid loid, DefElem *newLabel)
+ {
+ return InvalidOid;
+ }
+
+ void
+ sepgsql_largeobject_alter(Oid loid, Oid newOwner)
+ {}
+
+ void
+ sepgsql_largeobject_drop(Oid loid, bool dacSkip)
+ {}
+
+ void
+ sepgsql_largeobject_read(Oid loid)
+ {}
+
+ void
+ sepgsql_largeobject_write(Oid loid)
+ {}
+
+ void
+ sepgsql_largeobject_export(Oid loid, const char *filename)
+ {}
+
+ Oid
+ sepgsql_largeobject_import(Oid loid, const char *filename, DefElem *newLabel)
+ {}
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_opclass related security hooks
+ *
+ * ------------------------------------------------------------ */
+ Oid
+ sepgsql_opclass_create(const char *opcName, Oid nspOid)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(OperatorClassRelationId);
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT,
+ opcName, true);
+
+ /* db_schema:{add_name} */
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_opclass_alter(Oid opcOid, const char *newName)
+ {
+ Form_pg_opclass opcForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(CLAOID,
+ ObjectIdGetDatum(opcOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for opclass %u", opcOid);
+ opcForm = (Form_pg_opclass) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(OperatorClassRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__UPDATE,
+ NameStr(opcForm->opcname), true);
+
+ /* db_schema:{add_name remove_name} */
+ if (newName)
+ {
+ sepgsql_schema_common(opcForm->opcnamespace,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ }
+ ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsql_opclass_drop(Oid opcOid)
+ {
+ Form_pg_opclass opcForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(CLAOID,
+ ObjectIdGetDatum(opcOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for opclass %u", opcOid);
+ opcForm = (Form_pg_opclass) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(OperatorClassRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__UPDATE,
+ NameStr(opcForm->opcname), true);
+
+ /* db_schema:{remove_name} */
+ sepgsql_schema_common(opcForm->opcnamespace,
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+
+ ReleaseSysCache(tuple);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_opfamily related security hooks
+ *
+ * ------------------------------------------------------------ */
+ Oid
+ sepgsql_opfamily_create(const char *opfName, Oid nspOid)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(OperatorFamilyRelationId);
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT,
+ opfName, true);
+
+ /* db_schema:{add_name} */
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_opfamily_alter(Oid opfOid, const char *newName)
+ {
+ Form_pg_opfamily opfForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(OPFAMILYOID,
+ ObjectIdGetDatum(opfOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for operator family: %u", opfOid);
+ opfForm = (Form_pg_opfamily) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(OperatorFamilyRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__UPDATE,
+ NameStr(opfForm->opfname), true);
+ if (newName)
+ {
+ sepgsql_schema_common(opfForm->opfnamespace,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ }
+ ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsql_opfamily_drop(Oid opfOid)
+ {
+ Form_pg_opfamily opfForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(OPFAMILYOID,
+ ObjectIdGetDatum(opfOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for operator family: %u", opfOid);
+ opfForm = (Form_pg_opfamily) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(OperatorFamilyRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__DELETE,
+ NameStr(opfForm->opfname), true);
+
+ /* db_schema:{remove_name} */
+ sepgsql_schema_common(opfForm->opfnamespace,
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+
+ ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsql_opfamily_add_operator(Oid opfOid, Oid operOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /* currently, do nothing here */
+ }
+
+ void
+ sepgsql_opfamily_add_procedure(Oid opfOid, Oid procOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /*
+ * Note that db_tuple:{setattr} is already checked at the
+ * earlier phase, so db_procedure:{install} is only needed.
+ */
+ if (OidIsValid(procOid))
+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__INSTALL, true);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_operator related security hooks
+ *
+ * ------------------------------------------------------------ */
+ static bool
+ sepgsql_operator_common(Oid oprOid, uint32 required, bool abort)
+ {
+ Form_pg_operator oprForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+ bool rc;
+
+ tuple = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(oprOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for operator: %u", oprOid);
+ oprForm = (Form_pg_operator) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(OperatorRelationId, tuple, &tclass);
+ rc = sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__DELETE,
+ NameStr(oprForm->oprname), abort);
+
+ ReleaseSysCache(tuple);
+
+ return rc;
+ }
+
+ Oid
+ sepgsql_operator_create(const char *oprName, Oid oprOid, Oid nspOid,
+ Oid codeFn, Oid restFn, Oid joinFn)
+ {
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint32 required;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ if (!OidIsValid(oprOid))
+ {
+ sid = sepgsqlGetDefaultTupleSecid(OperatorRelationId);
+ required = SEPG_DB_TUPLE__INSERT;
+ }
+ else
+ {
+ tuple = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(oprOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for operator %u", oprOid);
+
+ sid = sepgsqlGetTupleSecid(OperatorRelationId, tuple, NULL);
+
+ ReleaseSysCache(tuple);
+
+ required = SEPG_DB_TUPLE__UPDATE;
+ }
+
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ required, oprName, true);
+
+ /* db_schema:{add_name} checks */
+ if (!OidIsValid(oprOid))
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+
+ /* db_procedure:{install} checks */
+ if (OidIsValid(codeFn))
+ sepgsql_proc_common(codeFn, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(restFn))
+ sepgsql_proc_common(restFn, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(joinFn))
+ sepgsql_proc_common(joinFn, SEPG_DB_PROCEDURE__INSTALL, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_operator_alter(Oid oprOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_operator_common(oprOid, SEPG_DB_TUPLE__UPDATE, true);
+ }
+
+ void
+ sepgsql_operator_drop(Oid oprOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_operator_common(oprOid, SEPG_DB_TUPLE__DELETE, true);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_rewrite related security hooks
+ *
+ * ------------------------------------------------------------ */
+ void
+ sepgsql_rule_create(Oid relOid, const char *ruleName)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true);
+ }
+
+ void
+ sepgsql_rule_drop(Oid relOid, const char *ruleName)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_trigger related security hooks
+ *
+ * ------------------------------------------------------------ */
+ void
+ sepgsql_trigger_create(Oid relOid, const char *trigName, Oid procOid)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /* db_table:{setattr} */
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true);
+
+ /* db_procedure:{install} */
+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__INSTALL, true);
+ }
+
+ void
+ sepgsql_trigger_alter(Oid relOid, const char *trigName)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /* db_table:{setattr} */
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true);
+ }
+
+ void
+ sepgsql_trigger_drop(Oid relOid, const char *trigName)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /* db_table:{setattr} */
+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_type related security hooks
+ *
+ * ------------------------------------------------------------ */
+ Oid
+ sepgsql_ts_config_create(const char *cfgName, Oid nspOid)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(TSConfigRelationId);
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT,
+ cfgName, true);
+
+ /* db_schema:{add_name} */
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_ts_config_alter(Oid cfgOid, const char *newName)
+ {
+ Form_pg_ts_config cfgForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(TSCONFIGOID,
+ ObjectIdGetDatum(cfgOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for text search dictionary %u", cfgOid);
+ cfgForm = (Form_pg_ts_config) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(TSConfigRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__UPDATE,
+ NameStr(cfgForm->cfgname), true);
+ if (newName)
+ {
+ sepgsql_schema_common(cfgForm->cfgnamespace,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ }
+ ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsql_ts_config_drop(Oid cfgOid)
+ {
+ Form_pg_ts_config cfgForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(TSCONFIGOID,
+ ObjectIdGetDatum(cfgOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for text search dictionary %u", cfgOid);
+ cfgForm = (Form_pg_ts_config) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(TSConfigRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__DELETE,
+ NameStr(cfgForm->cfgname), true);
+
+ /* db_schema:{remove_name} */
+ sepgsql_schema_common(cfgForm->cfgnamespace,
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+
+ ReleaseSysCache(tuple);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_type related security hooks
+ *
+ * ------------------------------------------------------------ */
+ Oid
+ sepgsql_ts_dict_create(const char *dictName, Oid nspOid)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(TSDictionaryRelationId);
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT,
+ dictName, true);
+
+ /* db_schema:{add_name} */
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_ts_dict_alter(Oid dictOid, const char *newName)
+ {
+ Form_pg_ts_dict dictForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(TSDICTOID,
+ ObjectIdGetDatum(dictOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for text search dictionary %u", dictOid);
+ dictForm = (Form_pg_ts_dict) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(TSDictionaryRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__UPDATE,
+ NameStr(dictForm->dictname), true);
+
+ /* db_schema:{add_name remove_name} */
+ if (newName)
+ {
+ sepgsql_schema_common(dictForm->dictnamespace,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ }
+ ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsql_ts_dict_drop(Oid dictOid)
+ {
+ Form_pg_ts_dict dictForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(TSDICTOID,
+ ObjectIdGetDatum(dictOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for text search dictionary %u", dictOid);
+ dictForm = (Form_pg_ts_dict) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(TSDictionaryRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__DELETE,
+ NameStr(dictForm->dictname), true);
+
+ /* db_schema:{remove_name} */
+ sepgsql_schema_common(dictForm->dictnamespace,
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+
+ ReleaseSysCache(tuple);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_type related security hooks
+ *
+ * ------------------------------------------------------------ */
+ Oid
+ sepgsql_ts_parser_create(const char *prsName, Oid nspOid,
+ Oid startFn, Oid tokenFn, Oid sendFn,
+ Oid headlineFn, Oid lextypeFn)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(TSParserRelationId);
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT,
+ prsName, true);
+
+ /* db_schema:{add_name} */
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+
+ /* db_procedure:{install} */
+ if (OidIsValid(startFn))
+ sepgsql_proc_common(startFn, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(tokenFn))
+ sepgsql_proc_common(tokenFn, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(sendFn))
+ sepgsql_proc_common(sendFn, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(headlineFn))
+ sepgsql_proc_common(headlineFn, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(lextypeFn))
+ sepgsql_proc_common(lextypeFn, SEPG_DB_PROCEDURE__INSTALL, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_ts_parser_alter(Oid prsOid, const char *newName)
+ {
+ Form_pg_ts_parser prsForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(TSPARSEROID,
+ ObjectIdGetDatum(prsOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for text search parser %u", prsOid);
+
+ prsForm = (Form_pg_ts_parser) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(TSParserRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__UPDATE,
+ NameStr(prsForm->prsname), true);
+ if (newName)
+ {
+ sepgsql_schema_common(prsForm->prsnamespace,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ }
+ ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsql_ts_parser_drop(Oid prsOid)
+ {
+ Form_pg_ts_parser prsForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(TSPARSEROID,
+ ObjectIdGetDatum(prsOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for text search parser %u", prsOid);
+
+ prsForm = (Form_pg_ts_parser) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(TSParserRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__DELETE,
+ NameStr(prsForm->prsname), true);
+
+ /* db_schema:{remove_name} */
+ sepgsql_schema_common(prsForm->prsnamespace,
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+
+ ReleaseSysCache(tuple);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_type related security hooks
+ *
+ * ------------------------------------------------------------ */
+ Oid
+ sepgsql_ts_template_create(const char *tmplName, Oid nspOid,
+ Oid initFn, Oid lexizeFn)
+ {
+ sepgsql_sid_t sid;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ sid = sepgsqlGetDefaultTupleSecid(TSTemplateRelationId);
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ SEPG_DB_TUPLE__INSERT,
+ tmplName, true);
+
+ /* db_schema:{add_name} */
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+
+ /* db_procedure:{install} */
+ if (OidIsValid(initFn))
+ sepgsql_proc_common(initFn, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(lexizeFn))
+ sepgsql_proc_common(lexizeFn, SEPG_DB_PROCEDURE__INSTALL, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_ts_template_alter(Oid tmplOid, const char *newName)
+ {
+ Form_pg_ts_template tmplForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(TSTEMPLATEOID,
+ ObjectIdGetDatum(tmplOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for text search template %u", tmplOid);
+ tmplForm = (Form_pg_ts_template) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(TSTemplateRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__UPDATE,
+ NameStr(tmplForm->tmplname), true);
+ if (newName)
+ {
+ sepgsql_schema_common(tmplForm->tmplnamespace,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ }
+ ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsql_ts_template_drop(Oid tmplOid)
+ {
+ Form_pg_ts_template tmplForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(TSTEMPLATEOID,
+ ObjectIdGetDatum(tmplOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for text search template %u", tmplOid);
+ tmplForm = (Form_pg_ts_template) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(TSTemplateRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__DELETE,
+ NameStr(tmplForm->tmplname), true);
+
+ /* db_schema:{remove_name} */
+ sepgsql_schema_common(tmplForm->tmplnamespace,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+
+ ReleaseSysCache(tuple);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Pg_type related security hooks
+ *
+ * ------------------------------------------------------------ */
+ Oid
+ sepgsql_type_create(const char *typName, HeapTuple oldTup, Oid nspOid,
+ Oid inputProc, Oid outputProc, Oid recvProc, Oid sendProc,
+ Oid modinProc, Oid modoutProc, Oid analyzeProc)
+ {
+ sepgsql_sid_t sid;
+ uint32 required;
+
+ if (!sepgsqlIsEnabled())
+ return InvalidOid;
+
+ if (!HeapTupleIsValid(oldTup))
+ {
+ sid = sepgsqlGetDefaultTupleSecid(TypeRelationId);
+ required = SEPG_DB_TUPLE__INSERT;
+ }
+ else
+ {
+ sid = sepgsqlGetTupleSecid(TypeRelationId, oldTup, NULL);
+ required = SEPG_DB_TUPLE__UPDATE;
+ }
+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE,
+ required, typName, true);
+ /* db_schema:{add_name} */
+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true);
+
+ /* db_procedure:{install} */
+ if (OidIsValid(inputProc))
+ sepgsql_proc_common(inputProc, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(outputProc))
+ sepgsql_proc_common(outputProc, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(recvProc))
+ sepgsql_proc_common(recvProc, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(sendProc))
+ sepgsql_proc_common(sendProc, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(modinProc))
+ sepgsql_proc_common(modinProc, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(modoutProc))
+ sepgsql_proc_common(modoutProc, SEPG_DB_PROCEDURE__INSTALL, true);
+ if (OidIsValid(analyzeProc))
+ sepgsql_proc_common(analyzeProc, SEPG_DB_PROCEDURE__INSTALL, true);
+
+ return sid.secid;
+ }
+
+ void
+ sepgsql_type_alter(Oid typOid, const char *newName, Oid newNsp)
+ {
+ Form_pg_type typForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for type: %u", typOid);
+ typForm = (Form_pg_type) GETSTRUCT(tuple);
+
+ sid = sepgsqlGetTupleSecid(TypeRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__UPDATE,
+ NameStr(typForm->typname), true);
+
+ if (newName || OidIsValid(newNsp))
+ {
+ Oid oldNsp = typForm->typnamespace;
+
+ if (!OidIsValid(newNsp))
+ {
+ sepgsql_schema_common(oldNsp,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ }
+ else
+ {
+ sepgsql_schema_common(oldNsp, SEPG_DB_SCHEMA__REMOVE_NAME, true);
+ sepgsql_schema_common(newNsp, SEPG_DB_SCHEMA__ADD_NAME, true);
+ }
+ }
+ ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsql_type_drop(Oid typOid)
+ {
+ Form_pg_type typForm;
+ HeapTuple tuple;
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ tuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for type: %u", typOid);
+ typForm = (Form_pg_type) GETSTRUCT(tuple);
+
+ if (typForm->typtype == TYPTYPE_COMPOSITE ||
+ (typForm->typtype == TYPTYPE_BASE && OidIsValid(typForm->typarray)))
+ {
+ /*
+ * No need to check for composite type and implicitly
+ * declared array type here.
+ */
+ ReleaseSysCache(tuple);
+ return;
+ }
+
+ sid = sepgsqlGetTupleSecid(TypeRelationId, tuple, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__DELETE,
+ NameStr(typForm->typname), true);
+
+ /* db_schema:{remove_name} */
+ sepgsql_schema_common(typForm->typnamespace,
+ SEPG_DB_SCHEMA__REMOVE_NAME, true);
+
+ ReleaseSysCache(tuple);
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Misc system object related security hooks
+ *
+ * ------------------------------------------------------------ */
+
+ void
+ sepgsql_sysobj_drop(const ObjectAddress *object)
+ {
+ switch (object->classId)
+ {
+ case RelationRelationId:
+ if (object->objectSubId == 0)
+ sepgsql_relation_drop(object->objectId);
+ else
+ sepgsql_attribute_drop(object->objectId,
+ object->objectSubId);
+ break;
+
+ case ProcedureRelationId:
+ sepgsql_proc_drop(object->objectId);
+ break;
+
+ case TypeRelationId:
+ sepgsql_type_drop(object->objectId);
+ break;
+
+ case CastRelationId:
+ sepgsql_cast_drop(object->objectId);
+ break;
+
+ case ConversionRelationId:
+ sepgsql_conversion_drop(object->objectId);
+ break;
+
+ case LanguageRelationId:
+ sepgsql_language_drop(object->objectId);
+ break;
+
+ case OperatorRelationId:
+ sepgsql_operator_drop(object->objectId);
+ break;
+
+ case OperatorClassRelationId:
+ sepgsql_opclass_drop(object->objectId);
+ break;
+
+ case OperatorFamilyRelationId:
+ sepgsql_opfamily_drop(object->objectId);
+ break;
+
+ case NamespaceRelationId:
+ sepgsql_schema_drop(object->objectId);
+ break;
+
+ case TSParserRelationId:
+ sepgsql_ts_parser_drop(object->objectId);
+ break;
+
+ case TSDictionaryRelationId:
+ sepgsql_ts_dict_drop(object->objectId);
+ break;
+
+ case TSTemplateRelationId:
+ sepgsql_ts_template_drop(object->objectId);
+ break;
+
+ case TSConfigRelationId:
+ sepgsql_ts_config_drop(object->objectId);
+ break;
+
+ case AuthIdRelationId:
+ break;
+
+ case DatabaseRelationId:
+ sepgsql_database_drop(object->objectId);
+ break;
+
+ case TableSpaceRelationId:
+ break;
+
+ case ForeignDataWrapperRelationId:
+ sepgsql_fdw_drop(object->objectId);
+ break;
+
+ case ForeignServerRelationId:
+ sepgsql_foreign_server_drop(object->objectId);
+ break;
+
+ case UserMappingRelationId:
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+ }
+
+ /* ------------------------------------------------------------ *
+ *
+ * Filesystem object related security hooks
+ *
+ * ------------------------------------------------------------ */
+ static char *
+ sepgsql_getfilecon(const char *path)
+ {
+ security_context_t context;
+ char *result;
+
+ if (getfilecon_raw(path, &context) < 0)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not get context of \"%s\": %m", path)));
+
+ PG_TRY();
+ {
+ result = pstrdup(context);
+ }
+ PG_CATCH();
+ {
+ freecon(context);
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
+ freecon(context);
+
+ return result;
+ }
+
+ static void
+ sepgsql_file_common(const char *filename, uint32 required, bool may_create)
+ {
+ struct stat stbuf;
+
+ if (stat(filename, &stbuf) == 0)
+ {
+ uint16 tclass;
+
+ /*
+ * Get file object class
+ */
+ if (S_ISDIR(stbuf.st_mode))
+ tclass = SEPG_CLASS_DIR;
+ else if (S_ISCHR(stbuf.st_mode))
+ tclass = SEPG_CLASS_CHR_FILE;
+ else if (S_ISBLK(stbuf.st_mode))
+ tclass = SEPG_CLASS_BLK_FILE;
+ else if (S_ISFIFO(stbuf.st_mode))
+ tclass = SEPG_CLASS_FIFO_FILE;
+ else if (S_ISLNK(stbuf.st_mode))
+ tclass = SEPG_CLASS_LNK_FILE;
+ else if (S_ISSOCK(stbuf.st_mode))
+ tclass = SEPG_CLASS_SOCK_FILE;
+ else
+ tclass = SEPG_CLASS_FILE;
+
+ /*
+ * Check permission (no cached operation)
+ */
+ sepgsqlComputePerms(sepgsqlGetClientLabel(),
+ sepgsql_getfilecon(filename),
+ tclass, required,
+ filename, true);
+ }
+ else if (may_create)
+ {
+ /*
+ * If the required file is not found, we check permission to
+ * create a new file and required permission on the new file.
+ */
+ security_context_t dcontext;
+ security_context_t ncontext;
+ char *copy = pstrdup(filename);
+
+ /*
+ * Compute a security context for the new file
+ */
+ dcontext = sepgsql_getfilecon(dirname(copy));
+
+ ncontext = sepgsqlComputeCreate(sepgsqlGetServerLabel(),
+ dcontext,
+ SEPG_CLASS_FILE);
+ /*
+ * Check permission (no cached operation)
+ */
+ required |= SEPG_FILE__CREATE;
+
+ sepgsqlComputePerms(sepgsqlGetClientLabel(),
+ sepgsql_getfilecon(filename),
+ SEPG_CLASS_FILE,
+ required, filename, true);
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not stat file \"%s\": %m", filename)));
+ }
+ }
+
+ void
+ sepgsql_file_stat(const char *filename)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_file_common(filename, SEPG_FILE__GETATTR, false);
+ }
+
+ void
+ sepgsql_file_read(const char *filename)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_file_common(filename, SEPG_FILE__READ, false);
+ }
+
+ void
+ sepgsql_file_write(const char *filename)
+ {
+ if (!sepgsqlIsEnabled())
+ return;
+
+ sepgsql_file_common(filename, SEPG_FILE__WRITE, true);
+ }
+
+ /*
+ * TODO: add check for pg_ls_dir()
+ */
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 Oct 8 09:29:32 2009
***************
*** 0 ****
--- 1,424 ----
+ /*
+ * 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 "catalog/pg_security.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;
+ Form_pg_class relForm;
+ HeapTuple reltup;
+ sepgsql_sid_t relsid;
+ sepgsql_sid_t attsid;
+ AttrNumber attno;
+ uint16 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
+ */
+ reltup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(reltup))
+ elog(ERROR, "SELinux: cache lookup failed for relation %u", relid);
+
+ relForm = (Form_pg_class) GETSTRUCT(reltup);
+
+ relsid = sepgsqlGetTupleSecid(RelationRelationId, reltup, &tclass);
+
+ if (tclass != SEPG_CLASS_DB_TABLE)
+ {
+ /* check db_sequence:{xxx} permission */
+ if (tclass == SEPG_CLASS_DB_SEQUENCE)
+ {
+ if (required & SEPG_DB_TABLE__SELECT)
+ {
+ sepgsqlClientHasPerms(relsid, tclass,
+ SEPG_DB_SEQUENCE__GET_VALUE,
+ NameStr(relForm->relname), true);
+ }
+ }
+ ReleaseSysCache(reltup);
+ return;
+ }
+ sepgsqlClientHasPerms(relsid, tclass, required,
+ NameStr(relForm->relname), true);
+
+ /*
+ * Check db_column:{...} permissions
+ */
+ selected_ex = fixupWholeRowReference(relid, relForm->relnatts, selected);
+ modified_ex = fixupWholeRowReference(relid, relForm->relnatts, modified);
+ columns = bms_union(selected_ex, modified_ex);
+
+ while ((attno = bms_first_member(columns)) >= 0)
+ {
+ Form_pg_attribute attForm;
+ HeapTuple atttup;
+ uint32 attperms = 0;
+ char auname[2 * NAMEDATALEN + 3];
+
+ 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;
+ atttup = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attno),
+ 0, 0);
+ if (!HeapTupleIsValid(atttup))
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+ attno, relid);
+
+ attForm = (Form_pg_attribute) GETSTRUCT(atttup);
+ if (attForm->attisdropped)
+ elog(ERROR, "attribute %d of relation %u does not exist",
+ attno, relid);
+
+ snprintf(auname, sizeof(auname), "%s.%s",
+ NameStr(relForm->relname),
+ NameStr(attForm->attname));
+ attsid = sepgsqlGetTupleSecid(AttributeRelationId,
+ atttup, &tclass);
+ sepgsqlClientHasPerms(attsid, tclass, attperms, auname, true);
+
+ ReleaseSysCache(atttup);
+ }
+
+ ReleaseSysCache(reltup);
+
+ 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);
+ }
+
+ /*
+ * sepgsqlExecScan
+ * makes a decision on the given tuple.
+ */
+ bool
+ sepgsqlExecScan(Relation rel, HeapTuple tuple, uint32 required, bool abort)
+ {
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled() ||
+ !required ||
+ RelationGetForm(rel)->relkind != RELKIND_RELATION ||
+ RelationGetRelid(rel) == SecurityRelationId)
+ return true;
+
+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel), tuple, &tclass);
+ /*
+ * Insert/Delete to an external attribute is equivalent to
+ * the set-attribute on the master
+ */
+ if (sid.relid != RelationGetRelid(rel) &&
+ (required & (SEPG_DB_TUPLE__INSERT | SEPG_DB_TUPLE__DELETE)))
+ {
+ required &= ~(SEPG_DB_TUPLE__INSERT | SEPG_DB_TUPLE__DELETE);
+ required |= SEPG_DB_TUPLE__UPDATE;
+ }
+
+ return sepgsqlClientHasPerms(sid, tclass, required, NULL, 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)
+ {
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /*
+ * assigns a default security label, if not explicit one
+ */
+ if (!OidIsValid(HeapTupleGetSecid(newtup)))
+ {
+ if (HeapTupleHasSecid(newtup))
+ sepgsqlSetDefaultSecid(rel, newtup);
+ }
+
+ /*
+ * It does not check permission for the new tuples
+ * inserted by system internal stuff using
+ * simple_heap_insert();
+ */
+ if (internal)
+ return;
+
+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel),
+ newtup, &tclass);
+ sepgsqlClientHasPerms(sid, tclass, SEPG_DB_TUPLE__INSERT, NULL, 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 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 = HeapTupleGetSecid(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 != HeapTupleGetSecid(&oldtup))
+ {
+ sepgsql_sid_t sid;
+ uint16 tclass;
+
+ /* db_tuple:{relabelfrom} for older security context */
+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel),
+ &oldtup, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__RELABELFROM,
+ NULL, true);
+
+ /* db_tuple:{relabelto} for newer security label */
+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel),
+ newtup, &tclass);
+ sepgsqlClientHasPerms(sid, tclass,
+ SEPG_DB_TUPLE__RELABELTO,
+ NULL, 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 Mon Sep 28 10:07:19 2009
***************
*** 0 ****
--- 1,239 ----
+ /*
+ * 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_blob object class
+ * ------------------------------------------------------------ */
+
+ /*
+ * sepgsqlCheckBlobCreate
+ * assigns a default security label and checks db_blob:{create}
+ */
+ void
+ sepgsqlCheckBlobCreate(Relation rel, HeapTuple lotup)
+ {
+ sepgsql_sid_t loSid;
+ Oid relid = RelationGetRelid(rel);
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /* set a default security context */
+ sepgsqlSetDefaultSecid(rel, lotup);
+
+ loSid = sepgsqlGetTupleSecid(relid, lotup, NULL);
+ sepgsqlClientHasPerms(loSid,
+ SEPG_CLASS_DB_BLOB,
+ SEPG_DB_BLOB__CREATE,
+ NULL, true);
+ }
+
+ /*
+ * sepgsqlCheckBlobDrop
+ * checks db_blob:{drop} permission
+ */
+ void
+ sepgsqlCheckBlobDrop(Relation rel, HeapTuple lotup)
+ {
+ sepgsql_sid_t loSid;
+ Oid relid = RelationGetRelid(rel);
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ loSid = sepgsqlGetTupleSecid(relid, lotup, NULL);
+ sepgsqlClientHasPerms(loSid,
+ SEPG_CLASS_DB_BLOB,
+ SEPG_DB_BLOB__DROP,
+ NULL, true);
+ }
+
+ /*
+ * sepgsqlCheckBlobRead
+ * checks db_blob:{read} permission
+ */
+ void
+ sepgsqlCheckBlobRead(LargeObjectDesc *lobj)
+ {
+ sepgsql_sid_t loSid;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ loSid.relid = LargeObjectRelationId;
+ loSid.secid = lobj->secid;
+ sepgsqlClientHasPerms(loSid,
+ SEPG_CLASS_DB_BLOB,
+ SEPG_DB_BLOB__READ,
+ NULL, true);
+ }
+
+ /*
+ * sepgsqlCheckBlobWrite
+ * check db_blob:{write} permission
+ */
+ void
+ sepgsqlCheckBlobWrite(LargeObjectDesc *lobj)
+ {
+ sepgsql_sid_t loSid;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ loSid.relid = LargeObjectRelationId;
+ loSid.secid = lobj->secid;
+ sepgsqlClientHasPerms(loSid,
+ SEPG_CLASS_DB_BLOB,
+ SEPG_DB_BLOB__WRITE,
+ NULL, true);
+ }
+
+ /*
+ * sepgsqlCheckBlobGetattr
+ * check db_blob:{getattr} permission
+ */
+ void
+ sepgsqlCheckBlobGetattr(HeapTuple tuple)
+ {
+ sepgsql_sid_t loSid;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ loSid.relid = LargeObjectRelationId;
+ loSid.secid = HeapTupleGetSecid(tuple);
+ sepgsqlClientHasPerms(loSid,
+ SEPG_CLASS_DB_BLOB,
+ SEPG_DB_BLOB__GETATTR,
+ NULL, true);
+ }
+
+ /*
+ * sepgsqlCheckBlobSetattr
+ * check db_blob:{setattr} permission
+ */
+ void
+ sepgsqlCheckBlobSetattr(HeapTuple tuple)
+ {
+ sepgsql_sid_t loSid;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ loSid.relid = LargeObjectRelationId;
+ loSid.secid = HeapTupleGetSecid(tuple);
+ sepgsqlClientHasPerms(loSid,
+ SEPG_CLASS_DB_BLOB,
+ SEPG_DB_BLOB__SETATTR,
+ NULL, true);
+ }
+
+ /*
+ * sepgsqlCheckBlobExport
+ * check db_blob:{read export} and file:{write} permission
+ */
+ void
+ sepgsqlCheckBlobExport(LargeObjectDesc *lobj, const char *filename)
+ {
+ sepgsql_sid_t loSid;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /* db_blob:{read export} */
+ loSid.relid = LargeObjectRelationId;
+ loSid.secid = lobj->secid;
+ sepgsqlClientHasPerms(loSid,
+ SEPG_CLASS_DB_BLOB,
+ SEPG_DB_BLOB__READ | SEPG_DB_BLOB__EXPORT,
+ NULL, true);
+ /* file:{write} */
+ sepgsql_file_write(filename);
+ }
+
+ /*
+ * sepgsqlCheckBlobImport
+ * check db_blob:{write import} and file:{read} permission
+ */
+ void
+ sepgsqlCheckBlobImport(LargeObjectDesc *lobj, const char *filename)
+ {
+ sepgsql_sid_t loSid;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ /* db_blob:{write import} */
+ loSid.relid = LargeObjectRelationId;
+ loSid.secid = lobj->secid;
+ sepgsqlClientHasPerms(loSid,
+ SEPG_CLASS_DB_BLOB,
+ SEPG_DB_BLOB__WRITE | SEPG_DB_BLOB__IMPORT,
+ NULL, true);
+ /* file:{read} */
+ sepgsql_file_read(filename);
+ }
+
+ /*
+ * sepgsqlCheckBlobRelabel
+ * check db_blob:{setattr relabelfrom relabelto}
+ */
+ void
+ sepgsqlCheckBlobRelabel(HeapTuple oldtup, HeapTuple newtup)
+ {
+ sepgsql_sid_t loSid;
+ access_vector_t required = SEPG_DB_BLOB__SETATTR;
+
+ if (HeapTupleGetSecid(oldtup) != HeapTupleGetSecid(newtup))
+ required |= SEPG_DB_BLOB__RELABELFROM;
+
+ /* db_blob:{setattr relabelfrom} */
+ loSid = sepgsqlGetTupleSecid(LargeObjectRelationId, oldtup, NULL);
+ sepgsqlClientHasPerms(loSid,
+ SEPG_CLASS_DB_BLOB,
+ required,
+ NULL, true);
+
+ if ((required & SEPG_DB_BLOB__RELABELFROM) == 0)
+ return;
+
+ /* db_blob:{relabelto} */
+ loSid = sepgsqlGetTupleSecid(LargeObjectRelationId, newtup, NULL);
+ sepgsqlClientHasPerms(loSid,
+ SEPG_CLASS_DB_BLOB,
+ SEPG_DB_BLOB__RELABELTO,
+ NULL, true);
+ }
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 Fri Sep 25 17:27:05 2009
***************
*** 0 ****
--- 1,1140 ----
+ /*
+ * 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/pg_constraint.h"
+ #include "catalog/heap.h"
+ #include "catalog/indexing.h"
+ #include "catalog/namespace.h"
+ #include "catalog/pg_aggregate.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_attrdef.h"
+ #include "catalog/pg_attribute.h"
+ #include "catalog/pg_auth_members.h"
+ #include "catalog/pg_authid.h"
+ #include "catalog/pg_cast.h"
+ #include "catalog/pg_class.h"
+ #include "catalog/pg_conversion.h"
+ #include "catalog/pg_database.h"
+ #include "catalog/pg_description.h"
+ #include "catalog/pg_enum.h"
+ #include "catalog/pg_foreign_data_wrapper.h"
+ #include "catalog/pg_foreign_server.h"
+ #include "catalog/pg_inherits.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_rewrite.h"
+ #include "catalog/pg_security.h"
+ #include "catalog/pg_shdescription.h"
+ #include "catalog/pg_statistic.h"
+ #include "catalog/pg_tablespace.h"
+ #include "catalog/pg_trigger.h"
+ #include "catalog/pg_ts_config.h"
+ #include "catalog/pg_ts_config_map.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_user_mapping.h"
+ #include "miscadmin.h"
+ #include "nodes/makefuncs.h"
+ #include "security/sepgsql.h"
+ #include "storage/fd.h"
+ #include "utils/fmgroids.h"
+ #include "utils/lsyscache.h"
+ #include "utils/syscache.h"
+ #include "utils/tqual.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;
+
+ /*
+ * sepgsqlTupleDescHasSecid
+ *
+ * returns a hint whether we should allocate a field to store
+ * security label on the given relation, or not.
+ */
+ bool
+ sepgsqlTupleDescHasSecid(Oid relid, char relkind)
+ {
+ if (!sepgsqlIsEnabled())
+ return false;
+
+ if (!OidIsValid(relid))
+ return sepostgresql_row_level; /* Target of SELECT INTO */
+
+ /* These system catalogs always have its secid */
+ if (relid == DatabaseRelationId ||
+ relid == NamespaceRelationId ||
+ relid == RelationRelationId ||
+ relid == AttributeRelationId ||
+ relid == ProcedureRelationId)
+ return true;
+
+ /* These system catalogs are an external attributes */
+ if (relid == AggregateRelationId ||
+ relid == AccessMethodOperatorRelationId ||
+ relid == AccessMethodProcedureRelationId ||
+ relid == AttrDefaultRelationId ||
+ relid == AuthMemRelationId ||
+ relid == ConstraintRelationId ||
+ relid == DescriptionRelationId ||
+ relid == EnumRelationId ||
+ relid == IndexRelationId ||
+ relid == InheritsRelationId ||
+ relid == RewriteRelationId ||
+ relid == SecurityRelationId ||
+ relid == SharedDescriptionRelationId ||
+ relid == StatisticRelationId ||
+ relid == TriggerRelationId)
+ return false;
+
+ return sepostgresql_row_level;
+ }
+
+ /*
+ * sepgsqlGetDefaultDatabaseSecid
+ * It returns the default security label of a database object.
+ */
+ sepgsql_sid_t
+ sepgsqlGetDefaultDatabaseSecid(void)
+ {
+ security_context_t seclabel;
+ sepgsql_sid_t sid;
+ 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);
+
+ sid.relid = DatabaseRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid, seclabel);
+
+ return sid;
+ }
+ FreeFile(filp);
+
+ fallback:
+ seclabel = sepgsqlComputeCreate(sepgsqlGetClientLabel(),
+ sepgsqlGetClientLabel(),
+ SEPG_CLASS_DB_DATABASE);
+ sid.relid = DatabaseRelationId;
+ sid.secid = securityTransSecLabelIn(sid.relid, seclabel);
+
+ return sid;
+ }
+
+ static sepgsql_sid_t
+ defaultSecidWithDatabase(Oid relid, Oid datoid, uint16 tclass)
+ {
+ HeapTuple tuple;
+ sepgsql_sid_t datsid;
+
+ if (IsBootstrapProcessingMode())
+ {
+ static sepgsql_sid_t cached = { InvalidOid, InvalidOid };
+
+ if (!SidIsValid(cached))
+ cached = sepgsqlGetDefaultDatabaseSecid();
+ datsid = cached;
+ }
+ else
+ {
+ tuple = SearchSysCache(DATABASEOID,
+ ObjectIdGetDatum(datoid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for database: %u", datoid);
+ datsid.relid = DatabaseRelationId;
+ datsid.secid = HeapTupleGetSecid(tuple);
+ ReleaseSysCache(tuple);
+ }
+
+ return sepgsqlClientCreateSecid(datsid, tclass, relid);
+ }
+
+ sepgsql_sid_t
+ sepgsqlGetDefaultSchemaSecid(Oid database_oid)
+ {
+ return defaultSecidWithDatabase(NamespaceRelationId,
+ database_oid,
+ SEPG_CLASS_DB_SCHEMA);
+ }
+
+ static sepgsql_sid_t
+ defaultSecidWithSchema(Oid relid, Oid nspoid, uint16 tclass)
+ {
+ HeapTuple tuple;
+ sepgsql_sid_t nspsid;
+
+ if (IsBootstrapProcessingMode())
+ {
+ static sepgsql_sid_t cached = { InvalidOid, InvalidOid };
+
+ if (!SidIsValid(cached))
+ cached = sepgsqlGetDefaultSchemaSecid(MyDatabaseId);
+
+ nspsid = sepgsqlGetDefaultSchemaSecid(MyDatabaseId);
+ }
+ else
+ {
+ tuple = SearchSysCache(NAMESPACEOID,
+ ObjectIdGetDatum(nspoid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for namespace: %u", nspoid);
+ nspsid.relid = NamespaceRelationId;
+ nspsid.secid = HeapTupleGetSecid(tuple);
+ ReleaseSysCache(tuple);
+ }
+
+ return sepgsqlClientCreateSecid(nspsid, tclass, relid);
+ }
+
+ sepgsql_sid_t
+ sepgsqlGetDefaultTableSecid(Oid namespace_oid)
+ {
+ return defaultSecidWithSchema(RelationRelationId,
+ namespace_oid,
+ SEPG_CLASS_DB_TABLE);
+ }
+
+ sepgsql_sid_t
+ sepgsqlGetDefaultSequenceSecid(Oid namespace_oid)
+ {
+ return defaultSecidWithSchema(RelationRelationId,
+ namespace_oid,
+ SEPG_CLASS_DB_SEQUENCE);
+ }
+
+ sepgsql_sid_t
+ sepgsqlGetDefaultProcedureSecid(Oid namespace_oid)
+ {
+ return defaultSecidWithSchema(ProcedureRelationId,
+ namespace_oid,
+ SEPG_CLASS_DB_PROCEDURE);
+ }
+
+ static sepgsql_sid_t
+ defaultSecidWithTable(Oid relid, Oid tbloid, security_class_t tclass)
+ {
+ HeapTuple tuple;
+ sepgsql_sid_t relsid;
+
+ if (IsBootstrapProcessingMode()
+ && (tbloid == TypeRelationId ||
+ tbloid == ProcedureRelationId ||
+ tbloid == AttributeRelationId ||
+ tbloid == RelationRelationId))
+ {
+ static sepgsql_sid_t cached = { InvalidOid, InvalidOid };
+
+ if (!SidIsValid(cached))
+ cached = sepgsqlGetDefaultTableSecid(PG_CATALOG_NAMESPACE);
+
+ relsid = cached;
+ }
+ else
+ {
+ tuple = SearchSysCache(RELOID,
+ ObjectIdGetDatum(tbloid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation: %u", tbloid);
+ relsid.relid = RelationRelationId;
+ relsid.secid = HeapTupleGetSecid(tuple);
+ ReleaseSysCache(tuple);
+ }
+
+ return sepgsqlClientCreateSecid(relsid, tclass, relid);
+ }
+
+ sepgsql_sid_t
+ sepgsqlGetDefaultColumnSecid(Oid table_oid)
+ {
+ return defaultSecidWithTable(AttributeRelationId,
+ table_oid,
+ SEPG_CLASS_DB_COLUMN);
+ }
+
+ sepgsql_sid_t
+ sepgsqlGetDefaultTupleSecid(Oid table_oid)
+ {
+ return defaultSecidWithTable(table_oid,
+ table_oid,
+ SEPG_CLASS_DB_TUPLE);
+ }
+
+ sepgsql_sid_t
+ sepgsqlGetDefaultBlobSecid(Oid database_oid)
+ {
+ return defaultSecidWithDatabase(LargeObjectRelationId,
+ MyDatabaseId,
+ SEPG_CLASS_DB_BLOB);
+ }
+
+ void
+ sepgsqlSetDefaultSecid(Relation rel, HeapTuple tuple)
+ {
+ sepgsql_sid_t newSid;
+ Oid relOid = RelationGetRelid(rel);
+ Oid nspOid, tblOid;
+ char relkind;
+
+ if (!sepgsqlIsEnabled())
+ return;
+
+ if (!HeapTupleHasSecid(tuple))
+ return;
+
+ /* initialize */
+ newSid.relid = relOid;
+ newSid.secid = InvalidOid;
+
+ switch (relOid)
+ {
+ case DatabaseRelationId:
+ newSid = sepgsqlGetDefaultDatabaseSecid();
+ break;
+
+ case NamespaceRelationId:
+ newSid = sepgsqlGetDefaultSchemaSecid(MyDatabaseId);
+ break;
+
+ case RelationRelationId:
+ nspOid = ((Form_pg_class) GETSTRUCT(tuple))->relnamespace;
+ relkind = ((Form_pg_class) GETSTRUCT(tuple))->relkind;
+
+ switch (relkind)
+ {
+ case RELKIND_RELATION:
+ newSid = sepgsqlGetDefaultTableSecid(nspOid);
+ break;
+
+ case RELKIND_SEQUENCE:
+ newSid = sepgsqlGetDefaultSequenceSecid(nspOid);
+ break;
+
+ default:
+ newSid = sepgsqlGetDefaultTupleSecid(relOid);
+ break;
+ }
+ break;
+
+ case ProcedureRelationId:
+ nspOid = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace;
+ newSid = sepgsqlGetDefaultProcedureSecid(nspOid);
+ break;
+
+ case AttributeRelationId:
+ tblOid = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid;
+
+ /*
+ * We cannot refer system cache in the very early initdb
+ * phase, because pg_class is not constructed yet.
+ */
+ if ((IsBootstrapProcessingMode() &&
+ (tblOid == TypeRelationId ||
+ tblOid == ProcedureRelationId ||
+ tblOid == AttributeRelationId ||
+ tblOid == RelationRelationId))
+ || get_rel_relkind(tblOid) == RELKIND_RELATION)
+ {
+ newSid = sepgsqlGetDefaultColumnSecid(tblOid);
+ }
+ /* otherwise, it does not have individual security context */
+ break;
+
+ case LargeObjectRelationId:
+ newSid = sepgsqlGetDefaultBlobSecid(MyDatabaseId);
+ break;
+
+ default:
+ newSid = sepgsqlGetDefaultTupleSecid(relOid);
+ break;
+ }
+
+ HeapTupleSetSecid(tuple, newSid.secid);
+ }
+
+ /*
+ * sepgsqlGetSysobjSecid
+ *
+ * It returns a pair of relid/secid for the given OID.
+ */
+ static sepgsql_sid_t
+ getSysobjSecidDirect(Oid classOid, Oid indexOid, Oid objectId, uint16 *tclass)
+ {
+ sepgsql_sid_t sid;
+ Relation rel;
+ HeapTuple tup;
+ ScanKeyData skey;
+ SysScanDesc scan;
+
+ rel = heap_open(CastRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(objectId));
+
+ scan = systable_beginscan(rel, CastOidIndexId, true,
+ SnapshotNow, 1, &skey);
+ tup = systable_getnext(scan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "system object lookup failed for oid %u on relation %u",
+ objectId, classOid);
+
+ sid = sepgsqlGetTupleSecid(classOid, tup, tclass);
+
+ systable_endscan(scan);
+
+ heap_close(rel, AccessShareLock);
+
+ return sid;
+ }
+
+ sepgsql_sid_t
+ sepgsqlGetSysobjSecid(Oid classOid, Oid objectId, int32 objsubId, uint16 *tclass)
+ {
+ sepgsql_sid_t sid;
+ HeapTuple tup;
+
+ switch (classOid)
+ {
+ case AccessMethodRelationId:
+ tup = SearchSysCache(AMOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for access method: %u", objectId);
+ break;
+
+ case AccessMethodOperatorRelationId:
+ return getSysobjSecidDirect(AccessMethodOperatorRelationId,
+ AccessMethodOperatorOidIndexId,
+ objectId, tclass);
+
+ case AccessMethodProcedureRelationId:
+ return getSysobjSecidDirect(AccessMethodProcedureRelationId,
+ AccessMethodProcedureOidIndexId,
+ objectId, tclass);
+
+ case AuthIdRelationId:
+ tup = SearchSysCache(AUTHOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for role: %u", objectId);
+ break;
+
+ case CastRelationId:
+ return getSysobjSecidDirect(CastRelationId,
+ CastOidIndexId,
+ objectId, tclass);
+
+ case ConstraintRelationId:
+ tup = SearchSysCache(CONSTROID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for constraint: %u", objectId);
+ break;
+
+ case ConversionRelationId:
+ tup = SearchSysCache(CONVOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for conversion: %u", objectId);
+ break;
+
+ case DatabaseRelationId:
+ tup = SearchSysCache(DATABASEOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for database: %u", objectId);
+ break;
+
+ case ForeignDataWrapperRelationId:
+ tup = SearchSysCache(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for FDW: %u", objectId);
+ break;
+
+ case ForeignServerRelationId:
+ tup = SearchSysCache(FOREIGNSERVEROID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for foreign server: %u", objectId);
+ break;
+
+ case LanguageRelationId:
+ tup = SearchSysCache(LANGOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ break;
+
+ case LargeObjectRelationId:
+ /* to be replaced by LargeObjectMetaRelationId! */
+ {
+ Relation rel;
+ ScanKeyData skey;
+ SysScanDesc scan;
+
+ rel = heap_open(LargeObjectRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ Anum_pg_largeobject_loid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(objectId));
+
+ scan = systable_beginscan(rel, LargeObjectLOidPNIndexId,
+ true, SnapshotNow, 1, &skey);
+
+ tup = systable_getnext(scan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "largeobject %u lookup failed", objectId);
+
+ sid = sepgsqlGetTupleSecid(classOid, tup, tclass);
+ systable_endscan(scan);
+
+ heap_close(rel, AccessShareLock);
+ }
+ return sid;
+
+ case RelationRelationId:
+ if (objsubId != 0)
+ {
+ classOid = AttributeRelationId;
+ tup = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(objectId),
+ Int16GetDatum(objsubId),
+ 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+ objsubId, objectId);
+ }
+ else
+ {
+ classOid = RelationRelationId;
+ tup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for relation %u", objectId);
+ }
+ break;
+
+ case NamespaceRelationId:
+ tup = SearchSysCache(NAMESPACEOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for schema %u", objectId);
+ break;
+
+ case OperatorClassRelationId:
+ tup = SearchSysCache(CLAOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for opclass %u", objectId);
+ break;
+
+ case OperatorFamilyRelationId:
+ tup = SearchSysCache(OPFAMILYOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for opfamily %u", objectId);
+ break;
+
+ case OperatorRelationId:
+ tup = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for operator %u", objectId);
+ break;
+
+ case ProcedureRelationId:
+ tup = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for procedure %u", objectId);
+ break;
+
+ case RewriteRelationId:
+ return getSysobjSecidDirect(RewriteRelationId,
+ RewriteOidIndexId,
+ objectId, tclass);
+
+ case TableSpaceRelationId:
+ return getSysobjSecidDirect(TableSpaceRelationId,
+ TablespaceOidIndexId,
+ objectId, tclass);
+
+ case TriggerRelationId:
+ return getSysobjSecidDirect(TriggerRelationId,
+ TriggerOidIndexId,
+ objectId, tclass);
+
+ case TSConfigRelationId:
+ tup = SearchSysCache(TSCONFIGOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search configuration %u", objectId);
+ break;
+
+ case TSDictionaryRelationId:
+ tup = SearchSysCache(TSDICTOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search dictionary %u", objectId);
+ break;
+
+ case TSParserRelationId:
+ tup = SearchSysCache(TSPARSEROID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search parser %u", objectId);
+ break;
+
+ case TSTemplateRelationId:
+ tup = SearchSysCache(TSTEMPLATEOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search template %u", objectId);
+ break;
+
+ case TypeRelationId:
+ tup = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for type %u", objectId);
+ break;
+
+ case UserMappingRelationId:
+ tup = SearchSysCache(USERMAPPINGOID,
+ ObjectIdGetDatum(objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for user mapping %u", objectId);
+ break;
+
+ default:
+ elog(ERROR, "unexpected class OID: %u", classOid);
+ tup = NULL; /* for compiler quiet */
+ break;
+ }
+
+ Assert(HeapTupleIsValid(tup));
+
+ sid = sepgsqlGetTupleSecid(classOid, tup, tclass);
+
+ ReleaseSysCache(tup);
+
+ return sid;
+ }
+
+ /*
+ * sepgsqlGetTupleSecid
+ *
+ * It returns a pair of relid/secid for the given HeapTuple.
+ * A few system catalogs is handled as an attribute of other
+ * system objects.
+ * E.g) pg_attrdef is an attribute of a certain pg_attribute
+ */
+ sepgsql_sid_t
+ sepgsqlGetTupleSecid(Oid tableOid, HeapTuple tuple, uint16 *tclass)
+ {
+ sepgsql_sid_t sid;
+ HeapTuple exttup;
+ Oid extid;
+ Oid extcls;
+ AttrNumber extsub;
+
+ /* initialize (unlabeled security context) */
+ sid.relid = tableOid;
+ sid.secid = InvalidOid;
+ if (tclass)
+ *tclass = SEPG_CLASS_DB_TUPLE;
+
+ switch (tableOid)
+ {
+ case AggregateRelationId:
+ extid = ((Form_pg_aggregate) GETSTRUCT(tuple))->aggfnoid;
+ exttup = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(ProcedureRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case AccessMethodOperatorRelationId:
+ extid = ((Form_pg_amop) GETSTRUCT(tuple))->amopfamily;
+ exttup = SearchSysCache(OPFAMILYOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(OperatorFamilyRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case AccessMethodProcedureRelationId:
+ extid = ((Form_pg_amproc) GETSTRUCT(tuple))->amprocfamily;
+ exttup = SearchSysCache(OPFAMILYOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(OperatorFamilyRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case AttrDefaultRelationId:
+ extid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
+ extsub = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
+ exttup = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(extid),
+ Int16GetDatum(extsub),
+ 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(AttributeRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case AttributeRelationId:
+ extid = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid;
+ exttup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ char relkind = ((Form_pg_class) GETSTRUCT(exttup))->relkind;
+
+ if (relkind == RELKIND_RELATION)
+ {
+ if (tclass)
+ *tclass = SEPG_CLASS_DB_COLUMN;
+ sid.secid = HeapTupleGetSecid(tuple);
+ }
+ else
+ sid = sepgsqlGetTupleSecid(RelationRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case AuthMemRelationId:
+ extid = ((Form_pg_auth_members) GETSTRUCT(tuple))->roleid;
+ exttup = SearchSysCache(AUTHOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(AuthIdRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case ConstraintRelationId:
+ /* CHECK constraint is an attribute of the relation */
+ extid = ((Form_pg_constraint) GETSTRUCT(tuple))->conrelid;
+ if (OidIsValid(extid))
+ {
+ exttup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(RelationRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+ }
+ /* DOMAIN constraint is an attribute of the domain type */
+ extid = ((Form_pg_constraint) GETSTRUCT(tuple))->contypid;
+ if (OidIsValid(extid))
+ {
+ sid.relid = TypeRelationId;
+ exttup = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(TypeRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+ }
+ /* Database's context for global assertion */
+ exttup = SearchSysCache(DATABASEOID,
+ ObjectIdGetDatum(MyDatabaseId),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(DatabaseRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case DatabaseRelationId:
+ sid.secid = HeapTupleGetSecid(tuple);
+ if (tclass)
+ *tclass = SEPG_CLASS_DB_DATABASE;
+ break;
+
+ case DescriptionRelationId:
+ /* recursive call */
+ extid = ((Form_pg_description) GETSTRUCT(tuple))->objoid;
+ extcls = ((Form_pg_description) GETSTRUCT(tuple))->classoid;
+ return sepgsqlGetSysobjSecid(extcls, extid, 0, tclass);
+
+ case EnumRelationId:
+ extid = ((Form_pg_enum) GETSTRUCT(tuple))->enumtypid;
+ exttup = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(TypeRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case IndexRelationId:
+ extid = ((Form_pg_index) GETSTRUCT(tuple))->indrelid;
+ exttup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(RelationRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case InheritsRelationId:
+ extid = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrelid;
+ exttup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(RelationRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case LargeObjectRelationId:
+ sid.secid = HeapTupleGetSecid(tuple);
+ if (tclass)
+ *tclass = SEPG_CLASS_DB_BLOB;
+ break;
+
+ case NamespaceRelationId:
+ sid.secid = HeapTupleGetSecid(tuple);
+ if (tclass)
+ *tclass = SEPG_CLASS_DB_SCHEMA;
+ break;
+
+ case ProcedureRelationId:
+ sid.secid = HeapTupleGetSecid(tuple);
+ if (tclass)
+ *tclass = SEPG_CLASS_DB_PROCEDURE;
+ break;
+
+ case RelationRelationId:
+ sid.secid = HeapTupleGetSecid(tuple);
+ if (tclass)
+ {
+ char relkind = ((Form_pg_class) GETSTRUCT(tuple))->relkind;
+
+ switch (relkind)
+ {
+ case RELKIND_RELATION:
+ *tclass = SEPG_CLASS_DB_TABLE;
+ break;
+
+ case RELKIND_SEQUENCE:
+ *tclass = SEPG_CLASS_DB_SEQUENCE;
+ break;
+
+ default:
+ *tclass = SEPG_CLASS_DB_TUPLE;
+ break;
+ }
+ }
+ break;
+
+ case RewriteRelationId:
+ extid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class;
+ exttup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(RelationRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case SharedDescriptionRelationId:
+ /* recursive invocation */
+ extid = ((Form_pg_shdescription) GETSTRUCT(tuple))->objoid;
+ extcls = ((Form_pg_shdescription) GETSTRUCT(tuple))->classoid;
+ return sepgsqlGetSysobjSecid(extcls, extid, 0, tclass);
+
+ case StatisticRelationId:
+ extid = ((Form_pg_statistic) GETSTRUCT(tuple))->starelid;
+ extsub = ((Form_pg_statistic) GETSTRUCT(tuple))->staattnum;
+ exttup = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(extid),
+ Int16GetDatum(extsub),
+ 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(AttributeRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case TriggerRelationId:
+ extid = ((Form_pg_trigger) GETSTRUCT(tuple))->tgrelid;
+ exttup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(RelationRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ case TSConfigMapRelationId:
+ extid = ((Form_pg_ts_config_map) GETSTRUCT(tuple))->mapcfg;
+ exttup = SearchSysCache(TSCONFIGOID,
+ ObjectIdGetDatum(extid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(exttup))
+ {
+ sid = sepgsqlGetTupleSecid(TSConfigRelationId,
+ exttup, tclass);
+ ReleaseSysCache(exttup);
+ }
+ break;
+
+ default:
+ /* No external lookups (normal case) */
+ sid.secid = HeapTupleGetSecid(tuple);
+ break;
+ }
+
+ return sid;
+ }
+
+ /*
+ * 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;
+ }
+
+ char *
+ sepgsqlSysattSecLabelOut(Oid relid, HeapTuple tuple)
+ {
+ sepgsql_sid_t sid;
+
+ sid = sepgsqlGetTupleSecid(relid, tuple, NULL);
+
+ return securityTransSecLabelOut(sid.relid, sid.secid);
+ }
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 Sun Aug 23 23:05:48 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 old_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 Mon Sep 28 09:29:32 2009
***************
*** 0 ****
--- 1,597 ----
+ /*
+ * 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 },
+ {"create", SEPG_FILE__CREATE },
+ {"getattr", SEPG_FILE__GETATTR },
+ {NULL, 0}
+ }
+ },
+ {
+ "dir", SEPG_CLASS_DIR,
+ {
+ {"read", SEPG_DIR__READ },
+ {"write", SEPG_DIR__WRITE },
+ {"create", SEPG_DIR__CREATE },
+ {"getattr", SEPG_DIR__GETATTR },
+ {NULL,0}
+ }
+ },
+ {
+ "lnk_file", SEPG_CLASS_LNK_FILE,
+ {
+ {"read", SEPG_LNK_FILE__READ },
+ {"write", SEPG_LNK_FILE__WRITE },
+ {"create", SEPG_LNK_FILE__CREATE },
+ {"getattr", SEPG_LNK_FILE__GETATTR },
+ {NULL,0}
+ }
+ },
+ {
+ "chr_file", SEPG_CLASS_CHR_FILE,
+ {
+ {"read", SEPG_CHR_FILE__READ },
+ {"write", SEPG_CHR_FILE__WRITE },
+ {"create", SEPG_CHR_FILE__CREATE },
+ {"getattr", SEPG_CHR_FILE__GETATTR },
+ {NULL,0}
+ }
+ },
+ {
+ "blk_file", SEPG_CLASS_BLK_FILE,
+ {
+ {"read", SEPG_BLK_FILE__READ },
+ {"write", SEPG_BLK_FILE__WRITE },
+ {"create", SEPG_BLK_FILE__CREATE },
+ {"getattr", SEPG_BLK_FILE__GETATTR },
+ {NULL,0}
+ }
+ },
+ {
+ "sock_file", SEPG_CLASS_SOCK_FILE,
+ {
+ {"read", SEPG_SOCK_FILE__READ },
+ {"write", SEPG_SOCK_FILE__WRITE },
+ {"create", SEPG_SOCK_FILE__CREATE },
+ {"getattr", SEPG_SOCK_FILE__GETATTR },
+ {NULL,0}
+ }
+ },
+ {
+ "fifo_file", SEPG_CLASS_FIFO_FILE,
+ {
+ {"read", SEPG_FIFO_FILE__READ },
+ {"write", SEPG_FIFO_FILE__WRITE },
+ {"create", SEPG_FIFO_FILE__CREATE },
+ {"getattr", SEPG_FIFO_FILE__GETATTR },
+ {NULL, 0UL }
+ }
+ },
+ {
+ "db_database", SEPG_CLASS_DB_DATABASE,
+ {
+ { "create", SEPG_DB_DATABASE__CREATE },
+ { "drop", SEPG_DB_DATABASE__DROP },
+ { "getattr", SEPG_DB_DATABASE__GETATTR },
+ { "setattr", SEPG_DB_DATABASE__SETATTR },
+ { "relabelfrom", SEPG_DB_DATABASE__RELABELFROM },
+ { "relabelto", SEPG_DB_DATABASE__RELABELTO },
+ { "access", SEPG_DB_DATABASE__ACCESS },
+ { "install_module", SEPG_DB_DATABASE__INSTALL_MODULE },
+ { "load_module", SEPG_DB_DATABASE__LOAD_MODULE },
+ { "superuser", SEPG_DB_DATABASE__SUPERUSER },
+ { NULL, 0UL },
+ }
+ },
+ {
+ "db_schema", SEPG_CLASS_DB_SCHEMA,
+ {
+ { "create", SEPG_DB_SCHEMA__CREATE },
+ { "drop", SEPG_DB_SCHEMA__DROP },
+ { "getattr", SEPG_DB_SCHEMA__GETATTR },
+ { "setattr", SEPG_DB_SCHEMA__SETATTR },
+ { "relabelfrom", SEPG_DB_SCHEMA__RELABELFROM },
+ { "relabelto", SEPG_DB_SCHEMA__RELABELTO },
+ { "search", SEPG_DB_SCHEMA__SEARCH },
+ { "add_name", SEPG_DB_SCHEMA__ADD_NAME },
+ { "remove_name", SEPG_DB_SCHEMA__REMOVE_NAME },
+ { NULL, 0UL },
+ }
+ },
+ {
+ "db_table", SEPG_CLASS_DB_TABLE,
+ {
+ { "create", SEPG_DB_TABLE__CREATE },
+ { "drop", SEPG_DB_TABLE__DROP },
+ { "getattr", SEPG_DB_TABLE__GETATTR },
+ { "setattr", SEPG_DB_TABLE__SETATTR },
+ { "relabelfrom", SEPG_DB_TABLE__RELABELFROM },
+ { "relabelto", SEPG_DB_TABLE__RELABELTO },
+ { "select", SEPG_DB_TABLE__SELECT },
+ { "update", SEPG_DB_TABLE__UPDATE },
+ { "insert", SEPG_DB_TABLE__INSERT },
+ { "delete", SEPG_DB_TABLE__DELETE },
+ { "lock", SEPG_DB_TABLE__LOCK },
+ { "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 },
+ { "untrusted", SEPG_DB_PROCEDURE__UNTRUSTED },
+ { 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(uint16 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;
+ }
+
+ #if 0
+
+ /*
+ * sepgsqlFileObjectClass
+ *
+ * It returns proper object class of filesystem object already opened.
+ * It is necessary to check privileges voluntarily.
+ */
+ uint16
+ 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
+ */
+ uint16
+ sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple)
+ {
+ Form_pg_class clsForm;
+ Form_pg_attribute attForm;
+
+ switch (relid)
+ {
+ case DatabaseRelationId:
+ return SEPG_CLASS_DB_DATABASE;
+
+ case NamespaceRelationId:
+ 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;
+ }
+
+ /*
+ * sepgsqlTupleNamespace
+ *
+ * It returns an OID of the namespace, if the given system object is
+ * deployed under a certain namespace.
+ */
+ Oid
+ sepgsqlTupleNamespace(Oid relOid, HeapTuple tuple)
+ {
+ Oid nspOid;
+
+ switch (relOid)
+ {
+ case RelationRelationId:
+ nspOid = ((Form_pg_class) GETSTRUCT(tuple))->relnamespace;
+ break;
+
+ case ConstraintRelationId:
+ nspOid = ((Form_pg_constraint) GETSTRUCT(tuple))->connamespace;
+ break;
+
+ case ConversionRelationId:
+ nspOid = ((Form_pg_conversion) GETSTRUCT(tuple))->connamespace;
+ break;
+
+ case OperatorClassRelationId:
+ nspOid = ((Form_pg_opclass) GETSTRUCT(tuple))->opcnamespace;
+ break;
+
+ case OperatorRelationId:
+ nspOid = ((Form_pg_operator) GETSTRUCT(tuple))->oprnamespace;
+ break;
+
+ case OperatorFamilyRelationId:
+ nspOid = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfnamespace;
+ break;
+
+ case ProcedureRelationId:
+ nspOid = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace;
+ break;
+
+ case TSConfigRelationId:
+ nspOid = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgnamespace;
+ break;
+
+ case TSDictionaryRelationId:
+ nspOid = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictnamespace;
+ break;
+
+ case TSParserRelationId:
+ nspOid = ((Form_pg_ts_parser) GETSTRUCT(tuple))->prsnamespace;
+ break;
+
+ case TSTemplateRelationId:
+ nspOid = ((Form_pg_ts_template) GETSTRUCT(tuple))->tmplnamespace;
+ break;
+
+ default:
+ /* no specific namespace */
+ nspOid = InvalidOid;
+ break;
+ }
+
+ return nspOid;
+ }
+
+ /*
+ * sepgsqlTupleAuditName
+ *
+ * It returns an OID of the namespace, if the given system object is
+ * deployed under a certain namespace.
+ */
+ void
+ sepgsqlTupleAuditName(Oid relid, HeapTuple tuple, char *auname_buf)
+ {
+ char *name;
+ Oid extid;
+
+ switch (relid)
+ {
+ case AccessMethodRelationId:
+ name = NameStr(((Form_pg_am) GETSTRUCT(tuple))->amname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case AttributeRelationId:
+ name = NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname);
+ extid = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid;
+ sprintf(audit_name, "%s.%s", name, extid);
+ return;
+
+ case AuthIdRelationId:
+ name = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case ConversionRelationId:
+ name = NameStr(((Form_pg_conversion) GETSTRUCT(tuple))->conname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case DatabaseRelationId:
+ name = NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case ForeignDataWrapperRelationId:
+ name = NameStr(((Form_pg_foreign_data_wrapper) GETSTRUCT(tuple))->fdwname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case ForeignServerRelationId:
+ name = NameStr(((Form_pg_foreign_server) GETSTRUCT(tuple))->srvname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case LanguageRelationId:
+ name = NameStr(((Form_pg_language) GETSTRUCT(tuple))->lanname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case NamespaceRelationId:
+ name = NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case OperatorClassRelationId:
+ name = NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case OperatorRelationId:
+ name = NameStr(((Form_pg_operator) GETSTRUCT(tuple))->oprname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case OperatorFamilyRelationId:
+ name = NameStr(((Form_pg_opfamily) GETSTRUCT(tuple))->opfname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case ProcedureRelationId:
+ name = NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case RelationRelationId:
+ name = NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case TableSpaceRelationId:
+ name = NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case TSConfigRelationId:
+ name = NameStr(((Form_pg_ts_config) GETSTRUCT(tuple))->cfgname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case TSDictionaryRelationId:
+ name = NameStr(((Form_pg_ts_dict) GETSTRUCT(tuple))->dictname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case TSParserRelationId:
+ name = NameStr(((Form_pg_ts_parser) GETSTRUCT(tuple))->prsname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ case TSTemplateRelationId:
+ name = NameStr(((Form_pg_templace) GETSTRUCT(tuple))->tmplname);
+ strncpy(auname_buf, name, NAMEDATALEN);
+ break;
+
+ default:
+ /* no auditable name */
+ auname_buf[0] = '\0';
+ break;
+ }
+ }
+ #endif
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 Tue Dec 1 17:11:40 2009
***************
*** 0 ****
--- 1,123 ----
+ policy_module(sepostgresql-devel, 3.29)
+
+ 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_exec_t;
+
+ attribute tmpfile;
+ ')
+
+ #################################
+ #
+ # 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;
+
+ optional_policy(`
+ term_write_all_terms(sepgsql_test_t)
+ ')
+
+ optional_policy(`
+ gen_require(`
+ type unconfined_t;
+ role unconfined_r;
+ ')
+
+ tunable_policy(`sepgsql_regression_test_mode',`
+ allow unconfined_t sepgsql_test_t : process transition;
+ ')
+ unconfined_rw_pipes(sepgsql_test_t)
+ 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_sysobj_table_type : db_tuple *;
+ 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_sysobj_table_type : db_tuple *;
+ 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 Tue Sep 8 23:55:48 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 = HeapTupleGetSecid(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 (HeapTupleHasSecid(newtup))
+ HeapTupleSetSecid(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 (HeapTupleHasSecid(newtup))
+ HeapTupleSetSecid(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 (HeapTupleHasSecid(newtup))
+ HeapTupleSetSecid(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 = HeapTupleGetSecid(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 (!HeapTupleHasSecid(newtuple))
+ elog(ERROR, "Unable to assign security label on \"%s\"",
+ RelationGetRelationName(rel));
+ HeapTupleSetSecid(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/fastpath.c sepgsql/src/backend/tcop/fastpath.c
*** base/src/backend/tcop/fastpath.c Sat Jan 3 13:01:35 2009
--- sepgsql/src/backend/tcop/fastpath.c Thu Sep 17 17:04:16 2009
***************
*** 26,31 ****
--- 26,32 ----
#include "libpq/pqformat.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
+ #include "security/sepgsql.h"
#include "tcop/fastpath.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h"
*************** HandleFunctionRequest(StringInfo msgBuf)
*** 343,353 ****
--- 344,356 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(fip->namespace));
+ sepgsql_schema_search(fip->namespace, true);
aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(fid));
+ sepgsql_proc_execute(fid);
/*
* Prepare function call info block and insert arguments.
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 Mon Sep 28 09:29:32 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)
*** 99,104 ****
--- 100,108 ----
filename = convert_and_check_filename(filename_t);
+ /* SELinux: check file:{read} permission */
+ sepgsql_file_read(filename);
+
if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
ereport(ERROR,
(errcode_for_file_access(),
*************** pg_stat_file(PG_FUNCTION_ARGS)
*** 159,164 ****
--- 163,170 ----
(errmsg("must be superuser to get file information"))));
filename = convert_and_check_filename(filename_t);
+ /* SELinux: check file:{getattr} permission */
+ sepgsql_file_stat(filename);
if (stat(filename, &fst) < 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/tid.c sepgsql/src/backend/utils/adt/tid.c
*** base/src/backend/utils/adt/tid.c Sat Jan 3 13:01:35 2009
--- sepgsql/src/backend/utils/adt/tid.c Fri Sep 18 14:51:00 2009
*************** currtid_byreloid(PG_FUNCTION_ARGS)
*** 347,352 ****
--- 347,354 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_CLASS,
RelationGetRelationName(rel));
+ /* SELinux checks */
+ sepgsql_relation_get_transaction_id(RelationGetRelid(rel));
if (rel->rd_rel->relkind == RELKIND_VIEW)
return currtid_for_view(rel, tid);
*************** currtid_byrelname(PG_FUNCTION_ARGS)
*** 377,382 ****
--- 379,386 ----
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_CLASS,
RelationGetRelationName(rel));
+ /* SELinux checks */
+ sepgsql_relation_get_transaction_id(RelationGetRelid(rel));
if (rel->rd_rel->relkind == RELKIND_VIEW)
return currtid_for_view(rel, tid);
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 Tue Sep 8 23:55:48 2009
*************** suppress_redundant_updates_trigger(PG_FU
*** 76,81 ****
--- 76,85 ----
!OidIsValid(HeapTupleHeaderGetOid(newheader)))
HeapTupleHeaderSetOid(newheader, HeapTupleHeaderGetOid(oldheader));
+ if (HeapTupleHeaderHasSecid(newheader) &&
+ !OidIsValid(HeapTupleHeaderGetSecid(newheader)))
+ HeapTupleHeaderSetSecid(newheader, HeapTupleHeaderGetSecid(oldheader));
+
/* if the tuple payload is the same ... */
if (newtuple->t_len == oldtuple->t_len &&
newheader->t_hoff == oldheader->t_hoff &&
diff -Nrpc base/src/backend/utils/cache/plancache.c sepgsql/src/backend/utils/cache/plancache.c
*** base/src/backend/utils/cache/plancache.c Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/utils/cache/plancache.c Sun Sep 6 19:53:10 2009
*************** PlanCacheComputeResultDesc(List *stmt_li
*** 859,870 ****
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;
--- 859,870 ----
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
*** 875,887 ****
{
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;
--- 875,888 ----
{
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 Sep 9 13:14:37 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->tdhassecid */
+ RelationGetDescr(relation)->tdhassecid
+ = securityTupleDescHasSecid(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->tdhassecid */
+ RelationGetDescr(relation)->tdhassecid
+ = securityTupleDescHasSecid(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->tdhassecid don't give us
+ * any effect.
+ * We omit to invoke securityTupleDescHasSecid() here.
+ */
for (i = 0; i < natts; i++)
{
*************** load_relcache_init_file(void)
*** 3453,3458 ****
--- 3470,3480 ----
rel->rd_options = NULL;
}
+ /* Fixup rel->rd_att->tdhassecid */
+ RelationGetDescr(rel)->tdhassecid
+ = securityTupleDescHasSecid(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 Wed Sep 9 21:29:33 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,
*************** GetSysCacheOid(int cacheId,
*** 931,937 ****
return result;
}
-
/*
* SearchSysCacheAttName
*
--- 956,961 ----
diff -Nrpc base/src/backend/utils/fmgr/dfmgr.c sepgsql/src/backend/utils/fmgr/dfmgr.c
*** base/src/backend/utils/fmgr/dfmgr.c Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/utils/fmgr/dfmgr.c Thu Sep 17 17:04:16 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} */
+ sepgsql_database_load_module(MyDatabaseId, 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} */
+ sepgsql_database_load_module(MyDatabaseId, 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 Thu Sep 17 17:04:16 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;
+ sepgsql_proc_entrypoint(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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/utils/init/postinit.c Thu Sep 17 17:04:16 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
*** 201,207 ****
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.)
*/
--- 202,208 ----
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.)
*/
*************** CheckMyDatabase(const char *name, bool a
*** 213,218 ****
--- 214,222 ----
errmsg("permission denied for database \"%s\"", name),
errdetail("User does not have CONNECT privilege.")));
+ /* SELinux: db_database:{access} */
+ sepgsql_database_access(MyDatabaseId);
+
/*
* Check connection limit for this database.
*
*************** InitPostgres(const char *in_dbname, Oid
*** 575,580 ****
--- 579,587 ----
*/
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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/utils/misc/guc.c Sun Sep 6 19:53:10 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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/backend/utils/misc/postgresql.conf.sample Tue Dec 1 17:11:40 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 Thu Sep 17 17:04:16 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,66 ****
/* 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)
--- 61,70 ----
/* 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)
*************** superuser_arg(Oid roleid)
*** 94,99 ****
--- 98,107 ----
last_roleid = roleid;
last_roleid_is_super = result;
+ out:
+ if (result)
+ result = sepgsql_database_superuser(MyDatabaseId);
+
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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/bin/pg_dump/pg_dump.c Tue Sep 8 17:13:41 2009
*************** static int disable_dollar_quoting = 0;
*** 112,117 ****
--- 112,119 ----
static int dump_inserts = 0;
static int column_inserts = 0;
+ /* flag to turn on/off security_context */
+ static int security_context = 0;
static void help(const char *progname);
static void expand_schema_name_patterns(SimpleStringList *patterns,
*************** main(int argc, char **argv)
*** 277,282 ****
--- 279,285 ----
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
{"role", required_argument, NULL, 3},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
+ {"security-context", no_argument, &security_context, 1},
{NULL, 0, NULL, 0}
};
*************** main(int argc, char **argv)
*** 425,430 ****
--- 428,435 ----
outputNoTablespaces = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
+ else if (strcmp(optarg, "security-context") == 0)
+ security_context = 1;
else
{
fprintf(stderr,
*************** main(int argc, char **argv)
*** 573,578 ****
--- 578,605 ----
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_context > 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_context > 0 && dump_inserts)
+ column_inserts = 1;
+
/* Set the role if requested */
if (use_role && g_fout->remoteVersion >= 80100)
{
*************** help(const char *progname)
*** 826,831 ****
--- 853,860 ----
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
*** 1227,1233 ****
if (fout->remoteVersion >= 70100)
{
appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
! "SELECT * FROM ONLY %s",
fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
classname));
}
--- 1256,1263 ----
if (fout->remoteVersion >= 70100)
{
appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
! "SELECT %s* FROM ONLY %s",
! (security_context > 0 ? "security_context, " : ""),
fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
classname));
}
*************** dumpDatabase(Archive *AH)
*** 1583,1589 ****
i_collate,
i_ctype,
i_frozenxid,
! i_tablespace;
CatalogId dbCatId;
DumpId dbDumpId;
const char *datname,
--- 1613,1620 ----
i_collate,
i_ctype,
i_frozenxid,
! i_tablespace,
! i_seclabel;
CatalogId dbCatId;
DumpId dbDumpId;
const char *datname,
*************** dumpDatabase(Archive *AH)
*** 1591,1597 ****
*encoding,
*collate,
*ctype,
! *tablespace;
uint32 frozenxid;
datname = PQdb(g_conn);
--- 1622,1629 ----
*encoding,
*collate,
*ctype,
! *tablespace,
! *seclabel;
uint32 frozenxid;
datname = PQdb(g_conn);
*************** dumpDatabase(Archive *AH)
*** 1610,1620 ****
"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)
--- 1642,1653 ----
"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_context "
"FROM pg_database "
"WHERE datname = ",
! username_subquery,
! security_context ? "security_context" : "NULL");
appendStringLiteralAH(dbQry, datname, AH);
}
else if (g_fout->remoteVersion >= 80200)
*************** dumpDatabase(Archive *AH)
*** 1624,1631 ****
"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);
--- 1657,1664 ----
"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_context "
"FROM pg_database "
"WHERE datname = ",
username_subquery);
*************** dumpDatabase(Archive *AH)
*** 1637,1643 ****
"(%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);
--- 1670,1677 ----
"(%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_context "
"FROM pg_database "
"WHERE datname = ",
username_subquery);
*************** dumpDatabase(Archive *AH)
*** 1650,1656 ****
"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);
--- 1684,1691 ----
"pg_encoding_to_char(encoding) AS encoding, "
"NULL AS datcollate, NULL AS datctype, "
"0 AS datfrozenxid, "
! "NULL AS tablespace, "
! "NULL AS security_context "
"FROM pg_database "
"WHERE datname = ",
username_subquery);
*************** dumpDatabase(Archive *AH)
*** 1665,1671 ****
"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);
--- 1700,1707 ----
"pg_encoding_to_char(encoding) AS encoding, "
"NULL AS datcollate, NULL AS datctype, "
"0 AS datfrozenxid, "
! "NULL AS tablespace, "
! "NULL as security_context "
"FROM pg_database "
"WHERE datname = ",
username_subquery);
*************** dumpDatabase(Archive *AH)
*** 1699,1704 ****
--- 1735,1741 ----
i_ctype = PQfnumber(res, "datctype");
i_frozenxid = PQfnumber(res, "datfrozenxid");
i_tablespace = PQfnumber(res, "tablespace");
+ i_seclabel = PQfnumber(res, "security_context");
dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
*************** dumpDatabase(Archive *AH)
*** 1708,1713 ****
--- 1745,1751 ----
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)
*** 1729,1734 ****
--- 1767,1775 ----
if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
appendPQExpBuffer(creaQry, " TABLESPACE = %s",
fmtId(tablespace));
+ if (strlen(seclabel) > 0)
+ appendPQExpBuffer(creaQry, " SECURITY_CONTEXT = '%s'", seclabel);
+
appendPQExpBuffer(creaQry, ";\n");
if (binary_upgrade)
*************** getTables(int *numTables)
*** 3190,3195 ****
--- 3231,3237 ----
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)
*** 3231,3237 ****
"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 "
--- 3273,3280 ----
"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_context "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
*************** getTables(int *numTables)
*** 3242,3247 ****
--- 3285,3291 ----
"WHERE c.relkind in ('%c', '%c', '%c', '%c') "
"ORDER BY c.oid",
username_subquery,
+ security_context ? "c.security_context" : "NULL",
RELKIND_SEQUENCE,
RELKIND_RELATION, RELKIND_SEQUENCE,
RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
*************** getTables(int *numTables)
*** 3263,3269 ****
"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 "
--- 3307,3314 ----
"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_context "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
*************** getTables(int *numTables)
*** 3294,3300 ****
"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 "
--- 3339,3346 ----
"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_context "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
*************** getTables(int *numTables)
*** 3325,3331 ****
"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 "
--- 3371,3378 ----
"d.refobjsubid AS owning_col, "
"NULL AS reltablespace, "
"NULL AS reloptions, "
! "NULL AS toast_reloptions, "
! "NULL as security_context "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
*************** getTables(int *numTables)
*** 3352,3358 ****
"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",
--- 3399,3406 ----
"NULL::int4 AS owning_col, "
"NULL AS reltablespace, "
"NULL AS reloptions, "
! "NULL AS toast_reloptions, "
! "NULL AS security_context "
"FROM pg_class "
"WHERE relkind IN ('%c', '%c', '%c') "
"ORDER BY oid",
*************** getTables(int *numTables)
*** 3374,3380 ****
"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",
--- 3422,3429 ----
"NULL::int4 AS owning_col, "
"NULL AS reltablespace, "
"NULL AS reloptions, "
! "NULL AS toast_reloptions, "
! "NULL AS security_context "
"FROM pg_class "
"WHERE relkind IN ('%c', '%c', '%c') "
"ORDER BY oid",
*************** getTables(int *numTables)
*** 3406,3412 ****
"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",
--- 3455,3462 ----
"NULL::int4 AS owning_col, "
"NULL AS reltablespace, "
"NULL AS reloptions, "
! "NULL AS toast_reloptions, "
! "NULL as security_context "
"FROM pg_class c "
"WHERE relkind IN ('%c', '%c') "
"ORDER BY oid",
*************** getTables(int *numTables)
*** 3451,3456 ****
--- 3501,3507 ----
i_reltablespace = PQfnumber(res, "reltablespace");
i_reloptions = PQfnumber(res, "reloptions");
i_toastreloptions = PQfnumber(res, "toast_reloptions");
+ i_relseclabel = PQfnumber(res, "security_context");
if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
{
*************** getTables(int *numTables)
*** 3498,3503 ****
--- 3549,3555 ----
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
*** 4697,4702 ****
--- 4749,4755 ----
int i_attlen;
int i_attalign;
int i_attislocal;
+ int i_attseclabel;
PGresult *res;
int ntups;
bool hasdefaults;
*************** getTableAttrs(TableInfo *tblinfo, int nu
*** 4741,4752 ****
"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)
--- 4794,4807 ----
"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_context "
"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_context ? "a.security_context" : "NULL",
tbinfo->dobj.catId.oid);
}
else if (g_fout->remoteVersion >= 70100)
*************** getTableAttrs(TableInfo *tblinfo, int nu
*** 4761,4767 ****
"t.typstorage, a.attnotnull, a.atthasdef, "
"false AS attisdropped, a.attlen, "
"a.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 "
--- 4816,4823 ----
"t.typstorage, a.attnotnull, a.atthasdef, "
"false AS attisdropped, a.attlen, "
"a.attalign, false AS attislocal, "
! "format_type(t.oid,a.atttypmod) AS atttypname, "
! "NULL as security_context "
"FROM pg_attribute a LEFT JOIN pg_type t "
"ON a.atttypid = t.oid "
"WHERE a.attrelid = '%u'::oid "
*************** getTableAttrs(TableInfo *tblinfo, int nu
*** 4778,4784 ****
"attnotnull, atthasdef, false AS attisdropped, "
"attlen, 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 "
--- 4834,4841 ----
"attnotnull, atthasdef, false AS attisdropped, "
"attlen, attalign, "
"false AS attislocal, "
! "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
! "NULL as security_context "
"FROM pg_attribute a "
"WHERE attrelid = '%u'::oid "
"AND attnum > 0::int2 "
*************** getTableAttrs(TableInfo *tblinfo, int nu
*** 4804,4809 ****
--- 4861,4867 ----
i_attlen = PQfnumber(res, "attlen");
i_attalign = PQfnumber(res, "attalign");
i_attislocal = PQfnumber(res, "attislocal");
+ i_attseclabel = PQfnumber(res, "security_context");
tbinfo->numatts = ntups;
tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
*************** getTableAttrs(TableInfo *tblinfo, int nu
*** 4816,4821 ****
--- 4874,4880 ----
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
*** 4841,4846 ****
--- 4900,4906 ----
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)
*** 7091,7096 ****
--- 7151,7157 ----
char *proconfig;
char *procost;
char *prorows;
+ char *proseclabel;
char *lanname;
char *rettypename;
int nallargs;
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 7127,7135 ****
"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)
--- 7188,7198 ----
"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_context "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
+ security_context ? "security_context" : "NULL",
finfo->dobj.catId.oid);
}
else if (g_fout->remoteVersion >= 80300)
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 7140,7146 ****
"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);
--- 7203,7210 ----
"false AS proiswindow, "
"provolatile, proisstrict, prosecdef, "
"proconfig, procost, prorows, "
! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname, "
! "NULL AS security_context "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
finfo->dobj.catId.oid);
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 7153,7159 ****
"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);
--- 7217,7224 ----
"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_context "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
finfo->dobj.catId.oid);
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 7168,7174 ****
"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);
--- 7233,7240 ----
"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_context "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
finfo->dobj.catId.oid);
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 7183,7189 ****
"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);
--- 7249,7256 ----
"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_context "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
finfo->dobj.catId.oid);
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 7200,7206 ****
"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);
--- 7267,7274 ----
"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_context "
"FROM pg_proc "
"WHERE oid = '%u'::oid",
finfo->dobj.catId.oid);
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 7217,7223 ****
"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);
--- 7285,7292 ----
"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_context "
"FROM pg_proc "
"WHERE oid = '%u'::oid",
finfo->dobj.catId.oid);
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 7261,7266 ****
--- 7330,7336 ----
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_context"));
lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
/*
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 7419,7424 ****
--- 7489,7497 ----
if (prosecdef[0] == 't')
appendPQExpBuffer(q, " SECURITY DEFINER");
+ if (security_context > 0 && strlen(proseclabel) > 0)
+ appendPQExpBuffer(q, " SECURITY_CONTEXT = '%s'", proseclabel);
+
/*
* COST and ROWS are emitted only if present and not default, so as not to
* break backwards-compatibility of the dump without need. Keep this code
*************** dumpTableSchema(Archive *fout, TableInfo
*** 9877,9882 ****
--- 9950,9966 ----
if (tbinfo->notnull[j] &&
(!tbinfo->inhNotNull[j] || binary_upgrade))
appendPQExpBuffer(q, " NOT NULL");
+
+ /*
+ * Security label -- if SE-PostgreSQL enabled
+ */
+ if (security_context > 0 &&
+ strlen(tbinfo->attseclabel[j]) > 0 &&
+ strcmp(tbinfo->relseclabel, tbinfo->attseclabel[j]) != 0)
+ appendPQExpBuffer(q, " SECURITY_CONTEXT = '%s'",
+ tbinfo->attseclabel[j]);
+
+ actual_atts++;
}
}
*************** dumpTableSchema(Archive *fout, TableInfo
*** 9939,9944 ****
--- 10023,10031 ----
appendPQExpBuffer(q, ")");
}
+ if (security_context > 0 && strlen(tbinfo->relseclabel) > 0)
+ appendPQExpBuffer(q, " SECURITY_CONTEXT = '%s'", tbinfo->relseclabel);
+
appendPQExpBuffer(q, ";\n");
/*
*************** fmtCopyColumnList(const TableInfo *ti)
*** 11508,11513 ****
--- 11595,11607 ----
appendPQExpBuffer(q, "(");
needComma = false;
+
+ if (security_context > 0)
+ {
+ appendPQExpBuffer(q, "security_context");
+ 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 Tue Sep 8 23:55:48 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_HASSECID 0x0010 /* has an security-id field */
#define HEAP_COMBOCID 0x0020 /* t_cid is a combo cid */
#define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */
#define HEAP_XMAX_SHARED_LOCK 0x0080 /* xmax is shared locker */
*************** 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 HeapTupleHeaderHasSecid(tup) \
+ ((tup)->t_infomask & HEAP_HASSECID)
+
+ #define HeapTupleHeaderGetSecid(tup) \
+ ( \
+ HeapTupleHeaderHasSecid(tup) \
+ ? (*(Oid *)((char *)(tup) + (tup)->t_hoff \
+ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \
+ - sizeof(Oid))) \
+ : InvalidOid \
+ )
+
+ #define HeapTupleHeaderSetSecid(tup, secid) \
+ do { \
+ Assert(HeapTupleHeaderHasSecid(tup)); \
+ *((Oid *)((char *)(tup) + (tup)->t_hoff \
+ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \
+ - sizeof(Oid))) = (secid); \
+ } while(0)
/*
* BITMAPLEN(NATTS) -
*************** typedef HeapTupleData *HeapTuple;
*** 549,554 ****
--- 571,584 ----
#define HeapTupleSetOid(tuple, oid) \
HeapTupleHeaderSetOid((tuple)->t_data, (oid))
+ #define HeapTupleHasSecid(tuple) \
+ HeapTupleHeaderHasSecid((tuple)->t_data)
+
+ #define HeapTupleGetSecid(tuple) \
+ HeapTupleHeaderGetSecid((tuple)->t_data)
+
+ #define HeapTupleSetSecid(tuple, secid) \
+ HeapTupleHeaderSetSecid((tuple)->t_data, (secid))
/*
* WAL record definitions for heapam.c's WAL operations
diff -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 Sep 9 16:47:01 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 SecurityAttributeNumber (-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 SecurityAttributeName "security_context"
#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 Sep 9 13:14:37 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 tdhassecid; /* tuple has secid attribute in its header */
int tdrefcount; /* reference count, or -1 if not counting */
} *TupleDesc;
diff -Nrpc base/src/include/bootstrap/bootstrap.h sepgsql/src/include/bootstrap/bootstrap.h
*** base/src/include/bootstrap/bootstrap.h Sat Jan 3 12:25:21 2009
--- sepgsql/src/include/bootstrap/bootstrap.h Tue Dec 8 14:04:25 2009
*************** typedef enum
*** 70,76 ****
BootstrapProcess,
StartupProcess,
BgWriterProcess,
! WalWriterProcess
} AuxProcType;
#endif /* BOOTSTRAP_H */
--- 70,77 ----
BootstrapProcess,
StartupProcess,
BgWriterProcess,
! WalWriterProcess,
! SelinuxReceiverProcess,
} AuxProcType;
#endif /* BOOTSTRAP_H */
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 Thu Sep 10 15:29: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_context 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_context 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_context 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_context 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_conversion_fn.h sepgsql/src/include/catalog/pg_conversion_fn.h
*** base/src/include/catalog/pg_conversion_fn.h Thu Jun 18 10:20:52 2009
--- sepgsql/src/include/catalog/pg_conversion_fn.h Thu Sep 17 22:10:19 2009
***************
*** 17,23 ****
extern Oid ConversionCreate(const char *conname, Oid connamespace,
Oid conowner,
int32 conforencoding, int32 contoencoding,
! Oid conproc, bool def);
extern void RemoveConversionById(Oid conversionOid);
extern Oid FindConversion(const char *conname, Oid connamespace);
extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding);
--- 17,23 ----
extern Oid ConversionCreate(const char *conname, Oid connamespace,
Oid conowner,
int32 conforencoding, int32 contoencoding,
! Oid conproc, Oid consecid, bool def);
extern void RemoveConversionById(Oid conversionOid);
extern Oid FindConversion(const char *conname, Oid connamespace);
extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding);
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 Thu Sep 10 15:18:03 2009
***************
*** 0 ****
--- 1,101 ----
+ /*
+ * 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
+ securityTupleDescHasSecid(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 Datum
+ securitySysattSecLabelOut(Oid relid, 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 Sun Sep 6 19:40:49 2009
--- sepgsql/src/include/executor/executor.h Wed Sep 9 13:14:37 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 ExecContextForcesSecids(PlanState *planstate, bool *hassecids);
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 Tue Dec 8 14:04:25 2009
***************
*** 0 ****
--- 1,777 ----
+ /*
+ * 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_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_FILE__CREATE (1<<2)
+ #define SEPG_FILE__GETATTR (1<<3)
+
+ #define SEPG_DIR__READ (SEPG_FILE__READ)
+ #define SEPG_DIR__WRITE (SEPG_FILE__WRITE)
+ #define SEPG_DIR__CREATE (SEPG_FILE__CREATE)
+ #define SEPG_DIR__GETATTR (SEPG_FILE__GETATTR)
+
+ #define SEPG_LNK_FILE__READ (SEPG_FILE__READ)
+ #define SEPG_LNK_FILE__WRITE (SEPG_FILE__WRITE)
+ #define SEPG_LNK_FILE__CREATE (SEPG_FILE__CREATE)
+ #define SEPG_LNK_FILE__GETATTR (SEPG_FILE__GETATTR)
+
+ #define SEPG_CHR_FILE__READ (SEPG_FILE__READ)
+ #define SEPG_CHR_FILE__WRITE (SEPG_FILE__WRITE)
+ #define SEPG_CHR_FILE__CREATE (SEPG_FILE__CREATE)
+ #define SEPG_CHR_FILE__GETATTR (SEPG_FILE__GETATTR)
+
+ #define SEPG_BLK_FILE__READ (SEPG_FILE__READ)
+ #define SEPG_BLK_FILE__WRITE (SEPG_FILE__WRITE)
+ #define SEPG_BLK_FILE__CREATE (SEPG_FILE__CREATE)
+ #define SEPG_BLK_FILE__GETATTR (SEPG_FILE__GETATTR)
+
+ #define SEPG_SOCK_FILE__READ (SEPG_FILE__READ)
+ #define SEPG_SOCK_FILE__WRITE (SEPG_FILE__WRITE)
+ #define SEPG_SOCK_FILE__CREATE (SEPG_FILE__CREATE)
+ #define SEPG_SOCK_FILE__GETATTR (SEPG_FILE__GETATTR)
+
+ #define SEPG_FIFO_FILE__READ (SEPG_FILE__READ)
+ #define SEPG_FIFO_FILE__WRITE (SEPG_FILE__WRITE)
+ #define SEPG_FIFO_FILE__CREATE (SEPG_FILE__CREATE)
+ #define SEPG_FIFO_FILE__GETATTR (SEPG_FILE__GETATTR)
+
+ #define SEPG_DB_DATABASE__CREATE (1<<0)
+ #define SEPG_DB_DATABASE__DROP (1<<1)
+ #define SEPG_DB_DATABASE__GETATTR (1<<2)
+ #define SEPG_DB_DATABASE__SETATTR (1<<3)
+ #define SEPG_DB_DATABASE__RELABELFROM (1<<4)
+ #define SEPG_DB_DATABASE__RELABELTO (1<<5)
+ #define SEPG_DB_DATABASE__ACCESS (1<<6)
+ #define SEPG_DB_DATABASE__INSTALL_MODULE (1<<7)
+ #define SEPG_DB_DATABASE__LOAD_MODULE (1<<8)
+ #define SEPG_DB_DATABASE__SUPERUSER (1<<9)
+
+ #define SEPG_DB_SCHEMA__CREATE (SEPG_DB_DATABASE__CREATE)
+ #define SEPG_DB_SCHEMA__DROP (SEPG_DB_DATABASE__DROP)
+ #define SEPG_DB_SCHEMA__GETATTR (SEPG_DB_DATABASE__GETATTR)
+ #define SEPG_DB_SCHEMA__SETATTR (SEPG_DB_DATABASE__SETATTR)
+ #define SEPG_DB_SCHEMA__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+ #define SEPG_DB_SCHEMA__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+ #define SEPG_DB_SCHEMA__SEARCH (1<<6)
+ #define SEPG_DB_SCHEMA__ADD_NAME (1<<7)
+ #define SEPG_DB_SCHEMA__REMOVE_NAME (1<<8)
+
+ #define SEPG_DB_TABLE__CREATE (SEPG_DB_DATABASE__CREATE)
+ #define SEPG_DB_TABLE__DROP (SEPG_DB_DATABASE__DROP)
+ #define SEPG_DB_TABLE__GETATTR (SEPG_DB_DATABASE__GETATTR)
+ #define SEPG_DB_TABLE__SETATTR (SEPG_DB_DATABASE__SETATTR)
+ #define SEPG_DB_TABLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+ #define SEPG_DB_TABLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+ #define SEPG_DB_TABLE__SELECT (1<<6)
+ #define SEPG_DB_TABLE__UPDATE (1<<7)
+ #define SEPG_DB_TABLE__INSERT (1<<8)
+ #define SEPG_DB_TABLE__DELETE (1<<9)
+ #define SEPG_DB_TABLE__LOCK (1<<10)
+ #define SEPG_DB_TABLE__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_PROCEDURE__UNTRUSTED (1<<9)
+
+ #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)
+
+ /*
+ * sepgsql_sid_t : alternative representation of security context
+ */
+ typedef struct {
+ Oid relid;
+ Oid secid;
+ } sepgsql_sid_t;
+
+ #define SidIsValid(sid) (OidIsValid((sid).relid) && OidIsValid((sid).secid))
+
+ /*
+ * 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 sepgsqlAvcReset(void);
+ extern void sepgsqlAvcSwitchClient(const char *scontext);
+
+ extern bool
+ sepgsqlClientHasPerms(sepgsql_sid_t tsid,
+ uint16 tclass, uint32 required,
+ const char *audit_name, bool abort);
+ extern sepgsql_sid_t
+ sepgsqlClientCreateSecid(sepgsql_sid_t tsid, uint16 tclass, Oid nrelid);
+
+ extern security_context_t
+ sepgsqlClientCreateLabel(sepgsql_sid_t tsid, uint16 tclass);
+
+ extern bool
+ sepgsqlComputePerms(security_context_t scontext,
+ security_context_t tcontext,
+ uint16 tclass, uint32 required,
+ const char *audit_name, bool abort);
+
+ extern security_context_t
+ sepgsqlComputeCreate(security_context_t scontext,
+ security_context_t tcontext,
+ uint16 tclass);
+
+ extern void sepgsqlReceiverMain(void);
+
+ /*
+ * bridge.c : new style security hooks
+ */
+
+ /* pg_attribute */
+ extern Oid
+ sepgsql_attribute_create(Oid relOid, ColumnDef *cdef);
+ extern void
+ sepgsql_attribute_alter(Oid relOid, const char *attname);
+ extern void
+ sepgsql_attribute_drop(Oid relOid, AttrNumber attnum);
+ extern void
+ sepgsql_attribute_grant(Oid relOid, AttrNumber attnum);
+ extern Oid
+ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, DefElem *newLabel);
+
+ /* pg_cast */
+ extern Oid
+ sepgsql_cast_create(Oid sourceTypOid, Oid targetTypOid, Oid funcOid);
+ extern void
+ sepgsql_cast_drop(Oid castOid);
+
+ /* pg_class */
+ extern Oid *
+ sepgsql_relation_create(const char *relName,
+ char relkind,
+ TupleDesc tupDesc,
+ Oid nspOid,
+ DefElem *relLabel,
+ List *colList,
+ bool createAs,
+ bool permission);
+ extern Oid *
+ sepgsql_relation_copy(Relation src);
+ extern void
+ sepgsql_relation_alter(Oid relOid, const char *newName, Oid newNsp);
+ extern void
+ sepgsql_relation_drop(Oid relOid);
+ extern void
+ sepgsql_relation_grant(Oid relOid);
+ extern Oid
+ sepgsql_relation_relabel(Oid relOid, DefElem *newLabel);
+ extern void
+ sepgsql_relation_get_transaction_id(Oid relOid);
+ extern void
+ sepgsql_relation_copy_definition(Oid relOid);
+ extern void
+ sepgsql_relation_truncate(Relation rel);
+ extern void
+ sepgsql_relation_references(Relation rel, int16 *attnums, int natts);
+ extern void
+ sepgsql_relation_lock(Oid relOid);
+ extern void
+ sepgsql_view_replace(Oid viewOid);
+ extern void
+ sepgsql_index_create(Oid relOid, Oid nspOid, bool check_rights);
+ extern void
+ sepgsql_sequence_get_value(Oid seqOid);
+ extern void
+ sepgsql_sequence_next_value(Oid seqOid);
+ extern void
+ sepgsql_sequence_set_value(Oid seqOid);
+
+ /* pg_conversion */
+ extern Oid
+ sepgsql_conversion_create(const char *convName, Oid nspOid, Oid procOid);
+ extern void
+ sepgsql_conversion_alter(Oid convOid, const char *newName);
+ extern void
+ sepgsql_conversion_drop(Oid convOid);
+
+ /* pg_database */
+ extern Oid
+ sepgsql_database_create(const char *datName, DefElem *newLabel);
+ extern void
+ sepgsql_database_alter(Oid datOid);
+ extern void
+ sepgsql_database_drop(Oid datOid);
+ extern Oid
+ sepgsql_database_relabel(Oid datOid, DefElem *newLabel);
+ extern void
+ sepgsql_database_grant(Oid datOid);
+ extern void
+ sepgsql_database_access(Oid datOid);
+ extern bool
+ sepgsql_database_superuser(Oid datOid);
+ extern void
+ sepgsql_database_load_module(Oid datOid, const char *filename);
+
+ /* pg_foreign_data_wrapper */
+ extern Oid
+ sepgsql_fdw_create(const char *fdwName, Oid fdwValidator);
+ extern void
+ sepgsql_fdw_alter(Oid fdwOid, Oid newValidator);
+ extern void
+ sepgsql_fdw_drop(Oid fdwOid);
+ extern void
+ sepgsql_fdw_grant(Oid fdwOid);
+
+ /* pg_foreign_server */
+ extern Oid
+ sepgsql_foreign_server_create(const char *fsrvName);
+ extern void
+ sepgsql_foreign_server_alter(Oid fsrvOid);
+ extern void
+ sepgsql_foreign_server_drop(Oid fsrvOid);
+ extern void
+ sepgsql_foreign_server_grant(Oid fsrvOid);
+
+ /* pg_language */
+ extern Oid
+ sepgsql_language_create(const char *langName, Oid handlerOid, Oid validatorOid);
+ extern void
+ sepgsql_language_alter(Oid langOid);
+ extern void
+ sepgsql_language_drop(Oid langOid);
+ extern void
+ sepgsql_language_grant(Oid langOid);
+
+ /* pg_largeobject */
+ extern Oid
+ sepgsql_largeobject_create(Oid loid, DefElem *newLabel);
+ extern void
+ sepgsql_largeobject_alter(Oid loid, Oid newOwner);
+ extern void
+ sepgsql_largeobject_drop(Oid loid, bool dacSkip);
+ extern void
+ sepgsql_largeobject_read(Oid loid);
+ extern void
+ sepgsql_largeobject_write(Oid loid);
+ extern void
+ sepgsql_largeobject_export(Oid loid, const char *filename);
+ extern Oid
+ sepgsql_largeobject_import(Oid loid, const char *filename, DefElem *newLabel);
+
+ /* pg_namespace */
+ extern Oid
+ sepgsql_schema_create(const char *nspName, bool isTemp, DefElem *newLabel);
+ extern void
+ sepgsql_schema_alter(Oid nspOid);
+ extern void
+ sepgsql_schema_drop(Oid nspOid);
+ extern Oid
+ sepgsql_schema_relabel(Oid nspOid, DefElem *newLabel);
+ extern void
+ sepgsql_schema_grant(Oid nspOid);
+ extern bool
+ sepgsql_schema_search(Oid nspOid, bool abort);
+
+ /* pg_opclass */
+ extern Oid
+ sepgsql_opclass_create(const char *opcName, Oid nspOid);
+ extern void
+ sepgsql_opclass_alter(Oid opcOid, const char *newName);
+ extern void
+ sepgsql_opclass_drop(Oid opcOid);
+
+ /* pg_opfamily */
+ extern Oid
+ sepgsql_opfamily_create(const char *opfName, Oid nspOid);
+ extern void
+ sepgsql_opfamily_alter(Oid opfOid, const char *newName);
+ extern void
+ sepgsql_opfamily_drop(Oid opfOid);
+ extern void
+ sepgsql_opfamily_add_operator(Oid opfOid, Oid operOid);
+ extern void
+ sepgsql_opfamily_add_procedure(Oid opfOid, Oid procOid);
+
+ /* pg_operator */
+ extern Oid
+ sepgsql_operator_create(const char *oprName, Oid oprOid, Oid nspOid,
+ Oid codeFn, Oid restFn, Oid joinFn);
+ extern void
+ sepgsql_operator_alter(Oid oprOid);
+ extern void
+ sepgsql_operator_drop(Oid oprOid);
+
+ /* pg_proc */
+ extern Oid
+ sepgsql_proc_create(const char *procName, HeapTuple oldTup,
+ Oid nspOid, Oid langOid, DefElem *newLabel);
+ extern void
+ sepgsql_proc_alter(Oid procOid, const char *newName, Oid newNsp);
+ extern void
+ sepgsql_proc_drop(Oid procOid);
+ extern Oid
+ sepgsql_proc_relabel(Oid procOid, DefElem *newLabel);
+ extern void
+ sepgsql_proc_grant(Oid procOid);
+ extern void
+ sepgsql_proc_execute(Oid procOid);
+ extern bool
+ sepgsql_proc_hint_inlined(HeapTuple protup);
+ extern void
+ sepgsql_proc_entrypoint(FmgrInfo *flinfo, HeapTuple protup);
+
+ /* pg_rewrite */
+ extern void
+ sepgsql_rule_create(Oid relOid, const char *ruleName);
+ extern void
+ sepgsql_rule_drop(Oid relOid, const char *ruleName);
+
+ /* pg_trigger */
+ extern void
+ sepgsql_trigger_create(Oid relOid, const char *trigName, Oid procOid);
+ extern void
+ sepgsql_trigger_alter(Oid relOid, const char *trigName);
+ extern void
+ sepgsql_trigger_drop(Oid relOid, const char *trigName);
+
+ /* pg_ts_config */
+ extern Oid
+ sepgsql_ts_config_create(const char *cfgName, Oid nspOid);
+ extern void
+ sepgsql_ts_config_alter(Oid cfgOid, const char *newName);
+ extern void
+ sepgsql_ts_config_drop(Oid cfgOid);
+
+ /* pg_ts_dict */
+ extern Oid
+ sepgsql_ts_dict_create(const char *dictName, Oid nspOid);
+ extern void
+ sepgsql_ts_dict_alter(Oid dictOid, const char *newName);
+ extern void
+ sepgsql_ts_dict_drop(Oid dictOid);
+
+ /* pg_ts_parser */
+ extern Oid
+ sepgsql_ts_parser_create(const char *prsName, Oid nspOid,
+ Oid startFn, Oid tokenFn, Oid sendFn,
+ Oid headlineFn, Oid lextypeFn);
+ extern void
+ sepgsql_ts_parser_alter(Oid prsOid, const char *newName);
+ extern void
+ sepgsql_ts_parser_drop(Oid prsOid);
+
+ /* pg_ts_templace */
+ extern Oid
+ sepgsql_ts_template_create(const char *tmplName, Oid nspOid,
+ Oid initFn, Oid lexizeFn);
+ extern void
+ sepgsql_ts_template_alter(Oid tmplOid, const char *newName);
+ extern void
+ sepgsql_ts_template_drop(Oid tmplOid);
+
+ /* pg_type */
+ extern Oid
+ sepgsql_type_create(const char *typName, HeapTuple oldTup, Oid nspOid,
+ Oid inputProc, Oid outputProc, Oid recvProc, Oid sendProc,
+ Oid modinProc, Oid modoutProc, Oid analyzeProc);
+ extern void
+ sepgsql_type_alter(Oid typOid, const char *newName, Oid newNsp);
+ extern void
+ sepgsql_type_drop(Oid typOid);
+
+ /* misc objects */
+ extern void
+ sepgsql_sysobj_drop(const ObjectAddress *object);
+
+ /* filesystem objects */
+ void
+ sepgsql_file_stat(const char *filename);
+ void
+ sepgsql_file_read(const char *filename);
+ void
+ sepgsql_file_write(const char *filename);
+
+ /*
+ * 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 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, const char *filename);
+ extern void
+ sepgsqlCheckBlobImport(LargeObjectDesc *lobj, const char *filename);
+ extern void
+ sepgsqlCheckBlobRelabel(HeapTuple oldtup, HeapTuple newtup);
+
+ /*
+ * label.c : security label management
+ */
+ extern bool
+ sepgsqlTupleDescHasSecid(Oid relid, char relkind);
+
+ extern void sepgsqlSetDefaultSecid(Relation rel, HeapTuple tuple);
+ extern sepgsql_sid_t sepgsqlGetDefaultDatabaseSecid(void);
+ extern sepgsql_sid_t sepgsqlGetDefaultSchemaSecid(Oid database_oid);
+ extern sepgsql_sid_t sepgsqlGetDefaultSchemaTempSecid(Oid database_oid);
+ extern sepgsql_sid_t sepgsqlGetDefaultTableSecid(Oid namespace_oid);
+ extern sepgsql_sid_t sepgsqlGetDefaultSequenceSecid(Oid namespace_oid);
+ extern sepgsql_sid_t sepgsqlGetDefaultProcedureSecid(Oid namespace_oid);
+ extern sepgsql_sid_t sepgsqlGetDefaultColumnSecid(Oid table_oid);
+ extern sepgsql_sid_t sepgsqlGetDefaultTupleSecid(Oid table_oid);
+ extern sepgsql_sid_t sepgsqlGetDefaultBlobSecid(Oid database_oid);
+
+ extern Oid *sepgsqlCreateTableColumns(CreateStmt *stmt,
+ const char *relname, Oid namespace_oid,
+ TupleDesc tupdesc, char relkind);
+ extern Oid *sepgsqlCopyTableColumns(Relation source);
+
+ extern sepgsql_sid_t
+ sepgsqlGetTupleSecid(Oid tableOid, HeapTuple tuple, uint16 *tclass);
+ extern sepgsql_sid_t
+ sepgsqlGetSysobjSecid(Oid tableOid, Oid objectId, int32 objsubId, uint16 *tclass);
+
+ extern char *sepgsqlTransSecLabelIn(char *seclabel);
+ extern char *sepgsqlTransSecLabelOut(char *seclabel);
+ extern char *sepgsqlRawSecLabelIn(char *seclabel);
+ extern char *sepgsqlRawSecLabelOut(char *seclabel);
+ extern char *sepgsqlSysattSecLabelOut(Oid relid, HeapTuple tuple);
+
+ /*
+ * perms.c : SELinux permission related stuff
+ */
+ extern uint16 sepgsqlFileObjectClass(int fdesc);
+
+ extern uint16 sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple);
+
+ extern security_class_t sepgsqlTransToExternalClass(uint16 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)
+
+ /* 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)
+
+ /* bridge.c */
+ #define sepgsql_attribute_create(a,b) (InvalidOid)
+ #define sepgsql_attribute_alter(a,b) do {} while(0)
+ #define sepgsql_attribute_drop(a,b) do {} while(0)
+ #define sepgsql_attribute_grant(a,b) do {} while(0)
+ #define sepgsql_attribute_relabel(a,b,c) (InvalidOid)
+
+ #define sepgsql_cast_create(a,b,c) (InvalidOid)
+ #define sepgsql_cast_drop(a) (InvalidOid)
+
+ #define sepgsql_relation_create(a,b,c,d,e,f) (NULL)
+ #define sepgsql_relation_copy(a) (NULL)
+ #define sepgsql_relation_alter(a,b,c) do {} while(0)
+ #define sepgsql_relation_drop(a) do {} while(0)
+ #define sepgsql_relation_grant(a) do {} while(0)
+ #define sepgsql_relation_relabel(a,b) do {} while(0)
+ #define sepgsql_relation_get_transaction_id(a) do {} while(0)
+ #define sepgsql_relation_copy_definition(a) do {} while(0)
+ #define sepgsql_relation_truncate(a) do {} while(0)
+ #define sepgsql_relation_references(a,b,c) do {} while(0)
+ #define sepgsql_relation_lock(a) do {} while(0)
+ #define sepgsql_view_replace(a) do {} while(0)
+ #define sepgsql_index_create(a,b,c) do {} while(0)
+ #define sepgsql_sequence_get_value(a) do {} while(0)
+ #define sepgsql_sequence_next_value(a) do {} while(0)
+ #define sepgsql_sequence_set_value(a) do {} while(0)
+
+ #define sepgsql_conversion_create(a,b,c) do {} while(0)
+ #define sepgsql_conversion_alter(a,b) do {} while(0)
+ #define sepgsql_conversion_drop(a) do {} while(0)
+
+ #define sepgsql_database_create(a,b) (InvalidOid)
+ #define sepgsql_database_alter(a) do {} while(0)
+ #define sepgsql_database_drop(a) do {} while(0)
+ #define sepgsql_database_relabel(a,b) (InvalidOid)
+ #define sepgsql_database_grant(a) do {} while(0)
+ #define sepgsql_database_access(a) do {} while(0)
+ #define sepgsql_database_superuser(a) (true)
+ #define sepgsql_database_load_module(a,b) do {} while(0)
+
+ #define sepgsql_fdw_create(a,b) (InvalidOid)
+ #define sepgsql_fdw_alter(a,b) do {} while(0)
+ #define sepgsql_fdw_drop(a) do {} while(0)
+ #define sepgsql_fdw_grant(a) do {} while(0)
+
+ #define sepgsql_foreign_server_create(a) (InvalidOid)
+ #define sepgsql_foreign_server_alter(a) do {} while(0)
+ #define sepgsql_foreign_server_drop(a) do {} while(0)
+ #define sepgsql_foreign_server_grant(a) do {} while(0)
+
+ #define sepgsql_language_create(a,b,c) (InvalidOid)
+ #define sepgsql_language_alter(a) do {} while(0)
+ #define sepgsql_language_drop(a) do {} while(0)
+ #define sepgsql_language_grant(a) do {} while(0)
+
+ #define sepgsql_largeobject_create(a,b) (InvalidOid)
+ #define sepgsql_largeobject_alter(a,b) do {} while(0)
+ #define sepgsql_largeobject_drop(a) do {} while(0)
+ #define sepgsql_largeobject_read(a) do {} while(0)
+ #define sepgsql_largeobject_write(a) do {} while(0)
+ #define sepgsql_largeobject_export(a,b) do {} while(0)
+ #define sepgsql_largeobject_import(a,b) (InvalidOid)
+
+ #define sepgsql_schema_create(a,b,c) (InvalidOid)
+ #define sepgsql_schema_alter(a) do {} while(0)
+ #define sepgsql_schema_drop(a) do {} while(0)
+ #define sepgsql_schema_relabel(a,b) (InvalidOid)
+ #define sepgsql_schema_grant(a) do {} while(0)
+ #define sepgsql_schema_search(a,b) (true)
+
+ #define sepgsql_opclass_create(a,b) (InvalidOid)
+ #define sepgsql_opclass_alter(a,b) do {} while(0)
+ #define sepgsql_opclass_drop(a) do {} while(0)
+
+ #define sepgsql_opfamily_create(a,b) (InvalidOid)
+ #define sepgsql_opfamily_alter(a,b) do {} while(0)
+ #define sepgsql_opfamily_drop(a) do {} while(0)
+ #define sepgsql_opfamily_add_operator(a,b) do {} while(0)
+ #define sepgsql_opfamily_add_procedure(a,b) do {} while(0)
+
+ #define sepgsql_operator_create(a,b,c,d,e,f) (InvalidOid)
+ #define sepgsql_operator_alter(a) do {} while(0)
+ #define sepgsql_operator_drop(a) do {} while(0)
+
+ #define sepgsql_proc_create(a,b,c,d,e) (InvalidOid)
+ #define sepgsql_proc_alter(a,b,c) do {} while(0)
+ #define sepgsql_proc_drop(a) do {} while(0)
+ #define sepgsql_proc_relabel(a,b) (InvalidOid)
+ #define sepgsql_proc_grant(a) do {} while(0)
+ #define sepgsql_proc_execute(a) do {} while(0)
+ #define sepgsql_proc_hint_inlined(a) (true)
+ #define sepgsql_proc_entrypoint(a,b) do {} while(0)
+
+ #define sepgsql_rule_create(a,b) do {} while(0)
+ #define sepgsql_rule_drop(a,b) do {} while(0)
+
+ #define sepgsql_trigger_create(a,b,c) do {} while(0)
+ #define sepgsql_trigger_alter(a,b) do {} while(0)
+ #define sepgsql_trigger_drop(a,b) do {} while(0)
+
+ #define sepgsql_ts_config_create(a,b) (InvalidOid)
+ #define sepgsql_ts_config_alter(a,b) do {} while(0)
+ #define sepgsql_ts_config_drop(a) do {} while(0)
+
+ #define sepgsql_ts_config_create(a,b) (InvalidOid)
+ #define sepgsql_ts_config_alter(a,b) do {} while(0)
+ #define sepgsql_ts_config_drop(a) do {} while(0)
+
+ #define sepgsql_ts_dict_create(a,b) (InvalidOid)
+ #define sepgsql_ts_dict_alter(a,b) do {} while(0)
+ #define sepgsql_ts_dict_drop(a) do {} while(0)
+
+ #define sepgsql_ts_parser_create(a,b,c,d,e,f,g) (InvalidOid)
+ #define sepgsql_ts_parser_alter(a,b) do {} while(0)
+ #define sepgsql_ts_parser_drop(a) do {} while(0)
+
+ #define sepgsql_ts_template_create(a,b,c,d) (InvalidOid)
+ #define sepgsql_ts_template_alter(a,b) do {} while(0)
+ #define sepgsql_ts_template_drop(a) do {} while(0)
+
+ #define sepgsql_type_create(a,b,c,d,e,f,g,h,i,j) (InvalidOid)
+ #define sepgsql_type_alter(a,b,c) do {} while(0)
+ #define sepgsql_type_drop(a) do {} while(0)
+
+ #define sepgsql_sysobj_drop(a) do {} while(0)
+
+ #define sepgsql_file_stat(a) do {} while(0)
+ #define sepgsql_file_read(a) do {} while(0)
+ #define sepgsql_file_write(a) do {} while(0)
+
+ /* label.c */
+ #define sepgsqlTupleDescHasSecLabel(a,b) (false)
+ #define sepgsqlSetDefaultSecLabel(a,b) do {} while(0)
+ #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/storage/proc.h sepgsql/src/include/storage/proc.h
*** base/src/include/storage/proc.h Thu Feb 26 10:18:55 2009
--- sepgsql/src/include/storage/proc.h Tue Dec 8 14:04:25 2009
*************** typedef struct PROC_HDR
*** 143,150 ****
* normal operation. Startup process also consumes one slot, but WAL
* writer and autovacuum launcher are launched only after it has
* exited.
*/
! #define NUM_AUXILIARY_PROCS 3
/* configurable options */
--- 143,152 ----
* normal operation. Startup process also consumes one slot, but WAL
* writer and autovacuum launcher are launched only after it has
* exited.
+ * In addition, a netlink receiver process may be launched, if SELinux
+ * support is enabled.
*/
! #define NUM_AUXILIARY_PROCS 4
/* configurable options */
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 Wed Sep 9 21:29:33 2009
*************** enum SysCacheIdentifier
*** 69,74 ****
--- 69,76 ----
RELNAMENSP,
RELOID,
RULERELNAME,
+ SECURITYATTR,
+ SECURITYSECID,
STATRELATT,
TSCONFIGMAP,
TSCONFIGNAMENSP,
diff -Nrpc base/src/test/regress/GNUmakefile sepgsql/src/test/regress/GNUmakefile
*** base/src/test/regress/GNUmakefile Sat Jan 3 13:01:35 2009
--- sepgsql/src/test/regress/GNUmakefile Tue Dec 1 17:11:40 2009
*************** ifdef NO_LOCALE
*** 38,43 ****
--- 38,49 ----
NOLOCALE += --no-locale
endif
+ # SELinux support
+ ENABLE_SELINUX =
+ ifdef SELINUX
+ ENABLE_SELINUX += --enable-selinux
+ endif
+
# stuff to pass into build of pg_regress
EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \
'-DMAKEPROG="$(MAKE)"' \
*************** tablespace-setup:
*** 138,144 ****
## Run tests
##
! pg_regress_call = ./pg_regress --inputdir=$(srcdir) --dlpath=. --multibyte=$(MULTIBYTE) --load-language=plpgsql $(NOLOCALE)
check: all
$(pg_regress_call) --temp-install=./tmp_check --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule $(MAXCONNOPT) $(TEMP_CONF)
--- 144,150 ----
## Run tests
##
! pg_regress_call = ./pg_regress --inputdir=$(srcdir) --dlpath=. --multibyte=$(MULTIBYTE) --load-language=plpgsql $(NOLOCALE) $(ENABLE_SELINUX)
check: all
$(pg_regress_call) --temp-install=./tmp_check --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule $(MAXCONNOPT) $(TEMP_CONF)
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
diff -Nrpc base/src/test/regress/pg_regress.c sepgsql/src/test/regress/pg_regress.c
*** base/src/test/regress/pg_regress.c Thu Jun 18 10:20:52 2009
--- sepgsql/src/test/regress/pg_regress.c Tue Dec 1 17:11:40 2009
*************** static _stringlist *schedulelist = NULL;
*** 82,87 ****
--- 82,88 ----
static _stringlist *extra_tests = NULL;
static char *temp_install = NULL;
static char *temp_config = NULL;
+ static bool enable_selinux = false;
static char *top_builddir = NULL;
static bool nolocale = false;
static char *hostname = NULL;
*************** help(void)
*** 1863,1868 ****
--- 1864,1870 ----
printf(_(" --top-builddir=DIR (relative) path to top level build directory\n"));
printf(_(" --port=PORT start postmaster on PORT\n"));
printf(_(" --temp-config=PATH append contents of PATH to temporary config\n"));
+ printf(_(" --enable-selinux enables SELinux support, if available\n"));
printf(_("\n"));
printf(_("Options for using an existing installation:\n"));
printf(_(" --host=HOST use postmaster running on HOST\n"));
*************** regression_main(int argc, char *argv[],
*** 1907,1912 ****
--- 1909,1915 ----
{"dlpath", required_argument, NULL, 17},
{"create-role", required_argument, NULL, 18},
{"temp-config", required_argument, NULL, 19},
+ {"enable-selinux", optional_argument, NULL, 20},
{NULL, 0, NULL, 0}
};
*************** regression_main(int argc, char *argv[],
*** 1997,2002 ****
--- 2000,2008 ----
case 19:
temp_config = strdup(optarg);
break;
+ case 20:
+ enable_selinux = true;
+ break;
default:
/* getopt_long already emitted a complaint */
fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
*************** regression_main(int argc, char *argv[],
*** 2086,2095 ****
/* initdb */
header(_("initializing database system"));
snprintf(buf, sizeof(buf),
! SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
bindir, temp_install, datadir,
debug ? " --debug" : "",
nolocale ? " --no-locale" : "",
outputdir);
if (system(buf))
{
--- 2092,2102 ----
/* initdb */
header(_("initializing database system"));
snprintf(buf, sizeof(buf),
! SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
bindir, temp_install, datadir,
debug ? " --debug" : "",
nolocale ? " --no-locale" : "",
+ enable_selinux ? " --enable-selinux" : "",
outputdir);
if (system(buf))
{