From e4206f4c3baf4424ff4c652a7fa3f55c6b9df255 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Tue, 15 Jan 2008 13:43:40 +0000 Subject: [PATCH] unnecessary legacy patches are removed. --- sepostgresql-8.2.4-0.434.patch | 8578 ------------------------------- sepostgresql-8.2.4-1.patch | 8578 ------------------------------- sepostgresql-8.2.5-1.patch | 8585 -------------------------------- 3 files changed, 25741 deletions(-) delete mode 100644 sepostgresql-8.2.4-0.434.patch delete mode 100644 sepostgresql-8.2.4-1.patch delete mode 100644 sepostgresql-8.2.5-1.patch diff --git a/sepostgresql-8.2.4-0.434.patch b/sepostgresql-8.2.4-0.434.patch deleted file mode 100644 index e76994b..0000000 --- a/sepostgresql-8.2.4-0.434.patch +++ /dev/null @@ -1,8578 +0,0 @@ -diff -rpNU3 postgresql-8.2.4/configure.in sepostgresql-8.2.4/configure.in ---- postgresql-8.2.4/configure.in 2007-04-20 12:20:42.000000000 +0900 -+++ sepostgresql-8.2.4/configure.in 2007-04-29 13:49:53.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 - # - -Binary files postgresql-8.2.4/doc/postgres.tar.gz and sepostgresql-8.2.4/doc/postgres.tar.gz differ -diff -rpNU3 postgresql-8.2.4/src/Makefile.global.in sepostgresql-8.2.4/src/Makefile.global.in ---- postgresql-8.2.4/src/Makefile.global.in 2006-10-09 02:15:33.000000000 +0900 -+++ sepostgresql-8.2.4/src/Makefile.global.in 2007-08-28 09:33:36.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 postgresql-8.2.4/src/backend/Makefile sepostgresql-8.2.4/src/backend/Makefile ---- postgresql-8.2.4/src/backend/Makefile 2006-10-09 02:15:33.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/Makefile 2007-02-13 03:22:30.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 postgresql-8.2.4/src/backend/access/common/heaptuple.c sepostgresql-8.2.4/src/backend/access/common/heaptuple.c ---- postgresql-8.2.4/src/backend/access/common/heaptuple.c 2006-11-23 14:27:18.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/access/common/heaptuple.c 2007-04-10 21:02:02.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 postgresql-8.2.4/src/backend/access/heap/heapam.c sepostgresql-8.2.4/src/backend/access/heap/heapam.c ---- postgresql-8.2.4/src/backend/access/heap/heapam.c 2007-02-05 05:00:49.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/access/heap/heapam.c 2007-04-10 02:49:22.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 postgresql-8.2.4/src/backend/bootstrap/bootparse.y sepostgresql-8.2.4/src/backend/bootstrap/bootparse.y ---- postgresql-8.2.4/src/backend/bootstrap/bootparse.y 2006-08-25 13:06:46.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/bootstrap/bootparse.y 2007-05-15 21:45:21.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 postgresql-8.2.4/src/backend/catalog/Makefile sepostgresql-8.2.4/src/backend/catalog/Makefile ---- postgresql-8.2.4/src/backend/catalog/Makefile 2006-07-31 10:16:36.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/Makefile 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/catalog/catalog.c sepostgresql-8.2.4/src/backend/catalog/catalog.c ---- postgresql-8.2.4/src/backend/catalog/catalog.c 2006-10-04 09:29:50.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/catalog.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/catalog/genbki.sh sepostgresql-8.2.4/src/backend/catalog/genbki.sh ---- postgresql-8.2.4/src/backend/catalog/genbki.sh 2006-07-31 10:16:36.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/genbki.sh 2007-04-10 02:23:28.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 postgresql-8.2.4/src/backend/catalog/heap.c sepostgresql-8.2.4/src/backend/catalog/heap.c ---- postgresql-8.2.4/src/backend/catalog/heap.c 2006-11-06 07:42:08.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/heap.c 2007-05-15 21:45:21.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 postgresql-8.2.4/src/backend/catalog/index.c sepostgresql-8.2.4/src/backend/catalog/index.c ---- postgresql-8.2.4/src/backend/catalog/index.c 2006-10-04 09:29:50.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/index.c 2007-05-15 21:45:21.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 postgresql-8.2.4/src/backend/catalog/pg_aggregate.c sepostgresql-8.2.4/src/backend/catalog/pg_aggregate.c ---- postgresql-8.2.4/src/backend/catalog/pg_aggregate.c 2006-10-04 09:29:50.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/pg_aggregate.c 2007-05-15 15:51:51.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 postgresql-8.2.4/src/backend/catalog/pg_largeobject.c sepostgresql-8.2.4/src/backend/catalog/pg_largeobject.c ---- postgresql-8.2.4/src/backend/catalog/pg_largeobject.c 2006-07-14 23:52:17.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/pg_largeobject.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/catalog/pg_proc.c sepostgresql-8.2.4/src/backend/catalog/pg_proc.c ---- postgresql-8.2.4/src/backend/catalog/pg_proc.c 2006-10-20 03:32:46.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/pg_proc.c 2007-05-17 23:32:22.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 postgresql-8.2.4/src/backend/catalog/toasting.c sepostgresql-8.2.4/src/backend/catalog/toasting.c ---- postgresql-8.2.4/src/backend/catalog/toasting.c 2006-10-04 09:29:50.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/toasting.c 2007-05-15 21:45:21.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 postgresql-8.2.4/src/backend/commands/cluster.c sepostgresql-8.2.4/src/backend/commands/cluster.c ---- postgresql-8.2.4/src/backend/commands/cluster.c 2006-10-04 09:29:50.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/cluster.c 2007-05-15 21:45:21.000000000 +0900 -@@ -615,7 +615,8 @@ make_new_heap(Oid OIDOldHeap, const char - 0, - ONCOMMIT_NOOP, - reloptions, -- allowSystemTableMods); -+ allowSystemTableMods, -+ NIL); - - ReleaseSysCache(tuple); - -diff -rpNU3 postgresql-8.2.4/src/backend/commands/copy.c sepostgresql-8.2.4/src/backend/commands/copy.c ---- postgresql-8.2.4/src/backend/commands/copy.c 2006-10-07 02:13:58.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/copy.c 2007-05-22 00:50:16.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 postgresql-8.2.4/src/backend/commands/dbcommands.c sepostgresql-8.2.4/src/backend/commands/dbcommands.c ---- postgresql-8.2.4/src/backend/commands/dbcommands.c 2007-04-13 00:04:41.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/dbcommands.c 2007-05-17 23:32:22.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 postgresql-8.2.4/src/backend/commands/functioncmds.c sepostgresql-8.2.4/src/backend/commands/functioncmds.c ---- postgresql-8.2.4/src/backend/commands/functioncmds.c 2006-10-07 02:13:58.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/functioncmds.c 2007-05-17 23:32:22.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 postgresql-8.2.4/src/backend/commands/lockcmds.c sepostgresql-8.2.4/src/backend/commands/lockcmds.c ---- postgresql-8.2.4/src/backend/commands/lockcmds.c 2006-08-19 01:09:08.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/lockcmds.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/commands/proclang.c sepostgresql-8.2.4/src/backend/commands/proclang.c ---- postgresql-8.2.4/src/backend/commands/proclang.c 2006-10-04 09:29:51.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/proclang.c 2007-05-15 15:51:51.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 postgresql-8.2.4/src/backend/commands/tablecmds.c sepostgresql-8.2.4/src/backend/commands/tablecmds.c ---- postgresql-8.2.4/src/backend/commands/tablecmds.c 2007-02-02 09:07:27.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/tablecmds.c 2007-05-16 01:14:32.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" -@@ -434,7 +435,8 @@ DefineRelation(CreateStmt *stmt, char re - parentOidCount, - stmt->oncommit, - reloptions, -- allowSystemTableMods); -+ allowSystemTableMods, -+ pgaceBuildAttrListForRelation(stmt)); - - StoreCatalogInheritance(relationId, inheritOids); - -@@ -2185,6 +2187,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 */ -@@ -2374,6 +2377,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 postgresql-8.2.4/src/backend/commands/trigger.c sepostgresql-8.2.4/src/backend/commands/trigger.c ---- postgresql-8.2.4/src/backend/commands/trigger.c 2007-01-25 13:17:56.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/trigger.c 2007-06-23 19:56:29.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 postgresql-8.2.4/src/backend/executor/execMain.c sepostgresql-8.2.4/src/backend/executor/execMain.c ---- postgresql-8.2.4/src/backend/executor/execMain.c 2007-02-02 09:07:27.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/executor/execMain.c 2007-06-26 02:08:29.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 postgresql-8.2.4/src/backend/executor/execQual.c sepostgresql-8.2.4/src/backend/executor/execQual.c ---- postgresql-8.2.4/src/backend/executor/execQual.c 2007-02-07 02:35:27.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/executor/execQual.c 2007-04-11 03:14:48.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" -@@ -1668,6 +1669,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 postgresql-8.2.4/src/backend/libpq/be-fsstubs.c sepostgresql-8.2.4/src/backend/libpq/be-fsstubs.c ---- postgresql-8.2.4/src/backend/libpq/be-fsstubs.c 2006-09-08 00:37:25.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/libpq/be-fsstubs.c 2007-04-10 22:23:13.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 postgresql-8.2.4/src/backend/nodes/copyfuncs.c sepostgresql-8.2.4/src/backend/nodes/copyfuncs.c ---- postgresql-8.2.4/src/backend/nodes/copyfuncs.c 2006-11-06 07:42:08.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/nodes/copyfuncs.c 2007-04-10 02:21:12.000000000 +0900 -@@ -24,6 +24,7 @@ - - #include "nodes/plannodes.h" - #include "nodes/relation.h" -+#include "security/pgace.h" - #include "utils/datum.h" - - -@@ -1714,6 +1715,7 @@ _copyQuery(Query *from) - COPY_NODE_FIELD(setOperations); - COPY_NODE_FIELD(resultRelations); - COPY_NODE_FIELD(returningLists); -+ COPY_NODE_FIELD(pgaceList); - - return newnode; - } -@@ -3342,6 +3344,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 postgresql-8.2.4/src/backend/nodes/outfuncs.c sepostgresql-8.2.4/src/backend/nodes/outfuncs.c ---- postgresql-8.2.4/src/backend/nodes/outfuncs.c 2006-09-20 07:49:52.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/nodes/outfuncs.c 2007-04-10 02:21:12.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" - - -@@ -2190,6 +2191,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 postgresql-8.2.4/src/backend/parser/analyze.c sepostgresql-8.2.4/src/backend/parser/analyze.c ---- postgresql-8.2.4/src/backend/parser/analyze.c 2006-10-12 01:42:59.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/parser/analyze.c 2007-04-07 15:10:06.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); -@@ -2146,6 +2151,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 postgresql-8.2.4/src/backend/parser/gram.y sepostgresql-8.2.4/src/backend/parser/gram.y ---- postgresql-8.2.4/src/backend/parser/gram.y 2006-11-06 07:42:09.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/parser/gram.y 2007-05-15 21:45:21.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 OptTableSpace OptConsTableSpace OptTableSpaceOwner - %type opt_check_option - -+%type 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 CONTEXT = '...' */ -+ | SecurityLabelItem -+ { -+ AlterTableCmd *n = makeNode(AlterTableCmd); -+ n->subtype = AT_SetSecurityLabel; -+ n->name = NULL; -+ n->def = (Node *) $1; -+ $$ = (Node *) n; -+ } -+ /* ALTER TABLE ALTER [COLUMN] 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 (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 postgresql-8.2.4/src/backend/parser/parse_target.c sepostgresql-8.2.4/src/backend/parser/parse_target.c ---- postgresql-8.2.4/src/backend/parser/parse_target.c 2006-10-04 09:29:56.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/parser/parse_target.c 2007-04-10 02:23:28.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 postgresql-8.2.4/src/backend/postmaster/postmaster.c sepostgresql-8.2.4/src/backend/postmaster/postmaster.c ---- postgresql-8.2.4/src/backend/postmaster/postmaster.c 2007-02-12 00:12:21.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/postmaster/postmaster.c 2007-04-29 13:49:53.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" -@@ -960,6 +961,9 @@ PostmasterMain(int argc, char *argv[]) - */ - StartupPID = StartupDataBase(); - -+ if (!pgaceInitializePostmaster()) -+ ExitPostmaster(1); -+ - status = ServerLoop(); - - /* -@@ -1982,9 +1986,11 @@ pmdie(SIGNAL_ARGS) - signal_child(PgStatPID, SIGQUIT); - if (DLGetHead(BackendList)) - SignalChildren(SIGQUIT); -+ pgaceFinalizePostmaster(); - ExitPostmaster(0); - break; - } -+ pgaceFinalizePostmaster(); - - PG_SETMASK(&UnBlockSig); - -diff -rpNU3 postgresql-8.2.4/src/backend/rewrite/rewriteHandler.c sepostgresql-8.2.4/src/backend/rewrite/rewriteHandler.c ---- postgresql-8.2.4/src/backend/rewrite/rewriteHandler.c 2007-03-02 03:50:36.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/rewrite/rewriteHandler.c 2007-04-29 13:49:53.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 postgresql-8.2.4/src/backend/security/Makefile sepostgresql-8.2.4/src/backend/security/Makefile ---- postgresql-8.2.4/src/backend/security/Makefile 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/Makefile 2007-05-26 15:04:24.000000000 +0900 -@@ -0,0 +1,31 @@ -+# -+# src/backend/security/Makefile -+# Makefile for Security Enhanced PostgreSQL -+# -+# Copyright (c) 2006 - 2007 KaiGai Kohei -+# -+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 postgresql-8.2.4/src/backend/security/pgaceCommon.c sepostgresql-8.2.4/src/backend/security/pgaceCommon.c ---- postgresql-8.2.4/src/backend/security/pgaceCommon.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/pgaceCommon.c 2007-06-22 02:22:56.000000000 +0900 -@@ -0,0 +1,764 @@ -+/* -+ * src/backend/security/pgaceCommon.c -+ * Common part of PostgreSQL Access Control Extension -+ * Copyright 2007 KaiGai Kohei -+ */ -+#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 -+#include -+ -+#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 [ALTER ] 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 postgresql-8.2.4/src/backend/security/sepgsqlCore.c sepostgresql-8.2.4/src/backend/security/sepgsqlCore.c ---- postgresql-8.2.4/src/backend/security/sepgsqlCore.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/sepgsqlCore.c 2007-08-09 17:28:31.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 -+ */ -+#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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 postgresql-8.2.4/src/backend/security/sepgsqlHooks.c sepostgresql-8.2.4/src/backend/security/sepgsqlHooks.c ---- postgresql-8.2.4/src/backend/security/sepgsqlHooks.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/sepgsqlHooks.c 2007-08-09 17:28:31.000000000 +0900 -@@ -0,0 +1,668 @@ -+/* -+ * src/backend/sepgsqlHooks.c -+ * SE-PostgreSQL hooks -+ * -+ * Copyright 2007 KaiGai Kohei -+ */ -+#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 -+#include -+#include -+#include -+ -+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; -+ char *result; -+ -+ if (selinux_trans_to_raw_context(context, &raw_context)) -+ selerror("could not translate MLS label"); -+ PG_TRY(); -+ { -+ result = pstrdup(raw_context); -+ } -+ PG_CATCH(); -+ { -+ freecon(raw_context); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(raw_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 postgresql-8.2.4/src/backend/security/sepgsqlPerms.c sepostgresql-8.2.4/src/backend/security/sepgsqlPerms.c ---- postgresql-8.2.4/src/backend/security/sepgsqlPerms.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/sepgsqlPerms.c 2007-08-09 17:28:31.000000000 +0900 -@@ -0,0 +1,489 @@ -+/* -+ * src/backend/security/sepgsqlPerms.c -+ * SE-PostgreSQL permission checking functions -+ * -+ * Copyright (c) 2007 KaiGai Kohei -+ */ -+#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; -+ -+ /* <-- database:module_install --> */ -+ sepgsql_avc_permission(sepgsqlGetClientContext(), -+ sepgsqlGetDatabaseContext(), -+ SECCLASS_DB_DATABASE, -+ DB_DATABASE__INSTALL_MODULE, -+ NULL); -+ -+ /* <-- database:module_install --> */ -+ 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 postgresql-8.2.4/src/backend/security/sepgsqlProxy.c sepostgresql-8.2.4/src/backend/security/sepgsqlProxy.c ---- postgresql-8.2.4/src/backend/security/sepgsqlProxy.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/sepgsqlProxy.c 2007-08-09 17:28:31.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 -+ */ -+#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<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<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 postgresql-8.2.4/src/backend/storage/ipc/ipci.c sepostgresql-8.2.4/src/backend/storage/ipc/ipci.c ---- postgresql-8.2.4/src/backend/storage/ipc/ipci.c 2006-10-16 07:04:07.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/storage/ipc/ipci.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/storage/large_object/inv_api.c sepostgresql-8.2.4/src/backend/storage/large_object/inv_api.c ---- postgresql-8.2.4/src/backend/storage/large_object/inv_api.c 2006-09-08 00:37:25.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/storage/large_object/inv_api.c 2007-04-10 22:23:13.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 postgresql-8.2.4/src/backend/tcop/fastpath.c sepostgresql-8.2.4/src/backend/tcop/fastpath.c ---- postgresql-8.2.4/src/backend/tcop/fastpath.c 2006-10-20 07:44:11.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/tcop/fastpath.c 2007-04-11 03:14:48.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 postgresql-8.2.4/src/backend/tcop/postgres.c sepostgresql-8.2.4/src/backend/tcop/postgres.c ---- postgresql-8.2.4/src/backend/tcop/postgres.c 2007-01-04 09:58:01.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/tcop/postgres.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/tcop/pquery.c sepostgresql-8.2.4/src/backend/tcop/pquery.c ---- postgresql-8.2.4/src/backend/tcop/pquery.c 2007-02-19 04:49:30.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/tcop/pquery.c 2007-04-29 13:49:53.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 postgresql-8.2.4/src/backend/utils/adt/ri_triggers.c sepostgresql-8.2.4/src/backend/utils/adt/ri_triggers.c ---- postgresql-8.2.4/src/backend/utils/adt/ri_triggers.c 2006-10-04 09:29:59.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/utils/adt/ri_triggers.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/utils/cache/syscache.c sepostgresql-8.2.4/src/backend/utils/cache/syscache.c ---- postgresql-8.2.4/src/backend/utils/cache/syscache.c 2006-10-07 03:23:35.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/utils/cache/syscache.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/utils/fmgr/dfmgr.c sepostgresql-8.2.4/src/backend/utils/fmgr/dfmgr.c ---- postgresql-8.2.4/src/backend/utils/fmgr/dfmgr.c 2006-10-07 02:13:59.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/utils/fmgr/dfmgr.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/utils/init/postinit.c sepostgresql-8.2.4/src/backend/utils/init/postinit.c ---- postgresql-8.2.4/src/backend/utils/init/postinit.c 2006-11-06 07:42:09.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/utils/init/postinit.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/utils/misc/guc.c sepostgresql-8.2.4/src/backend/utils/misc/guc.c ---- postgresql-8.2.4/src/backend/utils/misc/guc.c 2006-11-29 23:50:07.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/utils/misc/guc.c 2007-04-07 15:10:06.000000000 +0900 -@@ -50,6 +50,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" -@@ -4566,6 +4567,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, -@@ -4828,6 +4832,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 -@@ -4872,6 +4879,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 postgresql-8.2.4/src/bin/pg_dump/pg_dump.c sepostgresql-8.2.4/src/bin/pg_dump/pg_dump.c ---- postgresql-8.2.4/src/bin/pg_dump/pg_dump.c 2007-04-17 03:42:17.000000000 +0900 -+++ sepostgresql-8.2.4/src/bin/pg_dump/pg_dump.c 2007-08-18 04:05:24.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 postgresql-8.2.4/src/bin/pg_dump/pg_dump.h sepostgresql-8.2.4/src/bin/pg_dump/pg_dump.h ---- postgresql-8.2.4/src/bin/pg_dump/pg_dump.h 2007-02-20 00:05:21.000000000 +0900 -+++ sepostgresql-8.2.4/src/bin/pg_dump/pg_dump.h 2007-08-18 04:05:24.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 postgresql-8.2.4/src/bin/pg_dump/pg_dumpall.c sepostgresql-8.2.4/src/bin/pg_dump/pg_dumpall.c ---- postgresql-8.2.4/src/bin/pg_dump/pg_dumpall.c 2006-11-22 07:19:46.000000000 +0900 -+++ sepostgresql-8.2.4/src/bin/pg_dump/pg_dumpall.c 2007-08-18 04:05:24.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")); -@@ -792,16 +806,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), " -@@ -810,7 +826,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), " -@@ -819,7 +835,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), " -@@ -835,7 +851,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), " -@@ -845,6 +861,7 @@ dumpCreateDB(PGconn *conn) - "FROM pg_database d " - "ORDER BY 1"); - } -+ res = executeQuery(conn, buf->data); - - for (i = 0; i < PQntuples(res); i++) - { -@@ -855,6 +872,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)); -@@ -898,6 +916,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 postgresql-8.2.4/src/include/access/htup.h sepostgresql-8.2.4/src/include/access/htup.h ---- postgresql-8.2.4/src/include/access/htup.h 2006-11-06 07:42:10.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/access/htup.h 2007-04-10 02:49:22.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 postgresql-8.2.4/src/include/catalog/heap.h sepostgresql-8.2.4/src/include/catalog/heap.h ---- postgresql-8.2.4/src/include/catalog/heap.h 2006-07-14 01:49:19.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/heap.h 2007-05-15 21:45:21.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 postgresql-8.2.4/src/include/catalog/indexing.h sepostgresql-8.2.4/src/include/catalog/indexing.h ---- postgresql-8.2.4/src/include/catalog/indexing.h 2006-07-14 02:47:01.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/indexing.h 2007-04-07 15:10:06.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 postgresql-8.2.4/src/include/catalog/pg_attribute.h sepostgresql-8.2.4/src/include/catalog/pg_attribute.h ---- postgresql-8.2.4/src/include/catalog/pg_attribute.h 2006-11-06 07:42:10.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/pg_attribute.h 2007-04-07 15:10:06.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 postgresql-8.2.4/src/include/catalog/pg_cast.h sepostgresql-8.2.4/src/include/catalog/pg_cast.h ---- postgresql-8.2.4/src/include/catalog/pg_cast.h 2006-03-06 00:58:54.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/pg_cast.h 2007-04-28 18:41:09.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 postgresql-8.2.4/src/include/catalog/pg_proc.h sepostgresql-8.2.4/src/include/catalog/pg_proc.h ---- postgresql-8.2.4/src/include/catalog/pg_proc.h 2006-11-29 04:18:44.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/pg_proc.h 2007-05-26 13:19:59.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 25 "3403" _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 3403 "25" _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 postgresql-8.2.4/src/include/catalog/pg_security.h sepostgresql-8.2.4/src/include/catalog/pg_security.h ---- postgresql-8.2.4/src/include/catalog/pg_security.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/pg_security.h 2007-04-07 15:26:44.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 -+ */ -+#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 postgresql-8.2.4/src/include/catalog/pg_type.h sepostgresql-8.2.4/src/include/catalog/pg_type.h ---- postgresql-8.2.4/src/include/catalog/pg_type.h 2006-12-28 10:09:04.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/pg_type.h 2007-04-07 15:10:06.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 postgresql-8.2.4/src/include/executor/tuptable.h sepostgresql-8.2.4/src/include/executor/tuptable.h ---- postgresql-8.2.4/src/include/executor/tuptable.h 2006-10-04 09:30:08.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/executor/tuptable.h 2007-04-07 15:10:06.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 postgresql-8.2.4/src/include/fmgr.h sepostgresql-8.2.4/src/include/fmgr.h ---- postgresql-8.2.4/src/include/fmgr.h 2006-10-04 09:30:06.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/fmgr.h 2007-04-11 03:14:48.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 postgresql-8.2.4/src/include/libpq/be-fsstubs.h sepostgresql-8.2.4/src/include/libpq/be-fsstubs.h ---- postgresql-8.2.4/src/include/libpq/be-fsstubs.h 2006-09-08 00:37:25.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/libpq/be-fsstubs.h 2007-02-17 01:25:55.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 postgresql-8.2.4/src/include/nodes/parsenodes.h sepostgresql-8.2.4/src/include/nodes/parsenodes.h ---- postgresql-8.2.4/src/include/nodes/parsenodes.h 2006-11-06 07:42:10.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/nodes/parsenodes.h 2007-05-15 21:45:21.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 postgresql-8.2.4/src/include/pg_config.h.in sepostgresql-8.2.4/src/include/pg_config.h.in ---- postgresql-8.2.4/src/include/pg_config.h.in 2006-11-06 12:44:38.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/pg_config.h.in 2007-04-10 02:23:28.000000000 +0900 -@@ -337,6 +337,9 @@ - /* Define to 1 if you have the 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 - -@@ -595,6 +598,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 postgresql-8.2.4/src/include/security/pgace.h sepostgresql-8.2.4/src/include/security/pgace.h ---- postgresql-8.2.4/src/include/security/pgace.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/security/pgace.h 2007-06-26 02:08:29.000000000 +0900 -@@ -0,0 +1,643 @@ -+/* -+ * include/security/pgace.h -+ * headers for PostgreSQL Access Control Extensions (PGACE) -+ * Copyright 2007 KaiGai Kohei -+ */ -+#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 string -+ * @value : given 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 postgresql-8.2.4/src/include/security/sepgsql.h sepostgresql-8.2.4/src/include/security/sepgsql.h ---- postgresql-8.2.4/src/include/security/sepgsql.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/security/sepgsql.h 2007-06-30 03:25:54.000000000 +0900 -@@ -0,0 +1,330 @@ -+/* -+ * src/include/sepgsql.h -+ * The header file of Security Enhanced PostgreSQL -+ * -+ * Copyright (c) 2006 - 2007, KaiGai Kohei -+ */ -+#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 postgresql-8.2.4/src/include/security/sepgsql_internal.h sepostgresql-8.2.4/src/include/security/sepgsql_internal.h ---- postgresql-8.2.4/src/include/security/sepgsql_internal.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/security/sepgsql_internal.h 2007-08-09 17:28:31.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 -+#include -+#include -+ -+#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 postgresql-8.2.4/src/include/utils/syscache.h sepostgresql-8.2.4/src/include/utils/syscache.h ---- postgresql-8.2.4/src/include/utils/syscache.h 2006-07-14 03:01:02.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/utils/syscache.h 2007-04-07 15:10:06.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); diff --git a/sepostgresql-8.2.4-1.patch b/sepostgresql-8.2.4-1.patch deleted file mode 100644 index e76994b..0000000 --- a/sepostgresql-8.2.4-1.patch +++ /dev/null @@ -1,8578 +0,0 @@ -diff -rpNU3 postgresql-8.2.4/configure.in sepostgresql-8.2.4/configure.in ---- postgresql-8.2.4/configure.in 2007-04-20 12:20:42.000000000 +0900 -+++ sepostgresql-8.2.4/configure.in 2007-04-29 13:49:53.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 - # - -Binary files postgresql-8.2.4/doc/postgres.tar.gz and sepostgresql-8.2.4/doc/postgres.tar.gz differ -diff -rpNU3 postgresql-8.2.4/src/Makefile.global.in sepostgresql-8.2.4/src/Makefile.global.in ---- postgresql-8.2.4/src/Makefile.global.in 2006-10-09 02:15:33.000000000 +0900 -+++ sepostgresql-8.2.4/src/Makefile.global.in 2007-08-28 09:33:36.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 postgresql-8.2.4/src/backend/Makefile sepostgresql-8.2.4/src/backend/Makefile ---- postgresql-8.2.4/src/backend/Makefile 2006-10-09 02:15:33.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/Makefile 2007-02-13 03:22:30.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 postgresql-8.2.4/src/backend/access/common/heaptuple.c sepostgresql-8.2.4/src/backend/access/common/heaptuple.c ---- postgresql-8.2.4/src/backend/access/common/heaptuple.c 2006-11-23 14:27:18.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/access/common/heaptuple.c 2007-04-10 21:02:02.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 postgresql-8.2.4/src/backend/access/heap/heapam.c sepostgresql-8.2.4/src/backend/access/heap/heapam.c ---- postgresql-8.2.4/src/backend/access/heap/heapam.c 2007-02-05 05:00:49.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/access/heap/heapam.c 2007-04-10 02:49:22.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 postgresql-8.2.4/src/backend/bootstrap/bootparse.y sepostgresql-8.2.4/src/backend/bootstrap/bootparse.y ---- postgresql-8.2.4/src/backend/bootstrap/bootparse.y 2006-08-25 13:06:46.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/bootstrap/bootparse.y 2007-05-15 21:45:21.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 postgresql-8.2.4/src/backend/catalog/Makefile sepostgresql-8.2.4/src/backend/catalog/Makefile ---- postgresql-8.2.4/src/backend/catalog/Makefile 2006-07-31 10:16:36.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/Makefile 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/catalog/catalog.c sepostgresql-8.2.4/src/backend/catalog/catalog.c ---- postgresql-8.2.4/src/backend/catalog/catalog.c 2006-10-04 09:29:50.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/catalog.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/catalog/genbki.sh sepostgresql-8.2.4/src/backend/catalog/genbki.sh ---- postgresql-8.2.4/src/backend/catalog/genbki.sh 2006-07-31 10:16:36.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/genbki.sh 2007-04-10 02:23:28.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 postgresql-8.2.4/src/backend/catalog/heap.c sepostgresql-8.2.4/src/backend/catalog/heap.c ---- postgresql-8.2.4/src/backend/catalog/heap.c 2006-11-06 07:42:08.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/heap.c 2007-05-15 21:45:21.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 postgresql-8.2.4/src/backend/catalog/index.c sepostgresql-8.2.4/src/backend/catalog/index.c ---- postgresql-8.2.4/src/backend/catalog/index.c 2006-10-04 09:29:50.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/index.c 2007-05-15 21:45:21.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 postgresql-8.2.4/src/backend/catalog/pg_aggregate.c sepostgresql-8.2.4/src/backend/catalog/pg_aggregate.c ---- postgresql-8.2.4/src/backend/catalog/pg_aggregate.c 2006-10-04 09:29:50.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/pg_aggregate.c 2007-05-15 15:51:51.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 postgresql-8.2.4/src/backend/catalog/pg_largeobject.c sepostgresql-8.2.4/src/backend/catalog/pg_largeobject.c ---- postgresql-8.2.4/src/backend/catalog/pg_largeobject.c 2006-07-14 23:52:17.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/pg_largeobject.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/catalog/pg_proc.c sepostgresql-8.2.4/src/backend/catalog/pg_proc.c ---- postgresql-8.2.4/src/backend/catalog/pg_proc.c 2006-10-20 03:32:46.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/pg_proc.c 2007-05-17 23:32:22.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 postgresql-8.2.4/src/backend/catalog/toasting.c sepostgresql-8.2.4/src/backend/catalog/toasting.c ---- postgresql-8.2.4/src/backend/catalog/toasting.c 2006-10-04 09:29:50.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/catalog/toasting.c 2007-05-15 21:45:21.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 postgresql-8.2.4/src/backend/commands/cluster.c sepostgresql-8.2.4/src/backend/commands/cluster.c ---- postgresql-8.2.4/src/backend/commands/cluster.c 2006-10-04 09:29:50.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/cluster.c 2007-05-15 21:45:21.000000000 +0900 -@@ -615,7 +615,8 @@ make_new_heap(Oid OIDOldHeap, const char - 0, - ONCOMMIT_NOOP, - reloptions, -- allowSystemTableMods); -+ allowSystemTableMods, -+ NIL); - - ReleaseSysCache(tuple); - -diff -rpNU3 postgresql-8.2.4/src/backend/commands/copy.c sepostgresql-8.2.4/src/backend/commands/copy.c ---- postgresql-8.2.4/src/backend/commands/copy.c 2006-10-07 02:13:58.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/copy.c 2007-05-22 00:50:16.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 postgresql-8.2.4/src/backend/commands/dbcommands.c sepostgresql-8.2.4/src/backend/commands/dbcommands.c ---- postgresql-8.2.4/src/backend/commands/dbcommands.c 2007-04-13 00:04:41.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/dbcommands.c 2007-05-17 23:32:22.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 postgresql-8.2.4/src/backend/commands/functioncmds.c sepostgresql-8.2.4/src/backend/commands/functioncmds.c ---- postgresql-8.2.4/src/backend/commands/functioncmds.c 2006-10-07 02:13:58.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/functioncmds.c 2007-05-17 23:32:22.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 postgresql-8.2.4/src/backend/commands/lockcmds.c sepostgresql-8.2.4/src/backend/commands/lockcmds.c ---- postgresql-8.2.4/src/backend/commands/lockcmds.c 2006-08-19 01:09:08.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/lockcmds.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/commands/proclang.c sepostgresql-8.2.4/src/backend/commands/proclang.c ---- postgresql-8.2.4/src/backend/commands/proclang.c 2006-10-04 09:29:51.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/proclang.c 2007-05-15 15:51:51.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 postgresql-8.2.4/src/backend/commands/tablecmds.c sepostgresql-8.2.4/src/backend/commands/tablecmds.c ---- postgresql-8.2.4/src/backend/commands/tablecmds.c 2007-02-02 09:07:27.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/tablecmds.c 2007-05-16 01:14:32.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" -@@ -434,7 +435,8 @@ DefineRelation(CreateStmt *stmt, char re - parentOidCount, - stmt->oncommit, - reloptions, -- allowSystemTableMods); -+ allowSystemTableMods, -+ pgaceBuildAttrListForRelation(stmt)); - - StoreCatalogInheritance(relationId, inheritOids); - -@@ -2185,6 +2187,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 */ -@@ -2374,6 +2377,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 postgresql-8.2.4/src/backend/commands/trigger.c sepostgresql-8.2.4/src/backend/commands/trigger.c ---- postgresql-8.2.4/src/backend/commands/trigger.c 2007-01-25 13:17:56.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/commands/trigger.c 2007-06-23 19:56:29.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 postgresql-8.2.4/src/backend/executor/execMain.c sepostgresql-8.2.4/src/backend/executor/execMain.c ---- postgresql-8.2.4/src/backend/executor/execMain.c 2007-02-02 09:07:27.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/executor/execMain.c 2007-06-26 02:08:29.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 postgresql-8.2.4/src/backend/executor/execQual.c sepostgresql-8.2.4/src/backend/executor/execQual.c ---- postgresql-8.2.4/src/backend/executor/execQual.c 2007-02-07 02:35:27.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/executor/execQual.c 2007-04-11 03:14:48.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" -@@ -1668,6 +1669,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 postgresql-8.2.4/src/backend/libpq/be-fsstubs.c sepostgresql-8.2.4/src/backend/libpq/be-fsstubs.c ---- postgresql-8.2.4/src/backend/libpq/be-fsstubs.c 2006-09-08 00:37:25.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/libpq/be-fsstubs.c 2007-04-10 22:23:13.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 postgresql-8.2.4/src/backend/nodes/copyfuncs.c sepostgresql-8.2.4/src/backend/nodes/copyfuncs.c ---- postgresql-8.2.4/src/backend/nodes/copyfuncs.c 2006-11-06 07:42:08.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/nodes/copyfuncs.c 2007-04-10 02:21:12.000000000 +0900 -@@ -24,6 +24,7 @@ - - #include "nodes/plannodes.h" - #include "nodes/relation.h" -+#include "security/pgace.h" - #include "utils/datum.h" - - -@@ -1714,6 +1715,7 @@ _copyQuery(Query *from) - COPY_NODE_FIELD(setOperations); - COPY_NODE_FIELD(resultRelations); - COPY_NODE_FIELD(returningLists); -+ COPY_NODE_FIELD(pgaceList); - - return newnode; - } -@@ -3342,6 +3344,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 postgresql-8.2.4/src/backend/nodes/outfuncs.c sepostgresql-8.2.4/src/backend/nodes/outfuncs.c ---- postgresql-8.2.4/src/backend/nodes/outfuncs.c 2006-09-20 07:49:52.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/nodes/outfuncs.c 2007-04-10 02:21:12.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" - - -@@ -2190,6 +2191,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 postgresql-8.2.4/src/backend/parser/analyze.c sepostgresql-8.2.4/src/backend/parser/analyze.c ---- postgresql-8.2.4/src/backend/parser/analyze.c 2006-10-12 01:42:59.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/parser/analyze.c 2007-04-07 15:10:06.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); -@@ -2146,6 +2151,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 postgresql-8.2.4/src/backend/parser/gram.y sepostgresql-8.2.4/src/backend/parser/gram.y ---- postgresql-8.2.4/src/backend/parser/gram.y 2006-11-06 07:42:09.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/parser/gram.y 2007-05-15 21:45:21.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 OptTableSpace OptConsTableSpace OptTableSpaceOwner - %type opt_check_option - -+%type 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 CONTEXT = '...' */ -+ | SecurityLabelItem -+ { -+ AlterTableCmd *n = makeNode(AlterTableCmd); -+ n->subtype = AT_SetSecurityLabel; -+ n->name = NULL; -+ n->def = (Node *) $1; -+ $$ = (Node *) n; -+ } -+ /* ALTER TABLE ALTER [COLUMN] 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 (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 postgresql-8.2.4/src/backend/parser/parse_target.c sepostgresql-8.2.4/src/backend/parser/parse_target.c ---- postgresql-8.2.4/src/backend/parser/parse_target.c 2006-10-04 09:29:56.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/parser/parse_target.c 2007-04-10 02:23:28.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 postgresql-8.2.4/src/backend/postmaster/postmaster.c sepostgresql-8.2.4/src/backend/postmaster/postmaster.c ---- postgresql-8.2.4/src/backend/postmaster/postmaster.c 2007-02-12 00:12:21.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/postmaster/postmaster.c 2007-04-29 13:49:53.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" -@@ -960,6 +961,9 @@ PostmasterMain(int argc, char *argv[]) - */ - StartupPID = StartupDataBase(); - -+ if (!pgaceInitializePostmaster()) -+ ExitPostmaster(1); -+ - status = ServerLoop(); - - /* -@@ -1982,9 +1986,11 @@ pmdie(SIGNAL_ARGS) - signal_child(PgStatPID, SIGQUIT); - if (DLGetHead(BackendList)) - SignalChildren(SIGQUIT); -+ pgaceFinalizePostmaster(); - ExitPostmaster(0); - break; - } -+ pgaceFinalizePostmaster(); - - PG_SETMASK(&UnBlockSig); - -diff -rpNU3 postgresql-8.2.4/src/backend/rewrite/rewriteHandler.c sepostgresql-8.2.4/src/backend/rewrite/rewriteHandler.c ---- postgresql-8.2.4/src/backend/rewrite/rewriteHandler.c 2007-03-02 03:50:36.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/rewrite/rewriteHandler.c 2007-04-29 13:49:53.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 postgresql-8.2.4/src/backend/security/Makefile sepostgresql-8.2.4/src/backend/security/Makefile ---- postgresql-8.2.4/src/backend/security/Makefile 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/Makefile 2007-05-26 15:04:24.000000000 +0900 -@@ -0,0 +1,31 @@ -+# -+# src/backend/security/Makefile -+# Makefile for Security Enhanced PostgreSQL -+# -+# Copyright (c) 2006 - 2007 KaiGai Kohei -+# -+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 postgresql-8.2.4/src/backend/security/pgaceCommon.c sepostgresql-8.2.4/src/backend/security/pgaceCommon.c ---- postgresql-8.2.4/src/backend/security/pgaceCommon.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/pgaceCommon.c 2007-06-22 02:22:56.000000000 +0900 -@@ -0,0 +1,764 @@ -+/* -+ * src/backend/security/pgaceCommon.c -+ * Common part of PostgreSQL Access Control Extension -+ * Copyright 2007 KaiGai Kohei -+ */ -+#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 -+#include -+ -+#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 [ALTER ] 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 postgresql-8.2.4/src/backend/security/sepgsqlCore.c sepostgresql-8.2.4/src/backend/security/sepgsqlCore.c ---- postgresql-8.2.4/src/backend/security/sepgsqlCore.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/sepgsqlCore.c 2007-08-09 17:28:31.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 -+ */ -+#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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 postgresql-8.2.4/src/backend/security/sepgsqlHooks.c sepostgresql-8.2.4/src/backend/security/sepgsqlHooks.c ---- postgresql-8.2.4/src/backend/security/sepgsqlHooks.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/sepgsqlHooks.c 2007-08-09 17:28:31.000000000 +0900 -@@ -0,0 +1,668 @@ -+/* -+ * src/backend/sepgsqlHooks.c -+ * SE-PostgreSQL hooks -+ * -+ * Copyright 2007 KaiGai Kohei -+ */ -+#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 -+#include -+#include -+#include -+ -+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; -+ char *result; -+ -+ if (selinux_trans_to_raw_context(context, &raw_context)) -+ selerror("could not translate MLS label"); -+ PG_TRY(); -+ { -+ result = pstrdup(raw_context); -+ } -+ PG_CATCH(); -+ { -+ freecon(raw_context); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(raw_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 postgresql-8.2.4/src/backend/security/sepgsqlPerms.c sepostgresql-8.2.4/src/backend/security/sepgsqlPerms.c ---- postgresql-8.2.4/src/backend/security/sepgsqlPerms.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/sepgsqlPerms.c 2007-08-09 17:28:31.000000000 +0900 -@@ -0,0 +1,489 @@ -+/* -+ * src/backend/security/sepgsqlPerms.c -+ * SE-PostgreSQL permission checking functions -+ * -+ * Copyright (c) 2007 KaiGai Kohei -+ */ -+#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; -+ -+ /* <-- database:module_install --> */ -+ sepgsql_avc_permission(sepgsqlGetClientContext(), -+ sepgsqlGetDatabaseContext(), -+ SECCLASS_DB_DATABASE, -+ DB_DATABASE__INSTALL_MODULE, -+ NULL); -+ -+ /* <-- database:module_install --> */ -+ 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 postgresql-8.2.4/src/backend/security/sepgsqlProxy.c sepostgresql-8.2.4/src/backend/security/sepgsqlProxy.c ---- postgresql-8.2.4/src/backend/security/sepgsqlProxy.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/security/sepgsqlProxy.c 2007-08-09 17:28:31.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 -+ */ -+#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<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<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 postgresql-8.2.4/src/backend/storage/ipc/ipci.c sepostgresql-8.2.4/src/backend/storage/ipc/ipci.c ---- postgresql-8.2.4/src/backend/storage/ipc/ipci.c 2006-10-16 07:04:07.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/storage/ipc/ipci.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/storage/large_object/inv_api.c sepostgresql-8.2.4/src/backend/storage/large_object/inv_api.c ---- postgresql-8.2.4/src/backend/storage/large_object/inv_api.c 2006-09-08 00:37:25.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/storage/large_object/inv_api.c 2007-04-10 22:23:13.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 postgresql-8.2.4/src/backend/tcop/fastpath.c sepostgresql-8.2.4/src/backend/tcop/fastpath.c ---- postgresql-8.2.4/src/backend/tcop/fastpath.c 2006-10-20 07:44:11.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/tcop/fastpath.c 2007-04-11 03:14:48.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 postgresql-8.2.4/src/backend/tcop/postgres.c sepostgresql-8.2.4/src/backend/tcop/postgres.c ---- postgresql-8.2.4/src/backend/tcop/postgres.c 2007-01-04 09:58:01.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/tcop/postgres.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/tcop/pquery.c sepostgresql-8.2.4/src/backend/tcop/pquery.c ---- postgresql-8.2.4/src/backend/tcop/pquery.c 2007-02-19 04:49:30.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/tcop/pquery.c 2007-04-29 13:49:53.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 postgresql-8.2.4/src/backend/utils/adt/ri_triggers.c sepostgresql-8.2.4/src/backend/utils/adt/ri_triggers.c ---- postgresql-8.2.4/src/backend/utils/adt/ri_triggers.c 2006-10-04 09:29:59.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/utils/adt/ri_triggers.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/utils/cache/syscache.c sepostgresql-8.2.4/src/backend/utils/cache/syscache.c ---- postgresql-8.2.4/src/backend/utils/cache/syscache.c 2006-10-07 03:23:35.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/utils/cache/syscache.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/utils/fmgr/dfmgr.c sepostgresql-8.2.4/src/backend/utils/fmgr/dfmgr.c ---- postgresql-8.2.4/src/backend/utils/fmgr/dfmgr.c 2006-10-07 02:13:59.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/utils/fmgr/dfmgr.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/utils/init/postinit.c sepostgresql-8.2.4/src/backend/utils/init/postinit.c ---- postgresql-8.2.4/src/backend/utils/init/postinit.c 2006-11-06 07:42:09.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/utils/init/postinit.c 2007-04-07 15:10:06.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 postgresql-8.2.4/src/backend/utils/misc/guc.c sepostgresql-8.2.4/src/backend/utils/misc/guc.c ---- postgresql-8.2.4/src/backend/utils/misc/guc.c 2006-11-29 23:50:07.000000000 +0900 -+++ sepostgresql-8.2.4/src/backend/utils/misc/guc.c 2007-04-07 15:10:06.000000000 +0900 -@@ -50,6 +50,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" -@@ -4566,6 +4567,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, -@@ -4828,6 +4832,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 -@@ -4872,6 +4879,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 postgresql-8.2.4/src/bin/pg_dump/pg_dump.c sepostgresql-8.2.4/src/bin/pg_dump/pg_dump.c ---- postgresql-8.2.4/src/bin/pg_dump/pg_dump.c 2007-04-17 03:42:17.000000000 +0900 -+++ sepostgresql-8.2.4/src/bin/pg_dump/pg_dump.c 2007-08-18 04:05:24.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 postgresql-8.2.4/src/bin/pg_dump/pg_dump.h sepostgresql-8.2.4/src/bin/pg_dump/pg_dump.h ---- postgresql-8.2.4/src/bin/pg_dump/pg_dump.h 2007-02-20 00:05:21.000000000 +0900 -+++ sepostgresql-8.2.4/src/bin/pg_dump/pg_dump.h 2007-08-18 04:05:24.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 postgresql-8.2.4/src/bin/pg_dump/pg_dumpall.c sepostgresql-8.2.4/src/bin/pg_dump/pg_dumpall.c ---- postgresql-8.2.4/src/bin/pg_dump/pg_dumpall.c 2006-11-22 07:19:46.000000000 +0900 -+++ sepostgresql-8.2.4/src/bin/pg_dump/pg_dumpall.c 2007-08-18 04:05:24.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")); -@@ -792,16 +806,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), " -@@ -810,7 +826,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), " -@@ -819,7 +835,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), " -@@ -835,7 +851,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), " -@@ -845,6 +861,7 @@ dumpCreateDB(PGconn *conn) - "FROM pg_database d " - "ORDER BY 1"); - } -+ res = executeQuery(conn, buf->data); - - for (i = 0; i < PQntuples(res); i++) - { -@@ -855,6 +872,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)); -@@ -898,6 +916,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 postgresql-8.2.4/src/include/access/htup.h sepostgresql-8.2.4/src/include/access/htup.h ---- postgresql-8.2.4/src/include/access/htup.h 2006-11-06 07:42:10.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/access/htup.h 2007-04-10 02:49:22.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 postgresql-8.2.4/src/include/catalog/heap.h sepostgresql-8.2.4/src/include/catalog/heap.h ---- postgresql-8.2.4/src/include/catalog/heap.h 2006-07-14 01:49:19.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/heap.h 2007-05-15 21:45:21.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 postgresql-8.2.4/src/include/catalog/indexing.h sepostgresql-8.2.4/src/include/catalog/indexing.h ---- postgresql-8.2.4/src/include/catalog/indexing.h 2006-07-14 02:47:01.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/indexing.h 2007-04-07 15:10:06.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 postgresql-8.2.4/src/include/catalog/pg_attribute.h sepostgresql-8.2.4/src/include/catalog/pg_attribute.h ---- postgresql-8.2.4/src/include/catalog/pg_attribute.h 2006-11-06 07:42:10.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/pg_attribute.h 2007-04-07 15:10:06.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 postgresql-8.2.4/src/include/catalog/pg_cast.h sepostgresql-8.2.4/src/include/catalog/pg_cast.h ---- postgresql-8.2.4/src/include/catalog/pg_cast.h 2006-03-06 00:58:54.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/pg_cast.h 2007-04-28 18:41:09.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 postgresql-8.2.4/src/include/catalog/pg_proc.h sepostgresql-8.2.4/src/include/catalog/pg_proc.h ---- postgresql-8.2.4/src/include/catalog/pg_proc.h 2006-11-29 04:18:44.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/pg_proc.h 2007-05-26 13:19:59.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 25 "3403" _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 3403 "25" _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 postgresql-8.2.4/src/include/catalog/pg_security.h sepostgresql-8.2.4/src/include/catalog/pg_security.h ---- postgresql-8.2.4/src/include/catalog/pg_security.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/pg_security.h 2007-04-07 15:26:44.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 -+ */ -+#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 postgresql-8.2.4/src/include/catalog/pg_type.h sepostgresql-8.2.4/src/include/catalog/pg_type.h ---- postgresql-8.2.4/src/include/catalog/pg_type.h 2006-12-28 10:09:04.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/catalog/pg_type.h 2007-04-07 15:10:06.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 postgresql-8.2.4/src/include/executor/tuptable.h sepostgresql-8.2.4/src/include/executor/tuptable.h ---- postgresql-8.2.4/src/include/executor/tuptable.h 2006-10-04 09:30:08.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/executor/tuptable.h 2007-04-07 15:10:06.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 postgresql-8.2.4/src/include/fmgr.h sepostgresql-8.2.4/src/include/fmgr.h ---- postgresql-8.2.4/src/include/fmgr.h 2006-10-04 09:30:06.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/fmgr.h 2007-04-11 03:14:48.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 postgresql-8.2.4/src/include/libpq/be-fsstubs.h sepostgresql-8.2.4/src/include/libpq/be-fsstubs.h ---- postgresql-8.2.4/src/include/libpq/be-fsstubs.h 2006-09-08 00:37:25.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/libpq/be-fsstubs.h 2007-02-17 01:25:55.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 postgresql-8.2.4/src/include/nodes/parsenodes.h sepostgresql-8.2.4/src/include/nodes/parsenodes.h ---- postgresql-8.2.4/src/include/nodes/parsenodes.h 2006-11-06 07:42:10.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/nodes/parsenodes.h 2007-05-15 21:45:21.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 postgresql-8.2.4/src/include/pg_config.h.in sepostgresql-8.2.4/src/include/pg_config.h.in ---- postgresql-8.2.4/src/include/pg_config.h.in 2006-11-06 12:44:38.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/pg_config.h.in 2007-04-10 02:23:28.000000000 +0900 -@@ -337,6 +337,9 @@ - /* Define to 1 if you have the 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 - -@@ -595,6 +598,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 postgresql-8.2.4/src/include/security/pgace.h sepostgresql-8.2.4/src/include/security/pgace.h ---- postgresql-8.2.4/src/include/security/pgace.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/security/pgace.h 2007-06-26 02:08:29.000000000 +0900 -@@ -0,0 +1,643 @@ -+/* -+ * include/security/pgace.h -+ * headers for PostgreSQL Access Control Extensions (PGACE) -+ * Copyright 2007 KaiGai Kohei -+ */ -+#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 string -+ * @value : given 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 postgresql-8.2.4/src/include/security/sepgsql.h sepostgresql-8.2.4/src/include/security/sepgsql.h ---- postgresql-8.2.4/src/include/security/sepgsql.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/security/sepgsql.h 2007-06-30 03:25:54.000000000 +0900 -@@ -0,0 +1,330 @@ -+/* -+ * src/include/sepgsql.h -+ * The header file of Security Enhanced PostgreSQL -+ * -+ * Copyright (c) 2006 - 2007, KaiGai Kohei -+ */ -+#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 postgresql-8.2.4/src/include/security/sepgsql_internal.h sepostgresql-8.2.4/src/include/security/sepgsql_internal.h ---- postgresql-8.2.4/src/include/security/sepgsql_internal.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/security/sepgsql_internal.h 2007-08-09 17:28:31.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 -+#include -+#include -+ -+#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 postgresql-8.2.4/src/include/utils/syscache.h sepostgresql-8.2.4/src/include/utils/syscache.h ---- postgresql-8.2.4/src/include/utils/syscache.h 2006-07-14 03:01:02.000000000 +0900 -+++ sepostgresql-8.2.4/src/include/utils/syscache.h 2007-04-07 15:10:06.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); diff --git a/sepostgresql-8.2.5-1.patch b/sepostgresql-8.2.5-1.patch deleted file mode 100644 index fb5227c..0000000 --- a/sepostgresql-8.2.5-1.patch +++ /dev/null @@ -1,8585 +0,0 @@ -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 OptTableSpace OptConsTableSpace OptTableSpaceOwner - %type opt_check_option - -+%type 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 CONTEXT = '...' */ -+ | SecurityLabelItem -+ { -+ AlterTableCmd *n = makeNode(AlterTableCmd); -+ n->subtype = AT_SetSecurityLabel; -+ n->name = NULL; -+ n->def = (Node *) $1; -+ $$ = (Node *) n; -+ } -+ /* ALTER TABLE ALTER [COLUMN] 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 (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 -+# -+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 -+ */ -+#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 -+#include -+ -+#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 [ALTER ] 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 -+ */ -+#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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 -+ */ -+#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 -+#include -+#include -+#include -+ -+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 -+ */ -+#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; -+ -+ /* <-- database:module_install --> */ -+ sepgsql_avc_permission(sepgsqlGetClientContext(), -+ sepgsqlGetDatabaseContext(), -+ SECCLASS_DB_DATABASE, -+ DB_DATABASE__INSTALL_MODULE, -+ NULL); -+ -+ /* <-- database:module_install --> */ -+ 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 -+ */ -+#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<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<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 -+ */ -+#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 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 -+ */ -+#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 string -+ * @value : given 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 -+ */ -+#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 -+#include -+#include -+ -+#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);