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 Sep 8 23:55:48 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 Wed Jul 15 19:35:52 2009 *************** *** 42,47 **** --- 42,48 ---- #include "nodes/pg_list.h" #include "nodes/primnodes.h" #include "rewrite/prs2lock.h" + #include "security/sepgsql.h" #include "storage/block.h" #include "storage/fd.h" #include "storage/ipc.h" *************** Boot_CreateStmt: *** 211,216 **** --- 212,222 ---- else { Oid id; + Oid *secLabels = + sepgsqlCreateTableColumns(NULL, + LexIDStr($5), + PG_CATALOG_NAMESPACE, + tupdesc, RELKIND_RELATION); id = heap_create_with_catalog(LexIDStr($5), PG_CATALOG_NAMESPACE, *************** Boot_CreateStmt: *** 225,231 **** 0, ONCOMMIT_NOOP, (Datum) 0, ! true); elog(DEBUG4, "relation created with oid %u", id); } do_end(); --- 231,238 ---- 0, ONCOMMIT_NOOP, (Datum) 0, ! true, ! secLabels); elog(DEBUG4, "relation created with oid %u", id); } do_end(); diff -Nrpc base/src/backend/bootstrap/bootstrap.c sepgsql/src/backend/bootstrap/bootstrap.c *** base/src/backend/bootstrap/bootstrap.c Fri Feb 20 22:15:36 2009 --- sepgsql/src/backend/bootstrap/bootstrap.c Wed Sep 9 13:14:37 2009 *************** *** 26,31 **** --- 26,32 ---- #include "access/xact.h" #include "bootstrap/bootstrap.h" #include "catalog/index.h" + #include "catalog/pg_security.h" #include "catalog/pg_type.h" #include "libpq/pqsignal.h" #include "miscadmin.h" *************** BootstrapModeMain(void) *** 497,502 **** --- 498,508 ---- */ boot_yyparse(); + /* + * Flush all the cached security label + */ + securityPostBootstrapingMode(); + /* Perform a checkpoint to ensure everything's down to disk */ SetProcessingMode(NormalProcessing); CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE); *************** InsertOneTuple(Oid objectid) *** 794,799 **** --- 800,807 ---- tupDesc = CreateTupleDesc(numattr, RelationGetForm(boot_reldesc)->relhasoids, attrtypes); + tupDesc->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 Wed Sep 9 21:29:33 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_Function(InternalGrant *istmt) *** 1572,1577 **** --- 1580,1587 ---- funcId, grantorId, ACL_KIND_PROC, NameStr(pg_proc_tuple->proname), 0, NULL); + /* SELinux: db_procedure:{setattr} */ + sepgsqlCheckProcedureSetattr(funcId); /* * Generate new ACL. *************** ExecGrant_Namespace(InternalGrant *istmt *** 1815,1820 **** --- 1825,1833 ---- NameStr(pg_namespace_tuple->nspname), 0, NULL); + /* SELinux: db_schema:{setattr} */ + sepgsqlCheckSchemaSetattr(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 Mon Sep 7 00:55:45 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) + sepgsqlCheckSysobjDrop(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 Wed Jul 15 19:39:56 2009 *************** *** 48,53 **** --- 48,54 ---- #include "nodes/nodeFuncs.h" #include "optimizer/clauses.h" #include "optimizer/var.h" + #include "security/sepgsql.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "storage/procarray.h" *************** static TupleDesc ConstructTupleDescripto *** 81,87 **** Oid *classObjectId); static void InitializeAttributeOids(Relation indexRelation, int numatts, Oid indexoid); ! static void AppendAttributeTuples(Relation indexRelation, int numatts); static void UpdateIndexRelation(Oid indexoid, Oid heapoid, IndexInfo *indexInfo, Oid *classOids, --- 82,88 ---- Oid *classObjectId); static void InitializeAttributeOids(Relation indexRelation, int numatts, Oid indexoid); ! static void AppendAttributeTuples(Relation indexRelation, int numatts, Oid *secLabels); static void UpdateIndexRelation(Oid indexoid, Oid heapoid, IndexInfo *indexInfo, Oid *classOids, *************** InitializeAttributeOids(Relation indexRe *** 323,333 **** * ---------------------------------------------------------------- */ static void ! AppendAttributeTuples(Relation indexRelation, int numatts) { Relation pg_attribute; CatalogIndexState indstate; TupleDesc indexTupDesc; int i; /* --- 324,335 ---- * ---------------------------------------------------------------- */ static void ! AppendAttributeTuples(Relation indexRelation, int numatts, Oid *secLabels) { Relation pg_attribute; CatalogIndexState indstate; TupleDesc indexTupDesc; + Oid attsid = InvalidOid; int i; /* *************** AppendAttributeTuples(Relation indexRela *** 351,357 **** Assert(indexTupDesc->attrs[i]->attnum == i + 1); Assert(indexTupDesc->attrs[i]->attcacheoff == -1); ! InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], indstate); } CatalogCloseIndexes(indstate); --- 353,363 ---- Assert(indexTupDesc->attrs[i]->attnum == i + 1); Assert(indexTupDesc->attrs[i]->attcacheoff == -1); ! if (secLabels) ! attsid = secLabels[i - FirstLowInvalidHeapAttributeNumber]; ! ! InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], ! indstate, attsid); } CatalogCloseIndexes(indstate); *************** index_create(Oid heapRelationId, *** 519,524 **** --- 525,532 ---- TupleDesc indexTupDesc; bool shared_relation; Oid namespaceId; + Oid *secLabels; + Oid relsid = InvalidOid; int i; pg_class = heap_open(RelationRelationId, RowExclusiveLock); *************** index_create(Oid heapRelationId, *** 604,609 **** --- 612,625 ---- classObjectId); /* + * compute security labels to be assigned on index relation + */ + secLabels = sepgsqlCreateTableColumns(NULL, indexRelationName, namespaceId, + indexTupDesc, RELKIND_INDEX); + if (secLabels) + relsid = secLabels[0]; + + /* * Allocate an OID for the index, unless we were told what to use. * * The OID will be the relfilenode as well, so make sure it doesn't *************** index_create(Oid heapRelationId, *** 652,658 **** */ InsertPgClassTuple(pg_class, indexRelation, RelationGetRelid(indexRelation), ! reloptions); /* done with pg_class */ heap_close(pg_class, RowExclusiveLock); --- 668,674 ---- */ InsertPgClassTuple(pg_class, indexRelation, RelationGetRelid(indexRelation), ! reloptions, relsid); /* done with pg_class */ heap_close(pg_class, RowExclusiveLock); *************** index_create(Oid heapRelationId, *** 668,674 **** /* * append ATTRIBUTE tuples for the index */ ! AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs); /* ---------------- * update pg_index --- 684,690 ---- /* * append ATTRIBUTE tuples for the index */ ! AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs, secLabels); /* ---------------- * update pg_index diff -Nrpc base/src/backend/catalog/namespace.c sepgsql/src/backend/catalog/namespace.c *** base/src/backend/catalog/namespace.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/catalog/namespace.c Mon Sep 7 00:55:45 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)) + { + sepgsqlCheckSchemaSearch(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); + sepgsqlCheckSchemaSearch(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 && ! sepgsqlCheckSchemaSearch(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) && ! sepgsqlCheckSchemaSearch(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 && ! sepgsqlCheckSchemaSearch(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 = sepgsqlCheckSchemaCreate(namespaceName, NULL, true); + snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId); namespaceId = GetSysCacheOid(NAMESPACENAME, *************** InitTempTableNamespace(void) *** 2851,2857 **** * temp tables. This works because the places that access the temp * namespace for my own backend skip permissions checks on it. */ ! namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID); /* Advance command counter to make namespace visible */ CommandCounterIncrement(); } --- 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_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_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 Tue Sep 8 23:55:48 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,361 ---- ObjectIdGetDatum(procNamespace), 0); + /* Check permission to create/replace a function */ + prosecid = sepgsqlCheckProcedureCreate(procedureName, + HeapTupleIsValid(oldtup) + ? HeapTupleGetOid(oldtup) + : InvalidOid, + procNamespace, + languageObjectId, + (DefElem *)proseclabel); + sepgsqlCheckSchemaAddName(procNamespace); + if (HeapTupleIsValid(oldtup)) { /* There is one; okay to replace it? */ *************** ProcedureCreate(const char *procedureNam *** 477,482 **** --- 490,497 ---- /* Okay, do it... */ tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces); + if (HeapTupleHasSecid(tup) && OidIsValid(prosecid)) + HeapTupleSetSecid(tup, prosecid); simple_heap_update(rel, &tup->t_self, tup); ReleaseSysCache(oldtup); *************** ProcedureCreate(const char *procedureNam *** 486,491 **** --- 501,508 ---- { /* 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 Tue Sep 8 23:55:48 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,1355 ---- break; case TypeRelationId: + /* + * NOTE: SELinux does not check anything inside + * AlterTypeOwnerInternal() + */ + tuple = SearchSysCache(TYPEOID, + ObjectIdGetDatum(sdepForm->objid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for type: %u", sdepForm->objid); + sepgsqlCheckSysobjSetattr(TypeRelationId, + HeapTupleGetSecid(tuple), + NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname)); + ReleaseSysCache(tuple); 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 --- 1362,1368 ---- break; case RelationRelationId: ! sepgsqlCheckTableSetattr(sdepForm->objid); /* * 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 Tue Sep 8 23:55:48 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,72 ---- 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 = sepgsqlCheckSysobjCreate(TypeRelationId, typeName); + sepgsqlCheckProcedureInstall(F_SHELL_IN); + sepgsqlCheckProcedureInstall(F_SHELL_OUT); + /* * open pg_type */ *************** TypeCreate(Oid newTypeOid, *** 201,206 **** --- 208,214 ---- { Relation pg_type_desc; Oid typeObjectId; + Oid typeSecid = InvalidOid; bool rebuildDeps = false; HeapTuple tup; bool nulls[Natts_pg_type]; *************** TypeCreate(Oid newTypeOid, *** 367,372 **** --- 375,394 ---- CStringGetDatum(typeName), ObjectIdGetDatum(typeNamespace), 0, 0); + + /* SELinux checks to create/replace type */ + if (!isImplicitArray && typeType != TYPTYPE_COMPOSITE) + { + if (!HeapTupleIsValid(tup)) + typeSecid = sepgsqlCheckSysobjCreate(TypeRelationId, typeName); + else + { + typeSecid = HeapTupleGetSecid(tup); + sepgsqlCheckSysobjSetattr(TypeRelationId, typeSecid, typeName); + } + sepgsqlCheckSchemaAddName(typeNamespace); + } + if (HeapTupleIsValid(tup)) { /* *************** TypeCreate(Oid newTypeOid, *** 412,417 **** --- 434,441 ---- /* 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 Wed Jul 15 19:35:52 2009 *************** *** 28,33 **** --- 28,34 ---- #include "catalog/toasting.h" #include "miscadmin.h" #include "nodes/makefuncs.h" + #include "security/sepgsql.h" #include "utils/builtins.h" #include "utils/syscache.h" *************** create_toast_table(Relation rel, Oid toa *** 125,130 **** --- 126,132 ---- char toast_relname[NAMEDATALEN]; char toast_idxname[NAMEDATALEN]; IndexInfo *indexInfo; + Oid *secLabels; Oid classObjectId[2]; int16 coloptions[2]; ObjectAddress baseobject, *************** create_toast_table(Relation rel, Oid toa *** 199,204 **** --- 201,210 ---- else namespaceid = PG_TOAST_NAMESPACE; + secLabels = sepgsqlCreateTableColumns(NULL, + toast_relname, namespaceid, + tupdesc, RELKIND_TOASTVALUE); + toast_relid = heap_create_with_catalog(toast_relname, namespaceid, rel->rd_rel->reltablespace, *************** create_toast_table(Relation rel, Oid toa *** 212,218 **** 0, ONCOMMIT_NOOP, reloptions, ! true); /* make the toast relation visible, else index creation will fail */ CommandCounterIncrement(); --- 218,225 ---- 0, ONCOMMIT_NOOP, reloptions, ! true, ! secLabels); /* make the toast relation visible, else index creation will fail */ CommandCounterIncrement(); diff -Nrpc base/src/backend/commands/aggregatecmds.c sepgsql/src/backend/commands/aggregatecmds.c *** base/src/backend/commands/aggregatecmds.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/commands/aggregatecmds.c Mon Sep 7 00:55:45 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,322 ---- aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceOid)); + /* SELinux permission checks */ + sepgsqlCheckProcedureSetattr(procOid); + sepgsqlCheckSchemaRemoveName(namespaceOid); + sepgsqlCheckSchemaAddName(namespaceOid); + /* rename */ namestrcpy(&(((Form_pg_proc) GETSTRUCT(tup))->proname), newname); simple_heap_update(rel, &tup->t_self, tup); diff -Nrpc base/src/backend/commands/alter.c sepgsql/src/backend/commands/alter.c *** base/src/backend/commands/alter.c Sat Jan 3 13:01:35 2009 --- sepgsql/src/backend/commands/alter.c Thu Jul 16 17:22:29 2009 *************** *** 28,33 **** --- 28,34 ---- #include "commands/user.h" #include "miscadmin.h" #include "parser/parse_clause.h" + #include "security/sepgsql.h" #include "tcop/utility.h" #include "utils/acl.h" #include "utils/lsyscache.h" *************** ExecRenameStmt(RenameStmt *stmt) *** 117,122 **** --- 118,126 ---- aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceId)); + /* SELinux checks db_table/db_sequence:{setattr} */ + sepgsqlCheckTableSetattr(relid); + RenameRelation(relid, stmt->newname, stmt->renameType); break; } *************** ExecAlterOwnerStmt(AlterOwnerStmt *stmt) *** 284,286 **** --- 288,319 ---- (int) stmt->objectType); } } + + void + ExecAlterSecLabelStmt(AlterSecLabelStmt *stmt) + { + DefElem *seclabel = (DefElem *)stmt->secLabel; + + switch (stmt->objectType) + { + case OBJECT_DATABASE: + AlterDatabaseSecLabel(strVal(linitial(stmt->object)), seclabel); + break; + case OBJECT_SCHEMA: + AlterSchemaSecLabel(strVal(linitial(stmt->object)), seclabel); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_COLUMN: + CheckRelationOwnership(stmt->relation, true); + AlterRelationSecLabel(stmt->relation, stmt->subname, + stmt->objectType, seclabel); + break; + case OBJECT_FUNCTION: + AlterFunctionSecLabel(stmt->object, stmt->objarg, seclabel); + break; + default: + elog(ERROR, "unrecognized AlterSecLabelStmt type: %d", + (int) stmt->objectType); + } + } diff -Nrpc base/src/backend/commands/cluster.c sepgsql/src/backend/commands/cluster.c *** base/src/backend/commands/cluster.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/commands/cluster.c Tue Sep 8 23:55:48 2009 *************** *** 36,41 **** --- 36,42 ---- #include "commands/trigger.h" #include "commands/vacuum.h" #include "miscadmin.h" + #include "security/sepgsql.h" #include "storage/bufmgr.h" #include "storage/procarray.h" #include "utils/acl.h" *************** rebuild_relation(Relation OldHeap, Oid i *** 617,624 **** /* * The new relation is local to our transaction and we know nothing * depends on it, so DROP_RESTRICT should be OK. */ ! performDeletion(&object, DROP_RESTRICT); /* performDeletion does CommandCounterIncrement at end */ --- 618,626 ---- /* * The new relation is local to our transaction and we know nothing * depends on it, so DROP_RESTRICT should be OK. + * SELinux does not check any permissions here. */ ! performDeletionNoPerms(&object, DROP_RESTRICT); /* performDeletion does CommandCounterIncrement at end */ *************** make_new_heap(Oid OIDOldHeap, const char *** 712,718 **** 0, ONCOMMIT_NOOP, reloptions, ! allowSystemTableMods); ReleaseSysCache(tuple); --- 714,721 ---- 0, ONCOMMIT_NOOP, reloptions, ! allowSystemTableMods, ! sepgsqlCopyTableColumns(OldHeap)); ReleaseSysCache(tuple); *************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl *** 924,929 **** --- 927,936 ---- if (NewHeap->rd_rel->relhasoids) HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple)); + /* Preserve 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 Wed Jul 15 19:48:58 2009 *************** *** 24,29 **** --- 24,30 ---- #include "mb/pg_wchar.h" #include "miscadmin.h" #include "parser/parse_func.h" + #include "security/sepgsql.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" *************** CreateConversionCommand(CreateConversion *** 96,101 **** --- 97,105 ---- aclcheck_error(aclresult, ACL_KIND_PROC, NameListToString(func_name)); + /* SELinux checks db_procedure:{install} */ + sepgsqlCheckProcedureInstall(funcoid); + /* * Check that the conversion function is suitable for the requested source * and target encodings. We do that by calling the function with an empty diff -Nrpc base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c *** base/src/backend/commands/copy.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/commands/copy.c Thu Sep 10 15:18:03 2009 *************** *** 21,28 **** --- 21,31 ---- #include #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 *** 1090,1095 **** --- 1099,1107 ---- num_phys_attrs = tupDesc->natts; + /* SELinux: check table/column level permission */ + sepgsqlCheckCopyTable(cstate->rel, cstate->attnumlist, is_from); + /* Convert FORCE QUOTE name list to per-column flags, check validity */ cstate->force_quote_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool)); if (force_quote) *************** DoCopy(const CopyStmt *stmt, const char *** 1104,1114 **** int attnum = lfirst_int(cur); if (!list_member_int(cstate->attnumlist, attnum)) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("FORCE QUOTE column \"%s\" not referenced by COPY", ! NameStr(tupDesc->attrs[attnum - 1]->attname)))); ! cstate->force_quote_flags[attnum - 1] = true; } } --- 1116,1146 ---- int attnum = lfirst_int(cur); if (!list_member_int(cstate->attnumlist, attnum)) + { + Form_pg_attribute attForm; + + if (SystemAttributeIsWritable(attnum)) + attForm = SystemAttributeDefinition(attnum, true); + else + attForm = tupDesc->attrs[attnum - 1]; + + Assert(attForm != NULL); + ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("FORCE QUOTE column \"%s\" not referenced by COPY", ! NameStr(attForm->attname)))); ! } ! ! switch (attnum) ! { ! case 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; } } --- 1158,1180 ---- int attnum = lfirst_int(cur); if (!list_member_int(cstate->attnumlist, attnum)) + { + Form_pg_attribute attForm; + + if (SystemAttributeIsWritable(attnum)) + attForm = SystemAttributeDefinition(attnum, true); + else + attForm = tupDesc->attrs[attnum - 1]; + + Assert(attForm != NULL); + ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY", ! NameStr(attForm->attname)))); ! } ! if (SystemAttributeIsWritable(attnum)) ! continue; /* ignore, if specified */ cstate->force_notnull_flags[attnum - 1] = true; } } *************** DoCopyTo(CopyState cstate) *** 1258,1263 **** --- 1303,1311 ---- ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a directory", cstate->filename))); + + /* SELinux checks file:{write} permission */ + sepgsqlCheckFileWrite(fileno(cstate->copy_file), cstate->filename); } PG_TRY(); *************** CopyTo(CopyState cstate) *** 1321,1336 **** int attnum = lfirst_int(cur); Oid out_func_oid; bool isvarlena; if (cstate->binary) ! getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid, &out_func_oid, &isvarlena); else ! getTypeOutputInfo(attr[attnum - 1]->atttypid, &out_func_oid, &isvarlena); ! fmgr_info(out_func_oid, &cstate->out_functions[attnum - 1]); } /* --- 1369,1399 ---- int attnum = lfirst_int(cur); Oid out_func_oid; bool isvarlena; + FmgrInfo *out_fmgr; + Form_pg_attribute attForm; + + switch (attnum) + { + case 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); --- 1448,1461 ---- CopySendChar(cstate, cstate->delim[0]); hdr_delim = true; ! if (SystemAttributeIsWritable(attnum)) ! { ! Form_pg_attribute attForm ! = SystemAttributeDefinition(attnum, true); ! colname = NameStr(attForm->attname); ! } ! else ! colname = NameStr(attr[attnum - 1]->attname); CopyAttributeOutCSV(cstate, colname, false, list_length(cstate->attnumlist) == 1); *************** CopyTo(CopyState cstate) *** 1411,1421 **** { CHECK_FOR_INTERRUPTS(); /* Deconstruct the tuple ... faster than repeated heap_getattr */ heap_deform_tuple(tuple, tupDesc, values, nulls); /* Format and send the data */ ! CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls); } heap_endscan(scandesc); --- 1481,1495 ---- { 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; --- 1515,1522 ---- * 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 --- 1536,1542 ---- { /* 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; } --- 1546,1552 ---- 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) { --- 1555,1565 ---- 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 **** --- 1568,1591 ---- 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); --- 1597,1605 ---- { 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); --- 1608,1614 ---- { bytea *outputbytes; ! outputbytes = SendFunctionCall(out_fmgr, value); CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ); CopySendData(cstate, VARDATA(outputbytes), VARSIZE(outputbytes) - VARHDRSZ); *************** CopyFrom(CopyState cstate) *** 1649,1656 **** --- 1742,1751 ---- num_defaults; FmgrInfo *in_functions; FmgrInfo oid_in_function; + FmgrInfo seclabel_in_function; Oid *typioparams; Oid oid_typioparam; + Oid seclabel_typioparam; int attnum; int i; Oid in_func_oid; *************** CopyFrom(CopyState cstate) *** 1753,1758 **** --- 1848,1856 ---- ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a directory", cstate->filename))); + + /* SELinux checks file:{read} permission */ + sepgsqlCheckFileRead(fileno(cstate->copy_file), cstate->filename); } tupDesc = RelationGetDescr(cstate->rel); *************** CopyFrom(CopyState cstate) *** 1888,1893 **** --- 1986,2003 ---- 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 **** --- 2032,2038 ---- { 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 && --- 2104,2124 ---- /* 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; } --- 2128,2167 ---- 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; } } --- 2207,2247 ---- 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 **** --- 2262,2269 ---- 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 **** --- 2288,2296 ---- } 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 **** --- 3571,3583 ---- } 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); } /* --- 3625,3632 ---- 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 Tue Sep 8 23:55:48 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 = sepgsqlCheckDatabaseCreate(dbname, dseclabel); + /* * Lookup database (template) to be cloned, and obtain share lock on it. * ShareLock allows two CREATE DATABASEs to work from the same template *************** createdb(const CreatedbStmt *stmt) *** 557,562 **** --- 572,579 ---- new_record, new_record_nulls); HeapTupleSetOid(tuple, dboid); + if (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 */ + sepgsqlCheckDatabaseDrop(db_id); + /* * Disallow dropping a DB that is marked istemplate. This is just to * prevent people from accidentally dropping template0 or template1; they *************** dropdb(const char *dbname, bool missing_ *** 829,834 **** --- 852,862 ---- dropDatabaseDependencies(db_id); /* + * Remove pg_security entries for the database. + */ + securityOnDropDatabase(db_id); + + /* * Drop pages for this database that are in the shared buffer cache. This * is important to ensure that no remaining backend tries to write out a * dirty buffer to the dead database later... *************** RenameDatabase(const char *oldname, cons *** 913,918 **** --- 941,949 ---- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to rename database"))); + /* SELinux: check db_database:{setattr} */ + sepgsqlCheckDatabaseSetattr(db_id); + /* * Make sure the new name doesn't exist. See notes for same error in * CREATE DATABASE. *************** movedb(const char *dbname, const char *t *** 1025,1030 **** --- 1056,1064 ---- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname); + /* SELinux checks db_database:{setattr} */ + sepgsqlCheckDatabaseSetattr(db_id); + /* * Obviously can't move the tables of my own database */ *************** AlterDatabase(AlterDatabaseStmt *stmt, b *** 1377,1382 **** --- 1411,1419 ---- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, stmt->dbname); + /* SELinux checks db_database:{setattr} */ + sepgsqlCheckDatabaseSetattr(HeapTupleGetOid(tuple)); + /* * Build an updated tuple, perusing the information just obtained */ *************** AlterDatabaseSet(AlterDatabaseSetStmt *s *** 1449,1454 **** --- 1486,1494 ---- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, stmt->dbname); + /* SELinux checks db_database:{setattr} */ + sepgsqlCheckDatabaseSetattr(HeapTupleGetOid(tuple)); + memset(repl_repl, false, sizeof(repl_repl)); repl_repl[Anum_pg_database_datconfig - 1] = true; *************** AlterDatabaseOwner(const char *dbname, O *** 1571,1576 **** --- 1611,1619 ---- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to change owner of database"))); + /* SELinux checks db_database:{setattr} */ + sepgsqlCheckDatabaseSetattr(HeapTupleGetOid(tuple)); + memset(repl_null, false, sizeof(repl_null)); memset(repl_repl, false, sizeof(repl_repl)); *************** AlterDatabaseOwner(const char *dbname, O *** 1615,1620 **** --- 1658,1715 ---- */ } + /* + * ALTER DATABASE name SECURITY_LABEL [=] newlabel + */ + void + AlterDatabaseSecLabel(const char *dbname, DefElem *seclabel) + { + Relation rel; + HeapTuple oldtup; + HeapTuple newtup; + ScanKeyData scankey; + SysScanDesc scan; + Oid secid; + bool replaces[Natts_pg_database]; + + /* Fetch the old tuple */ + rel = heap_open(DatabaseRelationId, RowExclusiveLock); + ScanKeyInit(&scankey, + Anum_pg_database_datname, + BTEqualStrategyNumber, F_NAMEEQ, + NameGetDatum(dbname)); + scan = systable_beginscan(rel, DatabaseNameIndexId, true, + SnapshotNow, 1, &scankey); + oldtup = systable_getnext(scan); + if (!HeapTupleIsValid(oldtup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist", dbname))); + + memset(replaces, false, sizeof(replaces)); + newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), + NULL, NULL, replaces); + systable_endscan(scan); + + /* check DAC permission */ + if (!pg_database_ownercheck(HeapTupleGetOid(newtup), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname); + + /* SELinux checks db_database:{setattr relabelfrom relabelto} */ + secid = sepgsqlCheckDatabaseRelabel(HeapTupleGetOid(newtup), seclabel); + if (!HeapTupleHasSecid(newtup)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unable to set security label on \"%s\"", dbname))); + 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 Wed Jul 15 19:48:58 2009 *************** *** 27,32 **** --- 27,33 ---- #include "foreign/foreign.h" #include "miscadmin.h" #include "parser/parse_func.h" + #include "security/sepgsql.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" *************** CreateForeignDataWrapper(CreateFdwStmt * *** 380,385 **** --- 381,389 ---- else fdwvalidator = InvalidOid; + /* SELinux checks db_procedure:{install} */ + sepgsqlCheckProcedureInstall(fdwvalidator); + values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = fdwvalidator; nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true; *************** AlterForeignDataWrapper(AlterFdwStmt *st *** 473,478 **** --- 477,485 ---- ereport(WARNING, (errmsg("changing the foreign-data wrapper validator can cause " "the options for dependent objects to become invalid"))); + + /* SELinux checks db_procedure:{install} */ + sepgsqlCheckProcedureInstall(fdwvalidator); } else { diff -Nrpc base/src/backend/commands/functioncmds.c sepgsql/src/backend/commands/functioncmds.c *** base/src/backend/commands/functioncmds.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/commands/functioncmds.c Tue Sep 8 23:55:48 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,1138 ---- aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceOid)); + /* SELinux permission checks */ + sepgsqlCheckProcedureSetattr(procOid); + sepgsqlCheckSchemaRemoveName(namespaceOid); + sepgsqlCheckSchemaAddName(namespaceOid); + /* rename */ namestrcpy(&(procForm->proname), newname); simple_heap_update(rel, &tup->t_self, tup); *************** AlterFunctionOwner_internal(Relation rel *** 1220,1225 **** --- 1241,1248 ---- aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(procForm->pronamespace)); } + /* SELinux permission checks */ + sepgsqlCheckProcedureSetattr(procOid); memset(repl_null, false, sizeof(repl_null)); memset(repl_repl, false, sizeof(repl_repl)); *************** AlterFunctionOwner_internal(Relation rel *** 1258,1263 **** --- 1281,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); + 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 = sepgsqlCheckProcedureRelabel(procOid, seclabel); + if (!HeapTupleHasSecid(newtup)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unable to set security label on \"%s\"", + get_func_name(procOid)))); + 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 */ + sepgsqlCheckProcedureSetattr(funcOid); + if (procForm->proisagg) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), *************** CreateCast(CreateCastStmt *stmt) *** 1580,1585 **** --- 1657,1665 ---- errmsg("cast function must not return a set"))); ReleaseSysCache(tuple); + + /* SELinux checks db_procedure:{install} */ + sepgsqlCheckProcedureInstall(funcid); } else { *************** AlterFunctionNamespace(List *name, List *** 1897,1902 **** --- 1977,1987 ---- NameStr(proc->proname), newschema))); + /* SELinux checks permissions */ + sepgsqlCheckProcedureSetattr(procOid); + sepgsqlCheckSchemaRemoveName(oldNspOid); + sepgsqlCheckSchemaAddName(nspOid); + /* OK, modify the pg_proc row */ /* tup is a copy, so we can scribble directly on it */ diff -Nrpc base/src/backend/commands/lockcmds.c sepgsql/src/backend/commands/lockcmds.c *** base/src/backend/commands/lockcmds.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/commands/lockcmds.c Wed Jul 15 19:35:52 2009 *************** *** 20,25 **** --- 20,26 ---- #include "commands/lockcmds.h" #include "miscadmin.h" #include "parser/parse_clause.h" + #include "security/sepgsql.h" #include "storage/lmgr.h" #include "utils/acl.h" #include "utils/lsyscache.h" *************** LockTableRecurse(Oid reloid, RangeVar *r *** 140,145 **** --- 141,149 ---- errmsg("\"%s\" is not a table", RelationGetRelationName(rel)))); + /* SELinux: check db_table:{lock} permission */ + sepgsqlCheckTableLock(reloid); + /* * If requested, recurse to children. We use find_inheritance_children * not find_all_inheritors to avoid taking locks far in advance of diff -Nrpc base/src/backend/commands/proclang.c sepgsql/src/backend/commands/proclang.c *** base/src/backend/commands/proclang.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/commands/proclang.c Wed Jul 15 19:48:58 2009 *************** *** 30,35 **** --- 30,36 ---- #include "miscadmin.h" #include "parser/gramparse.h" #include "parser/parse_func.h" + #include "security/sepgsql.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/fmgroids.h" *************** CreateProceduralLanguage(CreatePLangStmt *** 151,157 **** NIL, PointerGetDatum(NULL), 1, ! 0); } /* --- 152,159 ---- NIL, PointerGetDatum(NULL), 1, ! 0, ! NULL); } /* *************** CreateProceduralLanguage(CreatePLangStmt *** 186,197 **** NIL, PointerGetDatum(NULL), 1, ! 0); } } else valOid = InvalidOid; /* ok, create it */ create_proc_lang(languageName, GetUserId(), handlerOid, valOid, pltemplate->tmpltrusted); --- 188,204 ---- NIL, PointerGetDatum(NULL), 1, ! 0, ! NULL); } } else valOid = InvalidOid; + /* SELinux checks db_procedure:{install} */ + sepgsqlCheckProcedureInstall(handlerOid); + sepgsqlCheckProcedureInstall(valOid); + /* ok, create it */ create_proc_lang(languageName, GetUserId(), handlerOid, valOid, pltemplate->tmpltrusted); *************** CreateProceduralLanguage(CreatePLangStmt *** 256,261 **** --- 263,272 ---- else valOid = InvalidOid; + /* SELinux checks db_procedure:{install} */ + sepgsqlCheckProcedureInstall(handlerOid); + sepgsqlCheckProcedureInstall(valOid); + /* ok, create it */ create_proc_lang(languageName, GetUserId(), handlerOid, valOid, stmt->pltrusted); diff -Nrpc base/src/backend/commands/schemacmds.c sepgsql/src/backend/commands/schemacmds.c *** base/src/backend/commands/schemacmds.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/commands/schemacmds.c Tue Sep 8 23:55:48 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,85 ---- check_is_member_of_role(saved_uid, owner_uid); + /* SELinux checks db_schema:{create} */ + nspsecid = sepgsqlCheckSchemaCreate(schemaName, (DefElem *)stmt->secLabel, false); + /* Additional check to protect reserved schema names */ if (!allowSystemTableMods && IsReservedName(schemaName)) ereport(ERROR, *************** CreateSchemaCommand(CreateSchemaStmt *st *** 94,100 **** SetUserIdAndContext(owner_uid, true); /* Create the schema's namespace */ ! namespaceId = NamespaceCreate(schemaName, owner_uid); /* Advance cmd counter to make the namespace visible */ CommandCounterIncrement(); --- 99,105 ---- 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, --- 272,278 ---- 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 **** --- 290,298 ---- aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); + /* SELinux checks db_schema:{setattr} */ + sepgsqlCheckSchemaSetattr(HeapTupleGetOid(tup)); + if (!allowSystemTableMods && IsReservedName(newname)) ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), *************** AlterSchemaOwner_internal(HeapTuple tup, *** 397,402 **** --- 404,412 ---- aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); + /* SELinux checks db_schema:{setattr} */ + sepgsqlCheckSchemaSetattr(HeapTupleGetOid(tup)); + memset(repl_null, false, sizeof(repl_null)); memset(repl_repl, false, sizeof(repl_repl)); *************** AlterSchemaOwner_internal(HeapTuple tup, *** 431,433 **** --- 441,489 ---- } } + + /* + * ALTER SCHEMA name SECURITY_LABEL [=] newlabel + */ + void + AlterSchemaSecLabel(const char *name, DefElem *secLabel) + { + Relation rel; + HeapTuple oldtup; + HeapTuple newtup; + Oid secid; + bool replaces[Natts_pg_namespace]; + + /* open pg_namespace relation */ + rel = heap_open(NamespaceRelationId, RowExclusiveLock); + oldtup = SearchSysCache(NAMESPACENAME, + CStringGetDatum(name), + 0, 0, 0); + if (!HeapTupleIsValid(oldtup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", name))); + + memset(replaces, false, sizeof(replaces)); + newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), + NULL, NULL, replaces); + ReleaseSysCache(oldtup); + + /* DAC permission check */ + if (!pg_namespace_ownercheck(HeapTupleGetOid(newtup), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, name); + /* SELinux checks db_schema:{setattr relabelfrom relabelto} */ + secid = sepgsqlCheckSchemaRelabel(HeapTupleGetOid(newtup), secLabel); + if (!HeapTupleHasSecid(newtup)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unable to set security label on \"%s\"", name))); + 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 Wed Jul 15 19:37:35 2009 *************** *** 26,31 **** --- 26,32 ---- #include "commands/tablecmds.h" #include "miscadmin.h" #include "nodes/makefuncs.h" + #include "security/sepgsql.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "storage/proc.h" *************** DefineSequence(CreateSeqStmt *seq) *** 201,206 **** --- 202,208 ---- stmt->options = list_make1(defWithOids(false)); stmt->oncommit = ONCOMMIT_NOOP; stmt->tablespacename = NULL; + stmt->secLabel = seq->secLabel; seqoid = DefineRelation(stmt, RELKIND_SEQUENCE); *************** AlterSequence(AlterSeqStmt *stmt) *** 328,333 **** --- 330,337 ---- if (!pg_class_ownercheck(relid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, stmt->sequence->relname); + /* SELinux checks db_sequence:{setattr} */ + sepgsqlCheckTableSetattr(relid); /* do the work */ AlterSequenceInternal(relid, stmt->options); *************** nextval_internal(Oid relid) *** 467,472 **** --- 471,479 ---- errmsg("permission denied for sequence %s", RelationGetRelationName(seqrel)))); + /* SELinux check db_sequence:{next_value} */ + sepgsqlCheckSequenceNextValue(elm->relid); + if (elm->last != elm->cached) /* some numbers were cached */ { Assert(elm->last_valid); *************** currval_oid(PG_FUNCTION_ARGS) *** 662,667 **** --- 669,677 ---- errmsg("permission denied for sequence %s", RelationGetRelationName(seqrel)))); + /* SELinux check db_sequence:{get_value} */ + sepgsqlCheckSequenceGetValue(elm->relid); + if (!elm->last_valid) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), *************** lastval(PG_FUNCTION_ARGS) *** 706,711 **** --- 716,724 ---- errmsg("permission denied for sequence %s", RelationGetRelationName(seqrel)))); + /* SELinux check db_sequence:{get_value} */ + sepgsqlCheckSequenceGetValue(last_used_seq->relid); + result = last_used_seq->last; relation_close(seqrel, NoLock); *************** do_setval(Oid relid, int64 next, bool is *** 742,747 **** --- 755,763 ---- errmsg("permission denied for sequence %s", RelationGetRelationName(seqrel)))); + /* SELinux check db_sequence:{set_value} */ + sepgsqlCheckSequenceSetValue(elm->relid); + /* lock page' buffer and read tuple */ seq = read_info(elm, seqrel, &buf); diff -Nrpc base/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/tablecmds.c *** base/src/backend/commands/tablecmds.c Sun Sep 6 19:40:49 2009 --- sepgsql/src/backend/commands/tablecmds.c Tue Sep 8 23:55:48 2009 *************** *** 62,67 **** --- 62,68 ---- #include "parser/parser.h" #include "rewrite/rewriteDefine.h" #include "rewrite/rewriteHandler.h" + #include "security/sepgsql.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "storage/smgr.h" *************** DefineRelation(CreateStmt *stmt, char re *** 351,356 **** --- 352,358 ---- List *rawDefaults; List *cookedDefaults; Datum reloptions; + Oid *secLabels; ListCell *listptr; AttrNumber attnum; static char *validnsps[] = HEAP_RELOPT_NAMESPACES; *************** DefineRelation(CreateStmt *stmt, char re *** 444,449 **** --- 446,455 ---- localHasOids = interpretOidsOption(stmt->options); descriptor->tdhasoid = (localHasOids || parentOidCount > 0); + /* SELinux checks db_table:{create} and db_column:{create} */ + secLabels = sepgsqlCreateTableColumns(stmt, relname, namespaceId, + descriptor, relkind); + /* * 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); --- 519,526 ---- parentOidCount, stmt->oncommit, reloptions, ! allowSystemTableMods, ! secLabels); StoreCatalogInheritance(relationId, inheritOids); *************** truncate_check_rel(Relation rel) *** 1042,1047 **** --- 1049,1057 ---- errmsg("permission denied: \"%s\" is a system catalog", RelationGetRelationName(rel)))); + /* SELinux: check db_table:{delete} permission */ + sepgsqlCheckTableTruncate(rel); + /* * We can never allow truncation of shared or nailed-in-cache relations, * because we can't support changing their relfilenode values. *************** renameatt(Oid myrelid, *** 1921,1926 **** --- 1931,1939 ---- errmsg("cannot rename system column \"%s\"", oldattname))); + /* SELinux checks db_column:{setattr} */ + sepgsqlCheckColumnSetattr(myrelid, attnum); + /* * if the attribute is inherited, forbid the renaming, unless we are * already inside a recursive rename. *************** ATRewriteTables(List **wqueue) *** 2850,2857 **** /* * The new relation is local to our transaction and we know * nothing depends on it, so DROP_RESTRICT should be OK. */ ! performDeletion(&object, DROP_RESTRICT); /* performDeletion does CommandCounterIncrement at end */ /* --- 2863,2871 ---- /* * The new relation is local to our transaction and we know * nothing depends on it, so DROP_RESTRICT should be OK. + * SELinux does not apply any permission checks here. */ ! performDeletionNoPerms(&object, DROP_RESTRICT); /* performDeletion does CommandCounterIncrement at end */ /* *************** ATRewriteTable(AlteredTableInfo *tab, Oi *** 3076,3086 **** --- 3090,3103 ---- if (newrel) { Oid tupOid = InvalidOid; + Oid 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 **** --- 3129,3137 ---- /* 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 */ *************** ATSimplePermissions(Relation rel, bool a *** 3242,3247 **** --- 3262,3270 ---- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied: \"%s\" is a system catalog", RelationGetRelationName(rel)))); + + /* SELinux checks db_table:{setattr} */ + sepgsqlCheckTableSetattr(RelationGetRelid(rel)); } /* *************** ATSimplePermissionsRelationOrIndex(Relat *** 3271,3276 **** --- 3294,3302 ---- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied: \"%s\" is a system catalog", RelationGetRelationName(rel)))); + + /* SELinux checks db_table:{setattr} */ + sepgsqlCheckTableSetattr(RelationGetRelid(rel)); } /* *************** ATExecAddColumn(AlteredTableInfo *tab, R *** 3509,3514 **** --- 3535,3541 ---- HeapTuple typeTuple; Oid typeOid; int32 typmod; + Oid attsecid; Form_pg_type tform; Expr *defval; *************** ATExecAddColumn(AlteredTableInfo *tab, R *** 3546,3551 **** --- 3573,3581 ---- errmsg("child table \"%s\" has a conflicting \"%s\" column", RelationGetRelationName(rel), colDef->colname))); + /* SELinux checks db_column:{setattr} */ + sepgsqlCheckColumnSetattr(myrelid, childatt->attnum); + /* Bump the existing child att's inhcount */ childatt->attinhcount++; simple_heap_update(attrdesc, &tuple->t_self, tuple); *************** ATExecAddColumn(AlteredTableInfo *tab, R *** 3585,3590 **** --- 3615,3624 ---- errmsg("column \"%s\" of relation \"%s\" already exists", colDef->colname, RelationGetRelationName(rel)))); + /* SELinux checks db_column:{create} */ + attsecid = sepgsqlCheckColumnCreate(myrelid, colDef->colname, + (DefElem *)colDef->secLabel); + /* Determine the new attribute's number */ if (isOid) newattnum = ObjectIdAttributeNumber; *************** ATExecAddColumn(AlteredTableInfo *tab, R *** 3627,3633 **** ReleaseSysCache(typeTuple); ! InsertPgAttributeTuple(attrdesc, &attribute, NULL); heap_close(attrdesc, RowExclusiveLock); --- 3661,3667 ---- ReleaseSysCache(typeTuple); ! InsertPgAttributeTuple(attrdesc, &attribute, NULL, attsecid); heap_close(attrdesc, RowExclusiveLock); *************** ATExecDropNotNull(Relation rel, const ch *** 3832,3837 **** --- 3866,3874 ---- errmsg("cannot alter system column \"%s\"", colName))); + /* SELinux checks db_column:{setattr} */ + sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attnum); + /* * Check that the attribute is not in a primary key */ *************** ATExecSetNotNull(AlteredTableInfo *tab, *** 3924,3929 **** --- 3961,3969 ---- errmsg("cannot alter system column \"%s\"", colName))); + /* SELinux checks db_column:{setattr} */ + sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attnum); + /* * Okay, actually perform the catalog change ... if needed */ *************** ATExecColumnDefault(Relation rel, const *** 3969,3974 **** --- 4009,4017 ---- errmsg("cannot alter system column \"%s\"", colName))); + /* SELinux checks db_column:{setattr} */ + sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attnum); + /* * Remove any old default for the column. We use RESTRICT here for * safety, but at present we do not expect anything to depend on the *************** ATPrepSetStatistics(Relation rel, const *** 4016,4021 **** --- 4059,4066 ---- if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(rel)); + /* SELinux checks db_table:{setatr} */ + sepgsqlCheckTableSetattr(RelationGetRelid(rel)); } static void *************** ATExecSetStatistics(Relation rel, const *** 4065,4070 **** --- 4110,4118 ---- errmsg("cannot alter system column \"%s\"", colName))); + /* SELinux checks db_column:{setattr} */ + sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attrtuple->attnum); + attrtuple->attstattarget = newtarget; simple_heap_update(attrelation, &tuple->t_self, tuple); *************** ATExecSetStorage(Relation rel, const cha *** 4126,4131 **** --- 4174,4182 ---- errmsg("cannot alter system column \"%s\"", colName))); + /* SELinux checks db_column:{setattr} */ + sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attrtuple->attnum); + /* * safety check: do not allow toasted storage modes unless column datatype * is TOAST-aware. *************** ATExecDropColumn(List **wqueue, Relation *** 4202,4207 **** --- 4253,4261 ---- ReleaseSysCache(tuple); + /* SELinux checks db_column:{drop} */ + sepgsqlCheckColumnDrop(RelationGetRelid(rel), attnum); + /* * Propagate to children as appropriate. Unlike most other ALTER * routines, we have to do this one level of recursion at a time; we can't *************** checkFkeyPermissions(Relation rel, int16 *** 5102,5108 **** aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid, ACL_REFERENCES); if (aclresult == ACLCHECK_OK) ! return; /* Else we must have REFERENCES on each column */ for (i = 0; i < natts; i++) { --- 5156,5162 ---- aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid, ACL_REFERENCES); if (aclresult == ACLCHECK_OK) ! goto ok; /* Else we must have REFERENCES on each column */ for (i = 0; i < natts; i++) { *************** checkFkeyPermissions(Relation rel, int16 *** 5112,5117 **** --- 5166,5174 ---- aclcheck_error(aclresult, ACL_KIND_CLASS, RelationGetRelationName(rel)); } + ok: + /* SELinux: check db_table/db_column:{reference} */ + sepgsqlCheckTableReference(rel, attnums, natts); } /* *************** ATExecAlterColumnType(AlteredTableInfo * *** 5715,5720 **** --- 5772,5780 ---- errmsg("cannot alter type of column \"%s\" twice", colName))); + /* SELinux checks db_column:{setattr} */ + sepgsqlCheckColumnSetattr(RelationGetRelid(rel), attnum); + /* Look up the target type (should not fail, since prep found it) */ typeTuple = typenameType(NULL, typename, &targettypmod); tform = (Form_pg_type) GETSTRUCT(typeTuple); *************** ATExecChangeOwner(Oid relationOid, Oid n *** 6308,6313 **** --- 6368,6375 ---- aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceOid)); } + /* SELinux checks db_table:{setattr} */ + sepgsqlCheckTableSetattr(relationOid); } memset(repl_null, false, sizeof(repl_null)); *************** AlterSeqNamespaces(Relation classRel, Re *** 7762,7767 **** --- 7824,7951 ---- relation_close(depRel, AccessShareLock); } + /* + * ALTER TABLE/SEQUENCE name SECURITY_LABEL [=] newlabel + * ALTER TABLE/SEQUENCE name ALTER column SECURITY_LABEL [=] newlabel + */ + static void + ExecRelationSetSecLabel(Oid relid, DefElem *seclabel) + { + Relation rel; + HeapTuple oldtup; + HeapTuple newtup; + Oid secid; + bool replaces[Natts_pg_class]; + + rel = heap_open(RelationRelationId, RowExclusiveLock); + oldtup = SearchSysCache(RELOID, + ObjectIdGetDatum(relid), + 0, 0, 0); + if (!HeapTupleIsValid(oldtup)) + elog(ERROR, "cache lookup failed for relation: %u", relid); + + memset(replaces, false, sizeof(replaces)); + newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), + NULL, NULL, replaces); + ReleaseSysCache(oldtup); + + /* SELinux checks db_table:{setattr relabelfrom relabelto} */ + secid = sepgsqlCheckTableRelabel(relid, seclabel); + if (!HeapTupleHasSecid(newtup)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unable to set security label on \"%s\"", + get_rel_name(relid)))); + 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); + ReleaseSysCache(oldtup); + + /* SELinux checks db_column:{setattr relabelfrom relabelto} */ + secid = sepgsqlCheckColumnRelabel(relid, attnum, seclabel); + if (!HeapTupleHasSecid(newtup)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unable to set security label on \"%s.%s\"", + get_rel_name(relid), attname))); + 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 Jul 16 17:22:29 2009 *************** *** 33,38 **** --- 33,39 ---- #include "nodes/makefuncs.h" #include "parser/parse_func.h" #include "pgstat.h" + #include "security/sepgsql.h" #include "storage/bufmgr.h" #include "tcop/utility.h" #include "utils/acl.h" *************** CreateTrigger(CreateTrigStmt *stmt, Oid *** 182,187 **** --- 183,191 ---- NameListToString(stmt->funcname)))); } + /* SELinux checks db_procedure:{install} */ + sepgsqlCheckProcedureInstall(funcoid); + /* * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that * references one of the built-in RI_FKey trigger functions, assume it is diff -Nrpc base/src/backend/commands/tsearchcmds.c sepgsql/src/backend/commands/tsearchcmds.c *** base/src/backend/commands/tsearchcmds.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/commands/tsearchcmds.c Wed Jul 15 19:48:58 2009 *************** *** 35,40 **** --- 35,41 ---- #include "miscadmin.h" #include "nodes/makefuncs.h" #include "parser/parse_func.h" + #include "security/sepgsql.h" #include "tsearch/ts_cache.h" #include "tsearch/ts_public.h" #include "tsearch/ts_utils.h" *************** get_ts_parser_func(DefElem *defel, int a *** 110,115 **** --- 111,119 ---- func_signature_string(funcName, nargs, typeId), format_type_be(retTypeId)))); + /* SELinux checks db_procedure:{install} */ + sepgsqlCheckProcedureInstall(procOid); + return ObjectIdGetDatum(procOid); } *************** get_ts_template_func(DefElem *defel, int *** 948,953 **** --- 952,960 ---- func_signature_string(funcName, nargs, typeId), format_type_be(retTypeId)))); + /* SELinux checks db_procedure:{install} */ + sepgsqlCheckProcedureInstall(procOid); + return ObjectIdGetDatum(procOid); } diff -Nrpc base/src/backend/commands/typecmds.c sepgsql/src/backend/commands/typecmds.c *** base/src/backend/commands/typecmds.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/commands/typecmds.c Tue Sep 8 23:55:48 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,1551 ---- /* Check it's a domain and check user has permission for ALTER DOMAIN */ checkDomainOwner(tup, typename); + sepgsqlCheckSysobjSetattr(TypeRelationId, HeapTupleGetSecid(tup), + format_type_be(domainoid)); /* Setup new tuple */ MemSet(new_record, (Datum) 0, sizeof(new_record)); *************** AlterDomainNotNull(List *names, bool not *** 1671,1676 **** --- 1674,1681 ---- /* Check it's a domain and check user has permission for ALTER DOMAIN */ checkDomainOwner(tup, typename); + sepgsqlCheckSysobjSetattr(TypeRelationId, HeapTupleGetSecid(tup), + format_type_be(domainoid)); /* Is the domain already set to the desired constraint? */ if (typTup->typnotnull == notNull) *************** AlterDomainDropConstraint(List *names, c *** 1772,1777 **** --- 1777,1784 ---- /* Check it's a domain and check user has permission for ALTER DOMAIN */ checkDomainOwner(tup, typename); + sepgsqlCheckSysobjSetattr(TypeRelationId, HeapTupleGetSecid(tup), + format_type_be(domainoid)); /* Grab an appropriate lock on the pg_constraint relation */ conrel = heap_open(ConstraintRelationId, RowExclusiveLock); *************** AlterDomainAddConstraint(List *names, No *** 1848,1853 **** --- 1855,1862 ---- /* Check it's a domain and check user has permission for ALTER DOMAIN */ checkDomainOwner(tup, typename); + sepgsqlCheckSysobjSetattr(TypeRelationId, HeapTupleGetSecid(tup), + format_type_be(domainoid)); /* Check for unsupported constraint types */ if (IsA(newConstraint, FkConstraint)) *************** RenameType(List *names, const char *newT *** 2470,2475 **** --- 2479,2490 ---- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, format_type_be(typeOid)); + /* SELinux check permission */ + sepgsqlCheckSysobjSetattr(TypeRelationId, HeapTupleGetSecid(tup), + format_type_be(typeOid)); + sepgsqlCheckSchemaRemoveName(typTup->typnamespace); + sepgsqlCheckSchemaAddName(typTup->typnamespace); + /* * 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 **** --- 2605,2613 ---- aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(typTup->typnamespace)); } + /* SELinux checks permissions */ + sepgsqlCheckSysobjSetattr(TypeRelationId, HeapTupleGetSecid(tup), + format_type_be(HeapTupleGetOid(tup))); /* * If it's a composite type, invoke ATExecChangeOwner so that we fix *************** void *** 2680,2685 **** --- 2698,2704 ---- AlterTypeNamespace(List *names, const char *newschema) { TypeName *typename; + HeapTuple typtup; Oid typeOid; Oid nspOid; Oid elemOid; *************** AlterTypeNamespace(List *names, const ch *** 2706,2711 **** --- 2725,2742 ---- errhint("You can alter type %s, which will alter the array type as well.", format_type_be(elemOid)))); + /* SELinux checks permissions */ + typtup = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typeOid), + 0, 0, 0); + if (!HeapTupleIsValid(typtup)) + elog(ERROR, "cache lookup failed for type: %u", typeOid); + sepgsqlCheckSysobjSetattr(TypeRelationId, HeapTupleGetSecid(typtup), + format_type_be(typeOid)); + sepgsqlCheckSchemaRemoveName(((Form_pg_type) GETSTRUCT(typtup))->typnamespace); + sepgsqlCheckSchemaAddName(nspOid); + ReleaseSysCache(typtup); + /* and do the work */ AlterTypeNamespaceInternal(typeOid, nspOid, false, true); } diff -Nrpc base/src/backend/executor/execJunk.c sepgsql/src/backend/executor/execJunk.c *** base/src/backend/executor/execJunk.c Sat Jan 3 13:01:35 2009 --- sepgsql/src/backend/executor/execJunk.c Wed Jul 15 19:30:50 2009 *************** *** 60,66 **** * An optional resultSlot can be passed as well. */ JunkFilter * ! ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot) { JunkFilter *junkfilter; TupleDesc cleanTupType; --- 60,67 ---- * An optional resultSlot can be passed as well. */ JunkFilter * ! ExecInitJunkFilter(List *targetList, bool hasoid, bool hasseclabel, ! TupleTableSlot *slot) { JunkFilter *junkfilter; TupleDesc cleanTupType; *************** ExecInitJunkFilter(List *targetList, boo *** 72,78 **** /* * Compute the tuple descriptor for the cleaned tuple. */ ! cleanTupType = ExecCleanTypeFromTL(targetList, hasoid); /* * Use the given slot, or make a new slot if we weren't given one. --- 73,79 ---- /* * Compute the tuple descriptor for the cleaned tuple. */ ! cleanTupType = ExecCleanTypeFromTL(targetList, hasoid, hasseclabel); /* * Use the given slot, or make a new slot if we weren't given one. diff -Nrpc base/src/backend/executor/execMain.c sepgsql/src/backend/executor/execMain.c *** base/src/backend/executor/execMain.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/executor/execMain.c Wed Sep 9 16:47:01 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,2991 ---- aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceId)); + /* SELinux checks db_table:{create} and db_column:{create} */ + secLabels = sepgsqlCreateTableColumns(NULL, intoName, namespaceId, + queryDesc->tupDesc, RELKIND_RELATION); + /* * Select tablespace to use. If not specified, use default tablespace * (which may in turn default to database's default). *************** OpenIntoRel(QueryDesc *queryDesc) *** 2929,2935 **** 0, into->onCommit, reloptions, ! allowSystemTableMods); FreeTupleDesc(tupdesc); --- 3044,3051 ---- 0, into->onCommit, reloptions, ! allowSystemTableMods, ! secLabels); FreeTupleDesc(tupdesc); *************** OpenIntoRel(QueryDesc *queryDesc) *** 2956,2961 **** --- 3072,3082 ---- AlterTableCreateToastTable(intoRelationId, InvalidOid, reloptions, false); /* + * SELinux: checks db_table/column:{insert} permission + */ + sepgsqlCheckSelectInto(intoRelationId); + + /* * And open the constructed table for writing. */ intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock); *************** intorel_receive(TupleTableSlot *slot, De *** 3054,3059 **** --- 3175,3184 ---- if (myState->rel->rd_rel->relhasoids) HeapTupleSetOid(tuple, InvalidOid); + storeWritableSystemAttribute(myState->rel, slot, tuple); + /* SELinux checks db_tuple:{insert} */ + sepgsqlHeapTupleInsert(myState->rel, tuple, false); + heap_insert(myState->rel, tuple, myState->estate->es_output_cid, diff -Nrpc base/src/backend/executor/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 Tue Sep 8 17:13:41 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)); + sepgsqlCheckProcedureExecute(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)); + sepgsqlCheckProcedureExecute(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 Mon Sep 7 00:55:45 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)); + sepgsqlCheckProcedureExecute(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)); + sepgsqlCheckProcedureExecute(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)); + sepgsqlCheckProcedureExecute(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 Mon Sep 7 00:55:45 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)); + sepgsqlCheckProcedureExecute(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 Mon Sep 7 00:55:45 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)); + sepgsqlCheckProcedureExecute(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)); + sepgsqlCheckProcedureExecute(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)); + sepgsqlCheckProcedureExecute(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 Wed Jul 15 19:48:58 2009 *************** *** 42,50 **** --- 42,53 ---- #include #include + #include "catalog/pg_largeobject.h" + #include "catalog/pg_security.h" #include "libpq/be-fsstubs.h" #include "libpq/libpq-fs.h" #include "miscadmin.h" + #include "security/sepgsql.h" #include "storage/fd.h" #include "storage/large_object.h" #include "utils/builtins.h" *************** lo_read(int fd, char *buf, int len) *** 156,161 **** --- 159,167 ---- (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("invalid large-object descriptor: %d", fd))); + /* SELinux checks db_blob:{read} */ + sepgsqlCheckBlobRead(cookies[fd]); + status = inv_read(cookies[fd], buf, len); return status; *************** lo_write(int fd, const char *buf, int le *** 177,182 **** --- 183,191 ---- errmsg("large object descriptor %d was not opened for writing", fd))); + /* SELinux checks db_blob:{write} */ + sepgsqlCheckBlobWrite(cookies[fd]); + status = inv_write(cookies[fd], buf, len); return status; *************** lo_import_internal(text *filename, Oid l *** 381,386 **** --- 390,398 ---- */ lobj = inv_open(oid, INV_WRITE, fscxt); + /* SELinux checks db_blob:{write import} and file:{read} */ + sepgsqlCheckBlobImport(lobj, FileRawDescriptor(fd), fnamebuf); + while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0) { tmp = inv_write(lobj, buf, nbytes); *************** lo_export(PG_FUNCTION_ARGS) *** 448,453 **** --- 460,468 ---- errmsg("could not create server file \"%s\": %m", fnamebuf))); + /* SELinux checks db_blob:{read export} and file:{write} */ + sepgsqlCheckBlobExport(lobj, FileRawDescriptor(fd), fnamebuf); + /* * read in from the inversion file and write to the filesystem */ *************** lo_truncate(PG_FUNCTION_ARGS) *** 482,493 **** --- 497,560 ---- (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("invalid large-object descriptor: %d", fd))); + /* SELinux checks db_blob:{write} */ + sepgsqlCheckBlobWrite(cookies[fd]); + inv_truncate(cookies[fd], len); PG_RETURN_INT32(0); } /* + * lo_get_seclabel + * get a security label of large object + */ + Datum + lo_get_security(PG_FUNCTION_ARGS) + { + Oid loid = PG_GETARG_OID(0); + Oid secid; + char *seclabel; + + secid = inv_get_security(loid); + seclabel = securityTransSecLabelOut(LargeObjectRelationId, secid); + + return CStringGetTextDatum(seclabel); + } + + /* + * lo_set_seclabel + * set a security label of large object + */ + Datum + lo_set_security(PG_FUNCTION_ARGS) + { + Oid loid = PG_GETARG_OID(0); + char *seclabel = TextDatumGetCString(PG_GETARG_DATUM(1)); + Oid secid; + + secid = securityTransSecLabelIn(LargeObjectRelationId, seclabel); + + inv_set_security(loid, secid); + + /* + * Also on memory caches to be updated + */ + if (fscxt != NULL) + { + int i; + + for (i = 0; i < cookies_size; i++) + { + if (cookies[i] != NULL && cookies[i]->id == loid) + cookies[i]->secid = secid; + } + } + + PG_RETURN_BOOL(true); + } + + /* * AtEOXact_LargeObject - * prepares large objects for transaction commit */ diff -Nrpc base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfuncs.c *** base/src/backend/nodes/copyfuncs.c Fri Jun 19 13:40:37 2009 --- sepgsql/src/backend/nodes/copyfuncs.c Wed Jul 15 19:39:56 2009 *************** CopyScanFields(Scan *from, Scan *newnode *** 259,264 **** --- 259,265 ---- CopyPlanFields((Plan *) from, (Plan *) newnode); COPY_SCALAR_FIELD(scanrelid); + COPY_SCALAR_FIELD(rowlvPerms); } /* *************** _copyColumnDef(ColumnDef *from) *** 2075,2080 **** --- 2076,2082 ---- COPY_NODE_FIELD(raw_default); COPY_STRING_FIELD(cooked_default); COPY_NODE_FIELD(constraints); + COPY_NODE_FIELD(secLabel); return newnode; } *************** _copyCreateStmt(CreateStmt *from) *** 2414,2419 **** --- 2416,2422 ---- COPY_NODE_FIELD(options); COPY_SCALAR_FIELD(oncommit); COPY_STRING_FIELD(tablespacename); + COPY_NODE_FIELD(secLabel); return newnode; } *************** _copyAlterOwnerStmt(AlterOwnerStmt *from *** 2638,2643 **** --- 2641,2661 ---- return newnode; } + static AlterSecLabelStmt * + _copyAlterSecLabelStmt(AlterSecLabelStmt *from) + { + AlterSecLabelStmt *newnode = makeNode(AlterSecLabelStmt); + + COPY_SCALAR_FIELD(objectType); + COPY_NODE_FIELD(relation); + COPY_NODE_FIELD(object); + COPY_NODE_FIELD(objarg); + COPY_STRING_FIELD(subname); + COPY_NODE_FIELD(secLabel); + + return newnode; + } + static RuleStmt * _copyRuleStmt(RuleStmt *from) { *************** _copyCreateSeqStmt(CreateSeqStmt *from) *** 2887,2892 **** --- 2905,2911 ---- COPY_NODE_FIELD(sequence); COPY_NODE_FIELD(options); + COPY_NODE_FIELD(secLabel); return newnode; } *************** copyObject(void *from) *** 3819,3824 **** --- 3838,3846 ---- case T_AlterOwnerStmt: retval = _copyAlterOwnerStmt(from); break; + case T_AlterSecLabelStmt: + retval = _copyAlterSecLabelStmt(from); + break; case T_RuleStmt: retval = _copyRuleStmt(from); break; diff -Nrpc base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalfuncs.c *** base/src/backend/nodes/equalfuncs.c Fri Jun 19 13:40:37 2009 --- sepgsql/src/backend/nodes/equalfuncs.c Wed Jul 15 19:37:35 2009 *************** _equalCreateStmt(CreateStmt *a, CreateSt *** 1078,1083 **** --- 1078,1084 ---- COMPARE_NODE_FIELD(options); COMPARE_SCALAR_FIELD(oncommit); COMPARE_STRING_FIELD(tablespacename); + COMPARE_NODE_FIELD(secLabel); return true; } *************** _equalAlterOwnerStmt(AlterOwnerStmt *a, *** 1271,1276 **** --- 1272,1290 ---- } static bool + _equalAlterSecLabelStmt(AlterSecLabelStmt *a, AlterSecLabelStmt *b) + { + COMPARE_SCALAR_FIELD(objectType); + COMPARE_NODE_FIELD(relation); + COMPARE_NODE_FIELD(object); + COMPARE_NODE_FIELD(objarg); + COMPARE_STRING_FIELD(subname); + COMPARE_NODE_FIELD(secLabel); + + return true; + } + + static bool _equalRuleStmt(RuleStmt *a, RuleStmt *b) { COMPARE_NODE_FIELD(relation); *************** _equalCreateSeqStmt(CreateSeqStmt *a, Cr *** 1477,1482 **** --- 1491,1497 ---- { COMPARE_NODE_FIELD(sequence); COMPARE_NODE_FIELD(options); + COMPARE_NODE_FIELD(secLabel); return true; } *************** _equalColumnDef(ColumnDef *a, ColumnDef *** 2054,2059 **** --- 2069,2075 ---- COMPARE_NODE_FIELD(raw_default); COMPARE_STRING_FIELD(cooked_default); COMPARE_NODE_FIELD(constraints); + COMPARE_NODE_FIELD(secLabel); return true; } *************** equal(void *a, void *b) *** 2596,2601 **** --- 2612,2620 ---- case T_AlterOwnerStmt: retval = _equalAlterOwnerStmt(a, b); break; + case T_AlterSecLabelStmt: + retval = _equalAlterSecLabelStmt(a, b); + break; case T_RuleStmt: retval = _equalRuleStmt(a, b); break; diff -Nrpc base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs.c *** base/src/backend/nodes/outfuncs.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/nodes/outfuncs.c Wed Jul 15 19:39:56 2009 *************** _outScanInfo(StringInfo str, Scan *node) *** 285,290 **** --- 285,291 ---- _outPlanInfo(str, (Plan *) node); WRITE_UINT_FIELD(scanrelid); + WRITE_UINT_FIELD(rowlvPerms); } /* *************** _outRelOptInfo(StringInfo str, RelOptInf *** 1534,1539 **** --- 1535,1541 ---- WRITE_BOOL_FIELD(has_eclass_joins); WRITE_BITMAPSET_FIELD(index_outer_relids); WRITE_NODE_FIELD(index_inner_paths); + WRITE_UINT_FIELD(rowlvPerms); } static void *************** _outCreateStmt(StringInfo str, CreateStm *** 1717,1722 **** --- 1719,1725 ---- WRITE_NODE_FIELD(options); WRITE_ENUM_FIELD(oncommit, OnCommitAction); WRITE_STRING_FIELD(tablespacename); + WRITE_NODE_FIELD(secLabel); } static void *************** _outColumnDef(StringInfo str, ColumnDef *** 1839,1844 **** --- 1842,1848 ---- WRITE_NODE_FIELD(raw_default); WRITE_STRING_FIELD(cooked_default); WRITE_NODE_FIELD(constraints); + WRITE_NODE_FIELD(secLabel); } static void diff -Nrpc base/src/backend/optimizer/plan/createplan.c sepgsql/src/backend/optimizer/plan/createplan.c *** base/src/backend/optimizer/plan/createplan.c 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 Mon Sep 7 00:55:45 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) || + !sepgsqlHintProcedureInlined(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) || + !sepgsqlHintProcedureInlined(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 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 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 OptTableSpace OptConsTableSpace OptTableSpaceOwner %type opt_check_option + %type OptSecCxt SecCxtItem + %type xml_attribute_el %type xml_attribute_list xml_attributes %type 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 (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 (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 [=] + * + *****************************************************************************/ + + 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/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 Sun Sep 6 19:53:10 2009 *************** *** 108,113 **** --- 108,114 ---- #include "postmaster/pgarch.h" #include "postmaster/postmaster.h" #include "postmaster/syslogger.h" + #include "security/sepgsql.h" #include "storage/fd.h" #include "storage/ipc.h" #include "storage/pg_shmem.h" *************** static pid_t StartupPID = 0, *** 209,215 **** AutoVacPID = 0, PgArchPID = 0, PgStatPID = 0, ! SysLoggerPID = 0; /* Startup/shutdown state */ #define NoShutdown 0 --- 210,217 ---- AutoVacPID = 0, PgArchPID = 0, PgStatPID = 0, ! SysLoggerPID = 0, ! sepgsqlWorkerPID = 0; /* Startup/shutdown state */ #define NoShutdown 0 *************** ServerLoop(void) *** 1436,1441 **** --- 1438,1447 ---- if (PgStatPID == 0 && pmState == PM_RUN) PgStatPID = pgstat_start(); + /* If we have lost the sepgsql worker (if needed), try to start a new one */ + if (sepgsqlWorkerPID == 0 && pmState == PM_RUN) + sepgsqlWorkerPID = sepgsqlStartupWorkerProcess(); + /* If we need to signal the autovacuum launcher, do so now */ if (avlauncher_needs_signal) { *************** SIGHUP_handler(SIGNAL_ARGS) *** 2053,2058 **** --- 2059,2066 ---- signal_child(SysLoggerPID, SIGHUP); if (PgStatPID != 0) signal_child(PgStatPID, SIGHUP); + if (sepgsqlWorkerPID != 0) + signal_child(sepgsqlWorkerPID, SIGHUP); /* Reload authentication config files too */ if (!load_hba()) *************** pmdie(SIGNAL_ARGS) *** 2113,2118 **** --- 2121,2129 ---- /* and the walwriter too */ if (WalWriterPID != 0) signal_child(WalWriterPID, SIGTERM); + /* and the sepgsql worker too */ + if (sepgsqlWorkerPID != 0) + signal_child(sepgsqlWorkerPID, SIGTERM); pmState = PM_WAIT_BACKUP; } *************** pmdie(SIGNAL_ARGS) *** 2160,2165 **** --- 2171,2179 ---- /* and the walwriter too */ if (WalWriterPID != 0) signal_child(WalWriterPID, SIGTERM); + /* and the sepgsqlWorker too */ + if (sepgsqlWorkerPID != 0) + signal_child(sepgsqlWorkerPID, SIGTERM); pmState = PM_WAIT_BACKENDS; } *************** pmdie(SIGNAL_ARGS) *** 2193,2198 **** --- 2207,2214 ---- signal_child(PgArchPID, SIGQUIT); if (PgStatPID != 0) signal_child(PgStatPID, SIGQUIT); + if (sepgsqlWorkerPID != 0) + signal_child(sepgsqlWorkerPID, SIGQUIT); ExitPostmaster(0); break; } *************** reaper(SIGNAL_ARGS) *** 2455,2460 **** --- 2471,2486 ---- continue; } + /* Was it the sepgsql worker process? */ + if (pid == sepgsqlWorkerPID) + { + sepgsqlWorkerPID = 0; + if (!EXIT_STATUS_0(exitstatus)) + LogChildExit(LOG, _("SE-PostgreSQL worker process"), + pid, exitstatus); + continue; + } + /* * Else do standard backend child cleanup. */ *************** HandleChildCrash(int pid, int exitstatus *** 2646,2651 **** --- 2672,2689 ---- signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT)); } + /* Take care of the sepgsql worker too */ + if (pid == sepgsqlWorkerPID) + sepgsqlWorkerPID = 0; + else if (sepgsqlWorkerPID != 0 && !FatalError) + { + ereport(DEBUG2, + (errmsg_internal("sending %s to process %d", + (SendStop ? "SIGSTOP" : "SIGQUIT"), + (int) sepgsqlWorkerPID))); + signal_child(sepgsqlWorkerPID, (SendStop ? SIGSTOP : SIGQUIT)); + } + /* * Force a power-cycle of the pgarch process too. (This isn't absolutely * necessary, but it seems like a good idea for robustness, and it *************** PostmasterStateMachine(void) *** 2778,2784 **** StartupPID == 0 && (BgWriterPID == 0 || !FatalError) && WalWriterPID == 0 && ! AutoVacPID == 0) { if (FatalError) { --- 2816,2823 ---- StartupPID == 0 && (BgWriterPID == 0 || !FatalError) && WalWriterPID == 0 && ! AutoVacPID == 0 && ! sepgsqlWorkerPID == 0) { if (FatalError) { diff -Nrpc base/src/backend/security/Makefile sepgsql/src/backend/security/Makefile *** base/src/backend/security/Makefile Thu Jan 1 09:00:00 1970 --- sepgsql/src/backend/security/Makefile Wed Jul 15 19:39:56 2009 *************** *** 0 **** --- 1,13 ---- + # + # Makefile for the enhanced security subsystem + # + + subdir = src/backend/security + top_builddir = ../../.. + include $(top_builddir)/src/Makefile.global + + SUBDIRS = sepgsql + + OBJS = rowlevel.o + + include $(top_srcdir)/src/backend/common.mk diff -Nrpc base/src/backend/security/rowlevel.c sepgsql/src/backend/security/rowlevel.c *** base/src/backend/security/rowlevel.c Thu Jan 1 09:00:00 1970 --- sepgsql/src/backend/security/rowlevel.c Thu Jul 16 17:22:29 2009 *************** *** 0 **** --- 1,121 ---- + /* + * src/backend/security/common.c + * common facilities for row-level access controls both of DAC and MAC + * + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + */ + #include "postgres.h" + + #include "catalog/pg_security.h" + #include "security/rowlevel.h" + #include "security/sepgsql.h" + #include "storage/bufmgr.h" + #include "storage/bufpage.h" + #include "utils/rel.h" + #include "utils/tqual.h" + + /* + * rowlvGetPerformingMode + * rowlvSetPerformingMode + * enables to control the behavior of row-level features + * when violated tuples are detected. + * The default is ROWLV_FILTER_MODE which filters out + * violated tuples from result set, ROWLV_ABORT_MODE + * raises an error and ROWLV_BYPASS_MODE do nothing. + */ + static int rowlv_mode = ROWLV_FILTER_MODE; + + int rowlvGetPerformingMode(void) + { + return rowlv_mode; + } + + int rowlvSetPerformingMode(int new_mode) + { + int old_mode = new_mode; + + rowlv_mode = new_mode; + + return old_mode; + } + + /* + * rowlvSetupPermissions + * setups permissions for row-level access controls. + */ + uint32 + rowlvSetupPermissions(RangeTblEntry *rte) + { + return sepgsqlSetupTuplePerms(rte); + } + + /* + * rowlvExecScan + * a hook to filter out invisible/untouchable tuples. + */ + static bool + rowlvExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort) + { + HeapTuple tuple; + uint32 perms = scan->rowlvPerms; + + if (!perms) + return true; + + tuple = ExecMaterializeSlot(slot); + + return sepgsqlExecScan(rel, tuple, perms, abort); + } + + bool + rowlvExecScanFilter(Scan *scan, Relation rel, TupleTableSlot *slot) + { + if (!rel || !scan->rowlvPerms || rowlv_mode != ROWLV_FILTER_MODE) + return true; + + return rowlvExecScan(scan, rel, slot, false); + } + + void + rowlvExecScanAbort(Scan *scan, Relation rel, TupleTableSlot *slot) + { + if (!rel || !scan->rowlvPerms || rowlv_mode != ROWLV_ABORT_MODE) + return; + + rowlvExecScan(scan, rel, slot, true); + } + + /* + * rowlvCopyToTuple + * checks permission on fetched tuple + */ + bool + rowlvCopyToTuple(Relation rel, HeapTuple tuple) + { + if (!sepgsqlExecScan(rel, tuple, SEPG_DB_TUPLE__SELECT, false)) + return false; + + return true; + } + + /* + * rowlvHeapTupleInsert + * assign default security attribute, and check permission + * if necessary. + */ + void + rowlvHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal) + { + sepgsqlHeapTupleInsert(rel, newtup, internal); + } + + /* + * rowlvHeapTupleUpdate + * check permission to change security attribute, if necesary + */ + void + rowlvHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup) + { + sepgsqlHeapTupleUpdate(rel, otid, newtup); + } diff -Nrpc base/src/backend/security/sepgsql/Makefile sepgsql/src/backend/security/sepgsql/Makefile *** base/src/backend/security/sepgsql/Makefile Thu Jan 1 09:00:00 1970 --- sepgsql/src/backend/security/sepgsql/Makefile Thu Jul 16 17:22:29 2009 *************** *** 0 **** --- 1,16 ---- + # + # Makefile + # Makefile for utils/sepgsql : SE-PostgreSQL + # + + subdir = src/backend/security/sepgsql + top_builddir = ../../../.. + include $(top_builddir)/src/Makefile.global + + ifeq ($(enable_selinux), yes) + OBJS = avc.o checker.o hooks.o label.o misc.o perms.o + else + OBJS = dummy.o + endif + + include $(top_srcdir)/src/backend/common.mk diff -Nrpc base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security/sepgsql/avc.c *** base/src/backend/security/sepgsql/avc.c Thu Jan 1 09:00:00 1970 --- sepgsql/src/backend/security/sepgsql/avc.c Wed Sep 9 17:45:12 2009 *************** *** 0 **** --- 1,894 ---- + /* + * 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 + #include + #include + + /* + * 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->version = selinux_state->version + 1; + selinux_state->enforcing = (enforce ? true : false); + LWLockRelease(SepgsqlAvcLock); + + return 0; + } + + static int + sepgsql_cb_policyload(int seqno) + { + /* invalidate local avc */ + LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); + selinux_state->version = selinux_state->version + 1; + LWLockRelease(SepgsqlAvcLock); + + return 0; + } + + static int + sepgsqlWorkerMain(void) + { + union selinux_callback cb; + + ClosePostmasterPorts(false); + + on_exit_reset(); + + /* + * map shared memory segment + */ + sepgsqlShmemInit(); + + /* + * setup the signal handler + */ + pqinitmask(); + pqsignal(SIGHUP, SIG_IGN); + pqsignal(SIGINT, SIG_IGN); + pqsignal(SIGTERM, exit); + pqsignal(SIGQUIT, exit); + pqsignal(SIGUSR1, SIG_IGN); + pqsignal(SIGUSR2, SIG_IGN); + pqsignal(SIGCHLD, SIG_DFL); + PG_SETMASK(&UnBlockSig); + + ereport(LOG, + (errcode(ERRCODE_SELINUX_INFO), + errmsg("SELinux: security policy monitor (pid=%u)", getpid()))); + /* + * setup callback functions from avc_netlink_loop() + */ + cb.func_log = sepgsql_cb_log; + selinux_set_callback(SELINUX_CB_LOG, cb); + cb.func_setenforce = sepgsql_cb_setenforce; + selinux_set_callback(SELINUX_CB_SETENFORCE, cb); + cb.func_policyload = sepgsql_cb_policyload; + selinux_set_callback(SELINUX_CB_POLICYLOAD, cb); + + /* + * open netlink socket and wait for messages + */ + avc_netlink_open(1); + + avc_netlink_loop(); + + return 0; + } + + pid_t + sepgsqlStartupWorkerProcess(void) + { + pid_t chld; + + if (!sepgsqlIsEnabled()) + return (pid_t) 0; + + chld = fork(); + if (chld == 0) + exit(sepgsqlWorkerMain()); + else if (chld > 0) + return chld; + + return (pid_t) 0; + } diff -Nrpc base/src/backend/security/sepgsql/checker.c sepgsql/src/backend/security/sepgsql/checker.c *** base/src/backend/security/sepgsql/checker.c Thu Jan 1 09:00:00 1970 --- sepgsql/src/backend/security/sepgsql/checker.c Thu Sep 10 00:06:47 2009 *************** *** 0 **** --- 1,443 ---- + /* + * 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 = sepgsqlGetTupleContext(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 = sepgsqlGetTupleContext(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); + } + + /* + * sepgsqlCheckSelectInto + * It checks db_table/db_column:{insert} on the table newly created + */ + void + sepgsqlCheckSelectInto(Oid relationId) + { + Bitmapset *modified = NULL; + + if (!sepgsqlIsEnabled()) + return; + + modified = bms_add_member(modified, InvalidAttrNumber + - FirstLowInvalidHeapAttributeNumber); + + checkTabelColumnPerms(relationId, NULL, modified, + SEPG_DB_TABLE__INSERT); + } + + /* + * sepgsqlExecScan + * makes a decision on the given tuple. + */ + bool + sepgsqlExecScan(Relation rel, HeapTuple tuple, uint32 required, bool abort) + { + sepgsql_sid_t sid; + uint16 tclass; + + if (!sepgsqlIsEnabled() || + !required || + RelationGetForm(rel)->relkind != RELKIND_RELATION || + RelationGetRelid(rel) == SecurityRelationId) + return true; + + sid = sepgsqlGetTupleContext(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 = sepgsqlGetTupleContext(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 = sepgsqlGetTupleContext(RelationGetRelid(rel), + &oldtup, &tclass); + sepgsqlClientHasPerms(sid, tclass, + SEPG_DB_TUPLE__RELABELFROM, + NULL, true); + + /* db_tuple:{relabelto} for newer security label */ + sid = sepgsqlGetTupleContext(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 Thu Sep 10 00:06:47 2009 *************** *** 0 **** --- 1,1273 ---- + /* + * src/backend/security/sepgsql/hooks.c + * SE-PostgreSQL security hooks + * + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + */ + #include "postgres.h" + + #include "catalog/indexing.h" + #include "catalog/namespace.h" + #include "catalog/pg_database.h" + #include "catalog/pg_foreign_data_wrapper.h" + #include "catalog/pg_language.h" + #include "catalog/pg_largeobject.h" + #include "catalog/pg_namespace.h" + #include "catalog/pg_opclass.h" + #include "catalog/pg_operator.h" + #include "catalog/pg_opfamily.h" + #include "catalog/pg_proc.h" + #include "catalog/pg_security.h" + #include "catalog/pg_trigger.h" + #include "catalog/pg_ts_dict.h" + #include "catalog/pg_ts_parser.h" + #include "catalog/pg_ts_template.h" + #include "catalog/pg_type.h" + #include "catalog/pg_security.h" + #include "commands/dbcommands.h" + #include "miscadmin.h" + #include "security/sepgsql.h" + #include "utils/builtins.h" + #include "utils/fmgroids.h" + #include "utils/lsyscache.h" + #include "utils/syscache.h" + #include "utils/tqual.h" + + /* + * ------------------------------------------------------------ + * Hooks corresponding to db_database object class + * ------------------------------------------------------------ + * + * sepgsqlCheckDatabaseInstallModule + * checks db_database:{install_module} permission when the client + * tries to install a dynamic link library on the current databse. + * + * sepgsqlCheckDatabaseLoadModule + * checks capability of the database when it loads a certain DLL + * into its process address space. + */ + Oid + sepgsqlCheckDatabaseCreate(const char *datname, DefElem *newLabel) + { + sepgsql_sid_t datSid; + + if (!sepgsqlIsEnabled()) + return InvalidOid; + + if (!newLabel) + datSid = sepgsqlGetDefaultDatabaseSecid(); + else + { + datSid.relid = DatabaseRelationId; + datSid.secid = securityTransSecLabelIn(datSid.relid, + strVal(newLabel->arg)); + } + + sepgsqlClientHasPerms(datSid, + SEPG_CLASS_DB_DATABASE, + SEPG_DB_DATABASE__CREATE, + datname, true); + return datSid.secid; + } + + static bool + checkDatabaseCommon(Oid datOid, uint32 required, bool abort) + { + HeapTuple tuple; + sepgsql_sid_t datSid; + uint16 tclass; + const char *auname; + bool rc; + + if (!sepgsqlIsEnabled()) + return true; + + tuple = SearchSysCache(DATABASEOID, + ObjectIdGetDatum(datOid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for database: %u", datOid); + + auname = NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname); + datSid = sepgsqlGetTupleContext(DatabaseRelationId, + tuple, &tclass); + rc = sepgsqlClientHasPerms(datSid, + tclass, required, + auname, abort); + + ReleaseSysCache(tuple); + + return rc; + } + + void + sepgsqlCheckDatabaseDrop(Oid datOid) + { + checkDatabaseCommon(datOid, SEPG_DB_DATABASE__DROP, true); + } + + void + sepgsqlCheckDatabaseSetattr(Oid datOid) + { + checkDatabaseCommon(datOid, SEPG_DB_DATABASE__SETATTR, true); + } + + Oid + sepgsqlCheckDatabaseRelabel(Oid datOid, DefElem *newLabel) + { + sepgsql_sid_t datSid; + + if (!sepgsqlIsEnabled()) + { + if (newLabel) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("SELinux is disabled now"))); + return InvalidOid; + } + datSid.relid = DatabaseRelationId; + datSid.secid = securityTransSecLabelIn(datSid.relid, + strVal(newLabel->arg)); + /* db_database:{setattr relabelfrom} for older seclabel */ + checkDatabaseCommon(datOid, + SEPG_DB_DATABASE__SETATTR | + SEPG_DB_DATABASE__RELABELFROM, true); + /* db_database:{relabelto} for newer seclabel */ + sepgsqlClientHasPerms(datSid, + SEPG_CLASS_DB_DATABASE, + SEPG_DB_DATABASE__RELABELTO, + get_database_name(datOid), true); + return datSid.secid; + } + + void + sepgsqlCheckDatabaseAccess(Oid datOid) + { + if (!checkDatabaseCommon(datOid, SEPG_DB_DATABASE__ACCESS, false)) + ereport(FATAL, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("SELinux: security policy violation"))); + } + + bool + sepgsqlCheckDatabaseSuperuser(void) + { + return checkDatabaseCommon(MyDatabaseId, + SEPG_DB_DATABASE__SUPERUSER, false); + } + + void + sepgsqlCheckDatabaseLoadModule(const char *filename) + { + HeapTuple tuple; + security_context_t filecon; + security_context_t dbcon; + + if (!sepgsqlIsEnabled()) + return; + /* + * It assumes preloaded libraries are secure, + * because it can be set up using guc variable + * not any SQL statements. + */ + if (GetProcessingMode() == InitProcessing) + return; + + /* Get database context */ + tuple = SearchSysCache(DATABASEOID, + ObjectIdGetDatum(MyDatabaseId), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for database: %u", MyDatabaseId); + + dbcon = securityRawSecLabelOut(DatabaseRelationId, + 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(dbcon, + filecon, + SEPG_CLASS_DB_DATABASE, + SEPG_DB_DATABASE__LOAD_MODULE, + filename, true); + } + PG_CATCH(); + { + freecon(filecon); + PG_RE_THROW(); + } + PG_END_TRY(); + freecon(filecon); + } + + /* + * ------------------------------------------------------------ + * Hooks corresponding to db_schema object class + * ------------------------------------------------------------ + */ + + Oid + sepgsqlCheckSchemaCreate(const char *nspName, DefElem *newLabel, bool isTemp) + { + sepgsql_sid_t nspSid; + + if (!sepgsqlIsEnabled()) + return InvalidOid; + + if (!newLabel) + { + nspSid = (!isTemp + ? sepgsqlGetDefaultSchemaSecid(MyDatabaseId) + : sepgsqlGetDefaultSchemaTempSecid(MyDatabaseId)); + } + else + { + nspSid.relid = NamespaceRelationId; + nspSid.secid = securityTransSecLabelIn(nspSid.relid, + strVal(newLabel->arg)); + } + sepgsqlClientHasPerms(nspSid, + (!isTemp + ? SEPG_CLASS_DB_SCHEMA + : SEPG_CLASS_DB_SCHEMA_TEMP), + SEPG_DB_SCHEMA__CREATE, + nspName, true); + return nspSid.secid; + } + + static bool + checkSchemaCommon(Oid nspOid, uint32 required, bool abort) + { + HeapTuple tuple; + sepgsql_sid_t nspSid; + uint16 tclass; + const char *auname; + bool rc; + + if (!sepgsqlIsEnabled()) + return true; + + tuple = SearchSysCache(NAMESPACEOID, + ObjectIdGetDatum(nspOid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for namespace: %u", nspOid); + + nspSid = sepgsqlGetTupleContext(NamespaceRelationId, + tuple, &tclass); + + auname = NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname); + rc = sepgsqlClientHasPerms(nspSid, tclass, required, + auname, abort); + + ReleaseSysCache(tuple); + + return rc; + } + + void + sepgsqlCheckSchemaDrop(Oid nspOid) + { + checkSchemaCommon(nspOid, SEPG_DB_SCHEMA__DROP, true); + } + + void + sepgsqlCheckSchemaSetattr(Oid nspOid) + { + checkSchemaCommon(nspOid, SEPG_DB_SCHEMA__SETATTR, true); + } + + Oid + sepgsqlCheckSchemaRelabel(Oid nspOid, DefElem *newLabel) + { + sepgsql_sid_t nspSid; + + if (!sepgsqlIsEnabled()) + { + if (newLabel) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("SELinux is disabled now"))); + return InvalidOid; + } + nspSid.relid = NamespaceRelationId; + nspSid.secid = securityTransSecLabelIn(nspSid.relid, + strVal(newLabel->arg)); + + /* db_schema:{setattr relabelfrom} for older seclabel */ + checkSchemaCommon(nspOid, + SEPG_DB_SCHEMA__SETATTR | + SEPG_DB_SCHEMA__RELABELFROM, true); + /* db_schema:{relabelto} for newer seclabel */ + sepgsqlClientHasPerms(nspSid, + !isAnyTempNamespace(nspOid) + ? SEPG_CLASS_DB_SCHEMA + : SEPG_CLASS_DB_SCHEMA_TEMP, + SEPG_DB_SCHEMA__RELABELTO, + get_namespace_name(nspOid), true); + return nspSid.secid; + } + + void + sepgsqlCheckSchemaAddName(Oid nspOid) + { + checkSchemaCommon(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); + } + + void + sepgsqlCheckSchemaRemoveName(Oid nspOid) + { + checkSchemaCommon(nspOid, SEPG_DB_SCHEMA__REMOVE_NAME, true); + } + + bool + sepgsqlCheckSchemaSearch(Oid nspOid, bool abort) + { + return checkSchemaCommon(nspOid, SEPG_DB_SCHEMA__SEARCH, abort); + } + + /* ------------------------------------------------------------ * + * Hooks corresponding to db_column object class + * ------------------------------------------------------------ */ + + /* + * NOTE: db_column:{create} is checked on sepgsqlCreateTableColumns() + * which is invoked on CREATE TABLE statement. + * The sepgsqlCheckColumnCreate() is called on the ALTER TABLE + * ... ADD COLUMN path. + */ + Oid + sepgsqlCheckColumnCreate(Oid table_oid, const char *attname, DefElem *newLabel) + { + sepgsql_sid_t attSid; + char relkind; + char auname[NAMEDATALEN * 2 + 3]; + + if (!sepgsqlIsEnabled()) + { + if (newLabel) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("SELinux is disabled now"))); + return InvalidOid; + } + + relkind = get_rel_relkind(table_oid); + if (relkind != RELKIND_RELATION) + { + if (newLabel) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("Unable to assign security label"))); + return InvalidOid; + } + + if (!newLabel) + attSid = sepgsqlGetDefaultColumnSecid(table_oid); + else + { + attSid.relid = AttributeRelationId; + attSid.secid = securityTransSecLabelIn(attSid.relid, + strVal(newLabel->arg)); + } + + sprintf(auname, "%s.%s", get_rel_name(table_oid), attname); + sepgsqlClientHasPerms(attSid, + SEPG_CLASS_DB_COLUMN, + SEPG_DB_COLUMN__CREATE, + auname, true); + return attSid.secid; + } + + static void + checkColumnCommon(Oid relOid, AttrNumber attno, uint32 required) + { + Form_pg_attribute attr; + sepgsql_sid_t attSid; + HeapTuple tuple; + uint16 tclass; + char auname[2 * NAMEDATALEN + 3]; + char relkind; + + if (!sepgsqlIsEnabled()) + return; + + relkind = get_rel_relkind(relOid); + if (relkind != RELKIND_RELATION) + return; + + tuple = SearchSysCache(ATTNUM, + ObjectIdGetDatum(relOid), + Int16GetDatum(attno), + 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for attribute %d of relation %u", + attno, relOid); + + attr = (Form_pg_attribute) GETSTRUCT(tuple); + if (!attr->attisdropped) + { + sprintf(auname, "%s.%s", + get_rel_name(relOid), + NameStr(attr->attname)); + attSid = sepgsqlGetTupleContext(AttributeRelationId, + tuple, &tclass); + sepgsqlClientHasPerms(attSid, tclass, required, + auname, true); + } + + ReleaseSysCache(tuple); + } + + void + sepgsqlCheckColumnDrop(Oid relOid, AttrNumber attno) + { + checkColumnCommon(relOid, attno, SEPG_DB_COLUMN__DROP); + } + + void + sepgsqlCheckColumnSetattr(Oid relOid, AttrNumber attno) + { + checkColumnCommon(relOid, attno, SEPG_DB_COLUMN__SETATTR); + } + + Oid + sepgsqlCheckColumnRelabel(Oid relOid, AttrNumber attno, DefElem *newLabel) + { + sepgsql_sid_t attSid; + 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) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unable to set security label on \"%s.%s\"", + get_rel_name(relOid), + get_attname(relOid, attno)))); + + attSid.relid = AttributeRelationId; + attSid.secid = securityTransSecLabelIn(attSid.relid, + strVal(newLabel->arg)); + + /* db_column:{setattr relabelfrom} for older seclabel */ + checkColumnCommon(relOid, attno, + SEPG_DB_COLUMN__SETATTR | + SEPG_DB_COLUMN__RELABELFROM); + + /* db_column:{relabelto} for newer seclabel */ + sepgsqlClientHasPerms(attSid, + SEPG_CLASS_DB_COLUMN, + SEPG_DB_COLUMN__RELABELTO, + get_attname(relOid, attno), true); + return attSid.secid; + } + + /* ------------------------------------------------------------ * + * Hooks corresponding to db_table object class + * ------------------------------------------------------------ */ + + /* + * NOTE: db_table/db_sequence:{create} permission is checked + * at sepgsqlCreateTableColumns() due to the reason + * for implementation. + * + * sepgsqlCheckTableReference + * checks db_table:{reference} and db_column:{reference} permission + * when the client tries to set up a foreign key constraint on the + * certain tables and columns. + */ + + static void + checkTableCommon(Oid table_oid, access_vector_t required) + { + HeapTuple tuple; + sepgsql_sid_t relSid; + uint16 tclass; + const char *auname; + + if (!sepgsqlIsEnabled()) + return; + + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(table_oid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", table_oid); + + auname = NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname); + relSid = sepgsqlGetTupleContext(RelationRelationId, + tuple, &tclass); + sepgsqlClientHasPerms(relSid, tclass, required, + auname, true); + ReleaseSysCache(tuple); + } + + void + sepgsqlCheckTableDrop(Oid table_oid) + { + checkTableCommon(table_oid, SEPG_DB_TABLE__DROP); + } + + void + sepgsqlCheckTableSetattr(Oid table_oid) + { + checkTableCommon(table_oid, SEPG_DB_TABLE__SETATTR); + } + + Oid + sepgsqlCheckTableRelabel(Oid table_oid, DefElem *newLabel) + { + sepgsql_sid_t relSid; + char relkind; + + if (!sepgsqlIsEnabled()) + { + if (newLabel) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("SELinux is disabled now"))); + return InvalidOid; + } + + relkind = get_rel_relkind(table_oid); + if (relkind != RELKIND_RELATION && relkind != RELKIND_SEQUENCE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unable to set security label on \"%s\"", + get_rel_name(table_oid)))); + + relSid.relid = RelationRelationId; + relSid.secid = securityTransSecLabelIn(relSid.relid, + strVal(newLabel->arg)); + + /* db_table/db_sequence:{setattr relabelfrom} for older seclabel */ + checkTableCommon(table_oid, + SEPG_DB_TABLE__SETATTR | + SEPG_DB_TABLE__RELABELFROM); + + /* db_table/db_sequence:{relabelto} for newer seclabel */ + sepgsqlClientHasPerms(relSid, + (relkind == RELKIND_RELATION + ? SEPG_CLASS_DB_TABLE + : SEPG_CLASS_DB_SEQUENCE), + SEPG_DB_TABLE__RELABELTO, + get_rel_name(table_oid), true); + return relSid.secid; + } + + void + sepgsqlCheckTableLock(Oid table_oid) + { + checkTableCommon(table_oid, SEPG_DB_TABLE__LOCK); + } + + void + sepgsqlCheckTableTruncate(Relation rel) + { + HeapScanDesc scan; + HeapTuple tuple; + sepgsql_sid_t tupSid; + uint16 tclass; + + if (!sepgsqlIsEnabled()) + return; + + /* check db_table:{delete} permission */ + checkTableCommon(RelationGetRelid(rel), SEPG_DB_TABLE__DELETE); + + /* 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) + { + tupSid = sepgsqlGetTupleContext(RelationGetRelid(rel), + tuple, &tclass); + sepgsqlClientHasPerms(tupSid, + tclass, SEPG_DB_TUPLE__DELETE, + NULL, true); + } + heap_endscan(scan); + } + + void + sepgsqlCheckTableReference(Relation rel, int16 *attnums, int natts) + { + int i; + + checkTableCommon(RelationGetRelid(rel), SEPG_DB_TABLE__REFERENCE); + + for (i=0; i < natts; i++) + { + checkColumnCommon(RelationGetRelid(rel), + attnums[i], SEPG_DB_COLUMN__REFERENCE); + } + } + + /* ------------------------------------------------------------ * + * Hooks corresponding to db_sequence object class + * ------------------------------------------------------------ */ + void sepgsqlCheckSequenceGetValue(Oid seqOid) + { + checkTableCommon(seqOid, SEPG_DB_SEQUENCE__GET_VALUE); + } + + void sepgsqlCheckSequenceNextValue(Oid seqOid) + { + checkTableCommon(seqOid, SEPG_DB_SEQUENCE__NEXT_VALUE); + } + + void sepgsqlCheckSequenceSetValue(Oid seqOid) + { + checkTableCommon(seqOid, SEPG_DB_SEQUENCE__SET_VALUE); + } + + /* ------------------------------------------------------------ * + * Hooks corresponding to db_procedure object class + * ------------------------------------------------------------ */ + static bool + checkProcedureCommon(Oid procOid, uint32 required, bool abort) + { + sepgsql_sid_t proSid; + HeapTuple tuple; + uint16 tclass; + const char *auname; + bool rc; + + if (!sepgsqlIsEnabled()) + return true; + + 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); + proSid = sepgsqlGetTupleContext(ProcedureRelationId, + tuple, &tclass); + rc = sepgsqlClientHasPerms(proSid, tclass, required, + auname, abort); + + ReleaseSysCache(tuple); + + return rc; + } + + Oid + sepgsqlCheckProcedureCreate(const char *procName, Oid procOid, + Oid procNsp, Oid procLang, DefElem *newLabel) + { + sepgsql_sid_t proSid; + HeapTuple tuple; + uint32 required; + + if (!sepgsqlIsEnabled()) + return InvalidOid; + + if (!OidIsValid(procOid)) + { + /* create a new function */ + required = SEPG_DB_PROCEDURE__CREATE; + if (!newLabel) + proSid = sepgsqlGetDefaultProcedureSecid(procNsp); + else + { + proSid.relid = ProcedureRelationId; + proSid.secid = securityTransSecLabelIn(proSid.relid, + strVal(newLabel->arg)); + } + } + else if (!newLabel) + { + /* replace an existing function, without any label */ + required = SEPG_DB_PROCEDURE__SETATTR; + tuple = SearchSysCache(PROCOID, + ObjectIdGetDatum(procOid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for procedure: %u", procOid); + + proSid = sepgsqlGetTupleContext(ProcedureRelationId, + tuple, NULL); + ReleaseSysCache(tuple); + } + else + { + /* replace an existing function, with relabeling */ + checkProcedureCommon(procOid, + SEPG_DB_PROCEDURE__SETATTR | + SEPG_DB_PROCEDURE__RELABELFROM, true); + + required = SEPG_DB_PROCEDURE__RELABELTO; + proSid.relid = ProcedureRelationId; + proSid.secid = securityTransSecLabelIn(proSid.relid, + strVal(newLabel->arg)); + } + + /* Procedural language is trusted? */ + tuple = SearchSysCache(LANGOID, + ObjectIdGetDatum(procLang), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for procedural langugage: %u", procLang); + + if (!((Form_pg_language) GETSTRUCT(tuple))->lanpltrusted) + required |= SEPG_DB_PROCEDURE__UNTRUSTED; + + ReleaseSysCache(tuple); + + /* check it */ + sepgsqlClientHasPerms(proSid, + SEPG_CLASS_DB_PROCEDURE, required, + procName, true); + + return proSid.secid; + } + + void + sepgsqlCheckProcedureDrop(Oid procOid) + { + checkProcedureCommon(procOid, SEPG_DB_PROCEDURE__DROP, true); + } + + void + sepgsqlCheckProcedureSetattr(Oid procOid) + { + checkProcedureCommon(procOid, SEPG_DB_PROCEDURE__SETATTR, true); + } + + Oid + sepgsqlCheckProcedureRelabel(Oid procOid, DefElem *newLabel) + { + sepgsql_sid_t proSid; + + if (!sepgsqlIsEnabled()) + { + if (newLabel) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("SELinux is disabled now"))); + return InvalidOid; + } + + proSid.relid = ProcedureRelationId; + proSid.secid = securityTransSecLabelIn(proSid.relid, + strVal(newLabel->arg)); + + /* db_procedure:{setattr relabelfrom} for older seclabel */ + checkProcedureCommon(procOid, + SEPG_DB_PROCEDURE__SETATTR | + SEPG_DB_PROCEDURE__RELABELFROM, true); + /* db_procedure:{relabelto} for newer seclabel */ + sepgsqlClientHasPerms(proSid, + SEPG_CLASS_DB_PROCEDURE, + SEPG_DB_PROCEDURE__RELABELTO, + get_func_name(procOid), true); + return proSid.secid; + } + + void + sepgsqlCheckProcedureExecute(Oid procOid) + { + checkProcedureCommon(procOid, SEPG_DB_PROCEDURE__EXECUTE, true); + } + + /* + * sepgsqlCheckProcedureInstall + * + * It should be checked when a procedure is installed as a part of system + * internal stuff. + */ + void + sepgsqlCheckProcedureInstall(Oid procOid) + { + if (OidIsValid(procOid)) + checkProcedureCommon(procOid, SEPG_DB_PROCEDURE__INSTALL, true); + } + + /* + * sepgsqlHintProcedureInlined + * + * It provides a hint whether the given sql procedure can be inlined, or not. + */ + bool + sepgsqlHintProcedureInlined(HeapTuple protup) + { + security_context_t newcon; + sepgsql_sid_t proSid; + + if (!sepgsqlIsEnabled()) + return true; + + if (!checkProcedureCommon(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. + */ + proSid = sepgsqlGetTupleContext(ProcedureRelationId, + protup, NULL); + + newcon = sepgsqlClientCreateLabel(proSid, 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 + sepgsqlCheckProcedureEntrypoint(FmgrInfo *flinfo, HeapTuple protup) + { + struct TrustedProcedureCache *tcache; + security_context_t newcon; + sepgsql_sid_t proSid; + + if (!sepgsqlIsEnabled()) + return; + + proSid = sepgsqlGetTupleContext(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; + } + + /* + * 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 = sepgsqlGetTupleContext(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 = sepgsqlGetTupleContext(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, + int fdesc, 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} */ + sepgsqlCheckFileWrite(fdesc, filename); + } + + /* + * sepgsqlCheckBlobImport + * check db_blob:{write import} and file:{read} permission + */ + void + sepgsqlCheckBlobImport(LargeObjectDesc *lobj, + int fdesc, 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} */ + sepgsqlCheckFileRead(fdesc, 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 = sepgsqlGetTupleContext(LargeObjectRelationId, oldtup, NULL); + sepgsqlClientHasPerms(loSid, + SEPG_CLASS_DB_BLOB, + required, + NULL, true); + + if ((required & SEPG_DB_BLOB__RELABELFROM) == 0) + return; + + /* db_blob:{relabelto} */ + loSid = sepgsqlGetTupleContext(LargeObjectRelationId, newtup, NULL); + sepgsqlClientHasPerms(loSid, + SEPG_CLASS_DB_BLOB, + SEPG_DB_BLOB__RELABELTO, + NULL, true); + } + + /* + * sepgsqlCheckSysobjCreate + * + * It checks db_tuple:{insert} for system catalog + */ + Oid + sepgsqlCheckSysobjCreate(Oid relid, const char *auditName) + { + sepgsql_sid_t sysSid; + + if (!sepgsqlIsEnabled()) + return InvalidOid; + + sysSid = sepgsqlGetDefaultTupleSecid(relid); + + sepgsqlClientHasPerms(sysSid, + SEPG_CLASS_DB_TUPLE, + SEPG_DB_TUPLE__INSERT, + auditName, true); + + return sysSid.secid; + } + + /* + * sepgsqlCheckSysobjGetattr + * + * It checks db_tuple:{select} for system catalog + */ + void + sepgsqlCheckSysobjGetattr(Oid relid, Oid secid, const char *auditName) + { + sepgsql_sid_t sysSid; + + if (!sepgsqlIsEnabled()) + return; + + sysSid.relid = relid; + sysSid.secid = secid; + sepgsqlClientHasPerms(sysSid, + SEPG_CLASS_DB_TUPLE, + SEPG_DB_TUPLE__SELECT, + auditName, true); + } + + /* + * sepgsqlCheckSysobjSetattr + * + * It checks db_tuple:{update} for system catalog + */ + void + sepgsqlCheckSysobjSetattr(Oid relid, Oid secid, const char *auditName) + { + sepgsql_sid_t sysSid; + + if (!sepgsqlIsEnabled()) + return; + + sysSid.relid = relid; + sysSid.secid = secid; + sepgsqlClientHasPerms(sysSid, + SEPG_CLASS_DB_TUPLE, + SEPG_DB_TUPLE__UPDATE, + auditName, true); + } + + /* + * sepgsqlCheckSysobjDrop + * It checks db_xxx:{drop} permission on the given opaque + * object, invoked from deleteOneObject() + */ + void + sepgsqlCheckSysobjDrop(const ObjectAddress *object) + { + switch (object->classId) + { + case NamespaceRelationId: + sepgsqlCheckSchemaDrop(object->objectId); + break; + + case RelationRelationId: + if (!object->objectSubId) + sepgsqlCheckTableDrop(object->objectId); + else + sepgsqlCheckColumnDrop(object->objectId, object->objectSubId); + break; + + case ProcedureRelationId: + sepgsqlCheckProcedureDrop(object->objectId); + break; + + default: + /* do nothing in this version */ + break; + } + } + + /* + * sepgsqlCheckFileRead + * sepgsqlCheckFileWrite + * check file:{read} or file:{write} permission on the given file, + * and raises an error if violated. + */ + static void + checkFileCommon(int fdesc, const char *filename, access_vector_t perms) + { + security_context_t context; + security_class_t tclass; + + if (!sepgsqlIsEnabled()) + return; + + tclass = sepgsqlFileObjectClass(fdesc); + + if (fgetfilecon_raw(fdesc, &context) < 0) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("SELinux: could not get context of %s", filename))); + PG_TRY(); + { + sepgsqlComputePerms(sepgsqlGetClientLabel(), + context, + tclass, + perms, + filename, true); + } + PG_CATCH(); + { + freecon(context); + PG_RE_THROW(); + } + PG_END_TRY(); + freecon(context); + } + + void + sepgsqlCheckFileRead(int fdesc, const char *filename) + { + checkFileCommon(fdesc, filename, SEPG_FILE__READ); + } + + void + sepgsqlCheckFileWrite(int fdesc, const char *filename) + { + checkFileCommon(fdesc, filename, SEPG_FILE__WRITE); + } 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 Thu Sep 10 15:18:03 2009 *************** *** 0 **** --- 1,1151 ---- + /* + * 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_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); + } + + sepgsql_sid_t + sepgsqlGetDefaultSchemaTempSecid(Oid database_oid) + { + return defaultSecidWithDatabase(NamespaceRelationId, + database_oid, + SEPG_CLASS_DB_SCHEMA_TEMP); + } + + 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) + { + Oid relOid = RelationGetRelid(rel); + Oid nspOid, tblOid; + sepgsql_sid_t newSid; + + if (!sepgsqlIsEnabled()) + return; + + if (!HeapTupleHasSecid(tuple)) + return; + + switch (sepgsqlTupleObjectClass(relOid, tuple)) + { + case SEPG_CLASS_DB_DATABASE: + newSid = sepgsqlGetDefaultDatabaseSecid(); + break; + case SEPG_CLASS_DB_SCHEMA: + newSid = sepgsqlGetDefaultSchemaSecid(MyDatabaseId); + break; + case SEPG_CLASS_DB_SCHEMA_TEMP: + newSid = sepgsqlGetDefaultSchemaTempSecid(MyDatabaseId); + break; + case SEPG_CLASS_DB_TABLE: + nspOid = ((Form_pg_class) GETSTRUCT(tuple))->relnamespace; + newSid = sepgsqlGetDefaultTableSecid(nspOid); + break; + case SEPG_CLASS_DB_SEQUENCE: + nspOid = ((Form_pg_class) GETSTRUCT(tuple))->relnamespace; + newSid = sepgsqlGetDefaultSequenceSecid(nspOid); + break; + case SEPG_CLASS_DB_PROCEDURE: + nspOid = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace; + newSid = sepgsqlGetDefaultProcedureSecid(nspOid); + break; + case SEPG_CLASS_DB_COLUMN: + tblOid = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid; + newSid = sepgsqlGetDefaultColumnSecid(tblOid); + break; + case SEPG_CLASS_DB_BLOB: + newSid = sepgsqlGetDefaultBlobSecid(MyDatabaseId); + break; + default: + newSid = sepgsqlGetDefaultTupleSecid(relOid); + break; + } + + Assert(newSid.relid == relOid); + HeapTupleSetSecid(tuple, newSid.secid); + } + + /* + * sepgsqlCreateTableColumn + * It returns an array of security identifier for the new table + * and columns to be assigned. The corresponding security labels + * are already checked for db_table/db_sequence/db_column:{create} + * permission. + * In the default labeling rule, a column inherits the security + * label of its table, but we cannot refer it using system caches, + * because the command counter is not incremented under the + * heap_create_with_catalog(). Thus, we need to compute and check + * them prior to the actual creation of table and columns. + */ + Oid * + sepgsqlCreateTableColumns(CreateStmt *stmt, + const char *relname, Oid namespace_oid, + TupleDesc tupdesc, char relkind) + { + sepgsql_sid_t relsid; + Oid *secLabels = NULL; + int index; + + if (!sepgsqlIsEnabled()) + return NULL; + + /* + * In the current version, we don't assign any certain security + * labels on relations except for tables/sequences. + */ + if (relkind != RELKIND_RELATION && relkind != RELKIND_SEQUENCE) + return NULL; + + /* + * The secLabels array stores security identifiers to be assigned + * on the new table and columns. + * + * secLabels[0] is security identifier of the table. + * secLabels[attnum - FirstLowInvalidHeapAttributeNumber] + * is security identifier of columns. + */ + secLabels = palloc0(sizeof(Oid) * (tupdesc->natts + - FirstLowInvalidHeapAttributeNumber)); + + /* + * SELinux checks db_table/db_sequence:{create} + */ + switch (relkind) + { + case RELKIND_RELATION: + if (!stmt || !stmt->secLabel) + relsid = sepgsqlGetDefaultTableSecid(namespace_oid); + else + { + relsid.relid = RelationRelationId; + relsid.secid = securityTransSecLabelIn(relsid.relid, + strVal(((DefElem *)stmt->secLabel)->arg)); + } + sepgsqlClientHasPerms(relsid, + SEPG_CLASS_DB_TABLE, + SEPG_DB_TABLE__CREATE, + relname, true); + break; + + case RELKIND_SEQUENCE: + if (!stmt || !stmt->secLabel) + relsid = sepgsqlGetDefaultSequenceSecid(namespace_oid); + else + { + relsid.relid = RelationRelationId; + relsid.secid = securityTransSecLabelIn(relsid.relid, + strVal(((DefElem *)stmt->secLabel)->arg)); + } + sepgsqlClientHasPerms(relsid, + SEPG_CLASS_DB_SEQUENCE, + SEPG_DB_SEQUENCE__CREATE, + relname, true); + break; + + default: + if (stmt && stmt->secLabel) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unable to set security label on \"%s\"", relname))); + relsid = sepgsqlGetDefaultTupleSecid(RelationRelationId); + break; + } + /* table's security identifier to be assigned on */ + secLabels[0] = relsid.secid; + + /* + * SELinux checks db_column:{create} + */ + for (index = FirstLowInvalidHeapAttributeNumber + 1; + index < tupdesc->natts; + index++) + { + Form_pg_attribute attr; + sepgsql_sid_t attsid = { InvalidOid, InvalidOid }; + char attname[NAMEDATALEN * 2 + 3]; + + /* skip unnecessary attributes */ + if (index < 0 && (relkind == RELKIND_VIEW || + relkind == RELKIND_COMPOSITE_TYPE)) + continue; + if (index == ObjectIdAttributeNumber && !tupdesc->tdhasoid) + continue; + + if (index < 0) + attr = SystemAttributeDefinition(index, tupdesc->tdhasoid); + else + attr = tupdesc->attrs[index]; + + /* Is there any given security label? */ + if (stmt) + { + ListCell *l; + + foreach (l, stmt->tableElts) + { + ColumnDef *colDef = lfirst(l); + + if (colDef->secLabel && + strcmp(colDef->colname, NameStr(attr->attname)) == 0) + { + attsid.relid = AttributeRelationId; + attsid.secid = securityTransSecLabelIn(attsid.relid, + strVal(((DefElem *)colDef->secLabel)->arg)); + break; + } + } + } + + switch (relkind) + { + case RELKIND_RELATION: + /* compute default column's label if necessary */ + if (!SidIsValid(attsid)) + attsid = sepgsqlClientCreateSecid(relsid, + SEPG_CLASS_DB_COLUMN, + AttributeRelationId); + + sprintf(attname, "%s.%s", relname, NameStr(attr->attname)); + sepgsqlClientHasPerms(attsid, + SEPG_CLASS_DB_COLUMN, + SEPG_DB_COLUMN__CREATE, + attname, true); + break; + + default: + if (SidIsValid(attsid)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unable to set security label on \"%s.%s\"", + relname, NameStr(attr->attname)))); + attsid = sepgsqlGetDefaultTupleSecid(AttributeRelationId); + break; + } + /* column's security identifier to be assigend on */ + secLabels[index - FirstLowInvalidHeapAttributeNumber] = attsid.secid; + } + return secLabels; + } + + /* + * sepgsqlCopyTableColumns + * It returns an array of security identifier of table and columns + * to be copied on make_new_heap(). It actually create a new temporary + * relation and insert all the tuples within original one into the + * temporary one, but swap_relation_files() swaps their file nodes. + * Thus, there are no changes from the viewpoint of users. + * SE-PostgreSQL also does not check and change anything. It simply + * copies security identifier of the source relation to the destination + * relation. + */ + Oid * + sepgsqlCopyTableColumns(Relation source) + { + HeapTuple tuple; + Oid *secLabels; + Oid relid = RelationGetRelid(source); + int index; + + if (!sepgsqlIsEnabled()) + return PointerGetDatum(NULL); + + /* see the comment at sepgsqlCreateTableColumn*/ + secLabels = palloc0(sizeof(Oid) * (RelationGetDescr(source)->natts + - FirstLowInvalidHeapAttributeNumber)); + + /* copy table's security identifier */ + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(relid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation \"%s\"", + RelationGetRelationName(source)); + + secLabels[0] = HeapTupleGetSecid(tuple); + + ReleaseSysCache(tuple); + + /* copy column's security identifier */ + for (index = FirstLowInvalidHeapAttributeNumber + 1; + index < RelationGetDescr(source)->natts; + index++) + { + Form_pg_attribute attr; + + if (index < 0) + attr = SystemAttributeDefinition(index, true); + else + attr = RelationGetDescr(source)->attrs[index]; + + tuple = SearchSysCache(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attr->attnum), + 0, 0); + if (!HeapTupleIsValid(tuple)) + continue; + + secLabels[index - FirstLowInvalidHeapAttributeNumber] + = HeapTupleGetSecid(tuple); + + ReleaseSysCache(tuple); + } + + return secLabels; + } + + /* + * sepgsqlGetSysobjContext + * + * It returns a pair of relid/secid for the given OID. + */ + static sepgsql_sid_t + getSysobjContextDirect(Oid classOid, Oid indexOid, Oid objectId, uint16 *tclass) + { + sepgsql_sid_t sid = { InvalidOid, InvalidOid }; + 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)) + sid = sepgsqlGetTupleContext(classOid, tup, tclass); + + systable_endscan(scan); + + heap_close(rel, AccessShareLock); + + return sid; + } + + sepgsql_sid_t + sepgsqlGetSysobjContext(Oid classOid, Oid objectId, int32 objsubId, uint16 *tclass) + { + sepgsql_sid_t sid = { InvalidOid, InvalidOid }; + HeapTuple tup = NULL; + + switch (classOid) + { + case AccessMethodRelationId: + tup = SearchSysCache(AMOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case AccessMethodOperatorRelationId: + return getSysobjContextDirect(AccessMethodOperatorRelationId, + AccessMethodOperatorOidIndexId, + objectId, tclass); + + case AccessMethodProcedureRelationId: + return getSysobjContextDirect(AccessMethodProcedureRelationId, + AccessMethodProcedureOidIndexId, + objectId, tclass); + + case AuthIdRelationId: + tup = SearchSysCache(AUTHOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case CastRelationId: + return getSysobjContextDirect(CastRelationId, + CastOidIndexId, + objectId, tclass); + + case ConstraintRelationId: + tup = SearchSysCache(CONSTROID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case ConversionRelationId: + tup = SearchSysCache(CONVOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case DatabaseRelationId: + tup = SearchSysCache(DATABASEOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case ForeignDataWrapperRelationId: + tup = SearchSysCache(FOREIGNDATAWRAPPEROID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case ForeignServerRelationId: + tup = SearchSysCache(FOREIGNSERVEROID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + 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)) + sid = sepgsqlGetTupleContext(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); + } + else + { + classOid = RelationRelationId; + tup = SearchSysCache(RELOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + } + break; + + case NamespaceRelationId: + tup = SearchSysCache(NAMESPACEOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case OperatorClassRelationId: + tup = SearchSysCache(CLAOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case OperatorFamilyRelationId: + tup = SearchSysCache(OPFAMILYOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case OperatorRelationId: + tup = SearchSysCache(OPEROID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case ProcedureRelationId: + tup = SearchSysCache(PROCOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case RewriteRelationId: + return getSysobjContextDirect(RewriteRelationId, + RewriteOidIndexId, + objectId, tclass); + + case TableSpaceRelationId: + return getSysobjContextDirect(TableSpaceRelationId, + TablespaceOidIndexId, + objectId, tclass); + + case TriggerRelationId: + return getSysobjContextDirect(TriggerRelationId, + TriggerOidIndexId, + objectId, tclass); + + case TSConfigRelationId: + tup = SearchSysCache(TSCONFIGOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case TSDictionaryRelationId: + tup = SearchSysCache(TSDICTOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case TSParserRelationId: + tup = SearchSysCache(TSPARSEROID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case TSTemplateRelationId: + tup = SearchSysCache(TSTEMPLATEOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case TypeRelationId: + tup = SearchSysCache(TYPEOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + case UserMappingRelationId: + tup = SearchSysCache(USERMAPPINGOID, + ObjectIdGetDatum(objectId), + 0, 0, 0); + break; + + default: + elog(ERROR, "unexpected class OID: %u", classOid); + break; + } + + if (HeapTupleIsValid(tup)) + { + sid = sepgsqlGetTupleContext(classOid, tup, tclass); + ReleaseSysCache(tup); + } + + return sid; + } + + /* + * sepgsqlGetTupleContext + * + * 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 + sepgsqlGetTupleContext(Oid tableOid, HeapTuple tuple, uint16 *tclass) + { + sepgsql_sid_t sid = { InvalidOid, InvalidOid }; + HeapTuple exttup; + Oid extid; + Oid extcls; + AttrNumber extsub; + + if (tclass) + *tclass = SEPG_CLASS_DB_TUPLE; + + switch (tableOid) + { + case AggregateRelationId: + sid.relid = ProcedureRelationId; + extid = ((Form_pg_aggregate) GETSTRUCT(tuple))->aggfnoid; + exttup = SearchSysCache(PROCOID, + ObjectIdGetDatum(extid), + 0, 0, 0); + break; + + case AccessMethodOperatorRelationId: + sid.relid = OperatorFamilyRelationId; + extid = ((Form_pg_amop) GETSTRUCT(tuple))->amopfamily; + exttup = SearchSysCache(OPFAMILYOID, + ObjectIdGetDatum(extid), + 0, 0, 0); + break; + + case AccessMethodProcedureRelationId: + sid.relid = OperatorFamilyRelationId; + extid = ((Form_pg_amproc) GETSTRUCT(tuple))->amprocfamily; + exttup = SearchSysCache(OPFAMILYOID, + ObjectIdGetDatum(extid), + 0, 0, 0); + break; + + case AttrDefaultRelationId: + sid.relid = AttributeRelationId; + extid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid; + extsub = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum; + exttup = SearchSysCache(ATTNUM, + ObjectIdGetDatum(extid), + Int16GetDatum(extsub), + 0, 0); + break; + + case AuthMemRelationId: + sid.relid = AuthIdRelationId; + extid = ((Form_pg_auth_members) GETSTRUCT(tuple))->roleid; + exttup = SearchSysCache(AUTHOID, + ObjectIdGetDatum(extid), + 0, 0, 0); + break; + + case ConstraintRelationId: + /* CHECK constraint is an attribute of the relation */ + extid = ((Form_pg_constraint) GETSTRUCT(tuple))->conrelid; + if (OidIsValid(extid)) + { + sid.relid = RelationRelationId; + exttup = SearchSysCache(RELOID, + ObjectIdGetDatum(extid), + 0, 0, 0); + 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); + break; + } + /* Database's context for global assertion */ + sid.relid = DatabaseRelationId; + exttup = SearchSysCache(DATABASEOID, + ObjectIdGetDatum(MyDatabaseId), + 0, 0, 0); + break; + + case DescriptionRelationId: + /* recursive call */ + extid = ((Form_pg_description) GETSTRUCT(tuple))->objoid; + extcls = ((Form_pg_description) GETSTRUCT(tuple))->classoid; + return sepgsqlGetSysobjContext(extcls, extid, 0, tclass); + + case EnumRelationId: + sid.relid = TypeRelationId; + extid = ((Form_pg_enum) GETSTRUCT(tuple))->enumtypid; + exttup = SearchSysCache(TYPEOID, + ObjectIdGetDatum(extid), + 0, 0, 0); + break; + + case IndexRelationId: + sid.relid = RelationRelationId; + extid = ((Form_pg_index) GETSTRUCT(tuple))->indexrelid; + exttup = SearchSysCache(RELOID, + ObjectIdGetDatum(extid), + 0, 0, 0); + break; + + case InheritsRelationId: + sid.relid = RelationRelationId; + extid = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrelid; + exttup = SearchSysCache(RELOID, + ObjectIdGetDatum(extid), + 0, 0, 0); + break; + + case RewriteRelationId: + sid.relid = RelationRelationId; + extid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class; + exttup = SearchSysCache(RELOID, + ObjectIdGetDatum(extid), + 0, 0, 0); + break; + + case SharedDescriptionRelationId: + /* recursive invocation */ + extid = ((Form_pg_shdescription) GETSTRUCT(tuple))->objoid; + extcls = ((Form_pg_shdescription) GETSTRUCT(tuple))->classoid; + return sepgsqlGetSysobjContext(extcls, extid, 0, tclass); + + case StatisticRelationId: + sid.relid = AttributeRelationId; + extid = ((Form_pg_statistic) GETSTRUCT(tuple))->starelid; + extsub = ((Form_pg_statistic) GETSTRUCT(tuple))->staattnum; + exttup = SearchSysCache(ATTNUM, + ObjectIdGetDatum(extid), + Int16GetDatum(extsub), + 0, 0); + break; + + case TriggerRelationId: + sid.relid = RelationRelationId; + extid = ((Form_pg_trigger) GETSTRUCT(tuple))->tgrelid; + exttup = SearchSysCache(RELOID, + ObjectIdGetDatum(extid), + 0, 0, 0); + break; + + default: + exttup = tuple; + sid.relid = tableOid; + break; + } + + if (HeapTupleIsValid(exttup)) + { + sid.secid = HeapTupleGetSecid(exttup); + + if (tclass) + *tclass = sepgsqlTupleObjectClass(sid.relid, exttup); + + if (exttup != tuple) + ReleaseSysCache(exttup); + } + 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 = sepgsqlGetTupleContext(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 Sun Sep 6 19:31:39 2009 *************** *** 0 **** --- 1,464 ---- + /* + * src/backend/utils/sepgsql/perms.c + * SE-PostgreSQL permission checks + * + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + */ + #include "postgres.h" + + #include "catalog/pg_database.h" + #include "catalog/pg_proc.h" + #include "catalog/pg_largeobject.h" + #include "catalog/pg_namespace.h" + #include "catalog/pg_type.h" + #include "miscadmin.h" + #include "security/sepgsql.h" + #include "utils/lsyscache.h" + + /* + * Dynamic object class/permissions mapping + * + * SELinux exports the list of object classes and permissions at + * /selinux/class. The libselinux provides an interface to translate + * between their names and codes. + */ + static struct + { + const char *class_name; + security_class_t class_code; + struct + { + const char *perm_name; + access_vector_t perm_code; + } av[sizeof(access_vector_t) * 8]; + } selinux_catalog[] = { + { + "process", SEPG_CLASS_PROCESS, + { + {"translation", SEPG_PROCESS__TRANSITION }, + {NULL, 0} + } + }, + { + "file", SEPG_CLASS_FILE, + { + {"read", SEPG_FILE__READ }, + {"write", SEPG_FILE__WRITE }, + {NULL, 0} + } + }, + { + "dir", SEPG_CLASS_DIR, + { + {"read", SEPG_DIR__READ }, + {"write", SEPG_DIR__WRITE }, + {NULL,0} + } + }, + { + "lnk_file", SEPG_CLASS_LNK_FILE, + { + {"read", SEPG_LNK_FILE__READ }, + {"write", SEPG_LNK_FILE__WRITE }, + {NULL,0} + } + }, + { + "chr_file", SEPG_CLASS_CHR_FILE, + { + {"read", SEPG_CHR_FILE__READ }, + {"write", SEPG_CHR_FILE__WRITE }, + {NULL,0} + } + }, + { + "blk_file", SEPG_CLASS_BLK_FILE, + { + {"read", SEPG_BLK_FILE__READ }, + {"write", SEPG_BLK_FILE__WRITE }, + {NULL,0} + } + }, + { + "sock_file", SEPG_CLASS_SOCK_FILE, + { + {"read", SEPG_SOCK_FILE__READ }, + {"write", SEPG_SOCK_FILE__WRITE }, + {NULL,0} + } + }, + { + "fifo_file", SEPG_CLASS_FIFO_FILE, + { + {"read", SEPG_FIFO_FILE__READ }, + {"write", SEPG_FIFO_FILE__WRITE }, + {NULL, 0UL } + } + }, + { + "db_database", SEPG_CLASS_DB_DATABASE, + { + { "create", SEPG_DB_DATABASE__CREATE }, + { "drop", SEPG_DB_DATABASE__DROP }, + { "getattr", SEPG_DB_DATABASE__GETATTR }, + { "setattr", SEPG_DB_DATABASE__SETATTR }, + { "relabelfrom", SEPG_DB_DATABASE__RELABELFROM }, + { "relabelto", SEPG_DB_DATABASE__RELABELTO }, + { "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_schema_temp", SEPG_CLASS_DB_SCHEMA_TEMP, + { + { "create", SEPG_DB_SCHEMA_TEMP__CREATE }, + { "drop", SEPG_DB_SCHEMA_TEMP__DROP}, + { "getattr", SEPG_DB_SCHEMA_TEMP__GETATTR }, + { "setattr", SEPG_DB_SCHEMA_TEMP__SETATTR }, + { "relabelfrom", SEPG_DB_SCHEMA_TEMP__RELABELFROM }, + { "relabelto", SEPG_DB_SCHEMA_TEMP__RELABELTO }, + { "search", SEPG_DB_SCHEMA_TEMP__SEARCH }, + { "add_name", SEPG_DB_SCHEMA_TEMP__ADD_NAME }, + { "remove_name", SEPG_DB_SCHEMA_TEMP__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(security_class_t tclass) + { + Assert(tclass < SEPG_CLASS_MAX); + + return string_to_security_class(selinux_catalog[tclass].class_name); + } + + /* + * sepgsqlTransToInternalPerms + * It translate the given permission masks into internal representation + * defined as SEPG_(class)_(permission). + */ + extern void + sepgsqlTransToInternalPerms(security_class_t tclass, struct av_decision *avd) + { + security_class_t tclass_ex; + struct av_decision i_avd; + int i, deny_unknown; + + Assert(tclass < SEPG_CLASS_MAX); + + memset(&i_avd, 0, sizeof(struct av_decision)); + + deny_unknown = security_deny_unknown(); + + tclass_ex = sepgsqlTransToExternalClass(tclass); + for (i=0; selinux_catalog[tclass].av[i].perm_name; i++) + { + const char *perm_name = selinux_catalog[tclass].av[i].perm_name; + access_vector_t perm_code = selinux_catalog[tclass].av[i].perm_code; + access_vector_t perm_code_ex; + + perm_code_ex = string_to_av_perm(tclass_ex, perm_name); + if (!perm_code_ex) + { + /* fill up undefined permission */ + if (!deny_unknown) + i_avd.allowed |= perm_code; + i_avd.decided |= perm_code; + i_avd.auditdeny |= perm_code; + continue; + } + + if (avd->allowed & perm_code_ex) + i_avd.allowed |= perm_code; + if (avd->decided & perm_code_ex) + i_avd.decided |= perm_code; + if (avd->auditallow & perm_code_ex) + i_avd.auditallow |= perm_code; + if (avd->auditdeny & perm_code_ex) + i_avd.auditdeny |= perm_code; + } + + avd->allowed = i_avd.allowed; + avd->decided = i_avd.decided; + avd->auditallow = i_avd.auditallow; + avd->auditdeny = i_avd.auditdeny; + } + + /* + * sepgsqlGetClassString + * sepgsqlGetPermissionString + * It returns text representation of object classes/permissions + */ + const char * + sepgsqlGetClassString(uint16 tclass) + { + Assert(tclass < SEPG_CLASS_MAX); + + return selinux_catalog[tclass].class_name; + } + + const char * + sepgsqlGetPermString(uint16 tclass, uint32 permission) + { + int i; + + Assert(tclass < SEPG_CLASS_MAX); + + for (i=0; selinux_catalog[tclass].av[i].perm_name; i++) + { + if (selinux_catalog[tclass].av[i].perm_code == permission) + return selinux_catalog[tclass].av[i].perm_name; + } + return NULL; + } + + /* + * sepgsqlAuditName + * returns an identifier string to generate audit record for + * the given tuple. Please note that its results can indicate + * an address within the given tuple, so we should not refer + * the returned pointer after HeapTuple is released. + */ + const char * + sepgsqlAuditName(Oid relid, HeapTuple tuple) + { + static char buffer[NAMEDATALEN * 2 + 10]; + + switch (relid) + { + case DatabaseRelationId: + return NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname); + + case NamespaceRelationId: + return NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname); + + case RelationRelationId: + return NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname); + + case AttributeRelationId: + if (!IsBootstrapProcessingMode()) + { + Form_pg_attribute attForm + = (Form_pg_attribute) GETSTRUCT(tuple); + char *relname + = get_rel_name(attForm->attrelid); + + if (relname) + { + snprintf(buffer, sizeof(buffer), "%s.%s", + relname, NameStr(attForm->attname)); + pfree(relname); + return buffer; + } + } + return NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname); + + case ProcedureRelationId: + return NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname); + } + return NULL; + } + + /* + * sepgsqlFileObjectClass + * + * It returns proper object class of filesystem object already opened. + * It is necessary to check privileges voluntarily. + */ + security_class_t + sepgsqlFileObjectClass(int fdesc) + { + struct stat stbuf; + + if (fstat(fdesc, &stbuf) != 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not stat file descriptor: %d", fdesc))); + + if (S_ISDIR(stbuf.st_mode)) + return SEPG_CLASS_DIR; + else if (S_ISCHR(stbuf.st_mode)) + return SEPG_CLASS_CHR_FILE; + else if (S_ISBLK(stbuf.st_mode)) + return SEPG_CLASS_BLK_FILE; + else if (S_ISFIFO(stbuf.st_mode)) + return SEPG_CLASS_FIFO_FILE; + else if (S_ISLNK(stbuf.st_mode)) + return SEPG_CLASS_LNK_FILE; + else if (S_ISSOCK(stbuf.st_mode)) + return SEPG_CLASS_SOCK_FILE; + + return SEPG_CLASS_FILE; + } + + /* + * sepgsqlTupleObjectClass + * + * It returns correct object class of given tuple + */ + security_class_t + sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple) + { + Form_pg_namespace nspForm; + Form_pg_class clsForm; + Form_pg_attribute attForm; + + switch (relid) + { + case DatabaseRelationId: + return SEPG_CLASS_DB_DATABASE; + + case NamespaceRelationId: + nspForm = (Form_pg_namespace) GETSTRUCT(tuple); + if (strncmp(NameStr(nspForm->nspname), "pg_temp_", 8) == 0 || + strncmp(NameStr(nspForm->nspname), "pg_toast_temp_", 14) == 0) + return SEPG_CLASS_DB_SCHEMA_TEMP; + return SEPG_CLASS_DB_SCHEMA; + + case RelationRelationId: + clsForm = (Form_pg_class) GETSTRUCT(tuple); + if (clsForm->relkind == RELKIND_RELATION) + return SEPG_CLASS_DB_TABLE; + if (clsForm->relkind == RELKIND_SEQUENCE) + return SEPG_CLASS_DB_SEQUENCE; + break; + + case AttributeRelationId: + attForm = (Form_pg_attribute) GETSTRUCT(tuple); + if (IsBootstrapProcessingMode() && + (attForm->attrelid == TypeRelationId || + attForm->attrelid == ProcedureRelationId || + attForm->attrelid == AttributeRelationId || + attForm->attrelid == RelationRelationId)) + return SEPG_CLASS_DB_COLUMN; + + if (get_rel_relkind(attForm->attrelid) == RELKIND_RELATION) + return SEPG_CLASS_DB_COLUMN; + break; + + case ProcedureRelationId: + return SEPG_CLASS_DB_PROCEDURE; + + case LargeObjectRelationId: + return SEPG_CLASS_DB_BLOB; + } + return SEPG_CLASS_DB_TUPLE; + } diff -Nrpc base/src/backend/security/sepgsql/policy/Makefile sepgsql/src/backend/security/sepgsql/policy/Makefile *** base/src/backend/security/sepgsql/policy/Makefile Thu Jan 1 09:00:00 1970 --- sepgsql/src/backend/security/sepgsql/policy/Makefile Wed Jul 15 19:35:52 2009 *************** *** 0 **** --- 1,28 ---- + # + # Makefile for SE-PostgreSQL security policy module + # + top_builddir = ../../../../.. + include $(top_builddir)/src/Makefile.global + + POLICY_BASEDIR := $(DESTDIR)/usr/share/selinux + POLICY_MAKEFILE := $(POLICY_BASEDIR)/devel/Makefile + POLICY_INSTDIR := $(POLICY_BASEDIR)/packages + PREFIX_RULE := "s/%%__prefix__%%/$(shell echo $(prefix)|sed 's/\//\\\//g')/g" + BINDIR_RULE := "s/%%__bindir__%%/$(shell echo $(bindir)|sed 's/\//\\\//g')/g" + LIBDIR_RULE := "s/%%__libdir__%%/$(shell echo $(pkglibdir)|sed 's/\//\\\//g')/g" + + all: sepostgresql-devel.pp + + install: all + test -d $(POLICY_INSTDIR) || mkdir -p $(POLICY_INSTDIR) + install -p -m 0644 sepostgresql-devel.pp $(POLICY_INSTDIR) + + sepostgresql-devel.pp: sepostgresql-devel.te sepostgresql-devel.fc + $(MAKE) -f $(POLICY_MAKEFILE) + + sepostgresql-devel.fc: sepostgresql-devel.fc.template + cat $< | sed -e $(PREFIX_RULE) -e $(BINDIR_RULE) -e $(LIBDIR_RULE) > $@ + + clean: + $(MAKE) -f $(POLICY_MAKEFILE) clean + rm -f *.fc diff -Nrpc base/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template *** base/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template Thu Jan 1 09:00:00 1970 --- sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template Wed Jul 15 19:35:52 2009 *************** *** 0 **** --- 1,12 ---- + # + # SE-PostgreSQL install path + # + %%__prefix__%%(/.*)? -- gen_context(system_u:object_r:usr_t,s0) + + %%__bindir__%%/(se)?postgres -- gen_context(system_u:object_r:postgresql_exec_t,s0) + %%__bindir__%%/(se)?pg_ctl -- gen_context(system_u:object_r:initrc_exec_t,s0) + %%__bindir__%%/initdb(\.sepgsql)? -- gen_context(system_u:object_r:postgresql_exec_t,s0) + %%__bindir__%%(/.*)? -- gen_context(system_u:object_r:bin_t,s0) + + %%__libdir__%%(/.*)? -- gen_context(system_u:object_r:lib_t,s0) + diff -Nrpc base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te *** base/src/backend/security/sepgsql/policy/sepostgresql-devel.te Thu Jan 1 09:00:00 1970 --- sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te Thu Sep 10 15:43:44 2009 *************** *** 0 **** --- 1,121 ---- + policy_module(sepostgresql-devel, 3.28) + + gen_require(` + class db_database all_db_database_perms; + class db_table all_db_table_perms; + class db_procedure all_db_procedure_perms; + class db_column all_db_column_perms; + class db_tuple all_db_tuple_perms; + class db_blob all_db_blob_perms; + + attribute sepgsql_client_type; + attribute sepgsql_unconfined_type; + + attribute sepgsql_database_type; + attribute sepgsql_table_type; + attribute sepgsql_sysobj_table_type; + attribute sepgsql_procedure_type; + attribute sepgsql_blob_type; + attribute sepgsql_module_type; + + # for regression test + type bin_t; + type user_home_t; + type sepgsql_trusted_proc_t; + + attribute tmpfile; + attribute ptynode; + ') + + ################################# + # + # Domain for Testcases + # + + role sepgsql_test_r; + + userdom_unpriv_user_template(sepgsql_test) + postgresql_role(sepgsql_test_r, sepgsql_test_t) + + allow sepgsql_test_t tmpfile : dir search_dir_perms; + allow sepgsql_test_t tmpfile : file rw_file_perms; + allow sepgsql_test_t ptynode : chr_file rw_file_perms; + + optional_policy(` + gen_require(` + type unconfined_t; + role unconfined_r; + ') + + tunable_policy(`sepgsql_regression_test_mode',` + allow unconfined_t sepgsql_test_t : process transition; + ') + allow sepgsql_test_t unconfined_t : fifo_file read_file_perms; + role unconfined_r types sepgsql_test_t; + role unconfined_r types sepgsql_trusted_proc_t; + ') + + ################################# + # + # SE-PostgreSQL Declarations + # + + ## + ##

