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