sepostgresql/sepostgresql-8.2.5-1.patch
2007-11-01 14:00:32 +00:00

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);