+ ## Allow to generate auditallow logs + ##

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

+ ## Allow to generate auditdeny logs + ##

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

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

+ ##
+ gen_tunable(sepgsql_regression_test_mode, false) + + ######################################## + # + # SE-PostgreSQL audit switch for debugging + # + tunable_policy(`sepgsql_enable_auditallow',` + auditallow domain sepgsql_database_type : db_database *; + auditallow domain sepgsql_table_type : db_table *; + auditallow domain sepgsql_table_type : db_column *; + auditallow domain sepgsql_table_type : db_tuple { relabelfrom relabelto }; + auditallow domain sepgsql_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 Mon Sep 7 00:55:45 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)); + sepgsqlCheckSchemaSearch(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)); + sepgsqlCheckProcedureExecute(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 Wed Jul 15 19:48:58 2009 *************** *** 24,29 **** --- 24,30 ---- #include "funcapi.h" #include "miscadmin.h" #include "postmaster/syslogger.h" + #include "security/sepgsql.h" #include "storage/fd.h" #include "utils/builtins.h" #include "utils/memutils.h" *************** pg_read_file(PG_FUNCTION_ARGS) *** 105,110 **** --- 106,114 ---- errmsg("could not open file \"%s\" for reading: %m", filename))); + /* SELinux: check file:{read} permission */ + sepgsqlCheckFileRead(fileno(file), filename); + if (fseeko(file, (off_t) seek_offset, (seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0) ereport(ERROR, diff -Nrpc base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/adt/ri_triggers.c *** base/src/backend/utils/adt/ri_triggers.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/utils/adt/ri_triggers.c Wed Jul 15 19:39:56 2009 *************** *** 39,44 **** --- 39,45 ---- #include "parser/parse_coerce.h" #include "parser/parse_relation.h" #include "miscadmin.h" + #include "security/rowlevel.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/fmgroids.h" *************** RI_Initial_Check(Trigger *trigger, Relat *** 2627,2632 **** --- 2628,2634 ---- const char *sep; int i; int old_work_mem; + int save_rowlv; char workmembuf[32]; int spi_result; SPIPlanPtr qplan; *************** RI_Initial_Check(Trigger *trigger, Relat *** 2759,2764 **** --- 2761,2771 ---- SPI_result, querybuf.data); /* + * Disables the Row-level stuff during the internal consistency checks. + */ + save_rowlv = rowlvSetPerformingMode(ROWLV_BYPASS_MODE); + + /* * Run the plan. For safety we force a current snapshot to be used. (In * serializable mode, this arguably violates serializability, but we * really haven't got much choice.) We don't need to register the *************** RI_Initial_Check(Trigger *trigger, Relat *** 2771,2776 **** --- 2778,2786 ---- InvalidSnapshot, true, false, 1); + /* Restore Row-level stuff */ + rowlvSetPerformingMode(save_rowlv); + /* Check result */ if (spi_result != SPI_OK_SELECT) elog(ERROR, "SPI_execute_snapshot returned %d", spi_result); *************** ri_PerformCheck(RI_QueryKey *qkey, SPIPl *** 3264,3269 **** --- 3274,3280 ---- int spi_result; Oid save_userid; bool save_secdefcxt; + int save_rowlv, temp_rowlv; Datum vals[RI_MAX_NUMKEYS * 2]; char nulls[RI_MAX_NUMKEYS * 2]; *************** ri_PerformCheck(RI_QueryKey *qkey, SPIPl *** 3346,3357 **** --- 3357,3375 ---- GetUserIdAndContext(&save_userid, &save_secdefcxt); SetUserIdAndContext(RelationGetForm(query_rel)->relowner, true); + /* Switch Row-level stuff behavior on FK checks, if necessary */ + temp_rowlv = (detectNewRows ? ROWLV_ABORT_MODE : ROWLV_FILTER_MODE); + save_rowlv = rowlvSetPerformingMode(temp_rowlv); + /* Finally we can run the query. */ spi_result = SPI_execute_snapshot(qplan, vals, nulls, test_snapshot, crosscheck_snapshot, false, false, limit); + /* Restore Row-level stuff behavior */ + rowlvSetPerformingMode(save_rowlv); + /* Restore UID */ SetUserIdAndContext(save_userid, save_secdefcxt); diff -Nrpc base/src/backend/utils/adt/trigfuncs.c sepgsql/src/backend/utils/adt/trigfuncs.c *** base/src/backend/utils/adt/trigfuncs.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/utils/adt/trigfuncs.c 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 Sun Sep 6 19:53:10 2009 *************** *** 23,28 **** --- 23,29 ---- #endif #include "lib/stringinfo.h" #include "miscadmin.h" + #include "security/sepgsql.h" #include "utils/dynamic_loader.h" #include "utils/hsearch.h" *************** load_external_function(char *filename, c *** 109,114 **** --- 110,118 ---- /* Expand the possibly-abbreviated filename to an exact path name */ fullname = expand_dynamic_library_name(filename); + /* SELinux checks db_database:{load_module} */ + sepgsqlCheckDatabaseLoadModule(fullname); + /* Load the shared library, unless we already did */ lib_handle = internal_load_library(fullname); *************** load_file(const char *filename, bool res *** 149,154 **** --- 153,161 ---- /* Expand the possibly-abbreviated filename to an exact path name */ fullname = expand_dynamic_library_name(filename); + /* SELinux checks db_database:{load_module} */ + sepgsqlCheckDatabaseLoadModule(fullname); + /* Unload the library if currently loaded */ internal_unload_library(fullname); diff -Nrpc base/src/backend/utils/fmgr/fmgr.c sepgsql/src/backend/utils/fmgr/fmgr.c *** base/src/backend/utils/fmgr/fmgr.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/backend/utils/fmgr/fmgr.c Wed Jul 15 19:35:52 2009 *************** *** 24,29 **** --- 24,30 ---- #include "miscadmin.h" #include "nodes/nodeFuncs.h" #include "pgstat.h" + #include "security/sepgsql.h" #include "utils/builtins.h" #include "utils/fmgrtab.h" #include "utils/guc.h" *************** fmgr_info_cxt_security(Oid functionId, F *** 289,294 **** --- 290,296 ---- } finfo->fn_oid = functionId; + sepgsqlCheckProcedureEntrypoint(finfo, procedureTuple); ReleaseSysCache(procedureTuple); } diff -Nrpc base/src/backend/utils/init/postinit.c sepgsql/src/backend/utils/init/postinit.c *** base/src/backend/utils/init/postinit.c Sun Sep 6 19:40:49 2009 --- sepgsql/src/backend/utils/init/postinit.c Mon Sep 7 00:55:45 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} */ + sepgsqlCheckDatabaseAccess(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 Thu Sep 10 00:06:47 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,102 ---- # 0 selects the system default #tcp_keepalives_count = 0 # TCP_KEEPCNT; # 0 selects the system default ! #sepostgresql = off # SE-PostgreSQL support ! sepostgresql = on #------------------------------------------------------------------------------ # RESOURCE USAGE (except WAL) diff -Nrpc base/src/backend/utils/misc/superuser.c sepgsql/src/backend/utils/misc/superuser.c *** base/src/backend/utils/misc/superuser.c Sat Jan 3 13:01:35 2009 --- sepgsql/src/backend/utils/misc/superuser.c Wed Jul 15 19:35:52 2009 *************** *** 21,26 **** --- 21,27 ---- #include "postgres.h" #include "catalog/pg_authid.h" + #include "security/sepgsql.h" #include "utils/inval.h" #include "utils/syscache.h" #include "miscadmin.h" *************** superuser_arg(Oid roleid) *** 60,70 **** /* Quick out for cache hit */ if (OidIsValid(last_roleid) && last_roleid == roleid) ! return last_roleid_is_super; /* Special escape path in case you deleted all your users. */ if (!IsUnderPostmaster && roleid == BOOTSTRAP_SUPERUSERID) ! return true; /* OK, look up the information in pg_authid */ rtup = SearchSysCache(AUTHOID, --- 61,77 ---- /* Quick out for cache hit */ if (OidIsValid(last_roleid) && last_roleid == roleid) ! { ! result = last_roleid_is_super; ! goto out; ! } /* Special escape path in case you deleted all your users. */ if (!IsUnderPostmaster && roleid == BOOTSTRAP_SUPERUSERID) ! { ! result = true; ! goto out; ! } /* OK, look up the information in pg_authid */ rtup = SearchSysCache(AUTHOID, *************** superuser_arg(Oid roleid) *** 94,99 **** --- 101,110 ---- last_roleid = roleid; last_roleid_is_super = result; + out: + if (result) + result = sepgsqlCheckDatabaseSuperuser(); + return result; } diff -Nrpc base/src/bin/initdb/initdb.c sepgsql/src/bin/initdb/initdb.c *** base/src/bin/initdb/initdb.c Thu Jun 18 10:20:52 2009 --- sepgsql/src/bin/initdb/initdb.c Wed Jul 15 19:35:52 2009 *************** static bool debug = false; *** 87,92 **** --- 87,93 ---- static bool noclean = false; static bool show_setting = false; static char *xlog_dir = ""; + static bool enable_selinux = false; /* internal vars */ *************** setup_config(void) *** 1205,1210 **** --- 1206,1218 ---- "#default_text_search_config = 'pg_catalog.simple'", repltok); + if (enable_selinux) + { + strcpy(repltok, "sepostgresql = on"); + conflines = replace_token(conflines, + "#sepostgresql = off", repltok); + } + snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); writefile(path, conflines); *************** usage(const char *progname) *** 2443,2448 **** --- 2451,2457 ---- printf(_(" -U, --username=NAME database superuser name\n")); printf(_(" -W, --pwprompt prompt for a password for the new superuser\n")); printf(_(" -X, --xlogdir=XLOGDIR location for the transaction log directory\n")); + printf(_(" --enable-selinux enables SELinux support, if compiled\n")); printf(_("\nLess commonly used options:\n")); printf(_(" -d, --debug generate lots of debugging output\n")); printf(_(" -L DIRECTORY where to find the input files\n")); *************** main(int argc, char *argv[]) *** 2478,2483 **** --- 2487,2493 ---- {"auth", required_argument, NULL, 'A'}, {"pwprompt", no_argument, NULL, 'W'}, {"pwfile", required_argument, NULL, 9}, + {"enable-selinux", no_argument, NULL, 10}, {"username", required_argument, NULL, 'U'}, {"help", no_argument, NULL, '?'}, {"version", no_argument, NULL, 'V'}, *************** main(int argc, char *argv[]) *** 2594,2599 **** --- 2604,2612 ---- case 9: pwfilename = xstrdup(optarg); break; + case 10: + enable_selinux = true; + break; case 's': show_setting = true; break; diff -Nrpc base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c *** base/src/bin/pg_dump/pg_dump.c 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/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_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 header file. */ #undef HAVE_SECURITY_PAM_APPL_H + /* Define to 1 if you enable SELinux support */ + #undef HAVE_SELINUX + /* Define to 1 if you have the `setproctitle' function. */ #undef HAVE_SETPROCTITLE diff -Nrpc base/src/include/security/rowlevel.h sepgsql/src/include/security/rowlevel.h *** base/src/include/security/rowlevel.h Thu Jan 1 09:00:00 1970 --- sepgsql/src/include/security/rowlevel.h Thu Jul 16 17:22:29 2009 *************** *** 0 **** --- 1,44 ---- + /* + * src/include/security/rowlevel.h + * Definition of the facility of row-level access controls + * + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + */ + #ifndef ROWLEVEL_H + #define ROWLEVEL_H + + #include "access/htup.h" + #include "executor/tuptable.h" + #include "nodes/plannodes.h" + #include "utils/relcache.h" + + #define ROWLV_BYPASS_MODE 1 + #define ROWLV_FILTER_MODE 2 + #define ROWLV_ABORT_MODE 3 + + extern int + rowlvGetPerformingMode(void); + + extern int + rowlvSetPerformingMode(int mode); + + extern uint32 + rowlvSetupPermissions(RangeTblEntry *rte); + + extern bool + rowlvExecScanFilter(Scan *scan, Relation rel, TupleTableSlot *slot); + + extern void + rowlvExecScanAbort(Scan *scan, Relation rel, TupleTableSlot *slot); + + extern void + rowlvHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal); + + extern void + rowlvHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup); + + extern bool + rowlvCopyToTuple(Relation rel, HeapTuple tuple); + + #endif /* ROWLEVEL_H */ diff -Nrpc base/src/include/security/sepgsql.h sepgsql/src/include/security/sepgsql.h *** base/src/include/security/sepgsql.h Thu Jan 1 09:00:00 1970 --- sepgsql/src/include/security/sepgsql.h Thu Sep 10 15:18:03 2009 *************** *** 0 **** --- 1,534 ---- + /* + * 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 + + /* GUC parameter to turn on/off SE-PostgreSQL */ + extern bool sepostgresql_is_enabled; + + /* GUC parameter to turn on/off Row-level controls */ + extern bool sepostgresql_row_level; + + /* GUC parameter to turn on/off mcstrans */ + extern bool sepostgresql_use_mcstrans; + + /* Objject classes and permissions internally used */ + enum SepgsqlClasses + { + SEPG_CLASS_PROCESS = 0, + SEPG_CLASS_FILE, + SEPG_CLASS_DIR, + SEPG_CLASS_LNK_FILE, + SEPG_CLASS_CHR_FILE, + SEPG_CLASS_BLK_FILE, + SEPG_CLASS_SOCK_FILE, + SEPG_CLASS_FIFO_FILE, + SEPG_CLASS_DB_DATABASE, + SEPG_CLASS_DB_SCHEMA, + SEPG_CLASS_DB_SCHEMA_TEMP, + SEPG_CLASS_DB_TABLE, + SEPG_CLASS_DB_SEQUENCE, + SEPG_CLASS_DB_PROCEDURE, + SEPG_CLASS_DB_COLUMN, + SEPG_CLASS_DB_TUPLE, + SEPG_CLASS_DB_BLOB, + SEPG_CLASS_MAX, + }; + + #define SEPG_PROCESS__TRANSITION (1<<0) + + #define SEPG_FILE__READ (1<<0) + #define SEPG_FILE__WRITE (1<<1) + + #define SEPG_DIR__READ (SEPG_FILE__READ) + #define SEPG_DIR__WRITE (SEPG_FILE__WRITE) + + #define SEPG_LNK_FILE__READ (SEPG_FILE__READ) + #define SEPG_LNK_FILE__WRITE (SEPG_FILE__WRITE) + + #define SEPG_CHR_FILE__READ (SEPG_FILE__READ) + #define SEPG_CHR_FILE__WRITE (SEPG_FILE__WRITE) + + #define SEPG_BLK_FILE__READ (SEPG_FILE__READ) + #define SEPG_BLK_FILE__WRITE (SEPG_FILE__WRITE) + + #define SEPG_SOCK_FILE__READ (SEPG_FILE__READ) + #define SEPG_SOCK_FILE__WRITE (SEPG_FILE__WRITE) + + #define SEPG_FIFO_FILE__READ (SEPG_FILE__READ) + #define SEPG_FIFO_FILE__WRITE (SEPG_FILE__WRITE) + + #define SEPG_DB_DATABASE__CREATE (1<<0) + #define SEPG_DB_DATABASE__DROP (1<<1) + #define SEPG_DB_DATABASE__GETATTR (1<<2) + #define SEPG_DB_DATABASE__SETATTR (1<<3) + #define SEPG_DB_DATABASE__RELABELFROM (1<<4) + #define SEPG_DB_DATABASE__RELABELTO (1<<5) + #define SEPG_DB_DATABASE__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_SCHEMA_TEMP__CREATE (SEPG_DB_DATABASE__CREATE) + #define SEPG_DB_SCHEMA_TEMP__DROP (SEPG_DB_DATABASE__DROP) + #define SEPG_DB_SCHEMA_TEMP__GETATTR (SEPG_DB_DATABASE__GETATTR) + #define SEPG_DB_SCHEMA_TEMP__SETATTR (SEPG_DB_DATABASE__SETATTR) + #define SEPG_DB_SCHEMA_TEMP__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) + #define SEPG_DB_SCHEMA_TEMP__RELABELTO (SEPG_DB_DATABASE__RELABELTO) + #define SEPG_DB_SCHEMA_TEMP__SEARCH (SEPG_DB_SCHEMA__SEARCH) + #define SEPG_DB_SCHEMA_TEMP__ADD_NAME (SEPG_DB_SCHEMA__ADD_NAME) + #define SEPG_DB_SCHEMA_TEMP__REMOVE_NAME (SEPG_DB_SCHEMA__REMOVE_NAME) + + #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 pid_t sepgsqlStartupWorkerProcess(void); + + /* + * checker.c : check permission on given queries + */ + extern void + sepgsqlCheckRTEPerms(RangeTblEntry *rte); + + extern void + sepgsqlCheckCopyTable(Relation rel, List *attnumlist, bool is_from); + + extern void + sepgsqlCheckSelectInto(Oid relaionId); + + extern bool + sepgsqlExecScan(Relation rel, HeapTuple tuple, uint32 required, bool abort); + + extern uint32 + sepgsqlSetupTuplePerms(RangeTblEntry *rte); + + extern void + sepgsqlHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal); + + extern void + sepgsqlHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup); + + /* + * core.c : core facilities + */ + extern security_context_t + sepgsqlGetServerLabel(void); + + extern security_context_t + sepgsqlGetClientLabel(void); + + extern security_context_t + sepgsqlSwitchClient(security_context_t new_client); + + extern bool + sepgsqlIsEnabled(void); + + extern void + sepgsqlInitialize(void); + + /* + * hooks.c : routines to check certain permissions + */ + extern Oid + sepgsqlCheckDatabaseCreate(const char *datname, DefElem *newLabel); + extern void + sepgsqlCheckDatabaseDrop(Oid datOid); + extern void + sepgsqlCheckDatabaseSetattr(Oid datOid); + extern Oid + sepgsqlCheckDatabaseRelabel(Oid datOid, DefElem *newLlabel); + extern void + sepgsqlCheckDatabaseAccess(Oid datOid); + extern bool + sepgsqlCheckDatabaseSuperuser(void); + extern void + sepgsqlCheckDatabaseLoadModule(const char *filename); + + extern Oid + sepgsqlCheckSchemaCreate(const char *nspName, DefElem *new_label, bool isTemp); + extern void + sepgsqlCheckSchemaDrop(Oid nspOid); + extern void + sepgsqlCheckSchemaSetattr(Oid nspOid); + extern Oid + sepgsqlCheckSchemaRelabel(Oid nspOid, DefElem *new_label); + extern void + sepgsqlCheckSchemaAddName(Oid nspOid); + extern void + sepgsqlCheckSchemaRemoveName(Oid nspOid); + extern bool + sepgsqlCheckSchemaSearch(Oid nspOid, bool abort); + + extern void + sepgsqlCheckTableDrop(Oid table_oid); + extern void + sepgsqlCheckTableSetattr(Oid table_oid); + extern Oid + sepgsqlCheckTableRelabel(Oid table_oid, DefElem *new_label); + extern void + sepgsqlCheckTableLock(Oid table_oid); + extern void + sepgsqlCheckTableTruncate(Relation rel); + extern void + sepgsqlCheckTableReference(Relation rel, int16 *attnums, int natts); + + extern void + sepgsqlCheckSequenceGetValue(Oid seqOid); + extern void + sepgsqlCheckSequenceNextValue(Oid seqOid); + extern void + sepgsqlCheckSequenceSetValue(Oid seqOid); + + extern Oid + sepgsqlCheckColumnCreate(Oid relOid, const char *attname, DefElem *newLabel); + extern void + sepgsqlCheckColumnDrop(Oid relOid, AttrNumber attno); + extern void + sepgsqlCheckColumnSetattr(Oid relOid, AttrNumber attno); + extern Oid + sepgsqlCheckColumnRelabel(Oid relOid, AttrNumber attno, DefElem *newLabel); + + extern Oid + sepgsqlCheckProcedureCreate(const char *procName, Oid procOid, + Oid procNsp, Oid procLang, DefElem *newLabel); + extern void + sepgsqlCheckProcedureDrop(Oid procOid); + extern void + sepgsqlCheckProcedureSetattr(Oid procOid); + extern Oid + sepgsqlCheckProcedureRelabel(Oid procOid, DefElem *newLabel); + extern void + sepgsqlCheckProcedureExecute(Oid procOid); + extern void + sepgsqlCheckProcedureInstall(Oid procOid); + extern bool + sepgsqlHintProcedureInlined(HeapTuple protup); + extern void + sepgsqlCheckProcedureEntrypoint(FmgrInfo *flinfo, HeapTuple protup); + + extern void + sepgsqlCheckBlobCreate(Relation rel, HeapTuple lotup); + extern void + sepgsqlCheckBlobDrop(Relation rel, HeapTuple lotup); + extern void + sepgsqlCheckBlobRead(LargeObjectDesc *lobj); + extern void + sepgsqlCheckBlobWrite(LargeObjectDesc *lobj); + extern void + sepgsqlCheckBlobGetattr(HeapTuple tuple); + extern void + sepgsqlCheckBlobSetattr(HeapTuple tuple); + extern void + sepgsqlCheckBlobExport(LargeObjectDesc *lobj, + int fdesc, const char *filename); + extern void + sepgsqlCheckBlobImport(LargeObjectDesc *lobj, + int fdesc, const char *filename); + extern void + sepgsqlCheckBlobRelabel(HeapTuple oldtup, HeapTuple newtup); + + extern void + sepgsqlCheckFileRead(int fdesc, const char *filename); + extern void + sepgsqlCheckFileWrite(int fdesc, const char *filename); + + extern Oid + sepgsqlCheckSysobjCreate(Oid relid, const char *auditName); + extern void + sepgsqlCheckSysobjGetattr(Oid relid, Oid secid, const char *auditName); + extern void + sepgsqlCheckSysobjSetattr(Oid relid, Oid secid, const char *auditName); + extern void + sepgsqlCheckSysobjDrop(const ObjectAddress *object); + + /* + * 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 + sepgsqlGetTupleContext(Oid tableOid, HeapTuple tuple, uint16 *tclass); + extern sepgsql_sid_t + sepgsqlGetSysobjContext(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 const char *sepgsqlAuditName(Oid relid, HeapTuple tuple); + + extern security_class_t sepgsqlFileObjectClass(int fdesc); + + extern security_class_t sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple); + + extern security_class_t sepgsqlTransToExternalClass(security_class_t tclass_in); + + extern void sepgsqlTransToInternalPerms(security_class_t tclass_ex, + struct av_decision *avd); + extern const char *sepgsqlGetClassString(uint16 tclass); + extern const char *sepgsqlGetPermString(uint16 tclass, uint32 permission); + + #else /* HAVE_SELINUX */ + + /* avc.c */ + #define sepgsqlShmemSize() (0) + #define sepgsqlStartupWorkerProcess() (0) + + /* checker.c */ + #define sepgsqlCheckRTEPerms(a) do {} while(0) + #define sepgsqlCheckCopyTable(a,b,c) do {} while(0) + #define sepgsqlCheckSelectInto(a) do {} while(0) + #define sepgsqlExecScan(a,b,c) (true) + #define sepgsqlSetupTuplePerms(a) (0) + #define sepgsqlHeapTupleInsert(a,b,c) do {} while(0) + #define sepgsqlHeapTupleUpdate(a,b,c) do {} while(0) + + /* core.c */ + #define sepgsqlIsEnabled() (false) + #define sepgsqlInitialize() do {} while(0) + + /* hooks.c */ + #define sepgsqlCheckDatabaseCreate(a,b) (InvalidOid) + #define sepgsqlCheckDatabaseDrop(a) do {} while(0) + #define sepgsqlCheckDatabaseSetattr(a) do {} while(0) + #define sepgsqlCheckDatabaseRelabel(a,b) (InvalidOid) + #define sepgsqlCheckDatabaseAccess(a) (true) + #define sepgsqlCheckDatabaseSuperuser() (true) + #define sepgsqlCheckDatabaseLoadModule(a) do {} while(0) + + #define sepgsqlCheckSchemaCreate(a,b,c) (InvalidOid) + #define sepgsqlCheckSchemaDrop(a) do {} while(0) + #define sepgsqlCheckSchemaSetattr(a) do {} while(0) + #define sepgsqlCheckSchemaRelabel(a,b) (InvalidOid) + #define sepgsqlCheckSchemaAddName(a) do {} while(0) + #define sepgsqlCheckSchemaRemoveName(a) do {} while(0) + #define sepgsqlCheckSchemaSearch(a,b) (true) + + #define sepgsqlCheckTableDrop(a) do {} while(0) + #define sepgsqlCheckTableSetattr(a) do {} while(0) + #define sepgsqlCheckTableRelabel(a,b) (InvalidOid) + #define sepgsqlCheckTableLock(a) do {} while(0) + #define sepgsqlCheckTableTruncate(a) do {} while(0) + #define sepgsqlCheckTableReference(a,b,c) do {} while(0) + + #define sepgsqlCheckSequenceGetValue(a) do {} while(0) + #define sepgsqlCheckSequenceNextValue(a) do {} while(0) + #define sepgsqlCheckSequenceSetValue(a) do {} while(0) + + #define sepgsqlCheckColumnCreate(a,b,c) (InvalidOid) + #define sepgsqlCheckColumnDrop(a,b) do {} while(0) + #define sepgsqlCheckColumnSetattr(a,b) do {} while(0) + #define sepgsqlCheckColumnRelabel(a,b,c) (InvalidOid) + + #define sepgsqlCheckProcedureCreate(a,b,c,d) (InvalidOid) + #define sepgsqlCheckProcedureDrop(a) do {} while(0) + #define sepgsqlCheckProcedureSetattr(a) do {} while(0) + #define sepgsqlCheckProcedureRelabel(a,b) (InvalidOid) + #define sepgsqlCheckProcedureExecute(a) (true) + #define sepgsqlCheckProcedureInstall(a) do {} while(0) + #define sepgsqlHintProcedureInlined(a) (true) + #define sepgsqlCheckProcedureEntrypoint(a,b) do {} while(0) + + #define sepgsqlCheckBlobCreate(a,b) do {} while(0) + #define sepgsqlCheckBlobDrop(a,b) do {} while(0) + #define sepgsqlCheckBlobRead(a) do {} while(0) + #define sepgsqlCheckBlobWrite(a) do {} while(0) + #define sepgsqlCheckBlobGetattr(a) do {} while(0) + #define sepgsqlCheckBlobSetattr(a) do {} while(0) + #define sepgsqlCheckBlobExport(a,b,c) do {} while(0) + #define sepgsqlCheckBlobImport(a,b,c) do {} while(0) + #define sepgsqlCheckBlobRelabel(a,b) do {} while(0) + #define sepgsqlCheckFileRead(a,b) do {} while(0) + #define sepgsqlCheckFileWrite(a,b) do {} while(0) + + #define sepgsqlCheckSysobjCreate(a,b) (InvalidOid) + #define sepgsqlCheckSysobjGetattr(a,b,c) do {} while(0) + #define sepgsqlCheckSysobjSetattr(a,b,c) do {} while(0) + #define sepgsqlCheckSysobjDrop(a) do {} while(0) + + /* label.c */ + #define sepgsqlTupleDescHasSecLabel(a,b) (false) + #define sepgsqlSetDefaultSecLabel(a,b) do {} while(0) + #define sepgsqlCreateTableColumns(a,b,c,d,e) (NULL) + #define sepgsqlCopyTableColumns(a) (NULL) + #define sepgsqlMetaSecurityLabel() (NULL) + #define sepgsqlTransSecLabelIn(a) (a) + #define sepgsqlTransSecLabelOut(a) (a) + #define sepgsqlRawSecLabelIn(a) (a) + #define sepgsqlRawSecLabelOut(a) (a) + + #endif /* HAVE_SELINUX */ + + extern Datum sepgsql_getcon(PG_FUNCTION_ARGS); + extern Datum sepgsql_server_getcon(PG_FUNCTION_ARGS); + extern Datum sepgsql_get_user(PG_FUNCTION_ARGS); + extern Datum sepgsql_get_role(PG_FUNCTION_ARGS); + extern Datum sepgsql_get_type(PG_FUNCTION_ARGS); + extern Datum sepgsql_get_range(PG_FUNCTION_ARGS); + extern Datum sepgsql_set_user(PG_FUNCTION_ARGS); + extern Datum sepgsql_set_role(PG_FUNCTION_ARGS); + extern Datum sepgsql_set_type(PG_FUNCTION_ARGS); + extern Datum sepgsql_set_range(PG_FUNCTION_ARGS); + + #endif /* SEPGSQL_H */ diff -Nrpc base/src/include/storage/fd.h sepgsql/src/include/storage/fd.h *** base/src/include/storage/fd.h Tue Jan 13 09:22:28 2009 --- sepgsql/src/include/storage/fd.h Wed Jul 15 19:48:58 2009 *************** extern int FileWrite(File file, char *bu *** 68,73 **** --- 68,74 ---- extern int FileSync(File file); extern off_t FileSeek(File file, off_t offset, int whence); extern int FileTruncate(File file, off_t offset); + extern int FileRawDescriptor(File file); /* Operations that allow use of regular stdio --- USE WITH CAUTION */ extern FILE *AllocateFile(const char *name, const char *mode); diff -Nrpc base/src/include/storage/large_object.h sepgsql/src/include/storage/large_object.h *** base/src/include/storage/large_object.h Sat Jan 3 12:25:21 2009 --- sepgsql/src/include/storage/large_object.h Wed Jul 15 19:48:58 2009 *************** typedef struct LargeObjectDesc *** 44,49 **** --- 44,50 ---- #define IFS_RDLOCK (1 << 0) #define IFS_WRLOCK (1 << 1) + Oid secid; /* security identifier of largeobject */ } LargeObjectDesc; *************** extern int inv_tell(LargeObjectDesc *obj *** 79,83 **** --- 80,86 ---- extern int inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes); extern int inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes); extern void inv_truncate(LargeObjectDesc *obj_desc, int len); + extern Oid inv_get_security(Oid loid); + extern void inv_set_security(Oid loid, Oid secid); #endif /* LARGE_OBJECT_H */ diff -Nrpc base/src/include/storage/lwlock.h sepgsql/src/include/storage/lwlock.h *** base/src/include/storage/lwlock.h Fri Mar 6 09:45:33 2009 --- sepgsql/src/include/storage/lwlock.h Wed Jul 15 19:35:52 2009 *************** typedef enum LWLockId *** 67,72 **** --- 67,73 ---- AutovacuumLock, AutovacuumScheduleLock, SyncScanLock, + SepgsqlAvcLock, /* Individual lock IDs end here */ FirstBufMappingLock, FirstLockMgrLock = FirstBufMappingLock + NUM_BUFFER_PARTITIONS, diff -Nrpc base/src/include/utils/errcodes.h sepgsql/src/include/utils/errcodes.h *** base/src/include/utils/errcodes.h Fri Mar 6 09:45:33 2009 --- sepgsql/src/include/utils/errcodes.h Wed Jul 15 19:35:52 2009 *************** *** 347,352 **** --- 347,357 ---- #define ERRCODE_NO_DATA_FOUND MAKE_SQLSTATE('P','0', '0','0','2') #define ERRCODE_TOO_MANY_ROWS MAKE_SQLSTATE('P','0', '0','0','3') + /* Class SE - SE-PostgreSQL Error */ + #define ERRCODE_SELINUX_ERROR MAKE_SQLSTATE('S','E', '0','0','1') + #define ERRCODE_SELINUX_AUDIT MAKE_SQLSTATE('S','E', '0','0','2') + #define ERRCODE_SELINUX_INFO MAKE_SQLSTATE('S','E', '0','0','3') + /* Class XX - Internal Error (PostgreSQL-specific error class) */ /* (this is for "can't-happen" conditions and software bugs) */ #define ERRCODE_INTERNAL_ERROR MAKE_SQLSTATE('X','X', '0','0','0') diff -Nrpc base/src/include/utils/syscache.h sepgsql/src/include/utils/syscache.h *** base/src/include/utils/syscache.h Sat Jan 3 12:25:21 2009 --- sepgsql/src/include/utils/syscache.h 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/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