8585 lines
268 KiB
Diff
8585 lines
268 KiB
Diff
diff -rpNU3 base/configure.in sepgsql/configure.in
|
|
--- base/configure.in 2007-10-25 07:40:55.000000000 +0900
|
|
+++ sepgsql/configure.in 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -539,6 +539,19 @@ PGAC_ARG_BOOL(with, zlib, yes,
|
|
AC_SUBST(with_zlib)
|
|
|
|
#
|
|
+# NSA SELinux support
|
|
+#
|
|
+PGAC_ARG_BOOL(enable, selinux, no,
|
|
+ [ --enable-selinux build with NSA SELinux support])
|
|
+if test "$enable_selinux" = yes; then
|
|
+ AC_CHECK_LIB(selinux, getpeercon,
|
|
+ AC_DEFINE(SECURITY_SYSATTR_NAME, "security_context")
|
|
+ AC_DEFINE_UNQUOTED(HAVE_SELINUX, 1)
|
|
+ AC_SUBST(enable_selinux),
|
|
+ AC_MSG_ERROR("libselinux didn't found."))
|
|
+fi
|
|
+
|
|
+#
|
|
# Elf
|
|
#
|
|
|
|
diff -rpNU3 base/src/Makefile.global.in sepgsql/src/Makefile.global.in
|
|
--- base/src/Makefile.global.in 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/Makefile.global.in 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -159,6 +159,7 @@ enable_nls = @enable_nls@
|
|
enable_debug = @enable_debug@
|
|
enable_dtrace = @enable_dtrace@
|
|
enable_thread_safety = @enable_thread_safety@
|
|
+enable_selinux = @enable_selinux@
|
|
|
|
python_includespec = @python_includespec@
|
|
python_libdir = @python_libdir@
|
|
diff -rpNU3 base/src/backend/Makefile sepgsql/src/backend/Makefile
|
|
--- base/src/backend/Makefile 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/Makefile 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -15,7 +15,7 @@ include $(top_builddir)/src/Makefile.glo
|
|
|
|
DIRS := access bootstrap catalog parser commands executor lib libpq \
|
|
main nodes optimizer port postmaster regex rewrite \
|
|
- storage tcop utils $(top_builddir)/src/timezone
|
|
+ security storage tcop utils $(top_builddir)/src/timezone
|
|
|
|
SUBSYSOBJS := $(DIRS:%=%/SUBSYS.o)
|
|
|
|
@@ -31,6 +31,11 @@ LIBS := $(filter-out -lpgport, $(LIBS))
|
|
# The backend doesn't need everything that's in LIBS, however
|
|
LIBS := $(filter-out -lz -lreadline -ledit -ltermcap -lncurses -lcurses, $(LIBS))
|
|
|
|
+# SELinux support needs to link libselinux
|
|
+ifeq ($(enable_selinux), yes)
|
|
+LIBS += -lselinux
|
|
+endif
|
|
+
|
|
##########################################################################
|
|
|
|
all: submake-libpgport postgres $(POSTGRES_IMP)
|
|
diff -rpNU3 base/src/backend/access/common/heaptuple.c sepgsql/src/backend/access/common/heaptuple.c
|
|
--- base/src/backend/access/common/heaptuple.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/access/common/heaptuple.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -26,6 +26,7 @@
|
|
#include "access/heapam.h"
|
|
#include "access/tuptoaster.h"
|
|
#include "executor/tuptable.h"
|
|
+#include "security/pgace.h"
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
@@ -314,6 +315,9 @@ heap_attisnull(HeapTuple tup, int attnum
|
|
case MinCommandIdAttributeNumber:
|
|
case MaxTransactionIdAttributeNumber:
|
|
case MaxCommandIdAttributeNumber:
|
|
+#ifdef SECURITY_SYSATTR_NAME
|
|
+ case SecurityAttributeNumber:
|
|
+#endif
|
|
/* these are never null */
|
|
break;
|
|
|
|
@@ -593,6 +597,11 @@ heap_getsysattr(HeapTuple tup, int attnu
|
|
case TableOidAttributeNumber:
|
|
result = ObjectIdGetDatum(tup->t_tableOid);
|
|
break;
|
|
+#ifdef SECURITY_SYSATTR_NAME
|
|
+ case SecurityAttributeNumber:
|
|
+ result = ObjectIdGetDatum(HeapTupleGetSecurity(tup));
|
|
+ break;
|
|
+#endif
|
|
default:
|
|
elog(ERROR, "invalid attnum: %d", attnum);
|
|
result = 0; /* keep compiler quiet */
|
|
@@ -624,6 +633,7 @@ heap_copytuple(HeapTuple tuple)
|
|
newTuple->t_tableOid = tuple->t_tableOid;
|
|
newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
|
|
memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_len);
|
|
+ HeapTupleSetSecurity(newTuple, HeapTupleGetSecurity(tuple));
|
|
return newTuple;
|
|
}
|
|
|
|
@@ -650,6 +660,7 @@ heap_copytuple_with_tuple(HeapTuple src,
|
|
dest->t_tableOid = src->t_tableOid;
|
|
dest->t_data = (HeapTupleHeader) palloc(src->t_len);
|
|
memcpy((char *) dest->t_data, (char *) src->t_data, src->t_len);
|
|
+ HeapTupleSetSecurity(dest, HeapTupleGetSecurity(src));
|
|
}
|
|
|
|
/*
|
|
@@ -928,6 +939,7 @@ heap_modify_tuple(HeapTuple tuple,
|
|
newTuple->t_tableOid = tuple->t_tableOid;
|
|
if (tupleDesc->tdhasoid)
|
|
HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
|
|
+ HeapTupleSetSecurity(newTuple, HeapTupleGetSecurity(tuple));
|
|
|
|
return newTuple;
|
|
}
|
|
@@ -1000,6 +1012,7 @@ heap_modifytuple(HeapTuple tuple,
|
|
newTuple->t_tableOid = tuple->t_tableOid;
|
|
if (tupleDesc->tdhasoid)
|
|
HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
|
|
+ HeapTupleSetSecurity(newTuple, HeapTupleGetSecurity(tuple));
|
|
|
|
return newTuple;
|
|
}
|
|
diff -rpNU3 base/src/backend/access/heap/heapam.c sepgsql/src/backend/access/heap/heapam.c
|
|
--- base/src/backend/access/heap/heapam.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/access/heap/heapam.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -49,6 +49,7 @@
|
|
#include "catalog/namespace.h"
|
|
#include "miscadmin.h"
|
|
#include "pgstat.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/procarray.h"
|
|
#include "utils/inval.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -1408,6 +1409,7 @@ heap_insert(Relation relation, HeapTuple
|
|
HeapTupleHeaderSetXmax(tup->t_data, 0); /* zero out Datum fields */
|
|
HeapTupleHeaderSetCmax(tup->t_data, 0); /* for cleanliness */
|
|
tup->t_tableOid = RelationGetRelid(relation);
|
|
+ pgaceHeapInsert(relation, tup);
|
|
|
|
/*
|
|
* If the new tuple is too big for storage or contains already toasted
|
|
@@ -1454,6 +1456,7 @@ heap_insert(Relation relation, HeapTuple
|
|
rdata[0].buffer = InvalidBuffer;
|
|
rdata[0].next = &(rdata[1]);
|
|
|
|
+ xlhdr.t_security = HeapTupleGetSecurity(heaptup);
|
|
xlhdr.t_natts = heaptup->t_data->t_natts;
|
|
xlhdr.t_infomask = heaptup->t_data->t_infomask;
|
|
xlhdr.t_hoff = heaptup->t_data->t_hoff;
|
|
@@ -1531,6 +1534,7 @@ heap_insert(Relation relation, HeapTuple
|
|
Oid
|
|
simple_heap_insert(Relation relation, HeapTuple tup)
|
|
{
|
|
+ pgaceSimpleHeapInsert(relation, tup);
|
|
return heap_insert(relation, tup, GetCurrentCommandId(), true, true);
|
|
}
|
|
|
|
@@ -1583,6 +1587,7 @@ heap_delete(Relation relation, ItemPoint
|
|
tp.t_data = (HeapTupleHeader) PageGetItem(dp, lp);
|
|
tp.t_len = ItemIdGetLength(lp);
|
|
tp.t_self = *tid;
|
|
+ pgaceHeapDelete(relation, &tp);
|
|
|
|
l1:
|
|
result = HeapTupleSatisfiesUpdate(tp.t_data, cid, buffer);
|
|
@@ -1805,6 +1810,7 @@ simple_heap_delete(Relation relation, It
|
|
ItemPointerData update_ctid;
|
|
TransactionId update_xmax;
|
|
|
|
+ pgaceSimpleHeapDelete(relation, tid);
|
|
result = heap_delete(relation, tid,
|
|
&update_ctid, &update_xmax,
|
|
GetCurrentCommandId(), InvalidSnapshot,
|
|
@@ -2046,6 +2052,7 @@ l2:
|
|
HeapTupleHeaderSetCmin(newtup->t_data, cid);
|
|
HeapTupleHeaderSetXmax(newtup->t_data, 0); /* zero out Datum fields */
|
|
HeapTupleHeaderSetCmax(newtup->t_data, 0); /* for cleanliness */
|
|
+ pgaceHeapUpdate(relation, newtup, &oldtup);
|
|
|
|
/*
|
|
* If the toaster needs to be activated, OR if the new tuple will not fit
|
|
@@ -2261,6 +2268,7 @@ simple_heap_update(Relation relation, It
|
|
ItemPointerData update_ctid;
|
|
TransactionId update_xmax;
|
|
|
|
+ pgaceSimpleHeapUpdate(relation, otid, tup);
|
|
result = heap_update(relation, otid, tup,
|
|
&update_ctid, &update_xmax,
|
|
GetCurrentCommandId(), InvalidSnapshot,
|
|
@@ -3206,6 +3214,7 @@ log_heap_update(Relation reln, Buffer ol
|
|
xlhdr.hdr.t_natts = newtup->t_data->t_natts;
|
|
xlhdr.hdr.t_infomask = newtup->t_data->t_infomask;
|
|
xlhdr.hdr.t_hoff = newtup->t_data->t_hoff;
|
|
+ xlhdr.hdr.t_security = HeapTupleGetSecurity(newtup);
|
|
if (move) /* remember xmax & xmin */
|
|
{
|
|
TransactionId xid[2]; /* xmax, xmin */
|
|
@@ -3505,6 +3514,7 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRec
|
|
htup->t_natts = xlhdr.t_natts;
|
|
htup->t_infomask = xlhdr.t_infomask;
|
|
htup->t_hoff = xlhdr.t_hoff;
|
|
+ HeapTupleHeaderSetSecurity(htup, xlhdr.t_security);
|
|
HeapTupleHeaderSetXmin(htup, record->xl_xid);
|
|
HeapTupleHeaderSetCmin(htup, FirstCommandId);
|
|
htup->t_ctid = xlrec->target.tid;
|
|
@@ -3668,6 +3678,7 @@ newsame:;
|
|
htup->t_natts = xlhdr.t_natts;
|
|
htup->t_infomask = xlhdr.t_infomask;
|
|
htup->t_hoff = xlhdr.t_hoff;
|
|
+ HeapTupleHeaderSetSecurity(htup, xlhdr.t_security);
|
|
|
|
if (move)
|
|
{
|
|
diff -rpNU3 base/src/backend/bootstrap/bootparse.y sepgsql/src/backend/bootstrap/bootparse.y
|
|
--- base/src/backend/bootstrap/bootparse.y 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/bootstrap/bootparse.y 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -212,7 +212,8 @@ Boot_CreateStmt:
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
(Datum) 0,
|
|
- true);
|
|
+ true,
|
|
+ NIL);
|
|
elog(DEBUG4, "relation created with oid %u", id);
|
|
}
|
|
do_end();
|
|
diff -rpNU3 base/src/backend/catalog/Makefile sepgsql/src/backend/catalog/Makefile
|
|
--- base/src/backend/catalog/Makefile 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/Makefile 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -35,6 +35,7 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_s
|
|
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 \
|
|
toasting.h indexing.h \
|
|
)
|
|
|
|
diff -rpNU3 base/src/backend/catalog/catalog.c sepgsql/src/backend/catalog/catalog.c
|
|
--- base/src/backend/catalog/catalog.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/catalog.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -29,6 +29,7 @@
|
|
#include "catalog/pg_database.h"
|
|
#include "catalog/pg_namespace.h"
|
|
#include "catalog/pg_pltemplate.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_shdepend.h"
|
|
#include "catalog/pg_shdescription.h"
|
|
#include "catalog/pg_tablespace.h"
|
|
@@ -254,6 +255,7 @@ IsSharedRelation(Oid relationId)
|
|
relationId == AuthMemRelationId ||
|
|
relationId == DatabaseRelationId ||
|
|
relationId == PLTemplateRelationId ||
|
|
+ relationId == SecurityRelationId ||
|
|
relationId == SharedDescriptionRelationId ||
|
|
relationId == SharedDependRelationId ||
|
|
relationId == TableSpaceRelationId)
|
|
@@ -266,6 +268,8 @@ IsSharedRelation(Oid relationId)
|
|
relationId == DatabaseNameIndexId ||
|
|
relationId == DatabaseOidIndexId ||
|
|
relationId == PLTemplateNameIndexId ||
|
|
+ relationId == SecurityOidIndexId ||
|
|
+ relationId == SecuritySeclabelIndexId ||
|
|
relationId == SharedDescriptionObjIndexId ||
|
|
relationId == SharedDependDependerIndexId ||
|
|
relationId == SharedDependReferenceIndexId ||
|
|
diff -rpNU3 base/src/backend/catalog/genbki.sh sepgsql/src/backend/catalog/genbki.sh
|
|
--- base/src/backend/catalog/genbki.sh 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/genbki.sh 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -130,6 +130,22 @@ for dir in $INCLUDE_DIRS; do
|
|
fi
|
|
done
|
|
|
|
+# Get SECURITY_SYSATTR_NAME from security/pgace.h
|
|
+for dir in $INCLUDE_DIRS; do
|
|
+ if [ -f "$dir/pg_config.h" ]; then
|
|
+ SECURITY_SYSATTR_NAME=`grep '#define[ ]*SECURITY_SYSATTR_NAME' $dir/pg_config.h | $AWK '{ print $3}' | sed 's/\"//g'`
|
|
+ break
|
|
+ fi
|
|
+done
|
|
+
|
|
+function SECURITY_SYSATTR_NAME_filter() {
|
|
+ if [ -z "$SECURITY_SYSATTR_NAME" ]; then
|
|
+ grep -v SECURITY_SYSATTR_NAME;
|
|
+ else
|
|
+ cat
|
|
+ fi
|
|
+}
|
|
+
|
|
touch ${OUTPUT_PREFIX}.description.$$
|
|
touch ${OUTPUT_PREFIX}.shdescription.$$
|
|
|
|
@@ -143,7 +159,7 @@ touch ${OUTPUT_PREFIX}.shdescription.$$
|
|
# Substitute values of configuration constants
|
|
# ----------------
|
|
#
|
|
-cat $INFILES | \
|
|
+cat $INFILES | SECURITY_SYSATTR_NAME_filter | \
|
|
sed -e 's;/\*.*\*/;;g' \
|
|
-e 's;/\*;\
|
|
/*\
|
|
@@ -165,6 +181,7 @@ sed -e "s/;[ ]*$//g" \
|
|
-e "s/PGUID/$BOOTSTRAP_SUPERUSERID/g" \
|
|
-e "s/NAMEDATALEN/$NAMEDATALEN/g" \
|
|
-e "s/PGNSP/$PG_CATALOG_NAMESPACE/g" \
|
|
+ -e "s/SECURITY_SYSATTR_NAME/$SECURITY_SYSATTR_NAME/g" \
|
|
| $AWK '
|
|
# ----------------
|
|
# now use awk to process remaining .h file..
|
|
diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c
|
|
--- base/src/backend/catalog/heap.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/heap.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -51,6 +51,7 @@
|
|
#include "parser/parse_coerce.h"
|
|
#include "parser/parse_expr.h"
|
|
#include "parser/parse_relation.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
@@ -65,7 +66,8 @@ static void AddNewRelationTuple(Relation
|
|
Oid new_rel_oid, Oid new_type_oid,
|
|
Oid relowner,
|
|
char relkind,
|
|
- Datum reloptions);
|
|
+ Datum reloptions,
|
|
+ List *pgace_attr_list);
|
|
static Oid AddNewRelationType(const char *typeName,
|
|
Oid typeNamespace,
|
|
Oid new_rel_oid,
|
|
@@ -141,7 +143,21 @@ static FormData_pg_attribute a7 = {
|
|
true, 'p', 'i', true, false, false, true, 0
|
|
};
|
|
|
|
+#ifdef SECURITY_SYSATTR_NAME
|
|
+/*
|
|
+ * SECURITY_SYSATTR_NAME is defined at PGACE header file.
|
|
+ * If SELinux is enabled, it is defined as "security_context"
|
|
+ */
|
|
+static FormData_pg_attribute a8 = {
|
|
+ 0, {SECURITY_SYSATTR_NAME}, SECLABELOID, 0, sizeof(Oid),
|
|
+ SecurityAttributeNumber, 0, -1, -1,
|
|
+ true, 'p', 'i', true, false, false, true, 0
|
|
+};
|
|
+
|
|
+static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8};
|
|
+#else
|
|
static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};
|
|
+#endif
|
|
|
|
/*
|
|
* This function returns a Form_pg_attribute pointer for a system attribute.
|
|
@@ -435,7 +451,8 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|
TupleDesc tupdesc,
|
|
char relkind,
|
|
bool oidislocal,
|
|
- int oidinhcount)
|
|
+ int oidinhcount,
|
|
+ List *pgace_attr_list)
|
|
{
|
|
const Form_pg_attribute *dpp;
|
|
int i;
|
|
@@ -470,6 +487,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|
false,
|
|
ATTRIBUTE_TUPLE_SIZE,
|
|
(void *) *dpp);
|
|
+ pgaceCreateAttributeCommon(rel, tup, pgace_attr_list);
|
|
|
|
simple_heap_insert(rel, tup);
|
|
|
|
@@ -560,7 +578,8 @@ void
|
|
InsertPgClassTuple(Relation pg_class_desc,
|
|
Relation new_rel_desc,
|
|
Oid new_rel_oid,
|
|
- Datum reloptions)
|
|
+ Datum reloptions,
|
|
+ List *pgace_attr_list)
|
|
{
|
|
Form_pg_class rd_rel = new_rel_desc->rd_rel;
|
|
Datum values[Natts_pg_class];
|
|
@@ -610,6 +629,7 @@ InsertPgClassTuple(Relation pg_class_des
|
|
* be embarrassing to do this sort of thing in polite company.
|
|
*/
|
|
HeapTupleSetOid(tup, new_rel_oid);
|
|
+ pgaceCreateRelationCommon(pg_class_desc, tup, pgace_attr_list);
|
|
|
|
/* finally insert the new tuple, update the indexes, and clean up */
|
|
simple_heap_insert(pg_class_desc, tup);
|
|
@@ -633,7 +653,8 @@ AddNewRelationTuple(Relation pg_class_de
|
|
Oid new_type_oid,
|
|
Oid relowner,
|
|
char relkind,
|
|
- Datum reloptions)
|
|
+ Datum reloptions,
|
|
+ List *pgace_attr_list)
|
|
{
|
|
Form_pg_class new_rel_reltup;
|
|
|
|
@@ -696,7 +717,7 @@ AddNewRelationTuple(Relation pg_class_de
|
|
new_rel_desc->rd_att->tdtypeid = new_type_oid;
|
|
|
|
/* Now build and insert the tuple */
|
|
- InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions);
|
|
+ InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions, pgace_attr_list);
|
|
}
|
|
|
|
|
|
@@ -756,7 +777,8 @@ heap_create_with_catalog(const char *rel
|
|
int oidinhcount,
|
|
OnCommitAction oncommit,
|
|
Datum reloptions,
|
|
- bool allow_system_table_mods)
|
|
+ bool allow_system_table_mods,
|
|
+ List *pgace_attr_list)
|
|
{
|
|
Relation pg_class_desc;
|
|
Relation new_rel_desc;
|
|
@@ -827,13 +849,14 @@ heap_create_with_catalog(const char *rel
|
|
new_type_oid,
|
|
ownerid,
|
|
relkind,
|
|
- reloptions);
|
|
+ reloptions,
|
|
+ pgace_attr_list);
|
|
|
|
/*
|
|
* now add tuples to pg_attribute for the attributes in our new relation.
|
|
*/
|
|
AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind,
|
|
- oidislocal, oidinhcount);
|
|
+ oidislocal, oidinhcount, pgace_attr_list);
|
|
|
|
/*
|
|
* make a dependency link to force the relation to be deleted if its
|
|
diff -rpNU3 base/src/backend/catalog/index.c sepgsql/src/backend/catalog/index.c
|
|
--- base/src/backend/catalog/index.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/index.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -591,7 +591,7 @@ index_create(Oid heapRelationId,
|
|
*/
|
|
InsertPgClassTuple(pg_class, indexRelation,
|
|
RelationGetRelid(indexRelation),
|
|
- reloptions);
|
|
+ reloptions, NIL);
|
|
|
|
/* done with pg_class */
|
|
heap_close(pg_class, RowExclusiveLock);
|
|
diff -rpNU3 base/src/backend/catalog/pg_aggregate.c sepgsql/src/backend/catalog/pg_aggregate.c
|
|
--- base/src/backend/catalog/pg_aggregate.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/pg_aggregate.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -214,7 +214,8 @@ AggregateCreate(const char *aggName,
|
|
numArgs), /* paramTypes */
|
|
PointerGetDatum(NULL), /* allParamTypes */
|
|
PointerGetDatum(NULL), /* parameterModes */
|
|
- PointerGetDatum(NULL)); /* parameterNames */
|
|
+ PointerGetDatum(NULL), /* parameterNames */
|
|
+ NULL);
|
|
|
|
/*
|
|
* Okay to create the pg_aggregate entry.
|
|
diff -rpNU3 base/src/backend/catalog/pg_largeobject.c sepgsql/src/backend/catalog/pg_largeobject.c
|
|
--- base/src/backend/catalog/pg_largeobject.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/pg_largeobject.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -18,6 +18,7 @@
|
|
#include "access/heapam.h"
|
|
#include "catalog/indexing.h"
|
|
#include "catalog/pg_largeobject.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
|
|
@@ -57,6 +58,8 @@ LargeObjectCreate(Oid loid)
|
|
|
|
ntup = heap_formtuple(pg_largeobject->rd_att, values, nulls);
|
|
|
|
+ pgaceLargeObjectCreate(pg_largeobject, ntup);
|
|
+
|
|
/*
|
|
* Insert it
|
|
*/
|
|
@@ -91,6 +94,8 @@ LargeObjectDrop(Oid loid)
|
|
|
|
while ((tuple = systable_getnext(sd)) != NULL)
|
|
{
|
|
+ if (!found)
|
|
+ pgaceLargeObjectDrop(pg_largeobject, tuple);
|
|
simple_heap_delete(pg_largeobject, &tuple->t_self);
|
|
found = true;
|
|
}
|
|
diff -rpNU3 base/src/backend/catalog/pg_proc.c sepgsql/src/backend/catalog/pg_proc.c
|
|
--- base/src/backend/catalog/pg_proc.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/pg_proc.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -27,6 +27,7 @@
|
|
#include "mb/pg_wchar.h"
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_type.h"
|
|
+#include "security/pgace.h"
|
|
#include "tcop/pquery.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/acl.h"
|
|
@@ -71,7 +72,8 @@ ProcedureCreate(const char *procedureNam
|
|
oidvector *parameterTypes,
|
|
Datum allParameterTypes,
|
|
Datum parameterModes,
|
|
- Datum parameterNames)
|
|
+ Datum parameterNames,
|
|
+ void *pgace_item)
|
|
{
|
|
Oid retval;
|
|
int parameterCount;
|
|
@@ -326,6 +328,7 @@ ProcedureCreate(const char *procedureNam
|
|
|
|
/* Okay, do it... */
|
|
tup = heap_modifytuple(oldtup, tupDesc, values, nulls, replaces);
|
|
+ pgaceCreateFunctionCommon(tup, (DefElem *) pgace_item);
|
|
simple_heap_update(rel, &tup->t_self, tup);
|
|
|
|
ReleaseSysCache(oldtup);
|
|
@@ -335,6 +338,7 @@ ProcedureCreate(const char *procedureNam
|
|
{
|
|
/* Creating a new procedure */
|
|
tup = heap_formtuple(tupDesc, values, nulls);
|
|
+ pgaceCreateFunctionCommon(tup, (DefElem *) pgace_item);
|
|
simple_heap_insert(rel, tup);
|
|
is_update = false;
|
|
}
|
|
diff -rpNU3 base/src/backend/catalog/toasting.c sepgsql/src/backend/catalog/toasting.c
|
|
--- base/src/backend/catalog/toasting.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/catalog/toasting.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -192,7 +192,8 @@ create_toast_table(Relation rel, Oid toa
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
(Datum) 0,
|
|
- true);
|
|
+ true,
|
|
+ NIL);
|
|
|
|
/* make the toast relation visible, else index creation will fail */
|
|
CommandCounterIncrement();
|
|
diff -rpNU3 base/src/backend/commands/cluster.c sepgsql/src/backend/commands/cluster.c
|
|
--- base/src/backend/commands/cluster.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/cluster.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -639,7 +639,8 @@ make_new_heap(Oid OIDOldHeap, const char
|
|
0,
|
|
ONCOMMIT_NOOP,
|
|
reloptions,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ NIL);
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c
|
|
--- base/src/backend/commands/copy.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/copy.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -22,6 +22,7 @@
|
|
|
|
#include "access/heapam.h"
|
|
#include "access/xact.h"
|
|
+#include "catalog/heap.h"
|
|
#include "catalog/namespace.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "commands/copy.h"
|
|
@@ -34,6 +35,7 @@
|
|
#include "optimizer/planner.h"
|
|
#include "parser/parse_relation.h"
|
|
#include "rewrite/rewriteHandler.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/fd.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/acl.h"
|
|
@@ -159,6 +161,11 @@ typedef struct CopyStateData
|
|
char *raw_buf;
|
|
int raw_buf_index; /* next byte to process */
|
|
int raw_buf_len; /* total # of bytes stored */
|
|
+
|
|
+ /* dumpable/restorable system column support */
|
|
+ FmgrInfo security_out_function;
|
|
+ bool security_force_quot;
|
|
+ bool security_force_notnull;
|
|
} CopyStateData;
|
|
|
|
typedef CopyStateData *CopyState;
|
|
@@ -242,7 +249,7 @@ static const char BinarySignature[11] =
|
|
/* non-export function prototypes */
|
|
static void DoCopyTo(CopyState cstate);
|
|
static void CopyTo(CopyState cstate);
|
|
-static void CopyOneRowTo(CopyState cstate, Oid tupleOid,
|
|
+static void CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid securityOid,
|
|
Datum *values, bool *nulls);
|
|
static void CopyFrom(CopyState cstate);
|
|
static bool CopyReadLine(CopyState cstate);
|
|
@@ -1068,6 +1075,8 @@ DoCopy(const CopyStmt *stmt)
|
|
/* Generate or convert list of attributes to process */
|
|
cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
|
|
|
|
+ pgaceCopyTable(cstate->rel, cstate->attnumlist, is_from);
|
|
+
|
|
num_phys_attrs = tupDesc->natts;
|
|
|
|
/* Convert FORCE QUOTE name list to per-column flags, check validity */
|
|
@@ -1088,6 +1097,10 @@ DoCopy(const CopyStmt *stmt)
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
errmsg("FORCE QUOTE column \"%s\" not referenced by COPY",
|
|
NameStr(tupDesc->attrs[attnum - 1]->attname))));
|
|
+ if (pgaceWritableSystemColumn(attnum)) {
|
|
+ cstate->security_force_quot = true;
|
|
+ continue;
|
|
+ }
|
|
cstate->force_quote_flags[attnum - 1] = true;
|
|
}
|
|
}
|
|
@@ -1110,6 +1123,9 @@ DoCopy(const CopyStmt *stmt)
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY",
|
|
NameStr(tupDesc->attrs[attnum - 1]->attname))));
|
|
+ if (pgaceWritableSystemColumn(attnum))
|
|
+ continue; /* ignore, if specified */
|
|
+
|
|
cstate->force_notnull_flags[attnum - 1] = true;
|
|
}
|
|
}
|
|
@@ -1304,16 +1320,27 @@ CopyTo(CopyState cstate)
|
|
int attnum = lfirst_int(cur);
|
|
Oid out_func_oid;
|
|
bool isvarlena;
|
|
+ FmgrInfo *out_fmgr;
|
|
+ Form_pg_attribute pg_attribute;
|
|
+
|
|
+ if (pgaceWritableSystemColumn(attnum)) {
|
|
+ /* PGACE: dumpable system column */
|
|
+ pg_attribute = SystemAttributeDefinition(attnum, false);
|
|
+ out_fmgr = &cstate->security_out_function;
|
|
+ } else {
|
|
+ pg_attribute = attr[attnum - 1];
|
|
+ out_fmgr = &cstate->out_functions[attnum - 1];
|
|
+ }
|
|
|
|
if (cstate->binary)
|
|
- getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid,
|
|
+ getTypeBinaryOutputInfo(pg_attribute->atttypid,
|
|
&out_func_oid,
|
|
&isvarlena);
|
|
else
|
|
- getTypeOutputInfo(attr[attnum - 1]->atttypid,
|
|
+ getTypeOutputInfo(pg_attribute->atttypid,
|
|
&out_func_oid,
|
|
&isvarlena);
|
|
- fmgr_info(out_func_oid, &cstate->out_functions[attnum - 1]);
|
|
+ fmgr_info(out_func_oid, out_fmgr);
|
|
}
|
|
|
|
/*
|
|
@@ -1368,7 +1395,12 @@ CopyTo(CopyState cstate)
|
|
CopySendChar(cstate, cstate->delim[0]);
|
|
hdr_delim = true;
|
|
|
|
- colname = NameStr(attr[attnum - 1]->attname);
|
|
+ if (pgaceWritableSystemColumn(attnum)) {
|
|
+ Form_pg_attribute sysatt = SystemAttributeDefinition(attnum, false);
|
|
+ colname = NameStr(sysatt->attname);
|
|
+ } else {
|
|
+ colname = NameStr(attr[attnum - 1]->attname);
|
|
+ }
|
|
|
|
CopyAttributeOutCSV(cstate, colname, false,
|
|
list_length(cstate->attnumlist) == 1);
|
|
@@ -1394,11 +1426,14 @@ CopyTo(CopyState cstate)
|
|
{
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
+ if (!pgaceCopyToTuple(cstate->rel, tuple))
|
|
+ continue;
|
|
+
|
|
/* Deconstruct the tuple ... faster than repeated heap_getattr */
|
|
heap_deform_tuple(tuple, tupDesc, values, nulls);
|
|
|
|
/* Format and send the data */
|
|
- CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls);
|
|
+ CopyOneRowTo(cstate, HeapTupleGetOid(tuple), HeapTupleGetSecurity(tuple), values, nulls);
|
|
}
|
|
|
|
heap_endscan(scandesc);
|
|
@@ -1424,7 +1459,7 @@ CopyTo(CopyState cstate)
|
|
* Emit one row during CopyTo().
|
|
*/
|
|
static void
|
|
-CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls)
|
|
+CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid tupleSecurity, Datum *values, bool *nulls)
|
|
{
|
|
bool need_delim = false;
|
|
FmgrInfo *out_functions = cstate->out_functions;
|
|
@@ -1463,8 +1498,10 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
foreach(cur, cstate->attnumlist)
|
|
{
|
|
int attnum = lfirst_int(cur);
|
|
- Datum value = values[attnum - 1];
|
|
- bool isnull = nulls[attnum - 1];
|
|
+ Datum value;
|
|
+ bool isnull;
|
|
+ bool force_quot;
|
|
+ FmgrInfo *out_fmgr;
|
|
|
|
if (!cstate->binary)
|
|
{
|
|
@@ -1473,6 +1510,19 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
need_delim = true;
|
|
}
|
|
|
|
+ /* PGACE: dumpable system column support */
|
|
+ if (pgaceWritableSystemColumn(attnum)) {
|
|
+ value = tupleSecurity;
|
|
+ isnull = false;
|
|
+ force_quot = cstate->security_force_quot;
|
|
+ out_fmgr = &cstate->security_out_function;
|
|
+ } else {
|
|
+ value = values[attnum - 1];
|
|
+ isnull = nulls[attnum - 1];
|
|
+ force_quot = cstate->force_quote_flags[attnum - 1];
|
|
+ out_fmgr = &out_functions[attnum - 1];
|
|
+ }
|
|
+
|
|
if (isnull)
|
|
{
|
|
if (!cstate->binary)
|
|
@@ -1484,11 +1534,9 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
{
|
|
if (!cstate->binary)
|
|
{
|
|
- string = OutputFunctionCall(&out_functions[attnum - 1],
|
|
- value);
|
|
+ string = OutputFunctionCall(out_fmgr, value);
|
|
if (cstate->csv_mode)
|
|
- CopyAttributeOutCSV(cstate, string,
|
|
- cstate->force_quote_flags[attnum - 1],
|
|
+ CopyAttributeOutCSV(cstate, string, force_quot,
|
|
list_length(cstate->attnumlist) == 1);
|
|
else
|
|
CopyAttributeOutText(cstate, string);
|
|
@@ -1497,8 +1545,7 @@ CopyOneRowTo(CopyState cstate, Oid tuple
|
|
{
|
|
bytea *outputbytes;
|
|
|
|
- outputbytes = SendFunctionCall(&out_functions[attnum - 1],
|
|
- value);
|
|
+ outputbytes = SendFunctionCall(out_fmgr, value);
|
|
CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);
|
|
CopySendData(cstate, VARDATA(outputbytes),
|
|
VARSIZE(outputbytes) - VARHDRSZ);
|
|
@@ -1632,8 +1679,11 @@ CopyFrom(CopyState cstate)
|
|
num_defaults;
|
|
FmgrInfo *in_functions;
|
|
FmgrInfo oid_in_function;
|
|
+ FmgrInfo security_in_function;
|
|
+ bool security_in_function_prepared = false;
|
|
Oid *typioparams;
|
|
Oid oid_typioparam;
|
|
+ Oid security_typioparam;
|
|
int attnum;
|
|
int i;
|
|
Oid in_func_oid;
|
|
@@ -1868,6 +1918,7 @@ CopyFrom(CopyState cstate)
|
|
{
|
|
bool skip_tuple;
|
|
Oid loaded_oid = InvalidOid;
|
|
+ Oid loaded_security = InvalidOid;
|
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
@@ -1942,6 +1993,36 @@ CopyFrom(CopyState cstate)
|
|
int attnum = lfirst_int(cur);
|
|
int m = attnum - 1;
|
|
|
|
+ if (pgaceWritableSystemColumn(attnum)) {
|
|
+ Form_pg_attribute sysatt = SystemAttributeDefinition(attnum, false);
|
|
+
|
|
+ if (fieldno >= fldct)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
|
+ errmsg("missing data for column \"%s\"",
|
|
+ NameStr(sysatt->attname))));
|
|
+ string = field_strings[fieldno++];
|
|
+ cstate->cur_attname = NameStr(attr[m]->attname);
|
|
+ cstate->cur_attval = string;
|
|
+
|
|
+ if (!security_in_function_prepared) {
|
|
+ getTypeInputInfo(sysatt->atttypid, &in_func_oid,
|
|
+ &security_typioparam);
|
|
+ fmgr_info(in_func_oid, &security_in_function);
|
|
+ security_in_function_prepared = true;
|
|
+ }
|
|
+ if (string) {
|
|
+ Datum d = InputFunctionCall(&security_in_function,
|
|
+ string,
|
|
+ security_typioparam,
|
|
+ sysatt->atttypmod);
|
|
+ loaded_security = ObjectIdGetDatum(d);
|
|
+ }
|
|
+ cstate->cur_attname = NULL;
|
|
+ cstate->cur_attval = NULL;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
if (fieldno >= fldct)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
|
@@ -2012,6 +2093,33 @@ CopyFrom(CopyState cstate)
|
|
int attnum = lfirst_int(cur);
|
|
int m = attnum - 1;
|
|
|
|
+ if (pgaceWritableSystemColumn(attnum)) {
|
|
+ Form_pg_attribute sysatt = SystemAttributeDefinition(attnum, false);
|
|
+ Datum d;
|
|
+
|
|
+ cstate->cur_attname = NameStr(sysatt->attname);
|
|
+ i++;
|
|
+
|
|
+ if (!security_in_function_prepared) {
|
|
+ Oid security_in_func_oid;
|
|
+ getTypeBinaryInputInfo(sysatt->atttypid,
|
|
+ &security_in_func_oid,
|
|
+ &security_typioparam);
|
|
+ fmgr_info(security_in_func_oid, &security_in_function);
|
|
+ security_in_function_prepared = true;
|
|
+ }
|
|
+ d = CopyReadBinaryAttribute(cstate,
|
|
+ i,
|
|
+ &security_in_function,
|
|
+ security_typioparam,
|
|
+ sysatt->atttypmod,
|
|
+ &isnull);
|
|
+ if (!isnull)
|
|
+ loaded_security = ObjectIdGetDatum(d);
|
|
+ cstate->cur_attname = NULL;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
cstate->cur_attname = NameStr(attr[m]->attname);
|
|
i++;
|
|
values[m] = CopyReadBinaryAttribute(cstate,
|
|
@@ -2043,6 +2151,7 @@ CopyFrom(CopyState cstate)
|
|
|
|
if (cstate->oids && file_has_oids)
|
|
HeapTupleSetOid(tuple, loaded_oid);
|
|
+ HeapTupleSetSecurity(tuple, loaded_security);
|
|
|
|
/* Triggers and stuff need to be invoked in query context. */
|
|
MemoryContextSwitchTo(oldcontext);
|
|
@@ -2066,6 +2175,9 @@ CopyFrom(CopyState cstate)
|
|
}
|
|
}
|
|
|
|
+ if (!skip_tuple && !pgaceCopyFromTuple(cstate->rel, tuple))
|
|
+ skip_tuple = true;
|
|
+
|
|
if (!skip_tuple)
|
|
{
|
|
/* Place tuple in tuple slot */
|
|
@@ -3250,6 +3362,17 @@ CopyGetAttnums(TupleDesc tupDesc, Relati
|
|
break;
|
|
}
|
|
}
|
|
+
|
|
+ /* PGACE: writable system column support */
|
|
+ if (attnum == InvalidAttrNumber)
|
|
+ {
|
|
+ Form_pg_attribute sysatt = SystemAttributeByName(name, true);
|
|
+ if (sysatt) {
|
|
+ if (pgaceWritableSystemColumn(sysatt->attnum))
|
|
+ attnum = sysatt->attnum;
|
|
+ }
|
|
+ }
|
|
+
|
|
if (attnum == InvalidAttrNumber)
|
|
{
|
|
if (rel != NULL)
|
|
@@ -3299,7 +3422,7 @@ copy_dest_receive(TupleTableSlot *slot,
|
|
slot_getallattrs(slot);
|
|
|
|
/* And send the data */
|
|
- CopyOneRowTo(cstate, InvalidOid, slot->tts_values, slot->tts_isnull);
|
|
+ CopyOneRowTo(cstate, InvalidOid, InvalidOid, slot->tts_values, slot->tts_isnull);
|
|
}
|
|
|
|
/*
|
|
diff -rpNU3 base/src/backend/commands/dbcommands.c sepgsql/src/backend/commands/dbcommands.c
|
|
--- base/src/backend/commands/dbcommands.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/dbcommands.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -38,6 +38,7 @@
|
|
#include "mb/pg_wchar.h"
|
|
#include "miscadmin.h"
|
|
#include "postmaster/bgwriter.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/freespace.h"
|
|
#include "storage/procarray.h"
|
|
#include "storage/smgr.h"
|
|
@@ -90,6 +91,7 @@ createdb(const CreatedbStmt *stmt)
|
|
DefElem *dtemplate = NULL;
|
|
DefElem *dencoding = NULL;
|
|
DefElem *dconnlimit = NULL;
|
|
+ DefElem *dpgace_item = NULL;
|
|
char *dbname = stmt->dbname;
|
|
char *dbowner = NULL;
|
|
const char *dbtemplate = NULL;
|
|
@@ -151,6 +153,13 @@ createdb(const CreatedbStmt *stmt)
|
|
errmsg("LOCATION is not supported anymore"),
|
|
errhint("Consider using tablespaces instead.")));
|
|
}
|
|
+ else if (pgaceNodeIsSecurityLabel(defel)) {
|
|
+ if (dpgace_item)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ dpgace_item = defel;
|
|
+ }
|
|
else
|
|
elog(ERROR, "option \"%s\" not recognized",
|
|
defel->defname);
|
|
@@ -381,6 +390,7 @@ createdb(const CreatedbStmt *stmt)
|
|
new_record, new_record_nulls);
|
|
|
|
HeapTupleSetOid(tuple, dboid);
|
|
+ pgaceCreateDatabaseCommon(tuple, dpgace_item);
|
|
|
|
simple_heap_insert(pg_database_rel, tuple);
|
|
|
|
@@ -773,6 +783,7 @@ AlterDatabase(AlterDatabaseStmt *stmt)
|
|
ListCell *option;
|
|
int connlimit = -1;
|
|
DefElem *dconnlimit = NULL;
|
|
+ DefElem *dpgace_item = NULL;
|
|
Datum new_record[Natts_pg_database];
|
|
char new_record_nulls[Natts_pg_database];
|
|
char new_record_repl[Natts_pg_database];
|
|
@@ -790,6 +801,13 @@ AlterDatabase(AlterDatabaseStmt *stmt)
|
|
errmsg("conflicting or redundant options")));
|
|
dconnlimit = defel;
|
|
}
|
|
+ else if (pgaceNodeIsSecurityLabel(defel)) {
|
|
+ if (dpgace_item)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ dpgace_item = defel;
|
|
+ }
|
|
else
|
|
elog(ERROR, "option \"%s\" not recognized",
|
|
defel->defname);
|
|
@@ -835,6 +853,7 @@ AlterDatabase(AlterDatabaseStmt *stmt)
|
|
|
|
newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), new_record,
|
|
new_record_nulls, new_record_repl);
|
|
+ pgaceAlterDatabaseCommon(newtuple, dpgace_item);
|
|
simple_heap_update(rel, &tuple->t_self, newtuple);
|
|
|
|
/* Update indexes */
|
|
diff -rpNU3 base/src/backend/commands/functioncmds.c sepgsql/src/backend/commands/functioncmds.c
|
|
--- base/src/backend/commands/functioncmds.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/functioncmds.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -47,6 +47,7 @@
|
|
#include "miscadmin.h"
|
|
#include "parser/parse_func.h"
|
|
#include "parser/parse_type.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
@@ -337,7 +338,8 @@ compute_attributes_sql_style(List *optio
|
|
char **language,
|
|
char *volatility_p,
|
|
bool *strict_p,
|
|
- bool *security_definer)
|
|
+ bool *security_definer,
|
|
+ DefElem **pgace_item)
|
|
{
|
|
ListCell *option;
|
|
DefElem *as_item = NULL;
|
|
@@ -366,6 +368,14 @@ compute_attributes_sql_style(List *optio
|
|
errmsg("conflicting or redundant options")));
|
|
language_item = defel;
|
|
}
|
|
+ else if (pgaceNodeIsSecurityLabel(defel))
|
|
+ {
|
|
+ if (*pgace_item)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ *pgace_item = defel;
|
|
+ }
|
|
else if (compute_common_attribute(defel,
|
|
&volatility_item,
|
|
&strict_item,
|
|
@@ -522,6 +532,7 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|
HeapTuple languageTuple;
|
|
Form_pg_language languageStruct;
|
|
List *as_clause;
|
|
+ DefElem *pgace_item = NULL;
|
|
|
|
/* Convert list of names to a name and namespace */
|
|
namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
|
|
@@ -540,7 +551,7 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|
|
|
/* override attributes from explicit list */
|
|
compute_attributes_sql_style(stmt->options,
|
|
- &as_clause, &language, &volatility, &isStrict, &security);
|
|
+ &as_clause, &language, &volatility, &isStrict, &security, &pgace_item);
|
|
|
|
/* Convert language name to canonical case */
|
|
languageName = case_translate_language_name(language);
|
|
@@ -665,7 +676,8 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|
parameterTypes,
|
|
PointerGetDatum(allParameterTypes),
|
|
PointerGetDatum(parameterModes),
|
|
- PointerGetDatum(parameterNames));
|
|
+ PointerGetDatum(parameterNames),
|
|
+ pgace_item);
|
|
}
|
|
|
|
|
|
@@ -1012,6 +1024,7 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|
DefElem *volatility_item = NULL;
|
|
DefElem *strict_item = NULL;
|
|
DefElem *security_def_item = NULL;
|
|
+ DefElem *pgace_def_item = NULL;
|
|
|
|
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
|
|
|
|
@@ -1043,6 +1056,15 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|
{
|
|
DefElem *defel = (DefElem *) lfirst(l);
|
|
|
|
+ if (pgaceNodeIsSecurityLabel(defel)) {
|
|
+ if (pgace_def_item)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_SYNTAX_ERROR),
|
|
+ errmsg("conflicting or redundant options")));
|
|
+ pgace_def_item = defel;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
if (compute_common_attribute(defel,
|
|
&volatility_item,
|
|
&strict_item,
|
|
@@ -1057,6 +1079,7 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|
if (security_def_item)
|
|
procForm->prosecdef = intVal(security_def_item->arg);
|
|
|
|
+ pgaceAlterFunctionCommon(tup, pgace_def_item);
|
|
/* Do the update */
|
|
simple_heap_update(rel, &tup->t_self, tup);
|
|
CatalogUpdateIndexes(rel, tup);
|
|
diff -rpNU3 base/src/backend/commands/lockcmds.c sepgsql/src/backend/commands/lockcmds.c
|
|
--- base/src/backend/commands/lockcmds.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/lockcmds.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -18,6 +18,7 @@
|
|
#include "catalog/namespace.h"
|
|
#include "commands/lockcmds.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/lsyscache.h"
|
|
|
|
@@ -59,6 +60,8 @@ LockTableCommand(LockStmt *lockstmt)
|
|
aclcheck_error(aclresult, ACL_KIND_CLASS,
|
|
get_rel_name(reloid));
|
|
|
|
+ pgaceLockTable(reloid);
|
|
+
|
|
if (lockstmt->nowait)
|
|
rel = relation_open_nowait(reloid, lockstmt->mode);
|
|
else
|
|
diff -rpNU3 base/src/backend/commands/proclang.c sepgsql/src/backend/commands/proclang.c
|
|
--- base/src/backend/commands/proclang.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/proclang.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -130,7 +130,8 @@ CreateProceduralLanguage(CreatePLangStmt
|
|
buildoidvector(funcargtypes, 0),
|
|
PointerGetDatum(NULL),
|
|
PointerGetDatum(NULL),
|
|
- PointerGetDatum(NULL));
|
|
+ PointerGetDatum(NULL),
|
|
+ NULL);
|
|
}
|
|
|
|
/*
|
|
@@ -160,7 +161,8 @@ CreateProceduralLanguage(CreatePLangStmt
|
|
buildoidvector(funcargtypes, 1),
|
|
PointerGetDatum(NULL),
|
|
PointerGetDatum(NULL),
|
|
- PointerGetDatum(NULL));
|
|
+ PointerGetDatum(NULL),
|
|
+ NULL);
|
|
}
|
|
}
|
|
else
|
|
diff -rpNU3 base/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/tablecmds.c
|
|
--- base/src/backend/commands/tablecmds.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/tablecmds.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -53,6 +53,7 @@
|
|
#include "parser/parse_type.h"
|
|
#include "parser/parser.h"
|
|
#include "rewrite/rewriteHandler.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
@@ -432,7 +433,8 @@ DefineRelation(CreateStmt *stmt, char re
|
|
parentOidCount,
|
|
stmt->oncommit,
|
|
reloptions,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ pgaceBuildAttrListForRelation(stmt));
|
|
|
|
StoreCatalogInheritance(relationId, inheritOids);
|
|
|
|
@@ -2183,6 +2185,7 @@ ATPrepCmd(List **wqueue, Relation rel, A
|
|
case AT_DisableTrigUser:
|
|
case AT_AddInherit: /* INHERIT / NO INHERIT */
|
|
case AT_DropInherit:
|
|
+ case AT_SetSecurityLabel:
|
|
ATSimplePermissions(rel, false);
|
|
/* These commands never recurse */
|
|
/* No command-specific prep needed */
|
|
@@ -2372,6 +2375,9 @@ ATExecCmd(AlteredTableInfo *tab, Relatio
|
|
case AT_DropInherit:
|
|
ATExecDropInherit(rel, (RangeVar *) cmd->def);
|
|
break;
|
|
+ case AT_SetSecurityLabel:
|
|
+ pgaceAlterRelationCommon(rel, cmd);
|
|
+ break;
|
|
default: /* oops */
|
|
elog(ERROR, "unrecognized alter table type: %d",
|
|
(int) cmd->subtype);
|
|
diff -rpNU3 base/src/backend/commands/trigger.c sepgsql/src/backend/commands/trigger.c
|
|
--- base/src/backend/commands/trigger.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/commands/trigger.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -30,6 +30,7 @@
|
|
#include "miscadmin.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/parse_func.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
@@ -1295,6 +1296,12 @@ ExecCallTriggerFunc(TriggerData *trigdat
|
|
*/
|
|
InitFunctionCallInfoData(fcinfo, finfo, 0, (Node *) trigdata, NULL);
|
|
|
|
+ /* PGACE: permission check for trigegr function */
|
|
+ if (!pgaceCallFunctionTrigger(finfo, trigdata)) {
|
|
+ MemoryContextSwitchTo(oldContext);
|
|
+ return (HeapTuple) DatumGetPointer(NULL);
|
|
+ }
|
|
+
|
|
result = FunctionCallInvoke(&fcinfo);
|
|
|
|
MemoryContextSwitchTo(oldContext);
|
|
diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/execMain.c
|
|
--- base/src/backend/executor/execMain.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/execMain.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -48,6 +48,7 @@
|
|
#include "optimizer/clauses.h"
|
|
#include "parser/parse_clause.h"
|
|
#include "parser/parsetree.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -134,6 +135,8 @@ ExecutorStart(QueryDesc *queryDesc, int
|
|
Assert(queryDesc != NULL);
|
|
Assert(queryDesc->estate == NULL);
|
|
|
|
+ pgaceExecutorStart(queryDesc, eflags);
|
|
+
|
|
/*
|
|
* If the transaction is read-only, we need to check if any writes are
|
|
* planned to non-temporary tables. EXPLAIN is considered read-only.
|
|
@@ -1065,6 +1068,8 @@ ExecutePlan(EState *estate,
|
|
|
|
for (;;)
|
|
{
|
|
+ Oid __tts_security = InvalidOid;
|
|
+
|
|
/* Reset the per-output-tuple exprcontext */
|
|
ResetPerTupleExprContext(estate);
|
|
|
|
@@ -1217,6 +1222,13 @@ lnext: ;
|
|
}
|
|
|
|
/*
|
|
+ * PGACE: writable system columnt support.
|
|
+ * If client specified a explicit security label,
|
|
+ * pgaceFetchSecurityLabel() fetch it from junk attribute.
|
|
+ */
|
|
+ pgaceFetchSecurityLabel(junkfilter, slot, &__tts_security);
|
|
+
|
|
+ /*
|
|
* Create a new "clean" tuple with all junk attributes removed. We
|
|
* don't need to do this for DELETE, however (there will in fact
|
|
* be no non-junk attributes in a DELETE!)
|
|
@@ -1224,6 +1236,7 @@ lnext: ;
|
|
if (operation != CMD_DELETE)
|
|
slot = ExecFilterJunk(junkfilter, slot);
|
|
}
|
|
+ slot->tts_security = __tts_security;
|
|
|
|
/*
|
|
* now that we have a tuple, do the appropriate thing with it.. either
|
|
@@ -1344,6 +1357,7 @@ ExecInsert(TupleTableSlot *slot,
|
|
resultRelInfo = estate->es_result_relation_info;
|
|
resultRelationDesc = resultRelInfo->ri_RelationDesc;
|
|
|
|
+ HeapTupleStoreSecurityFromSlot(tuple, slot);
|
|
/* BEFORE ROW INSERT Triggers */
|
|
if (resultRelInfo->ri_TrigDesc &&
|
|
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
|
|
@@ -1380,6 +1394,13 @@ ExecInsert(TupleTableSlot *slot,
|
|
ExecConstraints(resultRelInfo, slot, estate);
|
|
|
|
/*
|
|
+ * Check the explicit labeling, if configured
|
|
+ */
|
|
+ if (!pgaceExecInsert(resultRelationDesc, tuple,
|
|
+ !!resultRelInfo->ri_projectReturning))
|
|
+ return;
|
|
+
|
|
+ /*
|
|
* insert the tuple
|
|
*
|
|
* Note: heap_insert returns the tid (location) of the new tuple in the
|
|
@@ -1447,6 +1468,10 @@ ExecDelete(ItemPointer tupleid,
|
|
return;
|
|
}
|
|
|
|
+ if (!pgaceExecDelete(resultRelationDesc, tupleid,
|
|
+ !!resultRelInfo->ri_projectReturning))
|
|
+ return;
|
|
+
|
|
/*
|
|
* delete the tuple
|
|
*
|
|
@@ -1584,6 +1609,7 @@ ExecUpdate(TupleTableSlot *slot,
|
|
resultRelInfo = estate->es_result_relation_info;
|
|
resultRelationDesc = resultRelInfo->ri_RelationDesc;
|
|
|
|
+ HeapTupleStoreSecurityFromSlot(tuple, slot);
|
|
/* BEFORE ROW UPDATE Triggers */
|
|
if (resultRelInfo->ri_TrigDesc &&
|
|
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
|
|
@@ -1629,6 +1655,13 @@ lreplace:;
|
|
ExecConstraints(resultRelInfo, slot, estate);
|
|
|
|
/*
|
|
+ * check explicit labeling, if necessary
|
|
+ */
|
|
+ if (!pgaceExecUpdate(resultRelationDesc, tuple, tupleid,
|
|
+ !!resultRelInfo->ri_projectReturning))
|
|
+ return;
|
|
+
|
|
+ /*
|
|
* replace the heap tuple
|
|
*
|
|
* Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that
|
|
@@ -2428,7 +2461,8 @@ OpenIntoRel(QueryDesc *queryDesc)
|
|
0,
|
|
parseTree->intoOnCommit,
|
|
reloptions,
|
|
- allowSystemTableMods);
|
|
+ allowSystemTableMods,
|
|
+ NIL);
|
|
|
|
FreeTupleDesc(tupdesc);
|
|
|
|
@@ -2549,6 +2583,11 @@ intorel_receive(TupleTableSlot *slot, De
|
|
HeapTuple tuple;
|
|
|
|
tuple = ExecCopySlotTuple(slot);
|
|
+ HeapTupleStoreSecurityFromSlot(tuple, slot);
|
|
+ if (!pgaceExecInsert(estate->es_into_relation_descriptor, tuple, false)) {
|
|
+ heap_freetuple(tuple);
|
|
+ return;
|
|
+ }
|
|
|
|
heap_insert(estate->es_into_relation_descriptor,
|
|
tuple,
|
|
diff -rpNU3 base/src/backend/executor/execQual.c sepgsql/src/backend/executor/execQual.c
|
|
--- base/src/backend/executor/execQual.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/executor/execQual.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -47,6 +47,7 @@
|
|
#include "nodes/makefuncs.h"
|
|
#include "optimizer/planmain.h"
|
|
#include "parser/parse_expr.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -1739,6 +1740,8 @@ ExecEvalFunc(FuncExprState *fcache,
|
|
/* Go directly to ExecMakeFunctionResult on subsequent uses */
|
|
fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult;
|
|
|
|
+ pgaceCallFunction(&fcache->func);
|
|
+
|
|
return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);
|
|
}
|
|
|
|
diff -rpNU3 base/src/backend/libpq/be-fsstubs.c sepgsql/src/backend/libpq/be-fsstubs.c
|
|
--- base/src/backend/libpq/be-fsstubs.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/libpq/be-fsstubs.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -45,6 +45,7 @@
|
|
#include "libpq/be-fsstubs.h"
|
|
#include "libpq/libpq-fs.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/large_object.h"
|
|
#include "utils/memutils.h"
|
|
@@ -367,6 +368,9 @@ lo_import(PG_FUNCTION_ARGS)
|
|
errmsg("could not open server file \"%s\": %m",
|
|
fnamebuf)));
|
|
|
|
+ /* check whether (server) --> (client) data flow is allowed, or not. */
|
|
+ pgaceLargeObjectImport();
|
|
+
|
|
/*
|
|
* create an inversion object
|
|
*/
|
|
@@ -422,6 +426,9 @@ lo_export(PG_FUNCTION_ARGS)
|
|
|
|
CreateFSContext();
|
|
|
|
+ /* check whether (client) --> (server) data flow is allowed, or not */
|
|
+ pgaceLargeObjectExport();
|
|
+
|
|
/*
|
|
* open the inversion object (no need to test for failure)
|
|
*/
|
|
diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfuncs.c
|
|
--- base/src/backend/nodes/copyfuncs.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/nodes/copyfuncs.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -24,6 +24,7 @@
|
|
|
|
#include "nodes/plannodes.h"
|
|
#include "nodes/relation.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/datum.h"
|
|
|
|
|
|
@@ -1717,6 +1718,7 @@ _copyQuery(Query *from)
|
|
COPY_NODE_FIELD(setOperations);
|
|
COPY_NODE_FIELD(resultRelations);
|
|
COPY_NODE_FIELD(returningLists);
|
|
+ COPY_NODE_FIELD(pgaceList);
|
|
|
|
return newnode;
|
|
}
|
|
@@ -3345,6 +3347,10 @@ copyObject(void *from)
|
|
break;
|
|
|
|
default:
|
|
+ retval = pgaceCopyObject(from);
|
|
+ if (retval)
|
|
+ break;
|
|
+
|
|
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
|
|
retval = from; /* keep compiler quiet */
|
|
break;
|
|
diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs.c
|
|
--- base/src/backend/nodes/outfuncs.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/nodes/outfuncs.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -26,6 +26,7 @@
|
|
#include "lib/stringinfo.h"
|
|
#include "nodes/plannodes.h"
|
|
#include "nodes/relation.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/datum.h"
|
|
|
|
|
|
@@ -2198,6 +2199,8 @@ _outNode(StringInfo str, void *obj)
|
|
break;
|
|
|
|
default:
|
|
+ if (pgaceOutObject(str, obj))
|
|
+ break;
|
|
|
|
/*
|
|
* This should be an ERROR, but it's too useful to be able to
|
|
diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze.c
|
|
--- base/src/backend/parser/analyze.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/parser/analyze.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -37,6 +37,7 @@
|
|
#include "parser/parse_type.h"
|
|
#include "parser/parsetree.h"
|
|
#include "rewrite/rewriteManip.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -662,6 +663,9 @@ transformInsertStmt(ParseState *pstate,
|
|
Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
|
|
pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
|
|
|
|
+ /* writable system column support */
|
|
+ pgaceTransformInsertStmt(&icolumns, &attrnos, selectQuery->targetList);
|
|
+
|
|
/*----------
|
|
* Generate an expression list for the INSERT that selects all the
|
|
* non-resjunk columns from the subquery. (INSERT's tlist must be
|
|
@@ -821,14 +825,15 @@ transformInsertStmt(ParseState *pstate,
|
|
Expr *expr = (Expr *) lfirst(lc);
|
|
ResTarget *col;
|
|
TargetEntry *tle;
|
|
+ AttrNumber anum = (AttrNumber) lfirst_int(attnos);
|
|
|
|
col = (ResTarget *) lfirst(icols);
|
|
Assert(IsA(col, ResTarget));
|
|
|
|
tle = makeTargetEntry(expr,
|
|
- (AttrNumber) lfirst_int(attnos),
|
|
+ anum,
|
|
col->name,
|
|
- false);
|
|
+ anum < 0 ? true : false);
|
|
qry->targetList = lappend(qry->targetList, tle);
|
|
|
|
icols = lnext(icols);
|
|
@@ -2150,6 +2155,9 @@ transformSelectStmt(ParseState *pstate,
|
|
qry->intoOptions = copyObject(stmt->intoOptions);
|
|
qry->intoOnCommit = stmt->intoOnCommit;
|
|
qry->intoTableSpaceName = stmt->intoTableSpaceName;
|
|
+
|
|
+ /* writable system column support */
|
|
+ pgaceTransformSelectStmt(qry->targetList);
|
|
}
|
|
|
|
qry->rtable = pstate->p_rtable;
|
|
diff -rpNU3 base/src/backend/parser/gram.y sepgsql/src/backend/parser/gram.y
|
|
--- base/src/backend/parser/gram.y 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/parser/gram.y 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -56,6 +56,7 @@
|
|
#include "commands/defrem.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/gramparse.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/lmgr.h"
|
|
#include "utils/date.h"
|
|
#include "utils/datetime.h"
|
|
@@ -345,6 +346,7 @@ static void doNegateFloat(Value *v);
|
|
%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
|
|
%type <list> opt_check_option
|
|
|
|
+%type <defelt> OptSecurityLabel SecurityLabelItem
|
|
|
|
/*
|
|
* If you make any token changes, update the keyword table in
|
|
@@ -1522,6 +1524,24 @@ alter_table_cmd:
|
|
n->def = (Node *) $3;
|
|
$$ = (Node *)n;
|
|
}
|
|
+ /* ALTER TABLE <relation> CONTEXT = '...' */
|
|
+ | SecurityLabelItem
|
|
+ {
|
|
+ AlterTableCmd *n = makeNode(AlterTableCmd);
|
|
+ n->subtype = AT_SetSecurityLabel;
|
|
+ n->name = NULL;
|
|
+ n->def = (Node *) $1;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
+ /* ALTER TABLE <relation> ALTER [COLUMN] <colname> CONTEXT = '...' */
|
|
+ | ALTER opt_column ColId SecurityLabelItem
|
|
+ {
|
|
+ AlterTableCmd *n = makeNode(AlterTableCmd);
|
|
+ n->subtype = AT_SetSecurityLabel;
|
|
+ n->name = $3;
|
|
+ n->def = (Node *) $4;
|
|
+ $$ = (Node *) n;
|
|
+ }
|
|
| alter_rel_cmd
|
|
{
|
|
$$ = $1;
|
|
@@ -1769,7 +1789,7 @@ opt_using:
|
|
*****************************************************************************/
|
|
|
|
CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
|
|
- OptInherit OptWith OnCommitOption OptTableSpace
|
|
+ OptInherit OptWith OnCommitOption OptTableSpace OptSecurityLabel
|
|
{
|
|
CreateStmt *n = makeNode(CreateStmt);
|
|
$4->istemp = $2;
|
|
@@ -1780,10 +1800,11 @@ CreateStmt: CREATE OptTemp TABLE qualifi
|
|
n->options = $9;
|
|
n->oncommit = $10;
|
|
n->tablespacename = $11;
|
|
+ n->pgace_item = (Node *) $12;
|
|
$$ = (Node *)n;
|
|
}
|
|
| CREATE OptTemp TABLE qualified_name OF qualified_name
|
|
- '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace
|
|
+ '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace OptSecurityLabel
|
|
{
|
|
/* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
|
|
* by our inheritance capabilities. Let's try it...
|
|
@@ -1797,6 +1818,7 @@ CreateStmt: CREATE OptTemp TABLE qualifi
|
|
n->options = $10;
|
|
n->oncommit = $11;
|
|
n->tablespacename = $12;
|
|
+ n->pgace_item = (Node *) $13;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
@@ -1839,13 +1861,14 @@ TableElement:
|
|
| TableConstraint { $$ = $1; }
|
|
;
|
|
|
|
-columnDef: ColId Typename ColQualList
|
|
+columnDef: ColId Typename ColQualList OptSecurityLabel
|
|
{
|
|
ColumnDef *n = makeNode(ColumnDef);
|
|
n->colname = $1;
|
|
n->typename = $2;
|
|
n->constraints = $3;
|
|
n->is_local = true;
|
|
+ n->pgace_item = (Node *) $4;
|
|
$$ = (Node *)n;
|
|
}
|
|
;
|
|
@@ -3950,6 +3973,10 @@ common_func_opt_item:
|
|
{
|
|
$$ = makeDefElem("security", (Node *)makeInteger(FALSE));
|
|
}
|
|
+ | SecurityLabelItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
;
|
|
|
|
createfunc_opt_item:
|
|
@@ -4935,6 +4962,10 @@ createdb_opt_item:
|
|
{
|
|
$$ = makeDefElem("owner", NULL);
|
|
}
|
|
+ | SecurityLabelItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
;
|
|
|
|
/*
|
|
@@ -4992,6 +5023,10 @@ alterdb_opt_item:
|
|
{
|
|
$$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
|
|
}
|
|
+ | SecurityLabelItem
|
|
+ {
|
|
+ $$ = $1;
|
|
+ }
|
|
;
|
|
|
|
|
|
@@ -8271,6 +8306,26 @@ target_el: a_expr AS ColLabel
|
|
}
|
|
;
|
|
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Explicit Security Labeling
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+
|
|
+OptSecurityLabel:
|
|
+ SecurityLabelItem { $$ = $1; }
|
|
+ | /* EMPTY */ { $$ = NULL; }
|
|
+ ;
|
|
+
|
|
+SecurityLabelItem:
|
|
+ IDENT '=' Sconst
|
|
+ {
|
|
+ DefElem *n = pgaceGramSecurityLabel($1, $3);
|
|
+ if (n == NULL)
|
|
+ yyerror("syntax error");
|
|
+ $$ = n;
|
|
+ }
|
|
+ ;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
diff -rpNU3 base/src/backend/parser/parse_target.c sepgsql/src/backend/parser/parse_target.c
|
|
--- base/src/backend/parser/parse_target.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/parser/parse_target.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -26,6 +26,7 @@
|
|
#include "parser/parse_relation.h"
|
|
#include "parser/parse_target.h"
|
|
#include "parser/parse_type.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
#include "utils/typcache.h"
|
|
@@ -335,14 +336,19 @@ transformAssignedExpr(ParseState *pstate
|
|
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 (attrno > 0) {
|
|
+ attrtype = attnumTypeId(rd, attrno);
|
|
+ attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
|
|
+ } else {
|
|
+ /* PGACE: writable system column support */
|
|
+ if (!pgaceWritableSystemColumn(attrno))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
+ errmsg("cannot assign to system column \"%s\"", colname),
|
|
+ parser_errposition(pstate, location)));
|
|
+ attrtype = SECLABELOID;
|
|
+ attrtypmod = -1;
|
|
+ }
|
|
|
|
/*
|
|
* If the expression is a DEFAULT placeholder, insert the attribute's
|
|
@@ -483,6 +489,9 @@ updateTargetListEntry(ParseState *pstate
|
|
*/
|
|
tle->resno = (AttrNumber) attrno;
|
|
tle->resname = colname;
|
|
+ /* PGACE: writable system column support */
|
|
+ if (pgaceWritableSystemColumn(attrno))
|
|
+ tle->resjunk = true;
|
|
}
|
|
|
|
|
|
@@ -749,6 +758,7 @@ checkInsertTargets(ParseState *pstate, L
|
|
Bitmapset *wholecols = NULL;
|
|
Bitmapset *partialcols = NULL;
|
|
ListCell *tl;
|
|
+ bool security_attr = false;
|
|
|
|
foreach(tl, cols)
|
|
{
|
|
@@ -757,14 +767,31 @@ checkInsertTargets(ParseState *pstate, L
|
|
int attrno;
|
|
|
|
/* Lookup column name, ereport on failure */
|
|
- attrno = attnameAttNum(pstate->p_target_relation, name, false);
|
|
- if (attrno == InvalidAttrNumber)
|
|
+ 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)),
|
|
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
|
|
+ name, RelationGetRelationName(pstate->p_target_relation)),
|
|
parser_errposition(pstate, col->location)));
|
|
+ } else if (attrno <= 0) {
|
|
+ /* PGACE: writable system column support */
|
|
+ if (pgaceWritableSystemColumn(attrno)) {
|
|
+ if (security_attr)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_DUPLICATE_COLUMN),
|
|
+ errmsg("column \"%s\" specified more than once", name),
|
|
+ parser_errposition(pstate, col->location)));
|
|
+ security_attr = true;
|
|
+ *attrnos = lappend_int(*attrnos, attrno);
|
|
+ continue;
|
|
+ }
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
+ errmsg("column \"%s\" of relation \"%s\" is system column",
|
|
+ name, RelationGetRelationName(pstate->p_target_relation)),
|
|
+ parser_errposition(pstate, col->location)));
|
|
+ }
|
|
|
|
/*
|
|
* Check for duplicates, but only of whole columns --- we allow
|
|
diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmaster/postmaster.c
|
|
--- base/src/backend/postmaster/postmaster.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/postmaster/postmaster.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -107,6 +107,7 @@
|
|
#include "postmaster/pgarch.h"
|
|
#include "postmaster/postmaster.h"
|
|
#include "postmaster/syslogger.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/pg_shmem.h"
|
|
@@ -963,6 +964,9 @@ PostmasterMain(int argc, char *argv[])
|
|
*/
|
|
StartupPID = StartupDataBase();
|
|
|
|
+ if (!pgaceInitializePostmaster())
|
|
+ ExitPostmaster(1);
|
|
+
|
|
status = ServerLoop();
|
|
|
|
/*
|
|
@@ -1985,9 +1989,11 @@ pmdie(SIGNAL_ARGS)
|
|
signal_child(PgStatPID, SIGQUIT);
|
|
if (DLGetHead(BackendList))
|
|
SignalChildren(SIGQUIT);
|
|
+ pgaceFinalizePostmaster();
|
|
ExitPostmaster(0);
|
|
break;
|
|
}
|
|
+ pgaceFinalizePostmaster();
|
|
|
|
PG_SETMASK(&UnBlockSig);
|
|
|
|
diff -rpNU3 base/src/backend/rewrite/rewriteHandler.c sepgsql/src/backend/rewrite/rewriteHandler.c
|
|
--- base/src/backend/rewrite/rewriteHandler.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/rewrite/rewriteHandler.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -23,6 +23,7 @@
|
|
#include "parser/parsetree.h"
|
|
#include "rewrite/rewriteHandler.h"
|
|
#include "rewrite/rewriteManip.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
|
|
@@ -1854,5 +1855,8 @@ QueryRewrite(Query *parsetree)
|
|
if (!foundOriginalQuery && lastInstead != NULL)
|
|
lastInstead->canSetTag = true;
|
|
|
|
+ /* PGACE: general queries proxy */
|
|
+ results = pgaceProxyQuery(results);
|
|
+
|
|
return results;
|
|
}
|
|
diff -rpNU3 base/src/backend/security/Makefile sepgsql/src/backend/security/Makefile
|
|
--- base/src/backend/security/Makefile 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/Makefile 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -0,0 +1,31 @@
|
|
+#
|
|
+# src/backend/security/Makefile
|
|
+# Makefile for Security Enhanced PostgreSQL
|
|
+#
|
|
+# Copyright (c) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+#
|
|
+ubdir = src/backend/security
|
|
+top_builddir = ../../..
|
|
+include $(top_builddir)/src/Makefile.global
|
|
+
|
|
+ifeq ($(enable_selinux), yes)
|
|
+OBJS := pgaceCommon.o \
|
|
+ sepgsqlCore.o sepgsqlPerms.o sepgsqlHooks.o sepgsqlProxy.o
|
|
+else
|
|
+OBJS := pgaceCommon.o
|
|
+endif
|
|
+
|
|
+all: SUBSYS.o
|
|
+
|
|
+SUBSYS.o: $(OBJS)
|
|
+ $(LD) $(LDREL) $(LDOUT) $@ $^
|
|
+
|
|
+depend dep:
|
|
+ $(CC) -MM $(CFLAGS) *.c >depend
|
|
+
|
|
+clean:
|
|
+ rm -f SUBSYS.o $(OBJS)
|
|
+
|
|
+ifeq (depend,$(wildcard depend))
|
|
+include depend
|
|
+endif
|
|
diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security/pgaceCommon.c
|
|
--- base/src/backend/security/pgaceCommon.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/pgaceCommon.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -0,0 +1,764 @@
|
|
+/*
|
|
+ * src/backend/security/pgaceCommon.c
|
|
+ * Common part of PostgreSQL Access Control Extension
|
|
+ * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/genam.h"
|
|
+#include "access/heapam.h"
|
|
+#include "access/xact.h"
|
|
+#include "catalog/indexing.h"
|
|
+#include "catalog/pg_attribute.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "executor/executor.h"
|
|
+#include "miscadmin.h"
|
|
+#include "nodes/makefuncs.h"
|
|
+#include "nodes/parsenodes.h"
|
|
+#include "security/pgace.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/syscache.h"
|
|
+#include <unistd.h>
|
|
+#include <sys/file.h>
|
|
+
|
|
+#ifdef SECURITY_SYSATTR_NAME
|
|
+/*****************************************************************************
|
|
+ * Writable system column support
|
|
+ *****************************************************************************/
|
|
+void pgaceTransformSelectStmt(List *targetList) {
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, targetList) {
|
|
+ TargetEntry *tle = lfirst(l);
|
|
+
|
|
+ if (tle->resjunk)
|
|
+ continue;
|
|
+ if (!strcmp(tle->resname, SECURITY_SYSATTR_NAME))
|
|
+ tle->resjunk = true;
|
|
+ }
|
|
+}
|
|
+
|
|
+void pgaceTransformInsertStmt(List **p_icolumns, List **p_attrnos, List *targetList) {
|
|
+ AttrNumber security_attrno = 0;
|
|
+ ListCell *lc;
|
|
+
|
|
+ foreach (lc, targetList) {
|
|
+ TargetEntry *tle = (TargetEntry *) lfirst(lc);
|
|
+
|
|
+ security_attrno++;
|
|
+ if (strcmp(tle->resname, SECURITY_SYSATTR_NAME))
|
|
+ continue;
|
|
+
|
|
+ if (list_length(*p_icolumns) < list_length(targetList)) {
|
|
+ List *__icolumns = NIL;
|
|
+ List *__attrnos = NIL;
|
|
+ ListCell *l1, *l2;
|
|
+ int index = 0;
|
|
+
|
|
+ forboth(l1, *p_icolumns, l2, *p_attrnos) {
|
|
+ if (++index == security_attrno) {
|
|
+ ResTarget *col = makeNode(ResTarget);
|
|
+ col->name = pstrdup(SECURITY_SYSATTR_NAME);
|
|
+ col->indirection = NIL;
|
|
+ col->val = NULL;
|
|
+ col->location = -1;
|
|
+
|
|
+ __icolumns = lappend(__icolumns, col);
|
|
+ __attrnos = lappend_int(__attrnos, SecurityAttributeNumber);
|
|
+ }
|
|
+ if (lfirst_int(l2) == SecurityAttributeNumber)
|
|
+ return;
|
|
+ __icolumns = lappend(__icolumns, lfirst(l1));
|
|
+ __attrnos = lappend_int(__attrnos, lfirst_int(l2));
|
|
+ }
|
|
+ *p_icolumns = __icolumns;
|
|
+ *p_attrnos = __attrnos;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+void pgaceFetchSecurityLabel(JunkFilter *junkfilter, TupleTableSlot *slot, Oid *tts_security) {
|
|
+ Datum datum;
|
|
+ bool isNull;
|
|
+
|
|
+ if (ExecGetJunkAttribute(junkfilter,
|
|
+ slot,
|
|
+ SECURITY_SYSATTR_NAME,
|
|
+ &datum,
|
|
+ &isNull) && !isNull)
|
|
+ *tts_security = DatumGetObjectId(datum);
|
|
+}
|
|
+#endif /* SECURITY_SYSATTR_NAME */
|
|
+
|
|
+/*****************************************************************************
|
|
+ * Extended SQL statements support
|
|
+ *****************************************************************************/
|
|
+
|
|
+/* CREATE TABLE with explicit CONTEXT */
|
|
+List *pgaceBuildAttrListForRelation(CreateStmt *stmt) {
|
|
+ List *result = NIL;
|
|
+ ListCell *l;
|
|
+ DefElem *defel, *newel;
|
|
+ Oid t_security;
|
|
+
|
|
+ if (stmt->pgace_item) {
|
|
+ defel = (DefElem *) stmt->pgace_item;
|
|
+ Assert(IsA(defel, DefElem));
|
|
+
|
|
+ t_security = pgaceParseSecurityLabel(defel);
|
|
+ newel = makeDefElem(NULL, (Node *) makeInteger(t_security));
|
|
+
|
|
+ result = lappend(result, newel);
|
|
+ }
|
|
+
|
|
+ foreach (l, stmt->tableElts) {
|
|
+ ColumnDef *cdef = (ColumnDef *) lfirst(l);
|
|
+ defel = (DefElem *) cdef->pgace_item;
|
|
+
|
|
+ if (defel) {
|
|
+ Assert(IsA(defel, DefElem));
|
|
+ t_security = pgaceParseSecurityLabel(defel);
|
|
+ newel = makeDefElem(pstrdup(cdef->colname),
|
|
+ (Node *) makeInteger(t_security));
|
|
+
|
|
+ result = lappend(result, newel);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+void pgaceCreateRelationCommon(Relation rel, HeapTuple tuple, List *pgace_attr_list) {
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, pgace_attr_list) {
|
|
+ DefElem *defel = (DefElem *) lfirst(l);
|
|
+
|
|
+ if (!defel->defname) {
|
|
+ Oid t_security = intVal(defel->arg);
|
|
+
|
|
+ HeapTupleSetSecurity(tuple, t_security);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void pgaceCreateAttributeCommon(Relation rel, HeapTuple tuple, List *pgace_attr_list) {
|
|
+ Form_pg_attribute attr = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, pgace_attr_list) {
|
|
+ DefElem *defel = lfirst(l);
|
|
+
|
|
+ if (!defel->defname)
|
|
+ continue; /* for table */
|
|
+ if (!strcmp(defel->defname, NameStr(attr->attname))) {
|
|
+ Oid t_security = intVal(defel->arg);
|
|
+
|
|
+ HeapTupleSetSecurity(tuple, t_security);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/* ALTER <tblname> [ALTER <colname>] CONTEXT = 'xxx' statement */
|
|
+static void alterRelationCommon(Relation rel, DefElem *defel) {
|
|
+ Relation pg_class;
|
|
+ HeapTuple tuple;
|
|
+ Oid t_security;
|
|
+
|
|
+ pg_class = heap_open(RelationRelationId, RowExclusiveLock);
|
|
+
|
|
+ tuple = SearchSysCacheCopy(RELOID,
|
|
+ ObjectIdGetDatum(RelationGetRelid(rel)),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_UNDEFINED_TABLE),
|
|
+ errmsg("relation '%s' does not exist",
|
|
+ RelationGetRelationName(rel))));
|
|
+
|
|
+ t_security = pgaceParseSecurityLabel(defel);
|
|
+ HeapTupleSetSecurity(tuple, t_security);
|
|
+
|
|
+ simple_heap_update(pg_class, &tuple->t_self, tuple);
|
|
+ CatalogUpdateIndexes(pg_class, tuple);
|
|
+
|
|
+ heap_freetuple(tuple);
|
|
+ heap_close(pg_class, RowExclusiveLock);
|
|
+}
|
|
+
|
|
+static void alterAttributeCommon(Relation rel, char *colName, DefElem *defel) {
|
|
+ Relation pg_attr;
|
|
+ HeapTuple tuple;
|
|
+ Oid t_security;
|
|
+
|
|
+ pg_attr = heap_open(AttributeRelationId, RowExclusiveLock);
|
|
+
|
|
+ tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
|
|
+ colName, RelationGetRelationName(rel))));
|
|
+
|
|
+ t_security = pgaceParseSecurityLabel(defel);
|
|
+ HeapTupleSetSecurity(tuple, t_security);
|
|
+
|
|
+ simple_heap_update(pg_attr, &tuple->t_self, tuple);
|
|
+ CatalogUpdateIndexes(pg_attr, tuple);
|
|
+
|
|
+ heap_freetuple(tuple);
|
|
+ heap_close(pg_attr, RowExclusiveLock);
|
|
+}
|
|
+
|
|
+void pgaceAlterRelationCommon(Relation rel, AlterTableCmd *cmd) {
|
|
+ DefElem *defel = (DefElem *) cmd->def;
|
|
+
|
|
+ Assert(IsA(defel, DefElem));
|
|
+
|
|
+ if (!pgaceNodeIsSecurityLabel(defel))
|
|
+ elog(ERROR, "unrecognized security attribute");
|
|
+
|
|
+ if (!cmd->name) {
|
|
+ alterRelationCommon(rel, defel);
|
|
+ } else {
|
|
+ alterAttributeCommon(rel, cmd->name, defel);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void pgacePutSecurityLabel(HeapTuple tuple, DefElem *defel) {
|
|
+ Oid t_security;
|
|
+
|
|
+ if (!defel)
|
|
+ return;
|
|
+
|
|
+ Assert(IsA(defel, DefElem) && IsA(defel->arg, String));
|
|
+
|
|
+ t_security = pgaceParseSecurityLabel(defel);
|
|
+ HeapTupleSetSecurity(tuple, t_security);
|
|
+}
|
|
+
|
|
+void pgaceCreateDatabaseCommon(HeapTuple tuple, DefElem *defel) {
|
|
+ pgacePutSecurityLabel(tuple, defel);
|
|
+}
|
|
+
|
|
+void pgaceAlterDatabaseCommon(HeapTuple tuple, DefElem *defel) {
|
|
+ pgacePutSecurityLabel(tuple, defel);
|
|
+}
|
|
+
|
|
+void pgaceCreateFunctionCommon(HeapTuple tuple, DefElem *defel) {
|
|
+ pgacePutSecurityLabel(tuple, defel);
|
|
+}
|
|
+
|
|
+void pgaceAlterFunctionCommon(HeapTuple tuple, DefElem *defel) {
|
|
+ pgacePutSecurityLabel(tuple, defel);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * security_label type input/output handler
|
|
+ *****************************************************************************/
|
|
+static Oid early_security_label_to_sid(char *seclabel);
|
|
+static char *early_sid_to_security_label(Oid sid);
|
|
+#define EARLY_PG_SECURITY "global/pg_security.bootstrap"
|
|
+
|
|
+static bool pg_security_is_available() {
|
|
+ /* -1 : early mode, 0: now in transfer, 1: available */
|
|
+ static int pg_security_state = -1;
|
|
+ char fname[MAXPGPATH];
|
|
+ FILE *filp;
|
|
+
|
|
+ if (pg_security_state > 0)
|
|
+ return true;
|
|
+ if (IsBootstrapProcessingMode() || pg_security_state == 0)
|
|
+ return false;
|
|
+ /*
|
|
+ * if initial setting up was not done, the cache file is remaining.
|
|
+ * so we have to insert its contains into pg_selinux.
|
|
+ * we can make decision of whether it already done, or not, by looking
|
|
+ * the existance of 'EARLY_PG_SECURITY'.
|
|
+ */
|
|
+ snprintf(fname, sizeof(fname), "%s/%s", DataDir, EARLY_PG_SECURITY);
|
|
+ filp = fopen(fname, "a+");
|
|
+ if (filp) {
|
|
+ Relation rel;
|
|
+ CatalogIndexState ind;
|
|
+ HeapTuple tuple;
|
|
+ char buffer[1024];
|
|
+ Oid secoid, metaoid;
|
|
+ Datum value;
|
|
+ char isnull;
|
|
+
|
|
+ pg_security_state = 0;
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+ ind = CatalogOpenIndexes(rel);
|
|
+ while (fscanf(filp, "%u %s", &secoid, buffer) == 2) {
|
|
+ metaoid = early_security_label_to_sid(pgaceSecurityLabelOfLabel(buffer));
|
|
+
|
|
+ value = DirectFunctionCall1(textin, CStringGetDatum(buffer));
|
|
+ isnull = ' ';
|
|
+ tuple = heap_formtuple(RelationGetDescr(rel), &value, &isnull);
|
|
+
|
|
+ HeapTupleSetOid(tuple, secoid);
|
|
+ HeapTupleSetSecurity(tuple, metaoid);
|
|
+
|
|
+ simple_heap_insert(rel, tuple);
|
|
+ CatalogIndexInsert(ind, tuple);
|
|
+
|
|
+ heap_freetuple(tuple);
|
|
+ }
|
|
+ CatalogCloseIndexes(ind);
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+
|
|
+ CommandCounterIncrement();
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ fclose(filp);
|
|
+ pg_security_state = -1;
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ fclose(filp);
|
|
+ unlink(fname);
|
|
+ }
|
|
+ pg_security_state = 1;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static Oid early_security_label_to_sid(char *seclabel)
|
|
+{
|
|
+ char fname[MAXPGPATH], buffer[1024];
|
|
+ Oid sid, minsid = SecurityRelationId;
|
|
+ FILE *filp;
|
|
+
|
|
+ snprintf(fname, sizeof(fname), "%s/%s", DataDir, EARLY_PG_SECURITY);
|
|
+ filp = fopen(fname, "a+b");
|
|
+ if (!filp)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INTERNAL_ERROR),
|
|
+ errmsg("could not open '%s'", fname)));
|
|
+ flock(fileno(filp), LOCK_EX);
|
|
+ while (fscanf(filp, "%u %s", &sid, buffer) == 2) {
|
|
+ if (!strcmp(seclabel, buffer)) {
|
|
+ fclose(filp);
|
|
+ return sid;
|
|
+ }
|
|
+ if (sid < minsid)
|
|
+ minsid = sid;
|
|
+ }
|
|
+ if (!pgaceSecurityLabelIsValid(seclabel))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INTERNAL_ERROR),
|
|
+ errmsg("'%s' is not a valid security label", seclabel)));
|
|
+
|
|
+ sid = minsid - 1;
|
|
+ fprintf(filp, "%u %s\n", sid, seclabel);
|
|
+ fclose(filp);
|
|
+
|
|
+ return sid;
|
|
+}
|
|
+
|
|
+static char *early_sid_to_security_label(Oid sid)
|
|
+{
|
|
+ char fname[MAXPGPATH], buffer[1024], *seclabel;
|
|
+ FILE *filp;
|
|
+ Oid __sid;
|
|
+
|
|
+ snprintf(fname, sizeof(fname), "%s/%s", DataDir, EARLY_PG_SECURITY);
|
|
+ filp = fopen(fname, "rb");
|
|
+ if (!filp)
|
|
+ goto not_found;
|
|
+
|
|
+ flock(fileno(filp), LOCK_SH);
|
|
+ while (fscanf(filp, "%u %s", &__sid, buffer) == 2) {
|
|
+ if (sid == __sid) {
|
|
+ fclose(filp);
|
|
+ return pstrdup(buffer);
|
|
+ }
|
|
+ }
|
|
+ fclose(filp);
|
|
+
|
|
+not_found:
|
|
+ seclabel = pgaceSecurityLabelNotFound(sid);
|
|
+ ereport((seclabel ? DEBUG1 : ERROR),
|
|
+ (errcode(ERRCODE_INTERNAL_ERROR),
|
|
+ errmsg("no text representation for sid = %u", sid)));
|
|
+ return seclabel;
|
|
+}
|
|
+
|
|
+static Oid get_security_label_oid(Relation rel, CatalogIndexState ind, char *new_label)
|
|
+{
|
|
+ /* rel has to be opened with RowExclusiveLock */
|
|
+ char *mlabel_str = pgaceSecurityLabelOfLabel(new_label);
|
|
+ Datum mlabel_text;
|
|
+ HeapTuple tuple;
|
|
+ Oid label_oid;
|
|
+
|
|
+ if (!pgaceSecurityLabelIsValid(mlabel_str))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INTERNAL_ERROR),
|
|
+ errmsg("'%s' is not a valid security label", mlabel_str)));
|
|
+
|
|
+ /* 1. lookup syscache */
|
|
+ mlabel_text = DirectFunctionCall1(textin, CStringGetDatum(mlabel_str));
|
|
+ tuple = SearchSysCache(SECURITYLABEL,
|
|
+ mlabel_text,
|
|
+ 0, 0, 0);
|
|
+ if (HeapTupleIsValid(tuple)) {
|
|
+ label_oid = HeapTupleGetSecurity(tuple);
|
|
+ ReleaseSysCache(tuple);
|
|
+ } else {
|
|
+ /* 2. lookup table on SnapshotSelf */
|
|
+ SysScanDesc scan;
|
|
+ ScanKeyData skey;
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_security_seclabel,
|
|
+ BTEqualStrategyNumber, F_TEXTEQ,
|
|
+ PointerGetDatum(mlabel_text));
|
|
+ scan = systable_beginscan(rel, SecuritySeclabelIndexId,
|
|
+ true, SnapshotSelf, 1, &skey);
|
|
+ tuple = systable_getnext(scan);
|
|
+ if (HeapTupleIsValid(tuple)) {
|
|
+ label_oid = HeapTupleGetSecurity(tuple);
|
|
+ } else {
|
|
+ /* 3. insert a new tuple into pg_security */
|
|
+ Datum value = PointerGetDatum(mlabel_text);
|
|
+ char isnull = ' ';
|
|
+ Oid meta_oid;
|
|
+
|
|
+ tuple = heap_formtuple(RelationGetDescr(rel),
|
|
+ &value, &isnull);
|
|
+ meta_oid = GetNewOid(rel);
|
|
+ HeapTupleSetOid(tuple, meta_oid);
|
|
+ HeapTupleSetSecurity(tuple, meta_oid);
|
|
+
|
|
+ label_oid = simple_heap_insert(rel, tuple);
|
|
+ Assert(label_oid == meta_oid);
|
|
+
|
|
+ CatalogIndexInsert(ind, tuple);
|
|
+ }
|
|
+ systable_endscan(scan);
|
|
+ }
|
|
+ return label_oid;
|
|
+}
|
|
+
|
|
+static Oid security_label_to_sid(char *label_str)
|
|
+{
|
|
+ Datum label_text;
|
|
+ Oid label_oid;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ if (!pg_security_is_available())
|
|
+ return early_security_label_to_sid(label_str);
|
|
+
|
|
+ /* 1. lookup system cache first */
|
|
+ label_text = DirectFunctionCall1(textin, CStringGetDatum(label_str));
|
|
+ tuple = SearchSysCache(SECURITYLABEL,
|
|
+ label_text,
|
|
+ 0, 0, 0);
|
|
+ if (HeapTupleIsValid(tuple)) {
|
|
+ label_oid = HeapTupleGetOid(tuple);
|
|
+ ReleaseSysCache(tuple);
|
|
+ } else {
|
|
+ /* 2. lookup within the current command ID */
|
|
+ Relation rel;
|
|
+ SysScanDesc scan;
|
|
+ ScanKeyData skey;
|
|
+ Oid meta_oid;
|
|
+
|
|
+ rel = heap_open(SecurityRelationId, RowExclusiveLock);
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_security_seclabel,
|
|
+ BTEqualStrategyNumber, F_TEXTEQ,
|
|
+ PointerGetDatum(label_text));
|
|
+ scan = systable_beginscan(rel, SecuritySeclabelIndexId,
|
|
+ true, SnapshotSelf, 1, &skey);
|
|
+ tuple = systable_getnext(scan);
|
|
+ if (HeapTupleIsValid(tuple)) {
|
|
+ label_oid = HeapTupleGetOid(tuple);
|
|
+ } else {
|
|
+ CatalogIndexState ind;
|
|
+ Datum value = PointerGetDatum(label_text);
|
|
+ char isnull = ' ';
|
|
+
|
|
+ if (!pgaceSecurityLabelIsValid(label_str))
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INTERNAL_ERROR),
|
|
+ errmsg("'%s' is not a valid security label", label_str)));
|
|
+ ind = CatalogOpenIndexes(rel);
|
|
+
|
|
+ tuple = heap_formtuple(RelationGetDescr(rel),
|
|
+ &value, &isnull);
|
|
+ meta_oid = get_security_label_oid(rel, ind, label_str);
|
|
+ HeapTupleSetSecurity(tuple, meta_oid);
|
|
+
|
|
+ label_oid = simple_heap_insert(rel, tuple);
|
|
+
|
|
+ CatalogIndexInsert(ind, tuple);
|
|
+ CatalogCloseIndexes(ind);
|
|
+ }
|
|
+ systable_endscan(scan);
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+ }
|
|
+ return label_oid;
|
|
+}
|
|
+
|
|
+static char *sid_to_security_label(Oid sid)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ Datum tcon;
|
|
+ char *seclabel;
|
|
+ bool isnull, syscache = true;
|
|
+
|
|
+ if (!pg_security_is_available())
|
|
+ return early_sid_to_security_label(sid);
|
|
+
|
|
+ tuple = SearchSysCache(SECURITYOID,
|
|
+ ObjectIdGetDatum(sid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple)) {
|
|
+ Relation rel;
|
|
+ SysScanDesc scan;
|
|
+ ScanKeyData skey;
|
|
+
|
|
+ syscache = false;
|
|
+ rel = heap_open(SecurityRelationId, AccessShareLock);
|
|
+ ScanKeyInit(&skey,
|
|
+ ObjectIdAttributeNumber,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(sid));
|
|
+ scan = systable_beginscan(rel, SecurityOidIndexId,
|
|
+ true, SnapshotSelf, 1, &skey);
|
|
+ tuple = systable_getnext(scan);
|
|
+ if (HeapTupleIsValid(tuple))
|
|
+ tuple = heap_copytuple(tuple);
|
|
+ systable_endscan(scan);
|
|
+ heap_close(rel, AccessShareLock);
|
|
+
|
|
+ if (!HeapTupleIsValid(tuple)) {
|
|
+ seclabel = pgaceSecurityLabelNotFound(sid);
|
|
+ ereport((seclabel ? DEBUG1 : ERROR),
|
|
+ (errcode(ERRCODE_INTERNAL_ERROR),
|
|
+ errmsg("no text representation for sid = %u", sid)));
|
|
+ return seclabel;
|
|
+ }
|
|
+ }
|
|
+ tcon = SysCacheGetAttr(SECURITYOID,
|
|
+ tuple,
|
|
+ Anum_pg_security_seclabel,
|
|
+ &isnull);
|
|
+ seclabel = DatumGetCString(DirectFunctionCall1(textout,
|
|
+ PointerGetDatum(tcon)));
|
|
+ if (syscache)
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return seclabel;
|
|
+}
|
|
+
|
|
+/* security_label_in -- security_label input function */
|
|
+Datum
|
|
+security_label_in(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *label = PG_GETARG_CSTRING(0);
|
|
+ Oid sid;
|
|
+
|
|
+ label = pgaceSecurityLabelIn(label);
|
|
+ sid = security_label_to_sid(label);
|
|
+
|
|
+ PG_RETURN_OID(sid);
|
|
+}
|
|
+
|
|
+/* security_label_out -- security_label output function */
|
|
+Datum
|
|
+security_label_out(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid sid = PG_GETARG_OID(0);
|
|
+ char *label;
|
|
+
|
|
+ label = sid_to_security_label(sid);
|
|
+ label = pgaceSecurityLabelOut(label);
|
|
+
|
|
+ PG_RETURN_CSTRING(label);
|
|
+}
|
|
+
|
|
+/* security_label_raw_in -- security_label input function in raw format */
|
|
+Datum
|
|
+security_label_raw_in(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ char *label = PG_GETARG_CSTRING(0);
|
|
+
|
|
+ PG_RETURN_OID(security_label_to_sid(label));
|
|
+}
|
|
+
|
|
+/* security_label_raw_out -- security_label output function in raw format */
|
|
+Datum
|
|
+security_label_raw_out(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid sid = PG_GETARG_OID(0);
|
|
+
|
|
+ PG_RETURN_CSTRING(sid_to_security_label(sid));
|
|
+}
|
|
+
|
|
+/* text_to_security_label -- security_label cast function */
|
|
+Datum
|
|
+text_to_security_label(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ text *t = PG_GETARG_TEXT_P(0);
|
|
+ char *seclabel;
|
|
+ int len;
|
|
+ Datum sid;
|
|
+
|
|
+ len = VARSIZE(t) - VARHDRSZ;
|
|
+ seclabel = palloc0(len + 1);
|
|
+ memcpy(seclabel, VARDATA(t), len);
|
|
+ sid = DirectFunctionCall1(security_label_in,
|
|
+ CStringGetDatum(seclabel));
|
|
+ pfree(seclabel);
|
|
+ PG_RETURN_DATUM(sid);
|
|
+}
|
|
+
|
|
+/* security_label_to_text -- security_label cast function */
|
|
+Datum
|
|
+security_label_to_text(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid sid = PG_GETARG_OID(0);
|
|
+ char *context;
|
|
+ text *result;
|
|
+
|
|
+ context = DatumGetCString(DirectFunctionCall1(security_label_out,
|
|
+ ObjectIdGetDatum(sid)));
|
|
+ result = palloc(VARHDRSZ + strlen(context));
|
|
+ VARATT_SIZEP(result) = VARHDRSZ + strlen(context);
|
|
+ memcpy(VARDATA(result), context, strlen(context));
|
|
+
|
|
+ PG_RETURN_TEXT_P(result);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * Set/Get security attribute of Large Object
|
|
+ *****************************************************************************/
|
|
+Datum
|
|
+lo_get_security(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid loid = PG_GETARG_OID(0);
|
|
+ Oid lo_security = InvalidOid;
|
|
+ Relation rel;
|
|
+ ScanKeyData skey;
|
|
+ SysScanDesc sd;
|
|
+ HeapTuple tuple;
|
|
+ bool found = false;
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(loid));
|
|
+
|
|
+ rel = heap_open(LargeObjectRelationId, AccessShareLock);
|
|
+
|
|
+ sd = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
|
|
+ SnapshotNow, 1, &skey);
|
|
+
|
|
+ while ((tuple = systable_getnext(sd)) != NULL) {
|
|
+ lo_security = pgaceLargeObjectGetSecurity(tuple);
|
|
+ found = true;
|
|
+ break;
|
|
+ }
|
|
+ systable_endscan(sd);
|
|
+
|
|
+ heap_close(rel, AccessShareLock);
|
|
+
|
|
+ if (!found)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
+ errmsg("large object %u does not exist", loid)));
|
|
+
|
|
+ PG_RETURN_OID(lo_security);
|
|
+}
|
|
+
|
|
+Datum
|
|
+lo_set_security(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid loid = PG_GETARG_OID(0);
|
|
+ Oid lo_security = PG_GETARG_OID(1);
|
|
+ Relation rel;
|
|
+ ScanKeyData skey;
|
|
+ SysScanDesc sd;
|
|
+ HeapTuple tuple, newtup;
|
|
+ CatalogIndexState indstate;
|
|
+ bool found = false;
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(loid));
|
|
+
|
|
+ rel = heap_open(LargeObjectRelationId, RowExclusiveLock);
|
|
+
|
|
+ indstate = CatalogOpenIndexes(rel);
|
|
+
|
|
+ sd = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
|
|
+ SnapshotNow, 1, &skey);
|
|
+
|
|
+ while ((tuple = systable_getnext(sd)) != NULL) {
|
|
+ newtup = heap_copytuple(tuple);
|
|
+ pgaceLargeObjectSetSecurity(newtup, lo_security, !found);
|
|
+ simple_heap_update(rel, &newtup->t_self, newtup);
|
|
+ CatalogUpdateIndexes(rel, newtup);
|
|
+ found = true;
|
|
+ }
|
|
+ systable_endscan(sd);
|
|
+ CatalogCloseIndexes(indstate);
|
|
+ heap_close(rel, RowExclusiveLock);
|
|
+
|
|
+ CommandCounterIncrement();
|
|
+
|
|
+ if (!found)
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
+ errmsg("large object %u does not exist", loid)));
|
|
+
|
|
+ PG_RETURN_BOOL(true);
|
|
+}
|
|
+
|
|
+#ifndef HAVE_SELINUX
|
|
+/* dummy definitions for SE-PostgreSQL */
|
|
+Datum sepgsql_getcon(PG_FUNCTION_ARGS);
|
|
+Datum sepgsql_tuple_perms(PG_FUNCTION_ARGS);
|
|
+Datum sepgsql_tuple_perms_abort(PG_FUNCTION_ARGS);
|
|
+
|
|
+Datum
|
|
+sepgsql_getcon(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
+ errmsg("SE-PostgreSQL is not configured")));
|
|
+ PG_RETURN_OID(InvalidOid);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_tuple_perms(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
+ errmsg("SE-PostgreSQL is not configured")));
|
|
+ PG_RETURN_BOOL(false);
|
|
+}
|
|
+
|
|
+Datum
|
|
+sepgsql_tuple_perms_abort(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
+ errmsg("SE-PostgreSQL is not configured")));
|
|
+ PG_RETURN_BOOL(false);
|
|
+}
|
|
+#endif
|
|
diff -rpNU3 base/src/backend/security/sepgsqlCore.c sepgsql/src/backend/security/sepgsqlCore.c
|
|
--- base/src/backend/security/sepgsqlCore.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/sepgsqlCore.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -0,0 +1,1019 @@
|
|
+/*
|
|
+ * src/backend/security/sepgsqlCore.c
|
|
+ * SE-PostgreSQL core facilities like userspace AVC, policy state monitoring.
|
|
+ *
|
|
+ * Copyright (c) 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/heapam.h"
|
|
+#include "access/genam.h"
|
|
+#include "access/tupdesc.h"
|
|
+#include "access/xact.h"
|
|
+#include "libpq/libpq-be.h"
|
|
+#include "libpq/pqsignal.h"
|
|
+#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
+#include "storage/lwlock.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/rel.h"
|
|
+#include "utils/syscache.h"
|
|
+#include <linux/netlink.h>
|
|
+#include <linux/selinux_netlink.h>
|
|
+#include <sched.h>
|
|
+#include <signal.h>
|
|
+#include <sys/file.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/wait.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+static struct {
|
|
+ struct {
|
|
+ char *name; /* name of object class */
|
|
+ uint16 inum; /* internal identifier number */
|
|
+ } tclass;
|
|
+ struct {
|
|
+ char *name; /* name of access vector */
|
|
+ uint32 inum; /* internal identifier number */
|
|
+ } av_perms[sizeof(access_vector_t) * 8];
|
|
+} selinux_catalog[] = {
|
|
+ {
|
|
+ { "db_database", SECCLASS_DB_DATABASE },
|
|
+ {
|
|
+ { "create", DB_DATABASE__CREATE },
|
|
+ { "drop", DB_DATABASE__DROP },
|
|
+ { "getattr", DB_DATABASE__GETATTR },
|
|
+ { "setattr", DB_DATABASE__SETATTR },
|
|
+ { "relabelfrom", DB_DATABASE__RELABELFROM },
|
|
+ { "relabelto", DB_DATABASE__RELABELTO },
|
|
+ { "access", DB_DATABASE__ACCESS },
|
|
+ { "install_module", DB_DATABASE__INSTALL_MODULE },
|
|
+ { "load_module", DB_DATABASE__LOAD_MODULE },
|
|
+ { "get_param", DB_DATABASE__GET_PARAM },
|
|
+ { "set_param", DB_DATABASE__SET_PARAM },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ { "db_table", SECCLASS_DB_TABLE },
|
|
+ {
|
|
+ { "create", DB_TABLE__CREATE },
|
|
+ { "drop", DB_TABLE__DROP },
|
|
+ { "getattr", DB_TABLE__GETATTR },
|
|
+ { "setattr", DB_TABLE__SETATTR },
|
|
+ { "relabelfrom", DB_TABLE__RELABELFROM },
|
|
+ { "relabelto", DB_TABLE__RELABELTO },
|
|
+ { "use", DB_TABLE__USE },
|
|
+ { "select", DB_TABLE__SELECT },
|
|
+ { "update", DB_TABLE__UPDATE },
|
|
+ { "insert", DB_TABLE__INSERT },
|
|
+ { "delete", DB_TABLE__DELETE },
|
|
+ { "lock", DB_TABLE__LOCK },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ { "db_procedure", SECCLASS_DB_PROCEDURE },
|
|
+ {
|
|
+ { "create", DB_PROCEDURE__CREATE },
|
|
+ { "drop", DB_PROCEDURE__DROP },
|
|
+ { "getattr", DB_PROCEDURE__GETATTR },
|
|
+ { "setattr", DB_PROCEDURE__SETATTR },
|
|
+ { "relabelfrom", DB_PROCEDURE__RELABELFROM },
|
|
+ { "relabelto", DB_PROCEDURE__RELABELTO },
|
|
+ { "execute", DB_PROCEDURE__EXECUTE },
|
|
+ { "entrypoint", DB_PROCEDURE__ENTRYPOINT },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ { "db_column", SECCLASS_DB_COLUMN },
|
|
+ {
|
|
+ { "create", DB_COLUMN__CREATE },
|
|
+ { "drop", DB_COLUMN__DROP },
|
|
+ { "getattr", DB_COLUMN__GETATTR },
|
|
+ { "setattr", DB_COLUMN__SETATTR },
|
|
+ { "relabelfrom", DB_COLUMN__RELABELFROM },
|
|
+ { "relabelto", DB_COLUMN__RELABELTO },
|
|
+ { "use", DB_COLUMN__USE },
|
|
+ { "select", DB_COLUMN__SELECT },
|
|
+ { "update", DB_COLUMN__UPDATE },
|
|
+ { "insert", DB_COLUMN__INSERT },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ { "db_tuple", SECCLASS_DB_TUPLE },
|
|
+ {
|
|
+ { "relabelfrom", DB_TUPLE__RELABELFROM },
|
|
+ { "relabelto", DB_TUPLE__RELABELTO },
|
|
+ { "use", DB_TUPLE__USE },
|
|
+ { "select", DB_TUPLE__SELECT },
|
|
+ { "update", DB_TUPLE__UPDATE },
|
|
+ { "insert", DB_TUPLE__INSERT },
|
|
+ { "delete", DB_TUPLE__DELETE },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+ {
|
|
+ { "db_blob", SECCLASS_DB_BLOB },
|
|
+ {
|
|
+ { "create", DB_BLOB__CREATE },
|
|
+ { "drop", DB_BLOB__DROP },
|
|
+ { "getattr", DB_BLOB__GETATTR },
|
|
+ { "setattr", DB_BLOB__SETATTR },
|
|
+ { "relabelfrom", DB_BLOB__RELABELFROM },
|
|
+ { "relabelto", DB_BLOB__RELABELTO },
|
|
+ { "read", DB_BLOB__READ },
|
|
+ { "write", DB_BLOB__WRITE },
|
|
+ { "import", DB_BLOB__IMPORT },
|
|
+ { "export", DB_BLOB__EXPORT },
|
|
+ { NULL, 0UL },
|
|
+ }
|
|
+ },
|
|
+};
|
|
+#define NUM_SELINUX_CATALOG (sizeof(selinux_catalog) / sizeof(selinux_catalog[0]))
|
|
+
|
|
+static const char *sepgsql_class_to_string(uint16 tclass)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i=0; i < NUM_SELINUX_CATALOG; i++) {
|
|
+ if (selinux_catalog[i].tclass.inum == tclass)
|
|
+ return selinux_catalog[i].tclass.name;
|
|
+ }
|
|
+#ifdef SEPGSQLOPT_LIBSELINUX_1_33
|
|
+ /* for legacy libselinux (Fedora core 6) */
|
|
+ /* This code will be replaced near future */
|
|
+ if (tclass == SECCLASS_PROCESS)
|
|
+ return "process";
|
|
+ return "unknown";
|
|
+#else
|
|
+ /* because tclass didn't match with userspace object classes,
|
|
+ * its external representation is always same as internal one */
|
|
+ return security_class_to_string((security_class_t) tclass);
|
|
+#endif
|
|
+}
|
|
+
|
|
+static const char *sepgsql_av_perm_to_string(uint16 tclass, uint32 perm)
|
|
+{
|
|
+ int i, j;
|
|
+
|
|
+ for (i=0; i < NUM_SELINUX_CATALOG; i++) {
|
|
+ if (selinux_catalog[i].tclass.inum == tclass) {
|
|
+ char *perm_name;
|
|
+
|
|
+ for (j=0; (perm_name = selinux_catalog[i].av_perms[j].name); j++) {
|
|
+ if (selinux_catalog[i].av_perms[j].inum == perm)
|
|
+ return perm_name;
|
|
+ }
|
|
+ return "unknown";
|
|
+ }
|
|
+ }
|
|
+#ifdef SEPGSQLOPT_LIBSELINUX_1_33
|
|
+ /* for legacy libselinux (Fedora core 6) */
|
|
+ /* This code will be replaced near future */
|
|
+ if (tclass == SECCLASS_PROCESS && perm == PROCESS__TRANSITION)
|
|
+ return "transition";
|
|
+ return "unknown";
|
|
+#else
|
|
+ /* because tclass/perm didn't match with userspace object classes,
|
|
+ * its external representation is always same as internal one */
|
|
+ return security_av_perm_to_string((security_class_t) tclass, (access_vector_t) perm);
|
|
+#endif
|
|
+}
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL Internal AVC(Access Vector Cache) implementation.
|
|
+ *
|
|
+ */
|
|
+struct avc_datum {
|
|
+ SHMEM_OFFSET next;
|
|
+
|
|
+ Oid ssid; /* subject context */
|
|
+ Oid tsid; /* object context */
|
|
+ uint16 tclass; /* object class */
|
|
+
|
|
+ uint32 allowed;
|
|
+ uint32 decided;
|
|
+ uint32 auditallow;
|
|
+ uint32 auditdeny;
|
|
+
|
|
+ Oid create; /* newly created context */
|
|
+ bool is_hot;
|
|
+};
|
|
+
|
|
+#define AVC_DATUM_CACHE_SLOTS 512
|
|
+#define AVC_DATUM_CACHE_MAXNODES 800
|
|
+static struct {
|
|
+ LWLockId lock;
|
|
+ SHMEM_OFFSET slot[AVC_DATUM_CACHE_SLOTS];
|
|
+ SHMEM_OFFSET freelist;
|
|
+ int lru_hint;
|
|
+ int enabled;
|
|
+ int enforcing;
|
|
+ struct avc_datum entry[AVC_DATUM_CACHE_MAXNODES];
|
|
+
|
|
+ /* dynamic object class/av permission mapping */
|
|
+ struct {
|
|
+ struct {
|
|
+ uint16 internal;
|
|
+ security_class_t external;
|
|
+ } tclass;
|
|
+ struct {
|
|
+ uint32 internal;
|
|
+ access_vector_t external;
|
|
+ } av_perms[sizeof(access_vector_t) * 8];
|
|
+ } catalog[NUM_SELINUX_CATALOG];
|
|
+} *avc_shmem = NULL;
|
|
+
|
|
+Size sepgsqlShmemSize()
|
|
+{
|
|
+ return sizeof(*avc_shmem);
|
|
+}
|
|
+
|
|
+static void sepgsql_load_class_av_mapping()
|
|
+{
|
|
+ extern char *selinux_mnt;
|
|
+ char buffer[PATH_MAX];
|
|
+ struct stat st_buf;
|
|
+ int i, j, fd, len;
|
|
+
|
|
+ if (!selinux_mnt)
|
|
+ goto legacy_mapping;
|
|
+
|
|
+ /* Does '/selinux/class' exist? */
|
|
+ snprintf(buffer, sizeof(buffer), "%s/class", selinux_mnt);
|
|
+ if (lstat(buffer, &st_buf) || !S_ISDIR(st_buf.st_mode))
|
|
+ goto legacy_mapping;
|
|
+
|
|
+ for (i=0; i < NUM_SELINUX_CATALOG; i++) {
|
|
+ /* obtain external object class number */
|
|
+ snprintf(buffer, sizeof(buffer), "%s/class/%s/index",
|
|
+ selinux_mnt, selinux_catalog[i].tclass.name);
|
|
+ fd = open(buffer, O_RDONLY);
|
|
+ if (fd < 0)
|
|
+ goto legacy_mapping;
|
|
+
|
|
+ len = read(fd, buffer, sizeof(buffer));
|
|
+ close(fd);
|
|
+ if (len < 1)
|
|
+ goto legacy_mapping;
|
|
+ buffer[len] = '\0';
|
|
+
|
|
+ avc_shmem->catalog[i].tclass.internal
|
|
+ = selinux_catalog[i].tclass.inum;
|
|
+ avc_shmem->catalog[i].tclass.external
|
|
+ = atoi(buffer);
|
|
+
|
|
+ /* obtain external access vector number */
|
|
+ for (j=0; selinux_catalog[i].av_perms[j].name; j++) {
|
|
+ snprintf(buffer, sizeof(buffer), "%s/class/%s/perms/%s",
|
|
+ selinux_mnt,
|
|
+ selinux_catalog[i].tclass.name,
|
|
+ selinux_catalog[i].av_perms[j].name);
|
|
+ fd = open(buffer, O_RDONLY);
|
|
+ if (fd < 0)
|
|
+ goto legacy_mapping;
|
|
+
|
|
+ len = read(fd, buffer, sizeof(buffer));
|
|
+ close(fd);
|
|
+ if (len < 1)
|
|
+ goto legacy_mapping;
|
|
+ buffer[len] = '\0';
|
|
+
|
|
+ avc_shmem->catalog[i].av_perms[j].internal
|
|
+ = selinux_catalog[i].av_perms[j].inum;
|
|
+ avc_shmem->catalog[i].av_perms[j].external
|
|
+ = (0x0001UL << (atoi(buffer) - 1));
|
|
+ }
|
|
+ }
|
|
+ return;
|
|
+
|
|
+legacy_mapping:
|
|
+ for (i=0; i < NUM_SELINUX_CATALOG; i++) {
|
|
+ uint16 tclass = selinux_catalog[i].tclass.inum;
|
|
+
|
|
+ avc_shmem->catalog[i].tclass.internal = tclass;
|
|
+ avc_shmem->catalog[i].tclass.external = tclass;
|
|
+
|
|
+ for (j=0; selinux_catalog[i].av_perms[j].name; j++) {
|
|
+ uint32 av_perm = selinux_catalog[i].av_perms[j].inum;
|
|
+
|
|
+ avc_shmem->catalog[i].av_perms[j].internal = av_perm;
|
|
+ avc_shmem->catalog[i].av_perms[j].external = av_perm;
|
|
+ }
|
|
+ }
|
|
+ return;
|
|
+}
|
|
+
|
|
+static void sepgsql_avc_reset()
|
|
+{
|
|
+ int i, enforcing, enabled;
|
|
+
|
|
+ enabled = is_selinux_enabled();
|
|
+ enforcing = security_getenforce();
|
|
+ Assert(enforcing==0 || enforcing==1);
|
|
+
|
|
+ LWLockAcquire(avc_shmem->lock, LW_EXCLUSIVE);
|
|
+
|
|
+ for (i=0; i < AVC_DATUM_CACHE_SLOTS; i++)
|
|
+ avc_shmem->slot[i] = INVALID_OFFSET;
|
|
+ avc_shmem->freelist = INVALID_OFFSET;
|
|
+ for (i=0; i < AVC_DATUM_CACHE_MAXNODES; i++) {
|
|
+ struct avc_datum *avd = avc_shmem->entry + i;
|
|
+
|
|
+ memset(avd, 0, sizeof(struct avc_datum));
|
|
+ avd->next = avc_shmem->freelist;
|
|
+ avc_shmem->freelist = MAKE_OFFSET(avd);
|
|
+ }
|
|
+ sepgsql_load_class_av_mapping();
|
|
+ avc_shmem->enabled = enabled;
|
|
+ avc_shmem->enforcing = enforcing;
|
|
+
|
|
+ LWLockRelease(avc_shmem->lock);
|
|
+}
|
|
+
|
|
+static void sepgsql_avc_init()
|
|
+{
|
|
+ bool found_avc;
|
|
+
|
|
+ avc_shmem = ShmemInitStruct("SELinux userspace AVC",
|
|
+ sepgsqlShmemSize(), &found_avc);
|
|
+ if (!found_avc) {
|
|
+ avc_shmem->lock = LWLockAssign();
|
|
+ sepgsql_avc_reset();
|
|
+ }
|
|
+}
|
|
+
|
|
+static uint32 sepgsql_validate_av_perms(security_class_t tclass, access_vector_t perms)
|
|
+{
|
|
+ /* we have to hold LW_SHARED lock at least */
|
|
+ int i, j;
|
|
+
|
|
+ for (i=0; i < NUM_SELINUX_CATALOG; i++) {
|
|
+ if (avc_shmem->catalog[i].tclass.external == tclass) {
|
|
+ uint32 __perms = 0;
|
|
+
|
|
+ for (j=0; j < sizeof(access_vector_t) * 8; j++) {
|
|
+ if (avc_shmem->catalog[i].av_perms[j].external & perms)
|
|
+ __perms |= avc_shmem->catalog[i].av_perms[j].internal;
|
|
+ }
|
|
+ //selnotice("tclass(ext:%d -> int:%d) av_perms(ext:%08x -> int:%08x) validated",
|
|
+ // tclass, avc_shmem->catalog[i].tclass.internal,
|
|
+ // perms, __perms);
|
|
+ return __perms;
|
|
+ }
|
|
+ }
|
|
+ //selnotice("tclass = %d is not user tclass, perms (%08x) is used as is", tclass, perms);
|
|
+
|
|
+ return (uint32) perms;
|
|
+}
|
|
+
|
|
+static void sepgsql_compute_avc_datum(Oid ssid, Oid tsid, uint16 tclass,
|
|
+ struct avc_datum *avd)
|
|
+{
|
|
+ security_class_t tclass_external = tclass;
|
|
+ security_context_t scon, tcon, ncon;
|
|
+ struct av_decision x;
|
|
+ Datum tmp;
|
|
+ int i;
|
|
+
|
|
+ memset(avd, 0, sizeof(struct avc_datum));
|
|
+ tmp = DirectFunctionCall1(security_label_raw_out,
|
|
+ ObjectIdGetDatum(ssid));
|
|
+ scon = DatumGetCString(tmp);
|
|
+ tmp = DirectFunctionCall1(security_label_raw_out,
|
|
+ ObjectIdGetDatum(tsid));
|
|
+ tcon = DatumGetCString(tmp);
|
|
+
|
|
+ LWLockAcquire(avc_shmem->lock, LW_SHARED);
|
|
+ /* translate internal tclass into external one, to query the kernel */
|
|
+ for (i=0; i < NUM_SELINUX_CATALOG; i++) {
|
|
+ if (avc_shmem->catalog[i].tclass.internal == tclass) {
|
|
+ tclass_external = avc_shmem->catalog[i].tclass.external;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (security_compute_av_raw(scon, tcon, tclass_external, 0, &x))
|
|
+ selerror("could not obtain access vector decision "
|
|
+ " scon='%s' tcon='%s' tclass=%u", scon, tcon, tclass);
|
|
+ if (security_compute_create_raw(scon, tcon, tclass_external, &ncon) != 0)
|
|
+ selerror("could not obtain a newly created security context "
|
|
+ "scon='%s' tcon='%s' tclass=%u", scon, tcon, tclass);
|
|
+
|
|
+ avd->ssid = ssid;
|
|
+ avd->tsid = tsid;
|
|
+ avd->tclass = tclass;
|
|
+
|
|
+ avd->allowed = sepgsql_validate_av_perms(tclass_external, x.allowed);
|
|
+ avd->decided = sepgsql_validate_av_perms(tclass_external, x.decided);
|
|
+ avd->auditallow = sepgsql_validate_av_perms(tclass_external, x.auditallow);
|
|
+ avd->auditdeny = sepgsql_validate_av_perms(tclass_external, x.auditdeny);
|
|
+ LWLockRelease(avc_shmem->lock);
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ tmp = DirectFunctionCall1(security_label_raw_in,
|
|
+ CStringGetDatum(ncon));
|
|
+ avd->create = DatumGetObjectId(tmp);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(ncon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ pfree(scon);
|
|
+ pfree(tcon);
|
|
+ freecon(ncon);
|
|
+}
|
|
+
|
|
+static Oid sepgsql_compute_relabel(Oid ssid, Oid tsid, uint16 tclass)
|
|
+{
|
|
+ security_context_t scon, tcon, ncon;
|
|
+ Oid nsid;
|
|
+ Datum tmp;
|
|
+
|
|
+ tmp = DirectFunctionCall1(security_label_raw_out,
|
|
+ ObjectIdGetDatum(ssid));
|
|
+ scon = DatumGetCString(tmp);
|
|
+ tmp = DirectFunctionCall1(security_label_raw_out,
|
|
+ ObjectIdGetDatum(tsid));
|
|
+ tcon = DatumGetCString(tmp);
|
|
+
|
|
+ if (security_compute_relabel_raw(scon, tcon, tclass, &ncon) != 0)
|
|
+ selerror("could not obtain a newly relabeled security context "
|
|
+ "scon='%s' tcon='%s' tclass=%u", scon, tcon, tclass);
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ tmp = DirectFunctionCall1(security_label_raw_in,
|
|
+ CStringGetDatum(ncon));
|
|
+ nsid = DatumGetObjectId(tmp);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(ncon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ freecon(ncon);
|
|
+ pfree(scon);
|
|
+ pfree(tcon);
|
|
+
|
|
+ return nsid;
|
|
+}
|
|
+
|
|
+static char *sepgsql_avc_audit(uint32 perms, struct avc_datum *avd, char *objname)
|
|
+{
|
|
+ /* we have to hold LW_SHARED lock at least */
|
|
+ uint32 denied, audited, mask;
|
|
+ char buffer[4096];
|
|
+ char *context;
|
|
+ int len;
|
|
+
|
|
+ denied = perms & ~avd->allowed;
|
|
+ audited = denied ? (denied & avd->auditdeny) : (perms & avd->auditallow);
|
|
+ if (!audited)
|
|
+ return NULL;
|
|
+
|
|
+ len = snprintf(buffer, sizeof(buffer), "%s {", denied ? "denied" : "granted");
|
|
+ for (mask=1; mask; mask <<= 1) {
|
|
+ if (audited & mask) {
|
|
+ len += snprintf(buffer + len, sizeof(buffer) - len, " %s",
|
|
+ sepgsql_av_perm_to_string(avd->tclass, mask));
|
|
+ }
|
|
+ }
|
|
+ len += snprintf(buffer + len, sizeof(buffer) - len, " }");
|
|
+
|
|
+ context = DatumGetCString(DirectFunctionCall1(security_label_out,
|
|
+ ObjectIdGetDatum(avd->ssid)));
|
|
+ len += snprintf(buffer + len, sizeof(buffer) - len, " scontext=%s", context);
|
|
+ pfree(context);
|
|
+
|
|
+ context = DatumGetCString(DirectFunctionCall1(security_label_out,
|
|
+ ObjectIdGetDatum(avd->tsid)));
|
|
+ len += snprintf(buffer + len, sizeof(buffer) - len, " tcontext=%s", context);
|
|
+ pfree(context);
|
|
+
|
|
+ len += snprintf(buffer + len, sizeof(buffer) - len, " tclass=%s",
|
|
+ sepgsql_class_to_string(avd->tclass));
|
|
+ if (objname)
|
|
+ len += snprintf(buffer + len, sizeof(buffer) - len, " name=%s", objname);
|
|
+
|
|
+ return pstrdup(buffer);
|
|
+}
|
|
+
|
|
+static inline int sepgsql_avc_hash(Oid ssid, Oid tsid, uint16 tclass)
|
|
+{
|
|
+ return ((uint32)ssid ^ ((uint32)tsid << 2) ^ tclass) % AVC_DATUM_CACHE_SLOTS;
|
|
+}
|
|
+
|
|
+static struct avc_datum *
|
|
+sepgsql_avc_lookup(Oid ssid, Oid tsid, uint16 tclass, uint32 perms)
|
|
+{
|
|
+ /* we have to hold LW_SHARED lock at least */
|
|
+ struct avc_datum *avd;
|
|
+ SHMEM_OFFSET curr;
|
|
+ int hashkey = sepgsql_avc_hash(ssid, tsid, tclass);
|
|
+
|
|
+ for (curr = avc_shmem->slot[hashkey];
|
|
+ SHM_OFFSET_VALID(curr);
|
|
+ curr = avd->next) {
|
|
+ avd = (void *)MAKE_PTR(curr);
|
|
+ if (avd->ssid==ssid && avd->tsid==tsid && avd->tclass==tclass
|
|
+ && (perms & avd->decided)==perms)
|
|
+ return avd;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void sepgsql_avc_reclaim() {
|
|
+ /* we have to hold LW_EXCLUSIVE lock */
|
|
+ SHMEM_OFFSET *prev, next;
|
|
+ struct avc_datum *avd;
|
|
+
|
|
+ while (!SHM_OFFSET_VALID(avc_shmem->freelist)) {
|
|
+ prev = avc_shmem->slot + avc_shmem->lru_hint;
|
|
+ next = *prev;
|
|
+ while (!SHM_OFFSET_VALID(next)) {
|
|
+ avd = (void *)MAKE_PTR(next);
|
|
+ next = avd->next;
|
|
+ if (avd->is_hot) {
|
|
+ avd->is_hot = false;
|
|
+ } else {
|
|
+ *prev = avd->next;
|
|
+ avd->next = avc_shmem->freelist;
|
|
+ avc_shmem->freelist = MAKE_OFFSET(avd);
|
|
+ }
|
|
+ avd = (void *)MAKE_PTR(next);
|
|
+ }
|
|
+ avc_shmem->lru_hint = (avc_shmem->lru_hint + 1) % AVC_DATUM_CACHE_SLOTS;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void sepgsql_avc_insert(struct avc_datum *tmp)
|
|
+{
|
|
+ /* we have to hold LW_EXCLUSIVE lock */
|
|
+ struct avc_datum *avd;
|
|
+ int hashkey;
|
|
+
|
|
+ avd = sepgsql_avc_lookup(tmp->ssid, tmp->tsid, tmp->tclass, tmp->decided);
|
|
+ if (avd)
|
|
+ return;
|
|
+
|
|
+ if (!SHM_OFFSET_VALID(avc_shmem->freelist))
|
|
+ sepgsql_avc_reclaim();
|
|
+ Assert(SHM_OFFSET_VALID(avc_shmem->freelist));
|
|
+
|
|
+ avd = (void *)MAKE_PTR(avc_shmem->freelist);
|
|
+ avc_shmem->freelist = avd->next;
|
|
+
|
|
+ memcpy(avd, tmp, sizeof(struct avc_datum));
|
|
+ avd->is_hot = true;
|
|
+
|
|
+ hashkey = sepgsql_avc_hash(avd->ssid, avd->tsid, avd->tclass);
|
|
+ avd->next = avc_shmem->slot[hashkey];
|
|
+ avc_shmem->slot[hashkey] = MAKE_OFFSET(avd);
|
|
+
|
|
+ return;
|
|
+}
|
|
+
|
|
+bool sepgsql_avc_permission_noaudit(Oid ssid, Oid tsid, uint16 tclass, uint32 perms,
|
|
+ char **audit, char *objname)
|
|
+{
|
|
+ struct avc_datum *avd, lavd;
|
|
+ uint32 denied;
|
|
+ bool rc = true;
|
|
+ bool wlock = false;
|
|
+
|
|
+ LWLockAcquire(avc_shmem->lock, LW_SHARED);
|
|
+retry:
|
|
+ avd = sepgsql_avc_lookup(ssid, tsid, tclass, perms);
|
|
+ if (!avd) {
|
|
+ LWLockRelease(avc_shmem->lock);
|
|
+
|
|
+ sepgsql_compute_avc_datum(ssid, tsid, tclass, &lavd);
|
|
+
|
|
+ LWLockAcquire(avc_shmem->lock, LW_EXCLUSIVE);
|
|
+ wlock = true;
|
|
+ sepgsql_avc_insert(&lavd);
|
|
+ } else {
|
|
+ memcpy(&lavd, avd, sizeof(struct avc_datum));
|
|
+ }
|
|
+ denied = perms & ~lavd.allowed;
|
|
+ if (!perms || denied) {
|
|
+ if (avc_shmem->enforcing) {
|
|
+ errno = EACCES;
|
|
+ rc = false;
|
|
+ } else {
|
|
+ if (!wlock) {
|
|
+ /* update avd need LW_EXCLUSIVE lock onto shmem */
|
|
+ LWLockRelease(avc_shmem->lock);
|
|
+ LWLockAcquire(avc_shmem->lock, LW_EXCLUSIVE);
|
|
+ wlock = true;
|
|
+ goto retry;
|
|
+ }
|
|
+ /* grant permission to avoid flood of access denied log */
|
|
+ if (!avd)
|
|
+ avd = sepgsql_avc_lookup(ssid, tsid, tclass, perms);
|
|
+ if (avd)
|
|
+ avd->allowed |= denied;
|
|
+ }
|
|
+ }
|
|
+ LWLockRelease(avc_shmem->lock);
|
|
+ if (audit)
|
|
+ *audit = sepgsql_avc_audit(perms, &lavd, objname);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+void sepgsql_avc_permission(Oid ssid, Oid tsid, uint16 tclass, uint32 perms, char *objname)
|
|
+{
|
|
+ char *audit;
|
|
+ bool rc;
|
|
+
|
|
+ rc = sepgsql_avc_permission_noaudit(ssid, tsid, tclass, perms, &audit, objname);
|
|
+ sepgsql_audit(rc, audit);
|
|
+
|
|
+ if (audit)
|
|
+ pfree(audit);
|
|
+}
|
|
+
|
|
+void sepgsql_audit(bool result, char *message)
|
|
+{
|
|
+ if (message) {
|
|
+ ereport((result ? NOTICE : ERROR),
|
|
+ (errcode(ERRCODE_INTERNAL_ERROR),
|
|
+ errmsg("SELinux: %s", message)));
|
|
+ } else if (!result) {
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INTERNAL_ERROR),
|
|
+ errmsg("Transaction aborted due to SELinux access denied.")));
|
|
+ }
|
|
+}
|
|
+
|
|
+Oid sepgsql_avc_createcon(Oid ssid, Oid tsid, uint16 tclass)
|
|
+{
|
|
+ struct avc_datum *avd, lavd;
|
|
+ Oid nsid;
|
|
+
|
|
+ LWLockAcquire(avc_shmem->lock, LW_SHARED);
|
|
+ avd = sepgsql_avc_lookup(ssid, tsid, tclass, 0);
|
|
+ if (!avd) {
|
|
+ LWLockRelease(avc_shmem->lock);
|
|
+
|
|
+ sepgsql_compute_avc_datum(ssid, tsid, tclass, &lavd);
|
|
+
|
|
+ LWLockAcquire(avc_shmem->lock, LW_EXCLUSIVE);
|
|
+ sepgsql_avc_insert(&lavd);
|
|
+ nsid = lavd.create;
|
|
+ } else {
|
|
+ nsid = avd->create;
|
|
+ }
|
|
+ LWLockRelease(avc_shmem->lock);
|
|
+
|
|
+ return nsid;
|
|
+}
|
|
+
|
|
+Oid sepgsql_avc_relabelcon(Oid ssid, Oid tsid, uint16 tclass)
|
|
+{
|
|
+ /* currently no avc support on relabeling */
|
|
+ return sepgsql_compute_relabel(ssid, tsid, tclass);
|
|
+}
|
|
+
|
|
+/* sepgsql_getcon() -- returns a security context of client */
|
|
+Datum
|
|
+sepgsql_getcon(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ PG_RETURN_OID(sepgsqlGetClientContext());
|
|
+}
|
|
+
|
|
+/* sepgsql_system_getcon() -- obtain the server's context */
|
|
+static Oid sepgsql_system_getcon()
|
|
+{
|
|
+ security_context_t context;
|
|
+ Oid ssid;
|
|
+
|
|
+ if (getcon_raw(&context) != 0)
|
|
+ selerror("could not obtain security context of server process");
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ ssid = DatumGetObjectId(DirectFunctionCall1(security_label_raw_in,
|
|
+ CStringGetDatum(context)));
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(context);
|
|
+ return ssid;
|
|
+}
|
|
+
|
|
+/* sepgsql_system_getpeercon() -- obtain the client's context */
|
|
+static Oid sepgsql_system_getpeercon(int sockfd)
|
|
+{
|
|
+ security_context_t context, __context;
|
|
+ Oid ssid;
|
|
+
|
|
+ if (getpeercon_raw(sockfd, &context)) {
|
|
+ /* we can set finally fallbacked context */
|
|
+ __context = getenv("SEPGSQL_FALLBACK_CONTEXT");
|
|
+ if (!__context)
|
|
+ selerror("could not obtain security context of database client");
|
|
+ if (security_check_context(__context) ||
|
|
+ selinux_trans_to_raw_context(__context, &context))
|
|
+ selerror("'%s' is not a valid context", __context);
|
|
+ }
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ ssid = DatumGetObjectId(DirectFunctionCall1(security_label_raw_in,
|
|
+ CStringGetDatum(context)));
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(context);
|
|
+ return ssid;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL core functions
|
|
+ *
|
|
+ * sepgsqlGetServerContext() -- obtains server's context
|
|
+ * sepgsqlGetClientContext() -- obtains client's context via getpeercon()
|
|
+ * sepgsqlSetClientContext() -- changes client's context for trusted procedure
|
|
+ * sepgsqlInitialize() -- called when initializing 'postgres' includes bootstraping
|
|
+ * sepgsqlInitializePostmaster() -- called when initializing 'postmaster'
|
|
+ * sepgsqlFinalizePostmaster() -- called when finalizing 'postmaster' to kill
|
|
+ * policy state monitoring process.
|
|
+ * sepgsqlMonitoringPolicyState() -- is implementation of policy state monitoring
|
|
+ * process.
|
|
+ *
|
|
+ */
|
|
+static Oid sepgsqlServerContext = InvalidOid;
|
|
+static Oid sepgsqlClientContext = InvalidOid;
|
|
+
|
|
+Oid sepgsqlGetServerContext()
|
|
+{
|
|
+ return sepgsqlServerContext;
|
|
+}
|
|
+
|
|
+Oid sepgsqlGetClientContext()
|
|
+{
|
|
+ return sepgsqlClientContext;
|
|
+}
|
|
+
|
|
+void sepgsqlSetClientContext(Oid new_context)
|
|
+{
|
|
+ sepgsqlClientContext = new_context;
|
|
+}
|
|
+
|
|
+Oid sepgsqlGetDatabaseContext()
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ Oid datcon;
|
|
+
|
|
+ if (IsBootstrapProcessingMode()) {
|
|
+ return sepgsql_avc_createcon(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetServerContext(),
|
|
+ SECCLASS_DB_DATABASE);
|
|
+ }
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("cache lookup failed for Database %u", MyDatabaseId);
|
|
+ datcon = HeapTupleGetSecurity(tuple);
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return datcon;
|
|
+}
|
|
+
|
|
+char *sepgsqlGetDatabaseName()
|
|
+{
|
|
+ Form_pg_database dat_form;
|
|
+ HeapTuple tuple;
|
|
+ char *datname;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ return NULL;
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("cache lookup failed for Database %u", MyDatabaseId);
|
|
+ dat_form = (Form_pg_database) GETSTRUCT(tuple);
|
|
+ datname = pstrdup(NameStr(dat_form->datname));
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return datname;
|
|
+}
|
|
+
|
|
+void sepgsqlInitialize()
|
|
+{
|
|
+ sepgsql_avc_init();
|
|
+
|
|
+ if (IsBootstrapProcessingMode()) {
|
|
+ sepgsqlServerContext = sepgsql_system_getcon();
|
|
+ sepgsqlClientContext = sepgsql_system_getcon();
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetDatabaseContext(),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__ACCESS,
|
|
+ NULL);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* obtain security context of server process */
|
|
+ sepgsqlServerContext = sepgsql_system_getcon();
|
|
+
|
|
+ /* obtain security context of client process */
|
|
+ if (MyProcPort != NULL) {
|
|
+ sepgsqlClientContext = sepgsql_system_getpeercon(MyProcPort->sock);
|
|
+ } else {
|
|
+ sepgsqlClientContext = sepgsql_system_getcon();
|
|
+ }
|
|
+
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetDatabaseContext(),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__ACCESS,
|
|
+ sepgsqlGetDatabaseName());
|
|
+}
|
|
+
|
|
+/* sepgsqlMonitoringPolicyState() is worker process to monitor
|
|
+ * the status of SELinux policy. When it is changed, light after the worker
|
|
+ * thread receive a notification via netlink socket. The notification is
|
|
+ * delivered into any PostgreSQL instance by reseting shared avc.
|
|
+ */
|
|
+static void sepgsqlMonitoringPolicyState_SIGHUP(int signum)
|
|
+{
|
|
+ selnotice("selinux userspace AVC reset, by receiving SIGHUP");
|
|
+ sepgsql_avc_reset();
|
|
+}
|
|
+
|
|
+static int sepgsqlMonitoringPolicyState()
|
|
+{
|
|
+ char buffer[2048];
|
|
+ struct sockaddr_nl addr;
|
|
+ socklen_t addrlen;
|
|
+ struct nlmsghdr *nlh;
|
|
+ int i, rc, nl_sockfd;
|
|
+
|
|
+ seldebug("%s pid=%u", __FUNCTION__, getpid());
|
|
+
|
|
+ /* close listen port */
|
|
+ for (i=3; !close(i); i++);
|
|
+
|
|
+ /* map shared memory segment */
|
|
+ sepgsql_avc_init();
|
|
+
|
|
+ /* setup the signal handler */
|
|
+ pqinitmask();
|
|
+ pqsignal(SIGHUP, sepgsqlMonitoringPolicyState_SIGHUP);
|
|
+ pqsignal(SIGINT, SIG_DFL);
|
|
+ pqsignal(SIGQUIT, SIG_DFL);
|
|
+ pqsignal(SIGTERM, SIG_DFL);
|
|
+ pqsignal(SIGUSR1, SIG_DFL);
|
|
+ pqsignal(SIGUSR2, SIG_DFL);
|
|
+ pqsignal(SIGCHLD, SIG_DFL);
|
|
+ PG_SETMASK(&UnBlockSig);
|
|
+
|
|
+ /* open netlink socket */
|
|
+ nl_sockfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_SELINUX);
|
|
+ if (nl_sockfd < 0) {
|
|
+ selnotice("could not create netlink socket");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ memset(&addr, 0, sizeof(addr));
|
|
+ addr.nl_family = AF_NETLINK;
|
|
+ addr.nl_groups = SELNL_GRP_AVC;
|
|
+ if (bind(nl_sockfd, (struct sockaddr *)&addr, sizeof(addr))) {
|
|
+ selnotice("could not bind netlink socket");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /* waiting loop */
|
|
+ while (true) {
|
|
+ addrlen = sizeof(addr);
|
|
+ rc = recvfrom(nl_sockfd, buffer, sizeof(buffer), 0,
|
|
+ (struct sockaddr *)&addr, &addrlen);
|
|
+ if (rc < 0) {
|
|
+ if (errno == EINTR)
|
|
+ continue;
|
|
+ selnotice("selinux netlink: recvfrom() error=%d, %s",
|
|
+ errno, strerror(errno));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (addrlen != sizeof(addr)) {
|
|
+ selnotice("selinux netlink: netlink address truncated (len = %d)", addrlen);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (addr.nl_pid) {
|
|
+ selnotice("selinux netlink: received spoofed packet from: %u", addr.nl_pid);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (rc == 0) {
|
|
+ selnotice("selinux netlink: received EOF on socket");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ nlh = (struct nlmsghdr *)buffer;
|
|
+
|
|
+ if (nlh->nlmsg_flags & MSG_TRUNC
|
|
+ || nlh->nlmsg_len > (unsigned int)rc) {
|
|
+ selnotice("selinux netlink: incomplete netlink message");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ switch (nlh->nlmsg_type) {
|
|
+ case NLMSG_ERROR: {
|
|
+ struct nlmsgerr *err = NLMSG_DATA(nlh);
|
|
+ if (err->error == 0)
|
|
+ break;
|
|
+ selnotice("selinux netlink: error message %d", -err->error);
|
|
+ return 1;
|
|
+ }
|
|
+ case SELNL_MSG_SETENFORCE: {
|
|
+ struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh);
|
|
+ selnotice("selinux netlink: received setenforce notice (enforcing=%d)", msg->val);
|
|
+ sepgsql_avc_reset();
|
|
+ break;
|
|
+ }
|
|
+ case SELNL_MSG_POLICYLOAD: {
|
|
+ struct selnl_msg_policyload *msg = NLMSG_DATA(nlh);
|
|
+ selnotice("selinux netlink: received policyload notice (seqno=%d)", msg->seqno);
|
|
+ sepgsql_avc_reset();
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ selnotice("selinux netlink: unknown message type (%d)", nlh->nlmsg_type);
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static pid_t MonitoringPolicyStatePid = -1;
|
|
+
|
|
+int sepgsqlInitializePostmaster()
|
|
+{
|
|
+ MonitoringPolicyStatePid = fork();
|
|
+ if (MonitoringPolicyStatePid == 0) {
|
|
+ exit(sepgsqlMonitoringPolicyState());
|
|
+ } else if (MonitoringPolicyStatePid < 0) {
|
|
+ selnotice("could not create a child process to monitor the policy state");
|
|
+ return false;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+void sepgsqlFinalizePostmaster()
|
|
+{
|
|
+ int status;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+
|
|
+ if (MonitoringPolicyStatePid > 0) {
|
|
+ if (kill(MonitoringPolicyStatePid, SIGTERM) < 0) {
|
|
+ selnotice("could not kill(%u, SIGTERM), errno=%d (%s)",
|
|
+ MonitoringPolicyStatePid, errno, strerror(errno));
|
|
+ return;
|
|
+ }
|
|
+ waitpid(MonitoringPolicyStatePid, &status, 0);
|
|
+ }
|
|
+}
|
|
+
|
|
+bool sepgsqlIsEnabled()
|
|
+{
|
|
+ int enabled;
|
|
+
|
|
+ if (avc_shmem) {
|
|
+ LWLockAcquire(avc_shmem->lock, LW_SHARED);
|
|
+ enabled = avc_shmem->enabled;
|
|
+ LWLockRelease(avc_shmem->lock);
|
|
+ } else {
|
|
+ enabled = is_selinux_enabled();
|
|
+ }
|
|
+ return (enabled > 0 ? true : false);
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsqlHooks.c sepgsql/src/backend/security/sepgsqlHooks.c
|
|
--- base/src/backend/security/sepgsqlHooks.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/sepgsqlHooks.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -0,0 +1,676 @@
|
|
+/*
|
|
+ * src/backend/sepgsqlHooks.c
|
|
+ * SE-PostgreSQL hooks
|
|
+ *
|
|
+ * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/heapam.h"
|
|
+#include "access/genam.h"
|
|
+#include "access/skey.h"
|
|
+#include "miscadmin.h"
|
|
+#include "nodes/makefuncs.h"
|
|
+#include "security/pgace.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/syscache.h"
|
|
+#include <fcntl.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+
|
|
+static HeapTuple __getHeapTupleFromItemPointer(Relation rel, ItemPointer tid)
|
|
+{
|
|
+ /* obtain an old tuple */
|
|
+ Buffer buffer;
|
|
+ PageHeader dp;
|
|
+ ItemId lp;
|
|
+ HeapTupleData tuple;
|
|
+ HeapTuple oldtup;
|
|
+
|
|
+ buffer = ReadBuffer(rel, ItemPointerGetBlockNumber(tid));
|
|
+
|
|
+ dp = (PageHeader) BufferGetPage(buffer);
|
|
+ lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
|
|
+
|
|
+ Assert(ItemIdIsUsed(lp));
|
|
+
|
|
+ tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
|
|
+ tuple.t_len = ItemIdGetLength(lp);
|
|
+ tuple.t_self = *tid;
|
|
+ tuple.t_tableOid = RelationGetRelid(rel);
|
|
+
|
|
+ oldtup = heap_copytuple(&tuple);
|
|
+ ReleaseBuffer(buffer);
|
|
+
|
|
+ return oldtup;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Extended SQL statement hooks
|
|
+ *******************************************************************************/
|
|
+/* make context = 'xxx' node */
|
|
+DefElem *sepgsqlGramSecurityLabel(char *defname, char *context) {
|
|
+ DefElem *n = NULL;
|
|
+ if (!strcmp(defname, "context"))
|
|
+ n = makeDefElem(pstrdup(defname), (Node *) makeString(context));
|
|
+ return n;
|
|
+}
|
|
+
|
|
+/* whether DefElem holds security context, or not */
|
|
+bool sepgsqlNodeIsSecurityLabel(DefElem *defel) {
|
|
+ Assert(IsA(defel, DefElem));
|
|
+ if (defel->defname && !strcmp(defel->defname, "context"))
|
|
+ return true;
|
|
+ return false;
|
|
+}
|
|
+
|
|
+/* parse explicitly specified security context */
|
|
+Oid sepgsqlParseSecurityLabel(DefElem *defel) {
|
|
+ Datum newcon;
|
|
+ Assert(IsA(defel, DefElem));
|
|
+
|
|
+ newcon = DirectFunctionCall1(security_label_in,
|
|
+ CStringGetDatum(strVal(defel->arg)));
|
|
+ return DatumGetObjectId(newcon);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * DATABASE object related hooks
|
|
+ *******************************************************************************/
|
|
+
|
|
+void sepgsqlGetDatabaseParam(const char *name)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("cache lookup failed for database %u", MyDatabaseId);
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__GET_PARAM,
|
|
+ sepgsqlGetTupleName(DatabaseRelationId, tuple));
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+void sepgsqlSetDatabaseParam(const char *name, char *argstring)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ tuple = SearchSysCache(DATABASEOID,
|
|
+ ObjectIdGetDatum(MyDatabaseId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("cache lookup failed for database %u", MyDatabaseId);
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__SET_PARAM,
|
|
+ sepgsqlGetTupleName(DatabaseRelationId, tuple));
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * RELATION(Table)/ATTRIBTUE(column) object related hooks
|
|
+ *******************************************************************************/
|
|
+void sepgsqlLockTable(Oid relid)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ Form_pg_class classForm;
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("cache lookup failed for relation %u", relid);
|
|
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+
|
|
+ if (classForm->relkind == RELKIND_RELATION)
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_DB_TABLE,
|
|
+ DB_TABLE__LOCK,
|
|
+ sepgsqlGetTupleName(RelationRelationId, tuple));
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * PROCEDURE related hooks
|
|
+ *******************************************************************************/
|
|
+
|
|
+static Datum __callTrustedProcedure(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid orig_client_con;
|
|
+ Datum retval;
|
|
+
|
|
+ /* save original security context */
|
|
+ orig_client_con = sepgsqlGetClientContext();
|
|
+ /* set exec context */
|
|
+ sepgsqlSetClientContext(DatumGetObjectId(fcinfo->flinfo->fn_pgace_data));
|
|
+ PG_TRY();
|
|
+ {
|
|
+ retval = fcinfo->flinfo->fn_pgace_addr(fcinfo);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ sepgsqlSetClientContext(orig_client_con);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ sepgsqlSetClientContext(orig_client_con);
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+void sepgsqlCallFunction(FmgrInfo *finfo, bool with_perm_check)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ Oid execcon;
|
|
+ uint32 perms = DB_PROCEDURE__EXECUTE;
|
|
+
|
|
+ tuple = SearchSysCache(PROCOID,
|
|
+ ObjectIdGetDatum(finfo->fn_oid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("cache lookup failed for procedure %u", finfo->fn_oid);
|
|
+
|
|
+ /* check trusted procedure */
|
|
+ execcon = sepgsql_avc_createcon(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_PROCESS);
|
|
+ if (sepgsqlGetClientContext() != execcon) {
|
|
+ finfo->fn_pgace_addr = finfo->fn_addr;
|
|
+ finfo->fn_pgace_data = ObjectIdGetDatum(execcon);
|
|
+ finfo->fn_addr = __callTrustedProcedure;
|
|
+
|
|
+ perms |= DB_PROCEDURE__ENTRYPOINT;
|
|
+ }
|
|
+
|
|
+ if (with_perm_check) {
|
|
+ /* check procedure:{execute entrypoint} permission */
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_DB_PROCEDURE,
|
|
+ perms,
|
|
+ sepgsqlGetTupleName(ProcedureRelationId, tuple));
|
|
+ }
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+bool sepgsqlCallFunctionTrigger(FmgrInfo *finfo, TriggerData *tgdata)
|
|
+{
|
|
+ Relation rel = tgdata->tg_relation;
|
|
+ HeapTuple newtup = NULL;
|
|
+ HeapTuple oldtup = NULL;
|
|
+
|
|
+ if (TRIGGER_FIRED_FOR_STATEMENT(tgdata->tg_event))
|
|
+ return true; /* statement trigger does not contain any tuple */
|
|
+ if (TRIGGER_FIRED_BY_INSERT(tgdata->tg_event)) {
|
|
+ if (TRIGGER_FIRED_AFTER(tgdata->tg_event))
|
|
+ newtup = tgdata->tg_trigtuple;
|
|
+ } else if (TRIGGER_FIRED_BY_UPDATE(tgdata->tg_event)) {
|
|
+ oldtup = tgdata->tg_trigtuple;
|
|
+ if (TRIGGER_FIRED_AFTER(tgdata->tg_event)
|
|
+ && HeapTupleGetSecurity(oldtup) != HeapTupleGetSecurity(tgdata->tg_newtuple))
|
|
+ newtup = tgdata->tg_newtuple;
|
|
+ } else if (TRIGGER_FIRED_BY_DELETE(tgdata->tg_event)) {
|
|
+ if (TRIGGER_FIRED_AFTER(tgdata->tg_event))
|
|
+ oldtup = tgdata->tg_trigtuple;
|
|
+ } else {
|
|
+ selerror("unknown trigger event type (%u)", tgdata->tg_event);
|
|
+ }
|
|
+ if (oldtup && !sepgsqlCheckTuplePerms(rel, oldtup, NULL, DB_TUPLE__SELECT, false))
|
|
+ return false;
|
|
+ if (newtup && !sepgsqlCheckTuplePerms(rel, newtup, NULL, DB_TUPLE__SELECT, false))
|
|
+ return false;
|
|
+
|
|
+ sepgsqlCallFunction(finfo, false);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * LOAD shared library module hook
|
|
+ *******************************************************************************/
|
|
+void sepgsqlLoadSharedModule(const char *filename)
|
|
+{
|
|
+ security_context_t filecon;
|
|
+ Datum filecon_sid;
|
|
+
|
|
+ if (getfilecon_raw(filename, &filecon) < 1)
|
|
+ selerror("could not obtain security context of %s", filename);
|
|
+ PG_TRY();
|
|
+ {
|
|
+ filecon_sid = DirectFunctionCall1(security_label_raw_in,
|
|
+ CStringGetDatum(filecon));
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(filecon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(filecon);
|
|
+
|
|
+ sepgsql_avc_permission(sepgsqlGetDatabaseContext(),
|
|
+ DatumGetObjectId(filecon_sid),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__LOAD_MODULE,
|
|
+ (char *) filename);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Binary Large Object hooks
|
|
+ *******************************************************************************/
|
|
+Oid sepgsqlLargeObjectGetSecurity(HeapTuple tuple) {
|
|
+ Oid lo_security = HeapTupleGetSecurity(tuple);
|
|
+
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ lo_security,
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__GETATTR,
|
|
+ sepgsqlGetTupleName(LargeObjectRelationId, tuple));
|
|
+ return lo_security;
|
|
+}
|
|
+
|
|
+void sepgsqlLargeObjectSetSecurity(HeapTuple tuple, Oid lo_security, bool is_first)
|
|
+{
|
|
+ if (is_first) {
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__SETATTR | DB_BLOB__RELABELFROM,
|
|
+ sepgsqlGetTupleName(LargeObjectRelationId, tuple));
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ lo_security,
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__RELABELTO,
|
|
+ sepgsqlGetTupleName(LargeObjectRelationId, tuple));
|
|
+ }
|
|
+ HeapTupleSetSecurity(tuple, lo_security);
|
|
+}
|
|
+
|
|
+void sepgsqlLargeObjectCreate(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ Oid newcon = sepgsqlComputeImplicitContext(rel, tuple);
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ newcon,
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__CREATE,
|
|
+ sepgsqlGetTupleName(LargeObjectRelationId, tuple));
|
|
+ HeapTupleSetSecurity(tuple, newcon);
|
|
+}
|
|
+
|
|
+void sepgsqlLargeObjectDrop(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__DROP,
|
|
+ sepgsqlGetTupleName(LargeObjectRelationId, tuple));
|
|
+}
|
|
+
|
|
+void sepgsqlLargeObjectOpen(Relation rel, HeapTuple tuple, bool read_only)
|
|
+{
|
|
+ sepgsqlCheckTuplePerms(rel, tuple, NULL, DB_TUPLE__SELECT, true);
|
|
+}
|
|
+
|
|
+void sepgsqlLargeObjectRead(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ sepgsqlCheckTuplePerms(rel, tuple, NULL, DB_TUPLE__SELECT | DB_BLOB__READ, true);
|
|
+}
|
|
+
|
|
+void sepgsqlLargeObjectWrite(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|
+{
|
|
+ Oid lo_security;
|
|
+
|
|
+ if (HeapTupleIsValid(oldtup)) {
|
|
+ lo_security = HeapTupleGetSecurity(oldtup);
|
|
+ } else {
|
|
+ Form_pg_largeobject lobj_form
|
|
+ = (Form_pg_largeobject) GETSTRUCT(newtup);
|
|
+ ScanKeyData skey;
|
|
+ SysScanDesc sd;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(lobj_form->loid));
|
|
+ sd = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
|
|
+ SnapshotNow, 1, &skey);
|
|
+ tuple = systable_getnext(sd);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("large object %u does not exist", lobj_form->loid);
|
|
+ lo_security = HeapTupleGetSecurity(tuple);
|
|
+ systable_endscan(sd);
|
|
+ }
|
|
+ HeapTupleSetSecurity(newtup, lo_security);
|
|
+ sepgsqlCheckTuplePerms(rel, newtup, NULL, DB_TUPLE__UPDATE | DB_BLOB__WRITE, true);
|
|
+}
|
|
+
|
|
+void sepgsqlLargeObjectImport()
|
|
+{
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetServerContext(),
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__IMPORT,
|
|
+ NULL);
|
|
+}
|
|
+
|
|
+void sepgsqlLargeObjectExport()
|
|
+{
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetServerContext(),
|
|
+ SECCLASS_DB_BLOB,
|
|
+ DB_BLOB__EXPORT,
|
|
+ NULL);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * security_label hooks
|
|
+ *******************************************************************************/
|
|
+char *sepgsqlSecurityLabelIn(char *context) {
|
|
+ security_context_t raw_context, canonical_context;
|
|
+ char *result;
|
|
+ int rc;
|
|
+
|
|
+ rc = selinux_trans_to_raw_context(context, &raw_context);
|
|
+ if (rc)
|
|
+ selerror("could not translate MLS label");
|
|
+
|
|
+ rc = security_canonicalize_context_raw(raw_context, &canonical_context);
|
|
+ freecon(raw_context);
|
|
+ if (rc)
|
|
+ selerror("could not canonicalize the context");
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(canonical_context);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(canonical_context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(canonical_context);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+char *sepgsqlSecurityLabelOut(char *raw_context) {
|
|
+ security_context_t context;
|
|
+ char *result;
|
|
+
|
|
+ if (selinux_raw_to_trans_context(raw_context, &context))
|
|
+ selerror("could not translate MLS label");
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(context);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(context);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(context);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+bool sepgsqlSecurityLabelIsValid(char *context) {
|
|
+ if (!security_check_context_raw(context))
|
|
+ return true;
|
|
+ return false;
|
|
+}
|
|
+
|
|
+char *sepgsqlSecurityLabelOfLabel(char *context) {
|
|
+ HeapTuple tuple;
|
|
+ security_context_t scon, tcon, ncon, _ncon;
|
|
+ int rc;
|
|
+
|
|
+ /* obtain the security context of pg_security */
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(SecurityRelationId),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("pg_security (relid=%u) not found", SecurityRelationId);
|
|
+ tcon = DatumGetCString(DirectFunctionCall1(security_label_raw_out,
|
|
+ ObjectIdGetDatum(HeapTupleGetSecurity(tuple))));
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ /* obtain server's context */
|
|
+ rc = getcon_raw(&scon);
|
|
+ if (rc)
|
|
+ selerror("could not obtain server's context");
|
|
+
|
|
+ /* compute pg_selinux tuple context */
|
|
+ rc = security_compute_create_raw(scon, tcon, SECCLASS_DB_TUPLE, &ncon);
|
|
+ pfree(tcon);
|
|
+ freecon(scon);
|
|
+ if (rc)
|
|
+ selerror("could not compute a newly created security context");
|
|
+
|
|
+ /* copy tuple's context */
|
|
+ PG_TRY();
|
|
+ {
|
|
+ _ncon = pstrdup(ncon);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(ncon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+
|
|
+ freecon(ncon);
|
|
+
|
|
+ return _ncon;
|
|
+}
|
|
+
|
|
+extern char *selinux_mnt;
|
|
+
|
|
+char *sepgsqlSecurityLabelNotFound(Oid sid) {
|
|
+ security_context_t unlabeled_con;
|
|
+
|
|
+#ifndef SEPGSQLOPT_LIBSELINUX_1_33
|
|
+ if (!security_get_initial_context_raw("unlabeled", &unlabeled_con)) {
|
|
+ char *result;
|
|
+
|
|
+ PG_TRY();
|
|
+ {
|
|
+ result = pstrdup(unlabeled_con);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(unlabeled_con);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(unlabeled_con);
|
|
+ return result;
|
|
+ }
|
|
+#endif
|
|
+ /* FIXME: This fallback code should be eliminated in the near future.
|
|
+ * /selinux/init_contexts support will be enabled at 2.6.22 kernel.
|
|
+ */
|
|
+ unlabeled_con = "system_u:object_r:unlabeled_t:s0";
|
|
+ if (sepgsqlSecurityLabelIsValid(unlabeled_con))
|
|
+ return pstrdup(unlabeled_con);
|
|
+ unlabeled_con = "system_u:object_r:unlabeled_t";
|
|
+ if (sepgsqlSecurityLabelIsValid(unlabeled_con))
|
|
+ return pstrdup(unlabeled_con);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * simple_heap_xxxx hooks
|
|
+ *******************************************************************************/
|
|
+static inline bool __is_simple_system_relation(Relation rel)
|
|
+{
|
|
+ bool retval = false;
|
|
+ switch (RelationGetRelid(rel)) {
|
|
+ case AggregateRelationId:
|
|
+ case AttributeRelationId:
|
|
+ case AuthIdRelationId:
|
|
+ case CastRelationId:
|
|
+ case ConversionRelationId:
|
|
+ case DatabaseRelationId:
|
|
+ case LanguageRelationId:
|
|
+ case NamespaceRelationId:
|
|
+ case OperatorRelationId:
|
|
+ case OperatorClassRelationId:
|
|
+ case ProcedureRelationId:
|
|
+ case RelationRelationId:
|
|
+ case RewriteRelationId:
|
|
+ case TableSpaceRelationId:
|
|
+ case TriggerRelationId:
|
|
+ case TypeRelationId:
|
|
+ retval = true;
|
|
+ break;
|
|
+ }
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+void sepgsqlSimpleHeapInsert(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ Oid newcon;
|
|
+
|
|
+ if (!__is_simple_system_relation(rel))
|
|
+ return;
|
|
+
|
|
+ newcon = HeapTupleGetSecurity(tuple);
|
|
+ if (newcon == InvalidOid) {
|
|
+ /* no explicit labeling */
|
|
+ newcon = sepgsqlComputeImplicitContext(rel, tuple);
|
|
+ HeapTupleSetSecurity(tuple, newcon);
|
|
+ }
|
|
+ sepgsqlCheckTuplePerms(rel, tuple, NULL, DB_TUPLE__INSERT, true);
|
|
+}
|
|
+
|
|
+void sepgsqlSimpleHeapUpdate(Relation rel, ItemPointer tid, HeapTuple newtup)
|
|
+{
|
|
+ HeapTuple oldtup;
|
|
+ Oid ncon, ocon;
|
|
+ uint32 perms = DB_TUPLE__UPDATE;
|
|
+
|
|
+ if (!__is_simple_system_relation(rel))
|
|
+ return;
|
|
+
|
|
+ oldtup = __getHeapTupleFromItemPointer(rel, tid);
|
|
+ ncon = HeapTupleGetSecurity(newtup);
|
|
+ ocon = HeapTupleGetSecurity(oldtup);
|
|
+ if (ncon == InvalidOid) {
|
|
+ HeapTupleSetSecurity(newtup, ocon);
|
|
+ ncon = ocon;
|
|
+ }
|
|
+ if (ncon != ocon)
|
|
+ perms |= DB_TUPLE__RELABELFROM;
|
|
+ sepgsqlCheckTuplePerms(rel, oldtup, NULL, perms, true);
|
|
+
|
|
+ perms = (ncon != ocon ? DB_TUPLE__RELABELTO : 0);
|
|
+ sepgsqlCheckTuplePerms(rel, newtup, oldtup, perms, true);
|
|
+
|
|
+ heap_freetuple(oldtup);
|
|
+}
|
|
+
|
|
+void sepgsqlSimpleHeapDelete(Relation rel, ItemPointer tid)
|
|
+{
|
|
+ HeapTuple oldtup;
|
|
+
|
|
+ if (!__is_simple_system_relation(rel))
|
|
+ return;
|
|
+
|
|
+ oldtup = __getHeapTupleFromItemPointer(rel, tid);
|
|
+ sepgsqlCheckTuplePerms(rel, oldtup, NULL, DB_TUPLE__DELETE, true);
|
|
+ heap_freetuple(oldtup);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * ExecInsert/Delete/Update hooks
|
|
+ *******************************************************************************/
|
|
+
|
|
+bool sepgsqlExecInsert(Relation rel, HeapTuple tuple, bool with_returning)
|
|
+{
|
|
+ Oid newcon;
|
|
+ uint32 perms;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true; /* always true, if disabled */
|
|
+
|
|
+ newcon = HeapTupleGetSecurity(tuple);
|
|
+ if (newcon == InvalidOid) {
|
|
+ /* no explicit labeling */
|
|
+ newcon = sepgsqlComputeImplicitContext(rel, tuple);
|
|
+ HeapTupleSetSecurity(tuple, newcon);
|
|
+ }
|
|
+ perms = DB_TUPLE__INSERT;
|
|
+ if (with_returning)
|
|
+ perms |= DB_TUPLE__SELECT;
|
|
+
|
|
+ return sepgsqlCheckTuplePerms(rel, tuple, NULL, perms, false);
|
|
+}
|
|
+
|
|
+bool sepgsqlExecUpdate(Relation rel, HeapTuple newtup, ItemPointer tid, bool with_returning)
|
|
+{
|
|
+ HeapTuple oldtup;
|
|
+ Oid newcon, oldcon;
|
|
+ uint32 perms = 0;
|
|
+ bool rc;
|
|
+
|
|
+ oldtup = __getHeapTupleFromItemPointer(rel, tid);
|
|
+ newcon = HeapTupleGetSecurity(newtup);
|
|
+ oldcon = HeapTupleGetSecurity(oldtup);
|
|
+ if (newcon == InvalidOid) {
|
|
+ HeapTupleSetSecurity(newtup, oldcon); /* keep old context */
|
|
+ oldcon = newcon;
|
|
+ }
|
|
+ if (newcon != oldcon) {
|
|
+ perms |= DB_TUPLE__RELABELTO;
|
|
+ if (with_returning)
|
|
+ perms |= DB_TUPLE__SELECT;
|
|
+ }
|
|
+ rc = sepgsqlCheckTuplePerms(rel, newtup, oldtup, perms, false);
|
|
+
|
|
+ heap_freetuple(oldtup);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+bool sepgsqlExecDelete(Relation rel, ItemPointer tid, bool with_returning)
|
|
+{
|
|
+ HeapTuple oldtup;
|
|
+ bool rc;
|
|
+
|
|
+ oldtup = __getHeapTupleFromItemPointer(rel, tid);
|
|
+
|
|
+ rc = sepgsqlCheckTuplePerms(rel, oldtup, NULL, 0, false);
|
|
+
|
|
+ heap_freetuple(oldtup);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * heap_insert/heap_update hooks -- the last gate of implicit labeling
|
|
+ *******************************************************************************/
|
|
+void sepgsqlHeapInsert(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ if (HeapTupleGetSecurity(tuple) == InvalidOid) {
|
|
+ Oid newcon = sepgsqlComputeImplicitContext(rel, tuple);
|
|
+ HeapTupleSetSecurity(tuple, newcon);
|
|
+ }
|
|
+}
|
|
+
|
|
+void sepgsqlHeapUpdate(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|
+{
|
|
+ if (HeapTupleGetSecurity(newtup) == InvalidOid) {
|
|
+ Oid oldcon = HeapTupleGetSecurity(oldtup);
|
|
+ HeapTupleSetSecurity(newtup, oldcon);
|
|
+ }
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsqlPerms.c sepgsql/src/backend/security/sepgsqlPerms.c
|
|
--- base/src/backend/security/sepgsqlPerms.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/sepgsqlPerms.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -0,0 +1,489 @@
|
|
+/*
|
|
+ * src/backend/security/sepgsqlPerms.c
|
|
+ * SE-PostgreSQL permission checking functions
|
|
+ *
|
|
+ * Copyright (c) 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/genam.h"
|
|
+#include "access/heapam.h"
|
|
+#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
+#include "utils/builtins.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/syscache.h"
|
|
+#include "utils/typcache.h"
|
|
+
|
|
+/*
|
|
+ * If we have to refere a object which is newly inserted or updated
|
|
+ * in the same command, SearchSysCache() returns NULL because it use
|
|
+ * SnapshowNow internally. The followings are fallback routine to
|
|
+ * avoid a failed cache lookup.
|
|
+ */
|
|
+static Oid __lookupRelationForm(Oid relid, Form_pg_class classForm) {
|
|
+ Relation rel;
|
|
+ SysScanDesc scan;
|
|
+ ScanKeyData skey;
|
|
+ HeapTuple tuple;
|
|
+ Oid t_security;
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (HeapTupleIsValid(tuple)) {
|
|
+ if (classForm)
|
|
+ memcpy(classForm, GETSTRUCT(tuple), sizeof(FormData_pg_class));
|
|
+ t_security = HeapTupleGetSecurity(tuple);
|
|
+ ReleaseSysCache(tuple);
|
|
+ return t_security;
|
|
+ }
|
|
+
|
|
+ rel = heap_open(RelationRelationId, AccessShareLock);
|
|
+ ScanKeyInit(&skey,
|
|
+ ObjectIdAttributeNumber,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(relid));
|
|
+ scan = systable_beginscan(rel, ClassOidIndexId,
|
|
+ true, SnapshotSelf, 1, &skey);
|
|
+ tuple = systable_getnext(scan);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("relation %u is not exist", relid);
|
|
+
|
|
+ if (classForm)
|
|
+ memcpy(classForm, GETSTRUCT(tuple), sizeof(FormData_pg_class));
|
|
+ t_security = HeapTupleGetSecurity(tuple);
|
|
+
|
|
+ systable_endscan(scan);
|
|
+ heap_close(rel, AccessShareLock);
|
|
+
|
|
+ return t_security;
|
|
+}
|
|
+
|
|
+static uint32 __tuple_perms_to_common_perms(uint32 perms) {
|
|
+ uint32 __perms = 0;
|
|
+ __perms |= (perms & DB_TUPLE__RELABELFROM ? COMMON_DATABASE__RELABELFROM : 0);
|
|
+ __perms |= (perms & DB_TUPLE__RELABELTO ? COMMON_DATABASE__RELABELTO : 0);
|
|
+ __perms |= (perms & DB_TUPLE__SELECT ? COMMON_DATABASE__GETATTR : 0);
|
|
+ __perms |= (perms & DB_TUPLE__UPDATE ? COMMON_DATABASE__SETATTR : 0);
|
|
+ __perms |= (perms & DB_TUPLE__INSERT ? COMMON_DATABASE__CREATE : 0);
|
|
+ __perms |= (perms & DB_TUPLE__DELETE ? COMMON_DATABASE__DROP : 0);
|
|
+ return __perms;
|
|
+}
|
|
+
|
|
+char *sepgsqlGetTupleName(Oid relid, HeapTuple tuple)
|
|
+{
|
|
+ char buffer[NAMEDATALEN * 2 + 32];
|
|
+
|
|
+ switch (relid) {
|
|
+ case AccessMethodRelationId:
|
|
+ return NameStr(((Form_pg_am) GETSTRUCT(tuple))->amname);
|
|
+
|
|
+ case AttributeRelationId: {
|
|
+ Form_pg_attribute attrForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ Form_pg_class classForm;
|
|
+ HeapTuple reltup;
|
|
+
|
|
+ if (IsBootstrapProcessingMode())
|
|
+ return NameStr(attrForm->attname);
|
|
+
|
|
+ reltup = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(attrForm->attrelid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(reltup))
|
|
+ return NameStr(attrForm->attname);
|
|
+
|
|
+ classForm = (Form_pg_class) GETSTRUCT(reltup);
|
|
+ snprintf(buffer, sizeof(buffer), "%s.%s",
|
|
+ NameStr(classForm->relname),
|
|
+ NameStr(attrForm->attname));
|
|
+ ReleaseSysCache(reltup);
|
|
+ return pstrdup(buffer);
|
|
+ }
|
|
+ case AuthIdRelationId:
|
|
+ return NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
|
|
+
|
|
+ case RelationRelationId:
|
|
+ return NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname);
|
|
+
|
|
+ case ConstraintRelationId:
|
|
+ return NameStr(((Form_pg_constraint) GETSTRUCT(tuple))->conname);
|
|
+
|
|
+ case ConversionRelationId:
|
|
+ return NameStr(((Form_pg_conversion) GETSTRUCT(tuple))->conname);
|
|
+
|
|
+ case DatabaseRelationId:
|
|
+ return NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname);
|
|
+
|
|
+ case LanguageRelationId:
|
|
+ return NameStr(((Form_pg_language) GETSTRUCT(tuple))->lanname);
|
|
+
|
|
+ case LargeObjectRelationId:
|
|
+ snprintf(buffer, sizeof(buffer), "loid:%u",
|
|
+ ((Form_pg_largeobject) GETSTRUCT(tuple))->loid);
|
|
+ return pstrdup(buffer);
|
|
+
|
|
+ case ListenerRelationId:
|
|
+ return NameStr(((Form_pg_listener) GETSTRUCT(tuple))->relname);
|
|
+
|
|
+ case NamespaceRelationId:
|
|
+ return NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname);
|
|
+
|
|
+ case OperatorClassRelationId:
|
|
+ return NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname);
|
|
+
|
|
+ case OperatorRelationId:
|
|
+ return NameStr(((Form_pg_operator) GETSTRUCT(tuple))->oprname);
|
|
+
|
|
+ case PLTemplateRelationId:
|
|
+ return NameStr(((Form_pg_pltemplate) GETSTRUCT(tuple))->tmplname);
|
|
+
|
|
+ case ProcedureRelationId:
|
|
+ return NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname);
|
|
+
|
|
+ case RewriteRelationId:
|
|
+ return NameStr(((Form_pg_rewrite) GETSTRUCT(tuple))->rulename);
|
|
+
|
|
+ case TableSpaceRelationId:
|
|
+ return NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname);
|
|
+
|
|
+ case TriggerRelationId:
|
|
+ return NameStr(((Form_pg_trigger) GETSTRUCT(tuple))->tgname);
|
|
+
|
|
+ case TypeRelationId:
|
|
+ snprintf(buffer, sizeof(buffer), "pg_type.%s",
|
|
+ NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname));
|
|
+ return pstrdup(buffer);
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void __check_pg_attribute(HeapTuple tuple, HeapTuple oldtup,
|
|
+ uint32 *p_perms, uint16 *p_tclass)
|
|
+{
|
|
+ Form_pg_attribute attrForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ FormData_pg_class classForm;
|
|
+
|
|
+ switch (attrForm->attrelid) {
|
|
+ case TypeRelationId:
|
|
+ case ProcedureRelationId:
|
|
+ case AttributeRelationId:
|
|
+ case RelationRelationId:
|
|
+ /* those are pure relation */
|
|
+ break;
|
|
+ default:
|
|
+ __lookupRelationForm(attrForm->attrelid, &classForm);
|
|
+ if (classForm.relkind != RELKIND_RELATION) {
|
|
+ *p_tclass = SECCLASS_DB_TUPLE;
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ *p_tclass = SECCLASS_DB_COLUMN;
|
|
+ *p_perms = __tuple_perms_to_common_perms(*p_perms);
|
|
+ if (HeapTupleIsValid(oldtup)) {
|
|
+ Form_pg_attribute oldForm = (Form_pg_attribute) GETSTRUCT(oldtup);
|
|
+
|
|
+ if (oldForm->attisdropped != true && attrForm->attisdropped == true)
|
|
+ *p_perms |= DB_COLUMN__DROP;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void __check_pg_largeobject(HeapTuple tuple, HeapTuple oldtup,
|
|
+ uint32 *p_perms, uint16 *p_tclass)
|
|
+{
|
|
+ Form_pg_largeobject blobForm
|
|
+ = (Form_pg_largeobject) GETSTRUCT(tuple);
|
|
+ Relation rel;
|
|
+ ScanKeyData skey;
|
|
+ SysScanDesc sd;
|
|
+ uint32 perms = 0;
|
|
+
|
|
+ perms |= (*p_perms & DB_TUPLE__SELECT ? DB_BLOB__GETATTR : 0);
|
|
+ perms |= (*p_perms & DB_TUPLE__UPDATE ? DB_BLOB__SETATTR : 0);
|
|
+ perms |= (*p_perms & DB_BLOB__READ ? DB_BLOB__READ : 0);
|
|
+ perms |= (*p_perms & DB_BLOB__WRITE ? DB_BLOB__WRITE : 0);
|
|
+
|
|
+ if (*p_perms & DB_TUPLE__INSERT) {
|
|
+ bool found = false;
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(blobForm->loid));
|
|
+ rel = heap_open(LargeObjectRelationId, AccessShareLock);
|
|
+ sd = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
|
|
+ SnapshotSelf, 1, &skey);
|
|
+ if (HeapTupleIsValid(systable_getnext(sd)))
|
|
+ found = true;
|
|
+ systable_endscan(sd);
|
|
+ heap_close(rel, AccessShareLock);
|
|
+ perms |= (!found ? DB_BLOB__CREATE : DB_BLOB__SETATTR);
|
|
+ }
|
|
+
|
|
+ if (*p_perms & DB_TUPLE__DELETE) {
|
|
+ HeapTuple exttup;
|
|
+ bool found = false;
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_largeobject_loid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(blobForm->loid));
|
|
+ rel = heap_open(LargeObjectRelationId, AccessShareLock);
|
|
+ sd = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
|
|
+ SnapshotSelf, 1, &skey);
|
|
+ while ((exttup = systable_getnext(sd))) {
|
|
+ int __pageno = ((Form_pg_largeobject) GETSTRUCT(exttup))->pageno;
|
|
+
|
|
+ if (blobForm->pageno != __pageno) {
|
|
+ found = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ systable_endscan(sd);
|
|
+ heap_close(rel, AccessShareLock);
|
|
+ perms |= (!found ? DB_BLOB__DROP : DB_BLOB__SETATTR);
|
|
+ }
|
|
+ *p_tclass = SECCLASS_DB_BLOB;
|
|
+ *p_perms = perms;
|
|
+}
|
|
+
|
|
+static void __check_pg_proc(HeapTuple tuple, HeapTuple oldtup,
|
|
+ uint32 *p_perms, uint16 *p_tclass)
|
|
+{
|
|
+ uint32 perms = __tuple_perms_to_common_perms(*p_perms);
|
|
+ Form_pg_proc procForm = (Form_pg_proc) GETSTRUCT(tuple);
|
|
+
|
|
+ if (procForm->prolang == ClanguageId) {
|
|
+ Datum oldbin, newbin;
|
|
+ bool isnull, verify = false;
|
|
+
|
|
+ newbin = SysCacheGetAttr(PROCOID, tuple,
|
|
+ Anum_pg_proc_probin, &isnull);
|
|
+ if (!isnull) {
|
|
+ if (perms & DB_PROCEDURE__CREATE) {
|
|
+ verify = true;
|
|
+ } else if (HeapTupleIsValid(oldtup)) {
|
|
+ oldbin = SysCacheGetAttr(PROCOID, oldtup,
|
|
+ Anum_pg_proc_probin, &isnull);
|
|
+ if (isnull || DatumGetBool(DirectFunctionCall2(textne, oldbin, newbin)))
|
|
+ verify = true;
|
|
+ }
|
|
+
|
|
+ if (verify) {
|
|
+ char *filename;
|
|
+ security_context_t filecon;
|
|
+ Datum filesid;
|
|
+
|
|
+ /* <client type> <-- database:module_install --> <database type> */
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetDatabaseContext(),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__INSTALL_MODULE,
|
|
+ NULL);
|
|
+
|
|
+ /* <client type> <-- database:module_install --> <file type> */
|
|
+ filename = DatumGetCString(DirectFunctionCall1(textout, newbin));
|
|
+ filename = expand_dynamic_library_name(filename);
|
|
+ if (getfilecon_raw(filename, &filecon) < 1)
|
|
+ selerror("could not obtain the security context of '%s'", filename);
|
|
+ PG_TRY();
|
|
+ {
|
|
+ filesid = DirectFunctionCall1(security_label_raw_in,
|
|
+ CStringGetDatum(filecon));
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ freecon(filecon);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ freecon(filecon);
|
|
+
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ DatumGetObjectId(filesid),
|
|
+ SECCLASS_DB_DATABASE,
|
|
+ DB_DATABASE__INSTALL_MODULE,
|
|
+ filename);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ *p_perms = perms;
|
|
+ *p_tclass = SECCLASS_DB_PROCEDURE;
|
|
+}
|
|
+
|
|
+static void __check_pg_relation(HeapTuple tuple, HeapTuple oldtup,
|
|
+ uint32 *p_perms, uint16 *p_tclass)
|
|
+{
|
|
+ Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+ if (classForm->relkind == RELKIND_RELATION) {
|
|
+ *p_tclass = SECCLASS_DB_TABLE;
|
|
+ *p_perms = __tuple_perms_to_common_perms(*p_perms);
|
|
+ } else {
|
|
+ *p_tclass = SECCLASS_DB_TUPLE;
|
|
+ }
|
|
+}
|
|
+
|
|
+static bool __check_tuple_perms(Oid tableoid, Oid tcontext, uint32 perms,
|
|
+ HeapTuple tuple, HeapTuple oldtup, bool abort)
|
|
+{
|
|
+ uint16 tclass;
|
|
+ bool rc = true;
|
|
+
|
|
+ Assert(tuple != NULL);
|
|
+
|
|
+ switch (tableoid) {
|
|
+ case DatabaseRelationId: /* pg_database */
|
|
+ perms = __tuple_perms_to_common_perms(perms);
|
|
+ tclass = SECCLASS_DB_DATABASE;
|
|
+ break;
|
|
+
|
|
+ case RelationRelationId: /* pg_class */
|
|
+ __check_pg_relation(tuple, oldtup, &perms, &tclass);
|
|
+ break;
|
|
+
|
|
+ case AttributeRelationId: /* pg_attribute */
|
|
+ __check_pg_attribute(tuple, oldtup, &perms, &tclass);
|
|
+ break;
|
|
+
|
|
+ case ProcedureRelationId: /* pg_proc */
|
|
+ __check_pg_proc(tuple, oldtup, &perms, &tclass);
|
|
+ break;
|
|
+
|
|
+ case LargeObjectRelationId: /* pg_largeobject */
|
|
+ __check_pg_largeobject(tuple, oldtup, &perms, &tclass);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ tclass = SECCLASS_DB_TUPLE;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (perms) {
|
|
+ char *audit;
|
|
+ rc = sepgsql_avc_permission_noaudit(sepgsqlGetClientContext(),
|
|
+ tcontext,
|
|
+ tclass,
|
|
+ perms,
|
|
+ &audit,
|
|
+ sepgsqlGetTupleName(tableoid, tuple));
|
|
+ sepgsql_audit(abort ? rc : true, audit);
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * MEMO: we cannot obtain system column from RECORD datatype.
|
|
+ * If those are necesasry, they should be separately delivered.
|
|
+ */
|
|
+Datum sepgsql_tuple_perms(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid tableoid = PG_GETARG_OID(0);
|
|
+ Oid tcontext = PG_GETARG_OID(1);
|
|
+ uint32 perms = PG_GETARG_UINT32(2);
|
|
+ HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(3);
|
|
+ HeapTupleData tuple;
|
|
+
|
|
+ tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
|
|
+ ItemPointerSetInvalid(&tuple.t_self);
|
|
+ tuple.t_tableOid = tableoid;
|
|
+ tuple.t_data = rec;
|
|
+
|
|
+ PG_RETURN_BOOL(__check_tuple_perms(tableoid, tcontext, perms, &tuple, NULL, false));
|
|
+}
|
|
+
|
|
+Datum sepgsql_tuple_perms_abort(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ Oid tableoid = PG_GETARG_OID(0);
|
|
+ Oid tcontext = PG_GETARG_OID(1);
|
|
+ uint32 perms = PG_GETARG_UINT32(2);
|
|
+ HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(3);
|
|
+ HeapTupleData tuple;
|
|
+
|
|
+ tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
|
|
+ ItemPointerSetInvalid(&tuple.t_self);
|
|
+ tuple.t_tableOid = tableoid;
|
|
+ tuple.t_data = rec;
|
|
+
|
|
+ PG_RETURN_BOOL(__check_tuple_perms(tableoid, tcontext, perms, &tuple, NULL, true));
|
|
+}
|
|
+
|
|
+bool sepgsqlCheckTuplePerms(Relation rel, HeapTuple tuple, HeapTuple oldtup, uint32 perms, bool abort)
|
|
+{
|
|
+ return __check_tuple_perms(RelationGetRelid(rel),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ perms,
|
|
+ tuple,
|
|
+ oldtup,
|
|
+ abort);
|
|
+}
|
|
+
|
|
+Oid sepgsqlComputeImplicitContext(Relation rel, HeapTuple tuple) {
|
|
+ uint16 tclass;
|
|
+ Oid tcon;
|
|
+
|
|
+ switch (RelationGetRelid(rel)) {
|
|
+ case DatabaseRelationId: /* pg_database */
|
|
+ tclass = SECCLASS_DB_DATABASE;
|
|
+ tcon = sepgsqlGetServerContext();
|
|
+ break;
|
|
+
|
|
+ case RelationRelationId: { /* pg_class */
|
|
+ Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+ if (classForm->relkind == RELKIND_RELATION) {
|
|
+ tclass = SECCLASS_DB_TABLE;
|
|
+ tcon = sepgsqlGetDatabaseContext();
|
|
+ break;
|
|
+ }
|
|
+ tcon = __lookupRelationForm(RelationRelationId, NULL);
|
|
+ tclass = SECCLASS_DB_TUPLE;
|
|
+ break;
|
|
+ }
|
|
+ case AttributeRelationId: { /* pg_attribute */
|
|
+ Form_pg_attribute attrForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ FormData_pg_class classForm;
|
|
+
|
|
+ /* special case in bootstraping mode */
|
|
+ if (IsBootstrapProcessingMode()
|
|
+ && (attrForm->attrelid == TypeRelationId ||
|
|
+ attrForm->attrelid == ProcedureRelationId ||
|
|
+ attrForm->attrelid == AttributeRelationId ||
|
|
+ attrForm->attrelid == RelationRelationId)) {
|
|
+ tcon = sepgsql_avc_createcon(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetDatabaseContext(),
|
|
+ SECCLASS_DB_TABLE);
|
|
+ tclass = SECCLASS_DB_COLUMN;
|
|
+ break;
|
|
+ }
|
|
+ tcon = __lookupRelationForm(attrForm->attrelid, &classForm);
|
|
+ tclass = (classForm.relkind == RELKIND_RELATION
|
|
+ ? SECCLASS_DB_COLUMN
|
|
+ : SECCLASS_DB_TUPLE);
|
|
+ break;
|
|
+ }
|
|
+ case ProcedureRelationId:
|
|
+ tclass = SECCLASS_DB_PROCEDURE;
|
|
+ tcon = sepgsqlGetDatabaseContext();
|
|
+ break;
|
|
+
|
|
+ case LargeObjectRelationId:
|
|
+ tclass = SECCLASS_DB_BLOB;
|
|
+ tcon = sepgsqlGetDatabaseContext();
|
|
+ break;
|
|
+
|
|
+ case TypeRelationId: /* pg_type */
|
|
+ if (IsBootstrapProcessingMode()) {
|
|
+ /* special case in early phase */
|
|
+ tcon = sepgsql_avc_createcon(sepgsqlGetClientContext(),
|
|
+ sepgsqlGetDatabaseContext(),
|
|
+ SECCLASS_DB_TABLE);
|
|
+ tclass = SECCLASS_DB_TUPLE;
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ tclass = SECCLASS_DB_TUPLE;
|
|
+ tcon = __lookupRelationForm(RelationGetRelid(rel), NULL);
|
|
+ break;
|
|
+ }
|
|
+ return sepgsql_avc_createcon(sepgsqlGetClientContext(), tcon, tclass);
|
|
+}
|
|
diff -rpNU3 base/src/backend/security/sepgsqlProxy.c sepgsql/src/backend/security/sepgsqlProxy.c
|
|
--- base/src/backend/security/sepgsqlProxy.c 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/backend/security/sepgsqlProxy.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -0,0 +1,1487 @@
|
|
+/*
|
|
+ * src/backend/security/sepgsqlProxy.c
|
|
+ * SE-PostgreSQL Query Proxy function to walk on query node tree
|
|
+ * and append tuple filter.
|
|
+ *
|
|
+ * Copyright KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+ */
|
|
+#include "postgres.h"
|
|
+
|
|
+#include "access/genam.h"
|
|
+#include "access/heapam.h"
|
|
+#include "catalog/heap.h"
|
|
+#include "catalog/pg_attribute.h"
|
|
+#include "catalog/pg_class.h"
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_operator.h"
|
|
+#include "catalog/pg_proc.h"
|
|
+#include "catalog/pg_type.h"
|
|
+#include "executor/spi.h"
|
|
+#include "nodes/makefuncs.h"
|
|
+#include "optimizer/plancat.h"
|
|
+#include "parser/parse_relation.h"
|
|
+#include "parser/parse_target.h"
|
|
+#include "security/pgace.h"
|
|
+#include "storage/lock.h"
|
|
+#include "utils/fmgroids.h"
|
|
+#include "utils/syscache.h"
|
|
+
|
|
+#define RTEMARK_USE (1<<(N_ACL_RIGHTS))
|
|
+#define RTEMARK_SELECT (1<<(N_ACL_RIGHTS + 1))
|
|
+#define RTEMARK_INSERT (1<<(N_ACL_RIGHTS + 2))
|
|
+#define RTEMARK_UPDATE (1<<(N_ACL_RIGHTS + 3))
|
|
+#define RTEMARK_DELETE (1<<(N_ACL_RIGHTS + 4))
|
|
+#define RTEMARK_RELABELFROM (1<<(N_ACL_RIGHTS + 5))
|
|
+#define RTEMARK_RELABELTO (1<<(N_ACL_RIGHTS + 6))
|
|
+#define RTEMARK_BLOB_READ (1<<(N_ACL_RIGHTS + 7))
|
|
+#define RTEMARK_BLOB_WRITE (1<<(N_ACL_RIGHTS + 8))
|
|
+
|
|
+/* SE-PostgreSQL Evaluation Item */
|
|
+#define T_SEvalItem (T_TIDBitmap + 1) /* must be unique identifier */
|
|
+
|
|
+typedef struct SEvalItem {
|
|
+ NodeTag type;
|
|
+ uint16 tclass;
|
|
+ uint32 perms;
|
|
+ union {
|
|
+ struct {
|
|
+ Oid relid;
|
|
+ bool inh;
|
|
+ } c; /* for pg_class */
|
|
+ struct {
|
|
+ Oid relid;
|
|
+ bool inh;
|
|
+ AttrNumber attno;
|
|
+ } a; /* for pg_attribute */
|
|
+ struct {
|
|
+ Oid funcid;
|
|
+ } p; /* for pg_proc */
|
|
+ };
|
|
+} SEvalItem;
|
|
+
|
|
+/* query stack definition for outer references */
|
|
+typedef struct queryChain {
|
|
+ struct queryChain *parent;
|
|
+ Query *tail;
|
|
+} queryChain;
|
|
+
|
|
+static inline queryChain *upperQueryChain(queryChain *qc, int lvup) {
|
|
+ while (lvup > 0) {
|
|
+ Assert(!!qc->parent);
|
|
+ qc = qc->parent;
|
|
+ lvup--;
|
|
+ }
|
|
+ return qc;
|
|
+}
|
|
+
|
|
+static inline Query *getQueryFromChain(queryChain *qc) {
|
|
+ return qc->tail;
|
|
+}
|
|
+
|
|
+/* static definitions for proxy functions */
|
|
+static List *proxyRteRelation(List *selist, queryChain *qc, int rtindex, Node **quals);
|
|
+static List *proxyRteSubQuery(List *selist, queryChain *qc, Query *query);
|
|
+static List *proxyJoinTree(List *selist, queryChain *qc, Node *n, Node **quals);
|
|
+static List *proxySetOperations(List *selist, queryChain *qc, Node *n);
|
|
+
|
|
+/* static */
|
|
+static List *sepgsqlWalkExpr(List *selist, queryChain *qc, Node *n, int flags);
|
|
+#define WKFLAG_INTERNAL_USE (0x0001)
|
|
+
|
|
+/* -----------------------------------------------------------
|
|
+ * addEvalXXXX -- add evaluation items into Query->SEvalItemList.
|
|
+ * Those are used for execution phase.
|
|
+ * ----------------------------------------------------------- */
|
|
+static List *__addEvalPgClass(List *selist, Oid relid, bool inh, uint32 perms)
|
|
+{
|
|
+ SEvalItem *se;
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, selist) {
|
|
+ se = (SEvalItem *) lfirst(l);
|
|
+ if (se->tclass == SECCLASS_DB_TABLE
|
|
+ && se->c.relid == relid
|
|
+ && se->c.inh == inh) {
|
|
+ se->perms |= perms;
|
|
+ return selist;
|
|
+ }
|
|
+ }
|
|
+ /* not found */
|
|
+ se = makeNode(SEvalItem);
|
|
+ se->tclass = SECCLASS_DB_TABLE;
|
|
+ se->perms = perms;
|
|
+ se->c.relid = relid;
|
|
+ se->c.inh = inh;
|
|
+ return lappend(selist, se);
|
|
+}
|
|
+
|
|
+static List *addEvalPgClass(List *selist, RangeTblEntry *rte, uint32 perms)
|
|
+{
|
|
+ rte->requiredPerms |= (perms & DB_TABLE__USE ? RTEMARK_USE : 0);
|
|
+ rte->requiredPerms |= (perms & DB_TABLE__SELECT ? RTEMARK_SELECT : 0);
|
|
+ rte->requiredPerms |= (perms & DB_TABLE__INSERT ? RTEMARK_INSERT : 0);
|
|
+ rte->requiredPerms |= (perms & DB_TABLE__UPDATE ? RTEMARK_UPDATE : 0);
|
|
+ rte->requiredPerms |= (perms & DB_TABLE__DELETE ? RTEMARK_DELETE : 0);
|
|
+
|
|
+ return __addEvalPgClass(selist, rte->relid, rte->inh, perms);
|
|
+}
|
|
+
|
|
+static List *__addEvalPgAttribute(List *selist, Oid relid, bool inh, AttrNumber attno, uint32 perms)
|
|
+{
|
|
+ ListCell *l;
|
|
+ SEvalItem *se;
|
|
+
|
|
+ foreach (l, selist) {
|
|
+ se = (SEvalItem *) lfirst(l);
|
|
+ if (se->tclass == SECCLASS_DB_COLUMN
|
|
+ && se->a.relid == relid
|
|
+ && se->a.inh == inh
|
|
+ && se->a.attno == attno) {
|
|
+ se->perms |= perms;
|
|
+ return selist;
|
|
+ }
|
|
+ }
|
|
+ /* not found */
|
|
+ se = makeNode(SEvalItem);
|
|
+ se->tclass = SECCLASS_DB_COLUMN;
|
|
+ se->perms = perms;
|
|
+ se->a.relid = relid;
|
|
+ se->a.inh = inh;
|
|
+ se->a.attno = attno;
|
|
+
|
|
+ return lappend(selist, se);
|
|
+}
|
|
+
|
|
+static List *addEvalPgAttribute(List *selist, RangeTblEntry *rte, AttrNumber attno, uint32 perms)
|
|
+{
|
|
+ /* for 'security_context' */
|
|
+ if (attno == SecurityAttributeNumber
|
|
+ && (perms & (DB_COLUMN__UPDATE | DB_COLUMN__INSERT)))
|
|
+ rte->requiredPerms |= RTEMARK_RELABELFROM;
|
|
+
|
|
+ /* for 'pg_largeobject' */
|
|
+ if (rte->relid == LargeObjectRelationId
|
|
+ && attno == Anum_pg_largeobject_data) {
|
|
+ if (perms & DB_COLUMN__SELECT)
|
|
+ rte->requiredPerms |= RTEMARK_BLOB_READ;
|
|
+ if (perms & (DB_COLUMN__UPDATE | DB_COLUMN__INSERT))
|
|
+ rte->requiredPerms |= RTEMARK_BLOB_WRITE;
|
|
+ }
|
|
+
|
|
+ return __addEvalPgAttribute(selist, rte->relid, rte->inh, attno, perms);
|
|
+}
|
|
+
|
|
+static List *addEvalPgProc(List *selist, Oid funcid, uint32 perms)
|
|
+{
|
|
+ ListCell *l;
|
|
+ SEvalItem *se;
|
|
+
|
|
+ foreach (l, selist) {
|
|
+ se = (SEvalItem *) lfirst(l);
|
|
+ if (se->tclass == SECCLASS_DB_PROCEDURE
|
|
+ && se->p.funcid == funcid) {
|
|
+ se->perms |= perms;
|
|
+ return selist;
|
|
+ }
|
|
+ }
|
|
+ se = makeNode(SEvalItem);
|
|
+ se->tclass = SECCLASS_DB_PROCEDURE;
|
|
+ se->perms = perms;
|
|
+ se->p.funcid = funcid;
|
|
+
|
|
+ return lappend(selist, se);
|
|
+}
|
|
+
|
|
+static List *addEvalTriggerAccess(List *selist, Oid relid, bool is_inh, int cmdType)
|
|
+{
|
|
+ Relation rel;
|
|
+ SysScanDesc scan;
|
|
+ ScanKeyData skey;
|
|
+ HeapTuple tuple;
|
|
+ bool checked = false;
|
|
+
|
|
+ Assert(cmdType == CMD_INSERT || cmdType == CMD_UPDATE || cmdType == CMD_DELETE);
|
|
+
|
|
+ rel = heap_open(TriggerRelationId, AccessShareLock);
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_trigger_tgrelid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(relid));
|
|
+ scan = systable_beginscan(rel, TriggerRelidNameIndexId,
|
|
+ true, SnapshotNow, 1, &skey);
|
|
+ while (HeapTupleIsValid((tuple = systable_getnext(scan)))) {
|
|
+ Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
|
|
+
|
|
+ if (!trigForm->tgenabled)
|
|
+ continue;
|
|
+
|
|
+ if ((cmdType == CMD_INSERT && !TRIGGER_FOR_INSERT(trigForm->tgtype))
|
|
+ || (cmdType == CMD_UPDATE && !TRIGGER_FOR_UPDATE(trigForm->tgtype))
|
|
+ || (cmdType == CMD_DELETE && !TRIGGER_FOR_DELETE(trigForm->tgtype)))
|
|
+ continue;
|
|
+
|
|
+ /* per STATEMENT trigger cannot refer whole of a tuple */
|
|
+ if (!TRIGGER_FOR_ROW(trigForm->tgtype))
|
|
+ continue;
|
|
+
|
|
+ /* BEFORE-ROW-INSERT trigger cannot refer whole of a tuple */
|
|
+ if (TRIGGER_FOR_BEFORE(trigForm->tgtype) && TRIGGER_FOR_INSERT(trigForm->tgtype))
|
|
+ continue;
|
|
+
|
|
+ selist = addEvalPgProc(selist, trigForm->tgfoid, DB_PROCEDURE__EXECUTE);
|
|
+ if (!checked) {
|
|
+ HeapTuple reltup;
|
|
+ Form_pg_class classForm;
|
|
+ AttrNumber attnum;
|
|
+
|
|
+ reltup = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ classForm = (Form_pg_class) GETSTRUCT(reltup);
|
|
+
|
|
+ selist = __addEvalPgClass(selist, relid, false, DB_TABLE__SELECT);
|
|
+ for (attnum = FirstLowInvalidHeapAttributeNumber + 1; attnum <= 0; attnum++) {
|
|
+ if (attnum == ObjectIdAttributeNumber && !classForm->relhasoids)
|
|
+ continue;
|
|
+ selist = __addEvalPgAttribute(selist, relid, false, attnum, DB_COLUMN__SELECT);
|
|
+ }
|
|
+ ReleaseSysCache(reltup);
|
|
+
|
|
+ checked = true;
|
|
+ }
|
|
+ }
|
|
+ systable_endscan(scan);
|
|
+ heap_close(rel, AccessShareLock);
|
|
+
|
|
+ if (is_inh) {
|
|
+ List *child_list = find_inheritance_children(relid);
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach(l, child_list)
|
|
+ selist = addEvalTriggerAccess(selist, lfirst_oid(l), is_inh, cmdType);
|
|
+ }
|
|
+
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+/* *******************************************************************************
|
|
+ * walkExpr() -- walk on expression tree recursively to pick up and to construct
|
|
+ * a SEvalItem list related to expression node.
|
|
+ * It is evaluated at later phase.
|
|
+ * *******************************************************************************/
|
|
+static List *walkVarHelper(List *selist, queryChain *qc, Var *var, int flags)
|
|
+{
|
|
+ RangeTblEntry *rte;
|
|
+ Query *query;
|
|
+ Node *n;
|
|
+
|
|
+ Assert(IsA(var, Var));
|
|
+ if (!qc)
|
|
+ selerror("we could not use Var node in parameter list");
|
|
+
|
|
+ qc = upperQueryChain(qc, var->varlevelsup);
|
|
+ query = getQueryFromChain(qc);
|
|
+ rte = list_nth(query->rtable, var->varno - 1);
|
|
+ Assert(IsA(rte, RangeTblEntry));
|
|
+
|
|
+ switch (rte->rtekind) {
|
|
+ case RTE_RELATION:
|
|
+ /* table:{select} */
|
|
+ selist = addEvalPgClass(selist, rte,
|
|
+ (flags & WKFLAG_INTERNAL_USE)
|
|
+ ? DB_TABLE__USE : DB_TABLE__SELECT);
|
|
+ /* column:{select} */
|
|
+ selist = addEvalPgAttribute(selist, rte, var->varattno,
|
|
+ (flags & WKFLAG_INTERNAL_USE)
|
|
+ ? DB_COLUMN__USE : DB_COLUMN__SELECT);
|
|
+ break;
|
|
+ case RTE_JOIN:
|
|
+ n = list_nth(rte->joinaliasvars, var->varattno - 1);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, n, flags);
|
|
+ break;
|
|
+ case RTE_SUBQUERY:
|
|
+ /* In normal cases, rte->relid equals zero for subquery.
|
|
+ * If rte->relid has none-zero value, it's rewritten subquery
|
|
+ * for outer join handling.
|
|
+ */
|
|
+ if (rte->relid) {
|
|
+ Query *sqry = rte->subquery;
|
|
+ RangeTblEntry *srte;
|
|
+ TargetEntry *tle;
|
|
+ Var *svar;
|
|
+
|
|
+ Assert(sqry->commandType == CMD_SELECT);
|
|
+ Assert(list_length(sqry->rtable) == 1);
|
|
+
|
|
+ srte = (RangeTblEntry *) list_nth(sqry->rtable, 0);
|
|
+ Assert(srte->rtekind == RTE_RELATION);
|
|
+ Assert(srte->relid == rte->relid);
|
|
+
|
|
+ if (var->varattno < 1) {
|
|
+ ListCell *l;
|
|
+ bool found = false;
|
|
+
|
|
+ foreach(l, sqry->targetList) {
|
|
+ TargetEntry *tle = lfirst(l);
|
|
+
|
|
+ Assert(IsA(tle, TargetEntry));
|
|
+ if (IsA(tle->expr, Const))
|
|
+ continue;
|
|
+
|
|
+ svar = (Var *) tle->expr;
|
|
+ Assert(IsA(svar, Var));
|
|
+ if (svar->varattno == var->varattno) {
|
|
+ var->varattno = tle->resno;
|
|
+ found = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!found) {
|
|
+ AttrNumber resno = list_length(sqry->targetList) + 1;
|
|
+ svar = makeVar(1,
|
|
+ var->varattno,
|
|
+ var->vartype,
|
|
+ var->vartypmod,
|
|
+ 0);
|
|
+ tle = makeTargetEntry((Expr *) svar, resno, NULL, false);
|
|
+ var->varattno = resno;
|
|
+ sqry->targetList = lappend(sqry->targetList, tle);
|
|
+ }
|
|
+ } else {
|
|
+ tle = list_nth(sqry->targetList, var->varattno - 1);
|
|
+ Assert(IsA(tle, TargetEntry));
|
|
+ if (!IsA(tle->expr, Var))
|
|
+ selerror("dropped column is accessed (relid=%u, attno=%d)",
|
|
+ rte->relid, var->varattno);
|
|
+ svar = (Var *) tle->expr;
|
|
+ }
|
|
+ /* table:{select} or [use} */
|
|
+ selist = addEvalPgClass(selist, srte,
|
|
+ (flags & WKFLAG_INTERNAL_USE)
|
|
+ ? DB_TABLE__USE : DB_TABLE__SELECT);
|
|
+ /* column:{select} or {use}*/
|
|
+ selist = addEvalPgAttribute(selist, srte, svar->varattno,
|
|
+ (flags & WKFLAG_INTERNAL_USE)
|
|
+ ? DB_COLUMN__USE : DB_COLUMN__SELECT);
|
|
+ }
|
|
+ break;
|
|
+ case RTE_SPECIAL:
|
|
+ case RTE_FUNCTION:
|
|
+ case RTE_VALUES:
|
|
+ break;
|
|
+ default:
|
|
+ selerror("unrecognized rtekind (%d)", rte->rtekind);
|
|
+ break;
|
|
+ }
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+static List *walkOpExprHelper(List *selist, Oid opid)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ Form_pg_operator oprform;
|
|
+
|
|
+ tuple = SearchSysCache(OPEROID,
|
|
+ ObjectIdGetDatum(opid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("cache lookup failed for OPEROID = %u", opid);
|
|
+ oprform = (Form_pg_operator) GETSTRUCT(tuple);
|
|
+
|
|
+ selist = addEvalPgProc(selist, oprform->oprcode, DB_PROCEDURE__EXECUTE);
|
|
+ /* NOTE: opr->oprrest and opr->oprjoin are internal use only
|
|
+ * and have no effect onto the data references, so we don't
|
|
+ * apply any checkings for them.
|
|
+ */
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+static List *sepgsqlWalkExpr(List *selist, queryChain *qc, Node *node, int flags)
|
|
+{
|
|
+ if (node == NULL)
|
|
+ return selist;
|
|
+
|
|
+ switch (nodeTag(node)) {
|
|
+ case T_Const:
|
|
+ case T_Param:
|
|
+ case T_CaseTestExpr:
|
|
+ /* do nothing */
|
|
+ break;
|
|
+ case T_List: {
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, (List *) node)
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) lfirst(l), flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_Var: {
|
|
+ selist = walkVarHelper(selist, qc, (Var *) node, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_FuncExpr: {
|
|
+ FuncExpr *func = (FuncExpr *) node;
|
|
+
|
|
+ selist = addEvalPgProc(selist, func->funcid, DB_PROCEDURE__EXECUTE);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) func->args, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_Aggref: {
|
|
+ Aggref *aggref = (Aggref *) node;
|
|
+
|
|
+ selist = addEvalPgProc(selist, aggref->aggfnoid, DB_PROCEDURE__EXECUTE);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) aggref->args, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_OpExpr:
|
|
+ case T_DistinctExpr: /* typedef of OpExpr */
|
|
+ case T_NullIfExpr: /* typedef of OpExpr */
|
|
+ {
|
|
+ OpExpr *op = (OpExpr *) node;
|
|
+
|
|
+ selist = walkOpExprHelper(selist, op->opno);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) op->args, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_ScalarArrayOpExpr: {
|
|
+ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) node;
|
|
+
|
|
+ selist = walkOpExprHelper(selist, saop->opno);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) saop->args, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_BoolExpr: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((BoolExpr *) node)->args, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_ArrayRef: {
|
|
+ ArrayRef *aref = (ArrayRef *) node;
|
|
+
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) aref->refupperindexpr, flags);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) aref->reflowerindexpr, flags);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) aref->refexpr, flags);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) aref->refassgnexpr, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_SubLink: {
|
|
+ SubLink *slink = (SubLink *) node;
|
|
+
|
|
+ Assert(IsA(slink->subselect, Query));
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) slink->testexpr, flags);
|
|
+ selist = proxyRteSubQuery(selist, qc, (Query *) slink->subselect);
|
|
+ break;
|
|
+ }
|
|
+ case T_SortClause:
|
|
+ case T_GroupClause: /* typedef of SortClause */
|
|
+ {
|
|
+ SortClause *sort = (SortClause *) node;
|
|
+ Query *query = getQueryFromChain(qc);
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, query->targetList) {
|
|
+ TargetEntry *tle = (TargetEntry *) lfirst(l);
|
|
+ Assert(IsA(tle, TargetEntry));
|
|
+ if (tle->ressortgroupref == sort->tleSortGroupRef) {
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) tle->expr, flags);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ case T_CoerceToDomain: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((CoerceToDomain *) node)->arg, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_CaseExpr: {
|
|
+ CaseExpr *ce = (CaseExpr *) node;
|
|
+
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) ce->arg, flags);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) ce->args, flags);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) ce->defresult, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_CaseWhen: {
|
|
+ CaseWhen *casewhen = (CaseWhen *) node;
|
|
+
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) casewhen->expr, flags);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) casewhen->result, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_RelabelType: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((RelabelType *) node)->arg, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_CoalesceExpr: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((CoalesceExpr *) node)->args, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_MinMaxExpr: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((MinMaxExpr *) node)->args, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_NullTest: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((NullTest *) node)->arg, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_BooleanTest: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((BooleanTest *) node)->arg, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_FieldSelect: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((FieldSelect *) node)->arg, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_FieldStore: {
|
|
+ FieldStore *fstore = (FieldStore *) node;
|
|
+
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) fstore->arg, flags);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) fstore->newvals, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_ArrayExpr: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((ArrayExpr *) node)->elements, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_RowExpr: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((RowExpr *) node)->args, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_RowCompareExpr: {
|
|
+ RowCompareExpr *rce = (RowCompareExpr *) node;
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, rce->opnos)
|
|
+ selist = walkOpExprHelper(selist, lfirst_oid(l));
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) rce->largs, flags);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) rce->rargs, flags);
|
|
+ break;
|
|
+ }
|
|
+ case T_ConvertRowtypeExpr: {
|
|
+ selist = sepgsqlWalkExpr(selist, qc,
|
|
+ (Node *) ((ConvertRowtypeExpr *) node)->arg, flags);
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ selnotice("node(%d) is ignored => %s", nodeTag(node), nodeToString(node));
|
|
+ break;
|
|
+ }
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+/* *******************************************************************************
|
|
+ * proxyRteXXXX() -- check any relation type objects in the required query,
|
|
+ * including general relation, outer|inner|cross join and subquery.
|
|
+ *
|
|
+ * sepgsqlProxyQuery() is called just after query rewriting phase to constract
|
|
+ * a list of SEvalItems. It is attached into Query->pgaceList and evaluated by
|
|
+ * sepgsqlVerifyQuery() at later phase.
|
|
+ * *******************************************************************************/
|
|
+
|
|
+static Oid fnoid_sepgsql_tuple_perm = F_SEPGSQL_TUPLE_PERMS;
|
|
+
|
|
+/*
|
|
+ * When we use LEFT OUTER JOIN, any condition defined at ON clause are not
|
|
+ * considered to filter tuples, so left-hand relation have to be re-written
|
|
+ * as a subquery to filter violated tuples.
|
|
+ */
|
|
+static List *makePseudoTargetList(Oid relid) {
|
|
+ HeapTuple reltup, atttup;
|
|
+ Form_pg_class classForm;
|
|
+ Form_pg_attribute attrForm;
|
|
+ AttrNumber attno, relnatts;
|
|
+ TargetEntry *tle;
|
|
+ Expr *expr;
|
|
+ List *targetList = NIL;
|
|
+
|
|
+ reltup = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(reltup))
|
|
+ selerror("relation (oid: %u) does not exist", relid);
|
|
+
|
|
+ classForm = (Form_pg_class) GETSTRUCT(reltup);
|
|
+ relnatts = classForm->relnatts;
|
|
+ for (attno = 1; attno <= relnatts; attno++) {
|
|
+ atttup = SearchSysCache(ATTNUM,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ Int16GetDatum(attno),
|
|
+ 0, 0);
|
|
+ if (!HeapTupleIsValid(atttup))
|
|
+ selerror("attribute %u of relation '%s' does not exist",
|
|
+ attno, NameStr(classForm->relname));
|
|
+ attrForm = (Form_pg_attribute) GETSTRUCT(atttup);
|
|
+ if (attrForm->attisdropped) {
|
|
+ expr = (Expr *) makeNullConst(INT4OID);
|
|
+ } else {
|
|
+ expr = (Expr *) makeVar(1,
|
|
+ attno,
|
|
+ attrForm->atttypid,
|
|
+ attrForm->atttypmod,
|
|
+ 0);
|
|
+ }
|
|
+ tle = makeTargetEntry(expr, attno, NULL, false);
|
|
+ targetList = lappend(targetList, tle);
|
|
+ ReleaseSysCache(atttup);
|
|
+
|
|
+ Assert(list_length(targetList) == attno);
|
|
+ }
|
|
+ ReleaseSysCache(reltup);
|
|
+
|
|
+ return targetList;
|
|
+}
|
|
+
|
|
+static void rewriteOuterJoinTree(Node *n, Query *query, bool is_outer_join)
|
|
+{
|
|
+ RangeTblRef *rtr, *srtr;
|
|
+ RangeTblEntry *rte, *srte;
|
|
+ Query *sqry;
|
|
+ FromExpr *sfrm;
|
|
+
|
|
+ if (IsA(n, RangeTblRef)) {
|
|
+ if (!is_outer_join)
|
|
+ return;
|
|
+
|
|
+ rtr = (RangeTblRef *) n;
|
|
+ rte = list_nth(query->rtable, rtr->rtindex - 1);
|
|
+ Assert(IsA(rte, RangeTblEntry));
|
|
+ if (rte->rtekind != RTE_RELATION)
|
|
+ return;
|
|
+
|
|
+ /* setup alternative query */
|
|
+ sqry = makeNode(Query);
|
|
+ sqry->commandType = CMD_SELECT;
|
|
+ sqry->targetList = makePseudoTargetList(rte->relid);
|
|
+
|
|
+ srte = copyObject(rte);
|
|
+ sqry->rtable = list_make1(srte);
|
|
+
|
|
+ srtr = makeNode(RangeTblRef);
|
|
+ srtr->rtindex = 1;
|
|
+
|
|
+ sfrm = makeNode(FromExpr);
|
|
+ sfrm->fromlist = list_make1(srtr);
|
|
+ sfrm->quals = NULL;
|
|
+
|
|
+ sqry->jointree = sfrm;
|
|
+ sqry->hasSubLinks = false;
|
|
+ sqry->hasAggs = false;
|
|
+
|
|
+ rte->rtekind = RTE_SUBQUERY;
|
|
+ rte->subquery = sqry;
|
|
+ } else if (IsA(n, FromExpr)) {
|
|
+ FromExpr *f = (FromExpr *)n;
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, f->fromlist)
|
|
+ rewriteOuterJoinTree(lfirst(l), query, false);
|
|
+ } else if (IsA(n, JoinExpr)) {
|
|
+ JoinExpr *j = (JoinExpr *) n;
|
|
+
|
|
+ rewriteOuterJoinTree(j->larg, query,
|
|
+ (j->jointype == JOIN_LEFT || j->jointype == JOIN_FULL));
|
|
+ rewriteOuterJoinTree(j->rarg, query,
|
|
+ (j->jointype == JOIN_RIGHT || j->jointype == JOIN_FULL));
|
|
+ } else {
|
|
+ selerror("unrecognized node type (%d) in query->jointree", nodeTag(n));
|
|
+ }
|
|
+}
|
|
+
|
|
+static List *proxyRteRelation(List *selist, queryChain *qc, int rtindex, Node **quals)
|
|
+{
|
|
+ Query *query;
|
|
+ RangeTblEntry *rte;
|
|
+ Relation rel;
|
|
+ TupleDesc tdesc;
|
|
+ uint32 perms = 0;
|
|
+
|
|
+ query = getQueryFromChain(qc);
|
|
+ rte = list_nth(query->rtable, rtindex - 1);
|
|
+ rel = relation_open(rte->relid, AccessShareLock);
|
|
+ tdesc = RelationGetDescr(rel);
|
|
+
|
|
+ /* setup tclass and access vector */
|
|
+ perms = 0;
|
|
+ if (rte->requiredPerms & RTEMARK_USE)
|
|
+ perms |= DB_TUPLE__USE;
|
|
+ if (rte->requiredPerms & RTEMARK_SELECT)
|
|
+ perms |= DB_TUPLE__SELECT;
|
|
+ if (rte->requiredPerms & RTEMARK_INSERT)
|
|
+ perms |= DB_TUPLE__INSERT;
|
|
+ if (rte->requiredPerms & RTEMARK_UPDATE)
|
|
+ perms |= DB_TUPLE__UPDATE;
|
|
+ if (rte->requiredPerms & RTEMARK_DELETE)
|
|
+ perms |= DB_TUPLE__DELETE;
|
|
+ if (rte->requiredPerms & RTEMARK_RELABELFROM)
|
|
+ perms |= DB_TUPLE__RELABELFROM;
|
|
+ if (rte->requiredPerms & RTEMARK_RELABELTO)
|
|
+ perms |= DB_TUPLE__RELABELTO;
|
|
+ if (rte->requiredPerms & RTEMARK_BLOB_READ)
|
|
+ perms |= DB_BLOB__READ;
|
|
+ if (rte->requiredPerms & RTEMARK_BLOB_WRITE)
|
|
+ perms |= DB_BLOB__WRITE;
|
|
+
|
|
+ /* append sepgsql_tuple_perm(relid, record, perms) */
|
|
+ if (perms) {
|
|
+ Var *v1, *v2, *v4;
|
|
+ Const *c3;
|
|
+ FuncExpr *func;
|
|
+
|
|
+ /* 1st arg : Oid of the target relation */
|
|
+ v1 = makeVar(rtindex, TableOidAttributeNumber, OIDOID, -1, 0);
|
|
+
|
|
+ /* 2nd arg : Security Attribute of tuple */
|
|
+ v2 = makeVar(rtindex, SecurityAttributeNumber, OIDOID, -1, 0);
|
|
+
|
|
+ /* 3rd arg : permission set */
|
|
+ c3 = makeConst(INT4OID, sizeof(int32), Int32GetDatum(perms), false, true);
|
|
+
|
|
+ /* 4th arg : RECORD of the target relation */
|
|
+ v4 = makeVar(rtindex, 0, RelationGetForm(rel)->reltype, -1, 0);
|
|
+
|
|
+ /* append sepgsql_tuple_perm */
|
|
+ func = makeFuncExpr(fnoid_sepgsql_tuple_perm, BOOLOID,
|
|
+ list_make4(v1, v2, c3, v4), COERCE_DONTCARE);
|
|
+ if (*quals == NULL) {
|
|
+ *quals = (Node *) func;
|
|
+ } else {
|
|
+ *quals = (Node *) makeBoolExpr(AND_EXPR, list_make2(func, *quals));
|
|
+ }
|
|
+ }
|
|
+ relation_close(rel, NoLock);
|
|
+
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+static List *proxyRteOuterJoin(List *selist, queryChain *qc, Query *query)
|
|
+{
|
|
+ queryChain qcData;
|
|
+ ListCell *l;
|
|
+
|
|
+ qcData.parent = qc;
|
|
+ qcData.tail = query;
|
|
+ qc = &qcData;
|
|
+
|
|
+ selist = proxyRteRelation(selist, qc, 1, &query->jointree->quals);
|
|
+
|
|
+ /* clean-up polluted RangeTblEntry */
|
|
+ foreach (l, query->rtable) {
|
|
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
|
+ rte->requiredPerms &= ((1<<N_ACL_RIGHTS) - 1);
|
|
+ }
|
|
+
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+static List *proxyRteSubQuery(List *selist, queryChain *qc, Query *query)
|
|
+{
|
|
+ CmdType cmdType = query->commandType;
|
|
+ RangeTblEntry *rte = NULL;
|
|
+ queryChain qcData;
|
|
+ ListCell *l;
|
|
+
|
|
+ /* query chain setup */
|
|
+ qcData.parent = qc;
|
|
+ qcData.tail = query;
|
|
+ qc = &qcData;
|
|
+
|
|
+ /* rewrite outer join */
|
|
+ rewriteOuterJoinTree((Node *) query->jointree, query, false);
|
|
+
|
|
+ if (cmdType != CMD_SELECT) {
|
|
+ rte = list_nth(query->rtable, query->resultRelation - 1);
|
|
+ Assert(IsA(rte, RangeTblEntry) && rte->rtekind==RTE_RELATION);
|
|
+ switch (cmdType) {
|
|
+ case CMD_INSERT:
|
|
+ selist = addEvalPgClass(selist, rte, DB_TABLE__INSERT);
|
|
+ break;
|
|
+ case CMD_UPDATE:
|
|
+ selist = addEvalPgClass(selist, rte, DB_TABLE__UPDATE);
|
|
+ break;
|
|
+ case CMD_DELETE:
|
|
+ selist = addEvalPgClass(selist, rte, DB_TABLE__DELETE);
|
|
+ break;
|
|
+ default:
|
|
+ selerror("commandType = %d should not be found here", cmdType);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* permission mark on the target columns */
|
|
+ if (cmdType != CMD_DELETE) {
|
|
+ foreach (l, query->targetList) {
|
|
+ TargetEntry *tle = lfirst(l);
|
|
+ Assert(IsA(tle, TargetEntry));
|
|
+
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) tle->expr,
|
|
+ tle->resjunk ? WKFLAG_INTERNAL_USE : 0);
|
|
+ /* mark insert/update target */
|
|
+ if (cmdType==CMD_UPDATE || cmdType==CMD_INSERT) {
|
|
+ uint32 perms = (cmdType == CMD_UPDATE
|
|
+ ? DB_COLUMN__UPDATE : DB_COLUMN__INSERT);
|
|
+ if (tle->resjunk) {
|
|
+ if (!strcmp(tle->resname, SECURITY_SYSATTR_NAME))
|
|
+ selist = addEvalPgAttribute(selist,
|
|
+ rte,
|
|
+ SecurityAttributeNumber,
|
|
+ perms);
|
|
+ continue;
|
|
+ }
|
|
+ selist = addEvalPgAttribute(selist, rte, tle->resno, perms);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* permission mark on RETURNING clause, if necessary */
|
|
+ foreach (l, query->returningList) {
|
|
+ TargetEntry *te = lfirst(l);
|
|
+ Assert(IsA(te, TargetEntry));
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) te->expr, 0);
|
|
+ }
|
|
+
|
|
+ /* permission mark on the WHERE/HAVING clause */
|
|
+ selist = sepgsqlWalkExpr(selist, qc, query->jointree->quals,
|
|
+ WKFLAG_INTERNAL_USE);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, query->havingQual,
|
|
+ WKFLAG_INTERNAL_USE);
|
|
+
|
|
+ /* permission mark on the ORDER BY clause */
|
|
+ //selist = sepgsqlWalkExpr(selist, qc, (Node *) query->sortClause, WKFLAG_INTERNAL_USE);
|
|
+
|
|
+ /* permission mark on the GROUP BY/HAVING clause */
|
|
+ //selist = sepgsqlWalkExpr(selist, qc, (Node *) query->groupClause, WKFLAG_INTERNAL_USE);
|
|
+
|
|
+ /* permission mark on the UNION/INTERSECT/EXCEPT */
|
|
+ selist = proxySetOperations(selist, qc, query->setOperations);
|
|
+
|
|
+ /* append sepgsql_permission() on the FROM clause/USING clause
|
|
+ * for SELECT/UPDATE/DELETE statement.
|
|
+ * The target Relation of INSERT is noe necessary to append it
|
|
+ */
|
|
+ selist = proxyJoinTree(selist, qc, (Node *) query->jointree,
|
|
+ &query->jointree->quals);
|
|
+
|
|
+ /* clean-up polluted RangeTblEntry */
|
|
+ foreach (l, query->rtable) {
|
|
+ rte = (RangeTblEntry *) lfirst(l);
|
|
+ rte->requiredPerms &= ((1<<N_ACL_RIGHTS) - 1);
|
|
+ }
|
|
+
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+static List *proxyJoinTree(List *selist, queryChain *qc, Node *n, Node **quals)
|
|
+{
|
|
+ Query *query = getQueryFromChain(qc);
|
|
+
|
|
+ if (n == NULL)
|
|
+ return selist;
|
|
+
|
|
+ if (IsA(n, RangeTblRef)) {
|
|
+ RangeTblRef *rtr = (RangeTblRef *) n;
|
|
+ RangeTblEntry *rte = list_nth(query->rtable, rtr->rtindex - 1);
|
|
+ Assert(IsA(rte, RangeTblEntry));
|
|
+
|
|
+ switch (rte->rtekind) {
|
|
+ case RTE_RELATION:
|
|
+ selist = proxyRteRelation(selist, qc, rtr->rtindex, quals);
|
|
+ break;
|
|
+ case RTE_SUBQUERY:
|
|
+ selist = (rte->relid
|
|
+ ? proxyRteOuterJoin(selist, qc, rte->subquery)
|
|
+ : proxyRteSubQuery(selist, qc, rte->subquery));
|
|
+ break;
|
|
+ case RTE_FUNCTION: {
|
|
+ FuncExpr *f = (FuncExpr *) rte->funcexpr;
|
|
+
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) f, 0);
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) f->args, 0);
|
|
+ break;
|
|
+ }
|
|
+ case RTE_VALUES:
|
|
+ selist = sepgsqlWalkExpr(selist, qc, (Node *) rte->values_lists, 0);
|
|
+ break;
|
|
+ default:
|
|
+ selerror("rtekind = %d should not be found fromList", rte->rtekind);
|
|
+ break;
|
|
+ }
|
|
+ } else if (IsA(n, FromExpr)) {
|
|
+ FromExpr *f = (FromExpr *)n;
|
|
+ ListCell *l;
|
|
+
|
|
+ selist = sepgsqlWalkExpr(selist, qc, f->quals, WKFLAG_INTERNAL_USE);
|
|
+ foreach (l, f->fromlist)
|
|
+ selist = proxyJoinTree(selist, qc, lfirst(l), quals);
|
|
+ } else if (IsA(n, JoinExpr)) {
|
|
+ JoinExpr *j = (JoinExpr *) n;
|
|
+
|
|
+ selist = sepgsqlWalkExpr(selist, qc, j->quals, WKFLAG_INTERNAL_USE);
|
|
+ selist = proxyJoinTree(selist, qc, j->larg, &j->quals);
|
|
+ selist = proxyJoinTree(selist, qc, j->rarg, &j->quals);
|
|
+ } else {
|
|
+ selerror("unrecognized node type (%d) in query->jointree", nodeTag(n));
|
|
+ }
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+static List *proxySetOperations(List *selist, queryChain *qc, Node *n)
|
|
+{
|
|
+ Query *query = getQueryFromChain(qc);
|
|
+
|
|
+ if (n == NULL)
|
|
+ return selist;
|
|
+
|
|
+ if (IsA(n, RangeTblRef)) {
|
|
+ RangeTblRef *rtr = (RangeTblRef *) n;
|
|
+ RangeTblEntry *rte = list_nth(query->rtable, rtr->rtindex - 1);
|
|
+
|
|
+ Assert(IsA(rte, RangeTblEntry) && rte->rtekind == RTE_SUBQUERY);
|
|
+
|
|
+ selist = proxyRteSubQuery(selist, qc, rte->subquery);
|
|
+ } else if (IsA(n, SetOperationStmt)) {
|
|
+ SetOperationStmt *op = (SetOperationStmt *) n;
|
|
+
|
|
+ selist = proxySetOperations(selist, qc, (Node *) op->larg);
|
|
+ selist = proxySetOperations(selist, qc, (Node *) op->rarg);
|
|
+ } else {
|
|
+ selerror("setOperationsTree contains => %s", nodeToString(n));
|
|
+ }
|
|
+
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+static List *proxyGeneralQuery(Query *query)
|
|
+{
|
|
+ List *selist = NIL;
|
|
+
|
|
+ selist = proxyRteSubQuery(selist, NULL, query);
|
|
+ query->pgaceList = selist;
|
|
+
|
|
+ return list_make1(query);
|
|
+}
|
|
+
|
|
+static List *proxyExecuteStmt(Query *query)
|
|
+{
|
|
+ List *selist = NIL;
|
|
+ ExecuteStmt *estmt = (ExecuteStmt *) query->utilityStmt;
|
|
+ queryChain qcData;
|
|
+
|
|
+ Assert(nodeTag(query->utilityStmt) == T_ExecuteStmt);
|
|
+
|
|
+ qcData.parent = NULL;
|
|
+ qcData.tail = query;
|
|
+ selist = sepgsqlWalkExpr(selist, &qcData, (Node *) estmt->params, 0);
|
|
+ query->pgaceList = selist;
|
|
+
|
|
+ return list_make1(query);
|
|
+}
|
|
+
|
|
+static Query *convertTruncateToDelete(Relation rel)
|
|
+{
|
|
+ Query *query = makeNode(Query);
|
|
+ RangeTblEntry *rte;
|
|
+ RangeTblRef *rtr;
|
|
+
|
|
+ rte = addRangeTableEntryForRelation(NULL, rel, NULL, false, false);
|
|
+ rte->requiredPerms = ACL_DELETE;
|
|
+ rtr = makeNode(RangeTblRef);
|
|
+ rtr->rtindex = 1;
|
|
+
|
|
+ query->commandType = CMD_DELETE;
|
|
+ query->rtable = list_make1(rte);
|
|
+ query->jointree = makeNode(FromExpr);
|
|
+ query->jointree->fromlist = list_make1(rtr);
|
|
+ query->jointree->quals = NULL;
|
|
+ query->resultRelation = rtr->rtindex;
|
|
+ query->hasSubLinks = false;
|
|
+ query->hasAggs = false;
|
|
+
|
|
+ sepgsqlProxyQuery(query);
|
|
+
|
|
+ return query;
|
|
+}
|
|
+
|
|
+static List *proxyTruncateStmt(Query *query)
|
|
+{
|
|
+ TruncateStmt *stmt = (TruncateStmt *) query->utilityStmt;
|
|
+ Relation rel;
|
|
+ Query *subqry;
|
|
+ ListCell *l;
|
|
+ List *subquery_list = NIL, *subquery_lids = NIL;
|
|
+
|
|
+ /* resolve the relation names */
|
|
+ foreach (l, stmt->relations) {
|
|
+ RangeVar *rv = lfirst(l);
|
|
+
|
|
+ rel = heap_openrv(rv, AccessShareLock);
|
|
+ subqry = convertTruncateToDelete(rel);
|
|
+ subquery_list = lappend(subquery_list, subqry);
|
|
+ subquery_lids = lappend_oid(subquery_lids, RelationGetRelid(rel));
|
|
+ heap_close(rel, NoLock);
|
|
+
|
|
+ selnotice("virtual TRUNCATE %s", RelationGetRelationName(rel));
|
|
+ }
|
|
+
|
|
+ if (stmt->behavior == DROP_CASCADE) {
|
|
+ subquery_lids = heap_truncate_find_FKs(subquery_lids);
|
|
+ foreach (l, subquery_lids) {
|
|
+ Oid relid = lfirst_oid(l);
|
|
+
|
|
+ rel = heap_open(relid, AccessShareLock);
|
|
+ subqry = convertTruncateToDelete(rel);
|
|
+ subquery_list = lappend(subquery_list, subqry);
|
|
+ heap_close(rel, NoLock);
|
|
+ }
|
|
+ }
|
|
+ return subquery_list;
|
|
+}
|
|
+
|
|
+List *sepgsqlProxyQuery(Query *query)
|
|
+{
|
|
+ List *new_list = NIL;
|
|
+
|
|
+ switch (query->commandType) {
|
|
+ case CMD_SELECT:
|
|
+ case CMD_UPDATE:
|
|
+ case CMD_INSERT:
|
|
+ case CMD_DELETE:
|
|
+ new_list = proxyGeneralQuery(query);
|
|
+ break;
|
|
+ case CMD_UTILITY:
|
|
+ switch (nodeTag(query->utilityStmt)) {
|
|
+ case T_TruncateStmt:
|
|
+ new_list = proxyTruncateStmt(query);
|
|
+ break;
|
|
+ case T_ExecuteStmt:
|
|
+ new_list = proxyExecuteStmt(query);
|
|
+ break;
|
|
+ default:
|
|
+ new_list = list_make1(query);
|
|
+ /* do nothing now */
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ selerror("unknown command type (=%d) found",
|
|
+ query->commandType);
|
|
+ break;
|
|
+ }
|
|
+ return new_list;
|
|
+}
|
|
+
|
|
+/* *******************************************************************************
|
|
+ * verifyXXXX() -- checks any SEvalItem attached with Query->pgaceList.
|
|
+ * Those are generated in proxyXXXX() phase, and this evaluation is done
|
|
+ * just before PortalStart().
|
|
+ * The reason why the checks are delayed is to handle cases when parse
|
|
+ * and execute are separated like PREPARE/EXECUTE statement.
|
|
+ * *******************************************************************************/
|
|
+static void verifyPgClassPerms(Oid relid, bool inh, uint32 perms)
|
|
+{
|
|
+ Form_pg_class pgclass;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ /* check untouchable tables */
|
|
+ if (perms & (DB_TABLE__UPDATE | DB_TABLE__INSERT | DB_TABLE__DELETE)) {
|
|
+ if (relid == SecurityRelationId)
|
|
+ selerror("user cannot modify pg_security directly, for security reason");
|
|
+ }
|
|
+
|
|
+ /* check table:{required permissions} */
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("RELOID cache lookup failed (relid=%u)", relid);
|
|
+ pgclass = (Form_pg_class) GETSTRUCT(tuple);
|
|
+
|
|
+ if (pgclass->relkind != RELKIND_RELATION) {
|
|
+ //selnotice("%s is not a general relation", NameStr(pgclass->relname));
|
|
+ ReleaseSysCache(tuple);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_DB_TABLE,
|
|
+ perms,
|
|
+ sepgsqlGetTupleName(RelationRelationId, tuple));
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+static void verifyPgAttributePerms(Oid relid, bool inh, AttrNumber attno, uint32 perms)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ Form_pg_class classForm;
|
|
+ Form_pg_attribute attrForm;
|
|
+
|
|
+ tuple = SearchSysCache(RELOID,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("RELOID cache lookup failed (relid=%u)", relid);
|
|
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
+ if (classForm->relkind != RELKIND_RELATION) {
|
|
+ /* column:{ xxx } checks are applied only column within tables */
|
|
+ ReleaseSysCache(tuple);
|
|
+ return;
|
|
+ }
|
|
+ ReleaseSysCache(tuple);
|
|
+
|
|
+ /* 2. verify column perms */
|
|
+ if (attno == 0) {
|
|
+ /* RECORD type permission check */
|
|
+ Relation rel;
|
|
+ ScanKeyData skey;
|
|
+ SysScanDesc scan;
|
|
+
|
|
+ ScanKeyInit(&skey,
|
|
+ Anum_pg_attribute_attrelid,
|
|
+ BTEqualStrategyNumber, F_OIDEQ,
|
|
+ ObjectIdGetDatum(relid));
|
|
+
|
|
+ rel = heap_open(AttributeRelationId, AccessShareLock);
|
|
+ scan = systable_beginscan(rel, AttributeRelidNumIndexId,
|
|
+ true, SnapshotNow, 1, &skey);
|
|
+ while ((tuple = systable_getnext(scan)) != NULL) {
|
|
+ attrForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ if (attrForm->attisdropped || attrForm->attnum < 1)
|
|
+ continue;
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_DB_COLUMN,
|
|
+ perms,
|
|
+ sepgsqlGetTupleName(AttributeRelationId, tuple));
|
|
+ }
|
|
+ systable_endscan(scan);
|
|
+ heap_close(rel, AccessShareLock);
|
|
+
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ tuple = SearchSysCache(ATTNUM,
|
|
+ ObjectIdGetDatum(relid),
|
|
+ Int16GetDatum(attno),
|
|
+ 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("ATTNUM cache lookup failed (relid=%u, attno=%d)", relid, attno);
|
|
+
|
|
+ /* check column:{required permissions} */
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_DB_COLUMN,
|
|
+ perms,
|
|
+ sepgsqlGetTupleName(AttributeRelationId, tuple));
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+static void verifyPgProcPerms(Oid funcid, uint32 perms)
|
|
+{
|
|
+ HeapTuple tuple;
|
|
+ Oid newcon;
|
|
+
|
|
+ tuple = SearchSysCache(PROCOID,
|
|
+ ObjectIdGetDatum(funcid),
|
|
+ 0, 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("cache lookup failed for procedure %d", funcid);
|
|
+
|
|
+ /* compute domain transition */
|
|
+ newcon = sepgsql_avc_createcon(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_PROCESS);
|
|
+ if (newcon != sepgsqlGetClientContext())
|
|
+ perms |= DB_PROCEDURE__ENTRYPOINT;
|
|
+
|
|
+ /* check procedure executiong permission */
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ HeapTupleGetSecurity(tuple),
|
|
+ SECCLASS_DB_PROCEDURE,
|
|
+ perms,
|
|
+ sepgsqlGetTupleName(ProcedureRelationId, tuple));
|
|
+
|
|
+ /* check domain transition, if necessary */
|
|
+ if (newcon != sepgsqlGetClientContext()) {
|
|
+ sepgsql_avc_permission(sepgsqlGetClientContext(),
|
|
+ newcon,
|
|
+ SECCLASS_PROCESS,
|
|
+ PROCESS__TRANSITION,
|
|
+ NULL);
|
|
+ }
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+}
|
|
+
|
|
+static List *__expandPgClassInheritance(List *selist, Oid relid, uint32 perms)
|
|
+{
|
|
+ List *child_list = find_inheritance_children(relid);
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, child_list) {
|
|
+ selist = __addEvalPgClass(selist, lfirst_oid(l), false, perms);
|
|
+ selist = __expandPgClassInheritance(selist, lfirst_oid(l), perms);
|
|
+ }
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+static List *__expandPgAttributeInheritance(List *selist, Oid relid, char *attname, uint32 perms)
|
|
+{
|
|
+ List *child_list = find_inheritance_children(relid);
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, child_list) {
|
|
+ Form_pg_attribute attrForm;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ if (!attname) {
|
|
+ /* attname == NULL means RECORD reference */
|
|
+ selist = __addEvalPgAttribute(selist, lfirst_oid(l), false, 0, perms);
|
|
+ selist = __expandPgAttributeInheritance(selist, lfirst_oid(l), NULL, perms);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ tuple = SearchSysCacheAttName(lfirst_oid(l), attname);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("relation %u does not have attribute %s",
|
|
+ lfirst_oid(l), attname);
|
|
+ attrForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+ selist = __addEvalPgAttribute(selist, lfirst_oid(l), false, attrForm->attnum, perms);
|
|
+ selist = __expandPgAttributeInheritance(selist, lfirst_oid(l), attname, perms);
|
|
+
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+
|
|
+ return selist;
|
|
+}
|
|
+
|
|
+static List *expandSEvalListInheritance(List *selist) {
|
|
+ List *result = NIL;
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, selist) {
|
|
+ SEvalItem *se = (SEvalItem *) lfirst(l);
|
|
+
|
|
+ result = lappend(result, se);
|
|
+ switch (se->tclass) {
|
|
+ case SECCLASS_DB_TABLE:
|
|
+ if (se->c.inh) {
|
|
+ se->c.inh = false;
|
|
+ result = __expandPgClassInheritance(result,
|
|
+ se->c.relid,
|
|
+ se->perms);
|
|
+ }
|
|
+ break;
|
|
+ case SECCLASS_DB_COLUMN:
|
|
+ if (se->a.inh) {
|
|
+ Form_pg_attribute attrForm;
|
|
+ HeapTuple tuple;
|
|
+
|
|
+ se->a.inh = false;
|
|
+ if (se->a.attno == 0) {
|
|
+ result = __expandPgAttributeInheritance(result,
|
|
+ se->a.relid,
|
|
+ NULL,
|
|
+ se->perms);
|
|
+ break;
|
|
+ }
|
|
+ tuple = SearchSysCache(ATTNUM,
|
|
+ ObjectIdGetDatum(se->a.relid),
|
|
+ Int16GetDatum(se->a.attno),
|
|
+ 0, 0);
|
|
+ if (!HeapTupleIsValid(tuple))
|
|
+ selerror("relation %u attribute %d not found", se->a.relid, se->a.attno);
|
|
+ attrForm = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
+
|
|
+ result = __expandPgAttributeInheritance(result,
|
|
+ se->a.relid,
|
|
+ NameStr(attrForm->attname),
|
|
+ se->perms);
|
|
+ ReleaseSysCache(tuple);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static void execVerifyQuery(List *selist)
|
|
+{
|
|
+ ListCell *l;
|
|
+
|
|
+ foreach (l, selist) {
|
|
+ SEvalItem *se = lfirst(l);
|
|
+
|
|
+ switch (se->tclass) {
|
|
+ case SECCLASS_DB_TABLE:
|
|
+ verifyPgClassPerms(se->c.relid, se->c.inh, se->perms);
|
|
+ break;
|
|
+ case SECCLASS_DB_COLUMN:
|
|
+ verifyPgAttributePerms(se->a.relid, se->a.inh, se->a.attno, se->perms);
|
|
+ break;
|
|
+ case SECCLASS_DB_PROCEDURE:
|
|
+ verifyPgProcPerms(se->p.funcid, se->perms);
|
|
+ break;
|
|
+ default:
|
|
+ selerror("unknown SEvalItem (tclass=%u)", se->tclass);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void sepgsqlVerifyQuery(Query *query)
|
|
+{
|
|
+ List *selist = copyObject(query->pgaceList);
|
|
+
|
|
+ /* expand table inheritances */
|
|
+ selist = expandSEvalListInheritance(selist);
|
|
+
|
|
+ /* add checks for access via trigger function */
|
|
+ if (query->resultRelation > 0) {
|
|
+ RangeTblEntry *rte = (RangeTblEntry *) list_nth(query->rtable,
|
|
+ query->resultRelation - 1);
|
|
+ Assert(IsA(rte, RangeTblEntry));
|
|
+ selist = addEvalTriggerAccess(selist, rte->relid, rte->inh, query->commandType);
|
|
+ }
|
|
+
|
|
+ execVerifyQuery(selist);
|
|
+}
|
|
+
|
|
+/* *******************************************************************************
|
|
+ * PGACE hooks: we cannon the following hooks in sepgsqlHooks.c because they
|
|
+ * refers static defined variables in sepgsqlProxy.c
|
|
+ * *******************************************************************************/
|
|
+
|
|
+/* ----------------------------------------------------------
|
|
+ * COPY TO/COPY FROM statement hooks
|
|
+ * ---------------------------------------------------------- */
|
|
+void sepgsqlCopyTable(Relation rel, List *attNumList, bool isFrom)
|
|
+{
|
|
+ List *selist = NIL;
|
|
+ ListCell *l;
|
|
+
|
|
+ /* on 'COPY FROM SELECT ...' cases, any checkings are done in select.c */
|
|
+ if (rel == NULL)
|
|
+ return;
|
|
+
|
|
+ /* no need to check non-table relation */
|
|
+ if (RelationGetForm(rel)->relkind != RELKIND_RELATION)
|
|
+ return;
|
|
+
|
|
+ selist = __addEvalPgClass(selist, RelationGetRelid(rel), false,
|
|
+ isFrom ? DB_TABLE__INSERT : DB_TABLE__SELECT);
|
|
+ foreach (l, attNumList) {
|
|
+ AttrNumber attnum = lfirst_int(l);
|
|
+
|
|
+ selist = __addEvalPgAttribute(selist, RelationGetRelid(rel), false, attnum,
|
|
+ isFrom ? DB_COLUMN__INSERT : DB_COLUMN__SELECT);
|
|
+ }
|
|
+
|
|
+ /* check call trigger function */
|
|
+ if (isFrom)
|
|
+ selist = addEvalTriggerAccess(selist, RelationGetRelid(rel), false, CMD_INSERT);
|
|
+
|
|
+ execVerifyQuery(selist);
|
|
+}
|
|
+
|
|
+bool sepgsqlCopyToTuple(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ return sepgsqlCheckTuplePerms(rel, tuple, NULL, DB_TUPLE__SELECT, false);
|
|
+}
|
|
+
|
|
+bool sepgsqlCopyFromTuple(Relation rel, HeapTuple tuple)
|
|
+{
|
|
+ Oid tcontext = HeapTupleGetSecurity(tuple);
|
|
+
|
|
+ if (tcontext == InvalidOid) {
|
|
+ /* implicit labeling */
|
|
+ tcontext = sepgsqlComputeImplicitContext(rel, tuple);
|
|
+ HeapTupleSetSecurity(tuple, tcontext);
|
|
+ }
|
|
+ return sepgsqlCheckTuplePerms(rel, tuple, NULL, DB_TUPLE__INSERT, false);
|
|
+}
|
|
+
|
|
+/* ----------------------------------------------------------
|
|
+ * node copy/print hooks
|
|
+ * ---------------------------------------------------------- */
|
|
+Node *sepgsqlCopyObject(Node *__oldnode) {
|
|
+ SEvalItem *oldnode, *newnode;
|
|
+
|
|
+ if (nodeTag(__oldnode) != T_SEvalItem)
|
|
+ return NULL;
|
|
+ oldnode = (SEvalItem *) __oldnode;
|
|
+
|
|
+ newnode = makeNode(SEvalItem);
|
|
+ newnode->tclass = oldnode->tclass;
|
|
+ newnode->perms = oldnode->perms;
|
|
+ switch (oldnode->tclass) {
|
|
+ case SECCLASS_DB_TABLE:
|
|
+ newnode->c.relid = oldnode->c.relid;
|
|
+ newnode->c.inh = oldnode->c.inh;
|
|
+ break;
|
|
+ case SECCLASS_DB_COLUMN:
|
|
+ newnode->a.relid = oldnode->a.relid;
|
|
+ newnode->a.attno = oldnode->a.attno;
|
|
+ newnode->a.inh = oldnode->a.inh;
|
|
+ break;
|
|
+ case SECCLASS_DB_PROCEDURE:
|
|
+ newnode->p.funcid = oldnode->p.funcid;
|
|
+ break;
|
|
+ default:
|
|
+ selerror("unrecognized SEvalItem node (tclass: %d)", oldnode->tclass);
|
|
+ break;
|
|
+ }
|
|
+ return (Node *) newnode;
|
|
+}
|
|
+
|
|
+bool sepgsqlOutObject(StringInfo str, Node *node) {
|
|
+ SEvalItem *seitem = (SEvalItem *) node;
|
|
+
|
|
+ if (nodeTag(node) != T_SEvalItem)
|
|
+ return false;
|
|
+
|
|
+ appendStringInfoString(str, "SEVALITEM");
|
|
+ appendStringInfo(str, ":tclass %u", seitem->tclass);
|
|
+ appendStringInfo(str, ":perms %u", seitem->perms);
|
|
+ switch(seitem->tclass) {
|
|
+ case SECCLASS_DB_TABLE:
|
|
+ appendStringInfo(str, ":c.relid %u", seitem->c.relid);
|
|
+ appendStringInfo(str, ":c.inh %s", seitem->c.inh ? "true" : "false");
|
|
+ break;
|
|
+ case SECCLASS_DB_COLUMN:
|
|
+ appendStringInfo(str, ":a.relid %u", seitem->c.relid);
|
|
+ appendStringInfo(str, ":a.inh %s", seitem->c.inh ? "true" : "false");
|
|
+ appendStringInfo(str, ":a.attno %u", seitem->c.inh);
|
|
+ break;
|
|
+ case SECCLASS_DB_PROCEDURE:
|
|
+ appendStringInfo(str, ":p.funcid %u", seitem->p.funcid);
|
|
+ break;
|
|
+ default:
|
|
+ selerror("unrecognized SEvalItem node (tclass: %d)", seitem->tclass);
|
|
+ break;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/* ----------------------------------------------------------
|
|
+ * special cases in foreign key constraint
|
|
+ * ---------------------------------------------------------- */
|
|
+Oid sepgsqlPreparePlanCheck(Relation rel) {
|
|
+ Oid pgace_saved = fnoid_sepgsql_tuple_perm;
|
|
+ fnoid_sepgsql_tuple_perm = F_SEPGSQL_TUPLE_PERMS_ABORT;
|
|
+ return pgace_saved;
|
|
+}
|
|
+
|
|
+void sepgsqlRestorePlanCheck(Relation rel, Oid pgace_saved) {
|
|
+ fnoid_sepgsql_tuple_perm = pgace_saved;
|
|
+}
|
|
diff -rpNU3 base/src/backend/storage/ipc/ipci.c sepgsql/src/backend/storage/ipc/ipci.c
|
|
--- base/src/backend/storage/ipc/ipci.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/storage/ipc/ipci.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -23,6 +23,7 @@
|
|
#include "pgstat.h"
|
|
#include "postmaster/bgwriter.h"
|
|
#include "postmaster/postmaster.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/freespace.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/pg_shmem.h"
|
|
@@ -113,6 +114,7 @@ CreateSharedMemoryAndSemaphores(bool mak
|
|
#ifdef EXEC_BACKEND
|
|
size = add_size(size, ShmemBackendArraySize());
|
|
#endif
|
|
+ size = add_size(size, pgaceShmemSize());
|
|
|
|
/* freeze the addin request size and include it */
|
|
addin_request_allowed = false;
|
|
diff -rpNU3 base/src/backend/storage/large_object/inv_api.c sepgsql/src/backend/storage/large_object/inv_api.c
|
|
--- base/src/backend/storage/large_object/inv_api.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/storage/large_object/inv_api.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -32,6 +32,7 @@
|
|
#include "catalog/pg_largeobject.h"
|
|
#include "commands/comment.h"
|
|
#include "libpq/libpq-fs.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/large_object.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/resowner.h"
|
|
@@ -131,6 +132,7 @@ myLargeObjectExists(Oid loid, Snapshot s
|
|
{
|
|
bool retval = false;
|
|
Relation pg_largeobject;
|
|
+ HeapTuple tuple;
|
|
ScanKeyData skey[1];
|
|
SysScanDesc sd;
|
|
|
|
@@ -147,8 +149,11 @@ myLargeObjectExists(Oid loid, Snapshot s
|
|
sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndexId, true,
|
|
snapshot, 1, skey);
|
|
|
|
- if (systable_getnext(sd) != NULL)
|
|
+ tuple = systable_getnext(sd);
|
|
+ if (HeapTupleIsValid(tuple)) {
|
|
+ pgaceLargeObjectOpen(pg_largeobject, tuple, !(snapshot == SnapshotNow));
|
|
retval = true;
|
|
+ }
|
|
|
|
systable_endscan(sd);
|
|
|
|
@@ -434,6 +439,8 @@ inv_read(LargeObjectDesc *obj_desc, char
|
|
bytea *datafield;
|
|
bool pfreeit;
|
|
|
|
+ pgaceLargeObjectRead(lo_heap_r, tuple);
|
|
+
|
|
data = (Form_pg_largeobject) GETSTRUCT(tuple);
|
|
|
|
/*
|
|
@@ -619,6 +626,8 @@ inv_write(LargeObjectDesc *obj_desc, con
|
|
replace[Anum_pg_largeobject_data - 1] = 'r';
|
|
newtup = heap_modifytuple(oldtuple, RelationGetDescr(lo_heap_r),
|
|
values, nulls, replace);
|
|
+
|
|
+ pgaceLargeObjectWrite(lo_heap_r, newtup, oldtuple);
|
|
simple_heap_update(lo_heap_r, &newtup->t_self, newtup);
|
|
CatalogIndexInsert(indstate, newtup);
|
|
heap_freetuple(newtup);
|
|
@@ -662,6 +671,7 @@ inv_write(LargeObjectDesc *obj_desc, con
|
|
values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
|
|
values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
|
|
newtup = heap_formtuple(lo_heap_r->rd_att, values, nulls);
|
|
+ pgaceLargeObjectWrite(lo_heap_r, newtup, NULL);
|
|
simple_heap_insert(lo_heap_r, newtup);
|
|
CatalogIndexInsert(indstate, newtup);
|
|
heap_freetuple(newtup);
|
|
diff -rpNU3 base/src/backend/tcop/fastpath.c sepgsql/src/backend/tcop/fastpath.c
|
|
--- base/src/backend/tcop/fastpath.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/tcop/fastpath.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -26,6 +26,7 @@
|
|
#include "libpq/pqformat.h"
|
|
#include "mb/pg_wchar.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "tcop/fastpath.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/acl.h"
|
|
@@ -353,6 +354,9 @@ HandleFunctionRequest(StringInfo msgBuf)
|
|
*/
|
|
InitFunctionCallInfoData(fcinfo, &fip->flinfo, 0, NULL, NULL);
|
|
|
|
+ /* PGACE: check procedure permission */
|
|
+ pgaceCallFunctionFastPath(fcinfo.flinfo);
|
|
+
|
|
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
|
|
rformat = parse_fcall_arguments(msgBuf, fip, &fcinfo);
|
|
else
|
|
diff -rpNU3 base/src/backend/tcop/postgres.c sepgsql/src/backend/tcop/postgres.c
|
|
--- base/src/backend/tcop/postgres.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/tcop/postgres.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -52,6 +52,7 @@
|
|
#include "parser/analyze.h"
|
|
#include "parser/parser.h"
|
|
#include "rewrite/rewriteHandler.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/freespace.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/proc.h"
|
|
@@ -607,8 +608,11 @@ pg_rewrite_queries(List *querytree_list)
|
|
|
|
if (querytree->commandType == CMD_UTILITY)
|
|
{
|
|
+ /* PGACE: utility query proxy */
|
|
+ List *tmp = pgaceProxyQuery(list_make1(querytree));
|
|
+
|
|
/* don't rewrite utilities, just dump 'em into new_list */
|
|
- new_list = lappend(new_list, querytree);
|
|
+ new_list = list_concat(new_list, tmp);
|
|
}
|
|
else
|
|
{
|
|
diff -rpNU3 base/src/backend/tcop/pquery.c sepgsql/src/backend/tcop/pquery.c
|
|
--- base/src/backend/tcop/pquery.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/tcop/pquery.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -19,6 +19,7 @@
|
|
#include "commands/prepare.h"
|
|
#include "commands/trigger.h"
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "tcop/pquery.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "tcop/utility.h"
|
|
@@ -352,6 +353,9 @@ PortalStart(Portal portal, ParamListInfo
|
|
AssertState(portal->queryContext != NULL); /* query defined? */
|
|
AssertState(portal->status == PORTAL_NEW); /* else extra PortalStart */
|
|
|
|
+ /* PGACE: verify query via PGACE subsystem */
|
|
+ pgacePortalStart(portal);
|
|
+
|
|
/*
|
|
* Set up global portal context pointers. (Should we set QueryContext?)
|
|
*/
|
|
diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/adt/ri_triggers.c
|
|
--- base/src/backend/utils/adt/ri_triggers.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/adt/ri_triggers.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -34,6 +34,7 @@
|
|
|
|
#include "commands/trigger.h"
|
|
#include "executor/spi_priv.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/lsyscache.h"
|
|
@@ -3009,6 +3010,7 @@ ri_PlanCheck(const char *querystr, int n
|
|
void *qplan;
|
|
Relation query_rel;
|
|
Oid save_uid;
|
|
+ Datum save_pgace;
|
|
|
|
/*
|
|
* The query is always run against the FK table except when this is an
|
|
@@ -3026,7 +3028,18 @@ ri_PlanCheck(const char *querystr, int n
|
|
SetUserId(RelationGetForm(query_rel)->relowner);
|
|
|
|
/* Create the plan */
|
|
- qplan = SPI_prepare(querystr, nargs, argtypes);
|
|
+ save_pgace = pgacePreparePlanCheck(query_rel);
|
|
+ PG_TRY();
|
|
+ {
|
|
+ qplan = SPI_prepare(querystr, nargs, argtypes);
|
|
+ }
|
|
+ PG_CATCH();
|
|
+ {
|
|
+ pgaceRestorePlanCheck(query_rel, save_pgace);
|
|
+ PG_RE_THROW();
|
|
+ }
|
|
+ PG_END_TRY();
|
|
+ pgaceRestorePlanCheck(query_rel, save_pgace);
|
|
|
|
if (qplan == NULL)
|
|
elog(ERROR, "SPI_prepare returned %d for %s", SPI_result, querystr);
|
|
diff -rpNU3 base/src/backend/utils/cache/syscache.c sepgsql/src/backend/utils/cache/syscache.c
|
|
--- base/src/backend/utils/cache/syscache.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/cache/syscache.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -37,6 +37,7 @@
|
|
#include "catalog/pg_operator.h"
|
|
#include "catalog/pg_proc.h"
|
|
#include "catalog/pg_rewrite.h"
|
|
+#include "catalog/pg_security.h"
|
|
#include "catalog/pg_statistic.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "utils/syscache.h"
|
|
@@ -513,7 +514,31 @@ static const struct cachedesc cacheinfo[
|
|
0
|
|
},
|
|
1024
|
|
- }
|
|
+ },
|
|
+ {SecurityRelationId, /* SECURITYOID */
|
|
+ SecurityOidIndexId,
|
|
+ 0,
|
|
+ 1,
|
|
+ {
|
|
+ ObjectIdAttributeNumber,
|
|
+ 0,
|
|
+ 0,
|
|
+ 0
|
|
+ },
|
|
+ 128
|
|
+ },
|
|
+ {SecurityRelationId, /* SECURITYLABEL */
|
|
+ SecuritySeclabelIndexId,
|
|
+ 0,
|
|
+ 1,
|
|
+ {
|
|
+ Anum_pg_security_seclabel,
|
|
+ 0,
|
|
+ 0,
|
|
+ 0
|
|
+ },
|
|
+ 128
|
|
+ },
|
|
};
|
|
|
|
static CatCache *SysCache[
|
|
diff -rpNU3 base/src/backend/utils/fmgr/dfmgr.c sepgsql/src/backend/utils/fmgr/dfmgr.c
|
|
--- base/src/backend/utils/fmgr/dfmgr.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/fmgr/dfmgr.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -22,6 +22,7 @@
|
|
#include "port/dynloader/win32.h"
|
|
#endif
|
|
#include "miscadmin.h"
|
|
+#include "security/pgace.h"
|
|
#include "utils/dynamic_loader.h"
|
|
#include "utils/hsearch.h"
|
|
|
|
@@ -73,7 +74,6 @@ char *Dynamic_library_path;
|
|
static void *internal_load_library(const char *libname);
|
|
static void internal_unload_library(const char *libname);
|
|
static bool file_exists(const char *name);
|
|
-static char *expand_dynamic_library_name(const char *name);
|
|
static void check_restricted_library_name(const char *name);
|
|
static char *substitute_libpath_macro(const char *name);
|
|
static char *find_in_dynamic_libpath(const char *basename);
|
|
@@ -106,6 +106,9 @@ load_external_function(char *filename, c
|
|
/* Expand the possibly-abbreviated filename to an exact path name */
|
|
fullname = expand_dynamic_library_name(filename);
|
|
|
|
+ /* PGACE: check whether the module can be loaded, or not */
|
|
+ pgaceLoadSharedModule(fullname);
|
|
+
|
|
/* Load the shared library, unless we already did */
|
|
lib_handle = internal_load_library(fullname);
|
|
|
|
@@ -146,6 +149,9 @@ load_file(const char *filename, bool res
|
|
/* Expand the possibly-abbreviated filename to an exact path name */
|
|
fullname = expand_dynamic_library_name(filename);
|
|
|
|
+ /* PGACE: check whether the module can be loaded, or not */
|
|
+ pgaceLoadSharedModule(fullname);
|
|
+
|
|
/* Unload the library if currently loaded */
|
|
internal_unload_library(fullname);
|
|
|
|
@@ -395,7 +401,7 @@ file_exists(const char *name)
|
|
*
|
|
* The result will always be freshly palloc'd.
|
|
*/
|
|
-static char *
|
|
+char *
|
|
expand_dynamic_library_name(const char *name)
|
|
{
|
|
bool have_slash;
|
|
diff -rpNU3 base/src/backend/utils/init/postinit.c sepgsql/src/backend/utils/init/postinit.c
|
|
--- base/src/backend/utils/init/postinit.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/init/postinit.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -30,6 +30,7 @@
|
|
#include "miscadmin.h"
|
|
#include "postmaster/autovacuum.h"
|
|
#include "postmaster/postmaster.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/backendid.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/ipc.h"
|
|
@@ -524,6 +525,9 @@ InitPostgres(const char *dbname, const c
|
|
if (!bootstrap)
|
|
pgstat_bestart();
|
|
|
|
+ /* PGACE: initialize access control extension facility */
|
|
+ pgaceInitialize();
|
|
+
|
|
/* close the transaction we started above */
|
|
if (!bootstrap)
|
|
CommitTransactionCommand();
|
|
diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc.c
|
|
--- base/src/backend/utils/misc/guc.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/backend/utils/misc/guc.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -51,6 +51,7 @@
|
|
#include "postmaster/bgwriter.h"
|
|
#include "postmaster/postmaster.h"
|
|
#include "postmaster/syslogger.h"
|
|
+#include "security/pgace.h"
|
|
#include "storage/fd.h"
|
|
#include "storage/freespace.h"
|
|
#include "tcop/tcopprot.h"
|
|
@@ -4567,6 +4568,9 @@ SetPGVariable(const char *name, List *ar
|
|
{
|
|
char *argstring = flatten_set_variable_args(name, args);
|
|
|
|
+ /* PGACE: check set param permission */
|
|
+ pgaceSetDatabaseParam(name, argstring);
|
|
+
|
|
/* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
|
|
set_config_option(name,
|
|
argstring,
|
|
@@ -4829,6 +4833,9 @@ EmitWarningsOnPlaceholders(const char *c
|
|
void
|
|
GetPGVariable(const char *name, DestReceiver *dest)
|
|
{
|
|
+ /* PGACE: check get param permission */
|
|
+ pgaceGetDatabaseParam(name);
|
|
+
|
|
if (pg_strcasecmp(name, "all") == 0)
|
|
ShowAllGUCConfig(dest);
|
|
else
|
|
@@ -4873,6 +4880,9 @@ GetPGVariableResultDesc(const char *name
|
|
void
|
|
ResetPGVariable(const char *name)
|
|
{
|
|
+ /* PGACE: check set param permission */
|
|
+ pgaceSetDatabaseParam(name, NULL);
|
|
+
|
|
if (pg_strcasecmp(name, "all") == 0)
|
|
ResetAllOptions();
|
|
else
|
|
diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c
|
|
--- base/src/bin/pg_dump/pg_dump.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/bin/pg_dump/pg_dump.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -119,6 +119,8 @@ static int g_numNamespaces;
|
|
/* flag to turn on/off dollar quoting */
|
|
static int disable_dollar_quoting = 0;
|
|
|
|
+/* flag to tuen on/off SE-PostgreSQL support */
|
|
+static int enable_selinux = 0;
|
|
|
|
static void help(const char *progname);
|
|
static void expand_schema_name_patterns(SimpleStringList *patterns,
|
|
@@ -261,6 +263,7 @@ main(int argc, char **argv)
|
|
{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
|
|
{"disable-triggers", no_argument, &disable_triggers, 1},
|
|
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
|
+ {"enable-selinux", no_argument, &enable_selinux, 1},
|
|
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
@@ -418,6 +421,8 @@ main(int argc, char **argv)
|
|
disable_triggers = 1;
|
|
else if (strcmp(optarg, "use-set-session-authorization") == 0)
|
|
use_setsessauth = 1;
|
|
+ else if (strcmp(optarg, "enable-selinux") == 0)
|
|
+ enable_selinux = 1;
|
|
else
|
|
{
|
|
fprintf(stderr,
|
|
@@ -474,6 +479,12 @@ main(int argc, char **argv)
|
|
exit(1);
|
|
}
|
|
|
|
+ /* If TableData dumped with security attribute, INSERT statement has to
|
|
+ * use explicit column list.
|
|
+ */
|
|
+ if (enable_selinux)
|
|
+ attrNames = true;
|
|
+
|
|
/* open the output file */
|
|
switch (format[0])
|
|
{
|
|
@@ -762,6 +773,7 @@ help(const char *progname)
|
|
printf(_(" --use-set-session-authorization\n"
|
|
" use SESSION AUTHORIZATION commands instead of\n"
|
|
" ALTER OWNER commands to set ownership\n"));
|
|
+ printf(_(" --enable-selinux enable to dump security context in SE-PostgreSQL\n"));
|
|
|
|
printf(_("\nConnection options:\n"));
|
|
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
|
|
@@ -1144,7 +1156,8 @@ dumpTableData_insert(Archive *fout, void
|
|
if (fout->remoteVersion >= 70100)
|
|
{
|
|
appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
|
|
- "SELECT * FROM ONLY %s",
|
|
+ "SELECT * %s FROM ONLY %s",
|
|
+ (!enable_selinux ? "" : ", security_context"),
|
|
fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
|
|
classname));
|
|
}
|
|
@@ -1757,11 +1770,33 @@ dumpBlobComments(Archive *AH, void *arg)
|
|
Oid blobOid;
|
|
char *comment;
|
|
|
|
+ blobOid = atooid(PQgetvalue(res, i, 0));
|
|
+
|
|
+ /* dump security context of binary large object */
|
|
+ if (enable_selinux) {
|
|
+ PGresult *__res;
|
|
+ char query[256];
|
|
+
|
|
+ snprintf(query, sizeof(query),
|
|
+ "SELECT lo_get_security(%u)", blobOid);
|
|
+ __res = PQexec(g_conn, query);
|
|
+ check_sql_result(__res, g_conn, query, PGRES_TUPLES_OK);
|
|
+
|
|
+ if (PQntuples(__res) != 1) {
|
|
+ write_msg(NULL, "lo_get_security(%u) returns %d tuples\n",
|
|
+ blobOid, PQntuples(__res));
|
|
+ exit_nicely();
|
|
+ }
|
|
+ archprintf(AH, "SELECT lo_set_security(%u, '%s');\n",
|
|
+ blobOid, PQgetvalue(__res, 0, 0));
|
|
+
|
|
+ PQclear(__res);
|
|
+ }
|
|
+
|
|
/* ignore blobs without comments */
|
|
if (PQgetisnull(res, i, 1))
|
|
continue;
|
|
|
|
- blobOid = atooid(PQgetvalue(res, i, 0));
|
|
comment = PQgetvalue(res, i, 1);
|
|
|
|
printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ",
|
|
@@ -2759,6 +2794,7 @@ getTables(int *numTables)
|
|
int i_owning_col;
|
|
int i_reltablespace;
|
|
int i_reloptions;
|
|
+ int i_selinux;
|
|
|
|
/* Make sure we are in proper schema */
|
|
selectSourceSchema("pg_catalog");
|
|
@@ -2791,6 +2827,7 @@ getTables(int *numTables)
|
|
*/
|
|
appendPQExpBuffer(query,
|
|
"SELECT c.tableoid, c.oid, relname, "
|
|
+ "%s" /* security context, if required */
|
|
"relacl, relkind, relnamespace, "
|
|
"(%s relowner) as rolname, "
|
|
"relchecks, reltriggers, "
|
|
@@ -2807,6 +2844,7 @@ getTables(int *numTables)
|
|
"d.refclassid = c.tableoid and d.deptype = 'a') "
|
|
"where relkind in ('%c', '%c', '%c', '%c') "
|
|
"order by c.oid",
|
|
+ (!enable_selinux ? "" : "c." SECURITY_SYSATTR_NAME ", "),
|
|
username_subquery,
|
|
RELKIND_SEQUENCE,
|
|
RELKIND_RELATION, RELKIND_SEQUENCE,
|
|
@@ -2974,6 +3012,7 @@ getTables(int *numTables)
|
|
i_owning_col = PQfnumber(res, "owning_col");
|
|
i_reltablespace = PQfnumber(res, "reltablespace");
|
|
i_reloptions = PQfnumber(res, "reloptions");
|
|
+ i_selinux = PQfnumber(res, "security_context");
|
|
|
|
for (i = 0; i < ntups; i++)
|
|
{
|
|
@@ -3004,6 +3043,9 @@ getTables(int *numTables)
|
|
}
|
|
tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
|
|
tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
|
|
+ tblinfo[i].relsecurity = NULL;
|
|
+ if (i_selinux >= 0)
|
|
+ tblinfo[i].relsecurity = strdup(PQgetvalue(res, i, i_selinux));
|
|
|
|
/* other fields were zeroed above */
|
|
|
|
@@ -4147,6 +4189,7 @@ getTableAttrs(TableInfo *tblinfo, int nu
|
|
int i_atthasdef;
|
|
int i_attisdropped;
|
|
int i_attislocal;
|
|
+ int i_attselinux;
|
|
PGresult *res;
|
|
int ntups;
|
|
bool hasdefaults;
|
|
@@ -4188,6 +4231,7 @@ getTableAttrs(TableInfo *tblinfo, int nu
|
|
{
|
|
/* need left join here to not fail on dropped columns ... */
|
|
appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, a.attstattarget, a.attstorage, t.typstorage, "
|
|
+ "%s" /* security context, if required */
|
|
"a.attnotnull, a.atthasdef, a.attisdropped, 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 "
|
|
@@ -4195,6 +4239,7 @@ getTableAttrs(TableInfo *tblinfo, int nu
|
|
"where a.attrelid = '%u'::pg_catalog.oid "
|
|
"and a.attnum > 0::pg_catalog.int2 "
|
|
"order by a.attrelid, a.attnum",
|
|
+ (!enable_selinux ? "" : "a.security_context, "),
|
|
tbinfo->dobj.catId.oid);
|
|
}
|
|
else if (g_fout->remoteVersion >= 70100)
|
|
@@ -4243,6 +4288,7 @@ getTableAttrs(TableInfo *tblinfo, int nu
|
|
i_atthasdef = PQfnumber(res, "atthasdef");
|
|
i_attisdropped = PQfnumber(res, "attisdropped");
|
|
i_attislocal = PQfnumber(res, "attislocal");
|
|
+ i_attselinux = PQfnumber(res, "security_context");
|
|
|
|
tbinfo->numatts = ntups;
|
|
tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
|
|
@@ -4253,6 +4299,7 @@ getTableAttrs(TableInfo *tblinfo, int nu
|
|
tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
|
|
tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
|
|
tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
|
|
+ tbinfo->attsecurity = (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));
|
|
@@ -4284,6 +4331,11 @@ getTableAttrs(TableInfo *tblinfo, int nu
|
|
tbinfo->inhAttrs[j] = false;
|
|
tbinfo->inhAttrDef[j] = false;
|
|
tbinfo->inhNotNull[j] = false;
|
|
+
|
|
+ /* security attribute, if defined */
|
|
+ tbinfo->attsecurity[j] = NULL;
|
|
+ if (i_attselinux >= 0 && !PQgetisnull(res, j, i_attselinux))
|
|
+ tbinfo->attsecurity[j] = strdup(PQgetvalue(res, j, i_attselinux));
|
|
}
|
|
|
|
PQclear(res);
|
|
@@ -5796,6 +5848,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
char *proisstrict;
|
|
char *prosecdef;
|
|
char *lanname;
|
|
+ char *proselinux = NULL;
|
|
char *rettypename;
|
|
int nallargs;
|
|
char **allargtypes = NULL;
|
|
@@ -5819,11 +5872,13 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
{
|
|
appendPQExpBuffer(query,
|
|
"SELECT proretset, prosrc, probin, "
|
|
+ "%s" /* security context, if required */
|
|
"proallargtypes, proargmodes, proargnames, "
|
|
"provolatile, proisstrict, prosecdef, "
|
|
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
|
"FROM pg_catalog.pg_proc "
|
|
"WHERE oid = '%u'::pg_catalog.oid",
|
|
+ (!enable_selinux ? "" : SECURITY_SYSATTR_NAME ", "),
|
|
finfo->dobj.catId.oid);
|
|
}
|
|
else if (g_fout->remoteVersion >= 80000)
|
|
@@ -5905,6 +5960,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
|
|
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
|
|
lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
|
|
+ if (enable_selinux) {
|
|
+ int i_selinux = PQfnumber(res, "security_context");
|
|
+
|
|
+ if (i_selinux >= 0 && !PQgetisnull(res, 0, i_selinux))
|
|
+ proselinux = PQgetvalue(res, 0, i_selinux);
|
|
+ }
|
|
|
|
/*
|
|
* See backend/commands/define.c for details of how the 'AS' clause is
|
|
@@ -6030,6 +6091,9 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|
if (prosecdef[0] == 't')
|
|
appendPQExpBuffer(q, " SECURITY DEFINER");
|
|
|
|
+ if (proselinux)
|
|
+ appendPQExpBuffer(q, " CONTEXT = '%s'", proselinux);
|
|
+
|
|
appendPQExpBuffer(q, ";\n");
|
|
|
|
ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
|
|
@@ -7362,6 +7426,9 @@ dumpTableSchema(Archive *fout, TableInfo
|
|
if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
|
|
appendPQExpBuffer(q, " NOT NULL");
|
|
|
|
+ if (enable_selinux && tbinfo->attsecurity[j])
|
|
+ appendPQExpBuffer(q, " CONTEXT = '%s'", tbinfo->attsecurity[j]);
|
|
+
|
|
actual_atts++;
|
|
}
|
|
}
|
|
@@ -7409,6 +7476,9 @@ dumpTableSchema(Archive *fout, TableInfo
|
|
if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
|
|
appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions);
|
|
|
|
+ if (enable_selinux && tbinfo->relsecurity)
|
|
+ appendPQExpBuffer(q, " CONTEXT = '%s'", tbinfo->relsecurity);
|
|
+
|
|
appendPQExpBuffer(q, ";\n");
|
|
|
|
/* Loop dumping statistics and storage statements */
|
|
@@ -8783,6 +8853,12 @@ fmtCopyColumnList(const TableInfo *ti)
|
|
|
|
appendPQExpBuffer(q, "(");
|
|
needComma = false;
|
|
+
|
|
+ if (enable_selinux) {
|
|
+ appendPQExpBuffer(q, "security_context");
|
|
+ needComma = true;
|
|
+ }
|
|
+
|
|
for (i = 0; i < numatts; i++)
|
|
{
|
|
if (attisdropped[i])
|
|
diff -rpNU3 base/src/bin/pg_dump/pg_dump.h sepgsql/src/bin/pg_dump/pg_dump.h
|
|
--- base/src/bin/pg_dump/pg_dump.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/bin/pg_dump/pg_dump.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -227,6 +227,7 @@ typedef struct _tableInfo
|
|
char relkind;
|
|
char *reltablespace; /* relation tablespace */
|
|
char *reloptions; /* options specified by WITH (...) */
|
|
+ char *relsecurity; /* security attribute of the relation */
|
|
bool hasindex; /* does it have any indexes? */
|
|
bool hasrules; /* does it have any rules? */
|
|
bool hasoids; /* does it have OIDs? */
|
|
@@ -251,6 +252,7 @@ typedef struct _tableInfo
|
|
char *typstorage; /* type storage scheme */
|
|
bool *attisdropped; /* true if attr is dropped; don't dump it */
|
|
bool *attislocal; /* true if attr has local definition */
|
|
+ char **attsecurity; /* security attribute of attribute (column) */
|
|
|
|
/*
|
|
* Note: we need to store per-attribute notnull, default, and constraint
|
|
diff -rpNU3 base/src/bin/pg_dump/pg_dumpall.c sepgsql/src/bin/pg_dump/pg_dumpall.c
|
|
--- base/src/bin/pg_dump/pg_dumpall.c 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/bin/pg_dump/pg_dumpall.c 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -68,6 +68,9 @@ static int disable_triggers = 0;
|
|
static int use_setsessauth = 0;
|
|
static int server_version;
|
|
|
|
+/* flag to tuen on/off SE-PostgreSQL support */
|
|
+static int enable_selinux = 0;
|
|
+
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
@@ -111,6 +114,7 @@ main(int argc, char *argv[])
|
|
{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
|
|
{"disable-triggers", no_argument, &disable_triggers, 1},
|
|
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
|
+ {"enable-selinux", no_argument, NULL, 1001},
|
|
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
@@ -260,6 +264,10 @@ main(int argc, char *argv[])
|
|
appendPQExpBuffer(pgdumpopts, " --disable-triggers");
|
|
else if (strcmp(optarg, "use-set-session-authorization") == 0)
|
|
/* no-op, still allowed for compatibility */ ;
|
|
+ else if (strcmp(optarg, "enable-selinux") == 0) {
|
|
+ appendPQExpBuffer(pgdumpopts, " --enable-selinux");
|
|
+ enable_selinux = 1;
|
|
+ }
|
|
else
|
|
{
|
|
fprintf(stderr,
|
|
@@ -270,6 +278,11 @@ main(int argc, char *argv[])
|
|
}
|
|
break;
|
|
|
|
+ case 1001:
|
|
+ appendPQExpBuffer(pgdumpopts, " --enable-selinux");
|
|
+ enable_selinux = 1;
|
|
+ break;
|
|
+
|
|
case 0:
|
|
break;
|
|
|
|
@@ -393,6 +406,7 @@ help(void)
|
|
printf(_(" --use-set-session-authorization\n"
|
|
" use SESSION AUTHORIZATION commands instead of\n"
|
|
" OWNER TO commands\n"));
|
|
+ printf(_(" --enable-selinux enable to dump security attribute\n"));
|
|
|
|
printf(_("\nConnection options:\n"));
|
|
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
|
|
@@ -802,16 +816,18 @@ dumpCreateDB(PGconn *conn)
|
|
printf("--\n-- Database creation\n--\n\n");
|
|
|
|
if (server_version >= 80100)
|
|
- res = executeQuery(conn,
|
|
+ appendPQExpBuffer(buf,
|
|
"SELECT datname, "
|
|
"coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
"datistemplate, datacl, datconnlimit, "
|
|
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
|
|
+ "%s" /* security context, if required */
|
|
"FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
|
|
- "WHERE datallowconn ORDER BY 1");
|
|
+ "WHERE datallowconn ORDER BY 1",
|
|
+ (!enable_selinux ? "" : ", d.security_context "));
|
|
else if (server_version >= 80000)
|
|
- res = executeQuery(conn,
|
|
+ appendPQExpBuffer(buf,
|
|
"SELECT datname, "
|
|
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
@@ -820,7 +836,7 @@ dumpCreateDB(PGconn *conn)
|
|
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
|
|
"WHERE datallowconn ORDER BY 1");
|
|
else if (server_version >= 70300)
|
|
- res = executeQuery(conn,
|
|
+ appendPQExpBuffer(buf,
|
|
"SELECT datname, "
|
|
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
@@ -829,7 +845,7 @@ dumpCreateDB(PGconn *conn)
|
|
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
|
|
"WHERE datallowconn ORDER BY 1");
|
|
else if (server_version >= 70100)
|
|
- res = executeQuery(conn,
|
|
+ appendPQExpBuffer(buf,
|
|
"SELECT datname, "
|
|
"coalesce("
|
|
"(select usename from pg_shadow where usesysid=datdba), "
|
|
@@ -845,7 +861,7 @@ dumpCreateDB(PGconn *conn)
|
|
* Note: 7.0 fails to cope with sub-select in COALESCE, so just deal
|
|
* with getting a NULL by not printing any OWNER clause.
|
|
*/
|
|
- res = executeQuery(conn,
|
|
+ appendPQExpBuffer(buf,
|
|
"SELECT datname, "
|
|
"(select usename from pg_shadow where usesysid=datdba), "
|
|
"pg_encoding_to_char(d.encoding), "
|
|
@@ -855,6 +871,7 @@ dumpCreateDB(PGconn *conn)
|
|
"FROM pg_database d "
|
|
"ORDER BY 1");
|
|
}
|
|
+ res = executeQuery(conn, buf->data);
|
|
|
|
for (i = 0; i < PQntuples(res); i++)
|
|
{
|
|
@@ -865,6 +882,7 @@ dumpCreateDB(PGconn *conn)
|
|
char *dbacl = PQgetvalue(res, i, 4);
|
|
char *dbconnlimit = PQgetvalue(res, i, 5);
|
|
char *dbtablespace = PQgetvalue(res, i, 6);
|
|
+ char *dbsecurity = PQgetvalue(res, i, 7);
|
|
char *fdbname;
|
|
|
|
fdbname = strdup(fmtId(dbname));
|
|
@@ -908,6 +926,9 @@ dumpCreateDB(PGconn *conn)
|
|
appendPQExpBuffer(buf, " CONNECTION LIMIT = %s",
|
|
dbconnlimit);
|
|
|
|
+ if (enable_selinux && dbsecurity)
|
|
+ appendPQExpBuffer(buf, " CONTEXT = '%s'", dbsecurity);
|
|
+
|
|
appendPQExpBuffer(buf, ";\n");
|
|
|
|
if (strcmp(dbistemplate, "t") == 0)
|
|
diff -rpNU3 base/src/include/access/htup.h sepgsql/src/include/access/htup.h
|
|
--- base/src/include/access/htup.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/access/htup.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -137,6 +137,9 @@ typedef struct HeapTupleHeaderData
|
|
|
|
ItemPointerData t_ctid; /* current TID of this or newer tuple */
|
|
|
|
+ /* PGAVE: security attribute of the tuple */
|
|
+ Oid t_security;
|
|
+
|
|
/* Fields below here must match MinimalTupleData! */
|
|
|
|
int16 t_natts; /* number of attributes */
|
|
@@ -297,6 +300,14 @@ do { \
|
|
*((Oid *) ((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) = (oid); \
|
|
} while (0)
|
|
|
|
+#define HeapTupleHeaderGetSecurity(htup) \
|
|
+ ((htup)->t_security)
|
|
+#define HeapTupleHeaderSetSecurity(htup, sid) \
|
|
+ ((htup)->t_security = (sid))
|
|
+#define HeapTupleGetSecurity(tuple) \
|
|
+ HeapTupleHeaderGetSecurity((tuple)->t_data)
|
|
+#define HeapTupleSetSecurity(tuple, sid) \
|
|
+ HeapTupleHeaderSetSecurity((tuple)->t_data, sid)
|
|
|
|
/*
|
|
* BITMAPLEN(NATTS) -
|
|
@@ -349,8 +360,12 @@ do { \
|
|
#define MaxTransactionIdAttributeNumber (-5)
|
|
#define MaxCommandIdAttributeNumber (-6)
|
|
#define TableOidAttributeNumber (-7)
|
|
+#ifdef SECURITY_SYSATTR_NAME
|
|
+#define SecurityAttributeNumber (-8)
|
|
+#define FirstLowInvalidHeapAttributeNumber (-9)
|
|
+#else
|
|
#define FirstLowInvalidHeapAttributeNumber (-8)
|
|
-
|
|
+#endif
|
|
|
|
/*
|
|
* MinimalTuple is an alternate representation that is used for transient
|
|
@@ -552,6 +567,7 @@ typedef struct xl_heap_delete
|
|
*/
|
|
typedef struct xl_heap_header
|
|
{
|
|
+ Oid t_security;
|
|
int16 t_natts;
|
|
uint16 t_infomask;
|
|
uint8 t_hoff;
|
|
diff -rpNU3 base/src/include/catalog/heap.h sepgsql/src/include/catalog/heap.h
|
|
--- base/src/include/catalog/heap.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/heap.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -52,7 +52,8 @@ extern Oid heap_create_with_catalog(cons
|
|
int oidinhcount,
|
|
OnCommitAction oncommit,
|
|
Datum reloptions,
|
|
- bool allow_system_table_mods);
|
|
+ bool allow_system_table_mods,
|
|
+ List *pgace_attr_list);
|
|
|
|
extern void heap_drop_with_catalog(Oid relid);
|
|
|
|
@@ -65,7 +66,8 @@ extern List *heap_truncate_find_FKs(List
|
|
extern void InsertPgClassTuple(Relation pg_class_desc,
|
|
Relation new_rel_desc,
|
|
Oid new_rel_oid,
|
|
- Datum reloptions);
|
|
+ Datum reloptions,
|
|
+ List *pgace_attr_list);
|
|
|
|
extern List *AddRelationRawConstraints(Relation rel,
|
|
List *rawColDefaults,
|
|
diff -rpNU3 base/src/include/catalog/indexing.h sepgsql/src/include/catalog/indexing.h
|
|
--- base/src/include/catalog/indexing.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/indexing.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -218,6 +218,11 @@ DECLARE_UNIQUE_INDEX(pg_type_oid_index,
|
|
DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index, 2704, on pg_type using btree(typname name_ops, typnamespace oid_ops));
|
|
#define TypeNameNspIndexId 2704
|
|
|
|
+DECLARE_UNIQUE_INDEX(pg_security_oid_index, 3401, on pg_security using btree(oid oid_ops));
|
|
+#define SecurityOidIndexId 3401
|
|
+DECLARE_UNIQUE_INDEX(pg_security_seclabel_index, 3402, on pg_security using btree(seclabel text_ops));
|
|
+#define SecuritySeclabelIndexId 3402
|
|
+
|
|
/* last step of initialization script: build the indexes declared above */
|
|
BUILD_INDICES
|
|
|
|
diff -rpNU3 base/src/include/catalog/pg_attribute.h sepgsql/src/include/catalog/pg_attribute.h
|
|
--- base/src/include/catalog/pg_attribute.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/pg_attribute.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -276,6 +276,7 @@ DATA(insert ( 1247 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1247 SECURITY_SYSATTR_NAME 3403 0 4 -8 0 -1 -1 t p i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_proc
|
|
@@ -326,6 +327,7 @@ DATA(insert ( 1255 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1255 SECURITY_SYSATTR_NAME 3403 0 4 -8 0 -1 -1 t p i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_attribute
|
|
@@ -374,6 +376,7 @@ DATA(insert ( 1249 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1249 SECURITY_SYSATTR_NAME 3403 0 4 -8 0 -1 -1 t p i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_class
|
|
@@ -442,6 +445,7 @@ DATA(insert ( 1259 cmin 29 0 4 -4 0
|
|
DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
|
|
DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|
+DATA(insert ( 1259 SECURITY_SYSATTR_NAME 3403 0 4 -8 0 -1 -1 t p i t f f t 0));
|
|
|
|
/* ----------------
|
|
* pg_index
|
|
diff -rpNU3 base/src/include/catalog/pg_cast.h sepgsql/src/include/catalog/pg_cast.h
|
|
--- base/src/include/catalog/pg_cast.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/pg_cast.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -392,4 +392,10 @@ DATA(insert ( 1560 1560 1685 i ));
|
|
DATA(insert ( 1562 1562 1687 i ));
|
|
DATA(insert ( 1700 1700 1703 i ));
|
|
|
|
+/*
|
|
+ * Security Context functions
|
|
+ */
|
|
+DATA(insert (25 3403 3408 i));
|
|
+DATA(insert (3403 25 3409 i));
|
|
+
|
|
#endif /* PG_CAST_H */
|
|
diff -rpNU3 base/src/include/catalog/pg_proc.h sepgsql/src/include/catalog/pg_proc.h
|
|
--- base/src/include/catalog/pg_proc.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/pg_proc.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -3974,6 +3974,22 @@ DESCR("release shared advisory lock");
|
|
DATA(insert OID = 2892 ( pg_advisory_unlock_all PGNSP PGUID 12 f f t f v 0 2278 "" _null_ _null_ _null_ pg_advisory_unlock_all - _null_ ));
|
|
DESCR("release all advisory locks");
|
|
|
|
+/* PostgreSQL Access Control Extension related functions */
|
|
+DATA(insert OID = 3404 ( security_label_in PGNSP PGUID 12 f f t f i 1 3403 "2275" _null_ _null_ _null_ security_label_in - _null_ ));
|
|
+DATA(insert OID = 3405 ( security_label_out PGNSP PGUID 12 f f t f i 1 2275 "3403" _null_ _null_ _null_ security_label_out - _null_ ));
|
|
+DATA(insert OID = 3406 ( security_label_raw_in PGNSP PGUID 12 f f t f i 1 3403 "2275" _null_ _null_ _null_ security_label_raw_in - _null_ ));
|
|
+DATA(insert OID = 3407 ( security_label_raw_out PGNSP PGUID 12 f f t f i 1 2275 "3403" _null_ _null_ _null_ security_label_raw_out - _null_ ));
|
|
+DATA(insert OID = 3408 ( text_to_security_label PGNSP PGUID 12 f f t f i 1 3403 "25" _null_ _null_ _null_ text_to_security_label - _null_ ));
|
|
+DATA(insert OID = 3409 ( security_label_to_text PGNSP PGUID 12 f f t f i 1 25 "3403" _null_ _null_ _null_ security_label_to_text - _null_ ));
|
|
+DATA(insert OID = 3410 ( lo_get_security PGNSP PGUID 12 f f t f v 1 3403 "26" _null_ _null_ _null_ lo_get_security - _null_ ));
|
|
+DATA(insert OID = 3411 ( lo_set_security PGNSP PGUID 12 f f t f v 2 16 "26 3403" _null_ _null_ _null_ lo_set_security - _null_ ));
|
|
+
|
|
+/* SE-PostgreSQL related functions */
|
|
+DATA(insert OID = 3420 ( sepgsql_getcon PGNSP PGUID 12 f f t f v 0 3403 "" _null_ _null_ _null_ sepgsql_getcon - _null_ ));
|
|
+DATA(insert OID = 3421 ( sepgsql_tuple_perms PGNSP PGUID 12 f f t f v 4 16 "26 3403 23 2249" _null_ _null_ _null_ sepgsql_tuple_perms - _null_ ));
|
|
+DATA(insert OID = 3422 ( sepgsql_tuple_perms_abort PGNSP PGUID 12 f f t f v 4 16 "26 3403 23 2249" _null_ _null_ _null_ sepgsql_tuple_perms_abort - _null_ ));
|
|
+
|
|
+
|
|
/*
|
|
* Symbolic values for provolatile column: these indicate whether the result
|
|
* of a function is dependent *only* on the values of its explicit arguments,
|
|
@@ -4015,7 +4031,8 @@ extern Oid ProcedureCreate(const char *p
|
|
oidvector *parameterTypes,
|
|
Datum allParameterTypes,
|
|
Datum parameterModes,
|
|
- Datum parameterNames);
|
|
+ Datum parameterNames,
|
|
+ void *pgace_item);
|
|
|
|
extern bool function_parse_error_transpose(const char *prosrc);
|
|
|
|
diff -rpNU3 base/src/include/catalog/pg_security.h sepgsql/src/include/catalog/pg_security.h
|
|
--- base/src/include/catalog/pg_security.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/pg_security.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -0,0 +1,31 @@
|
|
+/*
|
|
+ * src/include/catalog/pg_security.h
|
|
+ * Definition of the security label relation (pg_security)
|
|
+ *
|
|
+ * Copyright (c) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+ */
|
|
+#ifndef PG_SECURITY_H
|
|
+#define PG_SECURITY_H
|
|
+
|
|
+#define SecurityRelationId 3400
|
|
+
|
|
+CATALOG(pg_security,3400) BKI_SHARED_RELATION
|
|
+{
|
|
+ text seclabel; /* text representation of security label */
|
|
+} FormData_pg_security;
|
|
+
|
|
+/* ----------------
|
|
+ * Form_pg_security corresponds to a pointer to a tuple with
|
|
+ * the format of pg_security relation.
|
|
+ * ----------------
|
|
+ */
|
|
+typedef FormData_pg_security *Form_pg_security;
|
|
+
|
|
+/* ----------------
|
|
+ * compiler constants for pg_selinux
|
|
+ * ----------------
|
|
+ */
|
|
+#define Natts_pg_security 1
|
|
+#define Anum_pg_security_seclabel 1
|
|
+
|
|
+#endif /* PG_SELINUX_H */
|
|
diff -rpNU3 base/src/include/catalog/pg_type.h sepgsql/src/include/catalog/pg_type.h
|
|
--- base/src/include/catalog/pg_type.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/catalog/pg_type.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -548,6 +548,9 @@ DATA(insert OID = 2282 ( opaque PGNSP
|
|
#define OPAQUEOID 2282
|
|
DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p t \054 0 0 anyelement_in anyelement_out - - - i p f 0 -1 0 _null_ _null_ ));
|
|
#define ANYELEMENTOID 2283
|
|
+DATA(insert OID = 3403 ( security_label PGNSP PGUID 4 t b t \054 0 0 security_label_in security_label_out - - - i p f 0 -1 0 _null_ _null_ ));
|
|
+DESCR("Security Label Identifier for PGACE");
|
|
+#define SECLABELOID 3403
|
|
|
|
/*
|
|
* prototypes for functions in pg_type.c
|
|
diff -rpNU3 base/src/include/executor/tuptable.h sepgsql/src/include/executor/tuptable.h
|
|
--- base/src/include/executor/tuptable.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/executor/tuptable.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -118,6 +118,7 @@ typedef struct TupleTableSlot
|
|
MinimalTuple tts_mintuple; /* set if it's a minimal tuple, else NULL */
|
|
HeapTupleData tts_minhdr; /* workspace if it's a minimal tuple */
|
|
long tts_off; /* saved state for slot_deform_tuple */
|
|
+ Oid tts_security; /* PGACE: security attribute explicitly specified */
|
|
} TupleTableSlot;
|
|
|
|
/*
|
|
@@ -139,6 +140,16 @@ typedef TupleTableData *TupleTable;
|
|
#define TupIsNull(slot) \
|
|
((slot) == NULL || (slot)->tts_isempty)
|
|
|
|
+/*
|
|
+ * HeapTupleStoreSecurityFromSlot
|
|
+ */
|
|
+#ifdef HAVE_SELINUX
|
|
+#define HeapTupleStoreSecurityFromSlot(tuple, slot) \
|
|
+ HeapTupleSetSecurity((tuple), (slot)->tts_security)
|
|
+#else
|
|
+#define HeapTupleStoreSecurityFromSlot(tuple, slot)
|
|
+#endif
|
|
+
|
|
/* in executor/execTuples.c */
|
|
extern TupleTable ExecCreateTupleTable(int tableSize);
|
|
extern void ExecDropTupleTable(TupleTable table, bool shouldFree);
|
|
diff -rpNU3 base/src/include/fmgr.h sepgsql/src/include/fmgr.h
|
|
--- base/src/include/fmgr.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/fmgr.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -52,6 +52,9 @@ typedef struct FmgrInfo
|
|
void *fn_extra; /* extra space for use by handler */
|
|
MemoryContext fn_mcxt; /* memory context to store fn_extra in */
|
|
fmNodePtr fn_expr; /* expression parse tree for call, or NULL */
|
|
+
|
|
+ PGFunction fn_pgace_addr; /* PGACE opaque addr field */
|
|
+ Datum fn_pgace_data; /* PGACE opaque data field */
|
|
} FmgrInfo;
|
|
|
|
/*
|
|
@@ -486,6 +489,7 @@ extern Oid get_call_expr_argtype(fmNodeP
|
|
*/
|
|
extern char *Dynamic_library_path;
|
|
|
|
+extern char *expand_dynamic_library_name(const char *name);
|
|
extern PGFunction load_external_function(char *filename, char *funcname,
|
|
bool signalNotFound, void **filehandle);
|
|
extern PGFunction lookup_external_function(void *filehandle, char *funcname);
|
|
diff -rpNU3 base/src/include/libpq/be-fsstubs.h sepgsql/src/include/libpq/be-fsstubs.h
|
|
--- base/src/include/libpq/be-fsstubs.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/libpq/be-fsstubs.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -35,6 +35,9 @@ extern Datum lo_lseek(PG_FUNCTION_ARGS);
|
|
extern Datum lo_tell(PG_FUNCTION_ARGS);
|
|
extern Datum lo_unlink(PG_FUNCTION_ARGS);
|
|
|
|
+extern Datum lo_get_security(PG_FUNCTION_ARGS);
|
|
+extern Datum lo_set_security(PG_FUNCTION_ARGS);
|
|
+
|
|
/*
|
|
* These are not fmgr-callable, but are available to C code.
|
|
* Probably these should have had the underscore-free names,
|
|
diff -rpNU3 base/src/include/nodes/parsenodes.h sepgsql/src/include/nodes/parsenodes.h
|
|
--- base/src/include/nodes/parsenodes.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/nodes/parsenodes.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -145,6 +145,9 @@ typedef struct Query
|
|
* plan node, not in the Query.
|
|
*/
|
|
List *returningLists; /* list of lists of TargetEntry, or NIL */
|
|
+
|
|
+ /* PGACE: opaque list for PGACE */
|
|
+ List *pgaceList;
|
|
} Query;
|
|
|
|
|
|
@@ -405,6 +408,7 @@ typedef struct ColumnDef
|
|
Node *raw_default; /* default value (untransformed parse tree) */
|
|
char *cooked_default; /* nodeToString representation */
|
|
List *constraints; /* other constraints on column */
|
|
+ Node *pgace_item; /* security attribute used by PGACE */
|
|
} ColumnDef;
|
|
|
|
/*
|
|
@@ -906,7 +910,8 @@ typedef enum AlterTableType
|
|
AT_EnableTrigUser, /* ENABLE TRIGGER USER */
|
|
AT_DisableTrigUser, /* DISABLE TRIGGER USER */
|
|
AT_AddInherit, /* INHERIT parent */
|
|
- AT_DropInherit /* NO INHERIT parent */
|
|
+ AT_DropInherit, /* NO INHERIT parent */
|
|
+ AT_SetSecurityLabel, /* SET SECURITY LABEL (via PGACE) */
|
|
} AlterTableType;
|
|
|
|
typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
|
|
@@ -1062,6 +1067,7 @@ typedef struct CreateStmt
|
|
List *options; /* options from WITH clause */
|
|
OnCommitAction oncommit; /* what do we do at COMMIT? */
|
|
char *tablespacename; /* table space to use, or NULL */
|
|
+ Node *pgace_item; /* security attribute used by PGACE */
|
|
} CreateStmt;
|
|
|
|
/* ----------
|
|
diff -rpNU3 base/src/include/pg_config.h.in sepgsql/src/include/pg_config.h.in
|
|
--- base/src/include/pg_config.h.in 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/pg_config.h.in 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -340,6 +340,9 @@
|
|
/* Define to 1 if you have the <security/pam_appl.h> header file. */
|
|
#undef HAVE_SECURITY_PAM_APPL_H
|
|
|
|
+/* Define to 1 if you enable NSA SELinux support */
|
|
+#undef HAVE_SELINUX
|
|
+
|
|
/* Define to 1 if you have the `setproctitle' function. */
|
|
#undef HAVE_SETPROCTITLE
|
|
|
|
@@ -598,6 +601,9 @@
|
|
your system. */
|
|
#undef PTHREAD_CREATE_JOINABLE
|
|
|
|
+/* The name of security attribute. */
|
|
+#undef SECURITY_SYSATTR_NAME
|
|
+
|
|
/* The size of a `size_t', as computed by sizeof. */
|
|
#undef SIZEOF_SIZE_T
|
|
|
|
diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace.h
|
|
--- base/src/include/security/pgace.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/include/security/pgace.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -0,0 +1,643 @@
|
|
+/*
|
|
+ * include/security/pgace.h
|
|
+ * headers for PostgreSQL Access Control Extensions (PGACE)
|
|
+ * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+ */
|
|
+#ifndef PGACE_H
|
|
+#define PGACE_H
|
|
+
|
|
+#include "access/htup.h"
|
|
+#include "commands/trigger.h"
|
|
+#include "lib/stringinfo.h"
|
|
+#include "nodes/execnodes.h"
|
|
+#include "nodes/parsenodes.h"
|
|
+#include "storage/itemptr.h"
|
|
+#include "storage/large_object.h"
|
|
+#include "tcop/dest.h"
|
|
+#include "utils/rel.h"
|
|
+
|
|
+/*
|
|
+ * SECURITY_SYSATTR_NAME is the name of system column name
|
|
+ * for security attribute, defined in pg_config.h
|
|
+ * If it is not defined, security attribute support is disabled
|
|
+ *
|
|
+ * see, src/include/pg_config.h
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_SELINUX
|
|
+#include "security/sepgsql.h"
|
|
+// the following line will be fixed by Sun's people
|
|
+// #elifdef HAVE_SOLARISTX
|
|
+// #include "security/solaristx.h"
|
|
+#else
|
|
+
|
|
+/******************************************************************
|
|
+ * Initialize / Finalize related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceShmemSize() have to return the size of shared memory segment
|
|
+ * required by PGACE implementation. If no shared memory segment needed,
|
|
+ * it should return 0.
|
|
+ */
|
|
+static inline Size pgaceShmemSize(void) {
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceInitialize() is called when a new PostgreSQL instance is generated.
|
|
+ * A PGACE implementation can initialize itself.
|
|
+ */
|
|
+static inline void pgaceInitialize(void) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceInitializePostmaster() is called when a postmaster server process
|
|
+ * is started up. If it returns false, the server starting up process
|
|
+ * will be aborted.
|
|
+ */
|
|
+static inline bool pgaceInitializePostmaster(void) {
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceFinalizePostmaster() is called when a postmaster server process
|
|
+ * is just ending up.
|
|
+ */
|
|
+static inline void pgaceFinalizePostmaster(void) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * SQL proxy hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceProxyQuery() is called just after query rewrite phase.
|
|
+ * PGACE implementation can modify the query trees in this hook,
|
|
+ * if necessary.
|
|
+ *
|
|
+ * @queryList : a list of Query typed objects.
|
|
+ */
|
|
+static inline List *pgaceProxyQuery(List *queryList) {
|
|
+ return queryList;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgacePortalStart() is called on the top of PortalStart().
|
|
+ *
|
|
+ * @portal : a Portal object currently executed.
|
|
+ */
|
|
+static inline void pgacePortalStart(Portal portal) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceExecutorStart() is called on the top of ExecutorStart().
|
|
+ *
|
|
+ * @queryDesc : a QueryDesc object given to ExecutorStart().
|
|
+ * @eflags : eflags valus given to ExecutorStart().
|
|
+ * if EXEC_FLAG_EXPLAIN_ONLY is set, no real access will run.
|
|
+ */
|
|
+static inline void pgaceExecutorStart(QueryDesc *queryDesc, int eflags) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * HeapTuple modification hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceExecInsert() is called when a client tries to insert a new tuple
|
|
+ * via explicit INSERT statement from ExecInsert() at execMain.c
|
|
+ * If it returns false, insertion of the tuple will be cancelled.
|
|
+ *
|
|
+ * @rel : the target relation of INSERT
|
|
+ * @tuple : the contains of the inserted tuple
|
|
+ * @with_returning : true, if the query has RETURNING clause
|
|
+ */
|
|
+static inline bool pgaceExecInsert(Relation rel, HeapTuple tuple, bool with_returning) {
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceExecUpdate() is called when clients tries to update a tuple
|
|
+ * via explicit UPDATE statement from ExecUpdate() at execMain.c
|
|
+ * If it returns false, updating the tuple will be cancelled.
|
|
+ *
|
|
+ * @rel : the target relation of UPDATE
|
|
+ * @newtup : the new contains of the updated tuple
|
|
+ * @tid : ItemPointer of the tuple updated
|
|
+ * @with_returning : true, if the query has RETURNING clause
|
|
+ */
|
|
+static inline bool pgaceExecUpdate(Relation rel, HeapTuple newtup, ItemPointer tid, bool with_returning) {
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceExecUpdate() is called when clients tries to delete a tuple
|
|
+ * via explicit DELETE statement from ExecDelete() at execMain.c
|
|
+ * If it returns false, deletion of the tuple will be cancelled.
|
|
+ *
|
|
+ * @rel : the target relation of DELETE
|
|
+ * @tid : ItemPointer of the tuple deleted
|
|
+ * @with_returning : true, if the query has RETURNING clause
|
|
+ */
|
|
+static inline bool pgaceExecDelete(Relation rel, ItemPointer tid, bool with_returning) {
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceSimpleHeapInsert() is called just before simple_heap_insert() is processed
|
|
+ *
|
|
+ * @rel : the target relation of simple_heap_insert()
|
|
+ * @tuple : the contains of the inserted tuple
|
|
+ */
|
|
+static inline void pgaceSimpleHeapInsert(Relation rel, HeapTuple tuple) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceSimpleHeapUpdate() is called just before simple_heap_update() is processed
|
|
+ *
|
|
+ * @rel : the target relation of simple_heap_update()
|
|
+ * @tid : ItemPointer of the tuple updated
|
|
+ * @tuple : the new contains of the updated tuple
|
|
+ */
|
|
+static inline void pgaceSimpleHeapUpdate(Relation rel, ItemPointer tid, HeapTuple tuple) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceSimpleHeapDelete() is called just before simple_heap_delete() is processed
|
|
+ *
|
|
+ * @rel : the target relation of simple_heap_delete()
|
|
+ * @tid : ItemPointer of the tuple deleted
|
|
+ */
|
|
+static inline void pgaceSimpleHeapDelete(Relation rel, ItemPointer tid) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceHeapInsert() is called from heap_insert()
|
|
+ *
|
|
+ * @rel : the target relation of heap_insert()
|
|
+ * @tuple : the contains of the inserted tuples. It also contains system attribute like Oid
|
|
+ */
|
|
+static inline void pgaceHeapInsert(Relation rel, HeapTuple tuple) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceHeapUpdate() is called from heap_update()
|
|
+ *
|
|
+ * @rel : the target relation of heap_update()
|
|
+ * @newtup : the contains of the updated tuples. It also contains system attribute like Oid
|
|
+ * @oldtup : the tuple which will be updated
|
|
+ */
|
|
+static inline void pgaceHeapUpdate(Relation rel, HeapTuple newtup, HeapTuple oldtup) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceHeapDelete() is called from heap_delete()
|
|
+ *
|
|
+ * @rel : the target relation of heap_delete()
|
|
+ * @oldtup : the tuple which will be deleted
|
|
+ */
|
|
+static inline void pgaceHeapDelete(Relation rel, HeapTuple oldtup) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Extended SQL statement hooks
|
|
+ ******************************************************************/
|
|
+/*
|
|
+ * PGACE implementation can use pgaceGramSecurityLabel() hook to extend
|
|
+ * SQL statement for explicit labeling. This hook is deployed on parser/gram.y
|
|
+ * as a part of the SQL grammer. If no SQL extension is necessary, it has to
|
|
+ * return NULL to cause yyerror().
|
|
+ *
|
|
+ * @defname : given <parameter> string
|
|
+ * @value : given <value> string
|
|
+ */
|
|
+static inline DefElem *pgaceGramSecurityLabel(char *defname, char *value) {
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * PGACE implementation has to return true, if the given DefElem holds
|
|
+ * security label generated in pgaceGramSecurityLabel(). false, if any other.
|
|
+ *
|
|
+ * @defel : given DefElem object
|
|
+ */
|
|
+static inline bool pgaceNodeIsSecurityLabel(DefElem *defel) {
|
|
+ return false;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * PGACE implementation has to translate DefElem object generated by
|
|
+ * pgaceGramSecurityLabel(), into t_security of HeapTupleHeader.
|
|
+ *
|
|
+ * @defel : given DefElem object
|
|
+ */
|
|
+static inline Oid pgaceParseSecurityLabel(DefElem *defel) {
|
|
+ return InvalidOid;
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * DATABASE related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceSetDatabaseParam() is called when clients tries to set GUC variables
|
|
+ *
|
|
+ * @name : The name of GUC variable
|
|
+ * @argstr : The new valus of GUC variable. If argstr is NULL, it means
|
|
+ * clients tries to reset the variable.
|
|
+ */
|
|
+static inline void pgaceSetDatabaseParam(const char *name, char *argstring) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceGetDatabaseParam() is called when clients tries to refer GUC variables
|
|
+ *
|
|
+ * @name : The name of GUC variable
|
|
+ */
|
|
+static inline void pgaceGetDatabaseParam(const char *name) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * FUNCTION related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceCallFunction() is called just before executing SQL function
|
|
+ * as a part of query.
|
|
+ *
|
|
+ * @finfo : FmgrInfo object for the target function
|
|
+ */
|
|
+static inline void pgaceCallFunction(FmgrInfo *finfo) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceCallFunctionTrigger() is called just before executing
|
|
+ * trigger function.
|
|
+ * If it returns false, the trigger function will not be called and caller
|
|
+ * receives NULL tuple as a result. In the case when Before-Row triggers,
|
|
+ * it means the current operations on the tuple should be skipped.
|
|
+ *
|
|
+ * @finfo : FmgrInfo object for the target function
|
|
+ * @tgdata : TriggerData object for the current trigger invokation
|
|
+ */
|
|
+static inline bool pgaceCallFunctionTrigger(FmgrInfo *finfo, TriggerData *tgdata) {
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceCallFunctionFastPath() is called just before executing
|
|
+ * SQL function in the fast path.
|
|
+ *
|
|
+ * @finfo : FmgrInfo object for the target function
|
|
+ */
|
|
+static inline void pgaceCallFunctionFastPath(FmgrInfo *finfo) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgacePreparePlanCheck() is called before foreign key/primary key constraint checks,
|
|
+ * at ri_PlanCheck(). PGACE implementation can return its opaque data for any purpose.
|
|
+ *
|
|
+ * @rel : the target relation in which a constraint is configured
|
|
+ */
|
|
+static inline Datum pgacePreparePlanCheck(Relation rel) {
|
|
+ return (Datum) 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceRestorePlanCheck() is called after foreign key/primary key constraint checks,
|
|
+ * at ri_PlanCheck(). PGACE implementation can use an opaque data generated in the above
|
|
+ * pgacePreparePlanCheck().
|
|
+ *
|
|
+ * @rel : the target relation in which a constraint is configured
|
|
+ * @pgace_saved : an opaque data returned from pgacePreparePlanCheck()
|
|
+ */
|
|
+static inline void pgaceRestorePlanCheck(Relation rel, Datum pgace_saved) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * TABLE related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceLockTable() is called when explicit LOCK statement used.
|
|
+ *
|
|
+ * @relid : the target relation id
|
|
+ */
|
|
+static inline void pgaceLockTable(Oid relid) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceAlterTable() is called to modify table/column. The PGACE implementation
|
|
+ * have to update the target tuples within pg_class or pg_attribute.
|
|
+ * If AlterTableCmd tag is unexpected one,
|
|
+ *
|
|
+ * @rel : the target relation
|
|
+ * @cmd : AlterTableCmd object
|
|
+ */
|
|
+static inline bool pgaceAlterTable(Relation rel, AlterTableCmd *cmd) {
|
|
+ return false;
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * COPY TO/COPY FROM statement hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceCopyTable() is called when COPY TO/COPY FROM statement is processed
|
|
+ *
|
|
+ * @rel : the target relation
|
|
+ * @attNumList : the list of attribute numbers
|
|
+ * @isFrom : true, if the given statement is 'COPY FROM'
|
|
+ */
|
|
+static inline void pgaceCopyTable(Relation rel, List *attNumList, bool isFrom) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceCopyToTuple() is called to check whether the given tuple should be
|
|
+ * filtered, or not in the process of COPY TO statement.
|
|
+ * If it returns false, the given tuple will be filtered from the result set
|
|
+ *
|
|
+ * @rel : the target relation
|
|
+ * @tuple : the target tuple
|
|
+ */
|
|
+static inline bool pgaceCopyToTuple(Relation rel, HeapTuple tuple) {
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceCopyFromTuple() is called to check whether the given tuple should be
|
|
+ * filtered, or not in the process of COPY FROM statement.
|
|
+ * If it returns false, the given tuple will be filtered from the result set
|
|
+ *
|
|
+ * @rel : the target relation
|
|
+ * @tuple : the target tuple
|
|
+ */
|
|
+static inline bool pgaceCopyFromTuple(Relation rel, HeapTuple tuple) {
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Loadable shared library module hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceLoadSharedModule() is called just before load a shared library
|
|
+ * module.
|
|
+ *
|
|
+ * @filename : full path name of the shared library module
|
|
+ */
|
|
+static inline void pgaceLoadSharedModule(const char *filename) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Binary Large Object (BLOB) hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectGetSecurity() is called when lo_get_security() is executed
|
|
+ * It returns it's security attribute.
|
|
+ *
|
|
+ * @tuple : a tuple which is a part of the target largeobject.
|
|
+ */
|
|
+static inline Oid pgaceLargeObjectGetSecurity(HeapTuple tuple) {
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INTERNAL_ERROR),
|
|
+ errmsg("There is no security attribute support.")));
|
|
+ return InvalidOid;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectSetSecurity() is called when lo_set_security() is executed
|
|
+ *
|
|
+ * @tuple : a tuple which is a part of the target largeobject.
|
|
+ * @lo_security : new security attribute specified
|
|
+ * @is_first : true, if it's the first call in the largeobject.
|
|
+ * Because a largeobject may contain some tuples, this hook
|
|
+ * may be called several times for a single largeobject.
|
|
+ */
|
|
+static inline void pgaceLargeObjectSetSecurity(HeapTuple tuple, Oid lo_security, bool is_first) {
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INTERNAL_ERROR),
|
|
+ errmsg("There is no security attribute support.")));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectCreate() is called when a new large object is created
|
|
+ *
|
|
+ * @rel : pg_largeobject relation opened with RowExclusiveLock
|
|
+ * @tuple : a new tuple for the new large object
|
|
+ */
|
|
+static inline void pgaceLargeObjectCreate(Relation rel, HeapTuple tuple) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectDrop() is called when a large object is dropped once for
|
|
+ * a large object
|
|
+ *
|
|
+ * @rel : pg_largeobject relation opened with RowExclusiveLock
|
|
+ * @tuple : one of the tuples within the target large object
|
|
+ */
|
|
+static inline void pgaceLargeObjectDrop(Relation rel, HeapTuple tuple) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectOpen() is called when a large object is opened
|
|
+ *
|
|
+ * @rel : pg_largeobject relation opened with RowExclusiveLock
|
|
+ * @tuple : head of the tuples within the target large object
|
|
+ * @read_only : true, if large object is opened as read only mode
|
|
+ */
|
|
+static inline void pgaceLargeObjectOpen(Relation rel, HeapTuple tuple, bool read_only) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectRead is called when they read from a large object
|
|
+ *
|
|
+ * @rel : pg_largeobject relation opened with AccessShareLock
|
|
+ * @tuple : a tuple within the target large object
|
|
+ */
|
|
+static inline void pgaceLargeObjectRead(Relation rel, HeapTuple tuple) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectWrite() is called when they write to a large object
|
|
+ *
|
|
+ * @rel : pg_largeobject relation opened with RowExclusiveLock
|
|
+ * @newtup : a new tuple within the target large object
|
|
+ * @oldtup : a original tuple within the target large object, if exist
|
|
+ */
|
|
+static inline void pgaceLargeObjectWrite(Relation rel, HeapTuple newtup, HeapTuple oldtup) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectImport() is called when lo_import() is processed
|
|
+ */
|
|
+static inline void pgaceLargeObjectImport(void) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceLargeObjectExport() is called when lo_import() is processed
|
|
+ */
|
|
+static inline void pgaceLargeObjectExport(void) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Security Label hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * PGACE implementation can use pgaceSecurityLabelIn() hook to translate
|
|
+ * a input security label from external representation into internal one.
|
|
+ * If no translation is necessary, it has to return @seclabel as is.
|
|
+ *
|
|
+ * @seclabel : security label being input
|
|
+ */
|
|
+static inline char *pgaceSecurityLabelIn(char *seclabel) {
|
|
+ return seclabel;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * PGACE implementation can use pgaceSecurityLabelOut() hook to translate
|
|
+ * a security label in internal representation into external one.
|
|
+ * If no translation is necessary, it has to return @seclabel as is.
|
|
+ *
|
|
+ * @seclabel : security label being output
|
|
+ */
|
|
+static inline char *pgaceSecurityLabelOut(char *seclabel) {
|
|
+ return seclabel;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceSecurityLabelIsValid() checks whether the @seclabel is valid or not.
|
|
+ * return false, if @seclabel is not valid security attribute in text representation.
|
|
+ *
|
|
+ * @seclabel : security attribute in text representation
|
|
+ */
|
|
+static inline bool pgaceSecurityLabelIsValid(char *seclabel) {
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceSecurityLabelOfLabel() returns the security attribute of a newly
|
|
+ * generated tuple within pg_security
|
|
+ *
|
|
+ * @new_label : a text representation of security context which will be newly
|
|
+ * inserted into pg_security.
|
|
+ */
|
|
+static inline char *pgaceSecurityLabelOfLabel(char *new_label) {
|
|
+ return pstrdup("unlabeled");
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceSecurityLabelNotFound() has to return a string representation of security
|
|
+ * attribute, when no tuple with oid equals to @sid is within pg_security system
|
|
+ * catalog.
|
|
+ *
|
|
+ * @sid : required sid, but not found on pg_security
|
|
+ */
|
|
+static inline char *pgaceSecurityLabelNotFound(Oid sid) {
|
|
+ return pstrdup("unlabeled");
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Extended node type hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+/*
|
|
+ * If PGACE implementation requires new node type, a method to copy object.
|
|
+ * pgaceCopyObject() provides a hook to copy new node typed object.
|
|
+ * If a given object (@orig) has a tag extended by PGACE implementation,
|
|
+ * it have to copy and return it.
|
|
+ * If it returns NULL, @orig is not available for the PGACE implementation.
|
|
+ *
|
|
+ * @orig : a object which to copy
|
|
+ */
|
|
+static inline Node *pgaceCopyObject(Node *orig) {
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pgaceOutObject() provides a hook to translate a object to text representation.
|
|
+ * If a given object (@node) has a tag extended by PGACE implementation, it have
|
|
+ * to put a text representation into StringInfo.
|
|
+ * If it returns false, @node is not available for the PGACE implementation.
|
|
+ *
|
|
+ * @str : StringInfo which to put the text representation
|
|
+ * @node : a object that text representation is required
|
|
+ */
|
|
+static inline bool pgaceOutObject(StringInfo str, Node *node) {
|
|
+ return false;
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+/* writable system column support */
|
|
+#ifdef SECURITY_SYSATTR_NAME
|
|
+static inline bool pgaceWritableSystemColumn(int attrno) {
|
|
+ return ((attrno == SecurityAttributeNumber) ? true : false);
|
|
+}
|
|
+extern void pgaceTransformSelectStmt(List *targetList);
|
|
+extern void pgaceTransformInsertStmt(List **p_icolumns, List **p_attrnos, List *targetList);
|
|
+extern void pgaceFetchSecurityLabel(JunkFilter *junkfilter, TupleTableSlot *slot, Oid *tts_security);
|
|
+#else
|
|
+static inline bool pgaceWritableSystemColumn(int attrno) {
|
|
+ return false;
|
|
+}
|
|
+static inline void pgaceTransformSelectStmt(List *targetList) { /* do nothing */ }
|
|
+static inline void pgaceTransformInsertStmt(List **p_icolumns,
|
|
+ List **p_attrnos,
|
|
+ List *targetList) { /* do nothing */ }
|
|
+static inline void pgaceFetchSecurityLabel(JunkFilter *junkfilter,
|
|
+ TupleTableSlot *slot,
|
|
+ Oid *tts_security) { /* do nothing */ }
|
|
+#endif
|
|
+
|
|
+/* Extended SQL statements related */
|
|
+extern List *pgaceBuildAttrListForRelation(CreateStmt *stmt);
|
|
+extern void pgaceCreateRelationCommon(Relation rel, HeapTuple tuple, List *pgace_attr_list);
|
|
+extern void pgaceCreateAttributeCommon(Relation rel, HeapTuple tuple, List *pgace_attr_list);
|
|
+extern void pgaceAlterRelationCommon(Relation rel, AlterTableCmd *cmd);
|
|
+extern void pgaceCreateDatabaseCommon(HeapTuple tuple, DefElem *defel);
|
|
+extern void pgaceAlterDatabaseCommon(HeapTuple tuple, DefElem *defel);
|
|
+extern void pgaceCreateFunctionCommon(HeapTuple tuple, DefElem *defel);
|
|
+extern void pgaceAlterFunctionCommon(HeapTuple tuple, DefElem *defel);
|
|
+
|
|
+/* SQL functions related to security label */
|
|
+extern Datum security_label_in(PG_FUNCTION_ARGS);
|
|
+extern Datum security_label_out(PG_FUNCTION_ARGS);
|
|
+extern Datum security_label_raw_in(PG_FUNCTION_ARGS);
|
|
+extern Datum security_label_raw_out(PG_FUNCTION_ARGS);
|
|
+extern Datum text_to_security_label(PG_FUNCTION_ARGS);
|
|
+extern Datum security_label_to_text(PG_FUNCTION_ARGS);
|
|
+
|
|
+/* SQL functions related to large object */
|
|
+extern Datum lo_get_security(PG_FUNCTION_ARGS);
|
|
+extern Datum lo_set_security(PG_FUNCTION_ARGS);
|
|
+
|
|
+#endif // PGACE_H
|
|
diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sepgsql.h
|
|
--- base/src/include/security/sepgsql.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/include/security/sepgsql.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -0,0 +1,330 @@
|
|
+/*
|
|
+ * src/include/sepgsql.h
|
|
+ * The header file of Security Enhanced PostgreSQL
|
|
+ *
|
|
+ * Copyright (c) 2006 - 2007, KaiGai Kohei <kaigai@kaigai.gr.jp>
|
|
+ */
|
|
+#ifndef SEPGSQL_H
|
|
+#define SEPGSQL_H
|
|
+#include "executor/executor.h"
|
|
+#include "security/sepgsql_internal.h"
|
|
+#include "utils/portal.h"
|
|
+
|
|
+#define SECURITY_SYSATTR_NAME "security_context"
|
|
+
|
|
+/******************************************************************
|
|
+ * Initialize / Finalize related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+static inline Size pgaceShmemSize(void) {
|
|
+ Size retval = 0;
|
|
+ if (sepgsqlIsEnabled())
|
|
+ retval = sepgsqlShmemSize();
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+static inline void pgaceInitialize(void) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlInitialize();
|
|
+}
|
|
+
|
|
+static inline bool pgaceInitializePostmaster(void) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+ return sepgsqlInitializePostmaster();
|
|
+}
|
|
+
|
|
+static inline void pgaceFinalizePostmaster(void) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return;
|
|
+ sepgsqlFinalizePostmaster();
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * SQL proxy hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+static inline List *pgaceProxyQuery(List *queryList) {
|
|
+ List *newList = NIL;
|
|
+ ListCell *l;
|
|
+
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return queryList;
|
|
+ foreach (l, queryList) {
|
|
+ Query *query = (Query *) lfirst(l);
|
|
+
|
|
+ newList = list_concat(newList, sepgsqlProxyQuery(query));
|
|
+ }
|
|
+ return newList;
|
|
+}
|
|
+
|
|
+static inline void pgacePortalStart(Portal portal) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+static inline void pgaceExecutorStart(QueryDesc *queryDesc, int eflags) {
|
|
+ if (!sepgsqlIsEnabled() || (eflags & EXEC_FLAG_EXPLAIN_ONLY))
|
|
+ return;
|
|
+
|
|
+ Assert(queryDesc->parsetree != NULL);
|
|
+ sepgsqlVerifyQuery(queryDesc->parsetree);
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * HeapTuple modification hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+static inline bool pgaceExecInsert(Relation rel, HeapTuple tuple, bool with_returning) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+ return sepgsqlExecInsert(rel, tuple, with_returning);
|
|
+}
|
|
+
|
|
+static inline bool pgaceExecUpdate(Relation rel, HeapTuple newtup, ItemPointer tid, bool with_returning) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+ return sepgsqlExecUpdate(rel, newtup, tid, with_returning);
|
|
+}
|
|
+
|
|
+static inline bool pgaceExecDelete(Relation rel, ItemPointer tid, bool with_returning) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+ return sepgsqlExecDelete(rel, tid, with_returning);
|
|
+}
|
|
+
|
|
+static inline void pgaceSimpleHeapInsert(Relation rel, HeapTuple tuple) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlSimpleHeapInsert(rel, tuple);
|
|
+}
|
|
+
|
|
+static inline void pgaceSimpleHeapUpdate(Relation rel, ItemPointer tid, HeapTuple tuple) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlSimpleHeapUpdate(rel, tid, tuple);
|
|
+}
|
|
+
|
|
+static inline void pgaceSimpleHeapDelete(Relation rel, ItemPointer tid) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlSimpleHeapDelete(rel, tid);
|
|
+}
|
|
+
|
|
+static inline void pgaceHeapInsert(Relation rel, HeapTuple tuple) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlHeapInsert(rel, tuple);
|
|
+}
|
|
+
|
|
+static inline void pgaceHeapUpdate(Relation rel, HeapTuple newtup, HeapTuple oldtup) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlHeapUpdate(rel, newtup, oldtup);
|
|
+}
|
|
+
|
|
+static inline void pgaceHeapDelete(Relation rel, HeapTuple oldtup) {
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Extended SQL statement hooks
|
|
+ ******************************************************************/
|
|
+static inline DefElem *pgaceGramSecurityLabel(char *defname, char *value) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return NULL;
|
|
+ return sepgsqlGramSecurityLabel(defname, value);
|
|
+}
|
|
+
|
|
+static inline bool pgaceNodeIsSecurityLabel(DefElem *defel) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return false;
|
|
+ return sepgsqlNodeIsSecurityLabel(defel);
|
|
+}
|
|
+
|
|
+static inline Oid pgaceParseSecurityLabel(DefElem *defel) {
|
|
+ if (sepgsqlIsEnabled() && defel)
|
|
+ return sepgsqlParseSecurityLabel(defel);
|
|
+ return InvalidOid;
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * DATABASE related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+static inline void pgaceSetDatabaseParam(const char *name, char *argstring) {
|
|
+ /* argstring == NULL means set default */
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlSetDatabaseParam(name, argstring);
|
|
+}
|
|
+
|
|
+static inline void pgaceGetDatabaseParam(const char *name) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlGetDatabaseParam(name);
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * FUNCTION related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+static inline void pgaceCallFunction(FmgrInfo *finfo) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlCallFunction(finfo, false);
|
|
+}
|
|
+
|
|
+static inline bool pgaceCallFunctionTrigger(FmgrInfo *finfo, TriggerData *tgdata) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+ return sepgsqlCallFunctionTrigger(finfo, tgdata);
|
|
+}
|
|
+
|
|
+static inline void pgaceCallFunctionFastPath(FmgrInfo *finfo) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlCallFunction(finfo, true);
|
|
+}
|
|
+
|
|
+static inline Datum pgacePreparePlanCheck(Relation rel) {
|
|
+ Oid pgace_saved = InvalidOid;
|
|
+ if (sepgsqlIsEnabled())
|
|
+ pgace_saved = sepgsqlPreparePlanCheck(rel);
|
|
+ return ObjectIdGetDatum(pgace_saved);
|
|
+}
|
|
+
|
|
+static inline void pgaceRestorePlanCheck(Relation rel, Datum pgace_saved) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlRestorePlanCheck(rel, DatumGetObjectId(pgace_saved));
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * TABLE related hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+static inline void pgaceLockTable(Oid relid) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLockTable(relid);
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * COPY TO/COPY FROM statement hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+static inline void pgaceCopyTable(Relation rel, List *attNumList, bool isFrom) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlCopyTable(rel, attNumList, isFrom);
|
|
+}
|
|
+
|
|
+static inline bool pgaceCopyToTuple(Relation rel, HeapTuple tuple) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+ return sepgsqlCopyToTuple(rel, tuple);
|
|
+}
|
|
+
|
|
+static inline bool pgaceCopyFromTuple(Relation rel, HeapTuple tuple) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return true;
|
|
+ return sepgsqlCopyFromTuple(rel, tuple);
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Loadable shared library module hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+static inline void pgaceLoadSharedModule(const char *filename) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLoadSharedModule(filename);
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Binary Large Object (BLOB) hooks
|
|
+ ******************************************************************/
|
|
+static inline Oid pgaceLargeObjectGetSecurity(HeapTuple tuple) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ selerror("SELinux is disabled");
|
|
+ return sepgsqlLargeObjectGetSecurity(tuple);
|
|
+}
|
|
+
|
|
+static inline void pgaceLargeObjectSetSecurity(HeapTuple tuple, Oid lo_security, bool is_first) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectSetSecurity(tuple, lo_security, is_first);
|
|
+}
|
|
+
|
|
+static inline void pgaceLargeObjectCreate(Relation rel, HeapTuple tuple) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectCreate(rel, tuple);
|
|
+}
|
|
+
|
|
+static inline void pgaceLargeObjectDrop(Relation rel, HeapTuple tuple) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectDrop(rel, tuple);
|
|
+}
|
|
+
|
|
+static inline void pgaceLargeObjectOpen(Relation rel, HeapTuple tuple, bool read_only) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectOpen(rel, tuple, read_only);
|
|
+}
|
|
+
|
|
+static inline void pgaceLargeObjectRead(Relation rel, HeapTuple tuple) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectRead(rel, tuple);
|
|
+}
|
|
+
|
|
+static inline void pgaceLargeObjectWrite(Relation rel, HeapTuple newtup, HeapTuple oldtup) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectWrite(rel, newtup, oldtup);
|
|
+}
|
|
+
|
|
+static inline void pgaceLargeObjectImport(void) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectImport();
|
|
+}
|
|
+
|
|
+static inline void pgaceLargeObjectExport(void) {
|
|
+ if (sepgsqlIsEnabled())
|
|
+ sepgsqlLargeObjectExport();
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Security Label hooks
|
|
+ ******************************************************************/
|
|
+static inline char *pgaceSecurityLabelIn(char *context) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return NULL;
|
|
+ return sepgsqlSecurityLabelIn(context);
|
|
+}
|
|
+
|
|
+static inline char *pgaceSecurityLabelOut(char *context) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return NULL;
|
|
+ return sepgsqlSecurityLabelOut(context);
|
|
+}
|
|
+
|
|
+static inline bool pgaceSecurityLabelIsValid(char *context) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return false;
|
|
+ return sepgsqlSecurityLabelIsValid(context);
|
|
+}
|
|
+
|
|
+static inline char *pgaceSecurityLabelOfLabel(char *new_label) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return pstrdup("unlabeled");
|
|
+ return sepgsqlSecurityLabelOfLabel(new_label);
|
|
+}
|
|
+
|
|
+static inline char *pgaceSecurityLabelNotFound(Oid sid) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return pstrdup("unlabeled");
|
|
+
|
|
+ return sepgsqlSecurityLabelNotFound(sid);
|
|
+}
|
|
+
|
|
+/******************************************************************
|
|
+ * Extended node type hooks
|
|
+ ******************************************************************/
|
|
+
|
|
+static inline Node *pgaceCopyObject(Node *orig) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return NULL;
|
|
+ return sepgsqlCopyObject(orig);
|
|
+}
|
|
+
|
|
+static inline bool pgaceOutObject(StringInfo str, Node *node) {
|
|
+ if (!sepgsqlIsEnabled())
|
|
+ return false;
|
|
+ return sepgsqlOutObject(str, node);
|
|
+}
|
|
+
|
|
+#endif /* SEPGSQL_H */
|
|
diff -rpNU3 base/src/include/security/sepgsql_internal.h sepgsql/src/include/security/sepgsql_internal.h
|
|
--- base/src/include/security/sepgsql_internal.h 1970-01-01 09:00:00.000000000 +0900
|
|
+++ sepgsql/src/include/security/sepgsql_internal.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -0,0 +1,273 @@
|
|
+#ifndef SEPGSQL_INTERNAL_H
|
|
+#define SEPGSQL_INTERNAL_H
|
|
+
|
|
+/* system catalogs */
|
|
+#include "catalog/catalog.h"
|
|
+#include "catalog/indexing.h"
|
|
+#include "catalog/pg_aggregate.h"
|
|
+#include "catalog/pg_am.h"
|
|
+#include "catalog/pg_attribute.h"
|
|
+#include "catalog/pg_authid.h"
|
|
+#include "catalog/pg_cast.h"
|
|
+#include "catalog/pg_class.h"
|
|
+#include "catalog/pg_constraint.h"
|
|
+#include "catalog/pg_conversion.h"
|
|
+#include "catalog/pg_database.h"
|
|
+#include "catalog/pg_language.h"
|
|
+#include "catalog/pg_largeobject.h"
|
|
+#include "catalog/pg_listener.h"
|
|
+#include "catalog/pg_namespace.h"
|
|
+#include "catalog/pg_opclass.h"
|
|
+#include "catalog/pg_operator.h"
|
|
+#include "catalog/pg_pltemplate.h"
|
|
+#include "catalog/pg_proc.h"
|
|
+#include "catalog/pg_rewrite.h"
|
|
+#include "catalog/pg_security.h"
|
|
+#include "catalog/pg_tablespace.h"
|
|
+#include "catalog/pg_trigger.h"
|
|
+#include "catalog/pg_type.h"
|
|
+#include "lib/stringinfo.h"
|
|
+#include "nodes/nodes.h"
|
|
+#include "storage/large_object.h"
|
|
+
|
|
+#include <selinux/selinux.h>
|
|
+#include <selinux/flask.h>
|
|
+#include <selinux/av_permissions.h>
|
|
+
|
|
+#define selerror(fmt, ...) \
|
|
+ ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), \
|
|
+ errmsg("%s(%d): " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)))
|
|
+#define selnotice(fmt, ...) \
|
|
+ ereport(NOTICE, (errcode(ERRCODE_WARNING), \
|
|
+ errmsg("%s(%d): " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)))
|
|
+#define seldebug(fmt, ...) \
|
|
+ ereport(NOTICE, (errcode(ERRCODE_WARNING), \
|
|
+ errmsg("%s(%d): " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)))
|
|
+#define selbugon(x) do { if (x)((char *)NULL)[0] = 'a'; }while(0)
|
|
+
|
|
+// for debugging macros
|
|
+#define seldump_pg_class(rel) \
|
|
+ selnotice("pg_class (%p) { relname='%s', relnamespace=%u, reltype=%u, " \
|
|
+ "relowner=%u, relam=%u, relfilenode=%u, reltablespace=%u, " \
|
|
+ "relpages=%d, reltuples=%f, reltoastrelid=%u, reltoastidxid=%u, " \
|
|
+ "relhasindex=%c, relisshared=%c, relkind=%c, relnatts=%d, " \
|
|
+ "relchecks=%d, reltriggers=%d, relukeys=%d, relfkeys=%d, " \
|
|
+ "relrefs=%d, relhasoids=%c, relhaspkey=%c, relhasrules=%c, " \
|
|
+ "relhassubclass=%c, ...}", \
|
|
+ (rel), NameStr((rel)->relname), (rel)->relnamespace, \
|
|
+ (rel)->reltype, (rel)->relowner, (rel)->relam, (rel)->relfilenode, \
|
|
+ (rel)->reltablespace, (rel)->relpages, (rel)->reltuples, \
|
|
+ (rel)->reltoastrelid, (rel)->reltoastidxid, (rel)->relhasindex ? 'y' : 'n', \
|
|
+ (rel)->relisshared ? 'y' : 'n', (rel)->relkind, (rel)->relnatts, \
|
|
+ (rel)->relchecks, (rel)->reltriggers, (rel)->relukeys, (rel)->relfkeys, \
|
|
+ (rel)->relrefs, (rel)->relhasoids ? 'y' : 'n', (rel)->relhaspkey ? 'y' : 'n', \
|
|
+ (rel)->relhasrules ? 'y' : 'n', (rel)->relhassubclass ? 'y' : 'n')
|
|
+#define seldump_pg_attribute(att) \
|
|
+ selnotice("pg_attribute (%p) { attrelid=%u, attname='%s', atttypid=%u, " \
|
|
+ "attstattarget=%d, attlen=%d, attnum=%d, attndims=%d, attcacheoff=%d, " \
|
|
+ "atttypmod=%d, attbyval=%c, attstorage=%c, attalign=%d, attnotnull=%c, " \
|
|
+ "atthasdef=%c, attisdropped=%c, attislocal=%c, attinhcount=%d }", \
|
|
+ (att), (att)->attrelid, NameStr((att)->attname), (att)->atttypid, \
|
|
+ (att)->attstattarget, (att)->attlen, (att)->attnum, (att)->attndims, \
|
|
+ (att)->attcacheoff, (att)->atttypmod, (att)->attbyval, (att)->attstorage, \
|
|
+ (att)->attalign, (att)->attnotnull ? 'y' : 'n', (att)->atthasdef ? 'y' : 'n', \
|
|
+ (att)->attisdropped ? 'y' : 'n', (att)->attislocal ? 'y' : 'n', (att)->attinhcount)
|
|
+
|
|
+/* object classes and access vectors are not included, in default */
|
|
+#ifndef SECCLASS_DB_DATABASE
|
|
+#define SECCLASS_DB_DATABASE (62) /* next to SECCLASS_MEMPROTECT */
|
|
+#endif
|
|
+#define SECCLASS_DB_TABLE (SECCLASS_DB_DATABASE + 1)
|
|
+#define SECCLASS_DB_PROCEDURE (SECCLASS_DB_DATABASE + 2)
|
|
+#define SECCLASS_DB_COLUMN (SECCLASS_DB_DATABASE + 3)
|
|
+#define SECCLASS_DB_TUPLE (SECCLASS_DB_DATABASE + 4)
|
|
+#define SECCLASS_DB_BLOB (SECCLASS_DB_DATABASE + 5)
|
|
+
|
|
+#define COMMON_DATABASE__CREATE 0x00000001UL
|
|
+#define COMMON_DATABASE__DROP 0x00000002UL
|
|
+#define COMMON_DATABASE__GETATTR 0x00000004UL
|
|
+#define COMMON_DATABASE__SETATTR 0x00000008UL
|
|
+#define COMMON_DATABASE__RELABELFROM 0x00000010UL
|
|
+#define COMMON_DATABASE__RELABELTO 0x00000020UL
|
|
+
|
|
+#define DB_DATABASE__CREATE 0x00000001UL
|
|
+#define DB_DATABASE__DROP 0x00000002UL
|
|
+#define DB_DATABASE__GETATTR 0x00000004UL
|
|
+#define DB_DATABASE__SETATTR 0x00000008UL
|
|
+#define DB_DATABASE__RELABELFROM 0x00000010UL
|
|
+#define DB_DATABASE__RELABELTO 0x00000020UL
|
|
+#define DB_DATABASE__ACCESS 0x00000040UL
|
|
+#define DB_DATABASE__INSTALL_MODULE 0x00000080UL
|
|
+#define DB_DATABASE__LOAD_MODULE 0x00000100UL
|
|
+#define DB_DATABASE__GET_PARAM 0x00000200UL
|
|
+#define DB_DATABASE__SET_PARAM 0x00000400UL
|
|
+#define DB_TABLE__CREATE 0x00000001UL
|
|
+#define DB_TABLE__DROP 0x00000002UL
|
|
+#define DB_TABLE__GETATTR 0x00000004UL
|
|
+#define DB_TABLE__SETATTR 0x00000008UL
|
|
+#define DB_TABLE__RELABELFROM 0x00000010UL
|
|
+#define DB_TABLE__RELABELTO 0x00000020UL
|
|
+#define DB_TABLE__USE 0x00000040UL
|
|
+#define DB_TABLE__SELECT 0x00000080UL
|
|
+#define DB_TABLE__UPDATE 0x00000100UL
|
|
+#define DB_TABLE__INSERT 0x00000200UL
|
|
+#define DB_TABLE__DELETE 0x00000400UL
|
|
+#define DB_TABLE__LOCK 0x00000800UL
|
|
+#define DB_PROCEDURE__CREATE 0x00000001UL
|
|
+#define DB_PROCEDURE__DROP 0x00000002UL
|
|
+#define DB_PROCEDURE__GETATTR 0x00000004UL
|
|
+#define DB_PROCEDURE__SETATTR 0x00000008UL
|
|
+#define DB_PROCEDURE__RELABELFROM 0x00000010UL
|
|
+#define DB_PROCEDURE__RELABELTO 0x00000020UL
|
|
+#define DB_PROCEDURE__EXECUTE 0x00000040UL
|
|
+#define DB_PROCEDURE__ENTRYPOINT 0x00000080UL
|
|
+#define DB_COLUMN__CREATE 0x00000001UL
|
|
+#define DB_COLUMN__DROP 0x00000002UL
|
|
+#define DB_COLUMN__GETATTR 0x00000004UL
|
|
+#define DB_COLUMN__SETATTR 0x00000008UL
|
|
+#define DB_COLUMN__RELABELFROM 0x00000010UL
|
|
+#define DB_COLUMN__RELABELTO 0x00000020UL
|
|
+#define DB_COLUMN__USE 0x00000040UL
|
|
+#define DB_COLUMN__SELECT 0x00000080UL
|
|
+#define DB_COLUMN__UPDATE 0x00000100UL
|
|
+#define DB_COLUMN__INSERT 0x00000200UL
|
|
+#define DB_TUPLE__RELABELFROM 0x00000001UL
|
|
+#define DB_TUPLE__RELABELTO 0x00000002UL
|
|
+#define DB_TUPLE__USE 0x00000004UL
|
|
+#define DB_TUPLE__SELECT 0x00000008UL
|
|
+#define DB_TUPLE__UPDATE 0x00000010UL
|
|
+#define DB_TUPLE__INSERT 0x00000020UL
|
|
+#define DB_TUPLE__DELETE 0x00000040UL
|
|
+#define DB_BLOB__CREATE 0x00000001UL
|
|
+#define DB_BLOB__DROP 0x00000002UL
|
|
+#define DB_BLOB__GETATTR 0x00000004UL
|
|
+#define DB_BLOB__SETATTR 0x00000008UL
|
|
+#define DB_BLOB__RELABELFROM 0x00000010UL
|
|
+#define DB_BLOB__RELABELTO 0x00000020UL
|
|
+#define DB_BLOB__READ 0x00000040UL
|
|
+#define DB_BLOB__WRITE 0x00000080UL
|
|
+#define DB_BLOB__IMPORT 0x00000100UL
|
|
+#define DB_BLOB__EXPORT 0x00000200UL
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL core functions
|
|
+ * src/backend/security/sepgsqlCore.c
|
|
+ */
|
|
+extern bool sepgsqlIsEnabled(void);
|
|
+extern Size sepgsqlShmemSize(void);
|
|
+extern void sepgsqlInitialize(void);
|
|
+extern int sepgsqlInitializePostmaster(void);
|
|
+extern void sepgsqlFinalizePostmaster(void);
|
|
+
|
|
+extern Oid sepgsqlGetServerContext(void);
|
|
+extern Oid sepgsqlGetClientContext(void);
|
|
+extern void sepgsqlSetClientContext(Oid new_ctx);
|
|
+extern Oid sepgsqlGetDatabaseContext(void);
|
|
+extern char *sepgsqlGetDatabaseName(void);
|
|
+
|
|
+extern bool sepgsql_avc_permission_noaudit(Oid ssid, Oid tsid, uint16 tclass,
|
|
+ uint32 perms, char **audit, char *objname);
|
|
+extern void sepgsql_avc_permission(Oid ssid, Oid tsid, uint16 tclass,
|
|
+ uint32 perms, char *objname);
|
|
+extern char *sepgsqlGetTupleName(Oid relid, HeapTuple tuple);
|
|
+extern void sepgsql_audit(bool result, char *message);
|
|
+extern Oid sepgsql_avc_createcon(Oid ssid, Oid tsid, uint16 tclass);
|
|
+extern Oid sepgsql_avc_relabelcon(Oid ssid, Oid tsid, uint16 tclass);
|
|
+extern bool sepgsql_check_context(char *context);
|
|
+
|
|
+extern Datum sepgsql_getcon(PG_FUNCTION_ARGS);
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL proxy functions
|
|
+ * src/backend/security/sepgsqlProxy.c
|
|
+ */
|
|
+extern List *sepgsqlProxyQuery(Query *query);
|
|
+extern void sepgsqlVerifyQuery(Query *query);
|
|
+extern Oid sepgsqlPreparePlanCheck(Relation rel);
|
|
+extern void sepgsqlRestorePlanCheck(Relation rel, Oid pgace_saved);
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL hooks
|
|
+ * src/backend/security/sepgsqlHooks.c
|
|
+ */
|
|
+
|
|
+/* simple_heap_xxxx hooks */
|
|
+extern void sepgsqlSimpleHeapInsert(Relation rel, HeapTuple tuple);
|
|
+extern void sepgsqlSimpleHeapUpdate(Relation rel, ItemPointer tid, HeapTuple newtup);
|
|
+extern void sepgsqlSimpleHeapDelete(Relation rel, ItemPointer tid);
|
|
+
|
|
+/* heap_xxxx hooks for implicit labeling */
|
|
+extern void sepgsqlHeapInsert(Relation rel, HeapTuple tuple);
|
|
+extern void sepgsqlHeapUpdate(Relation rel, HeapTuple newtup, HeapTuple oldtup);
|
|
+
|
|
+/* INSERT/UPDATE/DELETE statement hooks */
|
|
+extern bool sepgsqlExecInsert(Relation rel, HeapTuple tuple, bool with_returning);
|
|
+extern bool sepgsqlExecUpdate(Relation rel, HeapTuple newtup, ItemPointer tid, bool with_returning);
|
|
+extern bool sepgsqlExecDelete(Relation rel, ItemPointer tid, bool with_returning);
|
|
+
|
|
+/* DATABASE */
|
|
+extern void sepgsqlAlterDatabaseContext(Relation rel, HeapTuple tuple, char *new_context);
|
|
+extern void sepgsqlSetDatabaseParam(const char *name, char *argstring);
|
|
+extern void sepgsqlGetDatabaseParam(const char *name);
|
|
+
|
|
+/* RELATION/ATTRIBUTE */
|
|
+extern void sepgsqlLockTable(Oid relid);
|
|
+
|
|
+/* FUNCTION */
|
|
+extern void sepgsqlCallFunction(FmgrInfo *finfo, bool with_perm_check);
|
|
+extern bool sepgsqlCallFunctionTrigger(FmgrInfo *finfo, TriggerData *tgdata);
|
|
+extern void sepgsqlAlterProcedureContext(Relation rel, HeapTuple tuple, char *context);
|
|
+
|
|
+/* COPY */
|
|
+extern void sepgsqlCopyTable(Relation rel, List *attnumlist, bool is_from);
|
|
+extern bool sepgsqlCopyToTuple(Relation rel, HeapTuple tuple);
|
|
+extern bool sepgsqlCopyFromTuple(Relation rel, HeapTuple tuple);
|
|
+
|
|
+/* LOAD shared library module */
|
|
+extern void sepgsqlLoadSharedModule(const char *filename);
|
|
+
|
|
+/* copy/print node object */
|
|
+extern Node *sepgsqlCopyObject(Node *node);
|
|
+extern bool sepgsqlOutObject(StringInfo str, Node *node);
|
|
+
|
|
+/* SECURITY LABEL IN/OUT */
|
|
+extern char *sepgsqlSecurityLabelIn(char *context);
|
|
+extern char *sepgsqlSecurityLabelOut(char *context);
|
|
+extern bool sepgsqlSecurityLabelIsValid(char *context);
|
|
+extern char *sepgsqlSecurityLabelOfLabel(char *context);
|
|
+extern char *sepgsqlSecurityLabelNotFound(Oid sid);
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL Binary Large Object (BLOB) functions
|
|
+ * src/backend/security/sepgsqlLargeObject.c
|
|
+ */
|
|
+extern Oid sepgsqlLargeObjectGetSecurity(HeapTuple tuple);
|
|
+extern void sepgsqlLargeObjectSetSecurity(HeapTuple tuple, Oid lo_security, bool is_first);
|
|
+extern void sepgsqlLargeObjectCreate(Relation rel, HeapTuple tuple);
|
|
+extern void sepgsqlLargeObjectDrop(Relation rel, HeapTuple tuple);
|
|
+extern void sepgsqlLargeObjectOpen(Relation rel, HeapTuple tuple, bool read_only);
|
|
+extern void sepgsqlLargeObjectRead(Relation rel, HeapTuple tuple);
|
|
+extern void sepgsqlLargeObjectWrite(Relation rel, HeapTuple newtup, HeapTuple oldtup);
|
|
+extern void sepgsqlLargeObjectImport(void);
|
|
+extern void sepgsqlLargeObjectExport(void);
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL Heap related functions
|
|
+ * src/backend/security/sepgsqlHeap.c
|
|
+ */
|
|
+
|
|
+extern Oid sepgsqlComputeImplicitContext(Relation rel, HeapTuple tuple);
|
|
+extern bool sepgsqlCheckTuplePerms(Relation rel, HeapTuple tuple, HeapTuple oldtup,
|
|
+ uint32 perms, bool abort);
|
|
+extern Datum sepgsql_tuple_perms(PG_FUNCTION_ARGS);
|
|
+extern Datum sepgsql_tuple_perms_abort(PG_FUNCTION_ARGS);
|
|
+
|
|
+/*
|
|
+ * SE-PostgreSQL extended SQL statement
|
|
+ * src/backend/security/sepgsqlExtStmt.c
|
|
+ */
|
|
+extern DefElem *sepgsqlGramSecurityLabel(char *defname, char *context);
|
|
+extern bool sepgsqlNodeIsSecurityLabel(DefElem *defel);
|
|
+extern Oid sepgsqlParseSecurityLabel(DefElem *defel);
|
|
+
|
|
+#endif /* SEPGSQL_INTERNAL_H */
|
|
diff -rpNU3 base/src/include/utils/syscache.h sepgsql/src/include/utils/syscache.h
|
|
--- base/src/include/utils/syscache.h 2007-10-25 08:32:26.000000000 +0900
|
|
+++ sepgsql/src/include/utils/syscache.h 2007-10-25 13:12:52.000000000 +0900
|
|
@@ -63,6 +63,8 @@
|
|
#define STATRELATT 32
|
|
#define TYPENAMENSP 33
|
|
#define TYPEOID 34
|
|
+#define SECURITYOID 35
|
|
+#define SECURITYLABEL 36
|
|
|
|
extern void InitCatalogCache(void);
|
|
extern void InitCatalogCachePhase2(void);
|