diff --git a/.cvsignore b/.cvsignore index 02d7344..54ba6ee 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,2 +1 @@ -postgresql-8.4.2.tar.bz2 -postgresql-8.4.3.tar.bz2 +postgresql-9.0alpha5.tar.bz2 diff --git a/pgsql-01-8.4-blobs.patch b/pgsql-01-8.4-blobs.patch deleted file mode 100644 index b2ef970..0000000 --- a/pgsql-01-8.4-blobs.patch +++ /dev/null @@ -1,2600 +0,0 @@ -diff -Nrpc base/contrib/lo/lo_test.sql blob/contrib/lo/lo_test.sql -*** base/contrib/lo/lo_test.sql Sat Nov 17 20:15:40 2007 ---- blob/contrib/lo/lo_test.sql Fri Dec 18 09:40:55 2009 -*************** SET search_path = public; -*** 12,18 **** - -- - - -- Check what is in pg_largeobject -! SELECT count(DISTINCT loid) FROM pg_largeobject; - - -- ignore any errors here - simply drop the table if it already exists - DROP TABLE a; ---- 12,18 ---- - -- - - -- Check what is in pg_largeobject -! SELECT count(oid) FROM pg_largeobject_metadata; - - -- ignore any errors here - simply drop the table if it already exists - DROP TABLE a; -*************** DELETE FROM a; -*** 74,79 **** - DROP TABLE a; - - -- Check what is in pg_largeobject ... if different from original, trouble -! SELECT count(DISTINCT loid) FROM pg_largeobject; - - -- end of tests ---- 74,79 ---- - DROP TABLE a; - - -- Check what is in pg_largeobject ... if different from original, trouble -! SELECT count(oid) FROM pg_largeobject_metadata; - - -- end of tests -diff -Nrpc base/contrib/vacuumlo/vacuumlo.c blob/contrib/vacuumlo/vacuumlo.c -*** base/contrib/vacuumlo/vacuumlo.c Mon Mar 2 13:43:07 2009 ---- blob/contrib/vacuumlo/vacuumlo.c Fri Dec 18 09:40:55 2009 -*************** vacuumlo(char *database, struct _param * -*** 142,148 **** - */ - buf[0] = '\0'; - strcat(buf, "CREATE TEMP TABLE vacuum_l AS "); -! strcat(buf, "SELECT DISTINCT loid AS lo FROM pg_largeobject "); - res = PQexec(conn, buf); - if (PQresultStatus(res) != PGRES_COMMAND_OK) - { ---- 142,151 ---- - */ - buf[0] = '\0'; - strcat(buf, "CREATE TEMP TABLE vacuum_l AS "); -! if (PQserverVersion(conn) >= 80500) -! strcat(buf, "SELECT oid AS lo FROM pg_largeobject_metadata"); -! else -! strcat(buf, "SELECT DISTINCT loid AS lo FROM pg_largeobject"); - res = PQexec(conn, buf); - if (PQresultStatus(res) != PGRES_COMMAND_OK) - { -diff -Nrpc base/src/backend/catalog/Makefile blob/src/backend/catalog/Makefile -*** base/src/backend/catalog/Makefile Wed May 13 11:30:07 2009 ---- blob/src/backend/catalog/Makefile Fri Dec 18 09:40:55 2009 -*************** POSTGRES_BKI_SRCS = $(addprefix $(top_sr -*** 29,37 **** - pg_proc.h pg_type.h pg_attribute.h pg_class.h \ - pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \ - pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \ -! pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \ -! pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \ -! pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \ - pg_database.h pg_tablespace.h pg_pltemplate.h \ - pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \ - pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ ---- 29,37 ---- - pg_proc.h pg_type.h pg_attribute.h pg_class.h \ - pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \ - pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \ -! pg_language.h pg_largeobject_metadata.h pg_largeobject.h pg_aggregate.h \ -! pg_statistic.h pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h \ -! pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \ - pg_database.h pg_tablespace.h pg_pltemplate.h \ - pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \ - pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ -diff -Nrpc base/src/backend/catalog/aclchk.c blob/src/backend/catalog/aclchk.c -*** base/src/backend/catalog/aclchk.c Thu Mar 18 01:40:54 2010 ---- blob/src/backend/catalog/aclchk.c Thu Mar 18 09:43:03 2010 -*************** -*** 30,35 **** ---- 30,37 ---- - #include "catalog/pg_foreign_data_wrapper.h" - #include "catalog/pg_foreign_server.h" - #include "catalog/pg_language.h" -+ #include "catalog/pg_largeobject.h" -+ #include "catalog/pg_largeobject_metadata.h" - #include "catalog/pg_namespace.h" - #include "catalog/pg_opclass.h" - #include "catalog/pg_operator.h" -*************** static void ExecGrant_Fdw(InternalGrant -*** 57,62 **** ---- 59,65 ---- - static void ExecGrant_ForeignServer(InternalGrant *grantStmt); - static void ExecGrant_Function(InternalGrant *grantStmt); - static void ExecGrant_Language(InternalGrant *grantStmt); -+ static void ExecGrant_Largeobject(InternalGrant *grantStmt); - static void ExecGrant_Namespace(InternalGrant *grantStmt); - static void ExecGrant_Tablespace(InternalGrant *grantStmt); - -*************** restrict_and_check_grant(bool is_grant, -*** 200,205 **** ---- 203,211 ---- - case ACL_KIND_LANGUAGE: - whole_mask = ACL_ALL_RIGHTS_LANGUAGE; - break; -+ case ACL_KIND_LARGEOBJECT: -+ whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT; -+ break; - case ACL_KIND_NAMESPACE: - whole_mask = ACL_ALL_RIGHTS_NAMESPACE; - break; -*************** ExecuteGrantStmt(GrantStmt *stmt) -*** 380,385 **** ---- 386,395 ---- - all_privileges = ACL_ALL_RIGHTS_LANGUAGE; - errormsg = gettext_noop("invalid privilege type %s for language"); - break; -+ case ACL_OBJECT_LARGEOBJECT: -+ all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT; -+ errormsg = gettext_noop("invalid privilege type %s for large object"); -+ break; - case ACL_OBJECT_NAMESPACE: - all_privileges = ACL_ALL_RIGHTS_NAMESPACE; - errormsg = gettext_noop("invalid privilege type %s for schema"); -*************** ExecGrantStmt_oids(InternalGrant *istmt) -*** 485,490 **** ---- 495,503 ---- - case ACL_OBJECT_LANGUAGE: - ExecGrant_Language(istmt); - break; -+ case ACL_OBJECT_LARGEOBJECT: -+ ExecGrant_Largeobject(istmt); -+ break; - case ACL_OBJECT_NAMESPACE: - ExecGrant_Namespace(istmt); - break; -*************** objectNamesToOids(GrantObjectType objtyp -*** 569,574 **** ---- 582,601 ---- - ReleaseSysCache(tuple); - } - break; -+ case ACL_OBJECT_LARGEOBJECT: -+ foreach(cell, objnames) -+ { -+ Oid lobjOid = intVal(lfirst(cell)); -+ -+ if (!LargeObjectExists(lobjOid)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_OBJECT), -+ errmsg("large object %u does not exist", -+ lobjOid))); -+ -+ objects = lappend_oid(objects, lobjOid); -+ } -+ break; - case ACL_OBJECT_NAMESPACE: - foreach(cell, objnames) - { -*************** ExecGrant_Language(InternalGrant *istmt) -*** 1782,1787 **** ---- 1809,1946 ---- - } - - static void -+ ExecGrant_Largeobject(InternalGrant *istmt) -+ { -+ Relation relation; -+ ListCell *cell; -+ -+ if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) -+ istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT; -+ -+ relation = heap_open(LargeObjectMetadataRelationId, -+ RowExclusiveLock); -+ -+ foreach(cell, istmt->objects) -+ { -+ Oid loid = lfirst_oid(cell); -+ Form_pg_largeobject_metadata form_lo_meta; -+ char loname[NAMEDATALEN]; -+ Datum aclDatum; -+ bool isNull; -+ AclMode avail_goptions; -+ AclMode this_privileges; -+ Acl *old_acl; -+ Acl *new_acl; -+ Oid grantorId; -+ Oid ownerId; -+ HeapTuple newtuple; -+ Datum values[Natts_pg_largeobject_metadata]; -+ bool nulls[Natts_pg_largeobject_metadata]; -+ bool replaces[Natts_pg_largeobject_metadata]; -+ int noldmembers; -+ int nnewmembers; -+ Oid *oldmembers; -+ Oid *newmembers; -+ ScanKeyData entry[1]; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ -+ /* There's no syscache for pg_largeobject_metadata */ -+ ScanKeyInit(&entry[0], -+ ObjectIdAttributeNumber, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(loid)); -+ -+ scan = systable_beginscan(relation, -+ LargeObjectMetadataOidIndexId, true, -+ SnapshotNow, 1, entry); -+ -+ tuple = systable_getnext(scan); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for large object %u", loid); -+ -+ form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple); -+ -+ /* -+ * Get owner ID and working copy of existing ACL. If there's no ACL, -+ * substitute the proper default. -+ */ -+ ownerId = form_lo_meta->lomowner; -+ aclDatum = heap_getattr(tuple, -+ Anum_pg_largeobject_metadata_lomacl, -+ RelationGetDescr(relation), &isNull); -+ if (isNull) -+ old_acl = acldefault(ACL_OBJECT_LARGEOBJECT, ownerId); -+ else -+ old_acl = DatumGetAclPCopy(aclDatum); -+ -+ /* Determine ID to do the grant as, and available grant options */ -+ select_best_grantor(GetUserId(), istmt->privileges, -+ old_acl, ownerId, -+ &grantorId, &avail_goptions); -+ -+ /* -+ * Restrict the privileges to what we can actually grant, and emit the -+ * standards-mandated warning and error messages. -+ */ -+ snprintf(loname, sizeof(loname), "large object %u", loid); -+ this_privileges = -+ restrict_and_check_grant(istmt->is_grant, avail_goptions, -+ istmt->all_privs, istmt->privileges, -+ loid, grantorId, ACL_KIND_LARGEOBJECT, -+ loname, 0, NULL); -+ -+ /* -+ * Generate new ACL. -+ * -+ * We need the members of both old and new ACLs so we can correct the -+ * shared dependency information. -+ */ -+ noldmembers = aclmembers(old_acl, &oldmembers); -+ -+ new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, -+ istmt->grant_option, istmt->behavior, -+ istmt->grantees, this_privileges, -+ grantorId, ownerId); -+ -+ nnewmembers = aclmembers(new_acl, &newmembers); -+ -+ /* finished building new ACL value, now insert it */ -+ MemSet(values, 0, sizeof(values)); -+ MemSet(nulls, false, sizeof(nulls)); -+ MemSet(replaces, false, sizeof(replaces)); -+ -+ replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true; -+ values[Anum_pg_largeobject_metadata_lomacl - 1] -+ = PointerGetDatum(new_acl); -+ -+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), -+ values, nulls, replaces); -+ -+ simple_heap_update(relation, &newtuple->t_self, newtuple); -+ -+ /* keep the catalog indexes up to date */ -+ CatalogUpdateIndexes(relation, newtuple); -+ -+ /* Update the shared dependency ACL info */ -+ updateAclDependencies(LargeObjectRelationId, -+ HeapTupleGetOid(tuple), 0, -+ ownerId, istmt->is_grant, -+ noldmembers, oldmembers, -+ nnewmembers, newmembers); -+ -+ systable_endscan(scan); -+ -+ pfree(new_acl); -+ -+ /* prevent error when processing duplicate objects */ -+ CommandCounterIncrement(); -+ } -+ -+ heap_close(relation, RowExclusiveLock); -+ } -+ -+ static void - ExecGrant_Namespace(InternalGrant *istmt) - { - Relation relation; -*************** static const char *const no_priv_msg[MAX -*** 2121,2126 **** ---- 2280,2287 ---- - gettext_noop("permission denied for type %s"), - /* ACL_KIND_LANGUAGE */ - gettext_noop("permission denied for language %s"), -+ /* ACL_KIND_LARGEOBJECT */ -+ gettext_noop("permission denied for large object %s"), - /* ACL_KIND_NAMESPACE */ - gettext_noop("permission denied for schema %s"), - /* ACL_KIND_OPCLASS */ -*************** static const char *const not_owner_msg[M -*** 2159,2164 **** ---- 2320,2327 ---- - gettext_noop("must be owner of type %s"), - /* ACL_KIND_LANGUAGE */ - gettext_noop("must be owner of language %s"), -+ /* ACL_KIND_LARGEOBJECT */ -+ gettext_noop("must be owner of large object %s"), - /* ACL_KIND_NAMESPACE */ - gettext_noop("must be owner of schema %s"), - /* ACL_KIND_OPCLASS */ -*************** pg_aclmask(AclObjectKind objkind, Oid ta -*** 2278,2283 **** ---- 2441,2449 ---- - return pg_proc_aclmask(table_oid, roleid, mask, how); - case ACL_KIND_LANGUAGE: - return pg_language_aclmask(table_oid, roleid, mask, how); -+ case ACL_KIND_LARGEOBJECT: -+ return pg_largeobject_aclmask_snapshot(table_oid, roleid, -+ mask, how, SnapshotNow); - case ACL_KIND_NAMESPACE: - return pg_namespace_aclmask(table_oid, roleid, mask, how); - case ACL_KIND_TABLESPACE: -*************** pg_language_aclmask(Oid lang_oid, Oid ro -*** 2661,2666 **** ---- 2827,2916 ---- - } - - /* -+ * Exported routine for examining a user's privileges for a largeobject -+ * -+ * The reason why this interface has an argument of snapshot is that -+ * we apply a snapshot available on lo_open(), not SnapshotNow, when -+ * it is opened as read-only mode. -+ * If we could see the metadata and data from inconsistent viewpoint, -+ * it will give us much confusion. So, we need to provide an interface -+ * which takes an argument of snapshot. -+ * -+ * If the caller refers a large object with a certain snapshot except -+ * for SnapshotNow, its permission checks should be also applied in -+ * the same snapshot. -+ */ -+ AclMode -+ pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, -+ AclMode mask, AclMaskHow how, -+ Snapshot snapshot) -+ { -+ AclMode result; -+ Relation pg_lo_meta; -+ ScanKeyData entry[1]; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ Datum aclDatum; -+ bool isNull; -+ Acl *acl; -+ Oid ownerId; -+ -+ /* Superusers bypass all permission checking. */ -+ if (superuser_arg(roleid)) -+ return mask; -+ -+ /* -+ * Get the largeobject's ACL from pg_language_metadata -+ */ -+ pg_lo_meta = heap_open(LargeObjectMetadataRelationId, -+ AccessShareLock); -+ -+ ScanKeyInit(&entry[0], -+ ObjectIdAttributeNumber, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(lobj_oid)); -+ -+ scan = systable_beginscan(pg_lo_meta, -+ LargeObjectMetadataOidIndexId, true, -+ snapshot, 1, entry); -+ -+ tuple = systable_getnext(scan); -+ if (!HeapTupleIsValid(tuple)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_OBJECT), -+ errmsg("large object %u does not exist", lobj_oid))); -+ -+ ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner; -+ -+ aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl, -+ RelationGetDescr(pg_lo_meta), &isNull); -+ -+ if (isNull) -+ { -+ /* No ACL, so build default ACL */ -+ acl = acldefault(ACL_OBJECT_LARGEOBJECT, ownerId); -+ aclDatum = (Datum) 0; -+ } -+ else -+ { -+ /* detoast ACL if necessary */ -+ acl = DatumGetAclP(aclDatum); -+ } -+ -+ result = aclmask(acl, roleid, ownerId, mask, how); -+ -+ /* if we have a detoasted copy, free it */ -+ if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) -+ pfree(acl); -+ -+ systable_endscan(scan); -+ -+ heap_close(pg_lo_meta, AccessShareLock); -+ -+ return result; -+ } -+ -+ /* - * Exported routine for examining a user's privileges for a namespace - */ - AclMode -*************** pg_language_aclcheck(Oid lang_oid, Oid r -*** 3111,3116 **** ---- 3361,3380 ---- - } - - /* -+ * Exported routine for checking a user's access privileges to a largeobject -+ */ -+ AclResult -+ pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode, -+ Snapshot snapshot) -+ { -+ if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode, -+ ACLMASK_ANY, snapshot) != 0) -+ return ACLCHECK_OK; -+ else -+ return ACLCHECK_NO_PRIV; -+ } -+ -+ /* - * Exported routine for checking a user's access privileges to a namespace - */ - AclResult -*************** pg_language_ownercheck(Oid lan_oid, Oid -*** 3301,3306 **** ---- 3565,3617 ---- - } - - /* -+ * Ownership check for a largeobject (specified by OID) -+ * -+ * Note that we have no candidate to call this routine with a certain -+ * snapshot except for SnapshotNow, so we don't provide an interface -+ * with _snapshot() version now. -+ */ -+ bool -+ pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid) -+ { -+ Relation pg_lo_meta; -+ ScanKeyData entry[1]; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ Oid ownerId; -+ -+ /* Superusers bypass all permission checking. */ -+ if (superuser_arg(roleid)) -+ return true; -+ -+ /* There's no syscache for pg_largeobject_metadata */ -+ pg_lo_meta = heap_open(LargeObjectMetadataRelationId, -+ AccessShareLock); -+ -+ ScanKeyInit(&entry[0], -+ ObjectIdAttributeNumber, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(lobj_oid)); -+ -+ scan = systable_beginscan(pg_lo_meta, -+ LargeObjectMetadataOidIndexId, true, -+ SnapshotNow, 1, entry); -+ -+ tuple = systable_getnext(scan); -+ if (!HeapTupleIsValid(tuple)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_OBJECT), -+ errmsg("large object %u does not exist", lobj_oid))); -+ -+ ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner; -+ -+ systable_endscan(scan); -+ heap_close(pg_lo_meta, AccessShareLock); -+ -+ return has_privs_of_role(roleid, ownerId); -+ } -+ -+ /* - * Ownership check for a namespace (specified by OID). - */ - bool -diff -Nrpc base/src/backend/catalog/dependency.c blob/src/backend/catalog/dependency.c -*** base/src/backend/catalog/dependency.c Tue Dec 15 17:16:51 2009 ---- blob/src/backend/catalog/dependency.c Fri Dec 18 09:40:55 2009 -*************** -*** 36,41 **** ---- 36,42 ---- - #include "catalog/pg_foreign_data_wrapper.h" - #include "catalog/pg_foreign_server.h" - #include "catalog/pg_language.h" -+ #include "catalog/pg_largeobject.h" - #include "catalog/pg_namespace.h" - #include "catalog/pg_opclass.h" - #include "catalog/pg_operator.h" -*************** static const Oid object_classes[MAX_OCLA -*** 129,134 **** ---- 130,136 ---- - ConversionRelationId, /* OCLASS_CONVERSION */ - AttrDefaultRelationId, /* OCLASS_DEFAULT */ - LanguageRelationId, /* OCLASS_LANGUAGE */ -+ LargeObjectRelationId, /* OCLASS_LARGEOBJECT */ - OperatorRelationId, /* OCLASS_OPERATOR */ - OperatorClassRelationId, /* OCLASS_OPCLASS */ - OperatorFamilyRelationId, /* OCLASS_OPFAMILY */ -*************** doDeletion(const ObjectAddress *object) -*** 1071,1076 **** ---- 1073,1082 ---- - DropProceduralLanguageById(object->objectId); - break; - -+ case OCLASS_LARGEOBJECT: -+ LargeObjectDrop(object->objectId); -+ break; -+ - case OCLASS_OPERATOR: - RemoveOperatorById(object->objectId); - break; -*************** getObjectClass(const ObjectAddress *obje -*** 1984,1989 **** ---- 1990,1999 ---- - Assert(object->objectSubId == 0); - return OCLASS_LANGUAGE; - -+ case LargeObjectRelationId: -+ Assert(object->objectSubId == 0); -+ return OCLASS_LARGEOBJECT; -+ - case OperatorRelationId: - Assert(object->objectSubId == 0); - return OCLASS_OPERATOR; -*************** getObjectDescription(const ObjectAddress -*** 2232,2237 **** ---- 2242,2251 ---- - ReleaseSysCache(langTup); - break; - } -+ case OCLASS_LARGEOBJECT: -+ appendStringInfo(&buffer, _("large object %u"), -+ object->objectId); -+ break; - - case OCLASS_OPERATOR: - appendStringInfo(&buffer, _("operator %s"), -diff -Nrpc base/src/backend/catalog/pg_largeobject.c blob/src/backend/catalog/pg_largeobject.c -*** base/src/backend/catalog/pg_largeobject.c Sat Jan 3 13:01:35 2009 ---- blob/src/backend/catalog/pg_largeobject.c Fri Dec 18 09:40:55 2009 -*************** -*** 16,23 **** ---- 16,31 ---- - - #include "access/genam.h" - #include "access/heapam.h" -+ #include "access/sysattr.h" -+ #include "catalog/catalog.h" -+ #include "catalog/dependency.h" - #include "catalog/indexing.h" -+ #include "catalog/pg_authid.h" - #include "catalog/pg_largeobject.h" -+ #include "catalog/pg_largeobject_metadata.h" -+ #include "catalog/toasting.h" -+ #include "miscadmin.h" -+ #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" - #include "utils/rel.h" -*************** -*** 27,139 **** - /* - * Create a large object having the given LO identifier. - * -! * We do this by inserting an empty first page, so that the object will -! * appear to exist with size 0. Note that the unique index will reject -! * an attempt to create a duplicate page. - */ -! void - LargeObjectCreate(Oid loid) - { -! Relation pg_largeobject; - HeapTuple ntup; -! Datum values[Natts_pg_largeobject]; -! bool nulls[Natts_pg_largeobject]; -! int i; - -! pg_largeobject = heap_open(LargeObjectRelationId, RowExclusiveLock); - - /* -! * Form new tuple - */ -! for (i = 0; i < Natts_pg_largeobject; i++) -! { -! values[i] = (Datum) NULL; -! nulls[i] = false; -! } - -! i = 0; -! values[i++] = ObjectIdGetDatum(loid); -! values[i++] = Int32GetDatum(0); -! values[i++] = DirectFunctionCall1(byteain, -! CStringGetDatum("")); - -! ntup = heap_form_tuple(pg_largeobject->rd_att, values, nulls); - -! /* -! * Insert it -! */ -! simple_heap_insert(pg_largeobject, ntup); - -! /* Update indexes */ -! CatalogUpdateIndexes(pg_largeobject, ntup); - -! heap_close(pg_largeobject, RowExclusiveLock); - -! heap_freetuple(ntup); - } - - void - LargeObjectDrop(Oid loid) - { -! bool found = false; - Relation pg_largeobject; - ScanKeyData skey[1]; -! SysScanDesc sd; - HeapTuple tuple; - - ScanKeyInit(&skey[0], -! Anum_pg_largeobject_loid, - BTEqualStrategyNumber, F_OIDEQ, -! ObjectIdGetDatum(loid)); - -! pg_largeobject = heap_open(LargeObjectRelationId, RowExclusiveLock); - -! sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndexId, true, -! SnapshotNow, 1, skey); - -! while ((tuple = systable_getnext(sd)) != NULL) - { - simple_heap_delete(pg_largeobject, &tuple->t_self); -- found = true; - } - -! systable_endscan(sd); - - heap_close(pg_largeobject, RowExclusiveLock); - -! if (!found) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("large object %u does not exist", loid))); - } - - bool - LargeObjectExists(Oid loid) - { - bool retval = false; -- Relation pg_largeobject; -- ScanKeyData skey[1]; -- SysScanDesc sd; - -- /* -- * See if we can find any tuples belonging to the specified LO -- */ - ScanKeyInit(&skey[0], -! Anum_pg_largeobject_loid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(loid)); - -! pg_largeobject = heap_open(LargeObjectRelationId, AccessShareLock); - -! sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndexId, true, - SnapshotNow, 1, skey); - -! if (systable_getnext(sd) != NULL) - retval = true; - - systable_endscan(sd); - -! heap_close(pg_largeobject, AccessShareLock); - - return retval; - } ---- 35,292 ---- - /* - * Create a large object having the given LO identifier. - * -! * We create a new large object by inserting an entry into -! * pg_largeobject_metadata without any data pages, so that the object -! * will appear to exist with size 0. - */ -! Oid - LargeObjectCreate(Oid loid) - { -! Relation pg_lo_meta; - HeapTuple ntup; -! Oid loid_new; -! Datum values[Natts_pg_largeobject_metadata]; -! bool nulls[Natts_pg_largeobject_metadata]; - -! pg_lo_meta = heap_open(LargeObjectMetadataRelationId, -! RowExclusiveLock); - - /* -! * Insert metadata of the largeobject - */ -! memset(values, 0, sizeof(values)); -! memset(nulls, false, sizeof(nulls)); - -! values[Anum_pg_largeobject_metadata_lomowner - 1] -! = ObjectIdGetDatum(GetUserId()); -! nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true; -! -! ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta), -! values, nulls); -! if (OidIsValid(loid)) -! HeapTupleSetOid(ntup, loid); - -! loid_new = simple_heap_insert(pg_lo_meta, ntup); -! Assert(!OidIsValid(loid) || loid == loid_new); - -! CatalogUpdateIndexes(pg_lo_meta, ntup); - -! heap_freetuple(ntup); - -! heap_close(pg_lo_meta, RowExclusiveLock); - -! return loid_new; - } - -+ /* -+ * Drop a large object having the given LO identifier. -+ * -+ * When we drop a large object, it is necessary to drop both of metadata -+ * and data pages in same time. -+ */ - void - LargeObjectDrop(Oid loid) - { -! Relation pg_lo_meta; - Relation pg_largeobject; - ScanKeyData skey[1]; -! SysScanDesc scan; - HeapTuple tuple; - -+ pg_lo_meta = heap_open(LargeObjectMetadataRelationId, -+ RowExclusiveLock); -+ -+ pg_largeobject = heap_open(LargeObjectRelationId, -+ RowExclusiveLock); -+ -+ /* -+ * Delete an entry from pg_largeobject_metadata -+ */ - ScanKeyInit(&skey[0], -! ObjectIdAttributeNumber, - BTEqualStrategyNumber, F_OIDEQ, -! ObjectIdGetDatum(loid)); - -! scan = systable_beginscan(pg_lo_meta, -! LargeObjectMetadataOidIndexId, true, -! SnapshotNow, 1, skey); - -! tuple = systable_getnext(scan); -! if (!HeapTupleIsValid(tuple)) -! ereport(ERROR, -! (errcode(ERRCODE_UNDEFINED_OBJECT), -! errmsg("large object %u does not exist", loid))); -! -! simple_heap_delete(pg_lo_meta, &tuple->t_self); -! -! systable_endscan(scan); -! -! /* -! * Delete all the associated entries from pg_largeobject -! */ -! ScanKeyInit(&skey[0], -! Anum_pg_largeobject_loid, -! BTEqualStrategyNumber, F_OIDEQ, -! ObjectIdGetDatum(loid)); - -! scan = systable_beginscan(pg_largeobject, -! LargeObjectLOidPNIndexId, true, -! SnapshotNow, 1, skey); -! while (HeapTupleIsValid(tuple = systable_getnext(scan))) - { - simple_heap_delete(pg_largeobject, &tuple->t_self); - } - -! systable_endscan(scan); - - heap_close(pg_largeobject, RowExclusiveLock); - -! heap_close(pg_lo_meta, RowExclusiveLock); -! } -! -! /* -! * LargeObjectAlterOwner -! * -! * Implementation of ALTER LARGE OBJECT statement -! */ -! void -! LargeObjectAlterOwner(Oid loid, Oid newOwnerId) -! { -! Form_pg_largeobject_metadata form_lo_meta; -! Relation pg_lo_meta; -! ScanKeyData skey[1]; -! SysScanDesc scan; -! HeapTuple oldtup; -! HeapTuple newtup; -! -! pg_lo_meta = heap_open(LargeObjectMetadataRelationId, -! RowExclusiveLock); -! -! ScanKeyInit(&skey[0], -! ObjectIdAttributeNumber, -! BTEqualStrategyNumber, F_OIDEQ, -! ObjectIdGetDatum(loid)); -! -! scan = systable_beginscan(pg_lo_meta, -! LargeObjectMetadataOidIndexId, true, -! SnapshotNow, 1, skey); -! -! oldtup = systable_getnext(scan); -! if (!HeapTupleIsValid(oldtup)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("large object %u does not exist", loid))); -+ -+ form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(oldtup); -+ if (form_lo_meta->lomowner != newOwnerId) -+ { -+ Datum values[Natts_pg_largeobject_metadata]; -+ bool nulls[Natts_pg_largeobject_metadata]; -+ bool replaces[Natts_pg_largeobject_metadata]; -+ Acl *newAcl; -+ Datum aclDatum; -+ bool isnull; -+ -+ /* Superusers can always do it */ -+ if (!superuser()) -+ { -+ /* -+ * The 'lo_compat_privileges' is not checked here, because we -+ * don't have any access control features in the 8.4.x series -+ * or earlier release. -+ * So, it is not a place we can define a compatible behavior. -+ */ -+ -+ /* Otherwise, must be owner of the existing object */ -+ if (!pg_largeobject_ownercheck(loid, GetUserId())) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("must be owner of large object %u", loid))); -+ -+ /* Must be able to become new owner */ -+ check_is_member_of_role(GetUserId(), newOwnerId); -+ } -+ -+ memset(values, 0, sizeof(values)); -+ memset(nulls, false, sizeof(nulls)); -+ memset(replaces, false, sizeof(nulls)); -+ -+ values[Anum_pg_largeobject_metadata_lomowner - 1] -+ = ObjectIdGetDatum(newOwnerId); -+ replaces[Anum_pg_largeobject_metadata_lomowner - 1] = true; -+ -+ /* -+ * Determine the modified ACL for the new owner. -+ * This is only necessary when the ACL is non-null. -+ */ -+ aclDatum = heap_getattr(oldtup, -+ Anum_pg_largeobject_metadata_lomacl, -+ RelationGetDescr(pg_lo_meta), &isnull); -+ if (!isnull) -+ { -+ newAcl = aclnewowner(DatumGetAclP(aclDatum), -+ form_lo_meta->lomowner, newOwnerId); -+ values[Anum_pg_largeobject_metadata_lomacl - 1] -+ = PointerGetDatum(newAcl); -+ replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true; -+ } -+ -+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_lo_meta), -+ values, nulls, replaces); -+ -+ simple_heap_update(pg_lo_meta, &newtup->t_self, newtup); -+ CatalogUpdateIndexes(pg_lo_meta, newtup); -+ -+ heap_freetuple(newtup); -+ -+ /* Update owner dependency reference */ -+ changeDependencyOnOwner(LargeObjectRelationId, -+ loid, newOwnerId); -+ } -+ systable_endscan(scan); -+ -+ heap_close(pg_lo_meta, RowExclusiveLock); - } - -+ /* -+ * LargeObjectExists -+ * -+ * Currently, we don't use system cache to contain metadata of -+ * large objects, because massive number of large objects can -+ * consume not a small amount of process local memory. -+ * -+ * Note that LargeObjectExists always scans the system catalog -+ * with SnapshotNow, so it is unavailable to use to check -+ * existence in read-only accesses. -+ */ - bool - LargeObjectExists(Oid loid) - { -+ Relation pg_lo_meta; -+ ScanKeyData skey[1]; -+ SysScanDesc sd; -+ HeapTuple tuple; - bool retval = false; - - ScanKeyInit(&skey[0], -! ObjectIdAttributeNumber, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(loid)); - -! pg_lo_meta = heap_open(LargeObjectMetadataRelationId, -! AccessShareLock); - -! sd = systable_beginscan(pg_lo_meta, -! LargeObjectMetadataOidIndexId, true, - SnapshotNow, 1, skey); - -! tuple = systable_getnext(sd); -! if (HeapTupleIsValid(tuple)) - retval = true; - - systable_endscan(sd); - -! heap_close(pg_lo_meta, AccessShareLock); - - return retval; - } -diff -Nrpc base/src/backend/catalog/pg_shdepend.c blob/src/backend/catalog/pg_shdepend.c -*** base/src/backend/catalog/pg_shdepend.c Thu Jun 18 10:20:52 2009 ---- blob/src/backend/catalog/pg_shdepend.c Fri Dec 18 09:40:55 2009 -*************** -*** 24,29 **** ---- 24,30 ---- - #include "catalog/pg_conversion.h" - #include "catalog/pg_database.h" - #include "catalog/pg_language.h" -+ #include "catalog/pg_largeobject.h" - #include "catalog/pg_namespace.h" - #include "catalog/pg_operator.h" - #include "catalog/pg_proc.h" -*************** shdepDropOwned(List *roleids, DropBehavi -*** 1210,1215 **** ---- 1211,1219 ---- - case LanguageRelationId: - istmt.objtype = ACL_OBJECT_LANGUAGE; - break; -+ case LargeObjectRelationId: -+ istmt.objtype = ACL_OBJECT_LARGEOBJECT; -+ break; - case NamespaceRelationId: - istmt.objtype = ACL_OBJECT_NAMESPACE; - break; -*************** shdepReassignOwned(List *roleids, Oid ne -*** 1365,1370 **** ---- 1369,1378 ---- - AlterLanguageOwner_oid(sdepForm->objid, newrole); - break; - -+ case LargeObjectRelationId: -+ LargeObjectAlterOwner(sdepForm->objid, newrole); -+ break; -+ - default: - elog(ERROR, "unexpected classid %d", sdepForm->classid); - break; -diff -Nrpc base/src/backend/commands/alter.c blob/src/backend/commands/alter.c -*** base/src/backend/commands/alter.c Sat Jan 3 13:01:35 2009 ---- blob/src/backend/commands/alter.c Fri Dec 18 09:40:55 2009 -*************** -*** 15,20 **** ---- 15,21 ---- - #include "postgres.h" - - #include "catalog/namespace.h" -+ #include "catalog/pg_largeobject.h" - #include "commands/alter.h" - #include "commands/conversioncmds.h" - #include "commands/dbcommands.h" -*************** ExecAlterOwnerStmt(AlterOwnerStmt *stmt) -*** 233,238 **** ---- 234,243 ---- - AlterLanguageOwner(strVal(linitial(stmt->object)), newowner); - break; - -+ case OBJECT_LARGEOBJECT: -+ LargeObjectAlterOwner(intVal(linitial(stmt->object)), newowner); -+ break; -+ - case OBJECT_OPERATOR: - Assert(list_length(stmt->objarg) == 2); - AlterOperatorOwner(stmt->object, -diff -Nrpc base/src/backend/commands/comment.c blob/src/backend/commands/comment.c -*** base/src/backend/commands/comment.c Thu Jun 18 10:20:52 2009 ---- blob/src/backend/commands/comment.c Fri Dec 18 09:40:55 2009 -*************** -*** 25,30 **** ---- 25,31 ---- - #include "catalog/pg_description.h" - #include "catalog/pg_language.h" - #include "catalog/pg_largeobject.h" -+ #include "catalog/pg_largeobject_metadata.h" - #include "catalog/pg_namespace.h" - #include "catalog/pg_opclass.h" - #include "catalog/pg_operator.h" -*************** -*** 42,47 **** ---- 43,49 ---- - #include "commands/comment.h" - #include "commands/dbcommands.h" - #include "commands/tablespace.h" -+ #include "libpq/be-fsstubs.h" - #include "miscadmin.h" - #include "nodes/makefuncs.h" - #include "parser/parse_func.h" -*************** CommentLargeObject(List *qualname, char -*** 1422,1428 **** - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("large object %u does not exist", loid))); - -! /* Call CreateComments() to create/drop the comments */ - CreateComments(loid, LargeObjectRelationId, 0, comment); - } - ---- 1424,1443 ---- - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("large object %u does not exist", loid))); - -! /* Permission checks */ -! if (!lo_compat_privileges && -! !pg_largeobject_ownercheck(loid, GetUserId())) -! ereport(ERROR, -! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -! errmsg("must be owner of large object %u", loid))); -! -! /* -! * Call CreateComments() to create/drop the comments -! * -! * See the comment in the inv_create() which describes -! * the reason why LargeObjectRelationId is used instead -! * of the LargeObjectMetadataRelationId. -! */ - CreateComments(loid, LargeObjectRelationId, 0, comment); - } - -diff -Nrpc base/src/backend/commands/tablecmds.c blob/src/backend/commands/tablecmds.c -*** base/src/backend/commands/tablecmds.c Tue Dec 15 17:16:51 2009 ---- blob/src/backend/commands/tablecmds.c Fri Dec 18 09:40:55 2009 -*************** ATExecAlterColumnType(AlteredTableInfo * -*** 5902,5907 **** ---- 5902,5908 ---- - case OCLASS_CAST: - case OCLASS_CONVERSION: - case OCLASS_LANGUAGE: -+ case OCLASS_LARGEOBJECT: - case OCLASS_OPERATOR: - case OCLASS_OPCLASS: - case OCLASS_OPFAMILY: -diff -Nrpc base/src/backend/libpq/be-fsstubs.c blob/src/backend/libpq/be-fsstubs.c -*** base/src/backend/libpq/be-fsstubs.c Thu Jun 18 10:20:52 2009 ---- blob/src/backend/libpq/be-fsstubs.c Fri Dec 18 09:40:55 2009 -*************** -*** 42,55 **** ---- 42,61 ---- - #include - #include - -+ #include "catalog/pg_largeobject_metadata.h" - #include "libpq/be-fsstubs.h" - #include "libpq/libpq-fs.h" - #include "miscadmin.h" - #include "storage/fd.h" - #include "storage/large_object.h" -+ #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/memutils.h" - -+ /* -+ * compatibility flag for permission checks -+ */ -+ bool lo_compat_privileges; - - /*#define FSDB 1*/ - #define BUFSIZE 8192 -*************** lo_read(int fd, char *buf, int len) -*** 156,161 **** ---- 162,178 ---- - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("invalid large-object descriptor: %d", fd))); - -+ /* Permission checks */ -+ if (!lo_compat_privileges && -+ pg_largeobject_aclcheck_snapshot(cookies[fd]->id, -+ GetUserId(), -+ ACL_SELECT, -+ cookies[fd]->snapshot) != ACLCHECK_OK) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("permission denied for large object %u", -+ cookies[fd]->id))); -+ - status = inv_read(cookies[fd], buf, len); - - return status; -*************** lo_write(int fd, const char *buf, int le -*** 177,182 **** ---- 194,210 ---- - errmsg("large object descriptor %d was not opened for writing", - fd))); - -+ /* Permission checks */ -+ if (!lo_compat_privileges && -+ pg_largeobject_aclcheck_snapshot(cookies[fd]->id, -+ GetUserId(), -+ ACL_UPDATE, -+ cookies[fd]->snapshot) != ACLCHECK_OK) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("permission denied for large object %u", -+ cookies[fd]->id))); -+ - status = inv_write(cookies[fd], buf, len); - - return status; -*************** lo_unlink(PG_FUNCTION_ARGS) -*** 251,256 **** ---- 279,291 ---- - { - Oid lobjId = PG_GETARG_OID(0); - -+ /* Must be owner of the largeobject */ -+ if (!lo_compat_privileges && -+ !pg_largeobject_ownercheck(lobjId, GetUserId())) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("must be owner of large object %u", lobjId))); -+ - /* - * If there are any open LO FDs referencing that ID, close 'em. - */ -*************** lo_truncate(PG_FUNCTION_ARGS) -*** 482,487 **** ---- 517,533 ---- - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("invalid large-object descriptor: %d", fd))); - -+ /* Permission checks */ -+ if (!lo_compat_privileges && -+ pg_largeobject_aclcheck_snapshot(cookies[fd]->id, -+ GetUserId(), -+ ACL_UPDATE, -+ cookies[fd]->snapshot) != ACLCHECK_OK) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("permission denied for large object %u", -+ cookies[fd]->id))); -+ - inv_truncate(cookies[fd], len); - - PG_RETURN_INT32(0); -diff -Nrpc base/src/backend/parser/gram.y blob/src/backend/parser/gram.y -*** base/src/backend/parser/gram.y Sun Sep 6 19:40:49 2009 ---- blob/src/backend/parser/gram.y Fri Dec 18 09:40:55 2009 -*************** static TypeName *TableFuncTypeName(List -*** 378,383 **** ---- 378,384 ---- - %type opt_varying opt_timezone - - %type Iconst SignedIconst -+ %type Iconst_list - %type Sconst comment_text - %type RoleId opt_granted_by opt_boolean ColId_or_Sconst - %type var_list -*************** privilege_target: -*** 4379,4384 **** ---- 4380,4392 ---- - n->objs = $2; - $$ = n; - } -+ | LARGE_P OBJECT_P Iconst_list -+ { -+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); -+ n->objtype = ACL_OBJECT_LARGEOBJECT; -+ n->objs = $3; -+ $$ = n; -+ } - | SCHEMA name_list - { - PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); -*************** AlterOwnerStmt: ALTER AGGREGATE func_nam -*** 5506,5511 **** ---- 5514,5527 ---- - n->newowner = $7; - $$ = (Node *)n; - } -+ | ALTER LARGE_P OBJECT_P Iconst OWNER TO RoleId -+ { -+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt); -+ n->objectType = OBJECT_LARGEOBJECT; -+ n->object = list_make1(makeInteger($4)); -+ n->newowner = $7; -+ $$ = (Node *)n; -+ } - | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId - { - AlterOwnerStmt *n = makeNode(AlterOwnerStmt); -*************** SignedIconst: Iconst { $$ = $1; } -*** 10066,10071 **** ---- 10082,10091 ---- - | '-' Iconst { $$ = - $2; } - ; - -+ Iconst_list: Iconst { $$ = list_make1(makeInteger($1)); } -+ | Iconst_list ',' Iconst { $$ = lappend($1, makeInteger($3)); } -+ ; -+ - /* - * Name classification hierarchy. - * -diff -Nrpc base/src/backend/storage/large_object/inv_api.c blob/src/backend/storage/large_object/inv_api.c -*** base/src/backend/storage/large_object/inv_api.c Thu Jun 18 10:20:52 2009 ---- blob/src/backend/storage/large_object/inv_api.c Fri Dec 18 09:40:55 2009 -*************** -*** 32,49 **** ---- 32,54 ---- - - #include "access/genam.h" - #include "access/heapam.h" -+ #include "access/sysattr.h" - #include "access/tuptoaster.h" - #include "access/xact.h" - #include "catalog/catalog.h" -+ #include "catalog/dependency.h" - #include "catalog/indexing.h" - #include "catalog/pg_largeobject.h" -+ #include "catalog/pg_largeobject_metadata.h" - #include "commands/comment.h" - #include "libpq/libpq-fs.h" -+ #include "miscadmin.h" - #include "storage/large_object.h" - #include "utils/fmgroids.h" - #include "utils/rel.h" - #include "utils/resowner.h" - #include "utils/snapmgr.h" -+ #include "utils/syscache.h" - #include "utils/tqual.h" - - -*************** close_lo_relation(bool isCommit) -*** 139,168 **** - static bool - myLargeObjectExists(Oid loid, Snapshot snapshot) - { - bool retval = false; -- Relation pg_largeobject; -- ScanKeyData skey[1]; -- SysScanDesc sd; - -- /* -- * See if we can find any tuples belonging to the specified LO -- */ - ScanKeyInit(&skey[0], -! Anum_pg_largeobject_loid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(loid)); - -! pg_largeobject = heap_open(LargeObjectRelationId, AccessShareLock); - -! sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndexId, true, - snapshot, 1, skey); - -! if (systable_getnext(sd) != NULL) - retval = true; - - systable_endscan(sd); - -! heap_close(pg_largeobject, AccessShareLock); - - return retval; - } ---- 144,174 ---- - static bool - myLargeObjectExists(Oid loid, Snapshot snapshot) - { -+ Relation pg_lo_meta; -+ ScanKeyData skey[1]; -+ SysScanDesc sd; -+ HeapTuple tuple; - bool retval = false; - - ScanKeyInit(&skey[0], -! ObjectIdAttributeNumber, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(loid)); - -! pg_lo_meta = heap_open(LargeObjectMetadataRelationId, -! AccessShareLock); - -! sd = systable_beginscan(pg_lo_meta, -! LargeObjectMetadataOidIndexId, true, - snapshot, 1, skey); - -! tuple = systable_getnext(sd); -! if (HeapTupleIsValid(tuple)) - retval = true; - - systable_endscan(sd); - -! heap_close(pg_lo_meta, AccessShareLock); - - return retval; - } -*************** getbytealen(bytea *data) -*** 193,223 **** - Oid - inv_create(Oid lobjId) - { - /* -! * Allocate an OID to be the LO's identifier, unless we were told what to -! * use. We can use the index on pg_largeobject for checking OID -! * uniqueness, even though it has additional columns besides OID. - */ -! if (!OidIsValid(lobjId)) -! { -! open_lo_relation(); -! -! lobjId = GetNewOidWithIndex(lo_heap_r, LargeObjectLOidPNIndexId, -! Anum_pg_largeobject_loid); -! } - - /* -! * Create the LO by writing an empty first page for it in pg_largeobject -! * (will fail if duplicate) - */ -! LargeObjectCreate(lobjId); -! - /* - * Advance command counter to make new tuple visible to later operations. - */ - CommandCounterIncrement(); - -! return lobjId; - } - - /* ---- 199,229 ---- - Oid - inv_create(Oid lobjId) - { -+ Oid lobjId_new; -+ - /* -! * Create a new largeobject with empty data pages - */ -! lobjId_new = LargeObjectCreate(lobjId); - - /* -! * dependency on the owner of largeobject -! * -! * The reason why we use LargeObjectRelationId instead of -! * LargeObjectMetadataRelationId here is to provide backward -! * compatibility to the applications which utilize a knowledge -! * about internal layout of system catalogs. -! * OID of pg_largeobject_metadata and loid of pg_largeobject -! * are same value, so there are no actual differences here. - */ -! recordDependencyOnOwner(LargeObjectRelationId, -! lobjId_new, GetUserId()); - /* - * Advance command counter to make new tuple visible to later operations. - */ - CommandCounterIncrement(); - -! return lobjId_new; - } - - /* -*************** inv_close(LargeObjectDesc *obj_desc) -*** 292,301 **** - int - inv_drop(Oid lobjId) - { -! LargeObjectDrop(lobjId); - -! /* Delete any comments on the large object */ -! DeleteComments(lobjId, LargeObjectRelationId, 0); - - /* - * Advance command counter so that tuple removal will be seen by later ---- 298,312 ---- - int - inv_drop(Oid lobjId) - { -! ObjectAddress object; - -! /* -! * Delete any comments and dependencies on the large object -! */ -! object.classId = LargeObjectRelationId; -! object.objectId = lobjId; -! object.objectSubId = 0; -! performDeletion(&object, DROP_CASCADE); - - /* - * Advance command counter so that tuple removal will be seen by later -*************** inv_drop(Oid lobjId) -*** 315,321 **** - static uint32 - inv_getsize(LargeObjectDesc *obj_desc) - { -- bool found = false; - uint32 lastbyte = 0; - ScanKeyData skey[1]; - SysScanDesc sd; ---- 326,331 ---- -*************** inv_getsize(LargeObjectDesc *obj_desc) -*** 339,351 **** - * large object in reverse pageno order. So, it's sufficient to examine - * the first valid tuple (== last valid page). - */ -! while ((tuple = systable_getnext_ordered(sd, BackwardScanDirection)) != NULL) - { - Form_pg_largeobject data; - bytea *datafield; - bool pfreeit; - -- found = true; - if (HeapTupleHasNulls(tuple)) /* paranoia */ - elog(ERROR, "null field found in pg_largeobject"); - data = (Form_pg_largeobject) GETSTRUCT(tuple); ---- 349,361 ---- - * large object in reverse pageno order. So, it's sufficient to examine - * the first valid tuple (== last valid page). - */ -! tuple = systable_getnext_ordered(sd, BackwardScanDirection); -! if (HeapTupleIsValid(tuple)) - { - Form_pg_largeobject data; - bytea *datafield; - bool pfreeit; - - if (HeapTupleHasNulls(tuple)) /* paranoia */ - elog(ERROR, "null field found in pg_largeobject"); - data = (Form_pg_largeobject) GETSTRUCT(tuple); -*************** inv_getsize(LargeObjectDesc *obj_desc) -*** 360,374 **** - lastbyte = data->pageno * LOBLKSIZE + getbytealen(datafield); - if (pfreeit) - pfree(datafield); -- break; - } - - systable_endscan_ordered(sd); - -- if (!found) -- ereport(ERROR, -- (errcode(ERRCODE_UNDEFINED_OBJECT), -- errmsg("large object %u does not exist", obj_desc->id))); - return lastbyte; - } - ---- 370,379 ---- -*************** inv_write(LargeObjectDesc *obj_desc, con -*** 545,550 **** ---- 550,561 ---- - errmsg("large object %u was not opened for writing", - obj_desc->id))); - -+ /* check existence of the target largeobject */ -+ if (!LargeObjectExists(obj_desc->id)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_OBJECT), -+ errmsg("large object %u was already dropped", obj_desc->id))); -+ - if (nbytes <= 0) - return 0; - -*************** inv_truncate(LargeObjectDesc *obj_desc, -*** 736,741 **** ---- 747,758 ---- - errmsg("large object %u was not opened for writing", - obj_desc->id))); - -+ /* check existence of the target largeobject */ -+ if (!LargeObjectExists(obj_desc->id)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_OBJECT), -+ errmsg("large object %u was already dropped", obj_desc->id))); -+ - open_lo_relation(); - - indstate = CatalogOpenIndexes(lo_heap_r); -diff -Nrpc base/src/backend/tcop/utility.c blob/src/backend/tcop/utility.c -*** base/src/backend/tcop/utility.c Tue Dec 15 17:16:51 2009 ---- blob/src/backend/tcop/utility.c Fri Dec 18 09:40:55 2009 -*************** CreateCommandTag(Node *parsetree) -*** 1625,1630 **** ---- 1625,1633 ---- - case OBJECT_LANGUAGE: - tag = "ALTER LANGUAGE"; - break; -+ case OBJECT_LARGEOBJECT: -+ tag = "ALTER LARGEOBJECT"; -+ break; - case OBJECT_OPERATOR: - tag = "ALTER OPERATOR"; - break; -diff -Nrpc base/src/backend/utils/adt/acl.c blob/src/backend/utils/adt/acl.c -*** base/src/backend/utils/adt/acl.c Thu Jun 18 10:20:52 2009 ---- blob/src/backend/utils/adt/acl.c Fri Dec 18 09:40:55 2009 -*************** acldefault(GrantObjectType objtype, Oid -*** 631,636 **** ---- 631,641 ---- - world_default = ACL_USAGE; - owner_default = ACL_ALL_RIGHTS_LANGUAGE; - break; -+ case ACL_OBJECT_LARGEOBJECT: -+ /* Grant SELECT,UPDATE by default, for now */ -+ world_default = ACL_NO_RIGHTS; -+ owner_default = ACL_ALL_RIGHTS_LARGEOBJECT; -+ break; - case ACL_OBJECT_NAMESPACE: - world_default = ACL_NO_RIGHTS; - owner_default = ACL_ALL_RIGHTS_NAMESPACE; -diff -Nrpc base/src/backend/utils/misc/guc.c blob/src/backend/utils/misc/guc.c -*** base/src/backend/utils/misc/guc.c Thu Mar 18 01:40:54 2010 ---- blob/src/backend/utils/misc/guc.c Thu Mar 18 09:43:03 2010 -*************** -*** 38,43 **** ---- 38,44 ---- - #include "commands/trigger.h" - #include "funcapi.h" - #include "libpq/auth.h" -+ #include "libpq/be-fsstubs.h" - #include "libpq/pqformat.h" - #include "miscadmin.h" - #include "optimizer/cost.h" -*************** static struct config_bool ConfigureNames -*** 1222,1227 **** ---- 1223,1238 ---- - false, NULL, NULL - }, - -+ { -+ {"lo_compat_privileges", PGC_SUSET, COMPAT_OPTIONS_PREVIOUS, -+ gettext_noop("Enables backward compatibility in privilege checks on large objects"), -+ gettext_noop("When turned on, privilege checks on large objects perform " -+ "with backward compatibility as 8.4.x or earlier releases.") -+ }, -+ &lo_compat_privileges, -+ false, NULL, NULL -+ }, -+ - /* End-of-list marker */ - { - {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL -diff -Nrpc base/src/backend/utils/misc/postgresql.conf.sample blob/src/backend/utils/misc/postgresql.conf.sample -*** base/src/backend/utils/misc/postgresql.conf.sample Thu Mar 18 01:40:54 2010 ---- blob/src/backend/utils/misc/postgresql.conf.sample Thu Mar 18 09:43:03 2010 -*************** -*** 484,489 **** ---- 484,490 ---- - #backslash_quote = safe_encoding # on, off, or safe_encoding - #default_with_oids = off - #escape_string_warning = on -+ #lo_compat_privileges = off - #regex_flavor = advanced # advanced, extended, or basic - #sql_inheritance = on - #standard_conforming_strings = off -diff -Nrpc base/src/bin/initdb/initdb.c blob/src/bin/initdb/initdb.c -*** base/src/bin/initdb/initdb.c Tue Dec 15 17:16:51 2009 ---- blob/src/bin/initdb/initdb.c Fri Dec 18 09:40:55 2009 -*************** setup_privileges(void) -*** 1815,1820 **** ---- 1815,1821 ---- - " WHERE relkind IN ('r', 'v', 'S') AND relacl IS NULL;\n", - "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n", - "GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n", -+ "REVOKE ALL ON pg_largeobject FROM PUBLIC;\n", - NULL - }; - -diff -Nrpc base/src/bin/pg_dump/dumputils.c blob/src/bin/pg_dump/dumputils.c -*** base/src/bin/pg_dump/dumputils.c Thu Mar 18 01:40:54 2010 ---- blob/src/bin/pg_dump/dumputils.c Thu Mar 18 09:43:03 2010 -*************** do { \ -*** 758,763 **** ---- 758,768 ---- - CONVERT_PRIV('U', "USAGE"); - else if (strcmp(type, "FOREIGN SERVER") == 0) - CONVERT_PRIV('U', "USAGE"); -+ else if (strcmp(type, "LARGE OBJECT") == 0) -+ { -+ CONVERT_PRIV('r', "SELECT"); -+ CONVERT_PRIV('w', "UPDATE"); -+ } - else - abort(); - -diff -Nrpc base/src/bin/pg_dump/pg_dump.c blob/src/bin/pg_dump/pg_dump.c -*** base/src/bin/pg_dump/pg_dump.c Thu Mar 18 01:40:54 2010 ---- blob/src/bin/pg_dump/pg_dump.c Thu Mar 18 09:43:03 2010 -*************** hasBlobs(Archive *AH) -*** 1923,1929 **** - selectSourceSchema("pg_catalog"); - - /* Check for BLOB OIDs */ -! if (AH->remoteVersion >= 70100) - blobQry = "SELECT loid FROM pg_largeobject LIMIT 1"; - else - blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1"; ---- 1923,1931 ---- - selectSourceSchema("pg_catalog"); - - /* Check for BLOB OIDs */ -! if (AH->remoteVersion >= 80402) -! blobQry = "SELECT oid FROM pg_largeobject_metadata LIMIT 1"; -! else if (AH->remoteVersion >= 70100) - blobQry = "SELECT loid FROM pg_largeobject LIMIT 1"; - else - blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1"; -*************** dumpBlobs(Archive *AH, void *arg) -*** 1959,1965 **** - selectSourceSchema("pg_catalog"); - - /* Cursor to get all BLOB OIDs */ -! if (AH->remoteVersion >= 70100) - blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject"; - else - blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'"; ---- 1961,1969 ---- - selectSourceSchema("pg_catalog"); - - /* Cursor to get all BLOB OIDs */ -! if (AH->remoteVersion >= 80402) -! blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata"; -! else if (AH->remoteVersion >= 70100) - blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject"; - else - blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'"; -*************** dumpBlobs(Archive *AH, void *arg) -*** 2023,2029 **** - - /* - * dumpBlobComments -! * dump all blob comments - * - * Since we don't provide any way to be selective about dumping blobs, - * there's no need to be selective about their comments either. We put ---- 2027,2035 ---- - - /* - * dumpBlobComments -! * dump all blob properties. -! * It has "BLOB COMMENTS" tag due to the historical reason, but note -! * that it is the routine to dump all the properties of blobs. - * - * Since we don't provide any way to be selective about dumping blobs, - * there's no need to be selective about their comments either. We put -*************** dumpBlobComments(Archive *AH, void *arg) -*** 2034,2063 **** - { - const char *blobQry; - const char *blobFetchQry; -! PQExpBuffer commentcmd = createPQExpBuffer(); - PGresult *res; - int i; - - if (g_verbose) -! write_msg(NULL, "saving large object comments\n"); - - /* Make sure we are in proper schema */ - selectSourceSchema("pg_catalog"); - - /* Cursor to get all BLOB comments */ -! if (AH->remoteVersion >= 70300) - blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, " -! "obj_description(loid, 'pg_largeobject') " - "FROM (SELECT DISTINCT loid FROM " - "pg_description d JOIN pg_largeobject l ON (objoid = loid) " - "WHERE classoid = 'pg_largeobject'::regclass) ss"; - else if (AH->remoteVersion >= 70200) - blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, " -! "obj_description(loid, 'pg_largeobject') " - "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss"; - else if (AH->remoteVersion >= 70100) - blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, " -! "obj_description(loid) " - "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss"; - else - blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, " ---- 2040,2074 ---- - { - const char *blobQry; - const char *blobFetchQry; -! PQExpBuffer cmdQry = createPQExpBuffer(); - PGresult *res; - int i; - - if (g_verbose) -! write_msg(NULL, "saving large object properties\n"); - - /* Make sure we are in proper schema */ - selectSourceSchema("pg_catalog"); - - /* Cursor to get all BLOB comments */ -! if (AH->remoteVersion >= 80402) -! blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, " -! "obj_description(oid, 'pg_largeobject'), " -! "pg_get_userbyid(lomowner), lomacl " -! "FROM pg_largeobject_metadata"; -! else if (AH->remoteVersion >= 70300) - blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, " -! "obj_description(loid, 'pg_largeobject'), NULL, NULL " - "FROM (SELECT DISTINCT loid FROM " - "pg_description d JOIN pg_largeobject l ON (objoid = loid) " - "WHERE classoid = 'pg_largeobject'::regclass) ss"; - else if (AH->remoteVersion >= 70200) - blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, " -! "obj_description(loid, 'pg_largeobject'), NULL, NULL " - "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss"; - else if (AH->remoteVersion >= 70100) - blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, " -! "obj_description(loid), NULL, NULL " - "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss"; - else - blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, " -*************** dumpBlobComments(Archive *AH, void *arg) -*** 2065,2071 **** - " SELECT description " - " FROM pg_description pd " - " WHERE pd.objoid=pc.oid " -! " ) " - "FROM pg_class pc WHERE relkind = 'l'"; - - res = PQexec(g_conn, blobQry); ---- 2076,2082 ---- - " SELECT description " - " FROM pg_description pd " - " WHERE pd.objoid=pc.oid " -! " ), NULL, NULL " - "FROM pg_class pc WHERE relkind = 'l'"; - - res = PQexec(g_conn, blobQry); -*************** dumpBlobComments(Archive *AH, void *arg) -*** 2085,2106 **** - /* Process the tuples, if any */ - for (i = 0; i < PQntuples(res); i++) - { -! Oid blobOid; -! char *comment; - -! /* 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 ", -! blobOid); -! appendStringLiteralAH(commentcmd, comment, AH); -! appendPQExpBuffer(commentcmd, ";\n"); - -! archputs(commentcmd->data, AH); - } - } while (PQntuples(res) > 0); - ---- 2096,2146 ---- - /* Process the tuples, if any */ - for (i = 0; i < PQntuples(res); i++) - { -! Oid blobOid = atooid(PQgetvalue(res, i, 0)); -! char *lo_comment = PQgetvalue(res, i, 1); -! char *lo_owner = PQgetvalue(res, i, 2); -! char *lo_acl = PQgetvalue(res, i, 3); -! char lo_name[32]; - -! resetPQExpBuffer(cmdQry); - -! /* comment on the blob */ -! if (!PQgetisnull(res, i, 1)) -! { -! appendPQExpBuffer(cmdQry, -! "COMMENT ON LARGE OBJECT %u IS ", blobOid); -! appendStringLiteralAH(cmdQry, lo_comment, AH); -! appendPQExpBuffer(cmdQry, ";\n"); -! } -! -! /* dump blob ownership, if necessary */ -! if (!PQgetisnull(res, i, 2)) -! { -! appendPQExpBuffer(cmdQry, -! "ALTER LARGE OBJECT %u OWNER TO %s;\n", -! blobOid, lo_owner); -! } - -! /* dump blob privileges, if necessary */ -! if (!PQgetisnull(res, i, 3) && -! !dataOnly && !aclsSkip) -! { -! snprintf(lo_name, sizeof(lo_name), "%u", blobOid); -! if (!buildACLCommands(lo_name, NULL, "LARGE OBJECT", -! lo_acl, lo_owner, -! AH->remoteVersion, cmdQry)) -! { -! write_msg(NULL, "could not parse ACL (%s) for " -! "large object %u", lo_acl, blobOid); -! exit_nicely(); -! } -! } - -! if (cmdQry->len > 0) -! { -! appendPQExpBuffer(cmdQry, "\n"); -! archputs(cmdQry->data, AH); -! } - } - } while (PQntuples(res) > 0); - -*************** dumpBlobComments(Archive *AH, void *arg) -*** 2108,2114 **** - - archputs("\n", AH); - -! destroyPQExpBuffer(commentcmd); - - return 1; - } ---- 2148,2154 ---- - - archputs("\n", AH); - -! destroyPQExpBuffer(cmdQry); - - return 1; - } -diff -Nrpc base/src/bin/psql/large_obj.c blob/src/bin/psql/large_obj.c -*** base/src/bin/psql/large_obj.c Sat Jan 3 12:49:23 2009 ---- blob/src/bin/psql/large_obj.c Fri Dec 18 09:40:55 2009 -*************** do_lo_list(void) -*** 278,290 **** - char buf[1024]; - printQueryOpt myopt = pset.popt; - -! snprintf(buf, sizeof(buf), -! "SELECT loid as \"%s\",\n" -! " pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n" -! "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n" -! "ORDER BY 1", -! gettext_noop("ID"), -! gettext_noop("Description")); - - res = PSQLexec(buf, false); - if (!res) ---- 278,305 ---- - char buf[1024]; - printQueryOpt myopt = pset.popt; - -! if (pset.sversion >= 80500) -! { -! snprintf(buf, sizeof(buf), -! "SELECT oid as \"%s\",\n" -! " pg_catalog.pg_get_userbyid(lomowner) as \"%s\",\n" -! " pg_catalog.obj_description(oid, 'pg_largeobject') as \"%s\"\n" -! " FROM pg_catalog.pg_largeobject_metadata " -! " ORDER BY oid", -! gettext_noop("ID"), -! gettext_noop("Owner"), -! gettext_noop("Description")); -! } -! else -! { -! snprintf(buf, sizeof(buf), -! "SELECT loid as \"%s\",\n" -! " pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n" -! "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n" -! "ORDER BY 1", -! gettext_noop("ID"), -! gettext_noop("Description")); -! } - - res = PSQLexec(buf, false); - if (!res) -diff -Nrpc base/src/bin/psql/tab-complete.c blob/src/bin/psql/tab-complete.c -*** base/src/bin/psql/tab-complete.c Thu Jun 18 10:20:52 2009 ---- blob/src/bin/psql/tab-complete.c Fri Dec 18 09:40:55 2009 -*************** psql_completion(char *text, int start, i -*** 693,699 **** - { - static const char *const list_ALTER[] = - {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FOREIGN DATA WRAPPER", "FUNCTION", -! "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE", - "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "USER MAPPING FOR", "VIEW", NULL}; - - COMPLETE_WITH_LIST(list_ALTER); ---- 693,699 ---- - { - static const char *const list_ALTER[] = - {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FOREIGN DATA WRAPPER", "FUNCTION", -! "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR", "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE", - "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "USER MAPPING FOR", "VIEW", NULL}; - - COMPLETE_WITH_LIST(list_ALTER); -*************** psql_completion(char *text, int start, i -*** 762,767 **** ---- 762,778 ---- - COMPLETE_WITH_LIST(list_ALTERLANGUAGE); - } - -+ /* ALTER LARGE OBJECT */ -+ else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && -+ pg_strcasecmp(prev3_wd, "LARGE") == 0 && -+ pg_strcasecmp(prev2_wd, "OBJECT") == 0) -+ { -+ static const char *const list_ALTERLARGEOBJECT[] = -+ {"OWNER TO", NULL}; -+ -+ COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT); -+ } -+ - /* ALTER USER,ROLE */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) && -*************** psql_completion(char *text, int start, i -*** 1703,1708 **** ---- 1714,1720 ---- - " UNION SELECT 'FOREIGN SERVER'" - " UNION SELECT 'FUNCTION'" - " UNION SELECT 'LANGUAGE'" -+ " UNION SELECT 'LARGE OBJECT'" - " UNION SELECT 'SCHEMA'" - " UNION SELECT 'TABLESPACE'"); - -diff -Nrpc base/src/include/catalog/catversion.h blob/src/include/catalog/catversion.h -*** base/src/include/catalog/catversion.h Thu Jun 18 10:20:52 2009 ---- blob/src/include/catalog/catversion.h Fri Dec 18 09:40:55 2009 -*************** -*** 53,58 **** - */ - - /* yyyymmddN */ -! #define CATALOG_VERSION_NO 200904091 - - #endif ---- 53,58 ---- - */ - - /* yyyymmddN */ -! #define CATALOG_VERSION_NO 200912151 - - #endif -diff -Nrpc base/src/include/catalog/dependency.h blob/src/include/catalog/dependency.h -*** base/src/include/catalog/dependency.h Thu Jun 18 10:20:52 2009 ---- blob/src/include/catalog/dependency.h Fri Dec 18 09:40:55 2009 -*************** typedef enum ObjectClass -*** 128,133 **** ---- 128,134 ---- - OCLASS_CONVERSION, /* pg_conversion */ - OCLASS_DEFAULT, /* pg_attrdef */ - OCLASS_LANGUAGE, /* pg_language */ -+ OCLASS_LARGEOBJECT, /* pg_largeobject */ - OCLASS_OPERATOR, /* pg_operator */ - OCLASS_OPCLASS, /* pg_opclass */ - OCLASS_OPFAMILY, /* pg_opfamily */ -diff -Nrpc base/src/include/catalog/indexing.h blob/src/include/catalog/indexing.h -*** base/src/include/catalog/indexing.h Thu Jun 18 10:20:52 2009 ---- blob/src/include/catalog/indexing.h Fri Dec 18 09:40:55 2009 -*************** DECLARE_UNIQUE_INDEX(pg_language_oid_ind -*** 165,170 **** ---- 165,173 ---- - DECLARE_UNIQUE_INDEX(pg_largeobject_loid_pn_index, 2683, on pg_largeobject using btree(loid oid_ops, pageno int4_ops)); - #define LargeObjectLOidPNIndexId 2683 - -+ DECLARE_UNIQUE_INDEX(pg_largeobject_metadata_oid_index, 2996, on pg_largeobject_metadata using btree(oid oid_ops)); -+ #define LargeObjectMetadataOidIndexId 2996 -+ - DECLARE_UNIQUE_INDEX(pg_namespace_nspname_index, 2684, on pg_namespace using btree(nspname name_ops)); - #define NamespaceNameIndexId 2684 - DECLARE_UNIQUE_INDEX(pg_namespace_oid_index, 2685, on pg_namespace using btree(oid oid_ops)); -diff -Nrpc base/src/include/catalog/pg_largeobject.h blob/src/include/catalog/pg_largeobject.h -*** base/src/include/catalog/pg_largeobject.h Sat Jan 3 12:25:21 2009 ---- blob/src/include/catalog/pg_largeobject.h Fri Dec 18 09:40:55 2009 -*************** typedef FormData_pg_largeobject *Form_pg -*** 51,58 **** - #define Anum_pg_largeobject_pageno 2 - #define Anum_pg_largeobject_data 3 - -! extern void LargeObjectCreate(Oid loid); - extern void LargeObjectDrop(Oid loid); - extern bool LargeObjectExists(Oid loid); - - #endif /* PG_LARGEOBJECT_H */ ---- 51,59 ---- - #define Anum_pg_largeobject_pageno 2 - #define Anum_pg_largeobject_data 3 - -! extern Oid LargeObjectCreate(Oid loid); - extern void LargeObjectDrop(Oid loid); -+ extern void LargeObjectAlterOwner(Oid loid, Oid newOwnerId); - extern bool LargeObjectExists(Oid loid); - - #endif /* PG_LARGEOBJECT_H */ -diff -Nrpc base/src/include/catalog/pg_largeobject_metadata.h blob/src/include/catalog/pg_largeobject_metadata.h -*** base/src/include/catalog/pg_largeobject_metadata.h Thu Jan 1 09:00:00 1970 ---- blob/src/include/catalog/pg_largeobject_metadata.h Fri Dec 18 09:41:26 2009 -*************** -*** 0 **** ---- 1,52 ---- -+ /*------------------------------------------------------------------------- -+ * -+ * pg_largeobject_metadata.h -+ * definition of the system "largeobject_metadata" relation (pg_largeobject_metadata) -+ * along with the relation's initial contents. -+ * -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ * -+ * $PostgreSQL$ -+ * -+ * NOTES -+ * the genbki.sh script reads this file and generates .bki -+ * information from the DATA() statements. -+ * -+ *------------------------------------------------------------------------- -+ */ -+ #ifndef PG_LARGEOBJECT_METADATA_H -+ #define PG_LARGEOBJECT_METADATA_H -+ -+ #include "catalog/genbki.h" -+ -+ /* ---------------- -+ * pg_largeobject_metadata definition. cpp turns this into -+ * typedef struct FormData_pg_largeobject_metadata -+ * ---------------- -+ */ -+ #define LargeObjectMetadataRelationId 2995 -+ -+ CATALOG(pg_largeobject_metadata,2995) -+ { -+ Oid lomowner; /* OID of the largeobject owner */ -+ aclitem lomacl[1]; /* access permissions */ -+ } FormData_pg_largeobject_metadata; -+ -+ /* ---------------- -+ * Form_pg_largeobject_metadata corresponds to a pointer to a tuple -+ * with the format of pg_largeobject_metadata relation. -+ * ---------------- -+ */ -+ typedef FormData_pg_largeobject_metadata *Form_pg_largeobject_metadata; -+ -+ /* ---------------- -+ * compiler constants for pg_largeobject_metadata -+ * ---------------- -+ */ -+ #define Natts_pg_largeobject_metadata 2 -+ #define Anum_pg_largeobject_metadata_lomowner 1 -+ #define Anum_pg_largeobject_metadata_lomacl 2 -+ -+ #endif /* PG_LARGEOBJECT_METADATA_H */ -diff -Nrpc base/src/include/libpq/be-fsstubs.h blob/src/include/libpq/be-fsstubs.h -*** base/src/include/libpq/be-fsstubs.h Sat Jan 3 12:25:21 2009 ---- blob/src/include/libpq/be-fsstubs.h Fri Dec 18 09:40:55 2009 -*************** extern Datum lo_unlink(PG_FUNCTION_ARGS) -*** 38,43 **** ---- 38,48 ---- - extern Datum lo_truncate(PG_FUNCTION_ARGS); - - /* -+ * compatibility option for access control -+ */ -+ extern bool lo_compat_privileges; -+ -+ /* - * These are not fmgr-callable, but are available to C code. - * Probably these should have had the underscore-free names, - * but too late now... -diff -Nrpc base/src/include/nodes/parsenodes.h blob/src/include/nodes/parsenodes.h -*** base/src/include/nodes/parsenodes.h Tue Dec 15 17:16:51 2009 ---- blob/src/include/nodes/parsenodes.h Fri Dec 18 09:40:55 2009 -*************** typedef enum GrantObjectType -*** 1186,1191 **** ---- 1186,1192 ---- - ACL_OBJECT_FOREIGN_SERVER, /* foreign server */ - ACL_OBJECT_FUNCTION, /* function */ - ACL_OBJECT_LANGUAGE, /* procedural language */ -+ ACL_OBJECT_LARGEOBJECT, /* largeobject */ - ACL_OBJECT_NAMESPACE, /* namespace */ - ACL_OBJECT_TABLESPACE /* tablespace */ - } GrantObjectType; -diff -Nrpc base/src/include/utils/acl.h blob/src/include/utils/acl.h -*** base/src/include/utils/acl.h Thu Jun 18 10:20:52 2009 ---- blob/src/include/utils/acl.h Fri Dec 18 09:40:55 2009 -*************** -*** 26,31 **** ---- 26,32 ---- - - #include "nodes/parsenodes.h" - #include "utils/array.h" -+ #include "utils/snapshot.h" - - - /* -*************** typedef ArrayType Acl; -*** 151,156 **** ---- 152,158 ---- - #define ACL_ALL_RIGHTS_FOREIGN_SERVER (ACL_USAGE) - #define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE) - #define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE) -+ #define ACL_ALL_RIGHTS_LARGEOBJECT (ACL_SELECT|ACL_UPDATE) - #define ACL_ALL_RIGHTS_NAMESPACE (ACL_USAGE|ACL_CREATE) - #define ACL_ALL_RIGHTS_TABLESPACE (ACL_CREATE) - -*************** typedef enum AclObjectKind -*** 181,186 **** ---- 183,189 ---- - ACL_KIND_OPER, /* pg_operator */ - ACL_KIND_TYPE, /* pg_type */ - ACL_KIND_LANGUAGE, /* pg_language */ -+ ACL_KIND_LARGEOBJECT, /* pg_largeobject */ - ACL_KIND_NAMESPACE, /* pg_namespace */ - ACL_KIND_OPCLASS, /* pg_opclass */ - ACL_KIND_OPFAMILY, /* pg_opfamily */ -*************** extern AclMode pg_proc_aclmask(Oid proc_ -*** 273,278 **** ---- 276,283 ---- - AclMode mask, AclMaskHow how); - extern AclMode pg_language_aclmask(Oid lang_oid, Oid roleid, - AclMode mask, AclMaskHow how); -+ extern AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, -+ AclMode mask, AclMaskHow how, Snapshot snapshot); - extern AclMode pg_namespace_aclmask(Oid nsp_oid, Oid roleid, - AclMode mask, AclMaskHow how); - extern AclMode pg_tablespace_aclmask(Oid spc_oid, Oid roleid, -*************** extern AclResult pg_class_aclcheck(Oid t -*** 290,295 **** ---- 295,302 ---- - extern AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode); - extern AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode); - extern AclResult pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode); -+ extern AclResult pg_largeobject_aclcheck_snapshot(Oid lang_oid, Oid roleid, -+ AclMode mode, Snapshot snapshot); - extern AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode); - extern AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode); - extern AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode); -*************** extern bool pg_type_ownercheck(Oid type_ -*** 307,312 **** ---- 314,320 ---- - extern bool pg_oper_ownercheck(Oid oper_oid, Oid roleid); - extern bool pg_proc_ownercheck(Oid proc_oid, Oid roleid); - extern bool pg_language_ownercheck(Oid lan_oid, Oid roleid); -+ extern bool pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid); - extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid); - extern bool pg_tablespace_ownercheck(Oid spc_oid, Oid roleid); - extern bool pg_opclass_ownercheck(Oid opc_oid, Oid roleid); -diff -Nrpc base/src/test/regress/expected/privileges.out blob/src/test/regress/expected/privileges.out -*** base/src/test/regress/expected/privileges.out Fri Mar 6 09:45:33 2009 ---- blob/src/test/regress/expected/privileges.out Fri Dec 18 09:40:55 2009 -*************** DROP ROLE IF EXISTS regressuser2; -*** 11,16 **** ---- 11,22 ---- - DROP ROLE IF EXISTS regressuser3; - DROP ROLE IF EXISTS regressuser4; - DROP ROLE IF EXISTS regressuser5; -+ DROP ROLE IF EXISTS regressuser6; -+ SELECT lo_unlink(oid) FROM pg_largeobject_metadata; -+ lo_unlink -+ ----------- -+ (0 rows) -+ - RESET client_min_messages; - -- test proper begins here - CREATE USER regressuser1; -*************** SELECT has_table_privilege('regressuser1 -*** 815,820 **** ---- 821,1014 ---- - t - (1 row) - -+ -- largeobject privilege tests -+ \c - -+ SET SESSION AUTHORIZATION regressuser1; -+ SELECT lo_create(1001); -+ lo_create -+ ----------- -+ 1001 -+ (1 row) -+ -+ SELECT lo_create(1002); -+ lo_create -+ ----------- -+ 1002 -+ (1 row) -+ -+ SELECT lo_create(1003); -+ lo_create -+ ----------- -+ 1003 -+ (1 row) -+ -+ SELECT lo_create(1004); -+ lo_create -+ ----------- -+ 1004 -+ (1 row) -+ -+ SELECT lo_create(1005); -+ lo_create -+ ----------- -+ 1005 -+ (1 row) -+ -+ GRANT ALL ON LARGE OBJECT 1001 TO PUBLIC; -+ GRANT SELECT ON LARGE OBJECT 1003 TO regressuser2; -+ GRANT SELECT,UPDATE ON LARGE OBJECT 1004 TO regressuser2; -+ GRANT ALL ON LARGE OBJECT 1005 TO regressuser2; -+ GRANT SELECT ON LARGE OBJECT 1005 TO regressuser2 WITH GRANT OPTION; -+ GRANT SELECT, INSERT ON LARGE OBJECT 1001 TO PUBLIC; -- to be failed -+ ERROR: invalid privilege type INSERT for large object -+ GRANT SELECT, UPDATE ON LARGE OBJECT 1001 TO nosuchuser; -- to be failed -+ ERROR: role "nosuchuser" does not exist -+ GRANT SELECT, UPDATE ON LARGE OBJECT 999 TO PUBLIC; -- to be failed -+ ERROR: large object 999 does not exist -+ \c - -+ SET SESSION AUTHORIZATION regressuser2; -+ SELECT lo_create(2001); -+ lo_create -+ ----------- -+ 2001 -+ (1 row) -+ -+ SELECT lo_create(2002); -+ lo_create -+ ----------- -+ 2002 -+ (1 row) -+ -+ SELECT loread(lo_open(1001, x'40000'::int), 32); -+ loread -+ -------- -+ -+ (1 row) -+ -+ SELECT loread(lo_open(1002, x'40000'::int), 32); -- to be denied -+ ERROR: permission denied for large object 1002 -+ SELECT loread(lo_open(1003, x'40000'::int), 32); -+ loread -+ -------- -+ -+ (1 row) -+ -+ SELECT loread(lo_open(1004, x'40000'::int), 32); -+ loread -+ -------- -+ -+ (1 row) -+ -+ SELECT lowrite(lo_open(1001, x'20000'::int), 'abcd'); -+ lowrite -+ --------- -+ 4 -+ (1 row) -+ -+ SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied -+ ERROR: permission denied for large object 1002 -+ SELECT lowrite(lo_open(1003, x'20000'::int), 'abcd'); -- to be denied -+ ERROR: permission denied for large object 1003 -+ SELECT lowrite(lo_open(1004, x'20000'::int), 'abcd'); -+ lowrite -+ --------- -+ 4 -+ (1 row) -+ -+ GRANT SELECT ON LARGE OBJECT 1005 TO regressuser3; -+ GRANT UPDATE ON LARGE OBJECT 1006 TO regressuser3; -- to be denied -+ ERROR: large object 1006 does not exist -+ REVOKE ALL ON LARGE OBJECT 2001, 2002 FROM PUBLIC; -+ GRANT ALL ON LARGE OBJECT 2001 TO regressuser3; -+ SELECT lo_unlink(1001); -- to be denied -+ ERROR: must be owner of large object 1001 -+ SELECT lo_unlink(2002); -+ lo_unlink -+ ----------- -+ 1 -+ (1 row) -+ -+ \c - -+ -- confirm ACL setting -+ SELECT oid, pg_get_userbyid(lomowner) ownername, lomacl FROM pg_largeobject_metadata; -+ oid | ownername | lomacl -+ ------+--------------+------------------------------------------------------------------------------------------ -+ 1002 | regressuser1 | -+ 1001 | regressuser1 | {regressuser1=rw/regressuser1,=rw/regressuser1} -+ 1003 | regressuser1 | {regressuser1=rw/regressuser1,regressuser2=r/regressuser1} -+ 1004 | regressuser1 | {regressuser1=rw/regressuser1,regressuser2=rw/regressuser1} -+ 1005 | regressuser1 | {regressuser1=rw/regressuser1,regressuser2=r*w/regressuser1,regressuser3=r/regressuser2} -+ 2001 | regressuser2 | {regressuser2=rw/regressuser2,regressuser3=rw/regressuser2} -+ (6 rows) -+ -+ SET SESSION AUTHORIZATION regressuser3; -+ SELECT loread(lo_open(1001, x'40000'::int), 32); -+ loread -+ -------- -+ abcd -+ (1 row) -+ -+ SELECT loread(lo_open(1003, x'40000'::int), 32); -- to be denied -+ ERROR: permission denied for large object 1003 -+ SELECT loread(lo_open(1005, x'40000'::int), 32); -+ loread -+ -------- -+ -+ (1 row) -+ -+ SELECT lo_truncate(lo_open(1005, x'20000'::int), 10); -- to be denied -+ ERROR: permission denied for large object 1005 -+ SELECT lo_truncate(lo_open(2001, x'20000'::int), 10); -+ lo_truncate -+ ------------- -+ 0 -+ (1 row) -+ -+ -- compatibility mode in largeobject permission -+ \c - -+ SET lo_compat_privileges = false; -- default setting -+ SET SESSION AUTHORIZATION regressuser4; -+ SELECT loread(lo_open(1002, x'40000'::int), 32); -- to be denied -+ ERROR: permission denied for large object 1002 -+ SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied -+ ERROR: permission denied for large object 1002 -+ SELECT lo_truncate(lo_open(1002, x'20000'::int), 10); -- to be denied -+ ERROR: permission denied for large object 1002 -+ SELECT lo_unlink(1002); -- to be denied -+ ERROR: must be owner of large object 1002 -+ SELECT lo_export(1001, '/dev/null'); -- to be denied -+ ERROR: must be superuser to use server-side lo_export() -+ HINT: Anyone can use the client-side lo_export() provided by libpq. -+ \c - -+ SET lo_compat_privileges = true; -- compatibility mode -+ SET SESSION AUTHORIZATION regressuser4; -+ SELECT loread(lo_open(1002, x'40000'::int), 32); -+ loread -+ -------- -+ -+ (1 row) -+ -+ SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -+ lowrite -+ --------- -+ 4 -+ (1 row) -+ -+ SELECT lo_truncate(lo_open(1002, x'20000'::int), 10); -+ lo_truncate -+ ------------- -+ 0 -+ (1 row) -+ -+ SELECT lo_unlink(1002); -+ lo_unlink -+ ----------- -+ 1 -+ (1 row) -+ -+ SELECT lo_export(1001, '/dev/null'); -- to be denied -+ ERROR: must be superuser to use server-side lo_export() -+ HINT: Anyone can use the client-side lo_export() provided by libpq. - -- clean up - \c - DROP FUNCTION testfunc2(int); -*************** DROP TABLE atest6; -*** 836,841 **** ---- 1030,1045 ---- - DROP TABLE atestc; - DROP TABLE atestp1; - DROP TABLE atestp2; -+ SELECT lo_unlink(oid) FROM pg_largeobject_metadata; -+ lo_unlink -+ ----------- -+ 1 -+ 1 -+ 1 -+ 1 -+ 1 -+ (5 rows) -+ - DROP GROUP regressgroup1; - DROP GROUP regressgroup2; - REVOKE USAGE ON LANGUAGE sql FROM regressuser1; -*************** DROP USER regressuser2; -*** 844,846 **** ---- 1048,1052 ---- - DROP USER regressuser3; - DROP USER regressuser4; - DROP USER regressuser5; -+ DROP USER regressuser6; -+ ERROR: role "regressuser6" does not exist -diff -Nrpc base/src/test/regress/expected/sanity_check.out blob/src/test/regress/expected/sanity_check.out -*** base/src/test/regress/expected/sanity_check.out Tue Feb 10 10:10:02 2009 ---- blob/src/test/regress/expected/sanity_check.out Fri Dec 18 09:40:55 2009 -*************** SELECT relname, relhasindex -*** 104,109 **** ---- 104,110 ---- - pg_inherits | t - pg_language | t - pg_largeobject | t -+ pg_largeobject_metadata | t - pg_listener | f - pg_namespace | t - pg_opclass | t -*************** SELECT relname, relhasindex -*** 151,157 **** - timetz_tbl | f - tinterval_tbl | f - varchar_tbl | f -! (140 rows) - - -- - -- another sanity check: every system catalog that has OIDs should have ---- 152,158 ---- - timetz_tbl | f - tinterval_tbl | f - varchar_tbl | f -! (141 rows) - - -- - -- another sanity check: every system catalog that has OIDs should have -diff -Nrpc base/src/test/regress/sql/privileges.sql blob/src/test/regress/sql/privileges.sql -*** base/src/test/regress/sql/privileges.sql Fri Mar 6 09:45:33 2009 ---- blob/src/test/regress/sql/privileges.sql Fri Dec 18 09:40:55 2009 -*************** DROP ROLE IF EXISTS regressuser2; -*** 15,20 **** ---- 15,23 ---- - DROP ROLE IF EXISTS regressuser3; - DROP ROLE IF EXISTS regressuser4; - DROP ROLE IF EXISTS regressuser5; -+ DROP ROLE IF EXISTS regressuser6; -+ -+ SELECT lo_unlink(oid) FROM pg_largeobject_metadata; - - RESET client_min_messages; - -*************** ALTER GROUP regressgroup2 ADD USER regre -*** 36,42 **** - ALTER GROUP regressgroup2 DROP USER regressuser2; - ALTER GROUP regressgroup2 ADD USER regressuser4; - -- - -- test owner privileges - - SET SESSION AUTHORIZATION regressuser1; ---- 39,44 ---- -*************** SELECT has_table_privilege('regressuser3 -*** 468,473 **** ---- 470,552 ---- - - SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION'); -- true - -+ -- largeobject privilege tests -+ \c - -+ SET SESSION AUTHORIZATION regressuser1; -+ -+ SELECT lo_create(1001); -+ SELECT lo_create(1002); -+ SELECT lo_create(1003); -+ SELECT lo_create(1004); -+ SELECT lo_create(1005); -+ -+ GRANT ALL ON LARGE OBJECT 1001 TO PUBLIC; -+ GRANT SELECT ON LARGE OBJECT 1003 TO regressuser2; -+ GRANT SELECT,UPDATE ON LARGE OBJECT 1004 TO regressuser2; -+ GRANT ALL ON LARGE OBJECT 1005 TO regressuser2; -+ GRANT SELECT ON LARGE OBJECT 1005 TO regressuser2 WITH GRANT OPTION; -+ -+ GRANT SELECT, INSERT ON LARGE OBJECT 1001 TO PUBLIC; -- to be failed -+ GRANT SELECT, UPDATE ON LARGE OBJECT 1001 TO nosuchuser; -- to be failed -+ GRANT SELECT, UPDATE ON LARGE OBJECT 999 TO PUBLIC; -- to be failed -+ -+ \c - -+ SET SESSION AUTHORIZATION regressuser2; -+ -+ SELECT lo_create(2001); -+ SELECT lo_create(2002); -+ -+ SELECT loread(lo_open(1001, x'40000'::int), 32); -+ SELECT loread(lo_open(1002, x'40000'::int), 32); -- to be denied -+ SELECT loread(lo_open(1003, x'40000'::int), 32); -+ SELECT loread(lo_open(1004, x'40000'::int), 32); -+ -+ SELECT lowrite(lo_open(1001, x'20000'::int), 'abcd'); -+ SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied -+ SELECT lowrite(lo_open(1003, x'20000'::int), 'abcd'); -- to be denied -+ SELECT lowrite(lo_open(1004, x'20000'::int), 'abcd'); -+ -+ GRANT SELECT ON LARGE OBJECT 1005 TO regressuser3; -+ GRANT UPDATE ON LARGE OBJECT 1006 TO regressuser3; -- to be denied -+ REVOKE ALL ON LARGE OBJECT 2001, 2002 FROM PUBLIC; -+ GRANT ALL ON LARGE OBJECT 2001 TO regressuser3; -+ -+ SELECT lo_unlink(1001); -- to be denied -+ SELECT lo_unlink(2002); -+ -+ \c - -+ -- confirm ACL setting -+ SELECT oid, pg_get_userbyid(lomowner) ownername, lomacl FROM pg_largeobject_metadata; -+ -+ SET SESSION AUTHORIZATION regressuser3; -+ -+ SELECT loread(lo_open(1001, x'40000'::int), 32); -+ SELECT loread(lo_open(1003, x'40000'::int), 32); -- to be denied -+ SELECT loread(lo_open(1005, x'40000'::int), 32); -+ -+ SELECT lo_truncate(lo_open(1005, x'20000'::int), 10); -- to be denied -+ SELECT lo_truncate(lo_open(2001, x'20000'::int), 10); -+ -+ -- compatibility mode in largeobject permission -+ \c - -+ SET lo_compat_privileges = false; -- default setting -+ SET SESSION AUTHORIZATION regressuser4; -+ -+ SELECT loread(lo_open(1002, x'40000'::int), 32); -- to be denied -+ SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied -+ SELECT lo_truncate(lo_open(1002, x'20000'::int), 10); -- to be denied -+ SELECT lo_unlink(1002); -- to be denied -+ SELECT lo_export(1001, '/dev/null'); -- to be denied -+ -+ \c - -+ SET lo_compat_privileges = true; -- compatibility mode -+ SET SESSION AUTHORIZATION regressuser4; -+ -+ SELECT loread(lo_open(1002, x'40000'::int), 32); -+ SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -+ SELECT lo_truncate(lo_open(1002, x'20000'::int), 10); -+ SELECT lo_unlink(1002); -+ SELECT lo_export(1001, '/dev/null'); -- to be denied - - -- clean up - -*************** DROP TABLE atestc; -*** 493,498 **** ---- 572,579 ---- - DROP TABLE atestp1; - DROP TABLE atestp2; - -+ SELECT lo_unlink(oid) FROM pg_largeobject_metadata; -+ - DROP GROUP regressgroup1; - DROP GROUP regressgroup2; - -*************** DROP USER regressuser2; -*** 502,504 **** ---- 583,586 ---- - DROP USER regressuser3; - DROP USER regressuser4; - DROP USER regressuser5; -+ DROP USER regressuser6; diff --git a/pgsql-02-8.4-sepgsql.patch b/pgsql-02-8.4-sepgsql.patch deleted file mode 100644 index 0339b07..0000000 --- a/pgsql-02-8.4-sepgsql.patch +++ /dev/null @@ -1,20258 +0,0 @@ -diff -Nrpc blob/configure sepgsql/configure -*** blob/configure Thu Mar 18 09:43:03 2010 ---- sepgsql/configure Thu Mar 18 01:55:40 2010 -*************** with_libxml -*** 710,715 **** ---- 710,717 ---- - with_libxslt - with_system_tzdata - with_zlib -+ enable_selinux -+ SELINUX_LIBS - GREP - EGREP - ELF_SYS -*************** Optional Features: -*** 1378,1383 **** ---- 1380,1386 ---- - --enable-thread-safety make client libraries thread-safe - --enable-thread-safety-force - force thread-safety despite thread test failure -+ --enable-selinux enable to build with SELinux support - --disable-largefile omit support for large files - --disable-float4-byval disable float4 passed by value - --disable-float8-byval disable float8 passed by value -*************** fi -*** 5532,5537 **** ---- 5535,5717 ---- - - - # -+ # SELinux support -+ # -+ -+ pgac_args="$pgac_args enable_selinux" -+ -+ # Check whether --enable-selinux was given. -+ if test "${enable_selinux+set}" = set; then -+ enableval=$enable_selinux; -+ case $enableval in -+ yes) -+ : -+ ;; -+ no) -+ : -+ ;; -+ *) -+ { { echo "$as_me:$LINENO: error: no argument expected for --enable-selinux option" >&5 -+ echo "$as_me: error: no argument expected for --enable-selinux option" >&2;} -+ { (exit 1); exit 1; }; } -+ ;; -+ esac -+ -+ else -+ enable_selinux=no -+ -+ fi -+ -+ -+ if test "$enable_selinux" = yes; then -+ SELINUX_LIBS="-lselinux" -+ { echo "$as_me:$LINENO: checking for avc_netlink_loop in -lselinux" >&5 -+ echo $ECHO_N "checking for avc_netlink_loop in -lselinux... $ECHO_C" >&6; } -+ if test "${ac_cv_lib_selinux_avc_netlink_loop+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+ else -+ ac_check_lib_save_LIBS=$LIBS -+ LIBS="-lselinux $LIBS" -+ cat >conftest.$ac_ext <<_ACEOF -+ /* confdefs.h. */ -+ _ACEOF -+ cat confdefs.h >>conftest.$ac_ext -+ cat >>conftest.$ac_ext <<_ACEOF -+ /* end confdefs.h. */ -+ -+ /* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+ #ifdef __cplusplus -+ extern "C" -+ #endif -+ char avc_netlink_loop (); -+ int -+ main () -+ { -+ return avc_netlink_loop (); -+ ; -+ return 0; -+ } -+ _ACEOF -+ rm -f conftest.$ac_objext conftest$ac_exeext -+ if { (ac_try="$ac_link" -+ case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+ esac -+ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_link") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest$ac_exeext && -+ $as_test_x conftest$ac_exeext; then -+ ac_cv_lib_selinux_avc_netlink_loop=yes -+ else -+ echo "$as_me: failed program was:" >&5 -+ sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_cv_lib_selinux_avc_netlink_loop=no -+ fi -+ -+ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ -+ conftest$ac_exeext conftest.$ac_ext -+ LIBS=$ac_check_lib_save_LIBS -+ fi -+ { echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_avc_netlink_loop" >&5 -+ echo "${ECHO_T}$ac_cv_lib_selinux_avc_netlink_loop" >&6; } -+ if test $ac_cv_lib_selinux_avc_netlink_loop = yes; then -+ -+ cat >>confdefs.h <<_ACEOF -+ #define HAVE_SELINUX 1 -+ _ACEOF -+ -+ else -+ { { echo "$as_me:$LINENO: error: \"--enable-selinux requires libselinux.\"" >&5 -+ echo "$as_me: error: \"--enable-selinux requires libselinux.\"" >&2;} -+ { (exit 1); exit 1; }; } -+ fi -+ -+ { echo "$as_me:$LINENO: checking for audit_open in -laudit" >&5 -+ echo $ECHO_N "checking for audit_open in -laudit... $ECHO_C" >&6; } -+ if test "${ac_cv_lib_audit_audit_open+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+ else -+ ac_check_lib_save_LIBS=$LIBS -+ LIBS="-laudit $LIBS" -+ cat >conftest.$ac_ext <<_ACEOF -+ /* confdefs.h. */ -+ _ACEOF -+ cat confdefs.h >>conftest.$ac_ext -+ cat >>conftest.$ac_ext <<_ACEOF -+ /* end confdefs.h. */ -+ -+ /* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+ #ifdef __cplusplus -+ extern "C" -+ #endif -+ char audit_open (); -+ int -+ main () -+ { -+ return audit_open (); -+ ; -+ return 0; -+ } -+ _ACEOF -+ rm -f conftest.$ac_objext conftest$ac_exeext -+ if { (ac_try="$ac_link" -+ case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+ esac -+ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_link") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest$ac_exeext && -+ $as_test_x conftest$ac_exeext; then -+ ac_cv_lib_audit_audit_open=yes -+ else -+ echo "$as_me: failed program was:" >&5 -+ sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_cv_lib_audit_audit_open=no -+ fi -+ -+ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ -+ conftest$ac_exeext conftest.$ac_ext -+ LIBS=$ac_check_lib_save_LIBS -+ fi -+ { echo "$as_me:$LINENO: result: $ac_cv_lib_audit_audit_open" >&5 -+ echo "${ECHO_T}$ac_cv_lib_audit_audit_open" >&6; } -+ if test $ac_cv_lib_audit_audit_open = yes; then -+ cat >>confdefs.h <<_ACEOF -+ #define HAVE_LIBAUDIT 1 -+ _ACEOF -+ -+ SELINUX_LIBS="$SELINUX_LIBS -laudit" -+ fi -+ -+ -+ -+ fi -+ -+ # - # Elf - # - -*************** with_libxml!$with_libxml$ac_delim -*** 28125,28135 **** - with_libxslt!$with_libxslt$ac_delim - with_system_tzdata!$with_system_tzdata$ac_delim - with_zlib!$with_zlib$ac_delim - GREP!$GREP$ac_delim - EGREP!$EGREP$ac_delim - ELF_SYS!$ELF_SYS$ac_delim -- LDFLAGS_SL!$LDFLAGS_SL$ac_delim -- LD!$LD$ac_delim - _ACEOF - - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then ---- 28305,28315 ---- - with_libxslt!$with_libxslt$ac_delim - with_system_tzdata!$with_system_tzdata$ac_delim - with_zlib!$with_zlib$ac_delim -+ enable_selinux!$enable_selinux$ac_delim -+ SELINUX_LIBS!$SELINUX_LIBS$ac_delim - GREP!$GREP$ac_delim - EGREP!$EGREP$ac_delim - ELF_SYS!$ELF_SYS$ac_delim - _ACEOF - - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then -*************** _ACEOF -*** 28171,28176 **** ---- 28351,28358 ---- - ac_delim='%!_!# ' - for ac_last_try in false false false false false :; do - cat >conf$$subs.sed <<_ACEOF -+ LDFLAGS_SL!$LDFLAGS_SL$ac_delim -+ LD!$LD$ac_delim - with_gnu_ld!$with_gnu_ld$ac_delim - ld_R_works!$ld_R_works$ac_delim - RANLIB!$RANLIB$ac_delim -*************** vpath_build!$vpath_build$ac_delim -*** 28233,28239 **** - LTLIBOBJS!$LTLIBOBJS$ac_delim - _ACEOF - -! if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 60; then - break - elif $ac_last_try; then - { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 ---- 28415,28421 ---- - LTLIBOBJS!$LTLIBOBJS$ac_delim - _ACEOF - -! if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 62; then - break - elif $ac_last_try; then - { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -diff -Nrpc blob/configure.in sepgsql/configure.in -*** blob/configure.in Thu Mar 18 09:43:03 2010 ---- sepgsql/configure.in Thu Mar 18 01:55:40 2010 -*************** PGAC_ARG_BOOL(with, zlib, yes, -*** 764,769 **** ---- 764,787 ---- - AC_SUBST(with_zlib) - - # -+ # SELinux support -+ # -+ PGAC_ARG_BOOL(enable, selinux, no, -+ [enable to build with SELinux support]) -+ if test "$enable_selinux" = yes; then -+ SELINUX_LIBS="-lselinux" -+ AC_CHECK_LIB(selinux, avc_netlink_loop, -+ AC_DEFINE_UNQUOTED(HAVE_SELINUX, 1, -+ [SE-PostgreSQL feature is enabled]), -+ AC_MSG_ERROR("--enable-selinux requires libselinux.")) -+ AC_CHECK_LIB(audit, audit_open, -+ AC_DEFINE_UNQUOTED(HAVE_LIBAUDIT, 1) -+ SELINUX_LIBS="$SELINUX_LIBS -laudit") -+ AC_SUBST(enable_selinux) -+ AC_SUBST(SELINUX_LIBS) -+ fi -+ -+ # - # Elf - # - -diff -Nrpc blob/src/Makefile.global.in sepgsql/src/Makefile.global.in -*** blob/src/Makefile.global.in Tue Jun 30 01:26:47 2009 ---- sepgsql/src/Makefile.global.in Sun Dec 20 00:41:22 2009 -*************** enable_nls = @enable_nls@ -*** 165,170 **** ---- 165,171 ---- - enable_debug = @enable_debug@ - enable_dtrace = @enable_dtrace@ - enable_coverage = @enable_coverage@ -+ enable_selinux = @enable_selinux@ - enable_thread_safety = @enable_thread_safety@ - - python_includespec = @python_includespec@ -*************** TCL_INCLUDE_SPEC = @TCL_INCLUDE_SPEC@ -*** 184,189 **** ---- 185,192 ---- - TCL_SHARED_BUILD = @TCL_SHARED_BUILD@ - TCL_SHLIB_LD_LIBS = @TCL_SHLIB_LD_LIBS@ - -+ SELINUX_LIBS = @SELINUX_LIBS@ -+ - PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ - PTHREAD_LIBS = @PTHREAD_LIBS@ - -diff -Nrpc blob/src/backend/Makefile sepgsql/src/backend/Makefile -*** blob/src/backend/Makefile Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/Makefile Thu Mar 18 01:55:40 2010 -*************** include $(top_builddir)/src/Makefile.glo -*** 16,22 **** - - SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \ - main nodes optimizer port postmaster regex rewrite \ -! storage tcop tsearch utils $(top_builddir)/src/timezone - - include $(srcdir)/common.mk - ---- 16,22 ---- - - SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \ - main nodes optimizer port postmaster regex rewrite \ -! security storage tcop tsearch utils $(top_builddir)/src/timezone - - include $(srcdir)/common.mk - -*************** LIBS := $(filter-out -lpgport, $(LIBS)) -*** 40,45 **** ---- 40,48 ---- - # The backend doesn't need everything that's in LIBS, however - LIBS := $(filter-out -lz -lreadline -ledit -ltermcap -lncurses -lcurses, $(LIBS)) - -+ # SELinux Libraries -+ LIBS += $(SELINUX_LIBS) -+ - ########################################################################## - - all: submake-libpgport postgres $(POSTGRES_IMP) -diff -Nrpc blob/src/backend/access/common/heaptuple.c sepgsql/src/backend/access/common/heaptuple.c -*** blob/src/backend/access/common/heaptuple.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/access/common/heaptuple.c Thu Sep 10 15:18:03 2009 -*************** -*** 60,65 **** ---- 60,66 ---- - #include "access/heapam.h" - #include "access/sysattr.h" - #include "access/tuptoaster.h" -+ #include "catalog/pg_security.h" - #include "executor/tuptable.h" - - -*************** heap_attisnull(HeapTuple tup, int attnum -*** 287,292 **** ---- 288,294 ---- - case MinCommandIdAttributeNumber: - case MaxTransactionIdAttributeNumber: - case MaxCommandIdAttributeNumber: -+ case SecurityAttributeNumber: - /* these are never null */ - break; - -*************** heap_getsysattr(HeapTuple tup, int attnu -*** 599,604 **** ---- 601,609 ---- - case TableOidAttributeNumber: - result = ObjectIdGetDatum(tup->t_tableOid); - break; -+ case SecurityAttributeNumber: -+ result = securitySysattSecLabelOut(tup->t_tableOid, tup); -+ break; - default: - elog(ERROR, "invalid attnum: %d", attnum); - result = 0; /* keep compiler quiet */ -*************** heap_form_tuple(TupleDesc tupleDescripto -*** 722,727 **** ---- 727,734 ---- - - if (tupleDescriptor->tdhasoid) - len += sizeof(Oid); -+ if (tupleDescriptor->tdhassecid) -+ len += sizeof(Oid); - - hoff = len = MAXALIGN(len); /* align user data safely */ - -*************** heap_form_tuple(TupleDesc tupleDescripto -*** 753,758 **** ---- 760,767 ---- - - if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ - td->t_infomask = HEAP_HASOID; -+ if (tupleDescriptor->tdhassecid) -+ td->t_infomask |= HEAP_HASSECID; - - heap_fill_tuple(tupleDescriptor, - values, -*************** heap_modify_tuple(HeapTuple tuple, -*** 864,869 **** ---- 873,880 ---- - newTuple->t_tableOid = tuple->t_tableOid; - if (tupleDesc->tdhasoid) - HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple)); -+ if (HeapTupleHasSecid(newTuple)) -+ HeapTupleSetSecid(newTuple, HeapTupleGetSecid(tuple)); - - return newTuple; - } -*************** heap_form_minimal_tuple(TupleDesc tupleD -*** 1474,1479 **** ---- 1485,1492 ---- - - if (tupleDescriptor->tdhasoid) - len += sizeof(Oid); -+ if (tupleDescriptor->tdhassecid) -+ len += sizeof(Oid); - - hoff = len = MAXALIGN(len); /* align user data safely */ - -*************** heap_form_minimal_tuple(TupleDesc tupleD -*** 1495,1500 **** ---- 1508,1515 ---- - - if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ - tuple->t_infomask = HEAP_HASOID; -+ if (tupleDescriptor->tdhassecid) -+ tuple->t_infomask |= HEAP_HASSECID; - - heap_fill_tuple(tupleDescriptor, - values, -diff -Nrpc blob/src/backend/access/common/tupdesc.c sepgsql/src/backend/access/common/tupdesc.c -*** blob/src/backend/access/common/tupdesc.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/access/common/tupdesc.c Wed Sep 9 13:14:37 2009 -*************** CreateTemplateTupleDesc(int natts, bool -*** 88,93 **** ---- 88,94 ---- - desc->tdtypeid = RECORDOID; - desc->tdtypmod = -1; - desc->tdhasoid = hasoid; -+ desc->tdhassecid = false; - desc->tdrefcount = -1; /* assume not reference-counted */ - - return desc; -*************** CreateTupleDesc(int natts, bool hasoid, -*** 121,126 **** ---- 122,128 ---- - desc->tdtypeid = RECORDOID; - desc->tdtypmod = -1; - desc->tdhasoid = hasoid; -+ desc->tdhassecid = false; - desc->tdrefcount = -1; /* assume not reference-counted */ - - return desc; -*************** CreateTupleDescCopy(TupleDesc tupdesc) -*** 150,155 **** ---- 152,158 ---- - - desc->tdtypeid = tupdesc->tdtypeid; - desc->tdtypmod = tupdesc->tdtypmod; -+ desc->tdhassecid = tupdesc->tdhassecid; - - return desc; - } -*************** CreateTupleDescCopyConstr(TupleDesc tupd -*** 208,213 **** ---- 211,217 ---- - - desc->tdtypeid = tupdesc->tdtypeid; - desc->tdtypmod = tupdesc->tdtypmod; -+ desc->tdhassecid = tupdesc->tdhassecid; - - return desc; - } -*************** equalTupleDescs(TupleDesc tupdesc1, Tupl -*** 314,319 **** ---- 318,325 ---- - return false; - if (tupdesc1->tdhasoid != tupdesc2->tdhasoid) - return false; -+ if (tupdesc1->tdhassecid != tupdesc2->tdhassecid) -+ return false; - - for (i = 0; i < tupdesc1->natts; i++) - { -diff -Nrpc blob/src/backend/access/heap/heapam.c sepgsql/src/backend/access/heap/heapam.c -*** blob/src/backend/access/heap/heapam.c Sun Sep 6 19:40:49 2009 ---- sepgsql/src/backend/access/heap/heapam.c Sun Dec 20 16:30:19 2009 -*************** -*** 54,59 **** ---- 54,60 ---- - #include "catalog/namespace.h" - #include "miscadmin.h" - #include "pgstat.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/freespace.h" - #include "storage/lmgr.h" -*************** heap_insert(Relation relation, HeapTuple -*** 2016,2021 **** ---- 2017,2028 ---- - Oid - simple_heap_insert(Relation relation, HeapTuple tup) - { -+ /* -+ * SELinux assigns default security label for the tuple, -+ * but does not check permissions to the internal operations. -+ */ -+ sepgsqlHeapTupleInsert(relation, tup, true); -+ - return heap_insert(relation, tup, GetCurrentCommandId(true), 0, NULL); - } - -*************** l2: -*** 2558,2563 **** ---- 2565,2575 ---- - Assert(!(newtup->t_data->t_infomask & HEAP_HASOID)); - } - -+ /* Preserve SecurityId, if not changed */ -+ if (HeapTupleHasSecid(newtup) && -+ !OidIsValid(HeapTupleGetSecid(newtup))) -+ HeapTupleSetSecid(newtup, HeapTupleGetSecid(&oldtup)); -+ - newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK); - newtup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK); - newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED); -*************** heap_inplace_update(Relation relation, H -*** 3499,3504 **** ---- 3511,3518 ---- - memcpy((char *) htup + htup->t_hoff, - (char *) tuple->t_data + tuple->t_data->t_hoff, - newlen); -+ if (HeapTupleHeaderGetSecid(htup) != HeapTupleGetSecid(tuple)) -+ HeapTupleHeaderSetSecid(htup, HeapTupleGetSecid(tuple)); - - MarkBufferDirty(buffer); - -diff -Nrpc blob/src/backend/access/heap/tuptoaster.c sepgsql/src/backend/access/heap/tuptoaster.c -*** blob/src/backend/access/heap/tuptoaster.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/access/heap/tuptoaster.c Tue Sep 8 23:55:48 2009 -*************** toast_insert_or_update(Relation rel, Hea -*** 591,596 **** ---- 591,598 ---- - hoff += BITMAPLEN(numAttrs); - if (newtup->t_data->t_infomask & HEAP_HASOID) - hoff += sizeof(Oid); -+ if (HeapTupleHasSecid(newtup)) -+ hoff += sizeof(Oid); - hoff = MAXALIGN(hoff); - Assert(hoff == newtup->t_data->t_hoff); - /* now convert to a limit on the tuple data size */ -*************** toast_insert_or_update(Relation rel, Hea -*** 864,869 **** ---- 866,873 ---- - new_len += BITMAPLEN(numAttrs); - if (olddata->t_infomask & HEAP_HASOID) - new_len += sizeof(Oid); -+ if (HeapTupleHeaderHasSecid(olddata)) -+ new_len += sizeof(Oid); - new_len = MAXALIGN(new_len); - Assert(new_len == olddata->t_hoff); - new_data_len = heap_compute_data_size(tupleDesc, -*************** toast_flatten_tuple_attribute(Datum valu -*** 1015,1020 **** ---- 1019,1026 ---- - new_len += BITMAPLEN(numAttrs); - if (olddata->t_infomask & HEAP_HASOID) - new_len += sizeof(Oid); -+ if (HeapTupleHeaderHasSecid(olddata)) -+ new_len += sizeof(Oid); - new_len = MAXALIGN(new_len); - Assert(new_len == olddata->t_hoff); - new_data_len = heap_compute_data_size(tupleDesc, -*************** toast_save_datum(Relation rel, Datum val -*** 1213,1218 **** ---- 1219,1230 ---- - memcpy(VARDATA(&chunk_data), data_p, chunk_size); - toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull); - -+ /* -+ * NOTE: SE-PostgreSQL does not assign any security label -+ * for tuples within the TOASTVALUE relation, so we omit -+ * to put sepgsqlHeapTupleInsert() hook here. -+ */ -+ - heap_insert(toastrel, toasttup, mycid, options, NULL); - - /* -diff -Nrpc blob/src/backend/access/transam/xact.c sepgsql/src/backend/access/transam/xact.c -*** blob/src/backend/access/transam/xact.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/access/transam/xact.c Thu Mar 18 01:55:40 2010 -*************** -*** 36,41 **** ---- 36,43 ---- - #include "libpq/be-fsstubs.h" - #include "miscadmin.h" - #include "pgstat.h" -+ #include "security/rowlevel.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/fd.h" - #include "storage/lmgr.h" -*************** typedef struct TransactionStateData -*** 140,145 **** ---- 142,149 ---- - Oid prevUser; /* previous CurrentUserId setting */ - int prevSecContext; /* previous SecurityRestrictionContext */ - bool prevXactReadOnly; /* entry-time xact r/o state */ -+ char *prevSecLabel; /* previous security label of client */ -+ int prevRowlv; /* previous Row-level control behavior */ - struct TransactionStateData *parent; /* back link to parent */ - } TransactionStateData; - -*************** static TransactionStateData TopTransacti -*** 168,173 **** ---- 172,179 ---- - InvalidOid, /* previous CurrentUserId setting */ - 0, /* previous SecurityRestrictionContext */ - false, /* entry-time xact r/o state */ -+ NULL, /* previous security label of client */ -+ ROWLV_FILTER_MODE, /* previous Row-level control behavior */ - NULL /* link to parent state block */ - }; - -*************** StartTransaction(void) -*** 1527,1532 **** ---- 1533,1541 ---- - /* SecurityRestrictionContext should never be set outside a transaction */ - Assert(s->prevSecContext == 0); - -+ s->prevSecLabel = sepgsqlGetClientLabel(); -+ s->prevRowlv = rowlvGetPerformingMode(); -+ - /* - * initialize other subsystems for new transaction - */ -*************** AbortTransaction(void) -*** 2031,2036 **** ---- 2040,2051 ---- - SetUserIdAndSecContext(s->prevUser, s->prevSecContext); - - /* -+ * Reset SELinux features -+ */ -+ sepgsqlSetClientLabel(s->prevSecLabel); -+ rowlvSetPerformingMode(s->prevRowlv); -+ -+ /* - * do abort processing - */ - AfterTriggerEndXact(false); -*************** AbortSubTransaction(void) -*** 3877,3882 **** ---- 3892,3903 ---- - SetUserIdAndSecContext(s->prevUser, s->prevSecContext); - - /* -+ * Reset SELinux features -+ */ -+ sepgsqlSetClientLabel(s->prevSecLabel); -+ rowlvSetPerformingMode(s->prevRowlv); -+ -+ /* - * We can skip all this stuff if the subxact failed before creating a - * ResourceOwner... - */ -*************** PushTransaction(void) -*** 4018,4023 **** ---- 4039,4046 ---- - s->blockState = TBLOCK_SUBBEGIN; - GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext); - s->prevXactReadOnly = XactReadOnly; -+ s->prevSecLabel = sepgsqlGetClientLabel(); -+ s->prevRowlv = rowlvGetPerformingMode(); - - CurrentTransactionState = s; - -diff -Nrpc blob/src/backend/bootstrap/bootparse.y sepgsql/src/backend/bootstrap/bootparse.y -*** blob/src/backend/bootstrap/bootparse.y Sat Jan 3 13:01:35 2009 ---- sepgsql/src/backend/bootstrap/bootparse.y Thu Oct 8 09:29:32 2009 -*************** -*** 42,47 **** ---- 42,48 ---- - #include "nodes/pg_list.h" - #include "nodes/primnodes.h" - #include "rewrite/prs2lock.h" -+ #include "security/sepgsql.h" - #include "storage/block.h" - #include "storage/fd.h" - #include "storage/ipc.h" -*************** Boot_CreateStmt: -*** 211,216 **** ---- 212,224 ---- - else - { - Oid id; -+ Oid *secLabels = -+ sepgsql_relation_create(LexIDStr($5), -+ RELKIND_RELATION, -+ tupdesc, -+ PG_CATALOG_NAMESPACE, -+ NULL, NIL, -+ false, false); - - id = heap_create_with_catalog(LexIDStr($5), - PG_CATALOG_NAMESPACE, -*************** Boot_CreateStmt: -*** 225,231 **** - 0, - ONCOMMIT_NOOP, - (Datum) 0, -! true); - elog(DEBUG4, "relation created with oid %u", id); - } - do_end(); ---- 233,240 ---- - 0, - ONCOMMIT_NOOP, - (Datum) 0, -! true, -! secLabels); - elog(DEBUG4, "relation created with oid %u", id); - } - do_end(); -diff -Nrpc blob/src/backend/bootstrap/bootstrap.c sepgsql/src/backend/bootstrap/bootstrap.c -*** blob/src/backend/bootstrap/bootstrap.c Fri Feb 20 22:15:36 2009 ---- sepgsql/src/backend/bootstrap/bootstrap.c Sun Dec 20 16:30:19 2009 -*************** -*** 26,37 **** ---- 26,39 ---- - #include "access/xact.h" - #include "bootstrap/bootstrap.h" - #include "catalog/index.h" -+ #include "catalog/pg_security.h" - #include "catalog/pg_type.h" - #include "libpq/pqsignal.h" - #include "miscadmin.h" - #include "nodes/makefuncs.h" - #include "postmaster/bgwriter.h" - #include "postmaster/walwriter.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/ipc.h" - #include "storage/proc.h" -*************** AuxiliaryProcessMain(int argc, char *arg -*** 338,343 **** ---- 340,350 ---- - case WalWriterProcess: - statmsg = "wal writer process"; - break; -+ #ifdef HAVE_SELINUX -+ case SelinuxReceiverProcess: -+ statmsg = "selinux netlink receiver"; -+ break; -+ #endif - default: - statmsg = "??? process"; - break; -*************** AuxiliaryProcessMain(int argc, char *arg -*** 430,435 **** ---- 437,448 ---- - WalWriterMain(); - proc_exit(1); /* should never return */ - -+ #ifdef HAVE_SELINUX -+ case SelinuxReceiverProcess: -+ sepgsqlReceiverMain(); -+ proc_exit(1); /* should nener return */ -+ #endif -+ - default: - elog(PANIC, "unrecognized process type: %d", auxType); - proc_exit(1); -*************** BootstrapModeMain(void) -*** 497,502 **** ---- 510,520 ---- - */ - boot_yyparse(); - -+ /* -+ * SELinux initial labeling -+ */ -+ sepgsqlPostBootstrapingMode(); -+ - /* Perform a checkpoint to ensure everything's down to disk */ - SetProcessingMode(NormalProcessing); - CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE); -*************** InsertOneTuple(Oid objectid) -*** 794,799 **** ---- 812,819 ---- - tupDesc = CreateTupleDesc(numattr, - RelationGetForm(boot_reldesc)->relhasoids, - attrtypes); -+ tupDesc->tdhassecid = RelationGetDescr(boot_reldesc)->tdhassecid; -+ - tuple = heap_form_tuple(tupDesc, values, Nulls); - if (objectid != (Oid) 0) - HeapTupleSetOid(tuple, objectid); -diff -Nrpc blob/src/backend/catalog/Makefile sepgsql/src/backend/catalog/Makefile -*** blob/src/backend/catalog/Makefile Fri Dec 18 09:40:55 2009 ---- sepgsql/src/backend/catalog/Makefile Fri Dec 18 10:27:56 2009 -*************** include $(top_builddir)/src/Makefile.glo -*** 13,19 **** - OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \ - pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \ - pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \ -! pg_shdepend.o pg_type.o storage.o toasting.o - - BKIFILES = postgres.bki postgres.description postgres.shdescription - ---- 13,19 ---- - OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \ - pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \ - pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \ -! pg_security.o pg_shdepend.o pg_type.o storage.o toasting.o - - BKIFILES = postgres.bki postgres.description postgres.shdescription - -*************** POSTGRES_BKI_SRCS = $(addprefix $(top_sr -*** 34,40 **** - pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \ - pg_database.h pg_tablespace.h pg_pltemplate.h \ - pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \ -! pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ - pg_ts_parser.h pg_ts_template.h \ - pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ - toasting.h indexing.h \ ---- 34,40 ---- - pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \ - pg_database.h pg_tablespace.h pg_pltemplate.h \ - pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \ -! pg_security.h pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ - pg_ts_parser.h pg_ts_template.h \ - pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ - toasting.h indexing.h \ -diff -Nrpc blob/src/backend/catalog/aclchk.c sepgsql/src/backend/catalog/aclchk.c -*** blob/src/backend/catalog/aclchk.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/catalog/aclchk.c Thu Mar 18 01:55:40 2010 -*************** -*** 37,42 **** ---- 37,43 ---- - #include "catalog/pg_operator.h" - #include "catalog/pg_opfamily.h" - #include "catalog/pg_proc.h" -+ #include "catalog/pg_security.h" - #include "catalog/pg_tablespace.h" - #include "catalog/pg_type.h" - #include "catalog/pg_ts_config.h" -*************** -*** 45,50 **** ---- 46,52 ---- - #include "foreign/foreign.h" - #include "miscadmin.h" - #include "parser/parse_func.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/fmgroids.h" - #include "utils/lsyscache.h" -*************** expand_all_col_privileges(Oid table_oid, -*** 735,740 **** ---- 737,748 ---- - if (curr_att == ObjectIdAttributeNumber && !classForm->relhasoids) - continue; - -+ /* Skip OID column, if it doesn't exist */ -+ if (curr_att == SecurityAttributeNumber && -+ (classForm->relkind != RELKIND_RELATION || -+ table_oid == SecurityRelationId)) -+ continue; -+ - /* Views don't have any system columns at all */ - if (classForm->relkind == RELKIND_VIEW && curr_att < 0) - continue; -*************** ExecGrant_Attribute(InternalGrant *istmt -*** 837,842 **** ---- 845,852 ---- - relOid, grantorId, ACL_KIND_COLUMN, - relname, attnum, - NameStr(pg_attribute_tuple->attname)); -+ /* SELinux checks */ -+ sepgsql_attribute_grant(relOid, attnum); - - /* - * Generate new ACL. -*************** ExecGrant_Relation(InternalGrant *istmt) -*** 1092,1097 **** ---- 1102,1109 ---- - ? ACL_KIND_SEQUENCE : ACL_KIND_CLASS, - NameStr(pg_class_tuple->relname), - 0, NULL); -+ /* SELinux checks */ -+ sepgsql_relation_grant(relOid); - - /* - * Generate new ACL. -*************** ExecGrant_Database(InternalGrant *istmt) -*** 1280,1285 **** ---- 1292,1299 ---- - datId, grantorId, ACL_KIND_DATABASE, - NameStr(pg_database_tuple->datname), - 0, NULL); -+ /* SELinux permission checks */ -+ sepgsql_database_grant(datId); - - /* - * Generate new ACL. -*************** ExecGrant_Fdw(InternalGrant *istmt) -*** 1398,1403 **** ---- 1412,1419 ---- - fdwid, grantorId, ACL_KIND_FDW, - NameStr(pg_fdw_tuple->fdwname), - 0, NULL); -+ /* SELinux permission checks */ -+ sepgsql_fdw_grant(fdwid); - - /* - * Generate new ACL. -*************** ExecGrant_ForeignServer(InternalGrant *i -*** 1517,1522 **** ---- 1533,1540 ---- - srvid, grantorId, ACL_KIND_FOREIGN_SERVER, - NameStr(pg_server_tuple->srvname), - 0, NULL); -+ /* SELinux checks */ -+ sepgsql_foreign_server_grant(srvid); - - /* - * Generate new ACL. -*************** ExecGrant_Function(InternalGrant *istmt) -*** 1635,1640 **** ---- 1653,1660 ---- - funcId, grantorId, ACL_KIND_PROC, - NameStr(pg_proc_tuple->proname), - 0, NULL); -+ /* SELinux: db_procedure:{setattr} */ -+ sepgsql_proc_grant(funcId); - - /* - * Generate new ACL. -*************** ExecGrant_Language(InternalGrant *istmt) -*** 1759,1764 **** ---- 1779,1786 ---- - langId, grantorId, ACL_KIND_LANGUAGE, - NameStr(pg_language_tuple->lanname), - 0, NULL); -+ /* SELinux checks */ -+ sepgsql_language_grant(langId); - - /* - * Generate new ACL. -*************** ExecGrant_Namespace(InternalGrant *istmt -*** 2010,2015 **** ---- 2032,2040 ---- - NameStr(pg_namespace_tuple->nspname), - 0, NULL); - -+ /* SELinux: db_schema:{setattr} */ -+ sepgsql_schema_grant(nspid); -+ - /* - * Generate new ACL. - * -diff -Nrpc blob/src/backend/catalog/catalog.c sepgsql/src/backend/catalog/catalog.c -*** blob/src/backend/catalog/catalog.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/catalog/catalog.c Wed Jul 15 19:30:50 2009 -*************** -*** 31,36 **** ---- 31,37 ---- - #include "catalog/pg_database.h" - #include "catalog/pg_namespace.h" - #include "catalog/pg_pltemplate.h" -+ #include "catalog/pg_security.h" - #include "catalog/pg_shdepend.h" - #include "catalog/pg_shdescription.h" - #include "catalog/pg_tablespace.h" -*************** IsSharedRelation(Oid relationId) -*** 304,309 **** ---- 305,311 ---- - relationId == AuthMemRelationId || - relationId == DatabaseRelationId || - relationId == PLTemplateRelationId || -+ relationId == SecurityRelationId || - relationId == SharedDescriptionRelationId || - relationId == SharedDependRelationId || - relationId == TableSpaceRelationId) -*************** IsSharedRelation(Oid relationId) -*** 316,321 **** ---- 318,325 ---- - relationId == DatabaseNameIndexId || - relationId == DatabaseOidIndexId || - relationId == PLTemplateNameIndexId || -+ relationId == SecuritySecidIndexId || -+ relationId == SecuritySecattrIndexId || - relationId == SharedDescriptionObjIndexId || - relationId == SharedDependDependerIndexId || - relationId == SharedDependReferenceIndexId || -*************** IsSharedRelation(Oid relationId) -*** 327,332 **** ---- 331,338 ---- - relationId == PgAuthidToastIndex || - relationId == PgDatabaseToastTable || - relationId == PgDatabaseToastIndex || -+ relationId == PgSecurityToastTable || -+ relationId == PgSecurityToastIndex || - relationId == PgShdescriptionToastTable || - relationId == PgShdescriptionToastIndex) - return true; -diff -Nrpc blob/src/backend/catalog/dependency.c sepgsql/src/backend/catalog/dependency.c -*** blob/src/backend/catalog/dependency.c Fri Dec 18 09:40:55 2009 ---- sepgsql/src/backend/catalog/dependency.c Fri Dec 18 10:27:56 2009 -*************** -*** 64,69 **** ---- 64,70 ---- - #include "nodes/nodeFuncs.h" - #include "parser/parsetree.h" - #include "rewrite/rewriteRemove.h" -+ #include "security/sepgsql.h" - #include "storage/lmgr.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -*************** static void reportDependentObjects(const -*** 162,168 **** - DropBehavior behavior, - int msglevel, - const ObjectAddress *origObject); -! static void deleteOneObject(const ObjectAddress *object, Relation depRel); - static void doDeletion(const ObjectAddress *object); - static void AcquireDeletionLock(const ObjectAddress *object); - static void ReleaseDeletionLock(const ObjectAddress *object); ---- 163,170 ---- - DropBehavior behavior, - int msglevel, - const ObjectAddress *origObject); -! static void deleteOneObject(const ObjectAddress *object, -! Relation depRel, bool permission); - static void doDeletion(const ObjectAddress *object); - static void AcquireDeletionLock(const ObjectAddress *object); - static void ReleaseDeletionLock(const ObjectAddress *object); -*************** static void getOpFamilyDescription(Strin -*** 194,202 **** - * are variants on the same theme; if you change anything here you'll likely - * need to fix them too. - */ -! void -! performDeletion(const ObjectAddress *object, -! DropBehavior behavior) - { - Relation depRel; - ObjectAddresses *targetObjects; ---- 196,204 ---- - * are variants on the same theme; if you change anything here you'll likely - * need to fix them too. - */ -! static void -! performDeletionInternal(const ObjectAddress *object, -! DropBehavior behavior, bool permission) - { - Relation depRel; - ObjectAddresses *targetObjects; -*************** performDeletion(const ObjectAddress *obj -*** 242,248 **** - { - ObjectAddress *thisobj = targetObjects->refs + i; - -! deleteOneObject(thisobj, depRel); - } - - /* And clean up */ ---- 244,250 ---- - { - ObjectAddress *thisobj = targetObjects->refs + i; - -! deleteOneObject(thisobj, depRel, permission); - } - - /* And clean up */ -*************** performDeletion(const ObjectAddress *obj -*** 251,256 **** ---- 253,270 ---- - heap_close(depRel, RowExclusiveLock); - } - -+ void -+ performDeletion(const ObjectAddress *object, DropBehavior behavior) -+ { -+ performDeletionInternal(object, behavior, true); -+ } -+ -+ void -+ performDeletionNoPerms(const ObjectAddress *object, DropBehavior behavior) -+ { -+ performDeletionInternal(object, behavior, false); -+ } -+ - /* - * performMultipleDeletions: Similar to performDeletion, but act on multiple - * objects at once. -*************** performMultipleDeletions(const ObjectAdd -*** 324,330 **** - { - ObjectAddress *thisobj = targetObjects->refs + i; - -! deleteOneObject(thisobj, depRel); - } - - /* And clean up */ ---- 338,345 ---- - { - ObjectAddress *thisobj = targetObjects->refs + i; - -! /* currently, all the caller path need permission checks */ -! deleteOneObject(thisobj, depRel, true); - } - - /* And clean up */ -*************** deleteWhatDependsOn(const ObjectAddress -*** 395,401 **** - if (thisextra->flags & DEPFLAG_ORIGINAL) - continue; - -! deleteOneObject(thisobj, depRel); - } - - /* And clean up */ ---- 410,416 ---- - if (thisextra->flags & DEPFLAG_ORIGINAL) - continue; - -! deleteOneObject(thisobj, depRel, false); - } - - /* And clean up */ -*************** reportDependentObjects(const ObjectAddre -*** 945,957 **** - * depRel is the already-open pg_depend relation. - */ - static void -! deleteOneObject(const ObjectAddress *object, Relation depRel) - { - ScanKeyData key[3]; - int nkeys; - SysScanDesc scan; - HeapTuple tup; - - /* - * First remove any pg_depend records that link from this object to - * others. (Any records linking to this object should be gone already.) ---- 960,976 ---- - * depRel is the already-open pg_depend relation. - */ - static void -! deleteOneObject(const ObjectAddress *object, Relation depRel, bool permission) - { - ScanKeyData key[3]; - int nkeys; - SysScanDesc scan; - HeapTuple tup; - -+ /* SELinux checks db_xxx:{drop}, if necessary */ -+ if (permission) -+ sepgsql_sysobj_drop(object); -+ - /* - * First remove any pg_depend records that link from this object to - * others. (Any records linking to this object should be gone already.) -diff -Nrpc blob/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c -*** blob/src/backend/catalog/heap.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/catalog/heap.c Wed Sep 9 16:47:01 2009 -*************** -*** 43,48 **** ---- 43,49 ---- - #include "catalog/pg_constraint.h" - #include "catalog/pg_inherits.h" - #include "catalog/pg_namespace.h" -+ #include "catalog/pg_security.h" - #include "catalog/pg_statistic.h" - #include "catalog/pg_tablespace.h" - #include "catalog/pg_type.h" -*************** -*** 56,61 **** ---- 57,63 ---- - #include "parser/parse_coerce.h" - #include "parser/parse_expr.h" - #include "parser/parse_relation.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/freespace.h" - #include "storage/smgr.h" -*************** static void AddNewRelationTuple(Relation -*** 74,80 **** - Oid new_rel_oid, Oid new_type_oid, - Oid relowner, - char relkind, -! Datum reloptions); - static Oid AddNewRelationType(const char *typeName, - Oid typeNamespace, - Oid new_rel_oid, ---- 76,83 ---- - Oid new_rel_oid, Oid new_type_oid, - Oid relowner, - char relkind, -! Datum reloptions, -! Oid *secLabels); - static Oid AddNewRelationType(const char *typeName, - Oid typeNamespace, - Oid new_rel_oid, -*************** static FormData_pg_attribute a7 = { -*** 158,164 **** - true, 'p', 'i', true, false, false, true, 0, {0} - }; - -! static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; - - /* - * This function returns a Form_pg_attribute pointer for a system attribute. ---- 161,176 ---- - true, 'p', 'i', true, false, false, true, 0, {0} - }; - -! /* -! * System columns for enhanced security features -! */ -! static FormData_pg_attribute a8 = { -! 0, {SecurityAttributeName}, TEXTOID, 0, -1, -! SecurityAttributeNumber, 0, -1, -1, -! false, 'x', 'i', true, false, false, true, 0, {0} -! }; -! -! static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8}; - - /* - * This function returns a Form_pg_attribute pointer for a system attribute. -*************** SystemAttributeByName(const char *attnam -*** 198,203 **** ---- 210,226 ---- - return NULL; - } - -+ /* -+ * If the given attribute number is writable, returns true. -+ */ -+ bool -+ SystemAttributeIsWritable(AttrNumber attnum) -+ { -+ if (attnum == SecurityAttributeNumber) -+ return true; -+ -+ return false; -+ } - - /* ---------------------------------------------------------------- - * XXX END OF UGLY HARD CODED BADNESS XXX -*************** heap_create(const char *relname, -*** 293,298 **** ---- 316,326 ---- - relid, - reltablespace, - shared_relation); -+ /* -+ * Does the relation have security attribute? -+ */ -+ RelationGetDescr(rel)->tdhassecid -+ = securityTupleDescHasSecid(relid, relkind); - - /* - * Have the storage manager create the relation's disk file, if needed. -*************** CheckAttributeType(const char *attname, -*** 487,493 **** - void - InsertPgAttributeTuple(Relation pg_attribute_rel, - Form_pg_attribute new_attribute, -! CatalogIndexState indstate) - { - Datum values[Natts_pg_attribute]; - bool nulls[Natts_pg_attribute]; ---- 515,522 ---- - void - InsertPgAttributeTuple(Relation pg_attribute_rel, - Form_pg_attribute new_attribute, -! CatalogIndexState indstate, -! Oid new_att_secid) - { - Datum values[Natts_pg_attribute]; - bool nulls[Natts_pg_attribute]; -*************** InsertPgAttributeTuple(Relation pg_attri -*** 520,525 **** ---- 549,557 ---- - - tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls); - -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, new_att_secid); -+ - /* finally insert the new tuple, update the indexes, and clean up */ - simple_heap_insert(pg_attribute_rel, tup); - -*************** AddNewAttributeTuples(Oid new_rel_oid, -*** 543,555 **** - TupleDesc tupdesc, - char relkind, - bool oidislocal, -! int oidinhcount) - { - Form_pg_attribute attr; - int i; - Relation rel; - CatalogIndexState indstate; - int natts = tupdesc->natts; - ObjectAddress myself, - referenced; - ---- 575,589 ---- - TupleDesc tupdesc, - char relkind, - bool oidislocal, -! int oidinhcount, -! Oid *secLabels) - { - Form_pg_attribute attr; - int i; - Relation rel; - CatalogIndexState indstate; - int natts = tupdesc->natts; -+ Oid new_att_secid; - ObjectAddress myself, - referenced; - -*************** AddNewAttributeTuples(Oid new_rel_oid, -*** 573,579 **** - attr->attstattarget = -1; - attr->attcacheoff = -1; - -! InsertPgAttributeTuple(rel, attr, indstate); - - /* Add dependency info */ - myself.classId = RelationRelationId; ---- 607,617 ---- - attr->attstattarget = -1; - attr->attcacheoff = -1; - -! /* Security label of the column */ -! new_att_secid = (!secLabels ? InvalidOid -! : secLabels[i - FirstLowInvalidHeapAttributeNumber]); -! -! InsertPgAttributeTuple(rel, attr, indstate, new_att_secid); - - /* Add dependency info */ - myself.classId = RelationRelationId; -*************** AddNewAttributeTuples(Oid new_rel_oid, -*** 601,606 **** ---- 639,650 ---- - SysAtt[i]->attnum == ObjectIdAttributeNumber) - continue; - -+ /* skip Secid where appropriate */ -+ if (SysAtt[i]->attnum == SecurityAttributeNumber && -+ (relkind != RELKIND_RELATION || -+ new_rel_oid == SecurityRelationId)) -+ continue; -+ - memcpy(&attStruct, (char *) SysAtt[i], sizeof(FormData_pg_attribute)); - - /* Fill in the correct relation OID in the copied tuple */ -*************** AddNewAttributeTuples(Oid new_rel_oid, -*** 613,619 **** - attStruct.attinhcount = oidinhcount; - } - -! InsertPgAttributeTuple(rel, &attStruct, indstate); - } - } - ---- 657,667 ---- - attStruct.attinhcount = oidinhcount; - } - -! /* Security label of the system column */ -! new_att_secid = (!secLabels ? InvalidOid -! : secLabels[SysAtt[i]->attnum - FirstLowInvalidHeapAttributeNumber]); -! -! InsertPgAttributeTuple(rel, &attStruct, indstate, new_att_secid); - } - } - -*************** void -*** 641,647 **** - InsertPgClassTuple(Relation pg_class_desc, - Relation new_rel_desc, - Oid new_rel_oid, -! Datum reloptions) - { - Form_pg_class rd_rel = new_rel_desc->rd_rel; - Datum values[Natts_pg_class]; ---- 689,696 ---- - InsertPgClassTuple(Relation pg_class_desc, - Relation new_rel_desc, - Oid new_rel_oid, -! Datum reloptions, -! Oid new_rel_secid) - { - Form_pg_class rd_rel = new_rel_desc->rd_rel; - Datum values[Natts_pg_class]; -*************** InsertPgClassTuple(Relation pg_class_des -*** 690,695 **** ---- 739,747 ---- - */ - HeapTupleSetOid(tup, new_rel_oid); - -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, new_rel_secid); -+ - /* finally insert the new tuple, update the indexes, and clean up */ - simple_heap_insert(pg_class_desc, tup); - -*************** AddNewRelationTuple(Relation pg_class_de -*** 712,720 **** - Oid new_type_oid, - Oid relowner, - char relkind, -! Datum reloptions) - { - Form_pg_class new_rel_reltup; - - /* - * first we update some of the information in our uncataloged relation's ---- 764,774 ---- - Oid new_type_oid, - Oid relowner, - char relkind, -! Datum reloptions, -! Oid *secLabels) - { - Form_pg_class new_rel_reltup; -+ Oid new_rel_secid = InvalidOid; - - /* - * first we update some of the information in our uncataloged relation's -*************** AddNewRelationTuple(Relation pg_class_de -*** 771,778 **** - - new_rel_desc->rd_att->tdtypeid = new_type_oid; - - /* Now build and insert the tuple */ -! InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions); - } - - ---- 825,836 ---- - - new_rel_desc->rd_att->tdtypeid = new_type_oid; - -+ if (secLabels) -+ new_rel_secid = secLabels[0]; -+ - /* Now build and insert the tuple */ -! InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, -! reloptions, new_rel_secid); - } - - -*************** heap_create_with_catalog(const char *rel -*** 843,849 **** - int oidinhcount, - OnCommitAction oncommit, - Datum reloptions, -! bool allow_system_table_mods) - { - Relation pg_class_desc; - Relation new_rel_desc; ---- 901,908 ---- - int oidinhcount, - OnCommitAction oncommit, - Datum reloptions, -! bool allow_system_table_mods, -! Oid *secLabels) - { - Relation pg_class_desc; - Relation new_rel_desc; -*************** heap_create_with_catalog(const char *rel -*** 1019,1031 **** - new_type_oid, - ownerid, - relkind, -! reloptions); - - /* - * now add tuples to pg_attribute for the attributes in our new relation. - */ - AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind, -! oidislocal, oidinhcount); - - /* - * Make a dependency link to force the relation to be deleted if its ---- 1078,1091 ---- - new_type_oid, - ownerid, - relkind, -! reloptions, -! secLabels); - - /* - * now add tuples to pg_attribute for the attributes in our new relation. - */ - AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind, -! oidislocal, oidinhcount, secLabels); - - /* - * Make a dependency link to force the relation to be deleted if its -*************** heap_drop_with_catalog(Oid relid) -*** 1484,1489 **** ---- 1544,1554 ---- - * delete relation tuple - */ - DeleteRelationTuple(relid); -+ -+ /* -+ * delete orphan pg_security entries -+ */ -+ securityReclaimOnDropTable(relid); - } - - -diff -Nrpc blob/src/backend/catalog/index.c sepgsql/src/backend/catalog/index.c -*** blob/src/backend/catalog/index.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/catalog/index.c Tue Dec 15 17:30:25 2009 -*************** -*** 48,53 **** ---- 48,54 ---- - #include "nodes/nodeFuncs.h" - #include "optimizer/clauses.h" - #include "optimizer/var.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/lmgr.h" - #include "storage/procarray.h" -*************** AppendAttributeTuples(Relation indexRela -*** 352,358 **** - Assert(indexTupDesc->attrs[i]->attnum == i + 1); - Assert(indexTupDesc->attrs[i]->attcacheoff == -1); - -! InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], indstate); - } - - CatalogCloseIndexes(indstate); ---- 353,360 ---- - Assert(indexTupDesc->attrs[i]->attnum == i + 1); - Assert(indexTupDesc->attrs[i]->attcacheoff == -1); - -! InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], -! indstate, InvalidOid); - } - - CatalogCloseIndexes(indstate); -*************** index_create(Oid heapRelationId, -*** 653,659 **** - */ - InsertPgClassTuple(pg_class, indexRelation, - RelationGetRelid(indexRelation), -! reloptions); - - /* done with pg_class */ - heap_close(pg_class, RowExclusiveLock); ---- 655,661 ---- - */ - InsertPgClassTuple(pg_class, indexRelation, - RelationGetRelid(indexRelation), -! reloptions, InvalidOid); - - /* done with pg_class */ - heap_close(pg_class, RowExclusiveLock); -diff -Nrpc blob/src/backend/catalog/namespace.c sepgsql/src/backend/catalog/namespace.c -*** blob/src/backend/catalog/namespace.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/catalog/namespace.c Thu Sep 17 17:04:16 2009 -*************** -*** 39,44 **** ---- 39,45 ---- - #include "miscadmin.h" - #include "nodes/makefuncs.h" - #include "parser/parse_func.h" -+ #include "security/sepgsql.h" - #include "storage/backendid.h" - #include "storage/ipc.h" - #include "utils/acl.h" -*************** LookupExplicitNamespace(const char *nspn -*** 2105,2111 **** ---- 2106,2115 ---- - if (strcmp(nspname, "pg_temp") == 0) - { - if (OidIsValid(myTempNamespace)) -+ { -+ sepgsql_schema_search(myTempNamespace, true); - return myTempNamespace; -+ } - - /* - * Since this is used only for looking up existing objects, there is -*************** LookupExplicitNamespace(const char *nspn -*** 2127,2132 **** ---- 2131,2137 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - nspname); -+ sepgsql_schema_search(namespaceId, true); - - return namespaceId; - } -*************** recomputeNamespacePath(void) -*** 2722,2728 **** - if (OidIsValid(namespaceId) && - !list_member_oid(oidlist, namespaceId) && - pg_namespace_aclcheck(namespaceId, roleid, -! ACL_USAGE) == ACLCHECK_OK) - oidlist = lappend_oid(oidlist, namespaceId); - } - } ---- 2727,2734 ---- - if (OidIsValid(namespaceId) && - !list_member_oid(oidlist, namespaceId) && - pg_namespace_aclcheck(namespaceId, roleid, -! ACL_USAGE) == ACLCHECK_OK && -! sepgsql_schema_search(namespaceId, false)) - oidlist = lappend_oid(oidlist, namespaceId); - } - } -*************** recomputeNamespacePath(void) -*** 2731,2737 **** - /* pg_temp --- substitute temp namespace, if any */ - if (OidIsValid(myTempNamespace)) - { -! if (!list_member_oid(oidlist, myTempNamespace)) - oidlist = lappend_oid(oidlist, myTempNamespace); - } - else ---- 2737,2744 ---- - /* pg_temp --- substitute temp namespace, if any */ - if (OidIsValid(myTempNamespace)) - { -! if (!list_member_oid(oidlist, myTempNamespace) && -! sepgsql_schema_search(myTempNamespace, false)) - oidlist = lappend_oid(oidlist, myTempNamespace); - } - else -*************** recomputeNamespacePath(void) -*** 2750,2756 **** - if (OidIsValid(namespaceId) && - !list_member_oid(oidlist, namespaceId) && - pg_namespace_aclcheck(namespaceId, roleid, -! ACL_USAGE) == ACLCHECK_OK) - oidlist = lappend_oid(oidlist, namespaceId); - } - } ---- 2757,2764 ---- - if (OidIsValid(namespaceId) && - !list_member_oid(oidlist, namespaceId) && - pg_namespace_aclcheck(namespaceId, roleid, -! ACL_USAGE) == ACLCHECK_OK && -! sepgsql_schema_search(namespaceId, false)) - oidlist = lappend_oid(oidlist, namespaceId); - } - } -*************** InitTempTableNamespace(void) -*** 2816,2821 **** ---- 2824,2830 ---- - char namespaceName[NAMEDATALEN]; - Oid namespaceId; - Oid toastspaceId; -+ Oid nspsecid; - - Assert(!OidIsValid(myTempNamespace)); - -*************** InitTempTableNamespace(void) -*** 2836,2841 **** ---- 2845,2853 ---- - errmsg("permission denied to create temporary tables in database \"%s\"", - get_database_name(MyDatabaseId)))); - -+ /* SELinux checks permission to create temp schema */ -+ nspsecid = sepgsql_schema_create(namespaceName, true, NULL); -+ - snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId); - - namespaceId = GetSysCacheOid(NAMESPACENAME, -*************** InitTempTableNamespace(void) -*** 2851,2857 **** - * temp tables. This works because the places that access the temp - * namespace for my own backend skip permissions checks on it. - */ -! namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID); - /* Advance command counter to make namespace visible */ - CommandCounterIncrement(); - } ---- 2863,2871 ---- - * temp tables. This works because the places that access the temp - * namespace for my own backend skip permissions checks on it. - */ -! namespaceId = NamespaceCreate(namespaceName, -! BOOTSTRAP_SUPERUSERID, -! nspsecid); - /* Advance command counter to make namespace visible */ - CommandCounterIncrement(); - } -*************** InitTempTableNamespace(void) -*** 2877,2883 **** - 0, 0, 0); - if (!OidIsValid(toastspaceId)) - { -! toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID); - /* Advance command counter to make namespace visible */ - CommandCounterIncrement(); - } ---- 2891,2899 ---- - 0, 0, 0); - if (!OidIsValid(toastspaceId)) - { -! toastspaceId = NamespaceCreate(namespaceName, -! BOOTSTRAP_SUPERUSERID, -! nspsecid); - /* Advance command counter to make namespace visible */ - CommandCounterIncrement(); - } -*************** RemoveTempRelations(Oid tempNamespaceId) -*** 3030,3035 **** ---- 3046,3058 ---- - object.objectId = tempNamespaceId; - object.objectSubId = 0; - -+ /* -+ * TODO: -+ * SELinux should not check db_xxx:{drop} permission during cleaning -+ * up all the temporary objects. It may be necessary a bool argument -+ * to control MAC permission check on deleteOneObject() called from -+ * deleteWhatDependsOn() and so on. -+ */ - deleteWhatDependsOn(&object, false); - } - -diff -Nrpc blob/src/backend/catalog/pg_aggregate.c sepgsql/src/backend/catalog/pg_aggregate.c -*** blob/src/backend/catalog/pg_aggregate.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/catalog/pg_aggregate.c Wed Jul 15 19:37:35 2009 -*************** AggregateCreate(const char *aggName, -*** 231,237 **** - NIL, /* parameterDefaults */ - PointerGetDatum(NULL), /* proconfig */ - 1, /* procost */ -! 0); /* prorows */ - - /* - * Okay to create the pg_aggregate entry. ---- 231,238 ---- - NIL, /* parameterDefaults */ - PointerGetDatum(NULL), /* proconfig */ - 1, /* procost */ -! 0, /* prorows */ -! NULL); /* proseclabel*/ - - /* - * Okay to create the pg_aggregate entry. -diff -Nrpc blob/src/backend/catalog/pg_conversion.c sepgsql/src/backend/catalog/pg_conversion.c -*** blob/src/backend/catalog/pg_conversion.c Sat Jan 3 13:01:35 2009 ---- sepgsql/src/backend/catalog/pg_conversion.c Thu Sep 17 22:10:19 2009 -*************** Oid -*** 40,46 **** - ConversionCreate(const char *conname, Oid connamespace, - Oid conowner, - int32 conforencoding, int32 contoencoding, -! Oid conproc, bool def) - { - int i; - Relation rel; ---- 40,46 ---- - ConversionCreate(const char *conname, Oid connamespace, - Oid conowner, - int32 conforencoding, int32 contoencoding, -! Oid conproc, Oid consecid, bool def) - { - int i; - Relation rel; -*************** ConversionCreate(const char *conname, Oi -*** 104,109 **** ---- 104,111 ---- - values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def); - - tup = heap_form_tuple(tupDesc, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, consecid); - - /* insert a new tuple */ - oid = simple_heap_insert(rel, tup); -diff -Nrpc blob/src/backend/catalog/pg_largeobject.c sepgsql/src/backend/catalog/pg_largeobject.c -*** blob/src/backend/catalog/pg_largeobject.c Fri Dec 18 09:40:55 2009 ---- sepgsql/src/backend/catalog/pg_largeobject.c Fri Dec 18 10:27:56 2009 -*************** -*** 25,30 **** ---- 25,31 ---- - #include "catalog/pg_largeobject_metadata.h" - #include "catalog/toasting.h" - #include "miscadmin.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -*************** -*** 40,46 **** - * will appear to exist with size 0. - */ - Oid -! LargeObjectCreate(Oid loid) - { - Relation pg_lo_meta; - HeapTuple ntup; ---- 41,47 ---- - * will appear to exist with size 0. - */ - Oid -! LargeObjectCreate(Oid loid, Oid secid) - { - Relation pg_lo_meta; - HeapTuple ntup; -*************** LargeObjectCreate(Oid loid) -*** 65,70 **** ---- 66,73 ---- - values, nulls); - if (OidIsValid(loid)) - HeapTupleSetOid(ntup, loid); -+ if (HeapTupleHasSecid(ntup)) -+ HeapTupleSetSecid(ntup, secid); - - loid_new = simple_heap_insert(pg_lo_meta, ntup); - Assert(!OidIsValid(loid) || loid == loid_new); -*************** LargeObjectAlterOwner(Oid loid, Oid newO -*** 205,210 **** ---- 208,216 ---- - - /* Must be able to become new owner */ - check_is_member_of_role(GetUserId(), newOwnerId); -+ -+ /* SELinux: db_blob:{setattr} */ -+ sepgsql_largeobject_alter(loid); - } - - memset(values, 0, sizeof(values)); -diff -Nrpc blob/src/backend/catalog/pg_namespace.c sepgsql/src/backend/catalog/pg_namespace.c -*** blob/src/backend/catalog/pg_namespace.c Sat Jan 3 13:01:35 2009 ---- sepgsql/src/backend/catalog/pg_namespace.c Tue Sep 8 23:55:48 2009 -*************** -*** 28,34 **** - * --------------- - */ - Oid -! NamespaceCreate(const char *nspName, Oid ownerId) - { - Relation nspdesc; - HeapTuple tup; ---- 28,34 ---- - * --------------- - */ - Oid -! NamespaceCreate(const char *nspName, Oid ownerId, Oid nspsecid) - { - Relation nspdesc; - HeapTuple tup; -*************** NamespaceCreate(const char *nspName, Oid -*** 66,71 **** ---- 66,73 ---- - tupDesc = nspdesc->rd_att; - - tup = heap_form_tuple(tupDesc, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, nspsecid); - - nspoid = simple_heap_insert(nspdesc, tup); - Assert(OidIsValid(nspoid)); -diff -Nrpc blob/src/backend/catalog/pg_operator.c sepgsql/src/backend/catalog/pg_operator.c -*** blob/src/backend/catalog/pg_operator.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/catalog/pg_operator.c Thu Sep 17 22:10:19 2009 -*************** -*** 28,33 **** ---- 28,34 ---- - #include "catalog/pg_type.h" - #include "miscadmin.h" - #include "parser/parse_oper.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -*************** OperatorShellMake(const char *operatorNa -*** 204,209 **** ---- 205,211 ---- - { - Relation pg_operator_desc; - Oid operatorObjectId; -+ Oid secid; - int i; - HeapTuple tup; - Datum values[Natts_pg_operator]; -*************** OperatorShellMake(const char *operatorNa -*** 220,225 **** ---- 222,231 ---- - errmsg("\"%s\" is not a valid operator name", - operatorName))); - -+ /* SELinux permission check */ -+ secid = sepgsql_operator_create(operatorName, InvalidOid, -+ operatorNamespace, -+ InvalidOid, InvalidOid, InvalidOid); - /* - * initialize our *nulls and *values arrays - */ -*************** OperatorShellMake(const char *operatorNa -*** 260,265 **** ---- 266,273 ---- - * create a new operator tuple - */ - tup = heap_form_tuple(tupDesc, values, nulls); -+ if (HeapTupleHasSecid(tup) && OidIsValid(secid)) -+ HeapTupleSetSecid(tup, secid); - - /* - * insert our "shell" operator tuple -*************** OperatorCreate(const char *operatorName, -*** 347,352 **** ---- 355,361 ---- - bool selfCommutator = false; - NameData oname; - TupleDesc tupDesc; -+ Oid secid; - int i; - - /* -*************** OperatorCreate(const char *operatorName, -*** 476,481 **** ---- 485,494 ---- - else - negatorId = InvalidOid; - -+ /* SELinux permission checks */ -+ secid = sepgsql_operator_create(operatorName, operatorObjectId, -+ operatorNamespace, -+ procedureId, restrictionId, joinId); - /* - * set up values in the operator tuple - */ -*************** OperatorCreate(const char *operatorName, -*** 523,528 **** ---- 536,543 ---- - values, - nulls, - replaces); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, secid); - - simple_heap_update(pg_operator_desc, &tup->t_self, tup); - } -*************** OperatorCreate(const char *operatorName, -*** 530,535 **** ---- 545,552 ---- - { - tupDesc = pg_operator_desc->rd_att; - tup = heap_form_tuple(tupDesc, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, secid); - - operatorObjectId = simple_heap_insert(pg_operator_desc, tup); - } -diff -Nrpc blob/src/backend/catalog/pg_proc.c sepgsql/src/backend/catalog/pg_proc.c -*** blob/src/backend/catalog/pg_proc.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/catalog/pg_proc.c Thu Mar 18 01:55:40 2010 -*************** -*** 29,34 **** ---- 29,35 ---- - #include "miscadmin.h" - #include "nodes/nodeFuncs.h" - #include "parser/parse_type.h" -+ #include "security/sepgsql.h" - #include "tcop/pquery.h" - #include "tcop/tcopprot.h" - #include "utils/acl.h" -*************** ProcedureCreate(const char *procedureNam -*** 78,84 **** - List *parameterDefaults, - Datum proconfig, - float4 procost, -! float4 prorows) - { - Oid retval; - int parameterCount; ---- 79,86 ---- - List *parameterDefaults, - Datum proconfig, - float4 procost, -! float4 prorows, -! Node *proseclabel) - { - Oid retval; - int parameterCount; -*************** ProcedureCreate(const char *procedureNam -*** 97,102 **** ---- 99,105 ---- - Datum values[Natts_pg_proc]; - bool replaces[Natts_pg_proc]; - Oid relid; -+ Oid prosecid = InvalidOid; - NameData procname; - TupleDesc tupDesc; - bool is_update; -*************** ProcedureCreate(const char *procedureNam -*** 344,349 **** ---- 347,357 ---- - ObjectIdGetDatum(procNamespace), - 0); - -+ /* Check permission to create/replace a function */ -+ prosecid = sepgsql_proc_create(procedureName, oldtup, -+ procNamespace, languageObjectId, -+ (DefElem *)proseclabel); -+ - if (HeapTupleIsValid(oldtup)) - { - /* There is one; okay to replace it? */ -*************** ProcedureCreate(const char *procedureNam -*** 481,486 **** ---- 489,496 ---- - - /* Okay, do it... */ - tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, prosecid); - simple_heap_update(rel, &tup->t_self, tup); - - ReleaseSysCache(oldtup); -*************** ProcedureCreate(const char *procedureNam -*** 490,495 **** ---- 500,507 ---- - { - /* Creating a new procedure */ - tup = heap_form_tuple(tupDesc, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, prosecid); - simple_heap_insert(rel, tup); - is_update = false; - } -diff -Nrpc blob/src/backend/catalog/pg_security.c sepgsql/src/backend/catalog/pg_security.c -*** blob/src/backend/catalog/pg_security.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/catalog/pg_security.c Sun Dec 20 23:35:32 2009 -*************** -*** 0 **** ---- 1,483 ---- -+ /* -+ * src/backend/catalog/pg_security.c -+ * routines to support security label management -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ -+ #include "access/genam.h" -+ #include "access/heapam.h" -+ #include "access/sysattr.h" -+ #include "access/xact.h" -+ #include "catalog/catalog.h" -+ #include "catalog/indexing.h" -+ #include "catalog/pg_proc.h" -+ #include "catalog/pg_security.h" -+ #include "catalog/pg_type.h" -+ #include "executor/spi.h" -+ #include "miscadmin.h" -+ #include "security/rowlevel.h" -+ #include "security/sepgsql.h" -+ #include "utils/builtins.h" -+ #include "utils/fmgroids.h" -+ #include "utils/memutils.h" -+ #include "utils/rel.h" -+ #include "utils/lsyscache.h" -+ #include "utils/syscache.h" -+ #include "utils/tqual.h" -+ -+ bool -+ securityTupleDescHasSecid(Oid relid, char relkind) -+ { -+ return sepgsqlTupleDescHasSecid(relid, relkind); -+ } -+ -+ /* -+ * securityOnCreateDatabase -+ * copies all the entries refered by source database -+ */ -+ void -+ securityOnCreateDatabase(Oid src_datid, Oid dst_datid) -+ { -+ Relation rel; -+ ScanKeyData keys[1]; -+ SysScanDesc scan; -+ HeapTuple oldtup, newtup; -+ Datum values[Natts_pg_security]; -+ bool nulls[Natts_pg_security]; -+ bool replaces[Natts_pg_security]; -+ -+ /* Scan all entries with pg_security.datid = src_datid */ -+ ScanKeyInit(&keys[0], -+ Anum_pg_security_datid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(src_datid)); -+ -+ rel = heap_open(SecurityRelationId, RowExclusiveLock); -+ -+ scan = systable_beginscan(rel, SecuritySecidIndexId, true, -+ SnapshotNow, 1, keys); -+ -+ /* pg_security.datid shall be replaced */ -+ memset(values, 0, sizeof(values)); -+ memset(nulls, false, sizeof(nulls)); -+ memset(replaces, false, sizeof(replaces)); -+ -+ values[Anum_pg_security_datid - 1] = ObjectIdGetDatum(dst_datid); -+ replaces[Anum_pg_security_datid - 1] = true; -+ -+ while (HeapTupleIsValid(oldtup = systable_getnext(scan))) -+ { -+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), -+ values, nulls, replaces); -+ simple_heap_insert(rel, newtup); -+ -+ CatalogUpdateIndexes(rel, newtup); -+ -+ heap_freetuple(newtup); -+ } -+ systable_endscan(scan); -+ -+ heap_close(rel, RowExclusiveLock); -+ } -+ -+ /* -+ * securityOnDropDatabase -+ * drops all the entries refered by dropped database -+ */ -+ void -+ securityOnDropDatabase(Oid datid) -+ { -+ Relation rel; -+ ScanKeyData keys[1]; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ -+ /* Scan all entries with pg_security.datid = datid */ -+ ScanKeyInit(&keys[0], -+ Anum_pg_security_datid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(datid)); -+ -+ rel = heap_open(SecurityRelationId, RowExclusiveLock); -+ -+ scan = systable_beginscan(rel, SecuritySecidIndexId, true, -+ SnapshotNow, 1, keys); -+ -+ while (HeapTupleIsValid(tuple = systable_getnext(scan))) -+ { -+ simple_heap_delete(rel, &tuple->t_self); -+ } -+ -+ systable_endscan(scan); -+ -+ heap_close(rel, RowExclusiveLock); -+ } -+ -+ /* -+ * InputSecurityAttr -+ */ -+ static Oid -+ InputSecurityAttr(Oid relid, const char *secattr) -+ { -+ LOCKMODE lockmode = AccessShareLock; -+ Relation rel; -+ ScanKeyData skey[3]; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ Oid datid; -+ Oid secid; -+ Datum values[Natts_pg_security]; -+ bool nulls[Natts_pg_security]; -+ -+ datid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId); -+ -+ retry: -+ /* -+ * Lookup pg_security catalog first -+ */ -+ rel = heap_open(SecurityRelationId, lockmode); -+ -+ ScanKeyInit(&skey[0], -+ Anum_pg_security_datid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(datid)); -+ ScanKeyInit(&skey[1], -+ Anum_pg_security_relid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(relid)); -+ ScanKeyInit(&skey[2], -+ Anum_pg_security_secattr, -+ BTEqualStrategyNumber, F_TEXTEQ, -+ CStringGetTextDatum(secattr)); -+ -+ scan = systable_beginscan(rel, SecuritySecattrIndexId, true, -+ SnapshotToast, 3, skey); -+ -+ tuple = systable_getnext(scan); -+ if (HeapTupleIsValid(tuple)) -+ { -+ secid = ((Form_pg_security) GETSTRUCT(tuple))->secid; -+ -+ systable_endscan(scan); -+ -+ heap_close(rel, lockmode); -+ -+ return secid; -+ } -+ -+ systable_endscan(scan); -+ -+ /* -+ * If not exist, try to insert a new entry. -+ */ -+ if (lockmode == AccessShareLock) -+ { -+ heap_close(rel, lockmode); -+ -+ lockmode = RowExclusiveLock; -+ -+ goto retry; -+ } -+ -+ memset(nulls, false, sizeof(nulls)); -+ secid = GetNewOidWithIndex(rel, SecuritySecidIndexId, -+ Anum_pg_security_secid); -+ values[Anum_pg_security_secid - 1] = ObjectIdGetDatum(secid); -+ values[Anum_pg_security_datid - 1] = ObjectIdGetDatum(datid); -+ values[Anum_pg_security_relid - 1] = ObjectIdGetDatum(relid); -+ values[Anum_pg_security_secattr - 1] = CStringGetTextDatum(secattr); -+ -+ tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); -+ -+ simple_heap_insert(rel, tuple); -+ -+ CatalogUpdateIndexes(rel, tuple); -+ -+ heap_close(rel, lockmode); -+ -+ return secid; -+ } -+ -+ static char * -+ OutputSecurityAttr(Oid relid, Oid secid) -+ { -+ Relation rel; -+ ScanKeyData skey[3]; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ Oid datid; -+ char *result = NULL; -+ -+ datid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId); -+ -+ /* -+ * Lookup pg_security catalog first -+ */ -+ rel = heap_open(SecurityRelationId, AccessShareLock); -+ -+ ScanKeyInit(&skey[0], -+ Anum_pg_security_secid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(secid)); -+ ScanKeyInit(&skey[1], -+ Anum_pg_security_datid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(datid)); -+ ScanKeyInit(&skey[2], -+ Anum_pg_security_relid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(relid)); -+ -+ scan = systable_beginscan(rel, SecuritySecidIndexId, true, -+ SnapshotToast, 3, skey); -+ -+ tuple = systable_getnext(scan); -+ if (HeapTupleIsValid(tuple)) -+ { -+ Datum datum; -+ bool isnull; -+ -+ datum = heap_getattr(tuple, -+ Anum_pg_security_secattr, -+ RelationGetDescr(rel), &isnull); -+ if (!isnull) -+ result = TextDatumGetCString(datum); -+ } -+ -+ systable_endscan(scan); -+ -+ heap_close(rel, AccessShareLock); -+ -+ return result; -+ } -+ -+ /* -+ * input/output handler -+ */ -+ Oid -+ securityRawSecLabelIn(Oid relid, char *seclabel) -+ { -+ seclabel = sepgsqlRawSecLabelIn(seclabel); -+ -+ return InputSecurityAttr(relid, seclabel); -+ } -+ -+ char * -+ securityRawSecLabelOut(Oid relid, Oid secid) -+ { -+ char *seclabel = OutputSecurityAttr(relid, secid); -+ -+ return sepgsqlRawSecLabelOut(seclabel); -+ } -+ -+ Oid -+ securityTransSecLabelIn(Oid relid, char *seclabel) -+ { -+ seclabel = sepgsqlTransSecLabelIn(seclabel); -+ -+ return securityRawSecLabelIn(relid, seclabel); -+ } -+ -+ char * -+ securityTransSecLabelOut(Oid relid, Oid secid) -+ { -+ char *seclabel = securityRawSecLabelOut(relid, secid); -+ -+ return sepgsqlTransSecLabelOut(seclabel); -+ } -+ -+ /* -+ * Output handler for system columns -+ */ -+ Datum -+ securitySysattSecLabelOut(Oid relid, HeapTuple tuple) -+ { -+ char *seclabel; -+ -+ seclabel = sepgsqlSysattSecLabelOut(relid, tuple); -+ if (!seclabel) -+ seclabel = "unlabled"; -+ -+ return CStringGetTextDatum(seclabel); -+ } -+ -+ /* -+ * securityReclaimOnDropTable -+ * drop orphan entries within pg_security on drop table -+ */ -+ void -+ securityReclaimOnDropTable(Oid relid) -+ { -+ Relation rel; -+ SysScanDesc scan; -+ ScanKeyData key[2]; -+ HeapTuple tuple; -+ Oid database_oid; -+ -+ database_oid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId); -+ ScanKeyInit(&key[0], -+ Anum_pg_security_datid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(database_oid)); -+ ScanKeyInit(&key[1], -+ Anum_pg_security_relid, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(relid)); -+ -+ rel = heap_open(SecurityRelationId, RowExclusiveLock); -+ scan = systable_beginscan(rel, SecuritySecattrIndexId, true, -+ SnapshotNow, 2, key); -+ while (HeapTupleIsValid(tuple = systable_getnext(scan))) -+ simple_heap_delete(rel, &tuple->t_self); -+ -+ systable_endscan(scan); -+ -+ heap_close(rel, RowExclusiveLock); -+ } -+ -+ /* -+ * security_quote_relation -+ * returns palloc'de identifier with explicit namespace -+ */ -+ static char * -+ security_quote_relation(Oid relid) -+ { -+ Oid nspoid = get_rel_namespace(relid); -+ char *nspname; -+ char *relname; -+ -+ nspname = get_namespace_name(nspoid); -+ relname = get_rel_name(relid); -+ -+ return quote_qualified_identifier(nspname, relname); -+ } -+ -+ /* -+ * security_reclaim_table -+ * reclaims orphan entries associated to a certain table -+ */ -+ static int -+ seclabelRelationReclaimExec(Oid relOid) -+ { -+ StringInfoData query; -+ SPIPlanPtr plan; -+ Oid types[2]; -+ Datum values[2]; -+ Oid proc_oid; -+ Oid database_oid; -+ char *relname_full; -+ char *attname_datid; -+ char *attname_relid; -+ char *attname_secid; -+ char *attname_seckind; -+ char *attname_secattr; -+ char *sec_proname; -+ char *sec_nspname; -+ Form_pg_proc proForm; -+ HeapTuple protup; -+ -+ /* -+ * LOCK the target table -+ */ -+ initStringInfo(&query); -+ relname_full = security_quote_relation(relOid); -+ appendStringInfo(&query, "LOCK %s IN SHARE MODE", relname_full); -+ if (SPI_execute(query.data, false, 0) != SPI_OK_UTILITY) -+ elog(ERROR, "SPI_execute failed on %s", query.data); -+ -+ /* -+ * DELETE orphan entries -+ */ -+ initStringInfo(&query); -+ attname_secid = get_attname(SecurityRelationId, Anum_pg_security_secid); -+ attname_datid = get_attname(SecurityRelationId, Anum_pg_security_datid); -+ attname_relid = get_attname(SecurityRelationId, Anum_pg_security_relid); -+ attname_secattr = get_attname(SecurityRelationId, Anum_pg_security_secattr); -+ -+ appendStringInfo(&query, -+ "DELETE FROM %s " -+ "WHERE %s = $1 AND %s = $2 AND %s NOT IN ", -+ security_quote_relation(SecurityRelationId), -+ quote_identifier(attname_datid), -+ quote_identifier(attname_relid), -+ quote_identifier(attname_secid)); -+ -+ protup = SearchSysCache(PROCOID, -+ ObjectIdGetDatum(F_SECLABEL_TO_SECID), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(protup)) -+ elog(ERROR, "cache lookup failed for procedure: %u", F_SECLABEL_TO_SECID); -+ -+ proForm = (Form_pg_proc) GETSTRUCT(protup); -+ sec_proname = NameStr(proForm->proname); -+ sec_nspname = get_namespace_name(proForm->pronamespace); -+ -+ appendStringInfo(&query, -+ "(SELECT %s.%s(%s) FROM ONLY %s)", -+ quote_identifier(sec_nspname), -+ quote_identifier(sec_proname), -+ quote_identifier(get_rel_name(relOid)), -+ relname_full); -+ ReleaseSysCache(protup); -+ -+ /* -+ * Setup and execute query -+ */ -+ types[0] = OIDOID; -+ types[1] = OIDOID; -+ plan = SPI_prepare(query.data, 2, types); -+ if (!plan) -+ elog(ERROR, "SPI_prepare failed on %s", query.data); -+ -+ database_oid = (IsSharedRelation(relOid) ? InvalidOid : MyDatabaseId); -+ -+ values[0] = ObjectIdGetDatum(database_oid); -+ values[1] = ObjectIdGetDatum(relOid); -+ if (SPI_execute_plan(plan, values, NULL, false, 0) != SPI_OK_DELETE) -+ elog(ERROR, "SPI_execute_plan failed on %s", query.data); -+ -+ SPI_freetuptable(SPI_tuptable); -+ -+ return SPI_processed; -+ } -+ -+ void -+ seclabelRelationReclaim(Oid relOid) -+ { -+ int save_mode; -+ -+ if (!superuser() || -+ get_rel_relkind(relOid) != RELKIND_RELATION) -+ return; -+ -+ save_mode = sepostgresql_mode; -+ sepostgresql_mode = SEPGSQL_MODE_INTERNAL; -+ PG_TRY(); -+ { -+ if (SPI_connect() != SPI_OK_CONNECT) -+ elog(ERROR, "SPI_connect failed"); -+ -+ seclabelRelationReclaimExec(relOid); -+ -+ if (SPI_finish() != SPI_OK_FINISH) -+ elog(ERROR, "SPI_finish failed"); -+ } -+ PG_CATCH(); -+ { -+ sepostgresql_mode = save_mode; -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ sepostgresql_mode = save_mode; -+ } -+ -+ Datum -+ seclabel_to_secid(PG_FUNCTION_ARGS) -+ { -+ HeapTupleHeader tuphdr = PG_GETARG_HEAPTUPLEHEADER(0); -+ -+ PG_RETURN_OID(HeapTupleHeaderGetSecid(tuphdr)); -+ } -diff -Nrpc blob/src/backend/catalog/pg_shdepend.c sepgsql/src/backend/catalog/pg_shdepend.c -*** blob/src/backend/catalog/pg_shdepend.c Fri Dec 18 09:40:55 2009 ---- sepgsql/src/backend/catalog/pg_shdepend.c Fri Dec 18 10:27:56 2009 -*************** -*** 37,42 **** ---- 37,43 ---- - #include "commands/schemacmds.h" - #include "commands/tablecmds.h" - #include "commands/typecmds.h" -+ #include "security/sepgsql.h" - #include "storage/lmgr.h" - #include "miscadmin.h" - #include "utils/acl.h" -*************** shdepReassignOwned(List *roleids, Oid ne -*** 1340,1345 **** ---- 1341,1348 ---- - break; - - case TypeRelationId: -+ /* SELinux checks */ -+ sepgsql_type_alter(sdepForm->objid, NULL, InvalidOid); - AlterTypeOwnerInternal(sdepForm->objid, newrole, true); - break; - -*************** shdepReassignOwned(List *roleids, Oid ne -*** 1352,1358 **** - break; - - case RelationRelationId: -! - /* - * Pass recursing = true so that we don't fail on indexes, - * owned sequences, etc when we happen to visit them ---- 1355,1362 ---- - break; - - case RelationRelationId: -! /* SELinux checks */ -! sepgsql_relation_alter(sdepForm->objid, NULL, InvalidOid); - /* - * Pass recursing = true so that we don't fail on indexes, - * owned sequences, etc when we happen to visit them -diff -Nrpc blob/src/backend/catalog/pg_type.c sepgsql/src/backend/catalog/pg_type.c -*** blob/src/backend/catalog/pg_type.c Sun Sep 6 19:40:49 2009 ---- sepgsql/src/backend/catalog/pg_type.c Fri Sep 18 17:39:46 2009 -*************** -*** 25,30 **** ---- 25,31 ---- - #include "commands/typecmds.h" - #include "miscadmin.h" - #include "parser/scansup.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -*************** TypeShellMake(const char *typeName, Oid -*** 56,65 **** ---- 57,73 ---- - Datum values[Natts_pg_type]; - bool nulls[Natts_pg_type]; - Oid typoid; -+ Oid typsid; - NameData name; - - Assert(PointerIsValid(typeName)); - -+ /* SELinux check permission to create a shell type */ -+ typsid = sepgsql_type_create(typeName, InvalidOid, typeNamespace, -+ F_SHELL_IN, F_SHELL_OUT, -+ InvalidOid, InvalidOid, -+ InvalidOid, InvalidOid, InvalidOid); -+ - /* - * open pg_type - */ -*************** TypeCreate(Oid newTypeOid, -*** 201,206 **** ---- 209,215 ---- - { - Relation pg_type_desc; - Oid typeObjectId; -+ Oid typeSecid = InvalidOid; - bool rebuildDeps = false; - HeapTuple tup; - bool nulls[Natts_pg_type]; -*************** TypeCreate(Oid newTypeOid, -*** 367,372 **** ---- 376,390 ---- - CStringGetDatum(typeName), - ObjectIdGetDatum(typeNamespace), - 0, 0); -+ -+ /* SELinux checks to create/replace type */ -+ if (!isImplicitArray && typeType != TYPTYPE_COMPOSITE) -+ typeSecid = sepgsql_type_create(typeName, tup, typeNamespace, -+ inputProcedure, outputProcedure, -+ receiveProcedure, sendProcedure, -+ typmodinProcedure, typmodoutProcedure, -+ analyzeProcedure); -+ - if (HeapTupleIsValid(tup)) - { - /* -*************** TypeCreate(Oid newTypeOid, -*** 412,417 **** ---- 430,437 ---- - /* Force the OID if requested by caller, else heap_insert does it */ - if (OidIsValid(newTypeOid)) - HeapTupleSetOid(tup, newTypeOid); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, typeSecid); - - typeObjectId = simple_heap_insert(pg_type_desc, tup); - } -diff -Nrpc blob/src/backend/catalog/toasting.c sepgsql/src/backend/catalog/toasting.c -*** blob/src/backend/catalog/toasting.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/catalog/toasting.c Thu Oct 8 09:29:32 2009 -*************** -*** 28,33 **** ---- 28,34 ---- - #include "catalog/toasting.h" - #include "miscadmin.h" - #include "nodes/makefuncs.h" -+ #include "security/sepgsql.h" - #include "utils/builtins.h" - #include "utils/syscache.h" - -*************** create_toast_table(Relation rel, Oid toa -*** 125,130 **** ---- 126,132 ---- - char toast_relname[NAMEDATALEN]; - char toast_idxname[NAMEDATALEN]; - IndexInfo *indexInfo; -+ Oid *secLabels; - Oid classObjectId[2]; - int16 coloptions[2]; - ObjectAddress baseobject, -*************** create_toast_table(Relation rel, Oid toa -*** 199,204 **** ---- 201,211 ---- - else - namespaceid = PG_TOAST_NAMESPACE; - -+ secLabels = sepgsql_relation_create(toast_relname, -+ RELKIND_TOASTVALUE, -+ tupdesc, namespaceid, -+ NULL, NIL, false, false); -+ - toast_relid = heap_create_with_catalog(toast_relname, - namespaceid, - rel->rd_rel->reltablespace, -*************** create_toast_table(Relation rel, Oid toa -*** 212,218 **** - 0, - ONCOMMIT_NOOP, - reloptions, -! true); - - /* make the toast relation visible, else index creation will fail */ - CommandCounterIncrement(); ---- 219,226 ---- - 0, - ONCOMMIT_NOOP, - reloptions, -! true, -! secLabels); - - /* make the toast relation visible, else index creation will fail */ - CommandCounterIncrement(); -diff -Nrpc blob/src/backend/commands/aggregatecmds.c sepgsql/src/backend/commands/aggregatecmds.c -*** blob/src/backend/commands/aggregatecmds.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/aggregatecmds.c Thu Sep 17 22:10:19 2009 -*************** -*** 32,37 **** ---- 32,38 ---- - #include "miscadmin.h" - #include "parser/parse_func.h" - #include "parser/parse_type.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -*************** RenameAggregate(List *name, List *args, -*** 311,316 **** ---- 312,320 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux permission checks */ -+ sepgsql_proc_alter(procOid, newname, InvalidOid); -+ - /* rename */ - namestrcpy(&(((Form_pg_proc) GETSTRUCT(tup))->proname), newname); - simple_heap_update(rel, &tup->t_self, tup); -diff -Nrpc blob/src/backend/commands/alter.c sepgsql/src/backend/commands/alter.c -*** blob/src/backend/commands/alter.c Fri Dec 18 09:40:55 2009 ---- sepgsql/src/backend/commands/alter.c Fri Dec 18 10:27:56 2009 -*************** ExecAlterOwnerStmt(AlterOwnerStmt *stmt) -*** 289,291 **** ---- 289,320 ---- - (int) stmt->objectType); - } - } -+ -+ void -+ ExecAlterSecLabelStmt(AlterSecLabelStmt *stmt) -+ { -+ DefElem *seclabel = (DefElem *)stmt->secLabel; -+ -+ switch (stmt->objectType) -+ { -+ case OBJECT_DATABASE: -+ AlterDatabaseSecLabel(strVal(linitial(stmt->object)), seclabel); -+ break; -+ case OBJECT_SCHEMA: -+ AlterSchemaSecLabel(strVal(linitial(stmt->object)), seclabel); -+ break; -+ case OBJECT_TABLE: -+ case OBJECT_SEQUENCE: -+ case OBJECT_COLUMN: -+ CheckRelationOwnership(stmt->relation, true); -+ AlterRelationSecLabel(stmt->relation, stmt->subname, -+ stmt->objectType, seclabel); -+ break; -+ case OBJECT_FUNCTION: -+ AlterFunctionSecLabel(stmt->object, stmt->objarg, seclabel); -+ break; -+ default: -+ elog(ERROR, "unrecognized AlterSecLabelStmt type: %d", -+ (int) stmt->objectType); -+ } -+ } -diff -Nrpc blob/src/backend/commands/cluster.c sepgsql/src/backend/commands/cluster.c -*** blob/src/backend/commands/cluster.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/commands/cluster.c Thu Mar 18 01:55:40 2010 -*************** -*** 36,41 **** ---- 36,42 ---- - #include "commands/trigger.h" - #include "commands/vacuum.h" - #include "miscadmin.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/procarray.h" - #include "utils/acl.h" -*************** rebuild_relation(Relation OldHeap, Oid i -*** 617,624 **** - /* - * The new relation is local to our transaction and we know nothing - * depends on it, so DROP_RESTRICT should be OK. - */ -! performDeletion(&object, DROP_RESTRICT); - - /* performDeletion does CommandCounterIncrement at end */ - ---- 618,626 ---- - /* - * The new relation is local to our transaction and we know nothing - * depends on it, so DROP_RESTRICT should be OK. -+ * SELinux does not check any permissions here. - */ -! performDeletionNoPerms(&object, DROP_RESTRICT); - - /* performDeletion does CommandCounterIncrement at end */ - -*************** make_new_heap(Oid OIDOldHeap, const char -*** 717,723 **** - 0, - ONCOMMIT_NOOP, - reloptions, -! allowSystemTableMods); - - ReleaseSysCache(tuple); - ---- 719,726 ---- - 0, - ONCOMMIT_NOOP, - reloptions, -! allowSystemTableMods, -! sepgsql_relation_copy(OldHeap)); - - ReleaseSysCache(tuple); - -*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl -*** 929,934 **** ---- 932,941 ---- - if (NewHeap->rd_rel->relhasoids) - HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple)); - -+ /* Preserve SID, if any */ -+ if (HeapTupleHasSecid(copiedTuple)) -+ HeapTupleSetSecid(copiedTuple, HeapTupleGetSecid(tuple)); -+ - /* The heap rewrite module does the rest */ - rewrite_heap_tuple(rwstate, tuple, copiedTuple); - -diff -Nrpc blob/src/backend/commands/conversioncmds.c sepgsql/src/backend/commands/conversioncmds.c -*** blob/src/backend/commands/conversioncmds.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/conversioncmds.c Thu Sep 17 22:10:19 2009 -*************** -*** 24,29 **** ---- 24,30 ---- - #include "mb/pg_wchar.h" - #include "miscadmin.h" - #include "parser/parse_func.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -*************** CreateConversionCommand(CreateConversion -*** 45,50 **** ---- 46,52 ---- - int from_encoding; - int to_encoding; - Oid funcoid; -+ Oid secid; - const char *from_encoding_name = stmt->for_encoding_name; - const char *to_encoding_name = stmt->to_encoding_name; - List *func_name = stmt->func_name; -*************** CreateConversionCommand(CreateConversion -*** 96,101 **** ---- 98,106 ---- - aclcheck_error(aclresult, ACL_KIND_PROC, - NameListToString(func_name)); - -+ /* SELinux checks */ -+ secid = sepgsql_conversion_create(conversion_name, namespaceId, funcoid); -+ - /* - * Check that the conversion function is suitable for the requested source - * and target encodings. We do that by calling the function with an empty -*************** CreateConversionCommand(CreateConversion -*** 114,120 **** - * name) - */ - ConversionCreate(conversion_name, namespaceId, GetUserId(), -! from_encoding, to_encoding, funcoid, stmt->def); - } - - /* ---- 119,125 ---- - * name) - */ - ConversionCreate(conversion_name, namespaceId, GetUserId(), -! from_encoding, to_encoding, funcoid, secid, stmt->def); - } - - /* -*************** RenameConversion(List *name, const char -*** 240,245 **** ---- 245,253 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux checks */ -+ sepgsql_conversion_alter(conversionOid, newname); -+ - /* rename */ - namestrcpy(&(((Form_pg_conversion) GETSTRUCT(tup))->conname), newname); - simple_heap_update(rel, &tup->t_self, tup); -*************** AlterConversionOwner_internal(Relation r -*** 336,341 **** ---- 344,351 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(convForm->connamespace)); - } -+ /* SELinux checks */ -+ sepgsql_conversion_alter(HeapTupleGetOid(tup), NULL); - - /* - * Modify the owner --- okay to scribble on tup because it's a copy -diff -Nrpc blob/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c -*** blob/src/backend/commands/copy.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/copy.c Mon Sep 28 09:29:32 2009 -*************** -*** 21,28 **** ---- 21,31 ---- - #include - - #include "access/heapam.h" -+ #include "access/sysattr.h" - #include "access/xact.h" -+ #include "catalog/heap.h" - #include "catalog/namespace.h" -+ #include "catalog/pg_security.h" - #include "catalog/pg_type.h" - #include "commands/copy.h" - #include "commands/trigger.h" -*************** -*** 34,39 **** ---- 37,44 ---- - #include "optimizer/planner.h" - #include "parser/parse_relation.h" - #include "rewrite/rewriteHandler.h" -+ #include "security/rowlevel.h" -+ #include "security/sepgsql.h" - #include "storage/fd.h" - #include "tcop/tcopprot.h" - #include "utils/acl.h" -*************** typedef struct CopyStateData -*** 160,165 **** ---- 165,174 ---- - char *raw_buf; - int raw_buf_index; /* next byte to process */ - int raw_buf_len; /* total # of bytes stored */ -+ -+ /* dump/restore support for security_label */ -+ FmgrInfo seclabel_out_function; -+ bool seclabel_force_quot; - } CopyStateData; - - typedef CopyStateData *CopyState; -*************** static const char BinarySignature[11] = -*** 243,250 **** - /* non-export function prototypes */ - static void DoCopyTo(CopyState cstate); - static void CopyTo(CopyState cstate); -! static void CopyOneRowTo(CopyState cstate, Oid tupleOid, -! Datum *values, bool *nulls); - static void CopyFrom(CopyState cstate); - static bool CopyReadLine(CopyState cstate); - static bool CopyReadLineText(CopyState cstate); ---- 252,259 ---- - /* non-export function prototypes */ - static void DoCopyTo(CopyState cstate); - static void CopyTo(CopyState cstate); -! static void CopyOneRowTo(CopyState cstate, HeapTuple tuple, -! Datum *values, bool *nulls); - static void CopyFrom(CopyState cstate); - static bool CopyReadLine(CopyState cstate); - static bool CopyReadLineText(CopyState cstate); -*************** DoCopy(const CopyStmt *stmt, const char -*** 958,969 **** - errmsg("CSV quote character must not appear in the NULL specification"))); - - /* Disallow file COPY except to superusers. */ -! if (!pipe && !superuser()) -! ereport(ERROR, -! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -! errmsg("must be superuser to COPY to or from a file"), -! errhint("Anyone can COPY to stdout or from stdin. " -! "psql's \\copy command also works for anyone."))); - - if (stmt->relation) - { ---- 967,985 ---- - errmsg("CSV quote character must not appear in the NULL specification"))); - - /* Disallow file COPY except to superusers. */ -! if (!pipe) -! { -! if (!superuser()) -! ereport(ERROR, -! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -! errmsg("must be superuser to COPY to or from a file"), -! errhint("Anyone can COPY to stdout or from stdin. " -! "psql's \\copy command also works for anyone."))); -! if (is_from) -! sepgsql_file_read(stmt->filename); -! else -! sepgsql_file_write(stmt->filename); -! } - - if (stmt->relation) - { -*************** DoCopy(const CopyStmt *stmt, const char -*** 1090,1095 **** ---- 1106,1114 ---- - - num_phys_attrs = tupDesc->natts; - -+ /* SELinux: check table/column level permission */ -+ sepgsqlCheckCopyTable(cstate->rel, cstate->attnumlist, is_from); -+ - /* Convert FORCE QUOTE name list to per-column flags, check validity */ - cstate->force_quote_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool)); - if (force_quote) -*************** DoCopy(const CopyStmt *stmt, const char -*** 1104,1114 **** - int attnum = lfirst_int(cur); - - if (!list_member_int(cstate->attnumlist, attnum)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), - errmsg("FORCE QUOTE column \"%s\" not referenced by COPY", -! NameStr(tupDesc->attrs[attnum - 1]->attname)))); -! cstate->force_quote_flags[attnum - 1] = true; - } - } - ---- 1123,1153 ---- - int attnum = lfirst_int(cur); - - if (!list_member_int(cstate->attnumlist, attnum)) -+ { -+ Form_pg_attribute attForm; -+ -+ if (SystemAttributeIsWritable(attnum)) -+ attForm = SystemAttributeDefinition(attnum, true); -+ else -+ attForm = tupDesc->attrs[attnum - 1]; -+ -+ Assert(attForm != NULL); -+ - ereport(ERROR, - (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), - errmsg("FORCE QUOTE column \"%s\" not referenced by COPY", -! NameStr(attForm->attname)))); -! } -! -! switch (attnum) -! { -! case SecurityAttributeNumber: -! cstate->seclabel_force_quot = true; -! break; -! default: -! cstate->force_quote_flags[attnum - 1] = true; -! break; -! } - } - } - -*************** DoCopy(const CopyStmt *stmt, const char -*** 1126,1135 **** - int attnum = lfirst_int(cur); - - if (!list_member_int(cstate->attnumlist, attnum)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), - errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY", -! NameStr(tupDesc->attrs[attnum - 1]->attname)))); - cstate->force_notnull_flags[attnum - 1] = true; - } - } ---- 1165,1187 ---- - int attnum = lfirst_int(cur); - - if (!list_member_int(cstate->attnumlist, attnum)) -+ { -+ Form_pg_attribute attForm; -+ -+ if (SystemAttributeIsWritable(attnum)) -+ attForm = SystemAttributeDefinition(attnum, true); -+ else -+ attForm = tupDesc->attrs[attnum - 1]; -+ -+ Assert(attForm != NULL); -+ - ereport(ERROR, - (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), - errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY", -! NameStr(attForm->attname)))); -! } -! if (SystemAttributeIsWritable(attnum)) -! continue; /* ignore, if specified */ - cstate->force_notnull_flags[attnum - 1] = true; - } - } -*************** CopyTo(CopyState cstate) -*** 1321,1336 **** - int attnum = lfirst_int(cur); - Oid out_func_oid; - bool isvarlena; - - if (cstate->binary) -! getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid, - &out_func_oid, - &isvarlena); - else -! getTypeOutputInfo(attr[attnum - 1]->atttypid, - &out_func_oid, - &isvarlena); -! fmgr_info(out_func_oid, &cstate->out_functions[attnum - 1]); - } - - /* ---- 1373,1403 ---- - int attnum = lfirst_int(cur); - Oid out_func_oid; - bool isvarlena; -+ FmgrInfo *out_fmgr; -+ Form_pg_attribute attForm; -+ -+ switch (attnum) -+ { -+ case SecurityAttributeNumber: -+ attForm = SystemAttributeDefinition(attnum, true); -+ out_fmgr = &cstate->seclabel_out_function; -+ break; -+ -+ default: -+ attForm = attr[attnum - 1]; -+ out_fmgr = &cstate->out_functions[attnum - 1]; -+ break; -+ } - - if (cstate->binary) -! getTypeBinaryOutputInfo(attForm->atttypid, - &out_func_oid, - &isvarlena); - else -! getTypeOutputInfo(attForm->atttypid, - &out_func_oid, - &isvarlena); -! fmgr_info(out_func_oid, out_fmgr); - } - - /* -*************** CopyTo(CopyState cstate) -*** 1385,1391 **** - CopySendChar(cstate, cstate->delim[0]); - hdr_delim = true; - -! colname = NameStr(attr[attnum - 1]->attname); - - CopyAttributeOutCSV(cstate, colname, false, - list_length(cstate->attnumlist) == 1); ---- 1452,1465 ---- - CopySendChar(cstate, cstate->delim[0]); - hdr_delim = true; - -! if (SystemAttributeIsWritable(attnum)) -! { -! Form_pg_attribute attForm -! = SystemAttributeDefinition(attnum, true); -! colname = NameStr(attForm->attname); -! } -! else -! colname = NameStr(attr[attnum - 1]->attname); - - CopyAttributeOutCSV(cstate, colname, false, - list_length(cstate->attnumlist) == 1); -*************** CopyTo(CopyState cstate) -*** 1411,1421 **** - { - CHECK_FOR_INTERRUPTS(); - - /* Deconstruct the tuple ... faster than repeated heap_getattr */ - heap_deform_tuple(tuple, tupDesc, values, nulls); - - /* Format and send the data */ -! CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls); - } - - heap_endscan(scandesc); ---- 1485,1499 ---- - { - CHECK_FOR_INTERRUPTS(); - -+ /* check Row-level permission on the tuple */ -+ if (!rowlvCopyToTuple(cstate->rel, tuple)) -+ continue; -+ - /* Deconstruct the tuple ... faster than repeated heap_getattr */ - heap_deform_tuple(tuple, tupDesc, values, nulls); - - /* Format and send the data */ -! CopyOneRowTo(cstate, tuple, values, nulls); - } - - heap_endscan(scandesc); -*************** CopyTo(CopyState cstate) -*** 1441,1447 **** - * Emit one row during CopyTo(). - */ - static void -! CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) - { - bool need_delim = false; - FmgrInfo *out_functions = cstate->out_functions; ---- 1519,1526 ---- - * Emit one row during CopyTo(). - */ - static void -! CopyOneRowTo(CopyState cstate, HeapTuple tuple, -! Datum *values, bool *nulls) - { - bool need_delim = false; - FmgrInfo *out_functions = cstate->out_functions; -*************** CopyOneRowTo(CopyState cstate, Oid tuple -*** 1461,1467 **** - { - /* Hack --- assume Oid is same size as int32 */ - CopySendInt32(cstate, sizeof(int32)); -! CopySendInt32(cstate, tupleOid); - } - } - else ---- 1540,1546 ---- - { - /* Hack --- assume Oid is same size as int32 */ - CopySendInt32(cstate, sizeof(int32)); -! CopySendInt32(cstate, HeapTupleGetOid(tuple)); - } - } - else -*************** CopyOneRowTo(CopyState cstate, Oid tuple -*** 1471,1477 **** - if (cstate->oids) - { - string = DatumGetCString(DirectFunctionCall1(oidout, -! ObjectIdGetDatum(tupleOid))); - CopySendString(cstate, string); - need_delim = true; - } ---- 1550,1556 ---- - if (cstate->oids) - { - string = DatumGetCString(DirectFunctionCall1(oidout, -! ObjectIdGetDatum(HeapTupleGetOid(tuple)))); - CopySendString(cstate, string); - need_delim = true; - } -*************** CopyOneRowTo(CopyState cstate, Oid tuple -*** 1480,1487 **** - foreach(cur, cstate->attnumlist) - { - int attnum = lfirst_int(cur); -! Datum value = values[attnum - 1]; -! bool isnull = nulls[attnum - 1]; - - if (!cstate->binary) - { ---- 1559,1569 ---- - foreach(cur, cstate->attnumlist) - { - int attnum = lfirst_int(cur); -! Oid relid; -! Datum value; -! bool isnull; -! bool force_quot; -! FmgrInfo *out_fmgr; - - if (!cstate->binary) - { -*************** CopyOneRowTo(CopyState cstate, Oid tuple -*** 1490,1495 **** ---- 1572,1595 ---- - need_delim = true; - } - -+ switch (attnum) -+ { -+ case SecurityAttributeNumber: -+ relid = RelationGetRelid(cstate->rel); -+ value = securitySysattSecLabelOut(relid, tuple); -+ isnull = false; -+ force_quot = cstate->seclabel_force_quot; -+ out_fmgr = &cstate->seclabel_out_function; -+ break; -+ -+ default: -+ value = values[attnum - 1]; -+ isnull = nulls[attnum - 1]; -+ force_quot = cstate->force_quote_flags[attnum - 1]; -+ out_fmgr = &out_functions[attnum - 1]; -+ break; -+ } -+ - if (isnull) - { - if (!cstate->binary) -*************** CopyOneRowTo(CopyState cstate, Oid tuple -*** 1501,1511 **** - { - if (!cstate->binary) - { -! string = OutputFunctionCall(&out_functions[attnum - 1], -! value); - if (cstate->csv_mode) -! CopyAttributeOutCSV(cstate, string, -! cstate->force_quote_flags[attnum - 1], - list_length(cstate->attnumlist) == 1); - else - CopyAttributeOutText(cstate, string); ---- 1601,1609 ---- - { - if (!cstate->binary) - { -! string = OutputFunctionCall(out_fmgr, value); - if (cstate->csv_mode) -! CopyAttributeOutCSV(cstate, string, force_quot, - list_length(cstate->attnumlist) == 1); - else - CopyAttributeOutText(cstate, string); -*************** CopyOneRowTo(CopyState cstate, Oid tuple -*** 1514,1521 **** - { - bytea *outputbytes; - -! outputbytes = SendFunctionCall(&out_functions[attnum - 1], -! value); - CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ); - CopySendData(cstate, VARDATA(outputbytes), - VARSIZE(outputbytes) - VARHDRSZ); ---- 1612,1618 ---- - { - bytea *outputbytes; - -! outputbytes = SendFunctionCall(out_fmgr, value); - CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ); - CopySendData(cstate, VARDATA(outputbytes), - VARSIZE(outputbytes) - VARHDRSZ); -*************** CopyFrom(CopyState cstate) -*** 1649,1656 **** ---- 1746,1755 ---- - num_defaults; - FmgrInfo *in_functions; - FmgrInfo oid_in_function; -+ FmgrInfo seclabel_in_function; - Oid *typioparams; - Oid oid_typioparam; -+ Oid seclabel_typioparam; - int attnum; - int i; - Oid in_func_oid; -*************** CopyFrom(CopyState cstate) -*** 1888,1893 **** ---- 1987,2004 ---- - fmgr_info(in_func_oid, &oid_in_function); - } - -+ if (list_member_int(cstate->attnumlist, -+ SecurityAttributeNumber)) -+ { -+ if (!cstate->binary) -+ getTypeInputInfo(TEXTOID, -+ &in_func_oid, &seclabel_typioparam); -+ else -+ getTypeBinaryInputInfo(TEXTOID, -+ &in_func_oid, &seclabel_typioparam); -+ fmgr_info(in_func_oid, &seclabel_in_function); -+ } -+ - values = (Datum *) palloc(num_phys_attrs * sizeof(Datum)); - nulls = (bool *) palloc(num_phys_attrs * sizeof(bool)); - -*************** CopyFrom(CopyState cstate) -*** 1922,1927 **** ---- 2033,2039 ---- - { - bool skip_tuple; - Oid loaded_oid = InvalidOid; -+ Oid loaded_seclabel = InvalidOid; - - CHECK_FOR_INTERRUPTS(); - -*************** CopyFrom(CopyState cstate) -*** 1993,2006 **** - /* Loop to read the user attributes on the line. */ - foreach(cur, cstate->attnumlist) - { - int attnum = lfirst_int(cur); - int m = attnum - 1; - - if (fieldno >= fldct) - ereport(ERROR, - (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), - errmsg("missing data for column \"%s\"", -! NameStr(attr[m]->attname)))); - string = field_strings[fieldno++]; - - if (cstate->csv_mode && string == NULL && ---- 2105,2125 ---- - /* Loop to read the user attributes on the line. */ - foreach(cur, cstate->attnumlist) - { -+ Form_pg_attribute attForm; -+ Datum dat; - int attnum = lfirst_int(cur); - int m = attnum - 1; - -+ if (SystemAttributeIsWritable(attnum)) -+ attForm = SystemAttributeDefinition(attnum, true); -+ else -+ attForm = attr[m]; -+ - if (fieldno >= fldct) - ereport(ERROR, - (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), - errmsg("missing data for column \"%s\"", -! NameStr(attForm->attname)))); - string = field_strings[fieldno++]; - - if (cstate->csv_mode && string == NULL && -*************** CopyFrom(CopyState cstate) -*** 2010,2023 **** - string = cstate->null_print; - } - -! cstate->cur_attname = NameStr(attr[m]->attname); - cstate->cur_attval = string; -! values[m] = InputFunctionCall(&in_functions[m], -! string, -! typioparams[m], -! attr[m]->atttypmod); -! if (string != NULL) -! nulls[m] = false; - cstate->cur_attname = NULL; - cstate->cur_attval = NULL; - } ---- 2129,2168 ---- - string = cstate->null_print; - } - -! cstate->cur_attname = NameStr(attForm->attname); - cstate->cur_attval = string; -! -! switch (attnum) -! { -! case SecurityAttributeNumber: -! if (!string) -! break; -! -! dat = InputFunctionCall(&seclabel_in_function, -! string, -! seclabel_typioparam, -! attForm->atttypmod); -! loaded_seclabel -! = securityTransSecLabelIn(RelationGetRelid(cstate->rel), -! TextDatumGetCString(dat)); -! break; -! -! default: -! if (cstate->csv_mode && string == NULL && -! cstate->force_notnull_flags[m]) -! { -! /* Go ahead and read the NULL string */ -! string = cstate->null_print; -! } -! -! values[m] = InputFunctionCall(&in_functions[m], -! string, -! typioparams[m], -! attForm->atttypmod); -! if (string != NULL) -! nulls[m] = false; -! break; -! } - cstate->cur_attname = NULL; - cstate->cur_attval = NULL; - } -*************** CopyFrom(CopyState cstate) -*** 2063,2079 **** - i = 0; - foreach(cur, cstate->attnumlist) - { - int attnum = lfirst_int(cur); - int m = attnum - 1; - -! cstate->cur_attname = NameStr(attr[m]->attname); - i++; -! values[m] = CopyReadBinaryAttribute(cstate, -! i, -! &in_functions[m], -! typioparams[m], -! attr[m]->atttypmod, -! &nulls[m]); - cstate->cur_attname = NULL; - } - } ---- 2208,2248 ---- - i = 0; - foreach(cur, cstate->attnumlist) - { -+ Form_pg_attribute attForm; -+ Datum dat; - int attnum = lfirst_int(cur); - int m = attnum - 1; - -! if (SystemAttributeIsWritable(attnum)) -! attForm = SystemAttributeDefinition(attnum, false); -! else -! attForm = attr[m]; -! -! cstate->cur_attname = NameStr(attForm->attname); - i++; -! -! switch (attnum) -! { -! case SecurityAttributeNumber: -! dat = CopyReadBinaryAttribute(cstate, i, -! &seclabel_in_function, -! seclabel_typioparam, -! attForm->atttypmod, -! &isnull); -! if (!isnull) -! loaded_seclabel -! = securityTransSecLabelIn(RelationGetRelid(cstate->rel), -! TextDatumGetCString(dat)); -! break; -! -! default: -! values[m] = CopyReadBinaryAttribute(cstate, i, -! &in_functions[m], -! typioparams[m], -! attr[m]->atttypmod, -! &nulls[m]); -! break; -! } - cstate->cur_attname = NULL; - } - } -*************** CopyFrom(CopyState cstate) -*** 2094,2099 **** ---- 2263,2270 ---- - - if (cstate->oids && file_has_oids) - HeapTupleSetOid(tuple, loaded_oid); -+ if (HeapTupleHasSecid(tuple)) -+ HeapTupleSetSecid(tuple, loaded_seclabel); - - /* Triggers and stuff need to be invoked in query context. */ - MemoryContextSwitchTo(oldcontext); -*************** CopyFrom(CopyState cstate) -*** 2118,2123 **** ---- 2289,2297 ---- - } - - if (!skip_tuple) -+ sepgsqlHeapTupleInsert(cstate->rel, tuple, false); -+ -+ if (!skip_tuple) - { - /* Place tuple in tuple slot */ - ExecStoreTuple(tuple, slot, InvalidBuffer, false); -*************** CopyGetAttnums(TupleDesc tupDesc, Relati -*** 3398,3403 **** ---- 3572,3584 ---- - } - if (attnum == InvalidAttrNumber) - { -+ Form_pg_attribute attForm -+ = SystemAttributeByName(name, tupDesc->tdhasoid); -+ if (attForm && SystemAttributeIsWritable(attForm->attnum)) -+ attnum = attForm->attnum; -+ } -+ if (attnum == InvalidAttrNumber) -+ { - if (rel != NULL) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), -*************** copy_dest_receive(TupleTableSlot *slot, -*** 3445,3451 **** - slot_getallattrs(slot); - - /* And send the data */ -! CopyOneRowTo(cstate, InvalidOid, slot->tts_values, slot->tts_isnull); - } - - /* ---- 3626,3633 ---- - slot_getallattrs(slot); - - /* And send the data */ -! CopyOneRowTo(cstate, slot->tts_tuple, -! slot->tts_values, slot->tts_isnull); - } - - /* -diff -Nrpc blob/src/backend/commands/dbcommands.c sepgsql/src/backend/commands/dbcommands.c -*** blob/src/backend/commands/dbcommands.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/dbcommands.c Sun Dec 20 16:30:19 2009 -*************** -*** 33,38 **** ---- 33,39 ---- - #include "catalog/indexing.h" - #include "catalog/pg_authid.h" - #include "catalog/pg_database.h" -+ #include "catalog/pg_security.h" - #include "catalog/pg_tablespace.h" - #include "commands/comment.h" - #include "commands/dbcommands.h" -*************** -*** 41,46 **** ---- 42,48 ---- - #include "miscadmin.h" - #include "pgstat.h" - #include "postmaster/bgwriter.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/fd.h" - #include "storage/lmgr.h" -*************** createdb(const CreatedbStmt *stmt) -*** 111,116 **** ---- 113,119 ---- - bool new_record_nulls[Natts_pg_database]; - Oid dboid; - Oid datdba; -+ Oid datsecid; - ListCell *option; - DefElem *dtablespacename = NULL; - DefElem *downer = NULL; -*************** createdb(const CreatedbStmt *stmt) -*** 119,124 **** ---- 122,128 ---- - DefElem *dcollate = NULL; - DefElem *dctype = NULL; - DefElem *dconnlimit = NULL; -+ DefElem *dseclabel = NULL; - char *dbname = stmt->dbname; - char *dbowner = NULL; - const char *dbtemplate = NULL; -*************** createdb(const CreatedbStmt *stmt) -*** 200,205 **** ---- 204,217 ---- - errmsg("LOCATION is not supported anymore"), - errhint("Consider using tablespaces instead."))); - } -+ else if (strcmp(defel->defname, "security_context") == 0) -+ { -+ if (dseclabel) -+ ereport(ERROR, -+ (errcode(ERRCODE_SYNTAX_ERROR), -+ errmsg("conflicting or redundant options"))); -+ dseclabel = defel; -+ } - else - elog(ERROR, "option \"%s\" not recognized", - defel->defname); -*************** createdb(const CreatedbStmt *stmt) -*** 294,299 **** ---- 306,314 ---- - errmsg("template database \"%s\" does not exist", - dbtemplate))); - -+ /* SELinux checks db_database:{create} */ -+ datsecid = sepgsql_database_create(dbname, src_dboid, dseclabel); -+ - /* - * Permission check: to copy a DB that's not marked datistemplate, you - * must be superuser or the owner thereof. -*************** createdb(const CreatedbStmt *stmt) -*** 557,562 **** ---- 572,579 ---- - new_record, new_record_nulls); - - HeapTupleSetOid(tuple, dboid); -+ if (HeapTupleHasSecid(tuple)) -+ HeapTupleSetSecid(tuple, datsecid); - - simple_heap_insert(pg_database_rel, tuple); - -*************** createdb(const CreatedbStmt *stmt) -*** 573,578 **** ---- 590,598 ---- - /* Create pg_shdepend entries for objects within database */ - copyTemplateDependencies(src_dboid, dboid); - -+ /* Create pg_security entries for objects within database */ -+ securityOnCreateDatabase(src_dboid, dboid); -+ - /* - * Force a checkpoint before starting the copy. This will force dirty - * buffers out to disk, to ensure source database is up-to-date on disk -*************** dropdb(const char *dbname, bool missing_ -*** 776,781 **** ---- 796,804 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - dbname); - -+ /* SELinux checks db_database:{drop} permission */ -+ sepgsql_database_drop(db_id); -+ - /* - * Disallow dropping a DB that is marked istemplate. This is just to - * prevent people from accidentally dropping template0 or template1; they -*************** dropdb(const char *dbname, bool missing_ -*** 829,834 **** ---- 852,862 ---- - dropDatabaseDependencies(db_id); - - /* -+ * Remove pg_security entries for the database. -+ */ -+ securityOnDropDatabase(db_id); -+ -+ /* - * Drop pages for this database that are in the shared buffer cache. This - * is important to ensure that no remaining backend tries to write out a - * dirty buffer to the dead database later... -*************** RenameDatabase(const char *oldname, cons -*** 913,918 **** ---- 941,949 ---- - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied to rename database"))); - -+ /* SELinux: check db_database:{setattr} */ -+ sepgsql_database_alter(db_id); -+ - /* - * Make sure the new name doesn't exist. See notes for same error in - * CREATE DATABASE. -*************** movedb(const char *dbname, const char *t -*** 1025,1030 **** ---- 1056,1064 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - dbname); - -+ /* SELinux checks db_database:{setattr} */ -+ sepgsql_database_alter(db_id); -+ - /* - * Obviously can't move the tables of my own database - */ -*************** AlterDatabase(AlterDatabaseStmt *stmt, b -*** 1377,1382 **** ---- 1411,1419 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - stmt->dbname); - -+ /* SELinux checks db_database:{setattr} */ -+ sepgsql_database_alter(HeapTupleGetOid(tuple)); -+ - /* - * Build an updated tuple, perusing the information just obtained - */ -*************** AlterDatabaseSet(AlterDatabaseSetStmt *s -*** 1449,1454 **** ---- 1486,1494 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - stmt->dbname); - -+ /* SELinux checks db_database:{setattr} */ -+ sepgsql_database_alter(HeapTupleGetOid(tuple)); -+ - memset(repl_repl, false, sizeof(repl_repl)); - repl_repl[Anum_pg_database_datconfig - 1] = true; - -*************** AlterDatabaseOwner(const char *dbname, O -*** 1571,1576 **** ---- 1611,1619 ---- - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied to change owner of database"))); - -+ /* SELinux checks db_database:{setattr} */ -+ sepgsql_database_alter(HeapTupleGetOid(tuple)); -+ - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - -*************** AlterDatabaseOwner(const char *dbname, O -*** 1615,1620 **** ---- 1658,1715 ---- - */ - } - -+ /* -+ * ALTER DATABASE name SECURITY_LABEL [=] newlabel -+ */ -+ void -+ AlterDatabaseSecLabel(const char *dbname, DefElem *seclabel) -+ { -+ Relation rel; -+ HeapTuple oldtup; -+ HeapTuple newtup; -+ ScanKeyData scankey; -+ SysScanDesc scan; -+ Oid secid; -+ bool replaces[Natts_pg_database]; -+ -+ /* Fetch the old tuple */ -+ rel = heap_open(DatabaseRelationId, RowExclusiveLock); -+ ScanKeyInit(&scankey, -+ Anum_pg_database_datname, -+ BTEqualStrategyNumber, F_NAMEEQ, -+ NameGetDatum(dbname)); -+ scan = systable_beginscan(rel, DatabaseNameIndexId, true, -+ SnapshotNow, 1, &scankey); -+ oldtup = systable_getnext(scan); -+ if (!HeapTupleIsValid(oldtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_DATABASE), -+ errmsg("database \"%s\" does not exist", dbname))); -+ -+ memset(replaces, false, sizeof(replaces)); -+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), -+ NULL, NULL, replaces); -+ if (!HeapTupleHasSecid(newtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("Unable to set security label on \"%s\"", dbname))); -+ systable_endscan(scan); -+ -+ /* check DAC permission */ -+ if (!pg_database_ownercheck(HeapTupleGetOid(newtup), GetUserId())) -+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname); -+ -+ /* SELinux checks db_database:{setattr relabelfrom relabelto} */ -+ secid = sepgsql_database_relabel(HeapTupleGetOid(newtup), seclabel); -+ HeapTupleSetSecid(newtup, secid); -+ -+ simple_heap_update(rel, &newtup->t_self, newtup); -+ CatalogUpdateIndexes(rel, newtup); -+ -+ heap_freetuple(newtup); -+ -+ heap_close(rel, RowExclusiveLock); -+ } - - /* - * Helper functions -diff -Nrpc blob/src/backend/commands/foreigncmds.c sepgsql/src/backend/commands/foreigncmds.c -*** blob/src/backend/commands/foreigncmds.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/commands/foreigncmds.c Thu Mar 18 01:55:40 2010 -*************** -*** 27,32 **** ---- 27,33 ---- - #include "foreign/foreign.h" - #include "miscadmin.h" - #include "parser/parse_func.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -*************** AlterForeignDataWrapperOwner(const char -*** 234,239 **** ---- 235,243 ---- - - if (form->fdwowner != newOwnerId) - { -+ /* SELinux permission check */ -+ sepgsql_fdw_alter(fdwId, InvalidOid); -+ - form->fdwowner = newOwnerId; - - simple_heap_update(rel, &tup->t_self, tup); -*************** AlterForeignServerOwner(const char *name -*** 298,303 **** ---- 302,309 ---- - aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname); - } - } -+ /* SELinux permission checks */ -+ sepgsql_foreign_server_alter(srvId); - - form->srvowner = newOwnerId; - -*************** CreateForeignDataWrapper(CreateFdwStmt * -*** 343,348 **** ---- 349,355 ---- - Oid fdwvalidator; - Datum fdwoptions; - Oid ownerId; -+ Oid secid; - - /* Must be super user */ - if (!superuser()) -*************** CreateForeignDataWrapper(CreateFdwStmt * -*** 381,386 **** ---- 388,396 ---- - else - fdwvalidator = InvalidOid; - -+ /* SELinux permission checks */ -+ secid = sepgsql_fdw_create(stmt->fdwname, fdwvalidator); -+ - values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = fdwvalidator; - - nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true; -*************** CreateForeignDataWrapper(CreateFdwStmt * -*** 396,401 **** ---- 406,413 ---- - nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true; - - tuple = heap_form_tuple(rel->rd_att, values, nulls); -+ if (HeapTupleHasSecid(tuple)) -+ HeapTupleSetSecid(tuple, secid); - - fdwId = simple_heap_insert(rel, tuple); - CatalogUpdateIndexes(rel, tuple); -*************** AlterForeignDataWrapper(AlterFdwStmt *st -*** 490,495 **** ---- 502,510 ---- - fdwvalidator = DatumGetObjectId(datum); - } - -+ /* SELinux permission checks */ -+ sepgsql_fdw_alter(fdwId, fdwvalidator); -+ - /* - * Options specified, validate and update. - */ -*************** CreateForeignServer(CreateForeignServerS -*** 615,620 **** ---- 630,636 ---- - HeapTuple tuple; - Oid srvId; - Oid ownerId; -+ Oid secid; - AclResult aclresult; - ObjectAddress myself; - ObjectAddress referenced; -*************** CreateForeignServer(CreateForeignServerS -*** 642,647 **** ---- 658,665 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname); - -+ secid = sepgsql_foreign_server_create(stmt->fdwname); -+ - /* - * Insert tuple into pg_foreign_server. - */ -*************** CreateForeignServer(CreateForeignServerS -*** 684,689 **** ---- 702,709 ---- - nulls[Anum_pg_foreign_server_srvoptions - 1] = true; - - tuple = heap_form_tuple(rel->rd_att, values, nulls); -+ if (HeapTupleHasSecid(tuple)) -+ HeapTupleSetSecid(tuple, secid); - - srvId = simple_heap_insert(rel, tuple); - -*************** AlterForeignServer(AlterForeignServerStm -*** 740,745 **** ---- 760,768 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER, - stmt->servername); - -+ /* SELinux permission checks */ -+ sepgsql_foreign_server_alter(srvId); -+ - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); -diff -Nrpc blob/src/backend/commands/functioncmds.c sepgsql/src/backend/commands/functioncmds.c -*** blob/src/backend/commands/functioncmds.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/functioncmds.c Thu Sep 17 17:04:16 2009 -*************** -*** 53,58 **** ---- 53,59 ---- - #include "parser/parse_expr.h" - #include "parser/parse_func.h" - #include "parser/parse_type.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -*************** compute_attributes_sql_style(List *optio -*** 517,523 **** - bool *security_definer, - ArrayType **proconfig, - float4 *procost, -! float4 *prorows) - { - ListCell *option; - DefElem *as_item = NULL; ---- 518,525 ---- - bool *security_definer, - ArrayType **proconfig, - float4 *procost, -! float4 *prorows, -! Node **proseclabel) - { - ListCell *option; - DefElem *as_item = NULL; -*************** compute_attributes_sql_style(List *optio -*** 529,534 **** ---- 531,537 ---- - List *set_items = NIL; - DefElem *cost_item = NULL; - DefElem *rows_item = NULL; -+ DefElem *seclabel_item = NULL; - - foreach(option, options) - { -*************** compute_attributes_sql_style(List *optio -*** 558,563 **** ---- 561,574 ---- - errmsg("conflicting or redundant options"))); - windowfunc_item = defel; - } -+ else if (strcmp(defel->defname, "security_context") == 0) -+ { -+ if (seclabel_item) -+ ereport(ERROR, -+ (errcode(ERRCODE_SYNTAX_ERROR), -+ errmsg("conflicting or redundant options"))); -+ seclabel_item = defel; -+ } - else if (compute_common_attribute(defel, - &volatility_item, - &strict_item, -*************** compute_attributes_sql_style(List *optio -*** 622,627 **** ---- 633,640 ---- - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("ROWS must be positive"))); - } -+ if (seclabel_item) -+ *proseclabel = (Node *)seclabel_item; - } - - -*************** CreateFunction(CreateFunctionStmt *stmt, -*** 762,767 **** ---- 775,781 ---- - ArrayType *proconfig; - float4 procost; - float4 prorows; -+ Node *proseclabel; - HeapTuple languageTuple; - Form_pg_language languageStruct; - List *as_clause; -*************** CreateFunction(CreateFunctionStmt *stmt, -*** 784,796 **** - proconfig = NULL; - procost = -1; /* indicates not set */ - prorows = -1; /* indicates not set */ - - /* override attributes from explicit list */ - compute_attributes_sql_style(stmt->options, - &as_clause, &language, - &isWindowFunc, &volatility, - &isStrict, &security, -! &proconfig, &procost, &prorows); - - /* Convert language name to canonical case */ - languageName = case_translate_language_name(language); ---- 798,811 ---- - proconfig = NULL; - procost = -1; /* indicates not set */ - prorows = -1; /* indicates not set */ -+ proseclabel = NULL; - - /* override attributes from explicit list */ - compute_attributes_sql_style(stmt->options, - &as_clause, &language, - &isWindowFunc, &volatility, - &isStrict, &security, -! &proconfig, &procost, &prorows, &proseclabel); - - /* Convert language name to canonical case */ - languageName = case_translate_language_name(language); -*************** CreateFunction(CreateFunctionStmt *stmt, -*** 926,932 **** - parameterDefaults, - PointerGetDatum(proconfig), - procost, -! prorows); - } - - ---- 941,948 ---- - parameterDefaults, - PointerGetDatum(proconfig), - procost, -! prorows, -! proseclabel); - } - - -*************** RenameFunction(List *name, List *argtype -*** 1112,1117 **** ---- 1128,1136 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux permission checks */ -+ sepgsql_proc_alter(procOid, newname, InvalidOid); -+ - /* rename */ - namestrcpy(&(procForm->proname), newname); - simple_heap_update(rel, &tup->t_self, tup); -*************** AlterFunctionOwner_internal(Relation rel -*** 1220,1225 **** ---- 1239,1246 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(procForm->pronamespace)); - } -+ /* SELinux permission checks */ -+ sepgsql_proc_alter(procOid, NULL, InvalidOid); - - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); -*************** AlterFunctionOwner_internal(Relation rel -*** 1258,1263 **** ---- 1279,1337 ---- - } - - /* -+ * ALTER FUNCTION name(args,...) SECURITY_LABEL [=] newlabel -+ */ -+ void -+ AlterFunctionSecLabel(List *name, List *argtypes, DefElem *seclabel) -+ { -+ Relation rel; -+ HeapTuple oldtup; -+ HeapTuple newtup; -+ Oid procOid; -+ Oid secid; -+ bool replaces[Natts_pg_proc]; -+ -+ /* open pg_proc system catalog */ -+ rel = heap_open(ProcedureRelationId, RowExclusiveLock); -+ -+ procOid = LookupFuncNameTypeNames(name, argtypes, false); -+ -+ oldtup = SearchSysCache(PROCOID, -+ ObjectIdGetDatum(procOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(oldtup)) -+ elog(ERROR, "cache lookup failed for function %u", procOid); -+ -+ memset(replaces, false, sizeof(replaces)); -+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), -+ NULL, NULL, replaces); -+ -+ if (!HeapTupleHasSecid(newtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("Unable to set security label on \"%s\"", -+ get_func_name(procOid)))); -+ -+ ReleaseSysCache(oldtup); -+ -+ /* DAC permission checks */ -+ if (!pg_proc_ownercheck(HeapTupleGetOid(newtup), GetUserId())) -+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, -+ get_func_name(HeapTupleGetOid(newtup))); -+ -+ /* SELinux permission checks */ -+ secid = sepgsql_proc_relabel(procOid, seclabel); -+ HeapTupleSetSecid(newtup, secid); -+ -+ simple_heap_update(rel, &newtup->t_self, newtup); -+ CatalogUpdateIndexes(rel, newtup); -+ -+ heap_freetuple(newtup); -+ -+ heap_close(rel, RowExclusiveLock); -+ } -+ -+ /* - * Implements the ALTER FUNCTION utility command (except for the - * RENAME and OWNER clauses, which are handled as part of the generic - * ALTER framework). -*************** AlterFunction(AlterFunctionStmt *stmt) -*** 1296,1301 **** ---- 1370,1378 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - NameListToString(stmt->func->funcname)); - -+ /* SELinux checks permissions */ -+ sepgsql_proc_alter(funcOid, NULL, InvalidOid); -+ - if (procForm->proisagg) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), -*************** CreateCast(CreateCastStmt *stmt) -*** 1473,1478 **** ---- 1550,1556 ---- - char sourcetyptype; - char targettyptype; - Oid funcid; -+ Oid secid; - int nargs; - char castcontext; - char castmethod; -*************** CreateCast(CreateCastStmt *stmt) -*** 1674,1679 **** ---- 1752,1759 ---- - castcontext = 0; /* keep compiler quiet */ - break; - } -+ /* SELinux permission check */ -+ secid = sepgsql_cast_create(sourcetypeid, targettypeid, funcid); - - relation = heap_open(CastRelationId, RowExclusiveLock); - -*************** CreateCast(CreateCastStmt *stmt) -*** 1704,1709 **** ---- 1784,1792 ---- - - tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); - -+ if (HeapTupleHasSecid(tuple)) -+ HeapTupleSetSecid(tuple, secid); -+ - simple_heap_insert(relation, tuple); - - CatalogUpdateIndexes(relation, tuple); -*************** AlterFunctionNamespace(List *name, List -*** 1897,1902 **** ---- 1980,1988 ---- - NameStr(proc->proname), - newschema))); - -+ /* SELinux checks permissions */ -+ sepgsql_proc_alter(procOid, NULL, nspOid); -+ - /* OK, modify the pg_proc row */ - - /* tup is a copy, so we can scribble directly on it */ -diff -Nrpc blob/src/backend/commands/indexcmds.c sepgsql/src/backend/commands/indexcmds.c -*** blob/src/backend/commands/indexcmds.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/indexcmds.c Sun Dec 20 00:41:22 2009 -*************** -*** 37,42 **** ---- 37,43 ---- - #include "parser/parse_coerce.h" - #include "parser/parse_func.h" - #include "parser/parsetree.h" -+ #include "security/sepgsql.h" - #include "storage/lmgr.h" - #include "storage/proc.h" - #include "storage/procarray.h" -*************** DefineIndex(RangeVar *heapRelation, -*** 197,202 **** ---- 198,206 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceId)); -+ -+ /* SELinux checks */ -+ sepgsql_index_create(relationId, namespaceId); - } - - /* -diff -Nrpc blob/src/backend/commands/lockcmds.c sepgsql/src/backend/commands/lockcmds.c -*** blob/src/backend/commands/lockcmds.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/lockcmds.c Fri Sep 18 14:51:00 2009 -*************** -*** 20,25 **** ---- 20,26 ---- - #include "commands/lockcmds.h" - #include "miscadmin.h" - #include "parser/parse_clause.h" -+ #include "security/sepgsql.h" - #include "storage/lmgr.h" - #include "utils/acl.h" - #include "utils/lsyscache.h" -*************** LockTableRecurse(Oid reloid, RangeVar *r -*** 140,145 **** ---- 141,149 ---- - errmsg("\"%s\" is not a table", - RelationGetRelationName(rel)))); - -+ /* SELinux: check db_table:{lock} permission */ -+ sepgsql_relation_lock(reloid); -+ - /* - * If requested, recurse to children. We use find_inheritance_children - * not find_all_inheritors to avoid taking locks far in advance of -diff -Nrpc blob/src/backend/commands/opclasscmds.c sepgsql/src/backend/commands/opclasscmds.c -*** blob/src/backend/commands/opclasscmds.c Sat Jan 3 13:01:35 2009 ---- sepgsql/src/backend/commands/opclasscmds.c Thu Sep 17 17:04:16 2009 -*************** -*** 35,40 **** ---- 35,41 ---- - #include "parser/parse_func.h" - #include "parser/parse_oper.h" - #include "parser/parse_type.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -*************** CreateOpFamily(char *amname, char *opfna -*** 177,182 **** ---- 178,184 ---- - HeapTuple tup; - Datum values[Natts_pg_opfamily]; - bool nulls[Natts_pg_opfamily]; -+ Oid opfSecid; - NameData opfName; - ObjectAddress myself, - referenced; -*************** CreateOpFamily(char *amname, char *opfna -*** 197,202 **** ---- 199,207 ---- - errmsg("operator family \"%s\" for access method \"%s\" already exists", - opfname, amname))); - -+ /* SELinux check permission */ -+ opfSecid = sepgsql_opfamily_create(opfname, namespaceoid); -+ - /* - * Okay, let's create the pg_opfamily entry. - */ -*************** CreateOpFamily(char *amname, char *opfna -*** 210,215 **** ---- 215,222 ---- - values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId()); - - tup = heap_form_tuple(rel->rd_att, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, opfSecid); - - opfamilyoid = simple_heap_insert(rel, tup); - -*************** DefineOpClass(CreateOpClassStmt *stmt) -*** 265,270 **** ---- 272,278 ---- - Form_pg_am pg_am; - Datum values[Natts_pg_opclass]; - bool nulls[Natts_pg_opclass]; -+ Oid opcSecid; - AclResult aclresult; - NameData opcName; - ObjectAddress myself, -*************** DefineOpClass(CreateOpClassStmt *stmt) -*** 353,358 **** ---- 361,369 ---- - NameListToString(stmt->opfamilyname), stmt->amname))); - opfamilyoid = HeapTupleGetOid(tup); - -+ /* SELinux checks permission */ -+ sepgsql_opfamily_alter(opfamilyoid, NULL); -+ - /* - * XXX given the superuser check above, there's no need for an - * ownership check here -*************** DefineOpClass(CreateOpClassStmt *stmt) -*** 371,376 **** ---- 382,390 ---- - { - opfamilyoid = HeapTupleGetOid(tup); - -+ /* SELinux checks permission */ -+ sepgsql_opfamily_alter(opfamilyoid, NULL); -+ - /* - * XXX given the superuser check above, there's no need for an - * ownership check here -*************** DefineOpClass(CreateOpClassStmt *stmt) -*** 441,446 **** ---- 455,462 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - get_func_name(funcOid)); - #endif -+ /* SELinux check permission */ -+ sepgsql_opfamily_add_operator(opfamilyoid, operOid); - - /* Save the info */ - member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember)); -*************** DefineOpClass(CreateOpClassStmt *stmt) -*** 465,470 **** ---- 481,488 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - get_func_name(funcOid)); - #endif -+ /* SELinux check permission */ -+ sepgsql_opfamily_add_procedure(opfamilyoid, funcOid); - - /* Save the info */ - member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember)); -*************** DefineOpClass(CreateOpClassStmt *stmt) -*** 531,536 **** ---- 549,557 ---- - errmsg("operator class \"%s\" for access method \"%s\" already exists", - opcname, stmt->amname))); - -+ /* SELinux permission check */ -+ opcSecid = sepgsql_opclass_create(opcname, namespaceoid); -+ - /* - * If we are creating a default opclass, check there isn't one already. - * (Note we do not restrict this test to visible opclasses; this ensures -*************** DefineOpFamily(CreateOpFamilyStmt *stmt) -*** 657,662 **** ---- 678,684 ---- - HeapTuple tup; - Datum values[Natts_pg_opfamily]; - bool nulls[Natts_pg_opfamily]; -+ Oid opfSecid; - AclResult aclresult; - NameData opfName; - ObjectAddress myself, -*************** DefineOpFamily(CreateOpFamilyStmt *stmt) -*** 699,704 **** ---- 721,729 ---- - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to create an operator family"))); - -+ /* SELinux permission check */ -+ opfSecid = sepgsql_opfamily_create(opfname, namespaceoid); -+ - rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock); - - /* -*************** AlterOpFamily(AlterOpFamilyStmt *stmt) -*** 773,778 **** ---- 798,804 ---- - int maxOpNumber, /* amstrategies value */ - maxProcNumber; /* amsupport value */ - HeapTuple tup; -+ Oid opfSecid; - Form_pg_am pg_am; - - /* Get necessary info about access method */ -*************** AlterOpFamily(AlterOpFamilyStmt *stmt) -*** 805,810 **** ---- 831,837 ---- - errmsg("operator family \"%s\" does not exist for access method \"%s\"", - NameListToString(stmt->opfamilyname), stmt->amname))); - opfamilyoid = HeapTupleGetOid(tup); -+ opfSecid = HeapTupleGetSecid(tup); - ReleaseSysCache(tup); - - /* -*************** AlterOpFamily(AlterOpFamilyStmt *stmt) -*** 817,822 **** ---- 844,852 ---- - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to alter an operator family"))); - -+ /* SELinux permission checks */ -+ sepgsql_opfamily_alter(opfamilyoid, NULL); -+ - /* - * ADD and DROP cases need separate code from here on down. - */ -*************** AlterOpFamilyAdd(List *opfamilyname, Oid -*** 893,898 **** ---- 923,930 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - get_func_name(funcOid)); - #endif -+ /* SELinux permission check */ -+ sepgsql_opfamily_add_operator(opfamilyoid, operOid); - - /* Save the info */ - member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember)); -*************** AlterOpFamilyAdd(List *opfamilyname, Oid -*** 917,922 **** ---- 949,956 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - get_func_name(funcOid)); - #endif -+ /* SELinux permission check */ -+ sepgsql_opfamily_add_procedure(opfamilyoid, funcOid); - - /* Save the info */ - member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember)); -*************** RenameOpClass(List *name, const char *ac -*** 1815,1820 **** ---- 1849,1857 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux permission checks */ -+ sepgsql_opclass_alter(opcOid, newname); -+ - /* rename */ - namestrcpy(&(((Form_pg_opclass) GETSTRUCT(tup))->opcname), newname); - simple_heap_update(rel, &tup->t_self, tup); -*************** RenameOpFamily(List *name, const char *a -*** 1915,1920 **** ---- 1952,1960 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux check permissions */ -+ sepgsql_opfamily_alter(opfOid, newname); -+ - /* rename */ - namestrcpy(&(((Form_pg_opfamily) GETSTRUCT(tup))->opfname), newname); - simple_heap_update(rel, &tup->t_self, tup); -*************** AlterOpClassOwner_internal(Relation rel, -*** 2035,2040 **** ---- 2075,2082 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - } -+ /* SELinux permission check */ -+ sepgsql_opclass_alter(HeapTupleGetOid(tup), NULL); - - /* - * Modify the owner --- okay to scribble on tup because it's a copy -*************** AlterOpFamilyOwner_internal(Relation rel -*** 2162,2167 **** ---- 2204,2211 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - } -+ /* SELinux permission checks */ -+ sepgsql_opfamily_alter(HeapTupleGetOid(tup), NULL); - - /* - * Modify the owner --- okay to scribble on tup because it's a copy -diff -Nrpc blob/src/backend/commands/operatorcmds.c sepgsql/src/backend/commands/operatorcmds.c -*** blob/src/backend/commands/operatorcmds.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/operatorcmds.c Thu Sep 17 22:10:19 2009 -*************** -*** 45,50 **** ---- 45,51 ---- - #include "parser/parse_func.h" - #include "parser/parse_oper.h" - #include "parser/parse_type.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/lsyscache.h" - #include "utils/rel.h" -*************** AlterOperatorOwner_internal(Relation rel -*** 432,437 **** ---- 433,440 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(oprForm->oprnamespace)); - } -+ /* SELinux permission check */ -+ sepgsql_operator_alter(operOid); - - /* - * Modify the owner --- okay to scribble on tup because it's a copy -diff -Nrpc blob/src/backend/commands/proclang.c sepgsql/src/backend/commands/proclang.c -*** blob/src/backend/commands/proclang.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/proclang.c Thu Sep 17 22:10:19 2009 -*************** -*** 30,35 **** ---- 30,36 ---- - #include "miscadmin.h" - #include "parser/gramparse.h" - #include "parser/parse_func.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -*************** CreateProceduralLanguage(CreatePLangStmt -*** 151,157 **** - NIL, - PointerGetDatum(NULL), - 1, -! 0); - } - - /* ---- 152,159 ---- - NIL, - PointerGetDatum(NULL), - 1, -! 0, -! NULL); - } - - /* -*************** CreateProceduralLanguage(CreatePLangStmt -*** 186,192 **** - NIL, - PointerGetDatum(NULL), - 1, -! 0); - } - } - else ---- 188,195 ---- - NIL, - PointerGetDatum(NULL), - 1, -! 0, -! NULL); - } - } - else -*************** create_proc_lang(const char *languageNam -*** 275,284 **** ---- 278,293 ---- - bool nulls[Natts_pg_language]; - NameData langname; - HeapTuple tup; -+ Oid langSecid; - ObjectAddress myself, - referenced; - - /* -+ * SELinux permission checks -+ */ -+ langSecid = sepgsql_language_create(languageName, handlerOid, valOid); -+ -+ /* - * Insert the new language into pg_language - */ - rel = heap_open(LanguageRelationId, RowExclusiveLock); -*************** create_proc_lang(const char *languageNam -*** 297,302 **** ---- 306,313 ---- - nulls[Anum_pg_language_lanacl - 1] = true; - - tup = heap_form_tuple(tupDesc, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, langSecid); - - simple_heap_insert(rel, tup); - -*************** RenameLanguage(const char *oldname, cons -*** 518,523 **** ---- 529,537 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE, - oldname); - -+ /* SELinux permission checks */ -+ sepgsql_language_alter(HeapTupleGetOid(tup)); -+ - /* rename */ - namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname); - simple_heap_update(rel, &tup->t_self, tup); -*************** AlterLanguageOwner_internal(HeapTuple tu -*** 613,618 **** ---- 627,635 ---- - /* Must be able to become new owner */ - check_is_member_of_role(GetUserId(), newOwnerId); - -+ /* SELinux permission checks */ -+ sepgsql_language_alter(HeapTupleGetOid(tup)); -+ - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - -diff -Nrpc blob/src/backend/commands/schemacmds.c sepgsql/src/backend/commands/schemacmds.c -*** blob/src/backend/commands/schemacmds.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/commands/schemacmds.c Tue Dec 15 17:30:25 2009 -*************** -*** 25,30 **** ---- 25,31 ---- - #include "commands/schemacmds.h" - #include "miscadmin.h" - #include "parser/parse_utilcmd.h" -+ #include "security/sepgsql.h" - #include "tcop/utility.h" - #include "utils/acl.h" - #include "utils/builtins.h" -*************** CreateSchemaCommand(CreateSchemaStmt *st -*** 48,53 **** ---- 49,55 ---- - ListCell *parsetree_item; - Oid owner_uid; - Oid saved_uid; -+ Oid nspsecid; - int save_sec_context; - AclResult aclresult; - -*************** CreateSchemaCommand(CreateSchemaStmt *st -*** 75,80 **** ---- 77,86 ---- - - check_is_member_of_role(saved_uid, owner_uid); - -+ /* SELinux checks db_schema:{create} */ -+ nspsecid = sepgsql_schema_create(schemaName, false, -+ (DefElem *)stmt->secLabel); -+ - /* Additional check to protect reserved schema names */ - if (!allowSystemTableMods && IsReservedName(schemaName)) - ereport(ERROR, -*************** CreateSchemaCommand(CreateSchemaStmt *st -*** 95,101 **** - save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - - /* Create the schema's namespace */ -! namespaceId = NamespaceCreate(schemaName, owner_uid); - - /* Advance cmd counter to make the namespace visible */ - CommandCounterIncrement(); ---- 101,107 ---- - save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - - /* Create the schema's namespace */ -! namespaceId = NamespaceCreate(schemaName, owner_uid, nspsecid); - - /* Advance cmd counter to make the namespace visible */ - CommandCounterIncrement(); -*************** RenameSchema(const char *oldname, const -*** 268,275 **** - errmsg("schema \"%s\" does not exist", oldname))); - - /* make sure the new name doesn't exist */ -! if (HeapTupleIsValid( -! SearchSysCache(NAMESPACENAME, - CStringGetDatum(newname), - 0, 0, 0))) - ereport(ERROR, ---- 274,280 ---- - errmsg("schema \"%s\" does not exist", oldname))); - - /* make sure the new name doesn't exist */ -! if (HeapTupleIsValid(SearchSysCache(NAMESPACENAME, - CStringGetDatum(newname), - 0, 0, 0))) - ereport(ERROR, -*************** RenameSchema(const char *oldname, const -*** 287,292 **** ---- 292,300 ---- - aclcheck_error(aclresult, ACL_KIND_DATABASE, - get_database_name(MyDatabaseId)); - -+ /* SELinux checks db_schema:{setattr} */ -+ sepgsql_schema_alter(HeapTupleGetOid(tup)); -+ - if (!allowSystemTableMods && IsReservedName(newname)) - ereport(ERROR, - (errcode(ERRCODE_RESERVED_NAME), -*************** AlterSchemaOwner_internal(HeapTuple tup, -*** 398,403 **** ---- 406,414 ---- - aclcheck_error(aclresult, ACL_KIND_DATABASE, - get_database_name(MyDatabaseId)); - -+ /* SELinux checks db_schema:{setattr} */ -+ sepgsql_schema_alter(HeapTupleGetOid(tup)); -+ - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - -*************** AlterSchemaOwner_internal(HeapTuple tup, -*** 432,434 **** ---- 443,493 ---- - } - - } -+ -+ /* -+ * ALTER SCHEMA name SECURITY_LABEL [=] newlabel -+ */ -+ void -+ AlterSchemaSecLabel(const char *name, DefElem *secLabel) -+ { -+ Relation rel; -+ HeapTuple oldtup; -+ HeapTuple newtup; -+ Oid secid; -+ bool replaces[Natts_pg_namespace]; -+ -+ /* open pg_namespace relation */ -+ rel = heap_open(NamespaceRelationId, RowExclusiveLock); -+ oldtup = SearchSysCache(NAMESPACENAME, -+ CStringGetDatum(name), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(oldtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_SCHEMA), -+ errmsg("schema \"%s\" does not exist", name))); -+ -+ memset(replaces, false, sizeof(replaces)); -+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), -+ NULL, NULL, replaces); -+ if (!HeapTupleHasSecid(newtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("Unable to set security label on \"%s\"", name))); -+ -+ ReleaseSysCache(oldtup); -+ -+ /* DAC permission check */ -+ if (!pg_namespace_ownercheck(HeapTupleGetOid(newtup), GetUserId())) -+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, name); -+ /* SELinux checks db_schema:{setattr relabelfrom relabelto} */ -+ secid = sepgsql_schema_relabel(HeapTupleGetOid(newtup), secLabel); -+ HeapTupleSetSecid(newtup, secid); -+ -+ simple_heap_update(rel, &newtup->t_self, newtup); -+ -+ CatalogUpdateIndexes(rel, newtup); -+ -+ heap_freetuple(newtup); -+ -+ heap_close(rel, RowExclusiveLock); -+ } -diff -Nrpc blob/src/backend/commands/sequence.c sepgsql/src/backend/commands/sequence.c -*** blob/src/backend/commands/sequence.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/sequence.c Fri Sep 18 14:51:00 2009 -*************** -*** 26,31 **** ---- 26,32 ---- - #include "commands/tablecmds.h" - #include "miscadmin.h" - #include "nodes/makefuncs.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/lmgr.h" - #include "storage/proc.h" -*************** DefineSequence(CreateSeqStmt *seq) -*** 201,206 **** ---- 202,208 ---- - stmt->options = list_make1(defWithOids(false)); - stmt->oncommit = ONCOMMIT_NOOP; - stmt->tablespacename = NULL; -+ stmt->secLabel = seq->secLabel; - - seqoid = DefineRelation(stmt, RELKIND_SEQUENCE); - -*************** AlterSequence(AlterSeqStmt *stmt) -*** 328,333 **** ---- 330,337 ---- - if (!pg_class_ownercheck(relid, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - stmt->sequence->relname); -+ /* SELinux checks db_sequence:{setattr} */ -+ sepgsql_relation_alter(relid, NULL, InvalidOid); - - /* do the work */ - AlterSequenceInternal(relid, stmt->options); -*************** nextval_internal(Oid relid) -*** 467,472 **** ---- 471,479 ---- - errmsg("permission denied for sequence %s", - RelationGetRelationName(seqrel)))); - -+ /* SELinux check db_sequence:{next_value} */ -+ sepgsql_sequence_next_value(elm->relid); -+ - if (elm->last != elm->cached) /* some numbers were cached */ - { - Assert(elm->last_valid); -*************** currval_oid(PG_FUNCTION_ARGS) -*** 662,667 **** ---- 669,677 ---- - errmsg("permission denied for sequence %s", - RelationGetRelationName(seqrel)))); - -+ /* SELinux check db_sequence:{get_value} */ -+ sepgsql_sequence_get_value(elm->relid); -+ - if (!elm->last_valid) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), -*************** lastval(PG_FUNCTION_ARGS) -*** 706,711 **** ---- 716,724 ---- - errmsg("permission denied for sequence %s", - RelationGetRelationName(seqrel)))); - -+ /* SELinux check db_sequence:{get_value} */ -+ sepgsql_sequence_get_value(last_used_seq->relid); -+ - result = last_used_seq->last; - relation_close(seqrel, NoLock); - -*************** do_setval(Oid relid, int64 next, bool is -*** 742,747 **** ---- 755,763 ---- - errmsg("permission denied for sequence %s", - RelationGetRelationName(seqrel)))); - -+ /* SELinux check db_sequence:{set_value} */ -+ sepgsql_sequence_set_value(elm->relid); -+ - /* lock page' buffer and read tuple */ - seq = read_info(elm, seqrel, &buf); - -diff -Nrpc blob/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/tablecmds.c -*** blob/src/backend/commands/tablecmds.c Fri Dec 18 09:40:55 2009 ---- sepgsql/src/backend/commands/tablecmds.c Sun Dec 20 00:41:22 2009 -*************** -*** 62,67 **** ---- 62,68 ---- - #include "parser/parser.h" - #include "rewrite/rewriteDefine.h" - #include "rewrite/rewriteHandler.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/lmgr.h" - #include "storage/smgr.h" -*************** static void ATExecCmd(List **wqueue, Alt -*** 260,267 **** - static void ATRewriteTables(List **wqueue); - static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap); - static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel); -! static void ATSimplePermissions(Relation rel, bool allowView); -! static void ATSimplePermissionsRelationOrIndex(Relation rel); - static void ATSimpleRecursion(List **wqueue, Relation rel, - AlterTableCmd *cmd, bool recurse); - static void ATOneLevelRecursion(List **wqueue, Relation rel, ---- 261,268 ---- - static void ATRewriteTables(List **wqueue); - static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap); - static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel); -! static void ATSimplePermissions(Relation rel, const char *colname, bool allowView); -! static void ATSimplePermissionsRelationOrIndex(Relation rel, const char *colname); - static void ATSimpleRecursion(List **wqueue, Relation rel, - AlterTableCmd *cmd, bool recurse); - static void ATOneLevelRecursion(List **wqueue, Relation rel, -*************** DefineRelation(CreateStmt *stmt, char re -*** 351,356 **** ---- 352,358 ---- - List *rawDefaults; - List *cookedDefaults; - Datum reloptions; -+ Oid *secLabels; - ListCell *listptr; - AttrNumber attnum; - static char *validnsps[] = HEAP_RELOPT_NAMESPACES; -*************** DefineRelation(CreateStmt *stmt, char re -*** 454,459 **** ---- 456,471 ---- - localHasOids = interpretOidsOption(stmt->options); - descriptor->tdhasoid = (localHasOids || parentOidCount > 0); - -+ /* SELinux checks db_table:{create} and db_column:{create} */ -+ secLabels = sepgsql_relation_create(relname, -+ relkind, -+ descriptor, -+ namespaceId, -+ (DefElem *)stmt->secLabel, -+ schema, -+ false, -+ true); -+ - /* - * Find columns with default values and prepare for insertion of the - * defaults. Pre-cooked (that is, inherited) defaults go into a list of -*************** DefineRelation(CreateStmt *stmt, char re -*** 523,529 **** - parentOidCount, - stmt->oncommit, - reloptions, -! allowSystemTableMods); - - StoreCatalogInheritance(relationId, inheritOids); - ---- 535,542 ---- - parentOidCount, - stmt->oncommit, - reloptions, -! allowSystemTableMods, -! secLabels); - - StoreCatalogInheritance(relationId, inheritOids); - -*************** ExecuteTruncate(TruncateStmt *stmt) -*** 897,902 **** ---- 910,917 ---- - if (!pg_class_ownercheck(seq_relid, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(seq_rel)); -+ /* SELinux checks */ -+ sepgsql_relation_alter(seq_relid, NULL, InvalidOid); - - seq_relids = lappend_oid(seq_relids, seq_relid); - -*************** truncate_check_rel(Relation rel) -*** 1052,1057 **** ---- 1067,1075 ---- - errmsg("permission denied: \"%s\" is a system catalog", - RelationGetRelationName(rel)))); - -+ /* SELinux: check db_table:{delete} permission */ -+ sepgsql_relation_truncate(rel); -+ - /* - * We can never allow truncation of shared or nailed-in-cache relations, - * because we can't support changing their relfilenode values. -*************** MergeAttributes(List *schema, List *supe -*** 1226,1231 **** ---- 1244,1251 ---- - if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(relation)); -+ /* SELinux checks db_table:{setattr} */ -+ sepgsql_relation_alter(RelationGetRelid(relation), NULL, InvalidOid); - - /* - * Reject duplications in the list of parents. -*************** renameatt(Oid myrelid, -*** 1931,1936 **** ---- 1951,1959 ---- - errmsg("cannot rename system column \"%s\"", - oldattname))); - -+ /* SELinux checks db_column:{setattr} */ -+ sepgsql_attribute_alter(myrelid, oldattname); -+ - /* - * if the attribute is inherited, forbid the renaming, unless we are - * already inside a recursive rename. -*************** RenameRelation(Oid myrelid, const char * -*** 2036,2041 **** ---- 2059,2067 ---- - Oid namespaceId; - char relkind; - -+ /* SELinux checks */ -+ sepgsql_relation_alter(myrelid, newrelname, InvalidOid); -+ - /* - * Grab an exclusive lock on the target table, index, sequence or view, - * which we will NOT release until end of transaction. -*************** ATPrepCmd(List **wqueue, Relation rel, A -*** 2369,2382 **** - switch (cmd->subtype) - { - case AT_AddColumn: /* ADD COLUMN */ -! ATSimplePermissions(rel, false); - /* Performs own recursion */ - ATPrepAddColumn(wqueue, rel, recurse, cmd); - pass = AT_PASS_ADD_COL; - break; - case AT_AddColumnToView: /* add column via CREATE OR REPLACE - * VIEW */ -! ATSimplePermissions(rel, true); - /* Performs own recursion */ - ATPrepAddColumn(wqueue, rel, recurse, cmd); - pass = AT_PASS_ADD_COL; ---- 2395,2408 ---- - switch (cmd->subtype) - { - case AT_AddColumn: /* ADD COLUMN */ -! ATSimplePermissions(rel, NULL, false); - /* Performs own recursion */ - ATPrepAddColumn(wqueue, rel, recurse, cmd); - pass = AT_PASS_ADD_COL; - break; - case AT_AddColumnToView: /* add column via CREATE OR REPLACE - * VIEW */ -! ATSimplePermissions(rel, NULL, true); - /* Performs own recursion */ - ATPrepAddColumn(wqueue, rel, recurse, cmd); - pass = AT_PASS_ADD_COL; -*************** ATPrepCmd(List **wqueue, Relation rel, A -*** 2389,2407 **** - * substitutes default values into INSERTs before it expands - * rules. - */ -! ATSimplePermissions(rel, true); - ATSimpleRecursion(wqueue, rel, cmd, recurse); - /* No command-specific prep needed */ - pass = cmd->def ? AT_PASS_ADD_CONSTR : AT_PASS_DROP; - break; - case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */ -! ATSimplePermissions(rel, false); - ATSimpleRecursion(wqueue, rel, cmd, recurse); - /* No command-specific prep needed */ - pass = AT_PASS_DROP; - break; - case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */ -! ATSimplePermissions(rel, false); - ATSimpleRecursion(wqueue, rel, cmd, recurse); - /* No command-specific prep needed */ - pass = AT_PASS_ADD_CONSTR; ---- 2415,2433 ---- - * substitutes default values into INSERTs before it expands - * rules. - */ -! ATSimplePermissions(rel, cmd->name, true); - ATSimpleRecursion(wqueue, rel, cmd, recurse); - /* No command-specific prep needed */ - pass = cmd->def ? AT_PASS_ADD_CONSTR : AT_PASS_DROP; - break; - case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */ -! ATSimplePermissions(rel, cmd->name, false); - ATSimpleRecursion(wqueue, rel, cmd, recurse); - /* No command-specific prep needed */ - pass = AT_PASS_DROP; - break; - case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */ -! ATSimplePermissions(rel, cmd->name, false); - ATSimpleRecursion(wqueue, rel, cmd, recurse); - /* No command-specific prep needed */ - pass = AT_PASS_ADD_CONSTR; -*************** ATPrepCmd(List **wqueue, Relation rel, A -*** 2413,2425 **** - pass = AT_PASS_COL_ATTRS; - break; - case AT_SetStorage: /* ALTER COLUMN STORAGE */ -! ATSimplePermissions(rel, false); - ATSimpleRecursion(wqueue, rel, cmd, recurse); - /* No command-specific prep needed */ - pass = AT_PASS_COL_ATTRS; - break; - case AT_DropColumn: /* DROP COLUMN */ -! ATSimplePermissions(rel, false); - /* Recursion occurs during execution phase */ - /* No command-specific prep needed except saving recurse flag */ - if (recurse) ---- 2439,2451 ---- - pass = AT_PASS_COL_ATTRS; - break; - case AT_SetStorage: /* ALTER COLUMN STORAGE */ -! ATSimplePermissions(rel, cmd->name, false); - ATSimpleRecursion(wqueue, rel, cmd, recurse); - /* No command-specific prep needed */ - pass = AT_PASS_COL_ATTRS; - break; - case AT_DropColumn: /* DROP COLUMN */ -! ATSimplePermissions(rel, NULL, false); - /* Recursion occurs during execution phase */ - /* No command-specific prep needed except saving recurse flag */ - if (recurse) -*************** ATPrepCmd(List **wqueue, Relation rel, A -*** 2427,2439 **** - pass = AT_PASS_DROP; - break; - case AT_AddIndex: /* ADD INDEX */ -! ATSimplePermissions(rel, false); - /* This command never recurses */ - /* No command-specific prep needed */ - pass = AT_PASS_ADD_INDEX; - break; - case AT_AddConstraint: /* ADD CONSTRAINT */ -! ATSimplePermissions(rel, false); - /* Recursion occurs during execution phase */ - /* No command-specific prep needed except saving recurse flag */ - if (recurse) ---- 2453,2465 ---- - pass = AT_PASS_DROP; - break; - case AT_AddIndex: /* ADD INDEX */ -! ATSimplePermissions(rel, NULL, false); - /* This command never recurses */ - /* No command-specific prep needed */ - pass = AT_PASS_ADD_INDEX; - break; - case AT_AddConstraint: /* ADD CONSTRAINT */ -! ATSimplePermissions(rel, NULL, false); - /* Recursion occurs during execution phase */ - /* No command-specific prep needed except saving recurse flag */ - if (recurse) -*************** ATPrepCmd(List **wqueue, Relation rel, A -*** 2441,2447 **** - pass = AT_PASS_ADD_CONSTR; - break; - case AT_DropConstraint: /* DROP CONSTRAINT */ -! ATSimplePermissions(rel, false); - /* Recursion occurs during execution phase */ - /* No command-specific prep needed except saving recurse flag */ - if (recurse) ---- 2467,2473 ---- - pass = AT_PASS_ADD_CONSTR; - break; - case AT_DropConstraint: /* DROP CONSTRAINT */ -! ATSimplePermissions(rel, NULL, false); - /* Recursion occurs during execution phase */ - /* No command-specific prep needed except saving recurse flag */ - if (recurse) -*************** ATPrepCmd(List **wqueue, Relation rel, A -*** 2449,2455 **** - pass = AT_PASS_DROP; - break; - case AT_AlterColumnType: /* ALTER COLUMN TYPE */ -! ATSimplePermissions(rel, false); - /* Performs own recursion */ - ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd); - pass = AT_PASS_ALTER_TYPE; ---- 2475,2481 ---- - pass = AT_PASS_DROP; - break; - case AT_AlterColumnType: /* ALTER COLUMN TYPE */ -! ATSimplePermissions(rel, cmd->name, false); - /* Performs own recursion */ - ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd); - pass = AT_PASS_ALTER_TYPE; -*************** ATPrepCmd(List **wqueue, Relation rel, A -*** 2461,2480 **** - break; - case AT_ClusterOn: /* CLUSTER ON */ - case AT_DropCluster: /* SET WITHOUT CLUSTER */ -! ATSimplePermissions(rel, false); - /* These commands never recurse */ - /* No command-specific prep needed */ - pass = AT_PASS_MISC; - break; - case AT_AddOids: /* SET WITH OIDS */ -! ATSimplePermissions(rel, false); - /* Performs own recursion */ - if (!rel->rd_rel->relhasoids || recursing) - ATPrepAddOids(wqueue, rel, recurse, cmd); - pass = AT_PASS_ADD_COL; - break; - case AT_DropOids: /* SET WITHOUT OIDS */ -! ATSimplePermissions(rel, false); - /* Performs own recursion */ - if (rel->rd_rel->relhasoids) - { ---- 2487,2506 ---- - break; - case AT_ClusterOn: /* CLUSTER ON */ - case AT_DropCluster: /* SET WITHOUT CLUSTER */ -! ATSimplePermissions(rel, NULL, false); - /* These commands never recurse */ - /* No command-specific prep needed */ - pass = AT_PASS_MISC; - break; - case AT_AddOids: /* SET WITH OIDS */ -! ATSimplePermissions(rel, NULL, false); - /* Performs own recursion */ - if (!rel->rd_rel->relhasoids || recursing) - ATPrepAddOids(wqueue, rel, recurse, cmd); - pass = AT_PASS_ADD_COL; - break; - case AT_DropOids: /* SET WITHOUT OIDS */ -! ATSimplePermissions(rel, NULL, false); - /* Performs own recursion */ - if (rel->rd_rel->relhasoids) - { -*************** ATPrepCmd(List **wqueue, Relation rel, A -*** 2488,2501 **** - pass = AT_PASS_DROP; - break; - case AT_SetTableSpace: /* SET TABLESPACE */ -! ATSimplePermissionsRelationOrIndex(rel); - /* This command never recurses */ - ATPrepSetTableSpace(tab, rel, cmd->name); - pass = AT_PASS_MISC; /* doesn't actually matter */ - break; - case AT_SetRelOptions: /* SET (...) */ - case AT_ResetRelOptions: /* RESET (...) */ -! ATSimplePermissionsRelationOrIndex(rel); - /* This command never recurses */ - /* No command-specific prep needed */ - pass = AT_PASS_MISC; ---- 2514,2527 ---- - pass = AT_PASS_DROP; - break; - case AT_SetTableSpace: /* SET TABLESPACE */ -! ATSimplePermissionsRelationOrIndex(rel, NULL); - /* This command never recurses */ - ATPrepSetTableSpace(tab, rel, cmd->name); - pass = AT_PASS_MISC; /* doesn't actually matter */ - break; - case AT_SetRelOptions: /* SET (...) */ - case AT_ResetRelOptions: /* RESET (...) */ -! ATSimplePermissionsRelationOrIndex(rel, NULL); - /* This command never recurses */ - /* No command-specific prep needed */ - pass = AT_PASS_MISC; -*************** ATPrepCmd(List **wqueue, Relation rel, A -*** 2514,2520 **** - case AT_DisableRule: - case AT_AddInherit: /* INHERIT / NO INHERIT */ - case AT_DropInherit: -! ATSimplePermissions(rel, false); - /* These commands never recurse */ - /* No command-specific prep needed */ - pass = AT_PASS_MISC; ---- 2540,2546 ---- - case AT_DisableRule: - case AT_AddInherit: /* INHERIT / NO INHERIT */ - case AT_DropInherit: -! ATSimplePermissions(rel, NULL, false); - /* These commands never recurse */ - /* No command-specific prep needed */ - pass = AT_PASS_MISC; -*************** ATRewriteTables(List **wqueue) -*** 2860,2867 **** - /* - * The new relation is local to our transaction and we know - * nothing depends on it, so DROP_RESTRICT should be OK. - */ -! performDeletion(&object, DROP_RESTRICT); - /* performDeletion does CommandCounterIncrement at end */ - - /* ---- 2886,2894 ---- - /* - * The new relation is local to our transaction and we know - * nothing depends on it, so DROP_RESTRICT should be OK. -+ * SELinux does not apply any permission checks here. - */ -! performDeletionNoPerms(&object, DROP_RESTRICT); - /* performDeletion does CommandCounterIncrement at end */ - - /* -*************** ATRewriteTable(AlteredTableInfo *tab, Oi -*** 3086,3096 **** ---- 3113,3126 ---- - if (newrel) - { - Oid tupOid = InvalidOid; -+ Oid tupSecid = InvalidOid; - - /* Extract data from old tuple */ - heap_deform_tuple(tuple, oldTupDesc, values, isnull); - if (oldTupDesc->tdhasoid) - tupOid = HeapTupleGetOid(tuple); -+ if (HeapTupleHasSecid(tuple)) -+ tupSecid = HeapTupleGetSecid(tuple); - - /* Set dropped attributes to null in new tuple */ - foreach(lc, dropped_attrs) -*************** ATRewriteTable(AlteredTableInfo *tab, Oi -*** 3122,3127 **** ---- 3152,3160 ---- - /* Preserve OID, if any */ - if (newTupDesc->tdhasoid) - HeapTupleSetOid(tuple, tupOid); -+ /* Preserve SID, if any */ -+ if (HeapTupleHasSecid(tuple)) -+ HeapTupleSetSecid(tuple, tupSecid); - } - - /* Now check any constraints on the possibly-changed tuple */ -*************** ATGetQueueEntry(List **wqueue, Relation -*** 3223,3229 **** - * - Ensure that it is not a system table - */ - static void -! ATSimplePermissions(Relation rel, bool allowView) - { - if (rel->rd_rel->relkind != RELKIND_RELATION) - { ---- 3256,3262 ---- - * - Ensure that it is not a system table - */ - static void -! ATSimplePermissions(Relation rel, const char *colName, bool allowView) - { - if (rel->rd_rel->relkind != RELKIND_RELATION) - { -*************** ATSimplePermissions(Relation rel, bool a -*** 3247,3252 **** ---- 3280,3291 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(rel)); - -+ /* SELinux checks */ -+ if (!colName) -+ sepgsql_relation_alter(RelationGetRelid(rel), NULL, InvalidOid); -+ else -+ sepgsql_attribute_alter(RelationGetRelid(rel), colName); -+ - if (!allowSystemTableMods && IsSystemRelation(rel)) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -*************** ATSimplePermissions(Relation rel, bool a -*** 3262,3268 **** - * - Ensure that it is not a system table - */ - static void -! ATSimplePermissionsRelationOrIndex(Relation rel) - { - if (rel->rd_rel->relkind != RELKIND_RELATION && - rel->rd_rel->relkind != RELKIND_INDEX) ---- 3301,3307 ---- - * - Ensure that it is not a system table - */ - static void -! ATSimplePermissionsRelationOrIndex(Relation rel, const char *colName) - { - if (rel->rd_rel->relkind != RELKIND_RELATION && - rel->rd_rel->relkind != RELKIND_INDEX) -*************** ATSimplePermissionsRelationOrIndex(Relat -*** 3276,3281 **** ---- 3315,3326 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(rel)); - -+ /* SELinux checks */ -+ if (!colName) -+ sepgsql_relation_alter(RelationGetRelid(rel), NULL, InvalidOid); -+ else -+ sepgsql_attribute_alter(RelationGetRelid(rel), colName); -+ - if (!allowSystemTableMods && IsSystemRelation(rel)) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -*************** ATExecAddColumn(AlteredTableInfo *tab, R -*** 3519,3524 **** ---- 3564,3570 ---- - HeapTuple typeTuple; - Oid typeOid; - int32 typmod; -+ Oid attsecid; - Form_pg_type tform; - Expr *defval; - -*************** ATExecAddColumn(AlteredTableInfo *tab, R -*** 3556,3561 **** ---- 3602,3610 ---- - errmsg("child table \"%s\" has a conflicting \"%s\" column", - RelationGetRelationName(rel), colDef->colname))); - -+ /* SELinux checks db_column:{setattr} */ -+ sepgsql_attribute_alter(myrelid, colDef->colname); -+ - /* Bump the existing child att's inhcount */ - childatt->attinhcount++; - simple_heap_update(attrdesc, &tuple->t_self, tuple); -*************** ATExecAddColumn(AlteredTableInfo *tab, R -*** 3595,3600 **** ---- 3644,3652 ---- - errmsg("column \"%s\" of relation \"%s\" already exists", - colDef->colname, RelationGetRelationName(rel)))); - -+ /* SELinux checks db_column:{create} */ -+ attsecid = sepgsql_attribute_create(myrelid, colDef); -+ - /* Determine the new attribute's number */ - if (isOid) - newattnum = ObjectIdAttributeNumber; -*************** ATExecAddColumn(AlteredTableInfo *tab, R -*** 3637,3643 **** - - ReleaseSysCache(typeTuple); - -! InsertPgAttributeTuple(attrdesc, &attribute, NULL); - - heap_close(attrdesc, RowExclusiveLock); - ---- 3689,3695 ---- - - ReleaseSysCache(typeTuple); - -! InsertPgAttributeTuple(attrdesc, &attribute, NULL, attsecid); - - heap_close(attrdesc, RowExclusiveLock); - -*************** ATPrepSetStatistics(Relation rel, const -*** 4026,4031 **** ---- 4078,4085 ---- - if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(rel)); -+ /* SELinux checks */ -+ sepgsql_attribute_alter(RelationGetRelid(rel), colName); - } - - static void -*************** ATExecDropColumn(List **wqueue, Relation -*** 4181,4187 **** - - /* At top level, permission check was done in ATPrepCmd, else do it */ - if (recursing) -! ATSimplePermissions(rel, false); - - /* - * get the number of the attribute ---- 4235,4241 ---- - - /* At top level, permission check was done in ATPrepCmd, else do it */ - if (recursing) -! ATSimplePermissions(rel, NULL, false); - - /* - * get the number of the attribute -*************** ATAddCheckConstraint(List **wqueue, Alte -*** 4483,4489 **** - - /* At top level, permission check was done in ATPrepCmd, else do it */ - if (recursing) -! ATSimplePermissions(rel, false); - - /* - * Call AddRelationNewConstraints to do the work, making sure it works on ---- 4537,4543 ---- - - /* At top level, permission check was done in ATPrepCmd, else do it */ - if (recursing) -! ATSimplePermissions(rel, NULL, false); - - /* - * Call AddRelationNewConstraints to do the work, making sure it works on -*************** ATExecDropConstraint(Relation rel, const -*** 5385,5391 **** - - /* At top level, permission check was done in ATPrepCmd, else do it */ - if (recursing) -! ATSimplePermissions(rel, false); - - conrel = heap_open(ConstraintRelationId, RowExclusiveLock); - ---- 5439,5445 ---- - - /* At top level, permission check was done in ATPrepCmd, else do it */ - if (recursing) -! ATSimplePermissions(rel, NULL, false); - - conrel = heap_open(ConstraintRelationId, RowExclusiveLock); - -*************** ATExecChangeOwner(Oid relationOid, Oid n -*** 6319,6324 **** ---- 6373,6380 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - } -+ /* SELinux checks db_table:{setattr} */ -+ sepgsql_relation_alter(relationOid, NULL, InvalidOid); - } - - memset(repl_null, false, sizeof(repl_null)); -*************** ATExecAddInherit(Relation child_rel, Ran -*** 6923,6929 **** - * Must be owner of both parent and child -- child was checked by - * ATSimplePermissions call in ATPrepCmd - */ -! ATSimplePermissions(parent_rel, false); - - /* Permanent rels cannot inherit from temporary ones */ - if (parent_rel->rd_istemp && !child_rel->rd_istemp) ---- 6979,6985 ---- - * Must be owner of both parent and child -- child was checked by - * ATSimplePermissions call in ATPrepCmd - */ -! ATSimplePermissions(parent_rel, NULL, false); - - /* Permanent rels cannot inherit from temporary ones */ - if (parent_rel->rd_istemp && !child_rel->rd_istemp) -*************** AlterTableNamespace(RangeVar *relation, -*** 7581,7586 **** ---- 7637,7645 ---- - RelationGetRelationName(rel), - newschema))); - -+ /* SELinux checks */ -+ sepgsql_relation_alter(relid, NULL, nspOid); -+ - /* disallow renaming into or out of temp schemas */ - if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid)) - ereport(ERROR, -*************** AlterSeqNamespaces(Relation classRel, Re -*** 7773,7778 **** ---- 7832,7965 ---- - relation_close(depRel, AccessShareLock); - } - -+ /* -+ * ALTER TABLE/SEQUENCE name SECURITY_LABEL [=] newlabel -+ * ALTER TABLE/SEQUENCE name ALTER column SECURITY_LABEL [=] newlabel -+ */ -+ static void -+ ExecRelationSetSecLabel(Oid relid, DefElem *seclabel) -+ { -+ Relation rel; -+ HeapTuple oldtup; -+ HeapTuple newtup; -+ Oid secid; -+ bool replaces[Natts_pg_class]; -+ -+ rel = heap_open(RelationRelationId, RowExclusiveLock); -+ oldtup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(relid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(oldtup)) -+ elog(ERROR, "cache lookup failed for relation: %u", relid); -+ -+ memset(replaces, false, sizeof(replaces)); -+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), -+ NULL, NULL, replaces); -+ if (!HeapTupleHasSecid(newtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("Unable to set security label on \"%s\"", -+ get_rel_name(relid)))); -+ -+ ReleaseSysCache(oldtup); -+ -+ /* SELinux checks db_table:{setattr relabelfrom relabelto} */ -+ secid = sepgsql_relation_relabel(relid, seclabel); -+ -+ HeapTupleSetSecid(newtup, secid); -+ -+ simple_heap_update(rel, &newtup->t_self, newtup); -+ -+ CatalogUpdateIndexes(rel, newtup); -+ -+ heap_freetuple(newtup); -+ -+ heap_close(rel, RowExclusiveLock); -+ } -+ -+ static void -+ ExecAttributeSetSecLabel(Oid relid, const char *attname, DefElem *seclabel) -+ { -+ Relation rel; -+ HeapTuple oldtup; -+ HeapTuple newtup; -+ AttrNumber attnum; -+ Oid secid; -+ bool replaces[Natts_pg_attribute]; -+ -+ rel = heap_open(AttributeRelationId, RowExclusiveLock); -+ oldtup = SearchSysCacheAttName(relid, attname); -+ if (!HeapTupleIsValid(oldtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_UNDEFINED_COLUMN), -+ errmsg("column \"%s\" of relation \"%s\" does not exist", -+ attname, get_rel_name(relid)))); -+ attnum = ((Form_pg_attribute) GETSTRUCT(oldtup))->attnum; -+ -+ memset(replaces, false, sizeof(replaces)); -+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), -+ NULL, NULL, replaces); -+ if (!HeapTupleHasSecid(newtup)) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("Unable to set security context on \"%s.%s\"", -+ get_rel_name(relid), attname))); -+ -+ ReleaseSysCache(oldtup); -+ -+ /* SELinux checks db_column:{setattr relabelfrom relabelto} */ -+ secid = sepgsql_attribute_relabel(relid, attnum, seclabel); -+ -+ HeapTupleSetSecid(newtup, secid); -+ -+ simple_heap_update(rel, &newtup->t_self, newtup); -+ -+ CatalogUpdateIndexes(rel, newtup); -+ -+ heap_freetuple(newtup); -+ -+ heap_close(rel, RowExclusiveLock); -+ } -+ -+ void -+ AlterRelationSecLabel(RangeVar *relation, const char *attname, -+ ObjectType objtype, DefElem *seclabel) -+ { -+ Oid relid; -+ char relkind; -+ -+ /* Check relation type against type specified in the ALTER command */ -+ relid = RangeVarGetRelid(relation, false); -+ relkind = get_rel_relkind(relid); -+ -+ switch (objtype) -+ { -+ case OBJECT_TABLE: -+ case OBJECT_COLUMN: -+ if (relkind != RELKIND_RELATION) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not a table", get_rel_name(relid)))); -+ break; -+ -+ case OBJECT_SEQUENCE: -+ if (relkind != RELKIND_SEQUENCE) -+ ereport(ERROR, -+ (errcode(ERRCODE_WRONG_OBJECT_TYPE), -+ errmsg("\"%s\" is not a sequence", get_rel_name(relid)))); -+ break; -+ -+ default: -+ elog(ERROR, "unrecognized object type: %d", (int)objtype); -+ break; -+ } -+ -+ /* Exec set security label */ -+ if (objtype != OBJECT_COLUMN) -+ ExecRelationSetSecLabel(relid, seclabel); -+ else -+ ExecAttributeSetSecLabel(relid, attname, seclabel); -+ } - - /* - * This code supports -diff -Nrpc blob/src/backend/commands/trigger.c sepgsql/src/backend/commands/trigger.c -*** blob/src/backend/commands/trigger.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/commands/trigger.c Thu Mar 18 01:55:40 2010 -*************** -*** 33,38 **** ---- 33,39 ---- - #include "nodes/makefuncs.h" - #include "parser/parse_func.h" - #include "pgstat.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "tcop/utility.h" - #include "utils/acl.h" -*************** CreateTrigger(CreateTrigStmt *stmt, Oid -*** 182,187 **** ---- 183,192 ---- - NameListToString(stmt->funcname)))); - } - -+ /* SELinux checks */ -+ if (checkPermissions) -+ sepgsql_trigger_create(RelationGetRelid(rel), stmt->trigname, funcoid); -+ - /* - * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that - * references one of the built-in RI_FKey trigger functions, assume it is -*************** DropTrigger(Oid relid, const char *trign -*** 746,751 **** ---- 751,757 ---- - if (!pg_class_ownercheck(relid, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - get_rel_name(relid)); -+ sepgsql_trigger_drop(relid, trigname); - - object.classId = TriggerRelationId; - object.objectId = HeapTupleGetOid(tup); -*************** renametrig(Oid relid, -*** 862,867 **** ---- 868,876 ---- - */ - targetrel = heap_open(relid, AccessExclusiveLock); - -+ /* SELinux checks */ -+ sepgsql_trigger_alter(relid, oldname); -+ - /* - * Scan pg_trigger twice for existing triggers on relation. We do this in - * order to ensure a trigger does not exist with newname (The unique index -diff -Nrpc blob/src/backend/commands/tsearchcmds.c sepgsql/src/backend/commands/tsearchcmds.c -*** blob/src/backend/commands/tsearchcmds.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/tsearchcmds.c Thu Sep 17 23:44:07 2009 -*************** -*** 35,40 **** ---- 35,41 ---- - #include "miscadmin.h" - #include "nodes/makefuncs.h" - #include "parser/parse_func.h" -+ #include "security/sepgsql.h" - #include "tsearch/ts_cache.h" - #include "tsearch/ts_public.h" - #include "tsearch/ts_utils.h" -*************** DefineTSParser(List *names, List *parame -*** 171,176 **** ---- 172,178 ---- - NameData pname; - Oid prsOid; - Oid namespaceoid; -+ Oid secid; - - if (!superuser()) - ereport(ERROR, -*************** DefineTSParser(List *names, List *parame -*** 250,261 **** ---- 252,273 ---- - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("text search parser lextypes method is required"))); - -+ /* Permission checks */ -+ secid = sepgsql_ts_parser_create(prsname, namespaceoid, -+ DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1]), -+ DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1]), -+ DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1]), -+ DatumGetObjectId(values[Anum_pg_ts_parser_prsheadline - 1]), -+ DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1])); -+ - /* - * Looks good, insert - */ - prsRel = heap_open(TSParserRelationId, RowExclusiveLock); - - tup = heap_form_tuple(prsRel->rd_att, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, secid); - - prsOid = simple_heap_insert(prsRel, tup); - -*************** RenameTSParser(List *oldname, const char -*** 372,377 **** ---- 384,392 ---- - - prsId = TSParserGetPrsid(oldname, false); - -+ /* SELinux checks */ -+ sepgsql_ts_parser_alter(prsId, newname); -+ - tup = SearchSysCacheCopy(TSPARSEROID, - ObjectIdGetDatum(prsId), - 0, 0, 0); -*************** DefineTSDictionary(List *names, List *pa -*** 503,508 **** ---- 518,524 ---- - List *dictoptions = NIL; - Oid dictOid; - Oid namespaceoid; -+ Oid secid; - AclResult aclresult; - char *dictname; - -*************** DefineTSDictionary(List *names, List *pa -*** 515,520 **** ---- 531,539 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceoid)); - -+ /* SELinux check */ -+ secid = sepgsql_ts_dict_create(dictname, namespaceoid); -+ - /* - * loop over the definition list and extract the information we need. - */ -*************** DefineTSDictionary(List *names, List *pa -*** 563,568 **** ---- 582,589 ---- - dictRel = heap_open(TSDictionaryRelationId, RowExclusiveLock); - - tup = heap_form_tuple(dictRel->rd_att, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, secid); - - dictOid = simple_heap_insert(dictRel, tup); - -*************** RenameTSDictionary(List *oldname, const -*** 621,626 **** ---- 642,650 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* SELinux checks */ -+ sepgsql_ts_dict_alter(dictId, newname); -+ - namestrcpy(&(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname), newname); - simple_heap_update(rel, &tup->t_self, tup); - CatalogUpdateIndexes(rel, tup); -*************** AlterTSDictionary(AlterTSDictionaryStmt -*** 762,767 **** ---- 786,794 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY, - NameListToString(stmt->dictname)); - -+ /* SELinux checks */ -+ sepgsql_ts_dict_alter(dictId, NULL); -+ - /* deserialize the existing set of options */ - opt = SysCacheGetAttr(TSDICTOID, tup, - Anum_pg_ts_dict_dictinitoption, -*************** AlterTSDictionaryOwner(List *name, Oid n -*** 889,894 **** ---- 916,923 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - } -+ /* SELinux checks */ -+ sepgsql_ts_dict_alter(dictId, NULL); - - form->dictowner = newOwnerId; - -*************** DefineTSTemplate(List *names, List *para -*** 999,1004 **** ---- 1028,1034 ---- - NameData dname; - int i; - Oid dictOid; -+ Oid dictSecid; - Oid namespaceoid; - char *tmplname; - -*************** DefineTSTemplate(List *names, List *para -*** 1054,1059 **** ---- 1084,1094 ---- - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("text search template lexize method is required"))); - -+ /* SELinux checks */ -+ dictSecid = sepgsql_ts_template_create(tmplname, namespaceoid, -+ DatumGetObjectId(values[Anum_pg_ts_template_tmplinit - 1]), -+ DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1])); -+ - /* - * Looks good, insert - */ -*************** DefineTSTemplate(List *names, List *para -*** 1061,1066 **** ---- 1096,1103 ---- - tmplRel = heap_open(TSTemplateRelationId, RowExclusiveLock); - - tup = heap_form_tuple(tmplRel->rd_att, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, dictSecid); - - dictOid = simple_heap_insert(tmplRel, tup); - -*************** RenameTSTemplate(List *oldname, const ch -*** 1093,1098 **** ---- 1130,1138 ---- - - tmplId = TSTemplateGetTmplid(oldname, false); - -+ /* Permission checks */ -+ sepgsql_ts_template_alter(tmplId, newname); -+ - tup = SearchSysCacheCopy(TSTEMPLATEOID, - ObjectIdGetDatum(tmplId), - 0, 0, 0); -*************** DefineTSConfiguration(List *names, List -*** 1335,1340 **** ---- 1375,1381 ---- - Oid sourceOid = InvalidOid; - Oid prsOid = InvalidOid; - Oid cfgOid; -+ Oid cfgSecid; - ListCell *pl; - - /* Convert list of names to a name and namespace */ -*************** DefineTSConfiguration(List *names, List -*** 1399,1404 **** ---- 1440,1448 ---- - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("text search parser is required"))); - -+ /* SELinux checks */ -+ cfgSecid = sepgsql_ts_config_create(cfgname, namespaceoid); -+ - /* - * Looks good, build tuple and insert - */ -*************** DefineTSConfiguration(List *names, List -*** 1414,1419 **** ---- 1458,1465 ---- - cfgRel = heap_open(TSConfigRelationId, RowExclusiveLock); - - tup = heap_form_tuple(cfgRel->rd_att, values, nulls); -+ if (HeapTupleHasSecid(tup)) -+ HeapTupleSetSecid(tup, cfgSecid); - - cfgOid = simple_heap_insert(cfgRel, tup); - -*************** RenameTSConfiguration(List *oldname, con -*** 1519,1524 **** ---- 1565,1573 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - -+ /* permission checks */ -+ sepgsql_ts_config_alter(cfgId, newname); -+ - namestrcpy(&(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname), newname); - simple_heap_update(rel, &tup->t_self, tup); - CatalogUpdateIndexes(rel, tup); -*************** AlterTSConfigurationOwner(List *name, Oi -*** 1690,1695 **** ---- 1739,1746 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceOid)); - } -+ /* SELinux checks */ -+ sepgsql_ts_config_alter(cfgId, NULL); - - form->cfgowner = newOwnerId; - -*************** AlterTSConfiguration(AlterTSConfiguratio -*** 1727,1732 **** ---- 1778,1786 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, - NameListToString(stmt->cfgname)); - -+ /* SELinux checks */ -+ sepgsql_ts_config_alter(HeapTupleGetOid(tup), NULL); -+ - relMap = heap_open(TSConfigMapRelationId, RowExclusiveLock); - - /* Add or drop mappings */ -diff -Nrpc blob/src/backend/commands/typecmds.c sepgsql/src/backend/commands/typecmds.c -*** blob/src/backend/commands/typecmds.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/typecmds.c Thu Sep 17 22:10:19 2009 -*************** -*** 56,61 **** ---- 56,62 ---- - #include "parser/parse_expr.h" - #include "parser/parse_func.h" - #include "parser/parse_type.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -*************** AlterDomainDefault(List *names, Node *de -*** 1543,1548 **** ---- 1544,1550 ---- - - /* Check it's a domain and check user has permission for ALTER DOMAIN */ - checkDomainOwner(tup, typename); -+ sepgsql_type_alter(domainoid, NULL, InvalidOid); - - /* Setup new tuple */ - MemSet(new_record, (Datum) 0, sizeof(new_record)); -*************** AlterDomainNotNull(List *names, bool not -*** 1671,1676 **** ---- 1673,1679 ---- - - /* Check it's a domain and check user has permission for ALTER DOMAIN */ - checkDomainOwner(tup, typename); -+ sepgsql_type_alter(domainoid, NULL, InvalidOid); - - /* Is the domain already set to the desired constraint? */ - if (typTup->typnotnull == notNull) -*************** AlterDomainDropConstraint(List *names, c -*** 1772,1777 **** ---- 1775,1781 ---- - - /* Check it's a domain and check user has permission for ALTER DOMAIN */ - checkDomainOwner(tup, typename); -+ sepgsql_type_alter(domainoid, NULL, InvalidOid); - - /* Grab an appropriate lock on the pg_constraint relation */ - conrel = heap_open(ConstraintRelationId, RowExclusiveLock); -*************** AlterDomainAddConstraint(List *names, No -*** 1848,1853 **** ---- 1852,1858 ---- - - /* Check it's a domain and check user has permission for ALTER DOMAIN */ - checkDomainOwner(tup, typename); -+ sepgsql_type_alter(domainoid, NULL, InvalidOid); - - /* Check for unsupported constraint types */ - if (IsA(newConstraint, FkConstraint)) -*************** RenameType(List *names, const char *newT -*** 2470,2475 **** ---- 2475,2483 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, - format_type_be(typeOid)); - -+ /* SELinux check permission */ -+ sepgsql_type_alter(typeOid, newTypeName, InvalidOid); -+ - /* - * If it's a composite type, we need to check that it really is a - * free-standing composite type, and not a table's rowtype. We want people -*************** AlterTypeOwner(List *names, Oid newOwner -*** 2590,2595 **** ---- 2598,2605 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(typTup->typnamespace)); - } -+ /* SELinux checks permissions */ -+ sepgsql_type_alter(HeapTupleGetOid(tup), NULL, InvalidOid); - - /* - * If it's a composite type, invoke ATExecChangeOwner so that we fix -*************** AlterTypeNamespace(List *names, const ch -*** 2706,2711 **** ---- 2716,2724 ---- - errhint("You can alter type %s, which will alter the array type as well.", - format_type_be(elemOid)))); - -+ /* SELinux checks permissions */ -+ sepgsql_type_alter(typeOid, NULL, nspOid); -+ - /* and do the work */ - AlterTypeNamespaceInternal(typeOid, nspOid, false, true); - } -diff -Nrpc blob/src/backend/commands/vacuum.c sepgsql/src/backend/commands/vacuum.c -*** blob/src/backend/commands/vacuum.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/commands/vacuum.c Sun Dec 20 23:35:32 2009 -*************** -*** 32,37 **** ---- 32,38 ---- - #include "catalog/namespace.h" - #include "catalog/pg_database.h" - #include "catalog/pg_namespace.h" -+ #include "catalog/pg_security.h" - #include "catalog/storage.h" - #include "commands/dbcommands.h" - #include "commands/vacuum.h" -*************** vacuum_rel(Oid relid, VacuumStmt *vacstm -*** 1209,1214 **** ---- 1210,1218 ---- - /* all done with this class, but hold lock until commit */ - relation_close(onerel, NoLock); - -+ /* Also reclaim orphan security label */ -+ seclabelRelationReclaim(relid); -+ - /* - * Complete the transaction and free all temporary memory used. - */ -diff -Nrpc blob/src/backend/commands/view.c sepgsql/src/backend/commands/view.c -*** blob/src/backend/commands/view.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/commands/view.c Fri Sep 18 14:51:00 2009 -*************** -*** 28,33 **** ---- 28,34 ---- - #include "rewrite/rewriteDefine.h" - #include "rewrite/rewriteManip.h" - #include "rewrite/rewriteSupport.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -*************** DefineVirtualRelation(const RangeVar *re -*** 166,171 **** ---- 167,175 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(rel)); - -+ /* SELinux checks */ -+ sepgsql_view_replace(viewOid); -+ - /* Also check it's not in use already */ - CheckTableNotInUse(rel, "CREATE OR REPLACE VIEW"); - -diff -Nrpc blob/src/backend/executor/execJunk.c sepgsql/src/backend/executor/execJunk.c -*** blob/src/backend/executor/execJunk.c Sat Jan 3 13:01:35 2009 ---- sepgsql/src/backend/executor/execJunk.c Wed Jul 15 19:30:50 2009 -*************** -*** 60,66 **** - * An optional resultSlot can be passed as well. - */ - JunkFilter * -! ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot) - { - JunkFilter *junkfilter; - TupleDesc cleanTupType; ---- 60,67 ---- - * An optional resultSlot can be passed as well. - */ - JunkFilter * -! ExecInitJunkFilter(List *targetList, bool hasoid, bool hasseclabel, -! TupleTableSlot *slot) - { - JunkFilter *junkfilter; - TupleDesc cleanTupType; -*************** ExecInitJunkFilter(List *targetList, boo -*** 72,78 **** - /* - * Compute the tuple descriptor for the cleaned tuple. - */ -! cleanTupType = ExecCleanTypeFromTL(targetList, hasoid); - - /* - * Use the given slot, or make a new slot if we weren't given one. ---- 73,79 ---- - /* - * Compute the tuple descriptor for the cleaned tuple. - */ -! cleanTupType = ExecCleanTypeFromTL(targetList, hasoid, hasseclabel); - - /* - * Use the given slot, or make a new slot if we weren't given one. -diff -Nrpc blob/src/backend/executor/execMain.c sepgsql/src/backend/executor/execMain.c -*** blob/src/backend/executor/execMain.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/executor/execMain.c Tue Dec 15 17:30:25 2009 -*************** -*** 39,44 **** ---- 39,45 ---- - #include "access/xact.h" - #include "catalog/heap.h" - #include "catalog/namespace.h" -+ #include "catalog/pg_security.h" - #include "catalog/toasting.h" - #include "commands/tablespace.h" - #include "commands/trigger.h" -*************** -*** 50,55 **** ---- 51,57 ---- - #include "optimizer/clauses.h" - #include "parser/parse_clause.h" - #include "parser/parsetree.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/lmgr.h" - #include "storage/smgr.h" -*************** ExecCheckRTPerms(List *rangeTable) -*** 442,448 **** - - foreach(l, rangeTable) - { -! ExecCheckRTEPerms((RangeTblEntry *) lfirst(l)); - } - } - ---- 444,453 ---- - - foreach(l, rangeTable) - { -! RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); -! -! ExecCheckRTEPerms(rte); -! sepgsqlCheckRTEPerms(rte); - } - } - -*************** InitPlan(QueryDesc *queryDesc, int eflag -*** 901,916 **** - for (i = 0; i < as_nplans; i++) - { - PlanState *subplan = appendplans[i]; - JunkFilter *j; - - if (operation == CMD_UPDATE) -! ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc, -! subplan->plan->targetlist); - - j = ExecInitJunkFilter(subplan->plan->targetlist, -! resultRelInfo->ri_RelationDesc->rd_att->tdhasoid, -! ExecAllocTableSlot(estate->es_tupleTable)); -! - /* - * Since it must be UPDATE/DELETE, there had better be a - * "ctid" junk attribute in the tlist ... but ctid could ---- 906,921 ---- - for (i = 0; i < as_nplans; i++) - { - PlanState *subplan = appendplans[i]; -+ Relation resultRel = resultRelInfo->ri_RelationDesc; - JunkFilter *j; - - if (operation == CMD_UPDATE) -! ExecCheckPlanOutput(resultRel, subplan->plan->targetlist); - - j = ExecInitJunkFilter(subplan->plan->targetlist, -! RelationGetDescr(resultRel)->tdhasoid, -! RelationGetDescr(resultRel)->tdhassecid, -! ExecAllocTableSlot(estate->es_tupleTable)); - /* - * Since it must be UPDATE/DELETE, there had better be a - * "ctid" junk attribute in the tlist ... but ctid could -*************** InitPlan(QueryDesc *queryDesc, int eflag -*** 953,958 **** ---- 958,964 ---- - - j = ExecInitJunkFilter(planstate->plan->targetlist, - tupType->tdhasoid, -+ tupType->tdhassecid, - ExecAllocTableSlot(estate->es_tupleTable)); - estate->es_junkFilter = j; - if (estate->es_result_relation_info) -*************** InitPlan(QueryDesc *queryDesc, int eflag -*** 1023,1029 **** - * We assume all the sublists will generate the same output tupdesc. - */ - tupType = ExecTypeFromTL((List *) linitial(plannedstmt->returningLists), -! false); - - /* Set up a slot for the output of the RETURNING projection(s) */ - slot = ExecAllocTableSlot(estate->es_tupleTable); ---- 1029,1035 ---- - * We assume all the sublists will generate the same output tupdesc. - */ - tupType = ExecTypeFromTL((List *) linitial(plannedstmt->returningLists), -! false, false); - - /* Set up a slot for the output of the RETURNING projection(s) */ - slot = ExecAllocTableSlot(estate->es_tupleTable); -*************** ExecContextForcesOids(PlanState *plansta -*** 1346,1351 **** ---- 1352,1388 ---- - return false; - } - -+ /* -+ * ExecContextForcesSecids -+ * -+ * We need to ensure that result tuples have space for security identifier. -+ * if the security feature need to store it within the given relation. -+ */ -+ bool ExecContextForcesSecids(PlanState *planstate, bool *hassecid) -+ { -+ if (planstate->state->es_select_into) -+ { -+ *hassecid = securityTupleDescHasSecid(InvalidOid, -+ RELKIND_RELATION); -+ return true; -+ } -+ else -+ { -+ ResultRelInfo *ri = planstate->state->es_result_relation_info; -+ -+ if (ri && ri->ri_RelationDesc) -+ { -+ Oid relid = RelationGetRelid(ri->ri_RelationDesc); -+ char relkind = RelationGetForm(ri->ri_RelationDesc)->relkind; -+ -+ *hassecid = securityTupleDescHasSecid(relid, relkind); -+ -+ return true; -+ } -+ } -+ return false; -+ } -+ - /* ---------------------------------------------------------------- - * ExecEndPlan - * -*************** ExecEndPlan(PlanState *planstate, EState -*** 1426,1431 **** ---- 1463,1520 ---- - } - } - -+ /* -+ * fetchWritableSystemAttribute() fetches writable system column data -+ * using Junkfilter, and saves them at TupleTableSlot temporary. -+ * -+ * storeWritableSystemAttribute() copies these fetched data into -+ * header structure of HeapTuple. -+ */ -+ static void -+ fetchWritableSystemAttribute(JunkFilter *junkfilter, TupleTableSlot *slot, -+ Datum *tts_seclabel) -+ { -+ AttrNumber attno; -+ Datum datum; -+ bool isnull; -+ -+ /* for Security Label */ -+ attno = ExecFindJunkAttribute(junkfilter, SecurityAttributeName); -+ if (attno != InvalidAttrNumber) -+ { -+ datum = ExecGetJunkAttribute(slot, attno, &isnull); -+ if (isnull) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("Unable to set NULL on \"%s\"", -+ SecurityAttributeName))); -+ *tts_seclabel = datum; -+ } -+ } -+ -+ static void -+ storeWritableSystemAttribute(Relation rel, TupleTableSlot *slot, HeapTuple tuple) -+ { -+ Oid relid = RelationGetRelid(rel); -+ Oid secid; -+ -+ /* "security_label" */ -+ if (DatumGetPointer(slot->tts_seclabel) != NULL) -+ { -+ char *seclabel = TextDatumGetCString(slot->tts_seclabel); -+ -+ if (!HeapTupleHasSecid(tuple)) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("Unable to assign security label on \"%s\"", -+ RelationGetRelationName(rel)))); -+ secid = securityTransSecLabelIn(relid, seclabel); -+ HeapTupleSetSecid(tuple, secid); -+ } -+ else if (HeapTupleHasSecid(tuple)) -+ HeapTupleSetSecid(tuple, InvalidOid); -+ } -+ - /* ---------------------------------------------------------------- - * ExecutePlan - * -*************** ExecutePlan(EState *estate, -*** 1487,1492 **** ---- 1576,1583 ---- - */ - for (;;) - { -+ Datum tts_seclabel = PointerGetDatum(NULL); -+ - /* Reset the per-output-tuple exprcontext */ - ResetPerTupleExprContext(estate); - -*************** lnext: ; -*** 1631,1636 **** ---- 1722,1732 ---- - } - - /* -+ * extract writable system attribute -+ */ -+ fetchWritableSystemAttribute(junkfilter, slot, &tts_seclabel); -+ -+ /* - * extract the 'ctid' junk attribute. - */ - if (operation == CMD_UPDATE || operation == CMD_DELETE) -*************** lnext: ; -*** 1657,1662 **** ---- 1753,1759 ---- - if (operation != CMD_DELETE) - slot = ExecFilterJunk(junkfilter, slot); - } -+ slot->tts_seclabel = tts_seclabel; - - /* - * now that we have a tuple, do the appropriate thing with it.. either -*************** ExecInsert(TupleTableSlot *slot, -*** 1781,1786 **** ---- 1878,1885 ---- - if (resultRelationDesc->rd_rel->relhasoids) - HeapTupleSetOid(tuple, InvalidOid); - -+ storeWritableSystemAttribute(resultRelationDesc, slot, tuple); -+ - /* BEFORE ROW INSERT Triggers */ - if (resultRelInfo->ri_TrigDesc && - resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) -*************** ExecInsert(TupleTableSlot *slot, -*** 1811,1816 **** ---- 1910,1921 ---- - } - - /* -+ * SELinux assigns default security label, and -+ * it also checks db_tuple:{insert} permission -+ */ -+ sepgsqlHeapTupleInsert(resultRelationDesc, tuple, false); -+ -+ /* - * Check the constraints of the tuple - */ - if (resultRelationDesc->rd_att->constr) -*************** ExecUpdate(TupleTableSlot *slot, -*** 2018,2023 **** ---- 2123,2130 ---- - resultRelInfo = estate->es_result_relation_info; - resultRelationDesc = resultRelInfo->ri_RelationDesc; - -+ storeWritableSystemAttribute(resultRelationDesc, slot, tuple); -+ - /* BEFORE ROW UPDATE Triggers */ - if (resultRelInfo->ri_TrigDesc && - resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0) -*************** ExecUpdate(TupleTableSlot *slot, -*** 2048,2053 **** ---- 2155,2163 ---- - } - } - -+ /* SELinux checks db_tuple:{relabelfrom relabelto}, if needed */ -+ sepgsqlHeapTupleUpdate(resultRelationDesc, tupleid, tuple); -+ - /* - * Check the constraints of the tuple - * -*************** OpenIntoRel(QueryDesc *queryDesc) -*** 2843,2848 **** ---- 2953,2959 ---- - Oid namespaceId; - Oid tablespaceId; - Datum reloptions; -+ Oid *secLabels; - AclResult aclresult; - Oid intoRelationId; - TupleDesc tupdesc; -*************** OpenIntoRel(QueryDesc *queryDesc) -*** 2886,2891 **** ---- 2997,3010 ---- - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceId)); - -+ /* SELinux checks */ -+ secLabels = sepgsql_relation_create(intoName, -+ RELKIND_RELATION, -+ queryDesc->tupDesc, -+ namespaceId, -+ NULL, NIL, -+ true, true); -+ - /* - * Select tablespace to use. If not specified, use default tablespace - * (which may in turn default to database's default). -*************** OpenIntoRel(QueryDesc *queryDesc) -*** 2944,2950 **** - 0, - into->onCommit, - reloptions, -! allowSystemTableMods); - - FreeTupleDesc(tupdesc); - ---- 3063,3070 ---- - 0, - into->onCommit, - reloptions, -! allowSystemTableMods, -! secLabels); - - FreeTupleDesc(tupdesc); - -*************** intorel_receive(TupleTableSlot *slot, De -*** 3069,3074 **** ---- 3189,3198 ---- - if (myState->rel->rd_rel->relhasoids) - HeapTupleSetOid(tuple, InvalidOid); - -+ storeWritableSystemAttribute(myState->rel, slot, tuple); -+ /* SELinux checks db_tuple:{insert} */ -+ sepgsqlHeapTupleInsert(myState->rel, tuple, false); -+ - heap_insert(myState->rel, - tuple, - myState->estate->es_output_cid, -diff -Nrpc blob/src/backend/executor/execQual.c sepgsql/src/backend/executor/execQual.c -*** blob/src/backend/executor/execQual.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/executor/execQual.c Thu Mar 18 01:55:40 2010 -*************** -*** 48,53 **** ---- 48,54 ---- - #include "optimizer/planner.h" - #include "parser/parse_coerce.h" - #include "pgstat.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -*************** init_fcache(Oid foid, FuncExprState *fca -*** 1138,1143 **** ---- 1139,1145 ---- - aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid)); -+ sepgsql_proc_execute(foid); - - /* - * Safety check on nargs. Under normal circumstances this should never -*************** ExecEvalArrayCoerceExpr(ArrayCoerceExprS -*** 4133,4138 **** ---- 4135,4141 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(acoerce->elemfuncid)); -+ sepgsql_proc_execute(acoerce->elemfuncid); - - /* Set up the primary fmgr lookup information */ - fmgr_info_cxt(acoerce->elemfuncid, &(astate->elemfunc), -diff -Nrpc blob/src/backend/executor/execScan.c sepgsql/src/backend/executor/execScan.c -*** blob/src/backend/executor/execScan.c Thu Apr 9 00:13:21 2009 ---- sepgsql/src/backend/executor/execScan.c Wed Sep 9 13:14:37 2009 -*************** -*** 20,25 **** ---- 20,26 ---- - - #include "executor/executor.h" - #include "miscadmin.h" -+ #include "security/rowlevel.h" - #include "utils/memutils.h" - - -*************** ExecScan(ScanState *node, -*** 53,58 **** ---- 54,60 ---- - ProjectionInfo *projInfo; - ExprDoneCond isDone; - TupleTableSlot *resultSlot; -+ Scan *scan = (Scan *)node->ps.plan; - - /* - * Fetch data from node -*************** ExecScan(ScanState *node, -*** 64,70 **** - * If we have neither a qual to check nor a projection to do, just skip - * all the overhead and return the raw scan tuple. - */ -! if (!qual && !projInfo) - return (*accessMtd) (node); - - /* ---- 66,72 ---- - * If we have neither a qual to check nor a projection to do, just skip - * all the overhead and return the raw scan tuple. - */ -! if (!qual && !projInfo && !scan->rowlvPerms) - return (*accessMtd) (node); - - /* -*************** ExecScan(ScanState *node, -*** 128,136 **** - * when the qual is nil ... saves only a few cycles, but they add up - * ... - */ -! if (!qual || ExecQual(qual, econtext, false)) - { - /* - * Found a satisfactory scan tuple. - */ - if (projInfo) ---- 130,147 ---- - * when the qual is nil ... saves only a few cycles, but they add up - * ... - */ -! if (rowlvExecScanFilter(scan, node->ss_currentRelation, slot) -! && (!qual || ExecQual(qual, econtext, false))) - { - /* -+ * NOTE: On FK checks, the Row-level feature needs to raise -+ * an error after evaluation of all the given quals to avoid -+ * incorrect error reporting. We assume FK implementation -+ * does not use malicious functions as the quals. -+ */ -+ rowlvExecScanAbort(scan, node->ss_currentRelation, slot); -+ -+ /* - * Found a satisfactory scan tuple. - */ - if (projInfo) -*************** tlist_matches_tupdesc(PlanState *ps, Lis -*** 197,202 **** ---- 208,214 ---- - int numattrs = tupdesc->natts; - int attrno; - bool hasoid; -+ bool hassecid; - ListCell *tlist_item = list_head(tlist); - - /* Check the tlist attributes */ -*************** tlist_matches_tupdesc(PlanState *ps, Lis -*** 240,251 **** - return false; /* tlist too long */ - - /* -! * If the plan context requires a particular hasoid setting, then that has -! * to match, too. - */ - if (ExecContextForcesOids(ps, &hasoid) && - hasoid != tupdesc->tdhasoid) - return false; - - return true; - } ---- 252,267 ---- - return false; /* tlist too long */ - - /* -! * If the plan context requires a particular hasoid or hassecid setting, -! * then that has to match, too. - */ - if (ExecContextForcesOids(ps, &hasoid) && - hasoid != tupdesc->tdhasoid) - return false; - -+ if (ExecContextForcesSecids(ps, &hassecid) && -+ hassecid != tupdesc->tdhassecid) -+ return false; -+ - return true; - } -diff -Nrpc blob/src/backend/executor/execTuples.c sepgsql/src/backend/executor/execTuples.c -*** blob/src/backend/executor/execTuples.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/executor/execTuples.c Wed Sep 9 13:14:37 2009 -*************** -*** 100,106 **** - - - static TupleDesc ExecTypeFromTLInternal(List *targetList, -! bool hasoid, bool skipjunk); - - - /* ---------------------------------------------------------------- ---- 100,106 ---- - - - static TupleDesc ExecTypeFromTLInternal(List *targetList, -! bool hasoid, bool hasseclabel, bool skipjunk); - - - /* ---------------------------------------------------------------- -*************** ExecInitNullTupleSlot(EState *estate, Tu -*** 968,976 **** - * ---------------------------------------------------------------- - */ - TupleDesc -! ExecTypeFromTL(List *targetList, bool hasoid) - { -! return ExecTypeFromTLInternal(targetList, hasoid, false); - } - - /* ---------------------------------------------------------------- ---- 968,976 ---- - * ---------------------------------------------------------------- - */ - TupleDesc -! ExecTypeFromTL(List *targetList, bool hasoid, bool hassecid) - { -! return ExecTypeFromTLInternal(targetList, hasoid, hassecid, false); - } - - /* ---------------------------------------------------------------- -*************** ExecTypeFromTL(List *targetList, bool ha -*** 980,992 **** - * ---------------------------------------------------------------- - */ - TupleDesc -! ExecCleanTypeFromTL(List *targetList, bool hasoid) - { -! return ExecTypeFromTLInternal(targetList, hasoid, true); - } - - static TupleDesc -! ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk) - { - TupleDesc typeInfo; - ListCell *l; ---- 980,993 ---- - * ---------------------------------------------------------------- - */ - TupleDesc -! ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hassecid) - { -! return ExecTypeFromTLInternal(targetList, hasoid, hassecid, true); - } - - static TupleDesc -! ExecTypeFromTLInternal(List *targetList, bool hasoid, -! bool hassecid, bool skipjunk) - { - TupleDesc typeInfo; - ListCell *l; -*************** ExecTypeFromTLInternal(List *targetList, -*** 998,1003 **** ---- 999,1005 ---- - else - len = ExecTargetListLength(targetList); - typeInfo = CreateTemplateTupleDesc(len, hasoid); -+ typeInfo->tdhassecid = hassecid; - - foreach(l, targetList) - { -diff -Nrpc blob/src/backend/executor/execUtils.c sepgsql/src/backend/executor/execUtils.c -*** blob/src/backend/executor/execUtils.c Sun Sep 6 19:40:49 2009 ---- sepgsql/src/backend/executor/execUtils.c Wed Sep 9 13:14:37 2009 -*************** void -*** 512,517 **** ---- 512,518 ---- - ExecAssignResultTypeFromTL(PlanState *planstate) - { - bool hasoid; -+ bool hassecid; - TupleDesc tupDesc; - - if (ExecContextForcesOids(planstate, &hasoid)) -*************** ExecAssignResultTypeFromTL(PlanState *pl -*** 524,535 **** - hasoid = false; - } - - /* - * ExecTypeFromTL needs the parse-time representation of the tlist, not a - * list of ExprStates. This is good because some plan nodes don't bother - * to set up planstate->targetlist ... - */ -! tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid); - ExecAssignResultType(planstate, tupDesc); - } - ---- 525,539 ---- - hasoid = false; - } - -+ if (!ExecContextForcesSecids(planstate, &hassecid)) -+ hassecid = false; -+ - /* - * ExecTypeFromTL needs the parse-time representation of the tlist, not a - * list of ExprStates. This is good because some plan nodes don't bother - * to set up planstate->targetlist ... - */ -! tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid, hassecid); - ExecAssignResultType(planstate, tupDesc); - } - -diff -Nrpc blob/src/backend/executor/functions.c sepgsql/src/backend/executor/functions.c -*** blob/src/backend/executor/functions.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/executor/functions.c Thu Mar 18 01:55:40 2010 -*************** check_sql_fn_retval(Oid func_id, Oid ret -*** 1158,1164 **** - - /* Set up junk filter if needed */ - if (junkFilter) -! *junkFilter = ExecInitJunkFilter(tlist, false, NULL); - } - else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID) - { ---- 1158,1164 ---- - - /* Set up junk filter if needed */ - if (junkFilter) -! *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL); - } - else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID) - { -*************** check_sql_fn_retval(Oid func_id, Oid ret -*** 1197,1203 **** - } - /* Set up junk filter if needed */ - if (junkFilter) -! *junkFilter = ExecInitJunkFilter(tlist, false, NULL); - return false; /* NOT returning whole tuple */ - } - } ---- 1197,1203 ---- - } - /* Set up junk filter if needed */ - if (junkFilter) -! *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL); - return false; /* NOT returning whole tuple */ - } - } -*************** check_sql_fn_retval(Oid func_id, Oid ret -*** 1210,1216 **** - * what the caller expects will happen at runtime. - */ - if (junkFilter) -! *junkFilter = ExecInitJunkFilter(tlist, false, NULL); - return true; - } - Assert(tupdesc); ---- 1210,1216 ---- - * what the caller expects will happen at runtime. - */ - if (junkFilter) -! *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL); - return true; - } - Assert(tupdesc); -diff -Nrpc blob/src/backend/executor/nodeAgg.c sepgsql/src/backend/executor/nodeAgg.c -*** blob/src/backend/executor/nodeAgg.c Sun Sep 6 19:40:49 2009 ---- sepgsql/src/backend/executor/nodeAgg.c Thu Sep 17 17:04:16 2009 -*************** -*** 81,86 **** ---- 81,87 ---- - #include "parser/parse_agg.h" - #include "parser/parse_coerce.h" - #include "parser/parse_oper.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -*************** ExecInitAgg(Agg *node, EState *estate, i -*** 1431,1436 **** ---- 1432,1438 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(aggref->aggfnoid)); -+ sepgsql_proc_execute(aggref->aggfnoid); - - peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn; - peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn; -*************** ExecInitAgg(Agg *node, EState *estate, i -*** 1454,1459 **** ---- 1456,1462 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(transfn_oid)); -+ sepgsql_proc_execute(transfn_oid); - if (OidIsValid(finalfn_oid)) - { - aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner, -*************** ExecInitAgg(Agg *node, EState *estate, i -*** 1461,1466 **** ---- 1464,1470 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(finalfn_oid)); -+ sepgsql_proc_execute(finalfn_oid); - } - } - -diff -Nrpc blob/src/backend/executor/nodeMergejoin.c sepgsql/src/backend/executor/nodeMergejoin.c -*** blob/src/backend/executor/nodeMergejoin.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/executor/nodeMergejoin.c Thu Mar 18 01:55:40 2010 -*************** -*** 98,103 **** ---- 98,104 ---- - #include "executor/execdefs.h" - #include "executor/nodeMergejoin.h" - #include "miscadmin.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/lsyscache.h" - #include "utils/memutils.h" -*************** MJExamineQuals(List *mergeclauses, -*** 215,220 **** ---- 216,222 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(cmpproc)); -+ sepgsql_proc_execute(cmpproc); - - /* Set up the fmgr lookup information */ - fmgr_info(cmpproc, &(clause->cmpfinfo)); -diff -Nrpc blob/src/backend/executor/nodeSubplan.c sepgsql/src/backend/executor/nodeSubplan.c -*** blob/src/backend/executor/nodeSubplan.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/executor/nodeSubplan.c Wed Jul 15 19:30:50 2009 -*************** ExecInitSubPlan(SubPlan *subplan, PlanSt -*** 869,875 **** - * (hack alert!). The righthand expressions will be evaluated in our - * own innerecontext. - */ -! tupDesc = ExecTypeFromTL(leftptlist, false); - slot = ExecAllocTableSlot(tupTable); - ExecSetSlotDescriptor(slot, tupDesc); - sstate->projLeft = ExecBuildProjectionInfo(lefttlist, ---- 869,875 ---- - * (hack alert!). The righthand expressions will be evaluated in our - * own innerecontext. - */ -! tupDesc = ExecTypeFromTL(leftptlist, false, false); - slot = ExecAllocTableSlot(tupTable); - ExecSetSlotDescriptor(slot, tupDesc); - sstate->projLeft = ExecBuildProjectionInfo(lefttlist, -*************** ExecInitSubPlan(SubPlan *subplan, PlanSt -*** 877,883 **** - slot, - NULL); - -! tupDesc = ExecTypeFromTL(rightptlist, false); - slot = ExecAllocTableSlot(tupTable); - ExecSetSlotDescriptor(slot, tupDesc); - sstate->projRight = ExecBuildProjectionInfo(righttlist, ---- 877,883 ---- - slot, - NULL); - -! tupDesc = ExecTypeFromTL(rightptlist, false, false); - slot = ExecAllocTableSlot(tupTable); - ExecSetSlotDescriptor(slot, tupDesc); - sstate->projRight = ExecBuildProjectionInfo(righttlist, -diff -Nrpc blob/src/backend/executor/nodeWindowAgg.c sepgsql/src/backend/executor/nodeWindowAgg.c -*** blob/src/backend/executor/nodeWindowAgg.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/executor/nodeWindowAgg.c Thu Mar 18 01:55:40 2010 -*************** -*** 43,48 **** ---- 43,49 ---- - #include "optimizer/clauses.h" - #include "parser/parse_agg.h" - #include "parser/parse_coerce.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/datum.h" -*************** ExecInitWindowAgg(WindowAgg *node, EStat -*** 1224,1229 **** ---- 1225,1231 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(wfunc->winfnoid)); -+ sepgsql_proc_execute(wfunc->winfnoid); - - /* Fill in the perfuncstate data */ - perfuncstate->wfuncstate = wfuncstate; -*************** initialize_peragg(WindowAggState *winsta -*** 1418,1423 **** ---- 1420,1426 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(transfn_oid)); -+ sepgsql_proc_execute(transfn_oid); - if (OidIsValid(finalfn_oid)) - { - aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner, -*************** initialize_peragg(WindowAggState *winsta -*** 1425,1430 **** ---- 1428,1434 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(finalfn_oid)); -+ sepgsql_proc_execute(finalfn_oid); - } - } - -diff -Nrpc blob/src/backend/executor/spi.c sepgsql/src/backend/executor/spi.c -*** blob/src/backend/executor/spi.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/executor/spi.c Tue Dec 15 17:30:25 2009 -*************** SPI_modifytuple(Relation rel, HeapTuple -*** 705,710 **** ---- 705,712 ---- - mtuple->t_tableOid = tuple->t_tableOid; - if (rel->rd_att->tdhasoid) - HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple)); -+ if (HeapTupleHasSecid(mtuple)) -+ HeapTupleSetSecid(mtuple, HeapTupleGetSecid(tuple)); - } - else - { -diff -Nrpc blob/src/backend/libpq/be-fsstubs.c sepgsql/src/backend/libpq/be-fsstubs.c -*** blob/src/backend/libpq/be-fsstubs.c Fri Dec 18 09:40:55 2009 ---- sepgsql/src/backend/libpq/be-fsstubs.c Fri Dec 18 10:27:56 2009 -*************** -*** 46,51 **** ---- 46,52 ---- - #include "libpq/be-fsstubs.h" - #include "libpq/libpq-fs.h" - #include "miscadmin.h" -+ #include "security/sepgsql.h" - #include "storage/fd.h" - #include "storage/large_object.h" - #include "utils/acl.h" -*************** lo_read(int fd, char *buf, int len) -*** 173,178 **** ---- 174,182 ---- - errmsg("permission denied for large object %u", - cookies[fd]->id))); - -+ /* SELinux db_blob:{read} checks */ -+ sepgsql_largeobject_read(cookies[fd]->id, cookies[fd]->snapshot); -+ - status = inv_read(cookies[fd], buf, len); - - return status; -*************** lo_write(int fd, const char *buf, int le -*** 205,210 **** ---- 209,217 ---- - errmsg("permission denied for large object %u", - cookies[fd]->id))); - -+ /* SELinux db_blob:{write} */ -+ sepgsql_largeobject_write(cookies[fd]->id, cookies[fd]->snapshot); -+ - status = inv_write(cookies[fd], buf, len); - - return status; -*************** Datum -*** 233,238 **** ---- 240,249 ---- - lo_creat(PG_FUNCTION_ARGS) - { - Oid lobjId; -+ Oid secid; -+ -+ /* SELinux: db_blob:{create} */ -+ secid = sepgsql_largeobject_create(InvalidOid, NULL); - - /* - * We don't actually need to store into fscxt, but create it anyway to -*************** lo_creat(PG_FUNCTION_ARGS) -*** 240,246 **** - */ - CreateFSContext(); - -! lobjId = inv_create(InvalidOid); - - PG_RETURN_OID(lobjId); - } ---- 251,257 ---- - */ - CreateFSContext(); - -! lobjId = inv_create(InvalidOid, secid); - - PG_RETURN_OID(lobjId); - } -*************** Datum -*** 249,254 **** ---- 260,269 ---- - lo_create(PG_FUNCTION_ARGS) - { - Oid lobjId = PG_GETARG_OID(0); -+ Oid secid; -+ -+ /* SELinux: db_blob:{create} */ -+ secid = sepgsql_largeobject_create(lobjId, NULL); - - /* - * We don't actually need to store into fscxt, but create it anyway to -*************** lo_create(PG_FUNCTION_ARGS) -*** 256,262 **** - */ - CreateFSContext(); - -! lobjId = inv_create(lobjId); - - PG_RETURN_OID(lobjId); - } ---- 271,277 ---- - */ - CreateFSContext(); - -! lobjId = inv_create(lobjId, secid); - - PG_RETURN_OID(lobjId); - } -*************** lo_unlink(PG_FUNCTION_ARGS) -*** 286,291 **** ---- 301,309 ---- - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be owner of large object %u", lobjId))); - -+ /* SELinux: db_blob:{drop} */ -+ sepgsql_largeobject_drop(lobjId); -+ - /* - * If there are any open LO FDs referencing that ID, close 'em. - */ -*************** lo_import_internal(text *filename, Oid l -*** 381,389 **** - int nbytes, - tmp; - char buf[BUFSIZE]; -! char fnamebuf[MAXPGPATH]; - LargeObjectDesc *lobj; - Oid oid; - - #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS - if (!superuser()) ---- 399,408 ---- - int nbytes, - tmp; - char buf[BUFSIZE]; -! char *fnamebuf = text_to_cstring(filename); - LargeObjectDesc *lobj; - Oid oid; -+ Oid secid; - - #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS - if (!superuser()) -*************** lo_import_internal(text *filename, Oid l -*** 392,404 **** - errmsg("must be superuser to use server-side lo_import()"), - errhint("Anyone can use the client-side lo_import() provided by libpq."))); - #endif - - CreateFSContext(); - - /* - * open the file to be read in - */ -- text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); - fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666); - if (fd < 0) - ereport(ERROR, ---- 411,424 ---- - errmsg("must be superuser to use server-side lo_import()"), - errhint("Anyone can use the client-side lo_import() provided by libpq."))); - #endif -+ /* SELinux: db_blob:{create import} */ -+ secid = sepgsql_largeobject_import(lobjOid, fnamebuf); - - CreateFSContext(); - - /* - * open the file to be read in - */ - fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666); - if (fd < 0) - ereport(ERROR, -*************** lo_import_internal(text *filename, Oid l -*** 409,415 **** - /* - * create an inversion object - */ -! oid = inv_create(lobjOid); - - /* - * read in from the filesystem and write to the inversion object ---- 429,435 ---- - /* - * create an inversion object - */ -! oid = inv_create(lobjOid, secid); - - /* - * read in from the filesystem and write to the inversion object -*************** lo_export(PG_FUNCTION_ARGS) -*** 447,453 **** - int nbytes, - tmp; - char buf[BUFSIZE]; -! char fnamebuf[MAXPGPATH]; - LargeObjectDesc *lobj; - mode_t oumask; - ---- 467,473 ---- - int nbytes, - tmp; - char buf[BUFSIZE]; -! char *fnamebuf = text_to_cstring(filename); - LargeObjectDesc *lobj; - mode_t oumask; - -*************** lo_export(PG_FUNCTION_ARGS) -*** 458,463 **** ---- 478,485 ---- - errmsg("must be superuser to use server-side lo_export()"), - errhint("Anyone can use the client-side lo_export() provided by libpq."))); - #endif -+ /* SELinux: db_blob:{read export} */ -+ sepgsql_largeobject_export(lobjId, fnamebuf); - - CreateFSContext(); - -*************** lo_truncate(PG_FUNCTION_ARGS) -*** 528,533 **** ---- 550,558 ---- - errmsg("permission denied for large object %u", - cookies[fd]->id))); - -+ /* SELinux: db_blob:{write} */ -+ sepgsql_largeobject_write(cookies[fd]->id, cookies[fd]->snapshot); -+ - inv_truncate(cookies[fd], len); - - PG_RETURN_INT32(0); -diff -Nrpc blob/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfuncs.c -*** blob/src/backend/nodes/copyfuncs.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/nodes/copyfuncs.c Tue Dec 15 17:30:25 2009 -*************** CopyScanFields(Scan *from, Scan *newnode -*** 259,264 **** ---- 259,265 ---- - CopyPlanFields((Plan *) from, (Plan *) newnode); - - COPY_SCALAR_FIELD(scanrelid); -+ COPY_SCALAR_FIELD(rowlvPerms); - } - - /* -*************** _copyColumnDef(ColumnDef *from) -*** 2075,2080 **** ---- 2076,2082 ---- - COPY_NODE_FIELD(raw_default); - COPY_NODE_FIELD(cooked_default); - COPY_NODE_FIELD(constraints); -+ COPY_NODE_FIELD(secLabel); - - return newnode; - } -*************** _copyCreateStmt(CreateStmt *from) -*** 2414,2419 **** ---- 2416,2422 ---- - COPY_NODE_FIELD(options); - COPY_SCALAR_FIELD(oncommit); - COPY_STRING_FIELD(tablespacename); -+ COPY_NODE_FIELD(secLabel); - - return newnode; - } -*************** _copyAlterOwnerStmt(AlterOwnerStmt *from -*** 2638,2643 **** ---- 2641,2661 ---- - return newnode; - } - -+ static AlterSecLabelStmt * -+ _copyAlterSecLabelStmt(AlterSecLabelStmt *from) -+ { -+ AlterSecLabelStmt *newnode = makeNode(AlterSecLabelStmt); -+ -+ COPY_SCALAR_FIELD(objectType); -+ COPY_NODE_FIELD(relation); -+ COPY_NODE_FIELD(object); -+ COPY_NODE_FIELD(objarg); -+ COPY_STRING_FIELD(subname); -+ COPY_NODE_FIELD(secLabel); -+ -+ return newnode; -+ } -+ - static RuleStmt * - _copyRuleStmt(RuleStmt *from) - { -*************** _copyCreateSeqStmt(CreateSeqStmt *from) -*** 2887,2892 **** ---- 2905,2911 ---- - - COPY_NODE_FIELD(sequence); - COPY_NODE_FIELD(options); -+ COPY_NODE_FIELD(secLabel); - - return newnode; - } -*************** copyObject(void *from) -*** 3819,3824 **** ---- 3838,3846 ---- - case T_AlterOwnerStmt: - retval = _copyAlterOwnerStmt(from); - break; -+ case T_AlterSecLabelStmt: -+ retval = _copyAlterSecLabelStmt(from); -+ break; - case T_RuleStmt: - retval = _copyRuleStmt(from); - break; -diff -Nrpc blob/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalfuncs.c -*** blob/src/backend/nodes/equalfuncs.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/nodes/equalfuncs.c Tue Dec 15 17:30:25 2009 -*************** _equalCreateStmt(CreateStmt *a, CreateSt -*** 1078,1083 **** ---- 1078,1084 ---- - COMPARE_NODE_FIELD(options); - COMPARE_SCALAR_FIELD(oncommit); - COMPARE_STRING_FIELD(tablespacename); -+ COMPARE_NODE_FIELD(secLabel); - - return true; - } -*************** _equalAlterOwnerStmt(AlterOwnerStmt *a, -*** 1271,1276 **** ---- 1272,1290 ---- - } - - static bool -+ _equalAlterSecLabelStmt(AlterSecLabelStmt *a, AlterSecLabelStmt *b) -+ { -+ COMPARE_SCALAR_FIELD(objectType); -+ COMPARE_NODE_FIELD(relation); -+ COMPARE_NODE_FIELD(object); -+ COMPARE_NODE_FIELD(objarg); -+ COMPARE_STRING_FIELD(subname); -+ COMPARE_NODE_FIELD(secLabel); -+ -+ return true; -+ } -+ -+ static bool - _equalRuleStmt(RuleStmt *a, RuleStmt *b) - { - COMPARE_NODE_FIELD(relation); -*************** _equalCreateSeqStmt(CreateSeqStmt *a, Cr -*** 1477,1482 **** ---- 1491,1497 ---- - { - COMPARE_NODE_FIELD(sequence); - COMPARE_NODE_FIELD(options); -+ COMPARE_NODE_FIELD(secLabel); - - return true; - } -*************** _equalColumnDef(ColumnDef *a, ColumnDef -*** 2054,2059 **** ---- 2069,2075 ---- - COMPARE_NODE_FIELD(raw_default); - COMPARE_NODE_FIELD(cooked_default); - COMPARE_NODE_FIELD(constraints); -+ COMPARE_NODE_FIELD(secLabel); - - return true; - } -*************** equal(void *a, void *b) -*** 2596,2601 **** ---- 2612,2620 ---- - case T_AlterOwnerStmt: - retval = _equalAlterOwnerStmt(a, b); - break; -+ case T_AlterSecLabelStmt: -+ retval = _equalAlterSecLabelStmt(a, b); -+ break; - case T_RuleStmt: - retval = _equalRuleStmt(a, b); - break; -diff -Nrpc blob/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs.c -*** blob/src/backend/nodes/outfuncs.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/nodes/outfuncs.c Tue Dec 15 17:30:25 2009 -*************** _outScanInfo(StringInfo str, Scan *node) -*** 285,290 **** ---- 285,291 ---- - _outPlanInfo(str, (Plan *) node); - - WRITE_UINT_FIELD(scanrelid); -+ WRITE_UINT_FIELD(rowlvPerms); - } - - /* -*************** _outRelOptInfo(StringInfo str, RelOptInf -*** 1534,1539 **** ---- 1535,1541 ---- - WRITE_BOOL_FIELD(has_eclass_joins); - WRITE_BITMAPSET_FIELD(index_outer_relids); - WRITE_NODE_FIELD(index_inner_paths); -+ WRITE_UINT_FIELD(rowlvPerms); - } - - static void -*************** _outCreateStmt(StringInfo str, CreateStm -*** 1717,1722 **** ---- 1719,1725 ---- - WRITE_NODE_FIELD(options); - WRITE_ENUM_FIELD(oncommit, OnCommitAction); - WRITE_STRING_FIELD(tablespacename); -+ WRITE_NODE_FIELD(secLabel); - } - - static void -*************** _outColumnDef(StringInfo str, ColumnDef -*** 1839,1844 **** ---- 1842,1848 ---- - WRITE_NODE_FIELD(raw_default); - WRITE_NODE_FIELD(cooked_default); - WRITE_NODE_FIELD(constraints); -+ WRITE_NODE_FIELD(secLabel); - } - - static void -diff -Nrpc blob/src/backend/optimizer/plan/createplan.c sepgsql/src/backend/optimizer/plan/createplan.c -*** blob/src/backend/optimizer/plan/createplan.c Sun Sep 6 19:40:49 2009 ---- sepgsql/src/backend/optimizer/plan/createplan.c Sun Sep 6 19:53:10 2009 -*************** create_scan_plan(PlannerInfo *root, Path -*** 305,310 **** ---- 305,313 ---- - break; - } - -+ /* Copy of row-level permissions to Scan node */ -+ ((Scan *)plan)->rowlvPerms = rel->rowlvPerms; -+ - /* - * If there are any pseudoconstant clauses attached to this node, insert a - * gating Result node that evaluates the pseudoconstants as one-time -diff -Nrpc blob/src/backend/optimizer/util/clauses.c sepgsql/src/backend/optimizer/util/clauses.c -*** blob/src/backend/optimizer/util/clauses.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/optimizer/util/clauses.c Thu Mar 18 01:55:40 2010 -*************** -*** 38,43 **** ---- 38,44 ---- - #include "parser/parse_coerce.h" - #include "parser/parse_func.h" - #include "rewrite/rewriteManip.h" -+ #include "security/sepgsql.h" - #include "tcop/tcopprot.h" - #include "utils/acl.h" - #include "utils/builtins.h" -*************** inline_function(Oid funcid, Oid result_t -*** 3503,3508 **** ---- 3504,3510 ---- - funcform->prosecdef || - funcform->proretset || - !heap_attisnull(func_tuple, Anum_pg_proc_proconfig) || -+ !sepgsql_proc_hint_inlined(func_tuple) || - funcform->pronargs != list_length(args)) - return NULL; - -*************** inline_set_returning_function(PlannerInf -*** 3974,3979 **** ---- 3976,3982 ---- - funcform->prosecdef || - !funcform->proretset || - !heap_attisnull(func_tuple, Anum_pg_proc_proconfig) || -+ !sepgsql_proc_hint_inlined(func_tuple) || - funcform->pronargs != list_length(fexpr->args)) - { - ReleaseSysCache(func_tuple); -diff -Nrpc blob/src/backend/optimizer/util/relnode.c sepgsql/src/backend/optimizer/util/relnode.c -*** blob/src/backend/optimizer/util/relnode.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/optimizer/util/relnode.c Wed Jul 15 19:39:56 2009 -*************** -*** 21,26 **** ---- 21,27 ---- - #include "optimizer/plancat.h" - #include "optimizer/restrictinfo.h" - #include "parser/parsetree.h" -+ #include "security/rowlevel.h" - #include "utils/hsearch.h" - - -*************** build_simple_rel(PlannerInfo *root, int -*** 91,96 **** ---- 92,98 ---- - rel->has_eclass_joins = false; - rel->index_outer_relids = NULL; - rel->index_inner_paths = NIL; -+ rel->rowlvPerms = rowlvSetupPermissions(rte); - - /* Check type of rtable entry */ - switch (rte->rtekind) -diff -Nrpc blob/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze.c -*** blob/src/backend/parser/analyze.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/parser/analyze.c Thu Mar 18 01:55:40 2010 -*************** -*** 25,30 **** ---- 25,31 ---- - #include "postgres.h" - - #include "access/sysattr.h" -+ #include "catalog/heap.h" - #include "catalog/pg_type.h" - #include "nodes/makefuncs.h" - #include "nodes/nodeFuncs.h" -*************** transformInsertStmt(ParseState *pstate, -*** 660,666 **** - tle = makeTargetEntry(expr, - attr_num, - col->name, -! false); - qry->targetList = lappend(qry->targetList, tle); - - rte->modifiedCols = bms_add_member(rte->modifiedCols, ---- 661,667 ---- - tle = makeTargetEntry(expr, - attr_num, - col->name, -! attr_num < 0 ? true : false); - qry->targetList = lappend(qry->targetList, tle); - - rte->modifiedCols = bms_add_member(rte->modifiedCols, -*************** transformInsertRow(ParseState *pstate, L -*** 775,780 **** ---- 776,823 ---- - return result; - } - -+ static void -+ transformSelectIntoSystemColumn(ParseState *pstate, Query *qry) -+ { -+ ListCell *l; -+ uint32 system_attrs = 0; -+ bool relhasoids -+ = interpretOidsOption(qry->intoClause->options); -+ -+ foreach (l, qry->targetList) -+ { -+ Form_pg_attribute attr; -+ TargetEntry *tle = lfirst(l); -+ -+ if (tle->resjunk) -+ continue; -+ -+ attr = SystemAttributeByName(tle->resname, relhasoids); -+ if (attr && SystemAttributeIsWritable(attr->attnum)) -+ { -+ uint32 mask = (1<<(-attr->attnum)); -+ -+ /* duplication checks */ -+ if (system_attrs & mask) -+ continue; -+ system_attrs |= mask; -+ -+ if (exprType((Node *) tle->expr) != attr->atttypid) -+ { -+ tle->expr = -+ (Expr *) coerce_to_target_type(pstate, -+ (Node *) tle->expr, -+ exprType((Node *) tle->expr), -+ attr->atttypid, -+ attr->atttypmod, -+ COERCION_IMPLICIT, -+ COERCE_IMPLICIT_CAST, -+ -1); -+ } -+ tle->resjunk = true; -+ } -+ } -+ } - - /* - * transformSelectStmt - -*************** transformSelectStmt(ParseState *pstate, -*** 879,884 **** ---- 922,928 ---- - if (stmt->intoClause) - { - qry->intoClause = stmt->intoClause; -+ transformSelectIntoSystemColumn(pstate, qry); - if (stmt->intoClause->colNames) - applyColumnNames(qry->targetList, stmt->intoClause->colNames); - } -diff -Nrpc blob/src/backend/parser/gram.y sepgsql/src/backend/parser/gram.y -*** blob/src/backend/parser/gram.y Fri Dec 18 09:40:55 2009 ---- sepgsql/src/backend/parser/gram.y Thu Dec 24 21:59:25 2009 -*************** -*** 58,63 **** ---- 58,64 ---- - #include "nodes/makefuncs.h" - #include "nodes/nodeFuncs.h" - #include "parser/gramparse.h" -+ #include "security/sepgsql.h" - #include "storage/lmgr.h" - #include "utils/date.h" - #include "utils/datetime.h" -*************** static TypeName *TableFuncTypeName(List -*** 184,190 **** - %type stmt schema_stmt - AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterFdwStmt - AlterForeignServerStmt AlterGroupStmt -! AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt - AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt - AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt - ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt ---- 185,191 ---- - %type stmt schema_stmt - AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterFdwStmt - AlterForeignServerStmt AlterGroupStmt -! AlterObjectSchemaStmt AlterOwnerStmt AlterSecLabelStmt AlterSeqStmt AlterTableStmt - AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt - AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt - ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt -*************** static TypeName *TableFuncTypeName(List -*** 402,407 **** ---- 403,412 ---- - %type OptTableSpace OptConsTableSpace OptTableSpaceOwner - %type opt_check_option - -+ %type OptSecLabel SecLabelItem SecLabelToItem -+ %type OptTableSecLabel TableSecLabelList -+ %type TableSecLabelItem -+ - %type xml_attribute_el - %type xml_attribute_list xml_attributes - %type xml_root_version opt_xml_root_standalone -*************** static TypeName *TableFuncTypeName(List -*** 437,443 **** - CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE - CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT - COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS -! CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB - CREATEROLE CREATEUSER CROSS CSV CURRENT_P - CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA - CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE ---- 442,448 ---- - CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE - CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT - COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS -! CONTENT_P CONTEXT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB - CREATEROLE CREATEUSER CROSS CSV CURRENT_P - CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA - CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE -*************** stmt : -*** 608,613 **** ---- 613,619 ---- - | AlterGroupStmt - | AlterObjectSchemaStmt - | AlterOwnerStmt -+ | AlterSecLabelStmt - | AlterSeqStmt - | AlterTableStmt - | AlterRoleSetStmt -*************** DropGroupStmt: -*** 1042,1048 **** - *****************************************************************************/ - - CreateSchemaStmt: -! CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList - { - CreateSchemaStmt *n = makeNode(CreateSchemaStmt); - /* One can omit the schema name or the authorization id. */ ---- 1048,1054 ---- - *****************************************************************************/ - - CreateSchemaStmt: -! CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSecLabel OptSchemaEltList - { - CreateSchemaStmt *n = makeNode(CreateSchemaStmt); - /* One can omit the schema name or the authorization id. */ -*************** CreateSchemaStmt: -*** 1051,1066 **** - else - n->schemaname = $5; - n->authid = $5; -! n->schemaElts = $6; - $$ = (Node *)n; - } -! | CREATE SCHEMA ColId OptSchemaEltList - { - CreateSchemaStmt *n = makeNode(CreateSchemaStmt); - /* ...but not both */ - n->schemaname = $3; - n->authid = NULL; -! n->schemaElts = $4; - $$ = (Node *)n; - } - ; ---- 1057,1074 ---- - else - n->schemaname = $5; - n->authid = $5; -! n->secLabel = $6; -! n->schemaElts = $7; - $$ = (Node *)n; - } -! | CREATE SCHEMA ColId OptSecLabel OptSchemaEltList - { - CreateSchemaStmt *n = makeNode(CreateSchemaStmt); - /* ...but not both */ - n->schemaname = $3; - n->authid = NULL; -! n->secLabel = $4; -! n->schemaElts = $5; - $$ = (Node *)n; - } - ; -*************** opt_using: -*** 2037,2043 **** - *****************************************************************************/ - - CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' -! OptInherit OptWith OnCommitOption OptTableSpace - { - CreateStmt *n = makeNode(CreateStmt); - $4->istemp = $2; ---- 2045,2051 ---- - *****************************************************************************/ - - CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' -! OptInherit OptWith OnCommitOption OptTableSpace OptTableSecLabel - { - CreateStmt *n = makeNode(CreateStmt); - $4->istemp = $2; -*************** CreateStmt: CREATE OptTemp TABLE qualifi -*** 2048,2057 **** - n->options = $9; - n->oncommit = $10; - n->tablespacename = $11; - $$ = (Node *)n; - } - | CREATE OptTemp TABLE qualified_name OF qualified_name -! '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace - { - /* SQL99 CREATE TABLE OF (cols) seems to be satisfied - * by our inheritance capabilities. Let's try it... ---- 2056,2066 ---- - n->options = $9; - n->oncommit = $10; - n->tablespacename = $11; -+ n->secLabel = $12; - $$ = (Node *)n; - } - | CREATE OptTemp TABLE qualified_name OF qualified_name -! '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace OptTableSecLabel - { - /* SQL99 CREATE TABLE OF (cols) seems to be satisfied - * by our inheritance capabilities. Let's try it... -*************** CreateStmt: CREATE OptTemp TABLE qualifi -*** 2065,2070 **** ---- 2074,2080 ---- - n->options = $10; - n->oncommit = $11; - n->tablespacename = $12; -+ n->secLabel = $13; - $$ = (Node *)n; - } - ; -*************** columnDef: ColId Typename ColQualList -*** 2114,2119 **** ---- 2124,2130 ---- - n->typename = $2; - n->constraints = $3; - n->is_local = true; -+ n->secLabel = NULL; - $$ = (Node *)n; - } - ; -*************** opt_with_data: -*** 2585,2596 **** - *****************************************************************************/ - - CreateSeqStmt: -! CREATE OptTemp SEQUENCE qualified_name OptSeqOptList - { - CreateSeqStmt *n = makeNode(CreateSeqStmt); - $4->istemp = $2; - n->sequence = $4; - n->options = $5; - $$ = (Node *)n; - } - ; ---- 2596,2608 ---- - *****************************************************************************/ - - CreateSeqStmt: -! CREATE OptTemp SEQUENCE qualified_name OptSeqOptList OptSecLabel - { - CreateSeqStmt *n = makeNode(CreateSeqStmt); - $4->istemp = $2; - n->sequence = $4; - n->options = $5; -+ n->secLabel = $6; - $$ = (Node *)n; - } - ; -*************** createfunc_opt_item: -*** 4893,4898 **** ---- 4905,4914 ---- - { - $$ = makeDefElem("window", (Node *)makeInteger(TRUE)); - } -+ | SecLabelItem -+ { -+ $$ = makeDefElem("security_context", $1); -+ } - | common_func_opt_item - { - $$ = $1; -*************** AlterOwnerStmt: ALTER AGGREGATE func_nam -*** 5607,5612 **** ---- 5623,5723 ---- - } - ; - -+ /***************************************************************************** -+ * -+ * ALTER THING name SECURITY CONTEXT TO -+ * -+ *****************************************************************************/ -+ -+ AlterSecLabelStmt: ALTER DATABASE database_name SecLabelToItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_DATABASE; -+ n->object = list_make1(makeString($3)); -+ n->secLabel = $4; -+ $$ = (Node *) n; -+ } -+ | ALTER SCHEMA name SecLabelToItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_SCHEMA; -+ n->object = list_make1(makeString($3)); -+ n->secLabel = $4; -+ $$ = (Node *) n; -+ } -+ | ALTER TABLE relation_expr SecLabelToItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_TABLE; -+ n->relation = $3; -+ n->secLabel = $4; -+ $$ = (Node *) n; -+ } -+ | ALTER TABLE relation_expr ALTER opt_column ColId SecLabelToItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_COLUMN; -+ n->relation = $3; -+ n->subname = $6; -+ n->secLabel = $7; -+ $$ = (Node *) n; -+ } -+ | ALTER SEQUENCE relation_expr SecLabelToItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_SEQUENCE; -+ n->relation = $3; -+ n->secLabel = $4; -+ $$ = (Node *) n; -+ } -+ | ALTER FUNCTION function_with_argtypes SecLabelToItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_FUNCTION; -+ n->object = $3->funcname; -+ n->objarg = $3->funcargs; -+ n->secLabel = $4; -+ $$ = (Node *) n; -+ } -+ | ALTER LARGE_P OBJECT_P Iconst SecLabelToItem -+ { -+ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); -+ n->objectType = OBJECT_LARGEOBJECT; -+ n->object = list_make1(makeInteger($4)); -+ n->secLabel = $5; -+ $$ = (Node *) n; -+ } -+ ; -+ -+ OptTableSecLabel: SECURITY CONTEXT_P '(' TableSecLabelList ')' { $$ = $4; } -+ | /* EMPTY */ { $$ = NIL; } -+ ; -+ -+ TableSecLabelList: TableSecLabelItem { $$ = list_make1($1); } -+ | TableSecLabelList ',' TableSecLabelItem { $$ = lappend($1, $3); } -+ ; -+ -+ TableSecLabelItem: Sconst -+ { $$ = makeDefElem(NULL, (Node *)makeString($1)); } -+ | ColId '=' Sconst -+ { $$ = makeDefElem($1, (Node *)makeString($3)); } -+ ; -+ -+ OptSecLabel: SecLabelItem { $$ = $1; } -+ | /* EMPTY */ { $$ = NULL; } -+ ; -+ -+ SecLabelItem: SECURITY CONTEXT_P '(' Sconst ')' -+ { -+ $$ = (Node *) makeString($4); -+ } -+ ; -+ -+ SecLabelToItem: SECURITY CONTEXT_P TO Sconst -+ { -+ $$ = (Node *) makeString($4); -+ } -+ ; - - /***************************************************************************** - * -*************** createdb_opt_item: -*** 6049,6054 **** ---- 6160,6169 ---- - { - $$ = makeDefElem("owner", NULL); - } -+ | SecLabelItem -+ { -+ $$ = makeDefElem("security_context", $1); -+ } - ; - - /* -*************** unreserved_keyword: -*** 10175,10180 **** ---- 10290,10296 ---- - | CONNECTION - | CONSTRAINTS - | CONTENT_P -+ | CONTEXT_P - | CONTINUE_P - | CONVERSION_P - | COPY -diff -Nrpc blob/src/backend/parser/parse_target.c sepgsql/src/backend/parser/parse_target.c -*** blob/src/backend/parser/parse_target.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/parser/parse_target.c Wed Jul 15 19:38:52 2009 -*************** -*** 14,19 **** ---- 14,20 ---- - */ - #include "postgres.h" - -+ #include "catalog/heap.h" - #include "catalog/pg_type.h" - #include "commands/dbcommands.h" - #include "funcapi.h" -*************** transformAssignedExpr(ParseState *pstate -*** 361,376 **** - Oid attrtype; /* type of target column */ - int32 attrtypmod; - Relation rd = pstate->p_target_relation; - - Assert(rd != NULL); -! if (attrno <= 0) -! ereport(ERROR, -! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -! errmsg("cannot assign to system column \"%s\"", -! colname), -! parser_errposition(pstate, location))); -! attrtype = attnumTypeId(rd, attrno); -! attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod; - - /* - * If the expression is a DEFAULT placeholder, insert the attribute's ---- 362,394 ---- - Oid attrtype; /* type of target column */ - int32 attrtypmod; - Relation rd = pstate->p_target_relation; -+ bool relhasoids = RelationGetForm(rd)->relhasoids; - - Assert(rd != NULL); -! if (attrno > 0) -! { -! attrtype = attnumTypeId(rd, attrno); -! attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod; -! } -! else -! { -! Form_pg_attribute attForm -! = SystemAttributeDefinition(attrno, relhasoids); -! if (attForm && SystemAttributeIsWritable(attrno)) -! { -! attrtype = attForm->atttypid; -! attrtypmod = attForm->atttypmod; -! } -! else -! { -! ereport(ERROR, -! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -! errmsg("cannot assign to system column \"%s\"", -! colname), -! parser_errposition(pstate, location))); -! return NULL; /* compiler kindness */ -! } -! } - - /* - * If the expression is a DEFAULT placeholder, insert the attribute's -*************** updateTargetListEntry(ParseState *pstate -*** 515,520 **** ---- 533,541 ---- - */ - tle->resno = (AttrNumber) attrno; - tle->resname = colname; -+ -+ if (SystemAttributeIsWritable(attrno)) -+ tle->resjunk = true; - } - - -*************** checkInsertTargets(ParseState *pstate, L -*** 789,794 **** ---- 810,816 ---- - Bitmapset *wholecols = NULL; - Bitmapset *partialcols = NULL; - ListCell *tl; -+ uint32 system_attrs = 0UL; - - foreach(tl, cols) - { -*************** checkInsertTargets(ParseState *pstate, L -*** 797,810 **** - int attrno; - - /* Lookup column name, ereport on failure */ -! attrno = attnameAttNum(pstate->p_target_relation, name, false); - if (attrno == InvalidAttrNumber) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - name, - RelationGetRelationName(pstate->p_target_relation)), - parser_errposition(pstate, col->location))); - - /* - * Check for duplicates, but only of whole columns --- we allow ---- 819,855 ---- - int attrno; - - /* Lookup column name, ereport on failure */ -! attrno = attnameAttNum(pstate->p_target_relation, name, true); - if (attrno == InvalidAttrNumber) -+ { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - name, - RelationGetRelationName(pstate->p_target_relation)), - parser_errposition(pstate, col->location))); -+ } -+ else if (attrno < 0) -+ { -+ if (SystemAttributeIsWritable(attrno)) -+ { -+ uint32 mask = (1<<(-attrno)); -+ -+ if ((system_attrs & mask) != 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_DUPLICATE_COLUMN), -+ errmsg("column \"%s\" specified more than once", name), -+ parser_errposition(pstate, col->location))); -+ system_attrs |= mask; -+ *attrnos = lappend_int(*attrnos, attrno); -+ continue; -+ } -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), -+ errmsg("column \"%s\" of relation \"%s\" is system column", -+ name, RelationGetRelationName(pstate->p_target_relation)), -+ parser_errposition(pstate, col->location))); -+ } - - /* - * Check for duplicates, but only of whole columns --- we allow -diff -Nrpc blob/src/backend/parser/parse_utilcmd.c sepgsql/src/backend/parser/parse_utilcmd.c -*** blob/src/backend/parser/parse_utilcmd.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/parser/parse_utilcmd.c Tue Dec 15 17:30:25 2009 -*************** -*** 49,54 **** ---- 49,55 ---- - #include "parser/parse_type.h" - #include "parser/parse_utilcmd.h" - #include "rewrite/rewriteManip.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/lsyscache.h" -*************** transformInhRelation(ParseState *pstate, -*** 565,570 **** ---- 566,573 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_CLASS, - RelationGetRelationName(relation)); -+ /* SELinux checks */ -+ sepgsql_relation_copy_definition(RelationGetRelid(relation)); - - tupleDesc = RelationGetDescr(relation); - constr = tupleDesc->constr; -diff -Nrpc blob/src/backend/postmaster/autovacuum.c sepgsql/src/backend/postmaster/autovacuum.c -*** blob/src/backend/postmaster/autovacuum.c Sun Sep 6 19:40:49 2009 ---- sepgsql/src/backend/postmaster/autovacuum.c Sun Sep 6 19:53:10 2009 -*************** do_autovacuum(void) -*** 2004,2010 **** - object.classId = RelationRelationId; - object.objectId = relid; - object.objectSubId = 0; -! performDeletion(&object, DROP_CASCADE); - } - else - { ---- 2004,2010 ---- - object.classId = RelationRelationId; - object.objectId = relid; - object.objectSubId = 0; -! performDeletionNoPerms(&object, DROP_CASCADE); - } - else - { -diff -Nrpc blob/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmaster/postmaster.c -*** blob/src/backend/postmaster/postmaster.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/postmaster/postmaster.c Sun Dec 20 00:41:22 2009 -*************** -*** 108,113 **** ---- 108,114 ---- - #include "postmaster/pgarch.h" - #include "postmaster/postmaster.h" - #include "postmaster/syslogger.h" -+ #include "security/sepgsql.h" - #include "storage/fd.h" - #include "storage/ipc.h" - #include "storage/pg_shmem.h" -*************** static pid_t StartupPID = 0, -*** 209,215 **** - AutoVacPID = 0, - PgArchPID = 0, - PgStatPID = 0, -! SysLoggerPID = 0; - - /* Startup/shutdown state */ - #define NoShutdown 0 ---- 210,217 ---- - AutoVacPID = 0, - PgArchPID = 0, - PgStatPID = 0, -! SysLoggerPID = 0, -! sepgsqlReceiverPID = 0; - - /* Startup/shutdown state */ - #define NoShutdown 0 -*************** static void ShmemBackendArrayRemove(Back -*** 445,450 **** ---- 447,453 ---- - #define StartupDataBase() StartChildProcess(StartupProcess) - #define StartBackgroundWriter() StartChildProcess(BgWriterProcess) - #define StartWalWriter() StartChildProcess(WalWriterProcess) -+ #define StartSELinuxReceiver() StartChildProcess(SelinuxReceiverProcess) - - /* Macros to check exit status of a child process */ - #define EXIT_STATUS_0(st) ((st) == 0) -*************** ServerLoop(void) -*** 1436,1441 **** ---- 1439,1449 ---- - if (PgStatPID == 0 && pmState == PM_RUN) - PgStatPID = pgstat_start(); - -+ /* if we have lost the selinux netlink receiver, try to start */ -+ if (sepgsqlReceiverPID == 0 && pmState == PM_RUN && -+ sepgsqlReceiverStart()) -+ sepgsqlReceiverPID = StartSELinuxReceiver(); -+ - /* If we need to signal the autovacuum launcher, do so now */ - if (avlauncher_needs_signal) - { -*************** SIGHUP_handler(SIGNAL_ARGS) -*** 2055,2060 **** ---- 2063,2070 ---- - signal_child(SysLoggerPID, SIGHUP); - if (PgStatPID != 0) - signal_child(PgStatPID, SIGHUP); -+ if (sepgsqlReceiverPID != 0) -+ signal_child(sepgsqlReceiverPID, SIGHUP); - - /* Reload authentication config files too */ - if (!load_hba()) -*************** pmdie(SIGNAL_ARGS) -*** 2115,2120 **** ---- 2125,2133 ---- - /* and the walwriter too */ - if (WalWriterPID != 0) - signal_child(WalWriterPID, SIGTERM); -+ /* and the selinux netlink receiver too */ -+ if (sepgsqlReceiverPID != 0) -+ signal_child(sepgsqlReceiverPID, SIGTERM); - pmState = PM_WAIT_BACKUP; - } - -*************** pmdie(SIGNAL_ARGS) -*** 2162,2167 **** ---- 2175,2183 ---- - /* and the walwriter too */ - if (WalWriterPID != 0) - signal_child(WalWriterPID, SIGTERM); -+ /* and the selinux netlink receiver too */ -+ if (sepgsqlReceiverPID != 0) -+ signal_child(sepgsqlReceiverPID, SIGTERM); - pmState = PM_WAIT_BACKENDS; - } - -*************** pmdie(SIGNAL_ARGS) -*** 2195,2200 **** ---- 2211,2218 ---- - signal_child(PgArchPID, SIGQUIT); - if (PgStatPID != 0) - signal_child(PgStatPID, SIGQUIT); -+ if (sepgsqlReceiverPID != 0) -+ signal_child(sepgsqlReceiverPID, SIGQUIT); - ExitPostmaster(0); - break; - } -*************** reaper(SIGNAL_ARGS) -*** 2457,2462 **** ---- 2475,2490 ---- - continue; - } - -+ /* Was it the selinux netlink receiver process? */ -+ if (pid == sepgsqlReceiverPID) -+ { -+ sepgsqlReceiverPID = 0; -+ if (!EXIT_STATUS_0(exitstatus)) -+ LogChildExit(LOG, _("SELinux netlink receiver process"), -+ pid, exitstatus); -+ continue; -+ } -+ - /* - * Else do standard backend child cleanup. - */ -*************** HandleChildCrash(int pid, int exitstatus -*** 2648,2653 **** ---- 2676,2693 ---- - signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT)); - } - -+ /* Take care of the selinux netlink receiver too */ -+ if (pid == sepgsqlReceiverPID) -+ sepgsqlReceiverPID = 0; -+ else if (sepgsqlReceiverPID != 0 && !FatalError) -+ { -+ ereport(DEBUG2, -+ (errmsg_internal("sending %s to process %d", -+ (SendStop ? "SIGSTOP" : "SIGQUIT"), -+ (int) sepgsqlReceiverPID))); -+ signal_child(sepgsqlReceiverPID, (SendStop ? SIGSTOP : SIGQUIT)); -+ } -+ - /* - * Force a power-cycle of the pgarch process too. (This isn't absolutely - * necessary, but it seems like a good idea for robustness, and it -*************** PostmasterStateMachine(void) -*** 2780,2786 **** - StartupPID == 0 && - (BgWriterPID == 0 || !FatalError) && - WalWriterPID == 0 && -! AutoVacPID == 0) - { - if (FatalError) - { ---- 2820,2827 ---- - StartupPID == 0 && - (BgWriterPID == 0 || !FatalError) && - WalWriterPID == 0 && -! AutoVacPID == 0 && -! sepgsqlReceiverPID == 0) - { - if (FatalError) - { -*************** StartChildProcess(AuxProcType type) -*** 4323,4328 **** ---- 4364,4375 ---- - ereport(LOG, - (errmsg("could not fork WAL writer process: %m"))); - break; -+ #ifdef HAVE_SELINUX -+ case SelinuxReceiverProcess: -+ ereport(LOG, -+ (errmsg("could not fork selinux receiver process: %m"))); -+ break; -+ #endif - default: - ereport(LOG, - (errmsg("could not fork process: %m"))); -diff -Nrpc blob/src/backend/rewrite/rewriteDefine.c sepgsql/src/backend/rewrite/rewriteDefine.c -*** blob/src/backend/rewrite/rewriteDefine.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/rewrite/rewriteDefine.c Fri Sep 18 14:51:00 2009 -*************** -*** 27,32 **** ---- 27,33 ---- - #include "rewrite/rewriteDefine.h" - #include "rewrite/rewriteManip.h" - #include "rewrite/rewriteSupport.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/inval.h" -*************** DefineQueryRewrite(char *rulename, -*** 266,271 **** ---- 267,275 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(event_relation)); - -+ /* SELinux checks */ -+ sepgsql_rule_create(event_relid, rulename); -+ - /* - * No rule actions that modify OLD or NEW - */ -diff -Nrpc blob/src/backend/rewrite/rewriteRemove.c sepgsql/src/backend/rewrite/rewriteRemove.c -*** blob/src/backend/rewrite/rewriteRemove.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/rewrite/rewriteRemove.c Fri Sep 18 14:51:00 2009 -*************** -*** 22,27 **** ---- 22,28 ---- - #include "catalog/pg_rewrite.h" - #include "miscadmin.h" - #include "rewrite/rewriteRemove.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/fmgroids.h" - #include "utils/inval.h" -*************** RemoveRewriteRule(Oid owningRel, const c -*** 78,83 **** ---- 79,87 ---- - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - get_rel_name(eventRelationOid)); - -+ /* SELinux checks */ -+ sepgsql_rule_drop(eventRelationOid, ruleName); -+ - /* - * Do the deletion - */ -diff -Nrpc blob/src/backend/security/Makefile sepgsql/src/backend/security/Makefile -*** blob/src/backend/security/Makefile Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/Makefile Wed Jul 15 19:39:56 2009 -*************** -*** 0 **** ---- 1,13 ---- -+ # -+ # Makefile for the enhanced security subsystem -+ # -+ -+ subdir = src/backend/security -+ top_builddir = ../../.. -+ include $(top_builddir)/src/Makefile.global -+ -+ SUBDIRS = sepgsql -+ -+ OBJS = rowlevel.o -+ -+ include $(top_srcdir)/src/backend/common.mk -diff -Nrpc blob/src/backend/security/rowlevel.c sepgsql/src/backend/security/rowlevel.c -*** blob/src/backend/security/rowlevel.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/rowlevel.c Thu Jul 16 17:22:29 2009 -*************** -*** 0 **** ---- 1,121 ---- -+ /* -+ * src/backend/security/common.c -+ * common facilities for row-level access controls both of DAC and MAC -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ -+ #include "catalog/pg_security.h" -+ #include "security/rowlevel.h" -+ #include "security/sepgsql.h" -+ #include "storage/bufmgr.h" -+ #include "storage/bufpage.h" -+ #include "utils/rel.h" -+ #include "utils/tqual.h" -+ -+ /* -+ * rowlvGetPerformingMode -+ * rowlvSetPerformingMode -+ * enables to control the behavior of row-level features -+ * when violated tuples are detected. -+ * The default is ROWLV_FILTER_MODE which filters out -+ * violated tuples from result set, ROWLV_ABORT_MODE -+ * raises an error and ROWLV_BYPASS_MODE do nothing. -+ */ -+ static int rowlv_mode = ROWLV_FILTER_MODE; -+ -+ int rowlvGetPerformingMode(void) -+ { -+ return rowlv_mode; -+ } -+ -+ int rowlvSetPerformingMode(int new_mode) -+ { -+ int old_mode = new_mode; -+ -+ rowlv_mode = new_mode; -+ -+ return old_mode; -+ } -+ -+ /* -+ * rowlvSetupPermissions -+ * setups permissions for row-level access controls. -+ */ -+ uint32 -+ rowlvSetupPermissions(RangeTblEntry *rte) -+ { -+ return sepgsqlSetupTuplePerms(rte); -+ } -+ -+ /* -+ * rowlvExecScan -+ * a hook to filter out invisible/untouchable tuples. -+ */ -+ static bool -+ rowlvExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort) -+ { -+ HeapTuple tuple; -+ uint32 perms = scan->rowlvPerms; -+ -+ if (!perms) -+ return true; -+ -+ tuple = ExecMaterializeSlot(slot); -+ -+ return sepgsqlExecScan(rel, tuple, perms, abort); -+ } -+ -+ bool -+ rowlvExecScanFilter(Scan *scan, Relation rel, TupleTableSlot *slot) -+ { -+ if (!rel || !scan->rowlvPerms || rowlv_mode != ROWLV_FILTER_MODE) -+ return true; -+ -+ return rowlvExecScan(scan, rel, slot, false); -+ } -+ -+ void -+ rowlvExecScanAbort(Scan *scan, Relation rel, TupleTableSlot *slot) -+ { -+ if (!rel || !scan->rowlvPerms || rowlv_mode != ROWLV_ABORT_MODE) -+ return; -+ -+ rowlvExecScan(scan, rel, slot, true); -+ } -+ -+ /* -+ * rowlvCopyToTuple -+ * checks permission on fetched tuple -+ */ -+ bool -+ rowlvCopyToTuple(Relation rel, HeapTuple tuple) -+ { -+ if (!sepgsqlExecScan(rel, tuple, SEPG_DB_TUPLE__SELECT, false)) -+ return false; -+ -+ return true; -+ } -+ -+ /* -+ * rowlvHeapTupleInsert -+ * assign default security attribute, and check permission -+ * if necessary. -+ */ -+ void -+ rowlvHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal) -+ { -+ sepgsqlHeapTupleInsert(rel, newtup, internal); -+ } -+ -+ /* -+ * rowlvHeapTupleUpdate -+ * check permission to change security attribute, if necesary -+ */ -+ void -+ rowlvHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup) -+ { -+ sepgsqlHeapTupleUpdate(rel, otid, newtup); -+ } -diff -Nrpc blob/src/backend/security/sepgsql/Makefile sepgsql/src/backend/security/sepgsql/Makefile -*** blob/src/backend/security/sepgsql/Makefile Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/Makefile Sun Dec 20 00:41:22 2009 -*************** -*** 0 **** ---- 1,15 ---- -+ # -+ # Makefile -+ # Makefile for utils/sepgsql : SE-PostgreSQL -+ # -+ -+ subdir = src/backend/security/sepgsql -+ top_builddir = ../../../.. -+ include $(top_builddir)/src/Makefile.global -+ -+ OBJS = misc.o -+ ifeq ($(enable_selinux), yes) -+ OBJS += selinux.o checker.o bridge.o label.o -+ endif -+ -+ include $(top_srcdir)/src/backend/common.mk -diff -Nrpc blob/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security/sepgsql/avc.c -*** blob/src/backend/security/sepgsql/avc.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/avc.c Thu Dec 10 10:36:18 2009 -*************** -*** 0 **** ---- 1,881 ---- -+ /* -+ * src/backend/security/sepgsql/avc.c -+ * SE-PostgreSQL userspace access vector cache -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ -+ #include "access/hash.h" -+ #include "catalog/pg_security.h" -+ #include "libpq/pqsignal.h" -+ #include "miscadmin.h" -+ #include "postmaster/postmaster.h" -+ #include "security/sepgsql.h" -+ #include "storage/ipc.h" -+ #include "storage/lwlock.h" -+ #include "utils/memutils.h" -+ #include -+ #include -+ #include -+ -+ /* -+ * AVC: userspace access vector cache -+ * -+ * SE-PostgreSQL asks in-kernel SELinux to make its decision whether -+ * the required accesses should be allowed, or not, based on the unified -+ * security policy. It needs a system call invocation to communicate -+ * a kernel feature, such as SELinux, but it is a heavy task in most cases -+ * due to the context switching. -+ * -+ * The userspace avc enables to minimize the number of system call -+ * invocations, using a chache mechanim for the certain pair of security -+ * contexts and object classes (it means the kind of actions). -+ * It enables to hold recently fetched results from the in-kernel SELinux, -+ * and make a decision without context switching, if the cache hit. -+ * -+ * When the state of security policy is changed, the cached results -+ * shall to be invalidated. The state monitoring process launched by -+ * postmaster can receives the notification messages from the kernel -+ * space, and invalidate the current version of avc. -+ */ -+ static MemoryContext AvcMemCtx = NULL; -+ -+ #define AVC_HASH_NUM_SLOTS 256 -+ #define AVC_HASH_NUM_NODES 180 -+ -+ #define AVC_DATUM_NSID_SLOTS 19 -+ typedef struct -+ { -+ uint32 hash_key; -+ -+ security_class_t tclass; -+ sepgsql_sid_t tsid; -+ sepgsql_sid_t nsid[AVC_DATUM_NSID_SLOTS]; -+ -+ access_vector_t allowed; -+ access_vector_t decided; -+ access_vector_t auditallow; -+ access_vector_t auditdeny; -+ -+ bool hot_cache; -+ bool permissive; -+ -+ char ncontext[1]; -+ } avc_datum; -+ -+ typedef struct avc_page -+ { -+ struct avc_page *next; -+ -+ security_context_t scontext; -+ -+ List *slot[AVC_HASH_NUM_SLOTS]; -+ -+ uint32 avc_count; -+ uint32 lru_hint; -+ } avc_page; -+ -+ static avc_page *current_page = NULL; -+ -+ static int avc_version; -+ -+ /* -+ * selinux_state -+ * -+ * It is deployed on the shared memory region, to show the system -+ * state of SELinux and its security policy. -+ * -+ * The selinux_state->version should be checked prior to avc accesses. -+ * If it does not match with the local avc_version, it means that -+ * system security policy was reloaded or system state (enforcing -+ * or permissive) was changed. -+ * -+ * The state monitoring worker process receives messages from the -+ * kernel using libselinux, and it updates the selinux_state. -+ */ -+ struct -+ { -+ int version; -+ -+ bool enforcing; -+ -+ } *selinux_state = NULL; -+ -+ Size -+ sepgsqlShmemSize(void) -+ { -+ if (!sepgsqlIsEnabled()) -+ return 0; -+ -+ return sizeof(*selinux_state); -+ } -+ -+ /* -+ * sepgsql_shmem_init -+ * attaches shared memory segment. -+ */ -+ static void -+ sepgsqlShmemInit(void) -+ { -+ bool found; -+ -+ selinux_state = ShmemInitStruct("SELinux policy state", -+ sepgsqlShmemSize(), &found); -+ if (!found) -+ { -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ -+ selinux_state->version = 0; -+ selinux_state->enforcing = (security_getenforce() > 0); -+ -+ LWLockRelease(SepgsqlAvcLock); -+ } -+ } -+ -+ /* -+ * sepgsqlAvcReset -+ * -+ * It invalidate access vector cache. It has to be called on errors, -+ * because avc entries for newly created context is uncertain whether -+ * it is still valid, or not. -+ * If error happens before avc initialization, we simply skip it. -+ */ -+ void -+ sepgsqlAvcReset(void) -+ { -+ if (!sepgsqlIsEnabled() || !AvcMemCtx) -+ return; -+ -+ MemoryContextReset(AvcMemCtx); -+ -+ current_page = NULL; -+ -+ sepgsqlAvcSwitchClient(sepgsqlGetClientLabel()); -+ } -+ -+ /* -+ * sepgsqlAvcCheckValid -+ * -+ * It checks whether the current AVC pages are valid, or not. -+ * If state monitoring process already received an invalidation -+ * message from the kernel, it clears current AVC pages and -+ * returns false. -+ */ -+ static bool -+ sepgsqlAvcCheckValid(void) -+ { -+ bool result = true; -+ -+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED); -+ if (avc_version != selinux_state->version) -+ { -+ /* reset invalid avc pages, and makes an empty one */ -+ MemoryContextReset(AvcMemCtx); -+ -+ current_page = NULL; -+ -+ sepgsqlAvcSwitchClient(sepgsqlGetClientLabel()); -+ -+ /* copy current version to local */ -+ avc_version = selinux_state->version; -+ -+ result = false; -+ } -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return result; -+ } -+ -+ /* -+ * sepgsqlAvcInitialize -+ * -+ * It allocates a memory context for userspace AVC, -+ * map shared memory segment, and initialize avc_page -+ * for the current client's privilege. -+ * -+ * If the current backend is not associated with a certain -+ * client process, it switches to permissive mode to avoid -+ * to prevent any internal processes. -+ */ -+ void -+ sepgsqlAvcInitialize(void) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* -+ * local memory context -+ */ -+ AvcMemCtx = AllocSetContextCreate(TopMemoryContext, -+ "SE-PostgreSQL userspace avc", -+ ALLOCSET_DEFAULT_MINSIZE, -+ ALLOCSET_DEFAULT_INITSIZE, -+ ALLOCSET_DEFAULT_MAXSIZE); -+ sepgsqlShmemInit(); -+ -+ /* -+ * Switch to local permissive mode -+ */ -+ if (!MyProcPort) -+ sepgsqlSetEnforce(0); -+ -+ /* -+ * selinux_state->version is never negative value, -+ * so this call always reset local avc. -+ */ -+ avc_version = -1; -+ sepgsqlAvcCheckValid(); -+ } -+ -+ /* -+ * sepgsqlGetEnforce -+ * sepgsqlSetEnforce -+ * -+ * SELinux has two working mode called Enforcing/Permissive. -+ * In enforcing mode, it checks security policy and actually -+ * applies its access controls. In permissive mode, it also -+ * checks security policy, but does not apply any access -+ * controls. It is used to collect access denied logs to -+ * debug security policy. -+ * -+ * sepgsqlGetEnforce() returns the current working mode, and -+ * sepgsqlSetEnforce() switches the current working mode -+ * temporary. When we switches the mode, any errors have to -+ * be acquired, and it should be restored correctly. -+ */ -+ static int local_enforce = -1; /* undefined */ -+ -+ bool -+ sepgsqlGetEnforce(void) -+ { -+ bool rc; -+ -+ if (local_enforce < 0) -+ { -+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED); -+ rc = selinux_state->enforcing; -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return rc; -+ } -+ -+ return (local_enforce > 0 ? true : false); -+ } -+ -+ int -+ sepgsqlSetEnforce(int new_mode) -+ { -+ int old_mode = local_enforce; -+ -+ local_enforce = new_mode; -+ -+ return old_mode; -+ } -+ -+ /* -+ * sepgsqlAvcAudit -+ * -+ * It write out audit message, when auditdeny or auditallow -+ * matches the required permission bits. -+ * If external module support sepgsqlAvcAuditHook, it allows -+ * to write audit logs to external log manager, such as system -+ * auditd. -+ */ -+ -+ PGDLLIMPORT sepgsqlAvcAuditHook_t sepgsqlAvcAuditHook = NULL; -+ -+ static void -+ sepgsqlAvcAudit(bool denied, char *scontext, char *tcontext, -+ uint16 tclass, uint32 audited, const char *audit_name) -+ { -+ StringInfoData buf; -+ uint32 mask; -+ const char *tclass_name; -+ -+ /* translate to human readable form */ -+ scontext = sepgsqlTransSecLabelOut(scontext); -+ tcontext = sepgsqlTransSecLabelOut(tcontext); -+ -+ /* permissions in text representation */ -+ initStringInfo(&buf); -+ appendStringInfo(&buf, "{"); -+ for (mask = 1; audited != 0; mask <<= 1) -+ { -+ if (audited & mask) -+ appendStringInfo(&buf, " %s", sepgsqlGetPermString(tclass, mask)); -+ -+ audited &= ~mask; -+ } -+ appendStringInfo(&buf, " }"); -+ -+ tclass_name = sepgsqlGetClassString(tclass); -+ -+ /* call external audit module, if loaded */ -+ if (sepgsqlAvcAuditHook) -+ (*sepgsqlAvcAuditHook) (denied, scontext, tcontext, -+ tclass_name, buf.data, audit_name); -+ else -+ { -+ appendStringInfo(&buf, " scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, tclass_name); -+ if (audit_name) -+ appendStringInfo(&buf, " name=%s", audit_name); -+ -+ ereport(LOG, -+ (errcode(ERRCODE_SELINUX_AUDIT), -+ errmsg("SELinux: %s %s", -+ denied ? "denied" : "granted", buf.data))); -+ } -+ } -+ -+ /* -+ * sepgsqlAvcReclaim -+ * -+ * It wipes recently unused AVC entries, when the number of entries -+ * reaches AVC_HASH_NUM_NODES.. -+ */ -+ static void -+ sepgsqlAvcReclaim(avc_page *page) -+ { -+ ListCell *l; -+ avc_datum *cache; -+ -+ while (page->avc_count > AVC_HASH_NUM_NODES) -+ { -+ foreach (l, page->slot[page->lru_hint]) -+ { -+ cache = lfirst(l); -+ -+ if (cache->hot_cache) -+ cache->hot_cache = false; -+ else -+ { -+ list_delete_ptr(page->slot[page->lru_hint], cache); -+ pfree(cache); -+ page->avc_count--; -+ } -+ } -+ page->lru_hint = (page->lru_hint + 1) % AVC_HASH_NUM_SLOTS; -+ } -+ } -+ -+ /* -+ * sepgsqlAvcMakeEntry -+ * -+ * It makes a new AVC entry and insert it on the avc_page. -+ * If is hold more than AVC_HASH_NUM_NODES entries, recently unused -+ * avc_datum shall be reclaimed. -+ */ -+ #define avc_hash_key(trelid,tsecid,tclass) \ -+ (hash_uint32((trelid) ^ (tsecid) ^ ((tclass) << 3))) -+ -+ static avc_datum * -+ sepgsqlAvcMakeEntry(avc_page *page, sepgsql_sid_t tsid, uint16 tclass) -+ { -+ security_context_t scontext, tcontext, ncontext; -+ security_class_t tclass_ex; -+ MemoryContext oldctx; -+ struct av_decision avd; -+ avc_datum *cache; -+ uint32 hash_key, index; -+ -+ hash_key = avc_hash_key(tsid.relid, tsid.secid, tclass); -+ index = hash_key % AVC_HASH_NUM_SLOTS; -+ -+ scontext = page->scontext; -+ tcontext = securityRawSecLabelOut(tsid.relid, tsid.secid); -+ -+ /* -+ * Compute SELinux permission -+ */ -+ tclass_ex = sepgsqlTransToExternalClass(tclass); -+ if (tclass_ex > 0) -+ { -+ if (security_compute_av_flags_raw(scontext, tcontext, -+ tclass_ex, 0, &avd) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: unable to compute av_decision: " -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, -+ sepgsqlGetClassString(tclass)))); -+ sepgsqlTransToInternalPerms(tclass, &avd); -+ } -+ else -+ { -+ /* fill it up as undefined class */ -+ avd.allowed = (security_deny_unknown() ? 0 : ~0UL); -+ avd.decided = ~0UL; -+ avd.auditallow = 0UL; -+ avd.auditdeny = ~0UL; -+ avd.flags = 0; -+ } -+ -+ /* -+ * Compute New security context -+ */ -+ if (security_compute_create_raw(scontext, tcontext, -+ tclass_ex, &ncontext) < 0) -+ { -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: unable to compute new context: " -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, sepgsqlGetClassString(tclass)))); -+ } -+ -+ /* -+ * Copy them to avc_datum -+ */ -+ oldctx = MemoryContextSwitchTo(AvcMemCtx); -+ PG_TRY(); -+ { -+ cache = palloc0(sizeof(avc_datum) + strlen(ncontext)); -+ } -+ PG_CATCH(); -+ { -+ freecon(ncontext); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ -+ cache->hash_key = hash_key; -+ cache->tclass = tclass; -+ cache->tsid.relid = tsid.relid; -+ cache->tsid.secid = tsid.secid; -+ /* cache->nsid shall be set later */ -+ -+ cache->allowed = avd.allowed; -+ cache->decided = avd.decided; -+ cache->auditallow = avd.auditallow; -+ cache->auditdeny = avd.auditdeny; -+ -+ cache->hot_cache = true; -+ if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) -+ cache->permissive = true; -+ strcpy(cache->ncontext, ncontext); -+ freecon(ncontext); -+ -+ sepgsqlAvcReclaim(page); -+ -+ page->slot[index] = lcons(cache, page->slot[index]); -+ page->avc_count++; -+ -+ MemoryContextSwitchTo(oldctx); -+ -+ return cache; -+ } -+ -+ /* -+ * sepgsqlAvcLookup -+ * -+ * It lookups required AVC entry. -+ */ -+ static avc_datum * -+ sepgsqlAvcLookup(avc_page *page, sepgsql_sid_t tsid, uint16 tclass) -+ { -+ avc_datum *cache = NULL; -+ uint32 hash_key, index; -+ ListCell *l; -+ -+ hash_key = avc_hash_key(tsid.relid, tsid.secid, tclass); -+ index = hash_key % AVC_HASH_NUM_SLOTS; -+ -+ foreach (l, page->slot[index]) -+ { -+ cache = lfirst(l); -+ if (cache->hash_key == hash_key -+ && cache->tclass == tclass -+ && cache->tsid.relid == tsid.relid -+ && cache->tsid.secid == tsid.secid) -+ { -+ cache->hot_cache = true; -+ return cache; -+ } -+ } -+ return NULL; -+ } -+ -+ /* -+ * sepgsqlAvcSwitchClientLabel() -+ * -+ * It switches the current avc_page. -+ * An avc_page is a set of cached access control decisions associated -+ * with a certain privilege of the client. This structure enables to -+ * lookup required avc_datum without any comparison to the subject -+ * label. -+ */ -+ void -+ sepgsqlAvcSwitchClient(const char *scontext) -+ { -+ MemoryContext oldctx; -+ avc_page *new_page; -+ int i; -+ -+ if (current_page) -+ { -+ new_page = current_page; -+ do { -+ if (strcmp(new_page->scontext, scontext) == 0) -+ { -+ current_page = new_page; -+ return; -+ } -+ new_page = new_page->next; -+ } while (new_page != current_page); -+ } -+ -+ /* Not found, create a new avc_page */ -+ oldctx = MemoryContextSwitchTo(AvcMemCtx); -+ new_page = palloc0(sizeof(avc_page)); -+ new_page->scontext = pstrdup(scontext); -+ MemoryContextSwitchTo(oldctx); -+ -+ for (i=0; i < AVC_HASH_NUM_SLOTS; i++) -+ new_page->slot[i] = NIL; -+ -+ if (!current_page) -+ new_page->next = new_page; -+ else -+ { -+ new_page->next = current_page->next; -+ current_page->next = new_page; -+ } -+ -+ current_page = new_page; -+ } -+ -+ /* -+ * sepgsqlClientHasPerms -+ * -+ * It checks client's privileges on the given object using avc. -+ */ -+ bool -+ sepgsqlClientHasPerms(sepgsql_sid_t tsid, -+ uint16 tclass, uint32 required, -+ const char *audit_name, bool abort) -+ { -+ avc_datum *cache; -+ uint32 denied, audited; -+ bool result = true; -+ -+ Assert(required != 0); -+ -+ do { -+ cache = sepgsqlAvcLookup(current_page, tsid, tclass); -+ if (!cache) -+ cache = sepgsqlAvcMakeEntry(current_page, tsid, tclass); -+ } while (!sepgsqlAvcCheckValid()); -+ -+ denied = required & ~cache->allowed; -+ audited = denied ? (denied & cache->auditdeny) -+ : (required & cache->auditallow); -+ if (audited) -+ { -+ sepgsqlAvcAudit(!!denied, -+ current_page->scontext, -+ securityRawSecLabelOut(tsid.relid, tsid.secid), -+ cache->tclass, audited, audit_name); -+ } -+ -+ if (denied) -+ { -+ if (!sepgsqlGetEnforce() || cache->permissive) -+ cache->allowed |= required; /* prevent flood of audit log */ -+ else -+ { -+ if (abort) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: security policy violation"))); -+ result = false; -+ } -+ } -+ -+ return result; -+ } -+ -+ /* -+ * sepgsqlClientCreateSecid -+ * sepgsqlClientCreateLabel -+ */ -+ sepgsql_sid_t -+ sepgsqlClientCreateSecid(sepgsql_sid_t tsid, uint16 tclass, Oid nrelid) -+ { -+ sepgsql_sid_t nsid; -+ avc_datum *cache; -+ int index; -+ -+ do { -+ cache = sepgsqlAvcLookup(current_page, tsid, tclass); -+ if (!cache) -+ cache = sepgsqlAvcMakeEntry(current_page, tsid, tclass); -+ -+ index = (nrelid % AVC_DATUM_NSID_SLOTS); -+ if (cache->nsid[index].relid != nrelid) -+ { -+ cache->nsid[index].secid -+ = securityRawSecLabelIn(nrelid, cache->ncontext); -+ cache->nsid[index].relid = nrelid; -+ } -+ nsid = cache->nsid[index]; -+ } while (!sepgsqlAvcCheckValid()); -+ -+ return nsid; -+ } -+ -+ security_context_t -+ sepgsqlClientCreateLabel(sepgsql_sid_t tsid, uint16 tclass) -+ { -+ avc_datum *cache; -+ -+ do { -+ cache = sepgsqlAvcLookup(current_page, tsid, tclass); -+ if (!cache) -+ cache = sepgsqlAvcMakeEntry(current_page, tsid, tclass); -+ } while (!sepgsqlAvcCheckValid()); -+ -+ return cache->ncontext; -+ } -+ -+ /* -+ * sepgsqlComputePerms -+ * sepgsqlComputeCreate -+ * -+ * The following two functions make a query to in-kernel SELinux -+ * without userspace caches, due to some reasons. -+ * The AVC can cover most of cases, but some of corner cases are -+ * not suitable for AVC structure, so we need uncached interfaces. -+ * For example, AVC is unavailable when we tries to load a shared -+ * library module, because security context of the library does not -+ * have its security identifier, so we cannot put it on AVC. -+ */ -+ bool -+ sepgsqlComputePerms(char *scontext, char *tcontext, -+ uint16 tclass_in, uint32 required, -+ const char *audit_name, bool abort) -+ { -+ access_vector_t denied, audited; -+ security_class_t tclass_ex; -+ struct av_decision avd; -+ -+ Assert(required != 0); -+ -+ tclass_ex = sepgsqlTransToExternalClass(tclass_in); -+ if (tclass_ex > 0) -+ { -+ /* -+ * security_compute_av_flags_raw() is a SELinux's API that -+ * returns its access control decision based on the security -+ * policy, to the given combination of user's privilege -+ * (scontext; security label of the client process), -+ * target's attribute (tcontext; security label of the -+ * object) and type of actions (tclass; object classes). -+ * -+ * The returned avd.allowed is a bitmap of allowed actions. -+ */ -+ if (security_compute_av_flags_raw(scontext, tcontext, -+ tclass_ex, 0, &avd) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not compute av_decision: " -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, -+ sepgsqlGetClassString(tclass_in)))); -+ sepgsqlTransToInternalPerms(tclass_in, &avd); -+ } -+ else -+ { -+ /* -+ * If security policy does not support database related -+ * permissions, it fulls up permission bits by dummy -+ * data. -+ * If security_deny_unknown() returns positive value, -+ * undefined permissions should not be allowed. -+ * Otherwise, it shall be allowed. -+ */ -+ avd.allowed = (security_deny_unknown() > 0 ? 0 : ~0UL); -+ avd.decided = ~0UL; -+ avd.auditallow = 0UL; -+ avd.auditdeny = ~0UL; -+ avd.flags = 0; -+ } -+ -+ denied = required & ~avd.allowed; -+ audited = denied ? (denied & avd.auditdeny) -+ : (required & avd.auditallow); -+ if (audited) -+ { -+ /* -+ * If security policy requires to generate an audit log -+ * record for the given request, it should be logged. -+ */ -+ sepgsqlAvcAudit(!!denied, scontext, tcontext, -+ tclass_in, audited, audit_name); -+ } -+ -+ /* -+ * If any required permissions are not allowed, and -+ * SE-PgSQL performs in enforcing mode, and the given -+ * combination of subject, object and action does not -+ * have special flag to be handled as permission, -+ * SE-PgSQL returns false or raises an error. -+ * Otherwise, it returns true that means required -+ * actions are allowed. -+ */ -+ if (!denied || /* no policy violation */ -+ !sepgsqlGetEnforce() || /* permissive mode */ -+ (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) != 0) /* permissive domain */ -+ return true; -+ -+ if (abort) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: security policy violation"))); -+ -+ return false; -+ } -+ -+ char * -+ sepgsqlComputeCreate(char *scontext, char *tcontext, uint16 tclass_in) -+ { -+ security_context_t ncontext, result; -+ security_class_t tclass_ex; -+ -+ tclass_ex = sepgsqlTransToExternalClass(tclass_in); -+ /* -+ * security_compute_create_raw() is a SELinux's API that -+ * returns a default security context to be assigned on -+ * a new object (categorized by object class) when a client -+ * labeled as scontext tries to create a new one under the -+ * parent object labeled as tcontext. -+ */ -+ if (security_compute_create_raw(scontext, tcontext, -+ tclass_ex, &ncontext) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not compute a new context " -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, sepgsqlGetClassString(tclass_in)))); -+ PG_TRY(); -+ { -+ result = pstrdup(ncontext); -+ } -+ PG_CATCH(); -+ { -+ freecon(ncontext); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(ncontext); -+ -+ return result; -+ } -+ -+ /* -+ * SELinux state monitoring process -+ * -+ * This process is forked from postmaster to monitor the state of SELinux. -+ * SELinux can make a notifier message to userspace object manager via -+ * netlink socket. When it receives the message, it updates selinux_state -+ * structure assigned on shared memory region to make any instance reset -+ * its AVC soon. -+ */ -+ static int -+ sepgsql_cb_log(int type, const char *fmt, ...) -+ { -+ char *c, buffer[1024]; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ vsnprintf(buffer, sizeof(buffer), fmt, ap); -+ va_end(ap); -+ -+ c = strrchr(buffer, '\n'); -+ if (c) -+ *c = '\0'; -+ -+ ereport(LOG, -+ (errcode(ERRCODE_SELINUX_INFO), -+ errmsg("%s", buffer))); -+ -+ return 0; -+ } -+ -+ static int -+ sepgsql_cb_setenforce(int enforce) -+ { -+ /* switch enforcing/permissive */ -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ selinux_state->enforcing = (enforce ? true : false); -+ selinux_state->version++; -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return 0; -+ } -+ -+ static int -+ sepgsql_cb_policyload(int seqno) -+ { -+ /* invalidate local avc */ -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ selinux_state->version++; -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return 0; -+ } -+ -+ void -+ sepgsqlReceiverMain(void) -+ { -+ union selinux_callback cb; -+ -+ Assert(sepgsqlIsEnabled()); -+ -+ #ifdef HAVE_SETSID -+ if (setsid() < 0) -+ elog(FATAL, "setsid() failed: %m"); -+ #endif -+ -+ /* -+ * setup the signal handler -+ */ -+ pqinitmask(); -+ pqsignal(SIGHUP, SIG_IGN); -+ pqsignal(SIGINT, SIG_IGN); -+ pqsignal(SIGTERM, exit); -+ pqsignal(SIGQUIT, exit); -+ pqsignal(SIGUSR1, SIG_IGN); -+ pqsignal(SIGUSR2, SIG_IGN); -+ pqsignal(SIGCHLD, SIG_DFL); -+ PG_SETMASK(&UnBlockSig); -+ -+ /* -+ * map shared memory segment -+ */ -+ sepgsqlShmemInit(); -+ -+ ereport(LOG, -+ (errcode(ERRCODE_SELINUX_INFO), -+ errmsg("SELinux: security policy monitor (pid=%u)", getpid()))); -+ /* -+ * setup callback functions from avc_netlink_loop() -+ */ -+ cb.func_log = sepgsql_cb_log; -+ selinux_set_callback(SELINUX_CB_LOG, cb); -+ cb.func_setenforce = sepgsql_cb_setenforce; -+ selinux_set_callback(SELINUX_CB_SETENFORCE, cb); -+ cb.func_policyload = sepgsql_cb_policyload; -+ selinux_set_callback(SELINUX_CB_POLICYLOAD, cb); -+ -+ /* -+ * open netlink socket and wait for messages -+ */ -+ avc_netlink_open(1); -+ -+ avc_netlink_loop(); -+ -+ exit(0); -+ } -diff -Nrpc blob/src/backend/security/sepgsql/bridge.c sepgsql/src/backend/security/sepgsql/bridge.c -*** blob/src/backend/security/sepgsql/bridge.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/bridge.c Thu Mar 18 10:00:36 2010 -*************** -*** 0 **** ---- 1,2922 ---- -+ /* -+ * src/backend/security/sepgsql/bridge.c -+ * -+ * New style security hooks for SE-PostgreSQL -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ -+ #include "access/sysattr.h" -+ #include "catalog/heap.h" -+ #include "catalog/indexing.h" -+ #include "catalog/pg_authid.h" -+ #include "catalog/pg_cast.h" -+ #include "catalog/pg_conversion.h" -+ #include "catalog/pg_database.h" -+ #include "catalog/pg_foreign_data_wrapper.h" -+ #include "catalog/pg_foreign_server.h" -+ #include "catalog/pg_language.h" -+ #include "catalog/pg_largeobject_metadata.h" -+ #include "catalog/pg_namespace.h" -+ #include "catalog/pg_operator.h" -+ #include "catalog/pg_opclass.h" -+ #include "catalog/pg_opfamily.h" -+ #include "catalog/pg_proc.h" -+ #include "catalog/pg_rewrite.h" -+ #include "catalog/pg_security.h" -+ #include "catalog/pg_tablespace.h" -+ #include "catalog/pg_ts_parser.h" -+ #include "catalog/pg_ts_dict.h" -+ #include "catalog/pg_ts_template.h" -+ #include "catalog/pg_ts_config.h" -+ #include "catalog/pg_type.h" -+ #include "catalog/pg_user_mapping.h" -+ #include "commands/dbcommands.h" -+ #include "miscadmin.h" -+ #include "security/sepgsql.h" -+ #include "utils/builtins.h" -+ #include "utils/fmgroids.h" -+ #include "utils/lsyscache.h" -+ #include "utils/syscache.h" -+ #include "utils/tqual.h" -+ -+ #include -+ #include -+ #include -+ #include -+ -+ /* ------------------------------------------------------------ * -+ * Common Helper Routines -+ * ------------------------------------------------------------ */ -+ static bool sepgsql_database_common(Oid datOid, uint32 required, bool abort); -+ static bool sepgsql_schema_common(Oid nspOid, uint32 required, bool abort); -+ static bool sepgsql_attribute_common(Oid relOid, AttrNumber attnum, -+ uint32 required, bool abort); -+ static bool sepgsql_relation_common(Oid relOid, uint32 required, bool abort); -+ static bool sepgsql_proc_common(Oid procOid, uint32 required, bool abort); -+ static bool sepgsql_fdw_common(Oid fdwOid, uint32 required, bool abort); -+ static bool sepgsql_foreign_server_common(Oid fsrvOid, uint32 required, bool abort); -+ static bool sepgsql_language_common(Oid langOid, uint32 required, bool abort); -+ static bool sepgsql_operator_common(Oid oprOid, uint32 required, bool abort); -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_database related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ static bool -+ sepgsql_database_common(Oid datOid, uint32 required, bool abort) -+ { -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ const char *auname; -+ bool rc; -+ -+ tuple = SearchSysCache(DATABASEOID, -+ ObjectIdGetDatum(datOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for database: %u", datOid); -+ -+ auname = NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname); -+ -+ sid = sepgsqlGetTupleSecid(DatabaseRelationId, tuple, &tclass); -+ -+ rc = sepgsqlClientHasPerms(sid, tclass, required, auname, abort); -+ -+ ReleaseSysCache(tuple); -+ -+ return rc; -+ } -+ -+ Oid -+ sepgsql_database_create(const char *datName, Oid srcDatOid, DefElem *newLabel) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ if (!newLabel) -+ sid = sepgsqlGetDefaultDatabaseSecid(srcDatOid); -+ else -+ { -+ sid.relid = DatabaseRelationId; -+ sid.secid = securityTransSecLabelIn(sid.relid, -+ strVal(newLabel->arg)); -+ } -+ -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_DATABASE, -+ SEPG_DB_DATABASE__CREATE, -+ datName, true); -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_database_alter(Oid datOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_database_common(datOid, SEPG_DB_DATABASE__SETATTR, true); -+ } -+ -+ void -+ sepgsql_database_drop(Oid datOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_database_common(datOid, SEPG_DB_DATABASE__DROP, true); -+ } -+ -+ Oid -+ sepgsql_database_relabel(Oid datOid, DefElem *newLabel) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ { -+ if (newLabel) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SELinux is disabled now"))); -+ -+ return InvalidOid; -+ } -+ sid.relid = DatabaseRelationId; -+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg)); -+ -+ /* db_database:{setattr relabelfrom} to older seclabel */ -+ sepgsql_database_common(datOid, -+ SEPG_DB_DATABASE__SETATTR | -+ SEPG_DB_DATABASE__RELABELFROM, true); -+ -+ /* db_database:{relabelto} to newer seclabel */ -+ sepgsqlClientHasPerms(sid, -+ SEPG_CLASS_DB_DATABASE, -+ SEPG_DB_DATABASE__RELABELTO, -+ get_database_name(datOid), true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_database_grant(Oid datOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_database_common(datOid, SEPG_DB_DATABASE__SETATTR, true); -+ } -+ -+ void -+ sepgsql_database_access(Oid datOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_database_common(datOid, SEPG_DB_DATABASE__ACCESS, true); -+ } -+ -+ void -+ sepgsql_database_load_module(Oid datOid, const char *filename) -+ { -+ HeapTuple tuple; -+ security_context_t filecon; -+ security_context_t datcon; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ /* -+ * It assumes preloaded libraries are secure, -+ * because it can be set up using guc variable -+ * not any SQL statements. -+ */ -+ if (GetProcessingMode() == InitProcessing) -+ return; -+ -+ /* Get database context */ -+ tuple = SearchSysCache(DATABASEOID, -+ ObjectIdGetDatum(datOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for database: %u", datOid); -+ -+ datcon = securityRawSecLabelOut(DatabaseRelationId, -+ HeapTupleGetSecid(tuple)); -+ ReleaseSysCache(tuple); -+ -+ /* Get library context */ -+ if (getfilecon_raw(filename, &filecon) < 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not access file \"%s\": %m", filename))); -+ PG_TRY(); -+ { -+ sepgsqlComputePerms(datcon, -+ filecon, -+ SEPG_CLASS_DB_DATABASE, -+ SEPG_DB_DATABASE__LOAD_MODULE, -+ filename, true); -+ } -+ PG_CATCH(); -+ { -+ freecon(filecon); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(filecon); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_namespace related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ static bool -+ sepgsql_schema_common(Oid nspOid, uint32 required, bool abort) -+ { -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ const char *auname; -+ bool rc; -+ -+ tuple = SearchSysCache(NAMESPACEOID, -+ ObjectIdGetDatum(nspOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for namespace: %u", nspOid); -+ -+ sid = sepgsqlGetTupleSecid(NamespaceRelationId, tuple, &tclass); -+ -+ auname = NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname); -+ -+ rc = sepgsqlClientHasPerms(sid, tclass, required, auname, abort); -+ -+ ReleaseSysCache(tuple); -+ -+ return rc; -+ } -+ -+ Oid -+ sepgsql_schema_create(const char *nspName, bool isTemp, DefElem *newLabel) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ if (!newLabel) -+ sid = sepgsqlGetDefaultSchemaSecid(MyDatabaseId); -+ else -+ { -+ sid.relid = NamespaceRelationId; -+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg)); -+ } -+ -+ sepgsqlClientHasPerms(sid, -+ SEPG_CLASS_DB_SCHEMA, -+ SEPG_DB_SCHEMA__CREATE, -+ nspName, true); -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_schema_alter(Oid nspOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__SETATTR, true); -+ } -+ -+ void -+ sepgsql_schema_drop(Oid nspOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__DROP, true); -+ } -+ -+ Oid -+ sepgsql_schema_relabel(Oid nspOid, DefElem *newLabel) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ { -+ if (newLabel) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SELinux is disabled now"))); -+ return InvalidOid; -+ } -+ sid.relid = NamespaceRelationId; -+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg)); -+ -+ /* db_schema:{setattr relabelfrom} for older seclabel */ -+ sepgsql_schema_common(nspOid, -+ SEPG_DB_SCHEMA__SETATTR | -+ SEPG_DB_SCHEMA__RELABELFROM, true); -+ -+ /* db_schema:{relabelto} for newer seclabel */ -+ sepgsqlClientHasPerms(sid, -+ SEPG_CLASS_DB_SCHEMA, -+ SEPG_DB_SCHEMA__RELABELTO, -+ get_namespace_name(nspOid), true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_schema_grant(Oid nspOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__SETATTR, true); -+ } -+ -+ bool -+ sepgsql_schema_search(Oid nspOid, bool abort) -+ { -+ if (!sepgsqlIsEnabled()) -+ return true; -+ -+ return sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__SEARCH, abort); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_attribute related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ static bool -+ sepgsql_attribute_common(Oid relOid, AttrNumber attnum, -+ uint32 required, bool abort) -+ { -+ Form_pg_attribute attForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ char auname[NAMEDATALEN * 2 + 3]; -+ bool rc = true; -+ -+ /* Caller prevent case when relkind != RELKIND_RELATION */ -+ Assert(get_rel_relkind(relOid) == RELKIND_RELATION); -+ -+ tuple = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(relOid), -+ Int16GetDatum(attnum), -+ 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for attribute %d of relation %u", -+ attnum, relOid); -+ attForm = (Form_pg_attribute) GETSTRUCT(tuple); -+ -+ /* -+ * NOTE: when a table to be dropped, corresponding attributes -+ * are also removed. Some of them can be already logically -+ * dropped using ALTER TABLE ... DROP statement. -+ * In this case, SE-PostgreSQL does not check anything. -+ * If any other situation touches dropped column, it is a bug. -+ */ -+ if (attForm->attisdropped) -+ goto skip; -+ -+ sprintf(auname, "%s.%s", get_rel_name(relOid), NameStr(attForm->attname)); -+ -+ sid = sepgsqlGetTupleSecid(AttributeRelationId, tuple, &tclass); -+ -+ rc = sepgsqlClientHasPerms(sid, tclass, required, auname, abort); -+ -+ skip: -+ ReleaseSysCache(tuple); -+ -+ return rc; -+ } -+ -+ Oid -+ sepgsql_attribute_create(Oid relOid, ColumnDef *cdef) -+ { -+ sepgsql_sid_t sid; -+ char relkind; -+ -+ if (!sepgsqlIsEnabled()) -+ { -+ if (cdef->secLabel) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SELinux is disabled now"))); -+ return InvalidOid; -+ } -+ -+ relkind = get_rel_relkind(relOid); -+ if (relkind == RELKIND_RELATION) -+ { -+ char auname[NAMEDATALEN * 2 + 3]; -+ -+ if (!cdef->secLabel) -+ sid = sepgsqlGetDefaultColumnSecid(relOid); -+ else -+ { -+ char *label = strVal(((DefElem *)cdef->secLabel)->arg); -+ -+ sid.relid = AttributeRelationId; -+ sid.secid = securityTransSecLabelIn(sid.relid, label); -+ } -+ -+ sprintf(auname, "%s.%s", get_rel_name(relOid), cdef->colname); -+ sepgsqlClientHasPerms(sid, -+ SEPG_CLASS_DB_COLUMN, -+ SEPG_DB_COLUMN__CREATE, -+ auname, true); -+ } -+ else -+ { -+ /* no need to check for toast relation */ -+ if (relkind != RELKIND_TOASTVALUE) -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true); -+ return InvalidOid; -+ } -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_attribute_alter(Oid relOid, const char *attname) -+ { -+ AttrNumber attno; -+ char relkind; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* -+ * If the target attribute does not exist, an error -+ * shall be raised later. -+ */ -+ attno = get_attnum(relOid, attname); -+ if (attno == InvalidAttrNumber) -+ return; -+ -+ relkind = get_rel_relkind(relOid); -+ if (relkind == RELKIND_RELATION) -+ { -+ sepgsql_attribute_common(relOid, attno, SEPG_DB_COLUMN__SETATTR, true); -+ } -+ else if (relkind != RELKIND_TOASTVALUE) -+ { -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true); -+ } -+ } -+ -+ void -+ sepgsql_attribute_drop(Oid relOid, AttrNumber attnum) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* -+ * We only need to check db_column:{drop} when relkind equals -+ * RELKIND_RELATION, because db_xxx:{drop} permission is already -+ * checked in other cases. (e.g DROP SEQUENCE, ...) -+ */ -+ if (get_rel_relkind(relOid) == RELKIND_RELATION) -+ sepgsql_attribute_common(relOid, attnum, -+ SEPG_DB_COLUMN__DROP, true); -+ } -+ -+ void -+ sepgsql_attribute_grant(Oid relOid, AttrNumber attnum) -+ { -+ char relkind; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ relkind = get_rel_relkind(relOid); -+ if (relkind == RELKIND_RELATION) -+ { -+ sepgsql_attribute_common(relOid, attnum, SEPG_DB_COLUMN__SETATTR, true); -+ } -+ else if (relkind != RELKIND_TOASTVALUE) -+ { -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true); -+ } -+ } -+ -+ Oid -+ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, DefElem *newLabel) -+ { -+ sepgsql_sid_t sid; -+ char auname[NAMEDATALEN * 2 + 3]; -+ -+ if (!sepgsqlIsEnabled()) -+ { -+ if (!newLabel) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SELinux is disabled now"))); -+ return InvalidOid; -+ } -+ -+ Assert(get_rel_relkind(relOid) == RELKIND_RELATION); -+ -+ sid.relid = AttributeRelationId; -+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg)); -+ -+ /* db_column:{setattr relabelfrom} */ -+ sepgsql_attribute_common(relOid, attnum, -+ SEPG_DB_COLUMN__SETATTR | -+ SEPG_DB_COLUMN__RELABELFROM, true); -+ -+ /* db_column:{relabelto} */ -+ sprintf(auname, "%s.%s", -+ get_rel_name(relOid), -+ get_attname(relOid, attnum)); -+ sepgsqlClientHasPerms(sid, -+ SEPG_CLASS_DB_COLUMN, -+ SEPG_DB_COLUMN__RELABELTO, -+ auname, true); -+ -+ return sid.secid; -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_class related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ static bool -+ sepgsql_relation_common(Oid relOid, uint32 required, bool abort) -+ { -+ Form_pg_class relForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ bool rc; -+ -+ tuple = SearchSysCache(RELOID, -+ ObjectIdGetDatum(relOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for relation %u", relOid); -+ relForm = (Form_pg_class) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(RelationRelationId, tuple, &tclass); -+ rc = sepgsqlClientHasPerms(sid, tclass, required, -+ NameStr(relForm->relname), abort); -+ -+ ReleaseSysCache(tuple); -+ -+ return rc; -+ } -+ -+ /* -+ * sepgsql_relation_create -+ * It returns an array of security identifier for the new table -+ * and columns to be assigned. The corresponding security labels -+ * are already checked for db_table/db_sequence/db_column:{create} -+ * permission. -+ * In the default labeling rule, a column inherits the security -+ * label of its table, but we cannot refer it using system caches, -+ * because the command counter is not incremented under the -+ * heap_create_with_catalog(). Thus, we need to compute and check -+ * them prior to the actual creation of table and columns. -+ */ -+ Oid * -+ sepgsql_relation_create(const char *relName, -+ char relkind, -+ TupleDesc tupDesc, -+ Oid nspOid, -+ DefElem *relLabel, -+ List *colList, -+ bool createAs, -+ bool permission) -+ { -+ Oid *secLabels; -+ sepgsql_sid_t relsid; -+ uint16 tclass; -+ uint32 required; -+ int index; -+ -+ if (!sepgsqlIsEnabled()) -+ return NULL; -+ -+ switch (relkind) -+ { -+ case RELKIND_RELATION: -+ if (!relLabel) -+ relsid = sepgsqlGetDefaultTableSecid(nspOid); -+ else -+ { -+ relsid.relid = RelationRelationId; -+ relsid.secid = securityTransSecLabelIn(relsid.relid, -+ strVal(relLabel->arg)); -+ } -+ tclass = SEPG_CLASS_DB_TABLE; -+ required = SEPG_DB_TABLE__CREATE; -+ if (createAs) -+ required |= SEPG_DB_TABLE__INSERT; -+ break; -+ -+ case RELKIND_SEQUENCE: -+ if (!relLabel) -+ relsid = sepgsqlGetDefaultSequenceSecid(nspOid); -+ else -+ { -+ relsid.relid = RelationRelationId; -+ relsid.secid = securityTransSecLabelIn(relsid.relid, -+ strVal(relLabel->arg)); -+ } -+ tclass = SEPG_CLASS_DB_SEQUENCE; -+ required = SEPG_DB_SEQUENCE__CREATE; -+ break; -+ -+ default: -+ if (!relLabel) -+ relsid = sepgsqlGetDefaultTupleSecid(RelationRelationId); -+ else -+ { -+ /* should not be happen */ -+ relsid.relid = RelationRelationId; -+ relsid.secid = securityTransSecLabelIn(relsid.relid, -+ strVal(relLabel->arg)); -+ } -+ tclass = SEPG_CLASS_DB_TUPLE; -+ required = SEPG_DB_TUPLE__INSERT; -+ break; -+ } -+ -+ /* -+ * The secLabeld array stores security identifiers to be assigned -+ * on the new table and columns. -+ * -+ * secLabels[0] is security identifier of the table. -+ * secLabels[attnum - FirstLowInvalidHeapAttributeNumber] -+ * is security identifier of columns (if necessary). -+ */ -+ secLabels = palloc0(sizeof(Oid) * (tupDesc->natts -+ - FirstLowInvalidHeapAttributeNumber)); -+ -+ /* relation's security identifier to be assigned on */ -+ secLabels[0] = relsid.secid; -+ -+ /* -+ * Note that this hook can be called during initdb processes. -+ * It is an exception of access controls, so we skip any checks. -+ * -+ * And, we don't need any checks for toast relations, because -+ * it is a quite internal stuff. -+ */ -+ if (permission) -+ { -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_table:{create}, db_sequence:{create} or db_tuple:{insert} */ -+ sepgsqlClientHasPerms(relsid, tclass, required, relName, true); -+ } -+ -+ /* no individual security context expect for RELKIND_RELATION */ -+ if (relkind != RELKIND_RELATION) -+ return secLabels; -+ -+ /* -+ * db_column:{create} permission -+ */ -+ for (index = FirstLowInvalidHeapAttributeNumber + 1; -+ index < tupDesc->natts; -+ index++) -+ { -+ Form_pg_attribute attr; -+ sepgsql_sid_t attsid = { InvalidOid, InvalidOid }; -+ char attname[NAMEDATALEN * 2 + 3]; -+ ListCell *l; -+ -+ /* skip unnecessary attributes */ -+ if (index == ObjectIdAttributeNumber && !tupDesc->tdhasoid) -+ continue; -+ -+ if (index < 0) -+ attr = SystemAttributeDefinition(index, tupDesc->tdhasoid); -+ else -+ attr = tupDesc->attrs[index]; -+ -+ /* Is there any given security context? */ -+ foreach (l, colList) -+ { -+ ColumnDef *cdef = lfirst(l); -+ -+ if (cdef->secLabel && -+ strcmp(cdef->colname, NameStr(attr->attname)) == 0) -+ { -+ attsid.relid = AttributeRelationId; -+ attsid.secid = securityTransSecLabelIn(attsid.relid, -+ strVal(((DefElem *)cdef->secLabel)->arg)); -+ break; -+ } -+ } -+ -+ /* default security context, if not given */ -+ if (!SidIsValid(attsid)) -+ attsid = sepgsqlClientCreateSecid(relsid, -+ SEPG_CLASS_DB_COLUMN, -+ AttributeRelationId); -+ if (permission) -+ { -+ required = SEPG_DB_COLUMN__CREATE; -+ -+ if (createAs) -+ required |= SEPG_DB_COLUMN__INSERT; -+ -+ /* db_column:{create (insert)} */ -+ sprintf(attname, "%s.%s", relName, NameStr(attr->attname)); -+ sepgsqlClientHasPerms(attsid, -+ SEPG_CLASS_DB_COLUMN, -+ required, attname, true); -+ } -+ /* column's security identifier to be assigend on */ -+ secLabels[index - FirstLowInvalidHeapAttributeNumber] = attsid.secid; -+ } -+ -+ return secLabels; -+ } -+ -+ /* -+ * sepgsql_relation_copy -+ * It returns an array of security identifier of table and columns -+ * to be copied on make_new_heap(). It actually create a new temporary -+ * relation and insert all the tuples within original one into the -+ * temporary one, but swap_relation_files() swaps their file nodes. -+ * Thus, there are no changes from the viewpoint of users. -+ * SE-PostgreSQL also does not check and change anything. It simply -+ * copies security identifier of the source relation to the destination -+ * relation. -+ */ -+ Oid * -+ sepgsql_relation_copy(Relation src) -+ { -+ Oid *secLabels; -+ HeapTuple tuple; -+ Oid relOid = RelationGetRelid(src); -+ int index; -+ -+ if (!sepgsqlIsEnabled()) -+ return NULL; -+ -+ /* see the comment at sepgsqlCreateTableColumn*/ -+ secLabels = palloc0(sizeof(Oid) * (RelationGetDescr(src)->natts -+ - FirstLowInvalidHeapAttributeNumber)); -+ -+ /* copy table's security identifier */ -+ tuple = SearchSysCache(RELOID, -+ ObjectIdGetDatum(relOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for relation \"%s\"", -+ RelationGetRelationName(src)); -+ -+ secLabels[0] = HeapTupleGetSecid(tuple); -+ -+ ReleaseSysCache(tuple); -+ -+ /* copy column's security identifier */ -+ for (index = FirstLowInvalidHeapAttributeNumber + 1; -+ index < RelationGetDescr(src)->natts; -+ index++) -+ { -+ Form_pg_attribute attr; -+ -+ if (index < 0) -+ attr = SystemAttributeDefinition(index, true); -+ else -+ attr = RelationGetDescr(src)->attrs[index]; -+ -+ tuple = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(relOid), -+ Int16GetDatum(attr->attnum), -+ 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ continue; -+ -+ secLabels[index - FirstLowInvalidHeapAttributeNumber] -+ = HeapTupleGetSecid(tuple); -+ -+ ReleaseSysCache(tuple); -+ } -+ -+ return secLabels; -+ } -+ -+ void -+ sepgsql_relation_alter(Oid relOid, const char *newName, Oid newNsp) -+ { -+ Form_pg_class relForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(RELOID, -+ ObjectIdGetDatum(relOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for relation %u", relOid); -+ relForm = (Form_pg_class) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(RelationRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TABLE__SETATTR, -+ NameStr(relForm->relname), true); -+ -+ /* db_schema:{add_name remove_name}, if necessary */ -+ if (newName || OidIsValid(newNsp)) -+ { -+ if (!OidIsValid(newNsp)) -+ sepgsql_schema_common(relForm->relnamespace, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ else -+ { -+ sepgsql_schema_common(relForm->relnamespace, -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ sepgsql_schema_common(newNsp, SEPG_DB_SCHEMA__ADD_NAME, true); -+ } -+ } -+ ReleaseSysCache(tuple); -+ } -+ -+ void -+ sepgsql_relation_drop(Oid relOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ if (get_rel_relkind(relOid) == RELKIND_TOASTVALUE) -+ return; -+ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__DROP, true); -+ } -+ -+ void -+ sepgsql_relation_grant(Oid relOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true); -+ } -+ -+ Oid -+ sepgsql_relation_relabel(Oid relOid, DefElem *newLabel) -+ { -+ sepgsql_sid_t sid; -+ char relkind; -+ -+ if (!sepgsqlIsEnabled()) -+ { -+ if (newLabel) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SELinux is disabled now"))); -+ return InvalidOid; -+ } -+ -+ relkind = get_rel_relkind(relOid); -+ if (relkind != RELKIND_RELATION && relkind != RELKIND_SEQUENCE) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("Unable to set security label on \"%s\"", -+ get_rel_name(relOid)))); -+ -+ /* input security context */ -+ sid.relid = RelationRelationId; -+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg)); -+ -+ /* db_table/db_sequence:{setattr relabelfrom} */ -+ sepgsql_relation_common(relOid, -+ SEPG_DB_TABLE__SETATTR | -+ SEPG_DB_TABLE__RELABELFROM, true); -+ -+ /* db_table/db_sequence:{relabelto} */ -+ sepgsqlClientHasPerms(sid, -+ (relkind == RELKIND_RELATION -+ ? SEPG_CLASS_DB_TABLE -+ : SEPG_CLASS_DB_SEQUENCE), -+ SEPG_DB_TABLE__RELABELTO, -+ get_rel_name(relOid), true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_relation_get_transaction_id(Oid relOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__GETATTR, true); -+ } -+ -+ void -+ sepgsql_relation_copy_definition(Oid relOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__GETATTR, true); -+ } -+ -+ void -+ sepgsql_relation_truncate(Relation rel) -+ { -+ HeapScanDesc scan; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ Assert(RelationGetForm(rel)->relkind == RELKIND_RELATION); -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* check db_table:{delete} permission */ -+ sepgsql_relation_common(RelationGetRelid(rel), -+ SEPG_DB_TABLE__DELETE, true); -+ -+ /* row-level access control is enabled? */ -+ if (!sepostgresql_row_level) -+ return; -+ -+ /* check db_tuple:{delete} permission */ -+ scan = heap_beginscan(rel, SnapshotNow, 0, NULL); -+ -+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) -+ { -+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel), tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__DELETE, -+ NULL, true); -+ } -+ heap_endscan(scan); -+ } -+ -+ void -+ sepgsql_relation_lock(Oid relOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ if (get_rel_relkind(relOid) != RELKIND_RELATION) -+ return; -+ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__LOCK, true); -+ } -+ -+ void -+ sepgsql_view_replace(Oid viewOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ Assert(get_rel_relkind(viewOid) == RELKIND_VIEW); -+ -+ sepgsql_relation_common(viewOid, SEPG_DB_TABLE__SETATTR, true); -+ } -+ -+ void -+ sepgsql_index_create(Oid relOid, Oid nspOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* db_table:{setattr} */ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ } -+ -+ void -+ sepgsql_sequence_get_value(Oid seqOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ Assert(get_rel_relkind(seqOid) == RELKIND_SEQUENCE); -+ -+ sepgsql_relation_common(seqOid, SEPG_DB_SEQUENCE__GET_VALUE, true); -+ } -+ -+ void -+ sepgsql_sequence_next_value(Oid seqOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ Assert(get_rel_relkind(seqOid) == RELKIND_SEQUENCE); -+ -+ sepgsql_relation_common(seqOid, SEPG_DB_SEQUENCE__NEXT_VALUE, true); -+ } -+ -+ void -+ sepgsql_sequence_set_value(Oid seqOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ Assert(get_rel_relkind(seqOid) == RELKIND_SEQUENCE); -+ -+ sepgsql_relation_common(seqOid, SEPG_DB_SEQUENCE__SET_VALUE, true); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_proc related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ static bool -+ sepgsql_proc_common(Oid procOid, uint32 required, bool abort) -+ { -+ sepgsql_sid_t sid; -+ HeapTuple tuple; -+ uint16 tclass; -+ const char *auname; -+ bool rc; -+ -+ tuple = SearchSysCache(PROCOID, -+ ObjectIdGetDatum(procOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for procedure: %u", procOid); -+ -+ auname = NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname); -+ sid = sepgsqlGetTupleSecid(ProcedureRelationId, tuple, &tclass); -+ -+ rc = sepgsqlClientHasPerms(sid, tclass, required, auname, abort); -+ -+ ReleaseSysCache(tuple); -+ -+ return rc; -+ } -+ -+ Oid -+ sepgsql_proc_create(const char *procName, HeapTuple oldTup, -+ Oid nspOid, Oid langOid, DefElem *newLabel) -+ { -+ sepgsql_sid_t sid; -+ //HeapTuple tuple; -+ uint32 required; -+ //bool trusted; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ if (!HeapTupleIsValid(oldTup)) -+ { -+ /* create a new function */ -+ required = SEPG_DB_PROCEDURE__CREATE; -+ if (!newLabel) -+ sid = sepgsqlGetDefaultProcedureSecid(nspOid); -+ else -+ { -+ sid.relid = ProcedureRelationId; -+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg)); -+ } -+ } -+ else if (!newLabel) -+ { -+ /* replace an existing function, without any label */ -+ required = SEPG_DB_PROCEDURE__SETATTR; -+ sid = sepgsqlGetTupleSecid(ProcedureRelationId, oldTup, NULL); -+ } -+ else -+ { -+ /* replace an existing function, with relabeling */ -+ sepgsql_proc_common(HeapTupleGetOid(oldTup), -+ SEPG_DB_PROCEDURE__SETATTR | -+ SEPG_DB_PROCEDURE__RELABELFROM, true); -+ -+ required = SEPG_DB_PROCEDURE__RELABELTO; -+ sid = sepgsqlGetTupleSecid(ProcedureRelationId, oldTup, NULL); -+ } -+ -+ #if 0 -+ /* Procedural language is trusted? */ -+ tuple = SearchSysCache(LANGOID, -+ ObjectIdGetDatum(langOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for procedural langugage: %u", langOid); -+ -+ trusted = ((Form_pg_language) GETSTRUCT(tuple))->lanpltrusted; -+ if (!trusted) -+ required |= SEPG_DB_PROCEDURE__UNTRUSTED; -+ -+ ReleaseSysCache(tuple); -+ #endif -+ -+ /* check it */ -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_PROCEDURE, -+ required, procName, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_proc_alter(Oid procOid, const char *newName, Oid newNsp) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); -+ if (newName || OidIsValid(newNsp)) -+ { -+ HeapTuple tuple; -+ Oid oldNsp; -+ -+ tuple = SearchSysCache(PROCOID, -+ ObjectIdGetDatum(procOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for function %u", procOid); -+ -+ oldNsp = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace; -+ -+ ReleaseSysCache(tuple); -+ -+ if (!OidIsValid(newNsp)) -+ { -+ sepgsql_schema_common(oldNsp, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ } -+ else -+ { -+ sepgsql_schema_common(oldNsp, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ sepgsql_schema_common(newNsp, SEPG_DB_SCHEMA__ADD_NAME, true); -+ } -+ } -+ } -+ -+ void -+ sepgsql_proc_drop(Oid procOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__DROP, true); -+ } -+ -+ void -+ sepgsql_proc_grant(Oid procOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); -+ } -+ -+ Oid -+ sepgsql_proc_relabel(Oid procOid, DefElem *newLabel) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ { -+ if (newLabel) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SELinux is disabled now"))); -+ return InvalidOid; -+ } -+ -+ sid.relid = ProcedureRelationId; -+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(newLabel->arg)); -+ -+ /* db_procedure:{setattr relabelfrom} for older seclabel */ -+ sepgsql_proc_common(procOid, -+ SEPG_DB_PROCEDURE__SETATTR | -+ SEPG_DB_PROCEDURE__RELABELFROM, true); -+ /* db_procedure:{relabelto} for newer seclabel */ -+ sepgsqlClientHasPerms(sid, -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_DB_PROCEDURE__RELABELTO, -+ get_func_name(procOid), true); -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_proc_execute(Oid procOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__EXECUTE, true); -+ } -+ -+ bool -+ sepgsql_proc_hint_inlined(HeapTuple protup) -+ { -+ security_context_t newcon; -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return true; -+ -+ if (!sepgsql_proc_common(HeapTupleGetOid(protup), -+ SEPG_DB_PROCEDURE__EXECUTE, false)) -+ return false; -+ /* -+ * If the security context of client is unchange -+ * before or after invocation of the functions, -+ * it is not a trusted procedure, so it can be -+ * inlined due to performance purpose. -+ */ -+ sid = sepgsqlGetTupleSecid(ProcedureRelationId, protup, NULL); -+ -+ newcon = sepgsqlClientCreateLabel(sid, SEPG_CLASS_PROCESS); -+ -+ if (strcmp(sepgsqlGetClientLabel(), newcon) == 0) -+ return true; -+ -+ return false; -+ } -+ -+ bool -+ sepgsql_proc_entrypoint(HeapTuple protup) -+ { -+ security_context_t newcon; -+ sepgsql_sid_t proSid; -+ -+ if (!sepgsqlIsEnabled()) -+ return false; -+ -+ proSid = sepgsqlGetTupleSecid(ProcedureRelationId, -+ protup, NULL); -+ -+ newcon = sepgsqlClientCreateLabel(proSid, SEPG_CLASS_PROCESS); -+ -+ /* Do nothing, if it is not a trusted procedure */ -+ if (strcmp(newcon, sepgsqlGetClientLabel()) == 0) -+ return false; -+ -+ /* check db_procedure:{entrypoint} */ -+ sepgsqlClientHasPerms(proSid, -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_DB_PROCEDURE__ENTRYPOINT, -+ NULL, true); -+ -+ /* check process:{transition} */ -+ sepgsqlComputePerms(sepgsqlGetClientLabel(), -+ newcon, -+ SEPG_CLASS_PROCESS, -+ SEPG_PROCESS__TRANSITION, -+ NULL, true); -+ -+ return true; -+ } -+ -+ char * -+ sepgsql_proc_trusted(HeapTuple protup, MemoryContext mcxt) -+ { -+ MemoryContext oldcxt; -+ security_context_t newcon; -+ sepgsql_sid_t proSid; -+ -+ if (!sepgsqlIsEnabled()) -+ return NULL; -+ -+ proSid = sepgsqlGetTupleSecid(ProcedureRelationId, protup, NULL); -+ -+ oldcxt = MemoryContextSwitchTo(mcxt); -+ -+ newcon = sepgsqlClientCreateLabel(proSid, SEPG_CLASS_PROCESS); -+ -+ MemoryContextSwitchTo(oldcxt); -+ -+ return newcon; -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_cast related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ Oid -+ sepgsql_cast_create(Oid sourceTypOid, Oid targetTypOid, Oid funcOid) -+ { -+ sepgsql_sid_t sid; -+ char audit_buffer[2*NAMEDATALEN+10]; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(CastRelationId); -+ -+ snprintf(audit_buffer, sizeof(audit_buffer), "%s::%s", -+ format_type_be(sourceTypOid), format_type_be(targetTypOid)); -+ -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ audit_buffer, true); -+ -+ if (OidIsValid(funcOid)) -+ sepgsql_proc_common(funcOid, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_cast_drop(Oid castOid) -+ { -+ Form_pg_cast castForm; -+ Relation rel; -+ HeapTuple tuple; -+ ScanKeyData skey; -+ SysScanDesc scan; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ char audit_buffer[2*NAMEDATALEN+10]; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ rel = heap_open(CastRelationId, AccessShareLock); -+ -+ ScanKeyInit(&skey, -+ ObjectIdAttributeNumber, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(castOid)); -+ -+ scan = systable_beginscan(rel, CastOidIndexId, true, -+ SnapshotNow, 1, &skey); -+ tuple = systable_getnext(scan); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "could not find tuple for cast: %u", castOid); -+ -+ castForm = (Form_pg_cast) GETSTRUCT(tuple); -+ -+ snprintf(audit_buffer, sizeof(audit_buffer), "%s::%s", -+ format_type_be(castForm->castsource), -+ format_type_be(castForm->casttarget)); -+ -+ sid = sepgsqlGetTupleSecid(CastRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__DELETE, -+ audit_buffer, true); -+ -+ systable_endscan(scan); -+ -+ heap_close(rel, AccessShareLock); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_conversion related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ Oid -+ sepgsql_conversion_create(const char *convName, Oid nspOid, Oid procOid) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(ConversionRelationId); -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ convName, true); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_procedure:{install} */ -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_conversion_alter(Oid convOid, const char *newName) -+ { -+ Form_pg_conversion convForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(CONVOID, -+ ObjectIdGetDatum(convOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for conversion %u", convOid); -+ convForm = (Form_pg_conversion) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(ConversionRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__UPDATE, -+ NameStr(convForm->conname), true); -+ if (newName) -+ { -+ Oid nspOid = convForm->connamespace; -+ -+ sepgsql_schema_common(nspOid, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ } -+ ReleaseSysCache(tuple); -+ } -+ -+ void -+ sepgsql_conversion_drop(Oid convOid) -+ { -+ Form_pg_conversion convForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(CONVOID, -+ ObjectIdGetDatum(convOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for conversion %u", convOid); -+ convForm = (Form_pg_conversion) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(ConversionRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__UPDATE, -+ NameStr(convForm->conname), true); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(convForm->connamespace, -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ ReleaseSysCache(tuple); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_foreign_data_wrapper related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ static bool -+ sepgsql_fdw_common(Oid fdwOid, uint32 required, bool abort) -+ { -+ Form_pg_foreign_data_wrapper fdwForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ bool rc; -+ -+ tuple = SearchSysCache(FOREIGNDATAWRAPPEROID, -+ ObjectIdGetDatum(fdwOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for FDW: %u", fdwOid); -+ fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(ForeignDataWrapperRelationId, tuple, &tclass); -+ rc = sepgsqlClientHasPerms(sid, tclass, required, -+ NameStr(fdwForm->fdwname), abort); -+ ReleaseSysCache(tuple); -+ -+ return rc; -+ } -+ -+ Oid -+ sepgsql_fdw_create(const char *fdwName, Oid fdwValidator) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(ForeignDataWrapperRelationId); -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ fdwName, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(fdwValidator)) -+ sepgsql_proc_common(fdwValidator, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_fdw_alter(Oid fdwOid, Oid newValidator) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__UPDATE, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(newValidator)) -+ sepgsql_proc_common(newValidator, SEPG_DB_PROCEDURE__INSTALL, true); -+ } -+ -+ void -+ sepgsql_fdw_drop(Oid fdwOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+ -+ void -+ sepgsql_fdw_grant(Oid fdwOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_foreign_server related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ static bool -+ sepgsql_foreign_server_common(Oid fsrvOid, uint32 required, bool abort) -+ { -+ Form_pg_foreign_server fsrvForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ bool rc; -+ -+ tuple = SearchSysCache(FOREIGNSERVEROID, -+ ObjectIdGetDatum(fsrvOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for foreign server %u", fsrvOid); -+ fsrvForm = (Form_pg_foreign_server) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(ForeignServerRelationId, tuple, &tclass); -+ rc = sepgsqlClientHasPerms(sid, tclass, required, -+ NameStr(fsrvForm->srvname), abort); -+ ReleaseSysCache(tuple); -+ -+ return rc; -+ } -+ -+ Oid -+ sepgsql_foreign_server_create(const char *fsrvName) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(ForeignServerRelationId); -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ fsrvName, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_foreign_server_alter(Oid fsrvOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_foreign_server_common(fsrvOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+ -+ void -+ sepgsql_foreign_server_drop(Oid fsrvOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_foreign_server_common(fsrvOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+ -+ void -+ sepgsql_foreign_server_grant(Oid fsrvOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_foreign_server_common(fsrvOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_language related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ static bool -+ sepgsql_language_common(Oid langOid, uint32 required, bool abort) -+ { -+ Form_pg_language langForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ bool rc; -+ -+ tuple = SearchSysCache(LANGOID, -+ ObjectIdGetDatum(langOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for language %u", langOid); -+ langForm = (Form_pg_language) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(LanguageRelationId, tuple, &tclass); -+ rc = sepgsqlClientHasPerms(sid, tclass, required, -+ NameStr(langForm->lanname), abort); -+ -+ ReleaseSysCache(tuple); -+ -+ return rc; -+ } -+ -+ Oid -+ sepgsql_language_create(const char *langName, Oid handlerOid, Oid validatorOid) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(LanguageRelationId); -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, langName, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(handlerOid)) -+ sepgsql_proc_common(handlerOid, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(validatorOid)) -+ sepgsql_proc_common(validatorOid, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_language_alter(Oid langOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_language_common(langOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+ -+ void -+ sepgsql_language_drop(Oid langOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_language_common(langOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+ -+ void -+ sepgsql_language_grant(Oid langOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_language_common(langOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_largeobject related security hooks -+ * (need to backport v8.5 feature) -+ * ------------------------------------------------------------ */ -+ static bool -+ sepgsql_largeobject_common(Oid loid, uint32 required, Snapshot snapshot) -+ { -+ Relation rel; -+ ScanKeyData skey; -+ SysScanDesc scan; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ char auname[64]; -+ bool rc; -+ -+ rel = heap_open(LargeObjectMetadataRelationId, AccessShareLock); -+ -+ ScanKeyInit(&skey, -+ ObjectIdAttributeNumber, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(loid)); -+ -+ scan = systable_beginscan(rel, LargeObjectMetadataOidIndexId, -+ true, snapshot, 1, &skey); -+ -+ tuple = systable_getnext(scan); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "largeobject %u lookup failed", loid); -+ -+ snprintf(auname, sizeof(auname), "blob:%u", loid); -+ -+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel), tuple, &tclass); -+ -+ rc = sepgsqlClientHasPerms(sid, tclass, required, auname, true); -+ -+ systable_endscan(scan); -+ -+ heap_close(rel, AccessShareLock); -+ -+ return rc; -+ } -+ -+ Oid -+ sepgsql_largeobject_create(Oid loid, Value *secLabel) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ if (!secLabel) -+ sid = sepgsqlGetDefaultBlobSecid(MyDatabaseId); -+ else -+ { -+ sid.relid = LargeObjectMetadataRelationId; -+ sid.secid = securityTransSecLabelIn(sid.relid, strVal(secLabel)); -+ } -+ -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__CREATE, -+ NULL, true); -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_largeobject_alter(Oid loid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_largeobject_common(loid, SEPG_DB_BLOB__SETATTR, SnapshotNow); -+ } -+ -+ void -+ sepgsql_largeobject_drop(Oid loid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_largeobject_common(loid, SEPG_DB_BLOB__DROP, SnapshotNow); -+ } -+ -+ void -+ sepgsql_largeobject_read(Oid loid, Snapshot snapshot) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_largeobject_common(loid, SEPG_DB_BLOB__READ, snapshot); -+ } -+ -+ void -+ sepgsql_largeobject_write(Oid loid, Snapshot snapshot) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_largeobject_common(loid, SEPG_DB_BLOB__WRITE, snapshot); -+ } -+ -+ void -+ sepgsql_largeobject_export(Oid loid, const char *filename) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_largeobject_common(loid, -+ SEPG_DB_BLOB__READ | -+ SEPG_DB_BLOB__EXPORT, SnapshotNow); -+ -+ sepgsql_file_write(filename); -+ } -+ -+ Oid -+ sepgsql_largeobject_import(Oid loid, const char *filename) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultBlobSecid(MyDatabaseId); -+ -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__CREATE | -+ SEPG_DB_BLOB__WRITE | -+ SEPG_DB_BLOB__IMPORT, -+ NULL, true); -+ -+ sepgsql_file_read(filename); -+ -+ return sid.secid; -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_opclass related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ Oid -+ sepgsql_opclass_create(const char *opcName, Oid nspOid) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(OperatorClassRelationId); -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ opcName, true); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_opclass_alter(Oid opcOid, const char *newName) -+ { -+ Form_pg_opclass opcForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(CLAOID, -+ ObjectIdGetDatum(opcOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for opclass %u", opcOid); -+ opcForm = (Form_pg_opclass) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(OperatorClassRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__UPDATE, -+ NameStr(opcForm->opcname), true); -+ -+ /* db_schema:{add_name remove_name} */ -+ if (newName) -+ { -+ sepgsql_schema_common(opcForm->opcnamespace, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ } -+ ReleaseSysCache(tuple); -+ } -+ -+ void -+ sepgsql_opclass_drop(Oid opcOid) -+ { -+ Form_pg_opclass opcForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(CLAOID, -+ ObjectIdGetDatum(opcOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for opclass %u", opcOid); -+ opcForm = (Form_pg_opclass) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(OperatorClassRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__UPDATE, -+ NameStr(opcForm->opcname), true); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(opcForm->opcnamespace, -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ ReleaseSysCache(tuple); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_opfamily related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ Oid -+ sepgsql_opfamily_create(const char *opfName, Oid nspOid) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(OperatorFamilyRelationId); -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ opfName, true); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_opfamily_alter(Oid opfOid, const char *newName) -+ { -+ Form_pg_opfamily opfForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(OPFAMILYOID, -+ ObjectIdGetDatum(opfOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for operator family: %u", opfOid); -+ opfForm = (Form_pg_opfamily) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(OperatorFamilyRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__UPDATE, -+ NameStr(opfForm->opfname), true); -+ if (newName) -+ { -+ sepgsql_schema_common(opfForm->opfnamespace, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ } -+ ReleaseSysCache(tuple); -+ } -+ -+ void -+ sepgsql_opfamily_drop(Oid opfOid) -+ { -+ Form_pg_opfamily opfForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(OPFAMILYOID, -+ ObjectIdGetDatum(opfOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for operator family: %u", opfOid); -+ opfForm = (Form_pg_opfamily) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(OperatorFamilyRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__DELETE, -+ NameStr(opfForm->opfname), true); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(opfForm->opfnamespace, -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ ReleaseSysCache(tuple); -+ } -+ -+ void -+ sepgsql_opfamily_add_operator(Oid opfOid, Oid operOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* currently, do nothing here */ -+ } -+ -+ void -+ sepgsql_opfamily_add_procedure(Oid opfOid, Oid procOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* -+ * Note that db_tuple:{setattr} is already checked at the -+ * earlier phase, so db_procedure:{install} is only needed. -+ */ -+ if (OidIsValid(procOid)) -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__INSTALL, true); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_operator related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ static bool -+ sepgsql_operator_common(Oid oprOid, uint32 required, bool abort) -+ { -+ Form_pg_operator oprForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ bool rc; -+ -+ tuple = SearchSysCache(OPEROID, -+ ObjectIdGetDatum(oprOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for operator: %u", oprOid); -+ oprForm = (Form_pg_operator) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(OperatorRelationId, tuple, &tclass); -+ rc = sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__DELETE, -+ NameStr(oprForm->oprname), abort); -+ -+ ReleaseSysCache(tuple); -+ -+ return rc; -+ } -+ -+ Oid -+ sepgsql_operator_create(const char *oprName, Oid oprOid, Oid nspOid, -+ Oid codeFn, Oid restFn, Oid joinFn) -+ { -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint32 required; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ if (!OidIsValid(oprOid)) -+ { -+ sid = sepgsqlGetDefaultTupleSecid(OperatorRelationId); -+ required = SEPG_DB_TUPLE__INSERT; -+ } -+ else -+ { -+ tuple = SearchSysCache(OPEROID, -+ ObjectIdGetDatum(oprOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for operator %u", oprOid); -+ -+ sid = sepgsqlGetTupleSecid(OperatorRelationId, tuple, NULL); -+ -+ ReleaseSysCache(tuple); -+ -+ required = SEPG_DB_TUPLE__UPDATE; -+ } -+ -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ required, oprName, true); -+ -+ /* db_schema:{add_name} checks */ -+ if (!OidIsValid(oprOid)) -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_procedure:{install} checks */ -+ if (OidIsValid(codeFn)) -+ sepgsql_proc_common(codeFn, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(restFn)) -+ sepgsql_proc_common(restFn, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(joinFn)) -+ sepgsql_proc_common(joinFn, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_operator_alter(Oid oprOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_operator_common(oprOid, SEPG_DB_TUPLE__UPDATE, true); -+ } -+ -+ void -+ sepgsql_operator_drop(Oid oprOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_operator_common(oprOid, SEPG_DB_TUPLE__DELETE, true); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_rewrite related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ void -+ sepgsql_rule_create(Oid relOid, const char *ruleName) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true); -+ } -+ -+ void -+ sepgsql_rule_drop(Oid relOid, const char *ruleName) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_trigger related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ void -+ sepgsql_trigger_create(Oid relOid, const char *trigName, Oid procOid) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* db_table:{setattr} */ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true); -+ -+ /* db_procedure:{install} */ -+ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__INSTALL, true); -+ } -+ -+ void -+ sepgsql_trigger_alter(Oid relOid, const char *trigName) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* db_table:{setattr} */ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true); -+ } -+ -+ void -+ sepgsql_trigger_drop(Oid relOid, const char *trigName) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* db_table:{setattr} */ -+ sepgsql_relation_common(relOid, SEPG_DB_TABLE__SETATTR, true); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_type related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ Oid -+ sepgsql_ts_config_create(const char *cfgName, Oid nspOid) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(TSConfigRelationId); -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ cfgName, true); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_ts_config_alter(Oid cfgOid, const char *newName) -+ { -+ Form_pg_ts_config cfgForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(TSCONFIGOID, -+ ObjectIdGetDatum(cfgOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search dictionary %u", cfgOid); -+ cfgForm = (Form_pg_ts_config) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(TSConfigRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__UPDATE, -+ NameStr(cfgForm->cfgname), true); -+ if (newName) -+ { -+ sepgsql_schema_common(cfgForm->cfgnamespace, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ } -+ ReleaseSysCache(tuple); -+ } -+ -+ void -+ sepgsql_ts_config_drop(Oid cfgOid) -+ { -+ Form_pg_ts_config cfgForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(TSCONFIGOID, -+ ObjectIdGetDatum(cfgOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search dictionary %u", cfgOid); -+ cfgForm = (Form_pg_ts_config) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(TSConfigRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__DELETE, -+ NameStr(cfgForm->cfgname), true); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(cfgForm->cfgnamespace, -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ ReleaseSysCache(tuple); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_type related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ Oid -+ sepgsql_ts_dict_create(const char *dictName, Oid nspOid) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(TSDictionaryRelationId); -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ dictName, true); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_ts_dict_alter(Oid dictOid, const char *newName) -+ { -+ Form_pg_ts_dict dictForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(TSDICTOID, -+ ObjectIdGetDatum(dictOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search dictionary %u", dictOid); -+ dictForm = (Form_pg_ts_dict) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(TSDictionaryRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__UPDATE, -+ NameStr(dictForm->dictname), true); -+ -+ /* db_schema:{add_name remove_name} */ -+ if (newName) -+ { -+ sepgsql_schema_common(dictForm->dictnamespace, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ } -+ ReleaseSysCache(tuple); -+ } -+ -+ void -+ sepgsql_ts_dict_drop(Oid dictOid) -+ { -+ Form_pg_ts_dict dictForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(TSDICTOID, -+ ObjectIdGetDatum(dictOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search dictionary %u", dictOid); -+ dictForm = (Form_pg_ts_dict) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(TSDictionaryRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__DELETE, -+ NameStr(dictForm->dictname), true); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(dictForm->dictnamespace, -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ ReleaseSysCache(tuple); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_type related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ Oid -+ sepgsql_ts_parser_create(const char *prsName, Oid nspOid, -+ Oid startFn, Oid tokenFn, Oid sendFn, -+ Oid headlineFn, Oid lextypeFn) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(TSParserRelationId); -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ prsName, true); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(startFn)) -+ sepgsql_proc_common(startFn, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(tokenFn)) -+ sepgsql_proc_common(tokenFn, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(sendFn)) -+ sepgsql_proc_common(sendFn, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(headlineFn)) -+ sepgsql_proc_common(headlineFn, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(lextypeFn)) -+ sepgsql_proc_common(lextypeFn, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_ts_parser_alter(Oid prsOid, const char *newName) -+ { -+ Form_pg_ts_parser prsForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(TSPARSEROID, -+ ObjectIdGetDatum(prsOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search parser %u", prsOid); -+ -+ prsForm = (Form_pg_ts_parser) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(TSParserRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__UPDATE, -+ NameStr(prsForm->prsname), true); -+ if (newName) -+ { -+ sepgsql_schema_common(prsForm->prsnamespace, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ } -+ ReleaseSysCache(tuple); -+ } -+ -+ void -+ sepgsql_ts_parser_drop(Oid prsOid) -+ { -+ Form_pg_ts_parser prsForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(TSPARSEROID, -+ ObjectIdGetDatum(prsOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search parser %u", prsOid); -+ -+ prsForm = (Form_pg_ts_parser) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(TSParserRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__DELETE, -+ NameStr(prsForm->prsname), true); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(prsForm->prsnamespace, -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ ReleaseSysCache(tuple); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_type related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ Oid -+ sepgsql_ts_template_create(const char *tmplName, Oid nspOid, -+ Oid initFn, Oid lexizeFn) -+ { -+ sepgsql_sid_t sid; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ sid = sepgsqlGetDefaultTupleSecid(TSTemplateRelationId); -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ SEPG_DB_TUPLE__INSERT, -+ tmplName, true); -+ -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(initFn)) -+ sepgsql_proc_common(initFn, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(lexizeFn)) -+ sepgsql_proc_common(lexizeFn, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_ts_template_alter(Oid tmplOid, const char *newName) -+ { -+ Form_pg_ts_template tmplForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(TSTEMPLATEOID, -+ ObjectIdGetDatum(tmplOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search template %u", tmplOid); -+ tmplForm = (Form_pg_ts_template) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(TSTemplateRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__UPDATE, -+ NameStr(tmplForm->tmplname), true); -+ if (newName) -+ { -+ sepgsql_schema_common(tmplForm->tmplnamespace, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ } -+ ReleaseSysCache(tuple); -+ } -+ -+ void -+ sepgsql_ts_template_drop(Oid tmplOid) -+ { -+ Form_pg_ts_template tmplForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(TSTEMPLATEOID, -+ ObjectIdGetDatum(tmplOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for text search template %u", tmplOid); -+ tmplForm = (Form_pg_ts_template) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(TSTemplateRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__DELETE, -+ NameStr(tmplForm->tmplname), true); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(tmplForm->tmplnamespace, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ ReleaseSysCache(tuple); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Pg_type related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ Oid -+ sepgsql_type_create(const char *typName, HeapTuple oldTup, Oid nspOid, -+ Oid inputProc, Oid outputProc, Oid recvProc, Oid sendProc, -+ Oid modinProc, Oid modoutProc, Oid analyzeProc) -+ { -+ sepgsql_sid_t sid; -+ uint32 required; -+ -+ if (!sepgsqlIsEnabled()) -+ return InvalidOid; -+ -+ if (!HeapTupleIsValid(oldTup)) -+ { -+ sid = sepgsqlGetDefaultTupleSecid(TypeRelationId); -+ required = SEPG_DB_TUPLE__INSERT; -+ } -+ else -+ { -+ sid = sepgsqlGetTupleSecid(TypeRelationId, oldTup, NULL); -+ required = SEPG_DB_TUPLE__UPDATE; -+ } -+ sepgsqlClientHasPerms(sid, SEPG_CLASS_DB_TUPLE, -+ required, typName, true); -+ /* db_schema:{add_name} */ -+ sepgsql_schema_common(nspOid, SEPG_DB_SCHEMA__ADD_NAME, true); -+ -+ /* db_procedure:{install} */ -+ if (OidIsValid(inputProc)) -+ sepgsql_proc_common(inputProc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(outputProc)) -+ sepgsql_proc_common(outputProc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(recvProc)) -+ sepgsql_proc_common(recvProc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(sendProc)) -+ sepgsql_proc_common(sendProc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(modinProc)) -+ sepgsql_proc_common(modinProc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(modoutProc)) -+ sepgsql_proc_common(modoutProc, SEPG_DB_PROCEDURE__INSTALL, true); -+ if (OidIsValid(analyzeProc)) -+ sepgsql_proc_common(analyzeProc, SEPG_DB_PROCEDURE__INSTALL, true); -+ -+ return sid.secid; -+ } -+ -+ void -+ sepgsql_type_alter(Oid typOid, const char *newName, Oid newNsp) -+ { -+ Form_pg_type typForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(TYPEOID, -+ ObjectIdGetDatum(typOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for type: %u", typOid); -+ typForm = (Form_pg_type) GETSTRUCT(tuple); -+ -+ sid = sepgsqlGetTupleSecid(TypeRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__UPDATE, -+ NameStr(typForm->typname), true); -+ -+ if (newName || OidIsValid(newNsp)) -+ { -+ Oid oldNsp = typForm->typnamespace; -+ -+ if (!OidIsValid(newNsp)) -+ { -+ sepgsql_schema_common(oldNsp, -+ SEPG_DB_SCHEMA__ADD_NAME | -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ } -+ else -+ { -+ sepgsql_schema_common(oldNsp, SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ sepgsql_schema_common(newNsp, SEPG_DB_SCHEMA__ADD_NAME, true); -+ } -+ } -+ ReleaseSysCache(tuple); -+ } -+ -+ void -+ sepgsql_type_drop(Oid typOid) -+ { -+ Form_pg_type typForm; -+ HeapTuple tuple; -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ tuple = SearchSysCache(TYPEOID, -+ ObjectIdGetDatum(typOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for type: %u", typOid); -+ typForm = (Form_pg_type) GETSTRUCT(tuple); -+ -+ if (typForm->typtype == TYPTYPE_COMPOSITE || -+ (typForm->typtype == TYPTYPE_BASE && OidIsValid(typForm->typarray))) -+ { -+ /* -+ * No need to check for composite type and implicitly -+ * declared array type here. -+ */ -+ ReleaseSysCache(tuple); -+ return; -+ } -+ -+ sid = sepgsqlGetTupleSecid(TypeRelationId, tuple, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__DELETE, -+ NameStr(typForm->typname), true); -+ -+ /* db_schema:{remove_name} */ -+ sepgsql_schema_common(typForm->typnamespace, -+ SEPG_DB_SCHEMA__REMOVE_NAME, true); -+ -+ ReleaseSysCache(tuple); -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Misc system object related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ -+ void -+ sepgsql_sysobj_drop(const ObjectAddress *object) -+ { -+ switch (object->classId) -+ { -+ case RelationRelationId: -+ if (object->objectSubId == 0) -+ sepgsql_relation_drop(object->objectId); -+ else -+ sepgsql_attribute_drop(object->objectId, -+ object->objectSubId); -+ break; -+ -+ case ProcedureRelationId: -+ sepgsql_proc_drop(object->objectId); -+ break; -+ -+ case TypeRelationId: -+ sepgsql_type_drop(object->objectId); -+ break; -+ -+ case CastRelationId: -+ sepgsql_cast_drop(object->objectId); -+ break; -+ -+ case ConversionRelationId: -+ sepgsql_conversion_drop(object->objectId); -+ break; -+ -+ case LanguageRelationId: -+ sepgsql_language_drop(object->objectId); -+ break; -+ -+ case OperatorRelationId: -+ sepgsql_operator_drop(object->objectId); -+ break; -+ -+ case OperatorClassRelationId: -+ sepgsql_opclass_drop(object->objectId); -+ break; -+ -+ case OperatorFamilyRelationId: -+ sepgsql_opfamily_drop(object->objectId); -+ break; -+ -+ case NamespaceRelationId: -+ sepgsql_schema_drop(object->objectId); -+ break; -+ -+ case TSParserRelationId: -+ sepgsql_ts_parser_drop(object->objectId); -+ break; -+ -+ case TSDictionaryRelationId: -+ sepgsql_ts_dict_drop(object->objectId); -+ break; -+ -+ case TSTemplateRelationId: -+ sepgsql_ts_template_drop(object->objectId); -+ break; -+ -+ case TSConfigRelationId: -+ sepgsql_ts_config_drop(object->objectId); -+ break; -+ -+ case AuthIdRelationId: -+ break; -+ -+ case DatabaseRelationId: -+ sepgsql_database_drop(object->objectId); -+ break; -+ -+ case TableSpaceRelationId: -+ break; -+ -+ case ForeignDataWrapperRelationId: -+ sepgsql_fdw_drop(object->objectId); -+ break; -+ -+ case ForeignServerRelationId: -+ sepgsql_foreign_server_drop(object->objectId); -+ break; -+ -+ case UserMappingRelationId: -+ break; -+ -+ default: -+ /* do nothing */ -+ break; -+ } -+ } -+ -+ /* ------------------------------------------------------------ * -+ * -+ * Filesystem object related security hooks -+ * -+ * ------------------------------------------------------------ */ -+ static char * -+ sepgsql_getfilecon(const char *path) -+ { -+ security_context_t context; -+ char *result; -+ -+ if (getfilecon_raw(path, &context) < 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not get context of \"%s\": %m", path))); -+ -+ PG_TRY(); -+ { -+ result = pstrdup(context); -+ } -+ PG_CATCH(); -+ { -+ freecon(context); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(context); -+ -+ return result; -+ } -+ -+ static void -+ sepgsql_file_common(const char *filename, uint32 required, bool may_create) -+ { -+ struct stat stbuf; -+ -+ if (stat(filename, &stbuf) == 0) -+ { -+ uint16 tclass; -+ -+ /* -+ * Get file object class -+ */ -+ if (S_ISDIR(stbuf.st_mode)) -+ tclass = SEPG_CLASS_DIR; -+ else if (S_ISCHR(stbuf.st_mode)) -+ tclass = SEPG_CLASS_CHR_FILE; -+ else if (S_ISBLK(stbuf.st_mode)) -+ tclass = SEPG_CLASS_BLK_FILE; -+ else if (S_ISFIFO(stbuf.st_mode)) -+ tclass = SEPG_CLASS_FIFO_FILE; -+ else if (S_ISLNK(stbuf.st_mode)) -+ tclass = SEPG_CLASS_LNK_FILE; -+ else if (S_ISSOCK(stbuf.st_mode)) -+ tclass = SEPG_CLASS_SOCK_FILE; -+ else -+ tclass = SEPG_CLASS_FILE; -+ -+ /* -+ * Check permission (no cached operation) -+ */ -+ sepgsqlComputePerms(sepgsqlGetClientLabel(), -+ sepgsql_getfilecon(filename), -+ tclass, required, -+ filename, true); -+ } -+ else if (may_create) -+ { -+ /* -+ * If the required file is not found, we check permission to -+ * create a new file and required permission on the new file. -+ */ -+ security_context_t dcontext; -+ security_context_t ncontext; -+ char *copy = pstrdup(filename); -+ -+ /* -+ * Compute a security context for the new file -+ */ -+ dcontext = sepgsql_getfilecon(dirname(copy)); -+ -+ ncontext = sepgsqlComputeCreate(sepgsqlGetServerLabel(), -+ dcontext, -+ SEPG_CLASS_FILE); -+ /* -+ * Check permission (no cached operation) -+ */ -+ required |= SEPG_FILE__CREATE; -+ -+ sepgsqlComputePerms(sepgsqlGetClientLabel(), -+ sepgsql_getfilecon(filename), -+ SEPG_CLASS_FILE, -+ required, filename, true); -+ } -+ else -+ { -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not stat file \"%s\": %m", filename))); -+ } -+ } -+ -+ void -+ sepgsql_file_stat(const char *filename) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_file_common(filename, SEPG_FILE__GETATTR, false); -+ } -+ -+ void -+ sepgsql_file_read(const char *filename) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_file_common(filename, SEPG_FILE__READ, false); -+ } -+ -+ void -+ sepgsql_file_write(const char *filename) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ sepgsql_file_common(filename, SEPG_FILE__WRITE, true); -+ } -+ -+ /* -+ * TODO: add check for pg_ls_dir() -+ */ -diff -Nrpc blob/src/backend/security/sepgsql/checker.c sepgsql/src/backend/security/sepgsql/checker.c -*** blob/src/backend/security/sepgsql/checker.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/checker.c Sun Dec 20 18:14:37 2009 -*************** -*** 0 **** ---- 1,432 ---- -+ /* -+ * src/backend/security/sepgsql/checker.c -+ * walks on given Query tree and applies checks -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ -+ #include "access/sysattr.h" -+ #include "catalog/catalog.h" -+ #include "catalog/pg_largeobject.h" -+ #include "catalog/pg_security.h" -+ #include "miscadmin.h" -+ #include "security/sepgsql.h" -+ #include "storage/bufmgr.h" -+ #include "utils/lsyscache.h" -+ #include "utils/syscache.h" -+ #include "utils/tqual.h" -+ -+ /* -+ * fixupWholeRowReference -+ */ -+ static Bitmapset * -+ fixupWholeRowReference(Oid relid, int nattrs, Bitmapset *columns) -+ { -+ Bitmapset *result; -+ AttrNumber attno; -+ -+ attno = InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber; -+ -+ if (!bms_is_member(attno, columns)) -+ return columns; /* no need to fixup */ -+ -+ result = bms_copy(columns); -+ result = bms_del_member(result, attno); -+ -+ for (attno=1; attno <= nattrs; attno++) -+ { -+ Form_pg_attribute attform; -+ HeapTuple atttup; -+ -+ atttup = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(relid), -+ Int16GetDatum(attno), -+ 0, 0); -+ if (!HeapTupleIsValid(atttup)) -+ continue; -+ -+ attform = (Form_pg_attribute) GETSTRUCT(atttup); -+ if (!attform->attisdropped) -+ { -+ int cindex = attno - FirstLowInvalidHeapAttributeNumber; -+ result = bms_add_member(result, cindex); -+ } -+ ReleaseSysCache(atttup); -+ } -+ -+ return result; -+ } -+ -+ /* -+ * checkTabelColumnPerms -+ * This functions applies table/column level permissions for -+ * all the appeared ones in user's query, and raises an error -+ * if violated. -+ * It also applies a few hardwired policy which prevent to -+ * modified some of system catalogs. -+ */ -+ static void -+ checkTabelColumnPerms(Oid relid, Bitmapset *selected, Bitmapset *modified, -+ access_vector_t required) -+ { -+ Bitmapset *columns; -+ Bitmapset *selected_ex; -+ Bitmapset *modified_ex; -+ Form_pg_class relForm; -+ HeapTuple reltup; -+ sepgsql_sid_t relsid; -+ sepgsql_sid_t attsid; -+ AttrNumber attno; -+ uint16 tclass; -+ -+ /* -+ * Hardwired Policy: -+ * SE-PostgreSQL enforces that clients cannot modify system -+ * catalogs and access toast values using DML statements, -+ * except initial setting up phase. -+ */ -+ if (sepgsqlGetEnforce()) -+ { -+ if (IsSystemNamespace(get_rel_namespace(relid)) && -+ (required & (SEPG_DB_TABLE__UPDATE | -+ SEPG_DB_TABLE__INSERT | -+ SEPG_DB_TABLE__DELETE)) != 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL prevents to modidy \"%s\"", -+ get_rel_name(relid)))); -+ if (get_rel_relkind(relid) == RELKIND_TOASTVALUE) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SE-PostgreSQL prevents to access \"%s\"", -+ get_rel_name(relid)))); -+ } -+ -+ /* -+ * Check db_table:{...} or db_sequence permissions -+ */ -+ reltup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(relid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(reltup)) -+ elog(ERROR, "SELinux: cache lookup failed for relation %u", relid); -+ -+ relForm = (Form_pg_class) GETSTRUCT(reltup); -+ -+ relsid = sepgsqlGetTupleSecid(RelationRelationId, reltup, &tclass); -+ -+ if (tclass != SEPG_CLASS_DB_TABLE) -+ { -+ /* check db_sequence:{xxx} permission */ -+ if (tclass == SEPG_CLASS_DB_SEQUENCE) -+ { -+ if (required & SEPG_DB_TABLE__SELECT) -+ { -+ sepgsqlClientHasPerms(relsid, tclass, -+ SEPG_DB_SEQUENCE__GET_VALUE, -+ NameStr(relForm->relname), true); -+ } -+ } -+ ReleaseSysCache(reltup); -+ return; -+ } -+ sepgsqlClientHasPerms(relsid, tclass, required, -+ NameStr(relForm->relname), true); -+ -+ /* -+ * Check db_column:{...} permissions -+ */ -+ selected_ex = fixupWholeRowReference(relid, relForm->relnatts, selected); -+ modified_ex = fixupWholeRowReference(relid, relForm->relnatts, modified); -+ columns = bms_union(selected_ex, modified_ex); -+ -+ while ((attno = bms_first_member(columns)) >= 0) -+ { -+ Form_pg_attribute attForm; -+ HeapTuple atttup; -+ uint32 attperms = 0; -+ char auname[2 * NAMEDATALEN + 3]; -+ -+ if (bms_is_member(attno, selected_ex)) -+ attperms |= SEPG_DB_COLUMN__SELECT; -+ if (bms_is_member(attno, modified_ex)) -+ { -+ if (required & SEPG_DB_TABLE__UPDATE) -+ attperms |= SEPG_DB_COLUMN__UPDATE; -+ if (required & SEPG_DB_TABLE__INSERT) -+ attperms |= SEPG_DB_COLUMN__INSERT; -+ } -+ if (attperms == 0) -+ continue; -+ -+ /* remove the attribute number offset */ -+ attno += FirstLowInvalidHeapAttributeNumber; -+ atttup = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(relid), -+ Int16GetDatum(attno), -+ 0, 0); -+ if (!HeapTupleIsValid(atttup)) -+ elog(ERROR, "cache lookup failed for attribute %d of relation %u", -+ attno, relid); -+ -+ attForm = (Form_pg_attribute) GETSTRUCT(atttup); -+ if (attForm->attisdropped) -+ elog(ERROR, "attribute %d of relation %u does not exist", -+ attno, relid); -+ -+ snprintf(auname, sizeof(auname), "%s.%s", -+ NameStr(relForm->relname), -+ NameStr(attForm->attname)); -+ attsid = sepgsqlGetTupleSecid(AttributeRelationId, -+ atttup, &tclass); -+ sepgsqlClientHasPerms(attsid, tclass, attperms, auname, true); -+ -+ ReleaseSysCache(atttup); -+ } -+ -+ ReleaseSysCache(reltup); -+ -+ if (selected_ex != selected) -+ bms_free(selected_ex); -+ -+ if (modified_ex != modified) -+ bms_free(modified_ex); -+ -+ bms_free(columns); -+ } -+ -+ /* -+ * sepgsqlCheckQueryPerms -+ * It checks permission for all the required tables/columns on -+ * generic user queries. -+ */ -+ void -+ sepgsqlCheckRTEPerms(RangeTblEntry *rte) -+ { -+ access_vector_t required = 0; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ if (rte->rtekind != RTE_RELATION) -+ return; -+ -+ if (rte->requiredPerms & ACL_SELECT) -+ required |= SEPG_DB_TABLE__SELECT; -+ if (rte->requiredPerms & ACL_INSERT) -+ required |= SEPG_DB_TABLE__INSERT; -+ if (rte->requiredPerms & ACL_UPDATE) -+ { -+ /* -+ * ACL_SELECT_FOR_UPDATE is defined as an aliase of ACL_UPDATE, -+ * so we cannot determine whether the given relation is accessed -+ * with UPDATE statement or SELECT FOR SHARE/UPDATE immediately. -+ * UPDATE statements set a bit on rte->modifiedCols at least, -+ * so we use it as a watermark. -+ */ -+ if (!bms_is_empty(rte->modifiedCols)) -+ required |= SEPG_DB_TABLE__UPDATE; -+ else -+ required |= SEPG_DB_TABLE__LOCK; -+ } -+ if (rte->requiredPerms & ACL_DELETE) -+ required |= SEPG_DB_TABLE__DELETE; -+ -+ if (required == 0) -+ return; -+ -+ checkTabelColumnPerms(rte->relid, -+ rte->selectedCols, -+ rte->modifiedCols, -+ required); -+ } -+ -+ /* -+ * sepgsqlCheckCopyTable -+ * It checks permissions on COPY TO/FROM. -+ */ -+ void -+ sepgsqlCheckCopyTable(Relation rel, List *attnumlist, bool is_from) -+ { -+ Bitmapset *selected = NULL; -+ Bitmapset *modified = NULL; -+ ListCell *l; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* all checkes are done in sepgsqlCheckRTEPerms */ -+ if (!rel) -+ return; -+ -+ foreach (l, attnumlist) -+ { -+ AttrNumber attno = lfirst_int(l); -+ -+ attno -= FirstLowInvalidHeapAttributeNumber; -+ if (is_from) -+ modified = bms_add_member(modified, attno); -+ else -+ selected = bms_add_member(selected, attno); -+ } -+ -+ checkTabelColumnPerms(RelationGetRelid(rel), -+ selected, modified, -+ is_from ? SEPG_DB_TABLE__INSERT -+ : SEPG_DB_TABLE__SELECT); -+ } -+ -+ /* -+ * sepgsqlExecScan -+ * makes a decision on the given tuple. -+ */ -+ bool -+ sepgsqlExecScan(Relation rel, HeapTuple tuple, uint32 required, bool abort) -+ { -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled() || -+ !required || -+ RelationGetForm(rel)->relkind != RELKIND_RELATION || -+ RelationGetRelid(rel) == SecurityRelationId) -+ return true; -+ -+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel), tuple, &tclass); -+ /* -+ * Insert/Delete to an external attribute is equivalent to -+ * the set-attribute on the master -+ */ -+ if (sid.relid != RelationGetRelid(rel) && -+ (required & (SEPG_DB_TUPLE__INSERT | SEPG_DB_TUPLE__DELETE))) -+ { -+ required &= ~(SEPG_DB_TUPLE__INSERT | SEPG_DB_TUPLE__DELETE); -+ required |= SEPG_DB_TUPLE__UPDATE; -+ } -+ -+ return sepgsqlClientHasPerms(sid, tclass, required, NULL, abort); -+ } -+ -+ uint32 -+ sepgsqlSetupTuplePerms(RangeTblEntry *rte) -+ { -+ AclMode perms = 0; -+ -+ if (!sepgsqlIsEnabled()) -+ return 0; -+ -+ if (rte->rtekind != RTE_RELATION) -+ return 0; -+ -+ if (rte->requiredPerms & ACL_SELECT) -+ perms |= SEPG_DB_TUPLE__SELECT; -+ if (rte->requiredPerms & ACL_UPDATE && !bms_is_empty(rte->modifiedCols)) -+ perms |= SEPG_DB_TUPLE__UPDATE; -+ if (rte->requiredPerms & ACL_DELETE) -+ perms |= SEPG_DB_TUPLE__DELETE; -+ -+ /* -+ * Special case in pg_largeobject -+ */ -+ if (rte->relid == LargeObjectRelationId && -+ bms_is_member(Anum_pg_largeobject_data -+ - FirstLowInvalidHeapAttributeNumber, -+ rte->selectedCols)) -+ perms |= SEPG_DB_BLOB__READ; -+ -+ return perms; -+ } -+ -+ /* -+ * sepgsqlHeapTupleInsert -+ * It assigns a default security label, if no explicit security labels -+ * were given. In addition, it also checks db_tuple:{insert} for the -+ * tuple newly inserted, when it invoked from user's query. -+ */ -+ void -+ sepgsqlHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal) -+ { -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* -+ * Assign a default security label, if necessary -+ */ -+ if (HeapTupleHasSecid(newtup) && -+ !OidIsValid(HeapTupleGetSecid(newtup))) -+ sepgsqlSetDefaultSecid(rel, newtup); -+ -+ /* -+ * It does not check permission for the new tuples -+ * inserted by system internal stuff using -+ * simple_heap_insert(); -+ */ -+ if (internal) -+ return; -+ -+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel), -+ newtup, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, SEPG_DB_TUPLE__INSERT, NULL, true); -+ } -+ -+ /* -+ * sepgsqlHeapTupleUpdate -+ * It checks db_tuple:{relabelfrom relabelto} permission on -+ * the user queries. (Please note that it does not check -+ * system internal stuff via simple_heap_update) -+ */ -+ void -+ sepgsqlHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup) -+ { -+ Oid secid; -+ HeapTupleData oldtup; -+ Buffer oldbuf; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* -+ * heap_update() preserves the original security label -+ * of the given tuple, if no explicit security label -+ * is assigned on the newer version. -+ * In this case, db_tuple:{update} is already checked -+ * at the sepgsqlExecScan() hook, so we don't need to -+ * check anything more. -+ */ -+ secid = HeapTupleGetSecid(newtup); -+ if (!OidIsValid(secid)) -+ return; -+ -+ /* -+ * User gave an explicit security label -+ */ -+ ItemPointerCopy(otid, &oldtup.t_self); -+ if (!heap_fetch(rel, SnapshotAny, &oldtup, &oldbuf, false, NULL)) -+ elog(ERROR, "failed to fetch old version of the tuple"); -+ -+ if (secid != HeapTupleGetSecid(&oldtup)) -+ { -+ sepgsql_sid_t sid; -+ uint16 tclass; -+ -+ /* db_tuple:{relabelfrom} for older security context */ -+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel), -+ &oldtup, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__RELABELFROM, -+ NULL, true); -+ -+ /* db_tuple:{relabelto} for newer security label */ -+ sid = sepgsqlGetTupleSecid(RelationGetRelid(rel), -+ newtup, &tclass); -+ sepgsqlClientHasPerms(sid, tclass, -+ SEPG_DB_TUPLE__RELABELTO, -+ NULL, true); -+ } -+ ReleaseBuffer(oldbuf); -+ } -diff -Nrpc blob/src/backend/security/sepgsql/dummy.c sepgsql/src/backend/security/sepgsql/dummy.c -*** blob/src/backend/security/sepgsql/dummy.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/dummy.c Wed Jul 15 19:39:56 2009 -*************** -*** 0 **** ---- 1,79 ---- -+ /* -+ * src/backend/utils/sepgsql/dummy.c -+ * A set of stubs when SE-PostgreSQL is not activated -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ -+ #include "security/sepgsql.h" -+ -+ static Datum -+ unavailable_function(const char *fn_name) -+ { -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("function \"%s\" is not available", fn_name))); -+ PG_RETURN_VOID(); -+ } -+ -+ Datum -+ sepgsql_getcon(PG_FUNCTION_ARGS) -+ { -+ return unavailable_function(__FUNCTION__); -+ } -+ -+ Datum -+ sepgsql_server_getcon(PG_FUNCTION_ARGS) -+ { -+ return unavailable_function(__FUNCTION__); -+ } -+ -+ Datum -+ sepgsql_get_user(PG_FUNCTION_ARGS) -+ { -+ return unavailable_function(__FUNCTION__); -+ } -+ -+ Datum -+ sepgsql_get_role(PG_FUNCTION_ARGS) -+ { -+ return unavailable_function(__FUNCTION__); -+ } -+ -+ Datum -+ sepgsql_get_type(PG_FUNCTION_ARGS) -+ { -+ return unavailable_function(__FUNCTION__); -+ } -+ -+ Datum -+ sepgsql_get_range(PG_FUNCTION_ARGS) -+ { -+ return unavailable_function(__FUNCTION__); -+ } -+ -+ Datum -+ sepgsql_set_user(PG_FUNCTION_ARGS) -+ { -+ return unavailable_function(__FUNCTION__); -+ } -+ -+ Datum -+ sepgsql_set_role(PG_FUNCTION_ARGS) -+ { -+ return unavailable_function(__FUNCTION__); -+ } -+ -+ Datum -+ sepgsql_set_type(PG_FUNCTION_ARGS) -+ { -+ return unavailable_function(__FUNCTION__); -+ } -+ -+ Datum -+ sepgsql_set_range(PG_FUNCTION_ARGS) -+ { -+ return unavailable_function(__FUNCTION__); -+ } -diff -Nrpc blob/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/security/sepgsql/hooks.c -*** blob/src/backend/security/sepgsql/hooks.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/hooks.c Fri Dec 18 09:11:54 2009 -*************** -*** 0 **** ---- 1,239 ---- -+ /* -+ * src/backend/security/sepgsql/hooks.c -+ * SE-PostgreSQL security hooks -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ -+ #include "catalog/indexing.h" -+ #include "catalog/namespace.h" -+ #include "catalog/pg_database.h" -+ #include "catalog/pg_foreign_data_wrapper.h" -+ #include "catalog/pg_language.h" -+ #include "catalog/pg_largeobject.h" -+ #include "catalog/pg_namespace.h" -+ #include "catalog/pg_opclass.h" -+ #include "catalog/pg_operator.h" -+ #include "catalog/pg_opfamily.h" -+ #include "catalog/pg_proc.h" -+ #include "catalog/pg_security.h" -+ #include "catalog/pg_trigger.h" -+ #include "catalog/pg_ts_dict.h" -+ #include "catalog/pg_ts_parser.h" -+ #include "catalog/pg_ts_template.h" -+ #include "catalog/pg_type.h" -+ #include "catalog/pg_security.h" -+ #include "commands/dbcommands.h" -+ #include "miscadmin.h" -+ #include "security/sepgsql.h" -+ #include "utils/builtins.h" -+ #include "utils/fmgroids.h" -+ #include "utils/lsyscache.h" -+ #include "utils/syscache.h" -+ #include "utils/tqual.h" -+ -+ /* ------------------------------------------------------------ * -+ * Hooks corresponding to db_blob object class -+ * ------------------------------------------------------------ */ -+ -+ /* -+ * sepgsqlCheckBlobCreate -+ * assigns a default security label and checks db_blob:{create} -+ */ -+ void -+ sepgsqlCheckBlobCreate(Relation rel, HeapTuple lotup) -+ { -+ sepgsql_sid_t loSid; -+ Oid relid = RelationGetRelid(rel); -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* set a default security context */ -+ sepgsqlSetDefaultSecid(rel, lotup); -+ -+ loSid = sepgsqlGetTupleSecid(relid, lotup, NULL); -+ sepgsqlClientHasPerms(loSid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__CREATE, -+ NULL, true); -+ } -+ -+ /* -+ * sepgsqlCheckBlobDrop -+ * checks db_blob:{drop} permission -+ */ -+ void -+ sepgsqlCheckBlobDrop(Relation rel, HeapTuple lotup) -+ { -+ sepgsql_sid_t loSid; -+ Oid relid = RelationGetRelid(rel); -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ loSid = sepgsqlGetTupleSecid(relid, lotup, NULL); -+ sepgsqlClientHasPerms(loSid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__DROP, -+ NULL, true); -+ } -+ -+ /* -+ * sepgsqlCheckBlobRead -+ * checks db_blob:{read} permission -+ */ -+ void -+ sepgsqlCheckBlobRead(LargeObjectDesc *lobj) -+ { -+ sepgsql_sid_t loSid; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ loSid.relid = LargeObjectRelationId; -+ loSid.secid = lobj->secid; -+ sepgsqlClientHasPerms(loSid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__READ, -+ NULL, true); -+ } -+ -+ /* -+ * sepgsqlCheckBlobWrite -+ * check db_blob:{write} permission -+ */ -+ void -+ sepgsqlCheckBlobWrite(LargeObjectDesc *lobj) -+ { -+ sepgsql_sid_t loSid; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ loSid.relid = LargeObjectRelationId; -+ loSid.secid = lobj->secid; -+ sepgsqlClientHasPerms(loSid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__WRITE, -+ NULL, true); -+ } -+ -+ /* -+ * sepgsqlCheckBlobGetattr -+ * check db_blob:{getattr} permission -+ */ -+ void -+ sepgsqlCheckBlobGetattr(HeapTuple tuple) -+ { -+ sepgsql_sid_t loSid; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ loSid.relid = LargeObjectRelationId; -+ loSid.secid = HeapTupleGetSecid(tuple); -+ sepgsqlClientHasPerms(loSid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__GETATTR, -+ NULL, true); -+ } -+ -+ /* -+ * sepgsqlCheckBlobSetattr -+ * check db_blob:{setattr} permission -+ */ -+ void -+ sepgsqlCheckBlobSetattr(HeapTuple tuple) -+ { -+ sepgsql_sid_t loSid; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ loSid.relid = LargeObjectRelationId; -+ loSid.secid = HeapTupleGetSecid(tuple); -+ sepgsqlClientHasPerms(loSid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__SETATTR, -+ NULL, true); -+ } -+ -+ /* -+ * sepgsqlCheckBlobExport -+ * check db_blob:{read export} and file:{write} permission -+ */ -+ void -+ sepgsqlCheckBlobExport(LargeObjectDesc *lobj, const char *filename) -+ { -+ sepgsql_sid_t loSid; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* db_blob:{read export} */ -+ loSid.relid = LargeObjectRelationId; -+ loSid.secid = lobj->secid; -+ sepgsqlClientHasPerms(loSid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__READ | SEPG_DB_BLOB__EXPORT, -+ NULL, true); -+ /* file:{write} */ -+ sepgsql_file_write(filename); -+ } -+ -+ /* -+ * sepgsqlCheckBlobImport -+ * check db_blob:{write import} and file:{read} permission -+ */ -+ void -+ sepgsqlCheckBlobImport(LargeObjectDesc *lobj, const char *filename) -+ { -+ sepgsql_sid_t loSid; -+ -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* db_blob:{write import} */ -+ loSid.relid = LargeObjectRelationId; -+ loSid.secid = lobj->secid; -+ sepgsqlClientHasPerms(loSid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__WRITE | SEPG_DB_BLOB__IMPORT, -+ NULL, true); -+ /* file:{read} */ -+ sepgsql_file_read(filename); -+ } -+ -+ /* -+ * sepgsqlCheckBlobRelabel -+ * check db_blob:{setattr relabelfrom relabelto} -+ */ -+ void -+ sepgsqlCheckBlobRelabel(HeapTuple oldtup, HeapTuple newtup) -+ { -+ sepgsql_sid_t loSid; -+ access_vector_t required = SEPG_DB_BLOB__SETATTR; -+ -+ if (HeapTupleGetSecid(oldtup) != HeapTupleGetSecid(newtup)) -+ required |= SEPG_DB_BLOB__RELABELFROM; -+ -+ /* db_blob:{setattr relabelfrom} */ -+ loSid = sepgsqlGetTupleSecid(LargeObjectRelationId, oldtup, NULL); -+ sepgsqlClientHasPerms(loSid, -+ SEPG_CLASS_DB_BLOB, -+ required, -+ NULL, true); -+ -+ if ((required & SEPG_DB_BLOB__RELABELFROM) == 0) -+ return; -+ -+ /* db_blob:{relabelto} */ -+ loSid = sepgsqlGetTupleSecid(LargeObjectRelationId, newtup, NULL); -+ sepgsqlClientHasPerms(loSid, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_DB_BLOB__RELABELTO, -+ NULL, true); -+ } -diff -Nrpc blob/src/backend/security/sepgsql/label.c sepgsql/src/backend/security/sepgsql/label.c -*** blob/src/backend/security/sepgsql/label.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/label.c Thu Dec 24 21:59:25 2009 -*************** -*** 0 **** ---- 1,1213 ---- -+ /* -+ * src/backend/security/sepgsql/label.c -+ * SE-PostgreSQL security label management -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ -+ #include "access/sysattr.h" -+ #include "access/xact.h" -+ #include "catalog/catalog.h" -+ #include "catalog/pg_constraint.h" -+ #include "catalog/heap.h" -+ #include "catalog/indexing.h" -+ #include "catalog/namespace.h" -+ #include "catalog/pg_aggregate.h" -+ #include "catalog/pg_amop.h" -+ #include "catalog/pg_amproc.h" -+ #include "catalog/pg_attrdef.h" -+ #include "catalog/pg_attribute.h" -+ #include "catalog/pg_auth_members.h" -+ #include "catalog/pg_authid.h" -+ #include "catalog/pg_cast.h" -+ #include "catalog/pg_class.h" -+ #include "catalog/pg_conversion.h" -+ #include "catalog/pg_database.h" -+ #include "catalog/pg_description.h" -+ #include "catalog/pg_enum.h" -+ #include "catalog/pg_foreign_data_wrapper.h" -+ #include "catalog/pg_foreign_server.h" -+ #include "catalog/pg_inherits.h" -+ #include "catalog/pg_language.h" -+ #include "catalog/pg_largeobject.h" -+ #include "catalog/pg_largeobject_metadata.h" -+ #include "catalog/pg_namespace.h" -+ #include "catalog/pg_opclass.h" -+ #include "catalog/pg_operator.h" -+ #include "catalog/pg_opfamily.h" -+ #include "catalog/pg_proc.h" -+ #include "catalog/pg_rewrite.h" -+ #include "catalog/pg_security.h" -+ #include "catalog/pg_shdescription.h" -+ #include "catalog/pg_statistic.h" -+ #include "catalog/pg_tablespace.h" -+ #include "catalog/pg_trigger.h" -+ #include "catalog/pg_ts_config.h" -+ #include "catalog/pg_ts_config_map.h" -+ #include "catalog/pg_ts_dict.h" -+ #include "catalog/pg_ts_parser.h" -+ #include "catalog/pg_ts_template.h" -+ #include "catalog/pg_type.h" -+ #include "catalog/pg_user_mapping.h" -+ #include "miscadmin.h" -+ #include "nodes/makefuncs.h" -+ #include "security/sepgsql.h" -+ #include "storage/fd.h" -+ #include "utils/fmgroids.h" -+ #include "utils/lsyscache.h" -+ #include "utils/syscache.h" -+ #include "utils/tqual.h" -+ -+ /* GUC: to turn on/off row level controls in SE-PostgreSQL */ -+ bool sepostgresql_row_level; -+ -+ /* GUC parameter to turn on/off mcstrans */ -+ bool sepostgresql_mcstrans; -+ -+ /* -+ * sepgsqlTupleDescHasSecid -+ * -+ * returns a hint whether we should allocate a field to store -+ * security label on the given relation, or not. -+ */ -+ bool -+ sepgsqlTupleDescHasSecid(Oid relid, char relkind) -+ { -+ /* -+ * sepgsqlIsEnabled() is not available because it always returns -+ * false in bootstraping mode -+ */ -+ if (sepostgresql_mode == SEPGSQL_MODE_DISABLED || -+ is_selinux_enabled() < 1) -+ return false; -+ -+ if (!OidIsValid(relid)) -+ return sepostgresql_row_level; /* Target of SELECT INTO */ -+ -+ /* These system catalogs always have its secid */ -+ if (relid == DatabaseRelationId || -+ relid == NamespaceRelationId || -+ relid == RelationRelationId || -+ relid == AttributeRelationId || -+ relid == ProcedureRelationId) -+ return true; -+ -+ /* These system catalogs are an external attributes */ -+ if (relid == AggregateRelationId || -+ relid == AccessMethodOperatorRelationId || -+ relid == AccessMethodProcedureRelationId || -+ relid == AttrDefaultRelationId || -+ relid == AuthMemRelationId || -+ relid == ConstraintRelationId || -+ relid == DescriptionRelationId || -+ relid == EnumRelationId || -+ relid == IndexRelationId || -+ relid == InheritsRelationId || -+ relid == LargeObjectRelationId || -+ relid == RewriteRelationId || -+ relid == SecurityRelationId || -+ relid == SharedDescriptionRelationId || -+ relid == StatisticRelationId || -+ relid == TriggerRelationId) -+ return false; -+ -+ return sepostgresql_row_level; -+ } -+ -+ /* -+ * defaultSecidWithXXXX -+ */ -+ static sepgsql_sid_t -+ defaultSecidWithDatabase(Oid relOid, Oid datOid, uint16 tclass) -+ { -+ HeapTuple tuple; -+ sepgsql_sid_t datSid; -+ -+ tuple = SearchSysCache(DATABASEOID, -+ ObjectIdGetDatum(datOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for database: %u", datOid); -+ -+ datSid.relid = DatabaseRelationId; -+ datSid.secid = HeapTupleGetSecid(tuple); -+ -+ ReleaseSysCache(tuple); -+ -+ return sepgsqlClientCreateSecid(datSid, tclass, relOid); -+ } -+ -+ static sepgsql_sid_t -+ defaultSecidWithSchema(Oid relOid, Oid nspOid, uint16 tclass) -+ { -+ HeapTuple tuple; -+ sepgsql_sid_t nspSid; -+ -+ tuple = SearchSysCache(NAMESPACEOID, -+ ObjectIdGetDatum(nspOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for schema: %u", nspOid); -+ -+ nspSid.relid = NamespaceRelationId; -+ nspSid.secid = HeapTupleGetSecid(tuple); -+ -+ ReleaseSysCache(tuple); -+ -+ return sepgsqlClientCreateSecid(nspSid, tclass, relOid); -+ } -+ -+ static sepgsql_sid_t -+ defaultSecidWithTable(Oid relOid, Oid tblOid, uint16 tclass) -+ { -+ HeapTuple tuple; -+ sepgsql_sid_t tblSid; -+ -+ tuple = SearchSysCache(RELOID, -+ ObjectIdGetDatum(tblOid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "cache lookup failed for relation: %u", tblOid); -+ -+ tblSid.relid = RelationRelationId; -+ tblSid.secid = HeapTupleGetSecid(tuple); -+ -+ ReleaseSysCache(tuple); -+ -+ return sepgsqlClientCreateSecid(tblSid, tclass, relOid); -+ } -+ -+ /* -+ * sepgsqlGetDefaultDatabaseSecid -+ * It returns the default security label of a database object. -+ */ -+ sepgsql_sid_t -+ sepgsqlGetDefaultDatabaseSecid(Oid source_database_oid) -+ { -+ return defaultSecidWithDatabase(DatabaseRelationId, -+ source_database_oid, -+ SEPG_CLASS_DB_DATABASE); -+ } -+ -+ sepgsql_sid_t -+ sepgsqlGetDefaultSchemaSecid(Oid database_oid) -+ { -+ return defaultSecidWithDatabase(NamespaceRelationId, -+ database_oid, -+ SEPG_CLASS_DB_SCHEMA); -+ } -+ -+ sepgsql_sid_t -+ sepgsqlGetDefaultTableSecid(Oid namespace_oid) -+ { -+ return defaultSecidWithSchema(RelationRelationId, -+ namespace_oid, -+ SEPG_CLASS_DB_TABLE); -+ } -+ -+ sepgsql_sid_t -+ sepgsqlGetDefaultSequenceSecid(Oid namespace_oid) -+ { -+ return defaultSecidWithSchema(RelationRelationId, -+ namespace_oid, -+ SEPG_CLASS_DB_SEQUENCE); -+ } -+ -+ sepgsql_sid_t -+ sepgsqlGetDefaultProcedureSecid(Oid namespace_oid) -+ { -+ return defaultSecidWithSchema(ProcedureRelationId, -+ namespace_oid, -+ SEPG_CLASS_DB_PROCEDURE); -+ } -+ -+ sepgsql_sid_t -+ sepgsqlGetDefaultColumnSecid(Oid table_oid) -+ { -+ return defaultSecidWithTable(AttributeRelationId, -+ table_oid, -+ SEPG_CLASS_DB_COLUMN); -+ } -+ -+ sepgsql_sid_t -+ sepgsqlGetDefaultTupleSecid(Oid table_oid) -+ { -+ return defaultSecidWithTable(table_oid, -+ table_oid, -+ SEPG_CLASS_DB_TUPLE); -+ } -+ -+ sepgsql_sid_t -+ sepgsqlGetDefaultBlobSecid(Oid database_oid) -+ { -+ return defaultSecidWithDatabase(LargeObjectMetadataRelationId, -+ MyDatabaseId, -+ SEPG_CLASS_DB_BLOB); -+ } -+ -+ void -+ sepgsqlSetDefaultSecid(Relation rel, HeapTuple tuple) -+ { -+ sepgsql_sid_t newSid; -+ Oid relOid = RelationGetRelid(rel); -+ Oid nspOid, tblOid; -+ char relkind; -+ -+ if (!HeapTupleHasSecid(tuple)) -+ return; -+ -+ /* initialize */ -+ newSid.relid = relOid; -+ newSid.secid = InvalidOid; -+ -+ switch (relOid) -+ { -+ case DatabaseRelationId: -+ /* should be never happen */ -+ elog(WARNING, "bug? pg_database tuple without security label"); -+ break; -+ -+ case NamespaceRelationId: -+ newSid = sepgsqlGetDefaultSchemaSecid(MyDatabaseId); -+ break; -+ -+ case RelationRelationId: -+ nspOid = ((Form_pg_class) GETSTRUCT(tuple))->relnamespace; -+ relkind = ((Form_pg_class) GETSTRUCT(tuple))->relkind; -+ -+ switch (relkind) -+ { -+ case RELKIND_RELATION: -+ newSid = sepgsqlGetDefaultTableSecid(nspOid); -+ break; -+ -+ case RELKIND_SEQUENCE: -+ newSid = sepgsqlGetDefaultSequenceSecid(nspOid); -+ break; -+ -+ default: -+ newSid = sepgsqlGetDefaultTupleSecid(relOid); -+ break; -+ } -+ break; -+ -+ case ProcedureRelationId: -+ nspOid = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace; -+ newSid = sepgsqlGetDefaultProcedureSecid(nspOid); -+ break; -+ -+ case AttributeRelationId: -+ tblOid = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid; -+ if (get_rel_relkind(tblOid) == RELKIND_RELATION) -+ newSid = sepgsqlGetDefaultColumnSecid(tblOid); -+ break; -+ -+ case LargeObjectMetadataRelationId: -+ newSid = sepgsqlGetDefaultBlobSecid(MyDatabaseId); -+ break; -+ -+ default: -+ newSid = sepgsqlGetDefaultTupleSecid(relOid); -+ break; -+ } -+ -+ HeapTupleSetSecid(tuple, newSid.secid); -+ } -+ -+ /* -+ * sepgsqlPostBootstrapingMode -+ * -+ * Assign initial security context -+ */ -+ static void -+ sepgsqlInitialLabeling(Oid relOid, char *seclabels[]) -+ { -+ Relation rel; -+ HeapScanDesc scan; -+ HeapTuple tuple; -+ HeapTuple newtup; -+ -+ rel = heap_open(relOid, RowExclusiveLock); -+ -+ scan = heap_beginscan(rel, SnapshotNow, 0, NULL); -+ -+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) -+ { -+ Oid secid = InvalidOid; -+ Oid attrelid; -+ char relkind; -+ -+ if (!HeapTupleHasSecid(tuple)) -+ continue; -+ -+ switch (relOid) -+ { -+ case DatabaseRelationId: -+ secid = securityRawSecLabelIn(relOid, seclabels[0]); -+ break; -+ -+ case NamespaceRelationId: -+ secid = securityRawSecLabelIn(relOid, seclabels[1]); -+ break; -+ -+ case RelationRelationId: -+ relkind = ((Form_pg_class) GETSTRUCT(tuple))->relkind; -+ switch (relkind) -+ { -+ case RELKIND_RELATION: -+ secid = securityRawSecLabelIn(relOid, seclabels[2]); -+ break; -+ case RELKIND_SEQUENCE: -+ secid = securityRawSecLabelIn(relOid, seclabels[3]); -+ break; -+ default: -+ secid = securityRawSecLabelIn(relOid, seclabels[6]); -+ break; -+ } -+ break; -+ -+ case AttributeRelationId: -+ attrelid = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid; -+ if (get_rel_relkind(attrelid) == RELKIND_RELATION) -+ secid = securityRawSecLabelIn(relOid, seclabels[5]); -+ break; -+ -+ case ProcedureRelationId: -+ secid = securityRawSecLabelIn(relOid, seclabels[4]); -+ break; -+ -+ case LargeObjectMetadataRelationId: -+ secid = securityRawSecLabelIn(relOid, seclabels[7]); -+ break; -+ -+ default: -+ secid = securityRawSecLabelIn(relOid, seclabels[6]); -+ break; -+ } -+ -+ /* -+ * Inplace update -+ */ -+ newtup = heap_copytuple(tuple); -+ -+ HeapTupleSetSecid(newtup, secid); -+ -+ heap_inplace_update(rel, newtup); -+ } -+ heap_endscan(scan); -+ -+ heap_close(rel, RowExclusiveLock); -+ } -+ -+ void -+ sepgsqlPostBootstrapingMode(void) -+ { -+ Form_pg_class classForm; -+ Relation rel; -+ ScanKeyData skey; -+ HeapScanDesc scan; -+ HeapTuple tuple; -+ char *scontext; -+ char *seclabels[8]; -+ -+ /* -+ * sepgsqlIsEnabled() is not available because it always returns -+ * false in bootstraping mode -+ */ -+ Assert(IsBootstrapProcessingMode()); -+ if (sepostgresql_mode == SEPGSQL_MODE_DISABLED || -+ is_selinux_enabled() < 1) -+ return; -+ -+ /* -+ * Compute default initial security context -+ */ -+ if (getprevcon_raw(&scontext) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("could not obtain current context"))); -+ -+ seclabels[0] = sepgsqlComputeCreate(scontext, scontext, -+ SEPG_CLASS_DB_DATABASE); -+ seclabels[1] = sepgsqlComputeCreate(scontext, seclabels[0], -+ SEPG_CLASS_DB_SCHEMA); -+ seclabels[2] = sepgsqlComputeCreate(scontext, seclabels[1], -+ SEPG_CLASS_DB_TABLE); -+ seclabels[3] = sepgsqlComputeCreate(scontext, seclabels[1], -+ SEPG_CLASS_DB_SEQUENCE); -+ seclabels[4] = sepgsqlComputeCreate(scontext, seclabels[1], -+ SEPG_CLASS_DB_PROCEDURE); -+ seclabels[5] = sepgsqlComputeCreate(scontext, seclabels[2], -+ SEPG_CLASS_DB_COLUMN); -+ seclabels[6] = sepgsqlComputeCreate(scontext, seclabels[2], -+ SEPG_CLASS_DB_TUPLE); -+ seclabels[7] = sepgsqlComputeCreate(scontext, seclabels[0], -+ SEPG_CLASS_DB_BLOB); -+ /* -+ * Inplace update -+ */ -+ StartTransactionCommand(); -+ -+ rel = heap_open(RelationRelationId, AccessShareLock); -+ -+ ScanKeyInit(&skey, -+ Anum_pg_class_relkind, -+ BTEqualStrategyNumber, F_CHAREQ, -+ CharGetDatum(RELKIND_RELATION)); -+ -+ scan = heap_beginscan(rel, SnapshotNow, 1, &skey); -+ -+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) -+ sepgsqlInitialLabeling(HeapTupleGetOid(tuple), seclabels); -+ -+ heap_endscan(scan); -+ -+ heap_close(rel, AccessShareLock); -+ -+ CommitTransactionCommand(); -+ } -+ -+ /* -+ * sepgsqlGetSysobjSecid -+ * -+ * It returns a pair of relid/secid for the given OID. -+ */ -+ static sepgsql_sid_t -+ getSysobjSecidDirect(Oid classOid, Oid indexOid, Oid objectId, uint16 *tclass) -+ { -+ sepgsql_sid_t sid; -+ Relation rel; -+ HeapTuple tup; -+ ScanKeyData skey; -+ SysScanDesc scan; -+ -+ rel = heap_open(CastRelationId, AccessShareLock); -+ -+ ScanKeyInit(&skey, -+ ObjectIdAttributeNumber, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(objectId)); -+ -+ scan = systable_beginscan(rel, CastOidIndexId, true, -+ SnapshotNow, 1, &skey); -+ tup = systable_getnext(scan); -+ -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "system object lookup failed for oid %u on relation %u", -+ objectId, classOid); -+ -+ sid = sepgsqlGetTupleSecid(classOid, tup, tclass); -+ -+ systable_endscan(scan); -+ -+ heap_close(rel, AccessShareLock); -+ -+ return sid; -+ } -+ -+ sepgsql_sid_t -+ sepgsqlGetSysobjSecid(Oid classOid, Oid objectId, int32 objsubId, uint16 *tclass) -+ { -+ sepgsql_sid_t sid; -+ HeapTuple tup; -+ -+ switch (classOid) -+ { -+ case AccessMethodRelationId: -+ tup = SearchSysCache(AMOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for access method: %u", objectId); -+ break; -+ -+ case AccessMethodOperatorRelationId: -+ return getSysobjSecidDirect(AccessMethodOperatorRelationId, -+ AccessMethodOperatorOidIndexId, -+ objectId, tclass); -+ -+ case AccessMethodProcedureRelationId: -+ return getSysobjSecidDirect(AccessMethodProcedureRelationId, -+ AccessMethodProcedureOidIndexId, -+ objectId, tclass); -+ -+ case AuthIdRelationId: -+ tup = SearchSysCache(AUTHOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for role: %u", objectId); -+ break; -+ -+ case CastRelationId: -+ return getSysobjSecidDirect(CastRelationId, -+ CastOidIndexId, -+ objectId, tclass); -+ -+ case ConstraintRelationId: -+ tup = SearchSysCache(CONSTROID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for constraint: %u", objectId); -+ break; -+ -+ case ConversionRelationId: -+ tup = SearchSysCache(CONVOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for conversion: %u", objectId); -+ break; -+ -+ case DatabaseRelationId: -+ tup = SearchSysCache(DATABASEOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for database: %u", objectId); -+ break; -+ -+ case ForeignDataWrapperRelationId: -+ tup = SearchSysCache(FOREIGNDATAWRAPPEROID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for FDW: %u", objectId); -+ break; -+ -+ case ForeignServerRelationId: -+ tup = SearchSysCache(FOREIGNSERVEROID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for foreign server: %u", objectId); -+ break; -+ -+ case LanguageRelationId: -+ tup = SearchSysCache(LANGOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ break; -+ -+ case LargeObjectRelationId: -+ case LargeObjectMetadataRelationId: -+ { -+ Relation rel; -+ ScanKeyData skey; -+ SysScanDesc scan; -+ -+ rel = heap_open(LargeObjectMetadataRelationId, AccessShareLock); -+ -+ ScanKeyInit(&skey, -+ ObjectIdAttributeNumber, -+ BTEqualStrategyNumber, F_OIDEQ, -+ ObjectIdGetDatum(objectId)); -+ -+ scan = systable_beginscan(rel, LargeObjectMetadataOidIndexId, -+ true, SnapshotNow, 1, &skey); -+ -+ tup = systable_getnext(scan); -+ -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "largeobject %u lookup failed", objectId); -+ -+ sid = sepgsqlGetTupleSecid(classOid, tup, tclass); -+ systable_endscan(scan); -+ -+ heap_close(rel, AccessShareLock); -+ } -+ return sid; -+ -+ case RelationRelationId: -+ if (objsubId != 0) -+ { -+ classOid = AttributeRelationId; -+ tup = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(objectId), -+ Int16GetDatum(objsubId), -+ 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for attribute %d of relation %u", -+ objsubId, objectId); -+ } -+ else -+ { -+ classOid = RelationRelationId; -+ tup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for relation %u", objectId); -+ } -+ break; -+ -+ case NamespaceRelationId: -+ tup = SearchSysCache(NAMESPACEOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for schema %u", objectId); -+ break; -+ -+ case OperatorClassRelationId: -+ tup = SearchSysCache(CLAOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for opclass %u", objectId); -+ break; -+ -+ case OperatorFamilyRelationId: -+ tup = SearchSysCache(OPFAMILYOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for opfamily %u", objectId); -+ break; -+ -+ case OperatorRelationId: -+ tup = SearchSysCache(OPEROID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for operator %u", objectId); -+ break; -+ -+ case ProcedureRelationId: -+ tup = SearchSysCache(PROCOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for procedure %u", objectId); -+ break; -+ -+ case RewriteRelationId: -+ return getSysobjSecidDirect(RewriteRelationId, -+ RewriteOidIndexId, -+ objectId, tclass); -+ -+ case TableSpaceRelationId: -+ return getSysobjSecidDirect(TableSpaceRelationId, -+ TablespaceOidIndexId, -+ objectId, tclass); -+ -+ case TriggerRelationId: -+ return getSysobjSecidDirect(TriggerRelationId, -+ TriggerOidIndexId, -+ objectId, tclass); -+ -+ case TSConfigRelationId: -+ tup = SearchSysCache(TSCONFIGOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for text search configuration %u", objectId); -+ break; -+ -+ case TSDictionaryRelationId: -+ tup = SearchSysCache(TSDICTOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for text search dictionary %u", objectId); -+ break; -+ -+ case TSParserRelationId: -+ tup = SearchSysCache(TSPARSEROID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for text search parser %u", objectId); -+ break; -+ -+ case TSTemplateRelationId: -+ tup = SearchSysCache(TSTEMPLATEOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for text search template %u", objectId); -+ break; -+ -+ case TypeRelationId: -+ tup = SearchSysCache(TYPEOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for type %u", objectId); -+ break; -+ -+ case UserMappingRelationId: -+ tup = SearchSysCache(USERMAPPINGOID, -+ ObjectIdGetDatum(objectId), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(tup)) -+ elog(ERROR, "cache lookup failed for user mapping %u", objectId); -+ break; -+ -+ default: -+ elog(ERROR, "unexpected class OID: %u", classOid); -+ tup = NULL; /* for compiler quiet */ -+ break; -+ } -+ -+ Assert(HeapTupleIsValid(tup)); -+ -+ sid = sepgsqlGetTupleSecid(classOid, tup, tclass); -+ -+ ReleaseSysCache(tup); -+ -+ return sid; -+ } -+ -+ /* -+ * sepgsqlGetTupleSecid -+ * -+ * It returns a pair of relid/secid for the given HeapTuple. -+ * A few system catalogs is handled as an attribute of other -+ * system objects. -+ * E.g) pg_attrdef is an attribute of a certain pg_attribute -+ */ -+ sepgsql_sid_t -+ sepgsqlGetTupleSecid(Oid tableOid, HeapTuple tuple, uint16 *tclass) -+ { -+ sepgsql_sid_t sid; -+ HeapTuple exttup; -+ Oid extid; -+ Oid extcls; -+ AttrNumber extsub; -+ -+ /* initialize (unlabeled security context) */ -+ sid.relid = tableOid; -+ sid.secid = InvalidOid; -+ if (tclass) -+ *tclass = SEPG_CLASS_DB_TUPLE; -+ -+ switch (tableOid) -+ { -+ case AggregateRelationId: -+ extid = ((Form_pg_aggregate) GETSTRUCT(tuple))->aggfnoid; -+ exttup = SearchSysCache(PROCOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(ProcedureRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case AccessMethodOperatorRelationId: -+ extid = ((Form_pg_amop) GETSTRUCT(tuple))->amopfamily; -+ exttup = SearchSysCache(OPFAMILYOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(OperatorFamilyRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case AccessMethodProcedureRelationId: -+ extid = ((Form_pg_amproc) GETSTRUCT(tuple))->amprocfamily; -+ exttup = SearchSysCache(OPFAMILYOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(OperatorFamilyRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case AttrDefaultRelationId: -+ extid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid; -+ extsub = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum; -+ exttup = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(extid), -+ Int16GetDatum(extsub), -+ 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(AttributeRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case AttributeRelationId: -+ extid = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid; -+ exttup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ char relkind = ((Form_pg_class) GETSTRUCT(exttup))->relkind; -+ -+ if (relkind == RELKIND_RELATION) -+ { -+ if (tclass) -+ *tclass = SEPG_CLASS_DB_COLUMN; -+ sid.secid = HeapTupleGetSecid(tuple); -+ } -+ else -+ sid = sepgsqlGetTupleSecid(RelationRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case AuthMemRelationId: -+ extid = ((Form_pg_auth_members) GETSTRUCT(tuple))->roleid; -+ exttup = SearchSysCache(AUTHOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(AuthIdRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case ConstraintRelationId: -+ /* CHECK constraint is an attribute of the relation */ -+ extid = ((Form_pg_constraint) GETSTRUCT(tuple))->conrelid; -+ if (OidIsValid(extid)) -+ { -+ exttup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(RelationRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ } -+ /* DOMAIN constraint is an attribute of the domain type */ -+ extid = ((Form_pg_constraint) GETSTRUCT(tuple))->contypid; -+ if (OidIsValid(extid)) -+ { -+ sid.relid = TypeRelationId; -+ exttup = SearchSysCache(TYPEOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(TypeRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ } -+ /* Database's context for global assertion */ -+ exttup = SearchSysCache(DATABASEOID, -+ ObjectIdGetDatum(MyDatabaseId), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(DatabaseRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case DatabaseRelationId: -+ sid.secid = HeapTupleGetSecid(tuple); -+ if (tclass) -+ *tclass = SEPG_CLASS_DB_DATABASE; -+ break; -+ -+ case DescriptionRelationId: -+ /* recursive call */ -+ extid = ((Form_pg_description) GETSTRUCT(tuple))->objoid; -+ extcls = ((Form_pg_description) GETSTRUCT(tuple))->classoid; -+ return sepgsqlGetSysobjSecid(extcls, extid, 0, tclass); -+ -+ case EnumRelationId: -+ extid = ((Form_pg_enum) GETSTRUCT(tuple))->enumtypid; -+ exttup = SearchSysCache(TYPEOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(TypeRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case IndexRelationId: -+ extid = ((Form_pg_index) GETSTRUCT(tuple))->indrelid; -+ exttup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(RelationRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case InheritsRelationId: -+ extid = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrelid; -+ exttup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(RelationRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case LargeObjectRelationId: -+ extid = ((Form_pg_largeobject) GETSTRUCT(tuple))->loid; -+ extcls = LargeObjectMetadataRelationId; -+ return sepgsqlGetSysobjSecid(extcls, extid, 0, tclass); -+ -+ case LargeObjectMetadataRelationId: -+ sid.secid = HeapTupleGetSecid(tuple); -+ if (tclass) -+ *tclass = SEPG_CLASS_DB_BLOB; -+ break; -+ -+ case NamespaceRelationId: -+ sid.secid = HeapTupleGetSecid(tuple); -+ if (tclass) -+ *tclass = SEPG_CLASS_DB_SCHEMA; -+ break; -+ -+ case ProcedureRelationId: -+ sid.secid = HeapTupleGetSecid(tuple); -+ if (tclass) -+ *tclass = SEPG_CLASS_DB_PROCEDURE; -+ break; -+ -+ case RelationRelationId: -+ sid.secid = HeapTupleGetSecid(tuple); -+ if (tclass) -+ { -+ char relkind = ((Form_pg_class) GETSTRUCT(tuple))->relkind; -+ -+ switch (relkind) -+ { -+ case RELKIND_RELATION: -+ *tclass = SEPG_CLASS_DB_TABLE; -+ break; -+ -+ case RELKIND_SEQUENCE: -+ *tclass = SEPG_CLASS_DB_SEQUENCE; -+ break; -+ -+ default: -+ *tclass = SEPG_CLASS_DB_TUPLE; -+ break; -+ } -+ } -+ break; -+ -+ case RewriteRelationId: -+ extid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class; -+ exttup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(RelationRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case SharedDescriptionRelationId: -+ /* recursive invocation */ -+ extid = ((Form_pg_shdescription) GETSTRUCT(tuple))->objoid; -+ extcls = ((Form_pg_shdescription) GETSTRUCT(tuple))->classoid; -+ return sepgsqlGetSysobjSecid(extcls, extid, 0, tclass); -+ -+ case StatisticRelationId: -+ extid = ((Form_pg_statistic) GETSTRUCT(tuple))->starelid; -+ extsub = ((Form_pg_statistic) GETSTRUCT(tuple))->staattnum; -+ exttup = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(extid), -+ Int16GetDatum(extsub), -+ 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(AttributeRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case TriggerRelationId: -+ extid = ((Form_pg_trigger) GETSTRUCT(tuple))->tgrelid; -+ exttup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(RelationRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ case TSConfigMapRelationId: -+ extid = ((Form_pg_ts_config_map) GETSTRUCT(tuple))->mapcfg; -+ exttup = SearchSysCache(TSCONFIGOID, -+ ObjectIdGetDatum(extid), -+ 0, 0, 0); -+ if (HeapTupleIsValid(exttup)) -+ { -+ sid = sepgsqlGetTupleSecid(TSConfigRelationId, -+ exttup, tclass); -+ ReleaseSysCache(exttup); -+ } -+ break; -+ -+ default: -+ /* No external lookups (normal case) */ -+ sid.secid = HeapTupleGetSecid(tuple); -+ break; -+ } -+ -+ return sid; -+ } -+ -+ /* -+ * sepgsqlRawSecLabelIn -+ * correctness checks for the given security context -+ */ -+ char * -+ sepgsqlRawSecLabelIn(char *seclabel) -+ { -+ if (!sepgsqlIsEnabled()) -+ return seclabel; -+ -+ if (!seclabel || security_check_context_raw(seclabel) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_SECURITY_LABEL), -+ errmsg("Invalid security context: \"%s\"", seclabel))); -+ -+ return seclabel; -+ } -+ -+ /* -+ * sepgsqlRawSecLabelOut -+ * correctness checks for the given security context, -+ * and replace it if invalid security context -+ */ -+ char * -+ sepgsqlRawSecLabelOut(char *seclabel) -+ { -+ if (!sepgsqlIsEnabled()) -+ return seclabel; -+ -+ if (!seclabel || security_check_context_raw(seclabel) < 0) -+ { -+ security_context_t unlabeledcon; -+ -+ if (security_get_initial_context_raw("unlabeled", -+ &unlabeledcon) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("Unabled to get unlabeled security context"))); -+ PG_TRY(); -+ { -+ seclabel = pstrdup(unlabeledcon); -+ } -+ PG_CATCH(); -+ { -+ freecon(unlabeledcon); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(unlabeledcon); -+ } -+ return seclabel; -+ } -+ -+ /* -+ * sepgsqlTransSecLabelIn -+ * sepgsqlTransSecLabelOut -+ * translation between human-readable and raw format -+ */ -+ char * -+ sepgsqlTransSecLabelIn(char *seclabel) -+ { -+ security_context_t rawlabel; -+ security_context_t result; -+ -+ if (!sepgsqlIsEnabled() || -+ !sepostgresql_mcstrans) -+ return seclabel; -+ -+ if (selinux_trans_to_raw_context(seclabel, &rawlabel) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("SELinux: failed to translate \"%s\"", seclabel))); -+ PG_TRY(); -+ { -+ result = pstrdup(rawlabel); -+ } -+ PG_CATCH(); -+ { -+ freecon(rawlabel); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(rawlabel); -+ -+ return result; -+ } -+ -+ char * -+ sepgsqlTransSecLabelOut(char *seclabel) -+ { -+ security_context_t translabel; -+ security_context_t result; -+ -+ if (!sepgsqlIsEnabled() || -+ !sepostgresql_mcstrans) -+ return seclabel; -+ -+ if (selinux_raw_to_trans_context(seclabel, &translabel) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("SELinux: failed to translate \"%s\"", seclabel))); -+ PG_TRY(); -+ { -+ result = pstrdup(translabel); -+ } -+ PG_CATCH(); -+ { -+ freecon(translabel); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(translabel); -+ -+ return result; -+ } -+ -+ char * -+ sepgsqlSysattSecLabelOut(Oid relid, HeapTuple tuple) -+ { -+ sepgsql_sid_t sid; -+ -+ sid = sepgsqlGetTupleSecid(relid, tuple, NULL); -+ -+ return securityTransSecLabelOut(sid.relid, sid.secid); -+ } -diff -Nrpc blob/src/backend/security/sepgsql/misc.c sepgsql/src/backend/security/sepgsql/misc.c -*** blob/src/backend/security/sepgsql/misc.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/misc.c Sun Dec 20 00:41:22 2009 -*************** -*** 0 **** ---- 1,214 ---- -+ /* -+ * src/backend/security/sepgsql/misc.c -+ * Miscellaneous facilities in SE-PostgreSQL -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ #include "libpq/libpq-be.h" -+ #include "miscadmin.h" -+ #include "security/sepgsql.h" -+ #include "utils/builtins.h" -+ -+ /* -+ * SE-PostgreSQL specific functions -+ */ -+ Datum -+ sepgsql_getcon(PG_FUNCTION_ARGS) -+ { -+ security_context_t context; -+ -+ if (!sepgsqlIsEnabled()) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SELinux: disabled now"))); -+ -+ context = sepgsqlGetClientLabel(); -+ context = sepgsqlTransSecLabelOut(context); -+ return CStringGetTextDatum(context); -+ } -+ -+ Datum -+ sepgsql_server_getcon(PG_FUNCTION_ARGS) -+ { -+ char *context; -+ -+ if (!sepgsqlIsEnabled()) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SELinux: disabled now"))); -+ -+ context = sepgsqlGetServerLabel(); -+ context = sepgsqlTransSecLabelOut(context); -+ -+ return CStringGetTextDatum(context); -+ } -+ -+ /* -+ * sepgsql_(get|set)_(user|role|type|range) -+ * get/set a component of security context. -+ */ -+ static void -+ parse_security_context(security_context_t context, -+ char **user, char **role, char **type, char **range) -+ { -+ security_context_t raw_context; -+ char *tok; -+ -+ if (!sepgsqlIsEnabled()) -+ ereport(ERROR, -+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), -+ errmsg("SELinux: disabled now"))); -+ -+ if (selinux_trans_to_raw_context(context, &raw_context) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("could not translate mls label: %s", context))); -+ -+ PG_TRY(); -+ { -+ tok = strtok(raw_context, ":"); -+ if (user) -+ *user = (!tok ? NULL : pstrdup(tok)); -+ -+ tok = strtok(NULL, ":"); -+ if (role) -+ *role = (!tok ? NULL : pstrdup(tok)); -+ -+ tok = strtok(NULL, ":"); -+ if (type) -+ *type = (!tok ? NULL : pstrdup(tok)); -+ -+ tok = strtok(NULL, "\0"); -+ if (range) -+ *range = (!tok ? NULL : pstrdup(tok)); -+ } -+ PG_CATCH(); -+ { -+ freecon(raw_context); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(raw_context); -+ } -+ -+ Datum -+ sepgsql_get_user(PG_FUNCTION_ARGS) -+ { -+ security_context_t context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *user; -+ -+ parse_security_context(context, &user, NULL, NULL, NULL); -+ if (!user) -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_SECURITY_LABEL), -+ errmsg("could not extract user of \"%s\"", context))); -+ -+ PG_RETURN_TEXT_P(CStringGetTextDatum(user)); -+ } -+ -+ Datum -+ sepgsql_get_role(PG_FUNCTION_ARGS) -+ { -+ security_context_t context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *role; -+ -+ parse_security_context(context, NULL, &role, NULL, NULL); -+ if (!role) -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_SECURITY_LABEL), -+ errmsg("could not extract role of \"%s\"", context))); -+ -+ PG_RETURN_TEXT_P(CStringGetTextDatum(role)); -+ } -+ -+ Datum -+ sepgsql_get_type(PG_FUNCTION_ARGS) -+ { -+ security_context_t context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *type; -+ -+ parse_security_context(context, NULL, NULL, &type, NULL); -+ if (!type) -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_SECURITY_LABEL), -+ errmsg("could not extract type of \"%s\"", context))); -+ -+ PG_RETURN_TEXT_P(CStringGetTextDatum(type)); -+ } -+ -+ Datum -+ sepgsql_get_range(PG_FUNCTION_ARGS) -+ { -+ security_context_t context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *range; -+ -+ parse_security_context(context, NULL, NULL, NULL, &range); -+ if (!range) -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_SECURITY_LABEL), -+ errmsg("could not extract range of \"%s\"", context))); -+ -+ PG_RETURN_TEXT_P(CStringGetTextDatum(range)); -+ } -+ -+ static Datum -+ sepgsql_set_common(char *context, -+ char *user, char *role, char *type, char *range) -+ { -+ StringInfoData newcon; -+ -+ parse_security_context(context, -+ !user ? &user : NULL, -+ !role ? &role : NULL, -+ !type ? &type : NULL, -+ !range ? &range : NULL); -+ if (!user || !role || !type) -+ ereport(ERROR, -+ (errcode(ERRCODE_INVALID_SECURITY_LABEL), -+ errmsg("invalid security context: \"%s\"", context))); -+ -+ initStringInfo(&newcon); -+ appendStringInfo(&newcon, "%s:%s:%s", user, role, type); -+ if (range) -+ appendStringInfo(&newcon, ":%s", range); -+ -+ return CStringGetTextDatum(sepgsqlTransSecLabelOut(newcon.data)); -+ } -+ -+ Datum -+ sepgsql_set_user(PG_FUNCTION_ARGS) -+ { -+ security_context_t context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *user = TextDatumGetCString(PG_GETARG_TEXT_P(1)); -+ -+ return sepgsql_set_common(context, user, NULL, NULL, NULL); -+ } -+ -+ Datum -+ sepgsql_set_role(PG_FUNCTION_ARGS) -+ { -+ security_context_t context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *role = TextDatumGetCString(PG_GETARG_TEXT_P(1)); -+ -+ return sepgsql_set_common(context, NULL, role, NULL, NULL); -+ } -+ -+ Datum -+ sepgsql_set_type(PG_FUNCTION_ARGS) -+ { -+ security_context_t context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *type = TextDatumGetCString(PG_GETARG_TEXT_P(1)); -+ -+ return sepgsql_set_common(context, NULL, NULL, type, NULL); -+ } -+ -+ Datum -+ sepgsql_set_range(PG_FUNCTION_ARGS) -+ { -+ security_context_t context = TextDatumGetCString(PG_GETARG_TEXT_P(0)); -+ char *range = TextDatumGetCString(PG_GETARG_TEXT_P(1)); -+ -+ return sepgsql_set_common(context, NULL, NULL, NULL, range); -+ } -diff -Nrpc blob/src/backend/security/sepgsql/perms.c sepgsql/src/backend/security/sepgsql/perms.c -*** blob/src/backend/security/sepgsql/perms.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/perms.c Mon Sep 28 09:29:32 2009 -*************** -*** 0 **** ---- 1,597 ---- -+ /* -+ * src/backend/utils/sepgsql/perms.c -+ * SE-PostgreSQL permission checks -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ -+ #include "catalog/pg_database.h" -+ #include "catalog/pg_proc.h" -+ #include "catalog/pg_largeobject.h" -+ #include "catalog/pg_namespace.h" -+ #include "catalog/pg_type.h" -+ #include "miscadmin.h" -+ #include "security/sepgsql.h" -+ #include "utils/lsyscache.h" -+ -+ /* -+ * Dynamic object class/permissions mapping -+ * -+ * SELinux exports the list of object classes and permissions at -+ * /selinux/class. The libselinux provides an interface to translate -+ * between their names and codes. -+ */ -+ static struct -+ { -+ const char *class_name; -+ security_class_t class_code; -+ struct -+ { -+ const char *perm_name; -+ access_vector_t perm_code; -+ } av[sizeof(access_vector_t) * 8]; -+ } selinux_catalog[] = { -+ { -+ "process", SEPG_CLASS_PROCESS, -+ { -+ {"translation", SEPG_PROCESS__TRANSITION }, -+ {NULL, 0} -+ } -+ }, -+ { -+ "file", SEPG_CLASS_FILE, -+ { -+ {"read", SEPG_FILE__READ }, -+ {"write", SEPG_FILE__WRITE }, -+ {"create", SEPG_FILE__CREATE }, -+ {"getattr", SEPG_FILE__GETATTR }, -+ {NULL, 0} -+ } -+ }, -+ { -+ "dir", SEPG_CLASS_DIR, -+ { -+ {"read", SEPG_DIR__READ }, -+ {"write", SEPG_DIR__WRITE }, -+ {"create", SEPG_DIR__CREATE }, -+ {"getattr", SEPG_DIR__GETATTR }, -+ {NULL,0} -+ } -+ }, -+ { -+ "lnk_file", SEPG_CLASS_LNK_FILE, -+ { -+ {"read", SEPG_LNK_FILE__READ }, -+ {"write", SEPG_LNK_FILE__WRITE }, -+ {"create", SEPG_LNK_FILE__CREATE }, -+ {"getattr", SEPG_LNK_FILE__GETATTR }, -+ {NULL,0} -+ } -+ }, -+ { -+ "chr_file", SEPG_CLASS_CHR_FILE, -+ { -+ {"read", SEPG_CHR_FILE__READ }, -+ {"write", SEPG_CHR_FILE__WRITE }, -+ {"create", SEPG_CHR_FILE__CREATE }, -+ {"getattr", SEPG_CHR_FILE__GETATTR }, -+ {NULL,0} -+ } -+ }, -+ { -+ "blk_file", SEPG_CLASS_BLK_FILE, -+ { -+ {"read", SEPG_BLK_FILE__READ }, -+ {"write", SEPG_BLK_FILE__WRITE }, -+ {"create", SEPG_BLK_FILE__CREATE }, -+ {"getattr", SEPG_BLK_FILE__GETATTR }, -+ {NULL,0} -+ } -+ }, -+ { -+ "sock_file", SEPG_CLASS_SOCK_FILE, -+ { -+ {"read", SEPG_SOCK_FILE__READ }, -+ {"write", SEPG_SOCK_FILE__WRITE }, -+ {"create", SEPG_SOCK_FILE__CREATE }, -+ {"getattr", SEPG_SOCK_FILE__GETATTR }, -+ {NULL,0} -+ } -+ }, -+ { -+ "fifo_file", SEPG_CLASS_FIFO_FILE, -+ { -+ {"read", SEPG_FIFO_FILE__READ }, -+ {"write", SEPG_FIFO_FILE__WRITE }, -+ {"create", SEPG_FIFO_FILE__CREATE }, -+ {"getattr", SEPG_FIFO_FILE__GETATTR }, -+ {NULL, 0UL } -+ } -+ }, -+ { -+ "db_database", SEPG_CLASS_DB_DATABASE, -+ { -+ { "create", SEPG_DB_DATABASE__CREATE }, -+ { "drop", SEPG_DB_DATABASE__DROP }, -+ { "getattr", SEPG_DB_DATABASE__GETATTR }, -+ { "setattr", SEPG_DB_DATABASE__SETATTR }, -+ { "relabelfrom", SEPG_DB_DATABASE__RELABELFROM }, -+ { "relabelto", SEPG_DB_DATABASE__RELABELTO }, -+ { "access", SEPG_DB_DATABASE__ACCESS }, -+ { "install_module", SEPG_DB_DATABASE__INSTALL_MODULE }, -+ { "load_module", SEPG_DB_DATABASE__LOAD_MODULE }, -+ { "superuser", SEPG_DB_DATABASE__SUPERUSER }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_schema", SEPG_CLASS_DB_SCHEMA, -+ { -+ { "create", SEPG_DB_SCHEMA__CREATE }, -+ { "drop", SEPG_DB_SCHEMA__DROP }, -+ { "getattr", SEPG_DB_SCHEMA__GETATTR }, -+ { "setattr", SEPG_DB_SCHEMA__SETATTR }, -+ { "relabelfrom", SEPG_DB_SCHEMA__RELABELFROM }, -+ { "relabelto", SEPG_DB_SCHEMA__RELABELTO }, -+ { "search", SEPG_DB_SCHEMA__SEARCH }, -+ { "add_name", SEPG_DB_SCHEMA__ADD_NAME }, -+ { "remove_name", SEPG_DB_SCHEMA__REMOVE_NAME }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_table", SEPG_CLASS_DB_TABLE, -+ { -+ { "create", SEPG_DB_TABLE__CREATE }, -+ { "drop", SEPG_DB_TABLE__DROP }, -+ { "getattr", SEPG_DB_TABLE__GETATTR }, -+ { "setattr", SEPG_DB_TABLE__SETATTR }, -+ { "relabelfrom", SEPG_DB_TABLE__RELABELFROM }, -+ { "relabelto", SEPG_DB_TABLE__RELABELTO }, -+ { "select", SEPG_DB_TABLE__SELECT }, -+ { "update", SEPG_DB_TABLE__UPDATE }, -+ { "insert", SEPG_DB_TABLE__INSERT }, -+ { "delete", SEPG_DB_TABLE__DELETE }, -+ { "lock", SEPG_DB_TABLE__LOCK }, -+ { "reference", SEPG_DB_TABLE__REFERENCE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_sequence", SEPG_CLASS_DB_SEQUENCE, -+ { -+ { "create", SEPG_DB_SEQUENCE__CREATE }, -+ { "drop", SEPG_DB_SEQUENCE__DROP }, -+ { "getattr", SEPG_DB_SEQUENCE__GETATTR }, -+ { "setattr", SEPG_DB_SEQUENCE__SETATTR }, -+ { "relabelfrom", SEPG_DB_SEQUENCE__RELABELFROM }, -+ { "relabelto", SEPG_DB_SEQUENCE__RELABELTO }, -+ { "get_value", SEPG_DB_SEQUENCE__GET_VALUE }, -+ { "next_value", SEPG_DB_SEQUENCE__NEXT_VALUE }, -+ { "set_value", SEPG_DB_SEQUENCE__SET_VALUE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_procedure", SEPG_CLASS_DB_PROCEDURE, -+ { -+ { "create", SEPG_DB_PROCEDURE__CREATE }, -+ { "drop", SEPG_DB_PROCEDURE__DROP }, -+ { "getattr", SEPG_DB_PROCEDURE__GETATTR }, -+ { "setattr", SEPG_DB_PROCEDURE__SETATTR }, -+ { "relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM }, -+ { "relabelto", SEPG_DB_PROCEDURE__RELABELTO }, -+ { "execute", SEPG_DB_PROCEDURE__EXECUTE }, -+ { "entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT }, -+ { "install", SEPG_DB_PROCEDURE__INSTALL }, -+ { "untrusted", SEPG_DB_PROCEDURE__UNTRUSTED }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_column", SEPG_CLASS_DB_COLUMN, -+ { -+ { "create", SEPG_DB_COLUMN__CREATE }, -+ { "drop", SEPG_DB_COLUMN__DROP }, -+ { "getattr", SEPG_DB_COLUMN__GETATTR }, -+ { "setattr", SEPG_DB_COLUMN__SETATTR }, -+ { "relabelfrom", SEPG_DB_COLUMN__RELABELFROM }, -+ { "relabelto", SEPG_DB_COLUMN__RELABELTO }, -+ { "select", SEPG_DB_COLUMN__SELECT }, -+ { "update", SEPG_DB_COLUMN__UPDATE }, -+ { "insert", SEPG_DB_COLUMN__INSERT }, -+ { "reference", SEPG_DB_COLUMN__REFERENCE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_tuple", SEPG_CLASS_DB_TUPLE, -+ { -+ { "relabelfrom", SEPG_DB_TUPLE__RELABELFROM }, -+ { "relabelto", SEPG_DB_TUPLE__RELABELTO }, -+ { "select", SEPG_DB_TUPLE__SELECT }, -+ { "update", SEPG_DB_TUPLE__UPDATE }, -+ { "insert", SEPG_DB_TUPLE__INSERT }, -+ { "delete", SEPG_DB_TUPLE__DELETE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_blob", SEPG_CLASS_DB_BLOB, -+ { -+ { "create", SEPG_DB_BLOB__CREATE }, -+ { "drop", SEPG_DB_BLOB__DROP }, -+ { "getattr", SEPG_DB_BLOB__GETATTR }, -+ { "setattr", SEPG_DB_BLOB__SETATTR }, -+ { "relabelfrom", SEPG_DB_BLOB__RELABELFROM }, -+ { "relabelto", SEPG_DB_BLOB__RELABELTO }, -+ { "read", SEPG_DB_BLOB__READ }, -+ { "write", SEPG_DB_BLOB__WRITE }, -+ { "import", SEPG_DB_BLOB__IMPORT }, -+ { "export", SEPG_DB_BLOB__EXPORT }, -+ { NULL, 0UL }, -+ } -+ } -+ }; -+ -+ /* -+ * sepgsqlTransToExternalClass -+ * It translate the given class code (defined as SEPGCLASS_(class)) into -+ * external code which is necessary to communicate in-kernel SELinux -+ */ -+ extern security_class_t -+ sepgsqlTransToExternalClass(uint16 tclass) -+ { -+ Assert(tclass < SEPG_CLASS_MAX); -+ -+ return string_to_security_class(selinux_catalog[tclass].class_name); -+ } -+ -+ /* -+ * sepgsqlTransToInternalPerms -+ * It translate the given permission masks into internal representation -+ * defined as SEPG_(class)_(permission). -+ */ -+ extern void -+ sepgsqlTransToInternalPerms(security_class_t tclass, struct av_decision *avd) -+ { -+ security_class_t tclass_ex; -+ struct av_decision i_avd; -+ int i, deny_unknown; -+ -+ Assert(tclass < SEPG_CLASS_MAX); -+ -+ memset(&i_avd, 0, sizeof(struct av_decision)); -+ -+ deny_unknown = security_deny_unknown(); -+ -+ tclass_ex = sepgsqlTransToExternalClass(tclass); -+ for (i=0; selinux_catalog[tclass].av[i].perm_name; i++) -+ { -+ const char *perm_name = selinux_catalog[tclass].av[i].perm_name; -+ access_vector_t perm_code = selinux_catalog[tclass].av[i].perm_code; -+ access_vector_t perm_code_ex; -+ -+ perm_code_ex = string_to_av_perm(tclass_ex, perm_name); -+ if (!perm_code_ex) -+ { -+ /* fill up undefined permission */ -+ if (!deny_unknown) -+ i_avd.allowed |= perm_code; -+ i_avd.decided |= perm_code; -+ i_avd.auditdeny |= perm_code; -+ continue; -+ } -+ -+ if (avd->allowed & perm_code_ex) -+ i_avd.allowed |= perm_code; -+ if (avd->decided & perm_code_ex) -+ i_avd.decided |= perm_code; -+ if (avd->auditallow & perm_code_ex) -+ i_avd.auditallow |= perm_code; -+ if (avd->auditdeny & perm_code_ex) -+ i_avd.auditdeny |= perm_code; -+ } -+ -+ avd->allowed = i_avd.allowed; -+ avd->decided = i_avd.decided; -+ avd->auditallow = i_avd.auditallow; -+ avd->auditdeny = i_avd.auditdeny; -+ } -+ -+ /* -+ * sepgsqlGetClassString -+ * sepgsqlGetPermissionString -+ * It returns text representation of object classes/permissions -+ */ -+ const char * -+ sepgsqlGetClassString(uint16 tclass) -+ { -+ Assert(tclass < SEPG_CLASS_MAX); -+ -+ return selinux_catalog[tclass].class_name; -+ } -+ -+ const char * -+ sepgsqlGetPermString(uint16 tclass, uint32 permission) -+ { -+ int i; -+ -+ Assert(tclass < SEPG_CLASS_MAX); -+ -+ for (i=0; selinux_catalog[tclass].av[i].perm_name; i++) -+ { -+ if (selinux_catalog[tclass].av[i].perm_code == permission) -+ return selinux_catalog[tclass].av[i].perm_name; -+ } -+ return NULL; -+ } -+ -+ #if 0 -+ -+ /* -+ * sepgsqlFileObjectClass -+ * -+ * It returns proper object class of filesystem object already opened. -+ * It is necessary to check privileges voluntarily. -+ */ -+ uint16 -+ sepgsqlFileObjectClass(int fdesc) -+ { -+ struct stat stbuf; -+ -+ if (fstat(fdesc, &stbuf) != 0) -+ ereport(ERROR, -+ (errcode_for_file_access(), -+ errmsg("could not stat file descriptor: %d", fdesc))); -+ -+ if (S_ISDIR(stbuf.st_mode)) -+ return SEPG_CLASS_DIR; -+ else if (S_ISCHR(stbuf.st_mode)) -+ return SEPG_CLASS_CHR_FILE; -+ else if (S_ISBLK(stbuf.st_mode)) -+ return SEPG_CLASS_BLK_FILE; -+ else if (S_ISFIFO(stbuf.st_mode)) -+ return SEPG_CLASS_FIFO_FILE; -+ else if (S_ISLNK(stbuf.st_mode)) -+ return SEPG_CLASS_LNK_FILE; -+ else if (S_ISSOCK(stbuf.st_mode)) -+ return SEPG_CLASS_SOCK_FILE; -+ -+ return SEPG_CLASS_FILE; -+ } -+ -+ /* -+ * sepgsqlTupleObjectClass -+ * -+ * It returns correct object class of given tuple -+ */ -+ uint16 -+ sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple) -+ { -+ Form_pg_class clsForm; -+ Form_pg_attribute attForm; -+ -+ switch (relid) -+ { -+ case DatabaseRelationId: -+ return SEPG_CLASS_DB_DATABASE; -+ -+ case NamespaceRelationId: -+ return SEPG_CLASS_DB_SCHEMA; -+ -+ case RelationRelationId: -+ clsForm = (Form_pg_class) GETSTRUCT(tuple); -+ if (clsForm->relkind == RELKIND_RELATION) -+ return SEPG_CLASS_DB_TABLE; -+ if (clsForm->relkind == RELKIND_SEQUENCE) -+ return SEPG_CLASS_DB_SEQUENCE; -+ break; -+ -+ case AttributeRelationId: -+ attForm = (Form_pg_attribute) GETSTRUCT(tuple); -+ if (IsBootstrapProcessingMode() && -+ (attForm->attrelid == TypeRelationId || -+ attForm->attrelid == ProcedureRelationId || -+ attForm->attrelid == AttributeRelationId || -+ attForm->attrelid == RelationRelationId)) -+ return SEPG_CLASS_DB_COLUMN; -+ -+ if (get_rel_relkind(attForm->attrelid) == RELKIND_RELATION) -+ return SEPG_CLASS_DB_COLUMN; -+ break; -+ -+ case ProcedureRelationId: -+ return SEPG_CLASS_DB_PROCEDURE; -+ -+ case LargeObjectRelationId: -+ return SEPG_CLASS_DB_BLOB; -+ } -+ return SEPG_CLASS_DB_TUPLE; -+ } -+ -+ /* -+ * sepgsqlTupleNamespace -+ * -+ * It returns an OID of the namespace, if the given system object is -+ * deployed under a certain namespace. -+ */ -+ Oid -+ sepgsqlTupleNamespace(Oid relOid, HeapTuple tuple) -+ { -+ Oid nspOid; -+ -+ switch (relOid) -+ { -+ case RelationRelationId: -+ nspOid = ((Form_pg_class) GETSTRUCT(tuple))->relnamespace; -+ break; -+ -+ case ConstraintRelationId: -+ nspOid = ((Form_pg_constraint) GETSTRUCT(tuple))->connamespace; -+ break; -+ -+ case ConversionRelationId: -+ nspOid = ((Form_pg_conversion) GETSTRUCT(tuple))->connamespace; -+ break; -+ -+ case OperatorClassRelationId: -+ nspOid = ((Form_pg_opclass) GETSTRUCT(tuple))->opcnamespace; -+ break; -+ -+ case OperatorRelationId: -+ nspOid = ((Form_pg_operator) GETSTRUCT(tuple))->oprnamespace; -+ break; -+ -+ case OperatorFamilyRelationId: -+ nspOid = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfnamespace; -+ break; -+ -+ case ProcedureRelationId: -+ nspOid = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace; -+ break; -+ -+ case TSConfigRelationId: -+ nspOid = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgnamespace; -+ break; -+ -+ case TSDictionaryRelationId: -+ nspOid = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictnamespace; -+ break; -+ -+ case TSParserRelationId: -+ nspOid = ((Form_pg_ts_parser) GETSTRUCT(tuple))->prsnamespace; -+ break; -+ -+ case TSTemplateRelationId: -+ nspOid = ((Form_pg_ts_template) GETSTRUCT(tuple))->tmplnamespace; -+ break; -+ -+ default: -+ /* no specific namespace */ -+ nspOid = InvalidOid; -+ break; -+ } -+ -+ return nspOid; -+ } -+ -+ /* -+ * sepgsqlTupleAuditName -+ * -+ * It returns an OID of the namespace, if the given system object is -+ * deployed under a certain namespace. -+ */ -+ void -+ sepgsqlTupleAuditName(Oid relid, HeapTuple tuple, char *auname_buf) -+ { -+ char *name; -+ Oid extid; -+ -+ switch (relid) -+ { -+ case AccessMethodRelationId: -+ name = NameStr(((Form_pg_am) GETSTRUCT(tuple))->amname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case AttributeRelationId: -+ name = NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname); -+ extid = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid; -+ sprintf(audit_name, "%s.%s", name, extid); -+ return; -+ -+ case AuthIdRelationId: -+ name = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case ConversionRelationId: -+ name = NameStr(((Form_pg_conversion) GETSTRUCT(tuple))->conname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case DatabaseRelationId: -+ name = NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case ForeignDataWrapperRelationId: -+ name = NameStr(((Form_pg_foreign_data_wrapper) GETSTRUCT(tuple))->fdwname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case ForeignServerRelationId: -+ name = NameStr(((Form_pg_foreign_server) GETSTRUCT(tuple))->srvname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case LanguageRelationId: -+ name = NameStr(((Form_pg_language) GETSTRUCT(tuple))->lanname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case NamespaceRelationId: -+ name = NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case OperatorClassRelationId: -+ name = NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case OperatorRelationId: -+ name = NameStr(((Form_pg_operator) GETSTRUCT(tuple))->oprname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case OperatorFamilyRelationId: -+ name = NameStr(((Form_pg_opfamily) GETSTRUCT(tuple))->opfname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case ProcedureRelationId: -+ name = NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case RelationRelationId: -+ name = NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case TableSpaceRelationId: -+ name = NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case TSConfigRelationId: -+ name = NameStr(((Form_pg_ts_config) GETSTRUCT(tuple))->cfgname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case TSDictionaryRelationId: -+ name = NameStr(((Form_pg_ts_dict) GETSTRUCT(tuple))->dictname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case TSParserRelationId: -+ name = NameStr(((Form_pg_ts_parser) GETSTRUCT(tuple))->prsname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ case TSTemplateRelationId: -+ name = NameStr(((Form_pg_templace) GETSTRUCT(tuple))->tmplname); -+ strncpy(auname_buf, name, NAMEDATALEN); -+ break; -+ -+ default: -+ /* no auditable name */ -+ auname_buf[0] = '\0'; -+ break; -+ } -+ } -+ #endif -diff -Nrpc blob/src/backend/security/sepgsql/policy/Makefile sepgsql/src/backend/security/sepgsql/policy/Makefile -*** blob/src/backend/security/sepgsql/policy/Makefile Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/policy/Makefile Wed Jul 15 19:35:52 2009 -*************** -*** 0 **** ---- 1,28 ---- -+ # -+ # Makefile for SE-PostgreSQL security policy module -+ # -+ top_builddir = ../../../../.. -+ include $(top_builddir)/src/Makefile.global -+ -+ POLICY_BASEDIR := $(DESTDIR)/usr/share/selinux -+ POLICY_MAKEFILE := $(POLICY_BASEDIR)/devel/Makefile -+ POLICY_INSTDIR := $(POLICY_BASEDIR)/packages -+ PREFIX_RULE := "s/%%__prefix__%%/$(shell echo $(prefix)|sed 's/\//\\\//g')/g" -+ BINDIR_RULE := "s/%%__bindir__%%/$(shell echo $(bindir)|sed 's/\//\\\//g')/g" -+ LIBDIR_RULE := "s/%%__libdir__%%/$(shell echo $(pkglibdir)|sed 's/\//\\\//g')/g" -+ -+ all: sepostgresql-devel.pp -+ -+ install: all -+ test -d $(POLICY_INSTDIR) || mkdir -p $(POLICY_INSTDIR) -+ install -p -m 0644 sepostgresql-devel.pp $(POLICY_INSTDIR) -+ -+ sepostgresql-devel.pp: sepostgresql-devel.te sepostgresql-devel.fc -+ $(MAKE) -f $(POLICY_MAKEFILE) -+ -+ sepostgresql-devel.fc: sepostgresql-devel.fc.template -+ cat $< | sed -e $(PREFIX_RULE) -e $(BINDIR_RULE) -e $(LIBDIR_RULE) > $@ -+ -+ clean: -+ $(MAKE) -f $(POLICY_MAKEFILE) clean -+ rm -f *.fc -diff -Nrpc blob/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template -*** blob/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.fc.template Wed Jul 15 19:35:52 2009 -*************** -*** 0 **** ---- 1,12 ---- -+ # -+ # SE-PostgreSQL install path -+ # -+ %%__prefix__%%(/.*)? -- gen_context(system_u:object_r:usr_t,s0) -+ -+ %%__bindir__%%/(se)?postgres -- gen_context(system_u:object_r:postgresql_exec_t,s0) -+ %%__bindir__%%/(se)?pg_ctl -- gen_context(system_u:object_r:initrc_exec_t,s0) -+ %%__bindir__%%/initdb(\.sepgsql)? -- gen_context(system_u:object_r:postgresql_exec_t,s0) -+ %%__bindir__%%(/.*)? -- gen_context(system_u:object_r:bin_t,s0) -+ -+ %%__libdir__%%(/.*)? -- gen_context(system_u:object_r:lib_t,s0) -+ -diff -Nrpc blob/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te -*** blob/src/backend/security/sepgsql/policy/sepostgresql-devel.te Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te Tue Dec 1 17:11:40 2009 -*************** -*** 0 **** ---- 1,123 ---- -+ policy_module(sepostgresql-devel, 3.29) -+ -+ gen_require(` -+ class db_database all_db_database_perms; -+ class db_table all_db_table_perms; -+ class db_procedure all_db_procedure_perms; -+ class db_column all_db_column_perms; -+ class db_tuple all_db_tuple_perms; -+ class db_blob all_db_blob_perms; -+ -+ attribute sepgsql_client_type; -+ attribute sepgsql_unconfined_type; -+ -+ attribute sepgsql_database_type; -+ attribute sepgsql_table_type; -+ attribute sepgsql_sysobj_table_type; -+ attribute sepgsql_procedure_type; -+ attribute sepgsql_blob_type; -+ attribute sepgsql_module_type; -+ -+ # for regression test -+ type bin_t; -+ type user_home_t; -+ type sepgsql_trusted_proc_exec_t; -+ -+ attribute tmpfile; -+ ') -+ -+ ################################# -+ # -+ # Domain for Testcases -+ # -+ -+ role sepgsql_test_r; -+ -+ userdom_unpriv_user_template(sepgsql_test) -+ postgresql_role(sepgsql_test_r, sepgsql_test_t) -+ -+ allow sepgsql_test_t tmpfile : dir search_dir_perms; -+ allow sepgsql_test_t tmpfile : file rw_file_perms; -+ -+ optional_policy(` -+ term_write_all_terms(sepgsql_test_t) -+ ') -+ -+ optional_policy(` -+ gen_require(` -+ type unconfined_t; -+ role unconfined_r; -+ ') -+ -+ tunable_policy(`sepgsql_regression_test_mode',` -+ allow unconfined_t sepgsql_test_t : process transition; -+ ') -+ unconfined_rw_pipes(sepgsql_test_t) -+ role unconfined_r types sepgsql_test_t; -+ role unconfined_r types sepgsql_trusted_proc_t; -+ ') -+ -+ ################################# -+ # -+ # SE-PostgreSQL Declarations -+ # -+ -+ ## -+ ##

-+ ## Allow to generate auditallow logs -+ ##

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

-+ ## Allow to generate auditdeny logs -+ ##

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

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

-+ ##
-+ gen_tunable(sepgsql_regression_test_mode, false) -+ -+ ######################################## -+ # -+ # SE-PostgreSQL audit switch for debugging -+ # -+ tunable_policy(`sepgsql_enable_auditallow',` -+ auditallow domain sepgsql_database_type : db_database *; -+ auditallow domain sepgsql_table_type : db_table *; -+ auditallow domain sepgsql_table_type : db_column *; -+ auditallow domain sepgsql_table_type : db_tuple { relabelfrom relabelto }; -+ auditallow domain sepgsql_sysobj_table_type : db_tuple *; -+ auditallow domain sepgsql_procedure_type : db_procedure *; -+ auditallow domain sepgsql_blob_type : db_blob *; -+ auditallow domain sepgsql_module_type : db_database { install_module }; -+ auditallow sepgsql_database_type sepgsql_module_type : db_database { load_module }; -+ ') -+ -+ tunable_policy(`! sepgsql_enable_auditdeny',` -+ dontaudit domain sepgsql_database_type : db_database *; -+ dontaudit domain sepgsql_table_type : db_table *; -+ dontaudit domain sepgsql_table_type : db_column *; -+ dontaudit domain sepgsql_table_type : db_tuple { relabelfrom relabelto }; -+ dontaudit domain sepgsql_sysobj_table_type : db_tuple *; -+ dontaudit domain sepgsql_procedure_type : db_procedure *; -+ dontaudit domain sepgsql_blob_type : db_blob *; -+ dontaudit domain sepgsql_module_type : db_database { install_module }; -+ dontaudit sepgsql_database_type sepgsql_module_type : db_database { load_module }; -+ ') -+ -+ ######################################## -+ # -+ # SE-PostgreSQL regression test mode switch -+ # -+ tunable_policy(`sepgsql_regression_test_mode',` -+ allow sepgsql_client_type user_home_t : db_database { install_module }; -+ allow sepgsql_unconfined_type user_home_t : db_database { install_module }; -+ allow sepgsql_database_type user_home_t : db_database { load_module }; -+ ') -diff -Nrpc blob/src/backend/security/sepgsql/selinux.c sepgsql/src/backend/security/sepgsql/selinux.c -*** blob/src/backend/security/sepgsql/selinux.c Thu Jan 1 09:00:00 1970 ---- sepgsql/src/backend/security/sepgsql/selinux.c Thu Dec 24 21:59:25 2009 -*************** -*** 0 **** ---- 1,1305 ---- -+ /* -+ * src/backend/security/sepgsql/selinux.c -+ * Routines to communicate with SELinux. -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #include "postgres.h" -+ -+ #include "access/hash.h" -+ #include "access/xact.h" -+ #include "catalog/pg_security.h" -+ #include "lib/stringinfo.h" -+ #include "libpq/libpq-be.h" -+ #include "libpq/pqsignal.h" -+ #include "miscadmin.h" -+ #include "security/sepgsql.h" -+ #include "storage/fd.h" -+ #include "utils/builtins.h" -+ #include "utils/memutils.h" -+ -+ #include -+ #include -+ #include -+ -+ /* -+ * selinux_catalog -+ * -+ * This static translation lookup table enables to associate a certain -+ * object class/permission name with its internal code, such as -+ * SEPG_CLASS_DB_SCHEMA. -+ * -+ * SELinux requires applications to represent object class and a set of -+ * permissions in code, instead of its name, when we ask SELinux's decision. -+ * -+ * See the definition of security_compute_av(3) API in libselinux. -+ * We need to gives a code of object class, and interpret what permissions -+ * are allowed on the object class from av_decision structure. -+ * Actual values of the code depend on the security policy. In other words, -+ * we cannot know what number is assigned on a certain object class and -+ * permissions. -+ * The string_to_security_class(3) and string_to_av_perm(3) APIs takes -+ * arguments with the name of object class/permission, and returns the -+ * code for the given object class/permissions. -+ * For example, we can know what code is assigned on the "db_table" class -+ * using these functions as follows: -+ * -+ * uint16 tclass_ex = string_to_security_class("db_table"); -+ * -+ * On the other hand, we use an alternative code internally to simplify -+ * the implementation, such as SEPG_CLASS_* for object class. -+ * The following selinux_catalog is used to translate the 'internal' -+ * code and the 'external' code. -+ * -+ * It allows to lookup name of the object class or permission corresponding -+ * to a certain 'internal' code. Then, we can give the name to SELinux's -+ * API to obtain 'external' code which can be used to ask in-kernel SELinux. -+ */ -+ static struct -+ { -+ const char *class_name; -+ uint16 class_code; -+ struct -+ { -+ const char *perm_name; -+ uint32 perm_code; -+ } perms[32]; -+ } selinux_catalog[] = { -+ { -+ "process", SEPG_CLASS_PROCESS, -+ { -+ {"translation", SEPG_PROCESS__TRANSITION }, -+ {NULL, 0} -+ } -+ }, -+ { -+ "file", SEPG_CLASS_FILE, -+ { -+ {"read", SEPG_FILE__READ }, -+ {"write", SEPG_FILE__WRITE }, -+ {"create", SEPG_FILE__CREATE }, -+ {"getattr", SEPG_FILE__GETATTR }, -+ {NULL, 0} -+ } -+ }, -+ { -+ "dir", SEPG_CLASS_DIR, -+ { -+ {"read", SEPG_DIR__READ }, -+ {"write", SEPG_DIR__WRITE }, -+ {"create", SEPG_DIR__CREATE }, -+ {"getattr", SEPG_DIR__GETATTR }, -+ {NULL,0} -+ } -+ }, -+ { -+ "lnk_file", SEPG_CLASS_LNK_FILE, -+ { -+ {"read", SEPG_LNK_FILE__READ }, -+ {"write", SEPG_LNK_FILE__WRITE }, -+ {"create", SEPG_LNK_FILE__CREATE }, -+ {"getattr", SEPG_LNK_FILE__GETATTR }, -+ {NULL,0} -+ } -+ }, -+ { -+ "chr_file", SEPG_CLASS_CHR_FILE, -+ { -+ {"read", SEPG_CHR_FILE__READ }, -+ {"write", SEPG_CHR_FILE__WRITE }, -+ {"create", SEPG_CHR_FILE__CREATE }, -+ {"getattr", SEPG_CHR_FILE__GETATTR }, -+ {NULL,0} -+ } -+ }, -+ { -+ "blk_file", SEPG_CLASS_BLK_FILE, -+ { -+ {"read", SEPG_BLK_FILE__READ }, -+ {"write", SEPG_BLK_FILE__WRITE }, -+ {"create", SEPG_BLK_FILE__CREATE }, -+ {"getattr", SEPG_BLK_FILE__GETATTR }, -+ {NULL,0} -+ } -+ }, -+ { -+ "sock_file", SEPG_CLASS_SOCK_FILE, -+ { -+ {"read", SEPG_SOCK_FILE__READ }, -+ {"write", SEPG_SOCK_FILE__WRITE }, -+ {"create", SEPG_SOCK_FILE__CREATE }, -+ {"getattr", SEPG_SOCK_FILE__GETATTR }, -+ {NULL,0} -+ } -+ }, -+ { -+ "fifo_file", SEPG_CLASS_FIFO_FILE, -+ { -+ {"read", SEPG_FIFO_FILE__READ }, -+ {"write", SEPG_FIFO_FILE__WRITE }, -+ {"create", SEPG_FIFO_FILE__CREATE }, -+ {"getattr", SEPG_FIFO_FILE__GETATTR }, -+ {NULL, 0UL } -+ } -+ }, -+ { -+ "db_database", SEPG_CLASS_DB_DATABASE, -+ { -+ { "create", SEPG_DB_DATABASE__CREATE }, -+ { "drop", SEPG_DB_DATABASE__DROP }, -+ { "getattr", SEPG_DB_DATABASE__GETATTR }, -+ { "setattr", SEPG_DB_DATABASE__SETATTR }, -+ { "relabelfrom", SEPG_DB_DATABASE__RELABELFROM }, -+ { "relabelto", SEPG_DB_DATABASE__RELABELTO }, -+ { "access", SEPG_DB_DATABASE__ACCESS }, -+ { "load_module", SEPG_DB_DATABASE__LOAD_MODULE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_schema", SEPG_CLASS_DB_SCHEMA, -+ { -+ { "create", SEPG_DB_SCHEMA__CREATE }, -+ { "drop", SEPG_DB_SCHEMA__DROP }, -+ { "getattr", SEPG_DB_SCHEMA__GETATTR }, -+ { "setattr", SEPG_DB_SCHEMA__SETATTR }, -+ { "relabelfrom", SEPG_DB_SCHEMA__RELABELFROM }, -+ { "relabelto", SEPG_DB_SCHEMA__RELABELTO }, -+ { "search", SEPG_DB_SCHEMA__SEARCH }, -+ { "add_name", SEPG_DB_SCHEMA__ADD_NAME }, -+ { "remove_name", SEPG_DB_SCHEMA__REMOVE_NAME }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_table", SEPG_CLASS_DB_TABLE, -+ { -+ { "create", SEPG_DB_TABLE__CREATE }, -+ { "drop", SEPG_DB_TABLE__DROP }, -+ { "getattr", SEPG_DB_TABLE__GETATTR }, -+ { "setattr", SEPG_DB_TABLE__SETATTR }, -+ { "relabelfrom", SEPG_DB_TABLE__RELABELFROM }, -+ { "relabelto", SEPG_DB_TABLE__RELABELTO }, -+ { "select", SEPG_DB_TABLE__SELECT }, -+ { "update", SEPG_DB_TABLE__UPDATE }, -+ { "insert", SEPG_DB_TABLE__INSERT }, -+ { "delete", SEPG_DB_TABLE__DELETE }, -+ { "lock", SEPG_DB_TABLE__LOCK }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_view", SEPG_CLASS_DB_VIEW, -+ { -+ { "create", SEPG_DB_VIEW__CREATE }, -+ { "drop", SEPG_DB_VIEW__DROP }, -+ { "getattr", SEPG_DB_VIEW__GETATTR }, -+ { "setattr", SEPG_DB_VIEW__SETATTR }, -+ { "relabelfrom", SEPG_DB_VIEW__RELABELFROM }, -+ { "relabelto", SEPG_DB_VIEW__RELABELTO }, -+ { "usage", SEPG_DB_VIEW__USAGE }, -+ { NULL, 0UL } -+ } -+ }, -+ { -+ "db_sequence", SEPG_CLASS_DB_SEQUENCE, -+ { -+ { "create", SEPG_DB_SEQUENCE__CREATE }, -+ { "drop", SEPG_DB_SEQUENCE__DROP }, -+ { "getattr", SEPG_DB_SEQUENCE__GETATTR }, -+ { "setattr", SEPG_DB_SEQUENCE__SETATTR }, -+ { "relabelfrom", SEPG_DB_SEQUENCE__RELABELFROM }, -+ { "relabelto", SEPG_DB_SEQUENCE__RELABELTO }, -+ { "get_value", SEPG_DB_SEQUENCE__GET_VALUE }, -+ { "next_value", SEPG_DB_SEQUENCE__NEXT_VALUE }, -+ { "set_value", SEPG_DB_SEQUENCE__SET_VALUE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_procedure", SEPG_CLASS_DB_PROCEDURE, -+ { -+ { "create", SEPG_DB_PROCEDURE__CREATE }, -+ { "drop", SEPG_DB_PROCEDURE__DROP }, -+ { "getattr", SEPG_DB_PROCEDURE__GETATTR }, -+ { "setattr", SEPG_DB_PROCEDURE__SETATTR }, -+ { "relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM }, -+ { "relabelto", SEPG_DB_PROCEDURE__RELABELTO }, -+ { "execute", SEPG_DB_PROCEDURE__EXECUTE }, -+ { "entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT }, -+ { "install", SEPG_DB_PROCEDURE__INSTALL }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_column", SEPG_CLASS_DB_COLUMN, -+ { -+ { "create", SEPG_DB_COLUMN__CREATE }, -+ { "drop", SEPG_DB_COLUMN__DROP }, -+ { "getattr", SEPG_DB_COLUMN__GETATTR }, -+ { "setattr", SEPG_DB_COLUMN__SETATTR }, -+ { "relabelfrom", SEPG_DB_COLUMN__RELABELFROM }, -+ { "relabelto", SEPG_DB_COLUMN__RELABELTO }, -+ { "select", SEPG_DB_COLUMN__SELECT }, -+ { "update", SEPG_DB_COLUMN__UPDATE }, -+ { "insert", SEPG_DB_COLUMN__INSERT }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_tuple", SEPG_CLASS_DB_TUPLE, -+ { -+ { "relabelfrom", SEPG_DB_TUPLE__RELABELFROM }, -+ { "relabelto", SEPG_DB_TUPLE__RELABELTO }, -+ { "select", SEPG_DB_TUPLE__SELECT }, -+ { "update", SEPG_DB_TUPLE__UPDATE }, -+ { "insert", SEPG_DB_TUPLE__INSERT }, -+ { "delete", SEPG_DB_TUPLE__DELETE }, -+ { NULL, 0UL }, -+ } -+ }, -+ { -+ "db_blob", SEPG_CLASS_DB_BLOB, -+ { -+ { "create", SEPG_DB_BLOB__CREATE }, -+ { "drop", SEPG_DB_BLOB__DROP }, -+ { "getattr", SEPG_DB_BLOB__GETATTR }, -+ { "setattr", SEPG_DB_BLOB__SETATTR }, -+ { "relabelfrom", SEPG_DB_BLOB__RELABELFROM }, -+ { "relabelto", SEPG_DB_BLOB__RELABELTO }, -+ { "read", SEPG_DB_BLOB__READ }, -+ { "write", SEPG_DB_BLOB__WRITE }, -+ { "import", SEPG_DB_BLOB__IMPORT }, -+ { "export", SEPG_DB_BLOB__EXPORT }, -+ { NULL, 0UL }, -+ } -+ } -+ }; -+ -+ /* -+ * GUC option: sepostgresql = [default|enforcing|permissive|disabled] -+ * -+ * SEPGSQL_MODE_DEFAULT : It follows system setting -+ * SEPGSQL_MODE_ENFORCING : Use enforcing mode always -+ * SEPGSQL_MODE_PERMISSIVE : Use permissive mode always -+ * SEPGSQL_MODE_INTERNAL : Internally used mode. Same as permissive mode -+ * except for silence in audit logs -+ * SEPGSQL_MODE_DISABLED : It always disables SE-PgSQL configuration -+ */ -+ int sepostgresql_mode; -+ -+ /* -+ * userspace access vector cache -+ * -+ * It enables to cache access control decisions in userspace, and minimize -+ * the number of system call invocations. -+ */ -+ static MemoryContext AvcMemCtx = NULL; -+ -+ #define AVC_HASH_NUM_SLOTS 256 -+ #define AVC_HASH_NUM_NODES 180 -+ -+ typedef struct _avc_datum -+ { -+ uint32 hash_key; -+ -+ uint16 tclass; -+ sepgsql_sid_t tsid; -+ sepgsql_sid_t nsid; -+ char *tcontext; -+ char *ncontext; -+ -+ uint32 allowed; -+ uint32 auditallow; -+ uint32 auditdeny; -+ bool permissive; -+ -+ bool hot_cache; -+ } avc_datum; -+ -+ typedef struct _avc_page -+ { -+ struct _avc_page *next; -+ -+ List *slot[AVC_HASH_NUM_SLOTS]; -+ -+ uint32 avc_count; -+ uint32 lru_hint; -+ -+ char scontext[1]; -+ } avc_page; -+ -+ static avc_page *current_page = NULL; -+ -+ static int avc_version; -+ -+ /* -+ * selinux_state -+ * -+ * It is deployed on the shared memory region, to show the system -+ * state of SELinux and its security policy. -+ * -+ * The selinux_state->version should be checked prior to avc accesses. -+ * If it does not match with the local avc_version, it means that -+ * system security policy was reloaded or system state (enforcing -+ * or permissive) was changed. -+ * -+ * The state monitoring worker process receives messages from the -+ * kernel using libselinux, and it updates the selinux_state. -+ */ -+ struct -+ { -+ int version; -+ -+ bool enforcing; -+ } *selinux_state = NULL; -+ -+ /* -+ * sepgsqlShmemSize -+ * -+ * It returns required size for shared memory segment -+ */ -+ Size -+ sepgsqlShmemSize(void) -+ { -+ if (!sepgsqlIsEnabled()) -+ return 0; -+ -+ return sizeof(*selinux_state); -+ } -+ -+ /* -+ * sepgsqlShmemInit -+ * -+ * It attaches shared memory segment. -+ */ -+ static void -+ sepgsqlShmemInit(void) -+ { -+ bool found; -+ -+ selinux_state = ShmemInitStruct("SELinux system state", -+ sepgsqlShmemSize(), &found); -+ if (!found) -+ { -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ -+ selinux_state->version = 0; -+ selinux_state->enforcing = (security_getenforce() > 0); -+ -+ LWLockRelease(SepgsqlAvcLock); -+ } -+ } -+ -+ /* -+ * sepgsqlIsEnabled -+ * sepgsqlIsEnabledBootstrap -+ * -+ * If it returns true, SE-PgSQL is enabled. Otherwise, it is disabled. -+ */ -+ bool -+ sepgsqlIsEnabledBootstrap(void) -+ { -+ static int enabled = -1; -+ -+ /* -+ * If sepostgresql = off, it is always disabled. -+ */ -+ if (sepostgresql_mode == SEPGSQL_MODE_DISABLED) -+ return false; -+ -+ /* -+ * SE-PgSQL needs SELinux is enabled on the operating system. -+ * If it is disabled, SE-PgSQL has to be also disabled, even if -+ * 'enforcing' or 'permissive' are specified. -+ */ -+ if (enabled < 0) -+ enabled = is_selinux_enabled(); -+ -+ return enabled > 0 ? true : false; -+ } -+ -+ bool -+ sepgsqlIsEnabled(void) -+ { -+ /* -+ * SE-PgSQL is not ready in bootstraping mode, -+ * except for initial labeling process -+ */ -+ if (IsBootstrapProcessingMode()) -+ return false; -+ -+ return sepgsqlIsEnabledBootstrap(); -+ } -+ -+ /* -+ * sepgsqlGetEnforce -+ * -+ * It returns true, if SE-PgSQL performs in enforcing mode. -+ * -+ * In enforcing mode, SE-PgSQL performs as expected. It checks permissions -+ * on the required action, and it prevents them if violated. -+ * In permissive mode, SE-PgSQL also checks permissions, but it does not -+ * prevent anything, even if violated. It generates audit logs for access -+ * violations, so we can use this mode to debug security policy itself. -+ */ -+ bool -+ sepgsqlGetEnforce(void) -+ { -+ if (sepostgresql_mode == SEPGSQL_MODE_DEFAULT) -+ { -+ bool rc; -+ -+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED); -+ rc = selinux_state->enforcing; -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return rc; -+ } -+ else if (sepostgresql_mode == SEPGSQL_MODE_ENFORCING) -+ return true; -+ -+ return false; -+ } -+ -+ /* -+ * sepgsqlShowMode -+ * -+ * It returns the current performing mode ('selinux_support') -+ * in human readable form. -+ */ -+ char * -+ sepgsqlShowMode(void) -+ { -+ if (!sepgsqlIsEnabled()) -+ return "disabled"; -+ -+ if (!sepgsqlGetEnforce()) -+ return "permissive"; -+ -+ return "enforcing"; -+ } -+ -+ /* -+ * sepgsqlGetClientLabel -+ * sepgsqlSetClientLabel -+ * sepgsqlGetServerLabel -+ */ -+ static char *clientLabel = NULL; -+ -+ char * -+ sepgsqlGetClientLabel(void) -+ { -+ if (clientLabel) -+ return clientLabel; -+ -+ if (!MyProcPort) -+ { -+ /* -+ * When this server process was launched in single-user mode, -+ * it does not have any client socket, and the server process also -+ * performs as a client in same time. So, we apply a security context -+ * of the current process as a client's one. -+ * The getcon_raw(3) is an libselinux API to obtain security context -+ * of the current process in raw format. -+ */ -+ if (getprevcon_raw(&clientLabel) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("could not get server's security context"))); -+ } -+ else -+ { -+ /* -+ * Otherwise, SE-PgSQL obtains the security context of the client -+ * process using getpeercon(3). It is an API of SELinux to obtain -+ * the security context of the peer process for the given file -+ * descriptor of the client socket. -+ * For example, a process labeled as "system_u:system_r:httpd_t:s0" -+ * (which is typically apache/httpd) connect to the PgSQL server, -+ * getpeercon_raw() in server side returns the security context -+ * in client side. -+ * If MyProcPort->sock came from unix domain socket, we don't need -+ * any special configuration. OS handles them correctly. -+ * If it is tcp/ip socket, either labeled ipsec or static fallback -+ * context should be configured. -+ * The labeled ipsec is a feature to deliver the security context -+ * of remote peer processes with an enhancement of key exchange -+ * server (racoon). If SELinux is also available in the client host -+ * also, it is the most preferable option. -+ * The static fallback context is a feature to assign an alternative -+ * security context based on the source address and network device -+ * in usage. It can be applied, even if Windows is run on the client. -+ */ -+ if (getpeercon_raw(MyProcPort->sock, &clientLabel) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("could not get client's security context"))); -+ } -+ return clientLabel; -+ } -+ -+ char * -+ sepgsqlSetClientLabel(char *new_label) -+ { -+ char *old_label = clientLabel; -+ avc_page *new_page; -+ int i, length; -+ -+ /* -+ * (1) Set new security context -+ */ -+ clientLabel = new_label; -+ -+ /* -+ * (2) Switch current AVC page -+ */ -+ if (current_page) -+ { -+ new_page = current_page; -+ do { -+ if (strcmp(new_page->scontext, new_label) == 0) -+ { -+ current_page = new_page; -+ return old_label; -+ } -+ new_page = new_page->next; -+ } while (new_page != current_page); -+ } -+ -+ /* Not found, create a new avc_page */ -+ length = sizeof(avc_page) + strlen(new_label); -+ new_page = MemoryContextAllocZero(AvcMemCtx, length); -+ -+ strcpy(new_page->scontext, new_label); -+ for (i=0; i < AVC_HASH_NUM_SLOTS; i++) -+ new_page->slot[i] = NIL; -+ -+ if (!current_page) -+ new_page->next = new_page; -+ else -+ { -+ new_page->next = current_page->next; -+ current_page->next = new_page; -+ } -+ -+ current_page = new_page; -+ -+ /* return old label */ -+ return old_label; -+ } -+ -+ char * -+ sepgsqlGetServerLabel(void) -+ { -+ static char *serverLabel = NULL; -+ -+ if (!serverLabel) -+ { -+ if (getcon_raw(&serverLabel) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("could not get server's security context"))); -+ } -+ return serverLabel; -+ } -+ -+ /* -+ * sepgsqlAuditLog -+ * -+ * It generates a security audit record. In the default, it writes out -+ * audit records into standard PG's logfile. It also allows to set up -+ * external audit log receiver, such as auditd in Linux, using the -+ * sepgsql_audit_hook. -+ * -+ * SELinux can control what should be audited and should not using -+ * "auditdeny" and "auditallow" rules in the security policy. In the -+ * default, all the access violations are audited, and all the access -+ * allowed are not audited. But we can set up the security policy, so -+ * we can have exceptions. So, it is necessary to follow the suggestion -+ * come from the security policy. (av_decision.auditallow and auditdeny) -+ * -+ * Security audit is an important feature, because it enables us to check -+ * what was happen if we have a security incident. In fact, ISO/IEC15408 -+ * defines several security functionalities for audit features. -+ */ -+ static void -+ sepgsqlAuditLog(bool denied, char *scontext, char *tcontext, -+ uint16 tclass, uint32 audited, const char *audit_name) -+ { -+ //static int auditfd = -2; -+ StringInfoData buf; -+ const char *tclass_name; -+ const char *perm_name; -+ int i; -+ -+ /* -+ * translation of security contexts to human readable format, -+ * if sepgsql_mcstrans is turned on. -+ */ -+ scontext = sepgsqlTransSecLabelOut(scontext); -+ tcontext = sepgsqlTransSecLabelOut(tcontext); -+ -+ /* lookup name of the object class */ -+ tclass_name = selinux_catalog[tclass].class_name; -+ -+ /* lookup name of the permissions */ -+ initStringInfo(&buf); -+ appendStringInfo(&buf, "{"); -+ -+ for (i=0; selinux_catalog[tclass].perms[i].perm_name; i++) -+ { -+ if (audited & (1UL << i)) -+ { -+ perm_name = selinux_catalog[tclass].perms[i].perm_name; -+ appendStringInfo(&buf, " %s", perm_name); -+ } -+ } -+ appendStringInfo(&buf, " }"); -+ -+ appendStringInfo(&buf, " scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, tclass_name); -+ if (audit_name) -+ appendStringInfo(&buf, " name=%s", audit_name); -+ -+ ereport(LOG, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("SELinux: %s %s", -+ (denied ? "denied" : "allowed"), buf.data))); -+ } -+ -+ /* -+ * computePermsInternal -+ * -+ * It actually asks SELinux what permissions are allowed on a pair of -+ * the security contexts and object class. It also returns what permissions -+ * should be audited on access violation or allowed. -+ * In most cases, subject's security context (scontext) is a client, and -+ * target security context (tcontext) is a database object. -+ * -+ * The access control decision shall be set on the given av_decision. -+ * The av_decision.allowed has a bitmask of SEPG___ -+ * to suggest a set of allowed actions in this object class. -+ */ -+ static void -+ computePermsInternal(char *scontext, char *tcontext, -+ uint16 tclass, struct av_decision *avd) -+ { -+ const char *tclass_name; -+ security_class_t tclass_ex; -+ struct av_decision avd_ex; -+ int i, deny_unknown = security_deny_unknown(); -+ -+ /* Get external code of the object class*/ -+ Assert(tclass < SEPG_CLASS_MAX); -+ Assert(tclass == selinux_catalog[tclass].class_code); -+ -+ tclass_name = selinux_catalog[tclass].class_name; -+ tclass_ex = string_to_security_class(tclass_name); -+ -+ if (tclass_ex == 0) -+ { -+ /* -+ * If the current security policy does not support permissions -+ * corresponding to database objects, we fill up them with dummy -+ * data. -+ * If security_deny_unknown() returns positive value, undefined -+ * permissions should be denied. Otherwise, allowed -+ */ -+ avd->allowed = (deny_unknown > 0 ? 0 : ~0UL); -+ avd->auditallow = 0UL; -+ avd->auditdeny = ~0UL; -+ avd->flags = 0; -+ -+ return; -+ } -+ -+ /* -+ * Ask SELinux what is allowed set of permissions on a pair of the -+ * security contexts and the given object class. -+ */ -+ if (security_compute_av_flags_raw(scontext, tcontext, -+ tclass_ex, 0, &avd_ex) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("SELinux could not compute av_decision: " -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, tclass_name))); -+ -+ /* -+ * SELinux returns its access control decision as a set of permissions -+ * represented in external code which depends on run-time environment. -+ * So, we need to translate it to the internal representation before -+ * returning results for the caller. -+ */ -+ memset(avd, 0, sizeof(struct av_decision)); -+ -+ for (i=0; selinux_catalog[tclass].perms[i].perm_name; i++) -+ { -+ access_vector_t perm_code_ex; -+ const char *perm_name = selinux_catalog[tclass].perms[i].perm_name; -+ uint32 perm_code = selinux_catalog[tclass].perms[i].perm_code; -+ -+ perm_code_ex = string_to_av_perm(tclass_ex, perm_name); -+ if (perm_code_ex == 0) -+ { -+ /* fill up undefined permissions */ -+ if (!deny_unknown) -+ avd->allowed |= perm_code; -+ avd->auditdeny |= perm_code; -+ -+ continue; -+ } -+ -+ if (avd_ex.allowed & perm_code_ex) -+ avd->allowed |= perm_code; -+ if (avd_ex.auditallow & perm_code_ex) -+ avd->auditallow |= perm_code; -+ if (avd_ex.auditdeny & perm_code_ex) -+ avd->auditdeny |= perm_code; -+ } -+ -+ return; -+ } -+ -+ /* -+ * sepgsqlComputePerms -+ * -+ * It makes access control decision communicating with SELinux. -+ * If SELinux does not allow required permissions on a pair of the security -+ * contexts, it raises an error or returns false. -+ * -+ * scontext : The security context of subject. In most cases, it is client. -+ * tcontext : The security context of target database object. -+ * tclass : One of the object class code (SEPG_CLASS_*) declared in the -+ * header file. -+ * required : A bitmap of the required permissions (SEPG___) -+ * declared in the header file. -+ * audit_name : A human readable name of the database object for auditing. -+ * abort : True, if caller want to raise an error on access violation. -+ */ -+ extern bool -+ sepgsqlComputePerms(char *scontext, char *tcontext, -+ uint16 tclass, uint32 required, -+ const char *audit_name, bool abort) -+ { -+ struct av_decision avd; -+ uint32 denied; -+ uint32 audited; -+ -+ computePermsInternal(scontext, tcontext, tclass, &avd); -+ -+ /* -+ * It logs a security audit record for the given request, if necessary. -+ * When SE-PgSQL performs 'internal' mode, it needs to keep silent. -+ */ -+ denied = required & ~avd.allowed; -+ audited = denied ? (denied & avd.auditdeny) -+ : (required & avd.auditallow); -+ -+ if (audited && sepostgresql_mode != SEPGSQL_MODE_INTERNAL) -+ { -+ sepgsqlAuditLog(!!denied, scontext, tcontext, -+ tclass, audited, audit_name); -+ } -+ -+ /* -+ * If here is no policy violations, or SE-PgSQL performs in permissive -+ * mode, or the client process peforms in permissive domain, it returns -+ * normally with 'true'. -+ */ -+ if (!denied || -+ !sepgsqlGetEnforce() || -+ (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) != 0) -+ return true; -+ -+ /* -+ * Otherwise, it raises an error or returns 'false', depending on the -+ * caller's indication by 'abort'. -+ */ -+ if (abort) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("SELinux: security policy violation"))); -+ -+ return false; -+ } -+ -+ /* -+ * sepgsqlComputeCreate -+ * -+ * It returns a default security context to be assigned on a new database -+ * object. SELinux compute it based on a combination of client, upper object -+ * which owns the new object and object class. -+ * -+ * For example, when a client (staff_u:staff_r:staff_t:s0) tries to create -+ * a new table within a schema (system_u:object_r:sepgsql_schema_t:s0), -+ * SELinux looks-up its security policy. If it has a special rule on the -+ * combination of these security contexts and object class (db_table), -+ * it returns the security context suggested by the special rule. -+ * Otherwise, it returns the security context of schema, as is. -+ * -+ * We expect the caller already applies sanity/validation checks on the -+ * given security context. -+ * -+ * scontext : The security context of subject. In most cases, it is client. -+ * tcontext : The security context of the parent database object.. -+ * tclass : One of the object class code (SEPG_CLASS_*) declared in the -+ * header file. -+ */ -+ char * -+ sepgsqlComputeCreate(char *scontext, char *tcontext, uint16 tclass) -+ { -+ security_context_t ncontext; -+ security_class_t tclass_ex; -+ const char *tclass_name; -+ char *result; -+ -+ /* Get external code of the object class*/ -+ Assert(tclass < SEPG_CLASS_MAX); -+ Assert(tclass == selinux_catalog[tclass].class_code); -+ -+ tclass_name = selinux_catalog[tclass].class_name; -+ tclass_ex = string_to_security_class(tclass_name); -+ -+ /* -+ * Ask SELinux what is the default context for the given object class -+ * on a pair of security contexts -+ */ -+ if (security_compute_create_raw(scontext, tcontext, -+ tclass_ex, &ncontext)) -+ ereport(ERROR, -+ (errcode(ERRCODE_INTERNAL_ERROR), -+ errmsg("SELinux could not compute a new context: " -+ "scontext=%s tcontext=%s tclass=%s", -+ scontext, tcontext, tclass_name))); -+ /* -+ * libselinux returns malloc()'ed string, so we need to copy it -+ * on the palloc()'ed region. -+ */ -+ PG_TRY(); -+ { -+ result = pstrdup(ncontext); -+ } -+ PG_CATCH(); -+ { -+ freecon(ncontext); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(ncontext); -+ -+ return result; -+ } -+ -+ /* -+ * sepgsqlAvcReset -+ * -+ * Invalidate all the cached access control decision -+ */ -+ static void -+ sepgsqlAvcReset(void) -+ { -+ Assert(AvcMemCtx != NULL); -+ -+ MemoryContextReset(AvcMemCtx); -+ -+ current_page = NULL; -+ -+ sepgsqlSetClientLabel(sepgsqlGetClientLabel()); -+ } -+ -+ static void -+ sepgsqlAvcResetOnAbort(XactEvent event, void *arg) -+ { -+ if (event == XACT_EVENT_ABORT) -+ sepgsqlAvcReset(); -+ } -+ -+ static void -+ sepgsqlAvcResetOnSubAbort(SubXactEvent event, SubTransactionId mySubid, -+ SubTransactionId parentSubid, void *arg) -+ { -+ if (event == SUBXACT_EVENT_ABORT_SUB) -+ sepgsqlAvcReset(); -+ } -+ -+ /* -+ * sepgsqlAvcCheckValid -+ * -+ * It checks whether the current AVC pages are valid, or not. -+ */ -+ static bool -+ sepgsqlAvcCheckValid(void) -+ { -+ bool result = true; -+ -+ LWLockAcquire(SepgsqlAvcLock, LW_SHARED); -+ if (avc_version != selinux_state->version) -+ { -+ sepgsqlAvcReset(); -+ -+ /* Copy the current version to local */ -+ avc_version = selinux_state->version; -+ -+ result = false; -+ } -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return result; -+ } -+ -+ /* -+ * sepgsqlAvcReclaim -+ * -+ * It wipes recently unused AVC entries, if necessary. -+ */ -+ static void -+ sepgsqlAvcReclaim(avc_page *page) -+ { -+ ListCell *l; -+ avc_datum *cache; -+ -+ while (page->avc_count > AVC_HASH_NUM_NODES - 10) -+ { -+ foreach (l, page->slot[page->lru_hint]) -+ { -+ cache = lfirst(l); -+ -+ if (cache->hot_cache) -+ cache->hot_cache = false; -+ else -+ { -+ list_delete_ptr(page->slot[page->lru_hint], cache); -+ pfree(cache); -+ page->avc_count--; -+ } -+ } -+ page->lru_hint = (page->lru_hint + 1) % AVC_HASH_NUM_SLOTS; -+ } -+ } -+ -+ /* -+ * sepgsqlAvcMakeEntry -+ * -+ * It makes a new avc entry, and insert it to the given page. -+ */ -+ #define avc_hash_key(trelid, tsecid, tclass, nrelid) \ -+ (hash_uint32((trelid) ^ (tsecid) ^ ((tclass) << 3) ^ (nrelid))) -+ -+ static avc_datum * -+ sepgsqlAvcMakeEntry(avc_page *page, sepgsql_sid_t tsid, uint16 tclass, Oid nrelid) -+ { -+ MemoryContext oldctx; -+ char *scontext; -+ char *tcontext; -+ char *ncontext; -+ avc_datum *cache; -+ uint32 hash_key, index; -+ -+ hash_key = avc_hash_key(tsid.relid, tsid.secid, tclass, nrelid); -+ index = hash_key % AVC_HASH_NUM_SLOTS; -+ -+ oldctx = MemoryContextSwitchTo(AvcMemCtx); -+ -+ scontext = page->scontext; -+ tcontext = securityRawSecLabelOut(tsid.relid, tsid.secid); -+ ncontext = sepgsqlComputeCreate(scontext, tcontext, tclass); -+ -+ cache = palloc0(sizeof(avc_datum)); -+ -+ cache->hash_key = hash_key; -+ -+ cache->tclass = tclass; -+ -+ cache->hot_cache = true; -+ cache->tcontext = tcontext; -+ cache->ncontext = ncontext; -+ cache->tsid.relid = tsid.relid; -+ cache->tsid.secid = tsid.secid; -+ cache->nsid.relid = nrelid; -+ -+ if (OidIsValid(nrelid)) -+ cache->nsid.secid = securityRawSecLabelIn(nrelid, ncontext); -+ else -+ cache->nsid.secid = InvalidOid; -+ -+ if (!OidIsValid(nrelid)) -+ { -+ struct av_decision avd; -+ -+ computePermsInternal(scontext, tcontext, tclass, &avd); -+ cache->allowed = avd.allowed; -+ cache->auditallow = avd.auditallow; -+ cache->auditdeny = avd.auditdeny; -+ -+ if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) -+ cache->permissive = true; -+ } -+ -+ if (page->avc_count > AVC_HASH_NUM_NODES) -+ sepgsqlAvcReclaim(page); -+ -+ page->slot[index] = lcons(cache, page->slot[index]); -+ page->avc_count++; -+ -+ MemoryContextSwitchTo(oldctx); -+ -+ return cache; -+ } -+ -+ /* -+ * sepgsqlAvcLookup -+ * -+ * It lookups required AVC entry -+ */ -+ static avc_datum * -+ sepgsqlAvcLookup(avc_page *page, sepgsql_sid_t tsid, uint16 tclass, Oid nrelid) -+ { -+ avc_datum *cache = NULL; -+ uint32 hash_key, index; -+ ListCell *l; -+ -+ hash_key = avc_hash_key(tsid.relid, tsid.secid, tclass, nrelid); -+ index = hash_key % AVC_HASH_NUM_SLOTS; -+ -+ foreach (l, page->slot[index]) -+ { -+ cache = lfirst(l); -+ if (cache->hash_key == hash_key && -+ cache->tclass == tclass && -+ cache->tsid.relid == tsid.relid && -+ cache->tsid.secid == tsid.secid && -+ cache->nsid.relid == nrelid) -+ { -+ cache->hot_cache = true; -+ return cache; -+ } -+ } -+ return NULL; -+ } -+ -+ /* -+ * sepgsqlClientHasPerms -+ * -+ * It checks client's privileges on the given object using avc. -+ */ -+ bool -+ sepgsqlClientHasPerms(sepgsql_sid_t tsid, -+ uint16 tclass, uint32 required, -+ const char *audit_name, bool abort) -+ { -+ avc_datum *cache; -+ uint32 denied, audited; -+ bool result = true; -+ -+ do { -+ cache = sepgsqlAvcLookup(current_page, tsid, tclass, InvalidOid); -+ if (!cache) -+ cache = sepgsqlAvcMakeEntry(current_page, tsid, tclass, InvalidOid); -+ } while (!sepgsqlAvcCheckValid()); -+ -+ denied = required & ~cache->allowed; -+ audited = denied ? (denied & cache->auditdeny) -+ : (required & cache->auditallow); -+ if (audited) -+ { -+ sepgsqlAuditLog(!!denied, -+ current_page->scontext, -+ securityRawSecLabelOut(tsid.relid, tsid.secid), -+ cache->tclass, audited, audit_name); -+ } -+ -+ if (denied) -+ { -+ if (!sepgsqlGetEnforce() || cache->permissive) -+ cache->allowed |= required; /* prevent flood of audit log */ -+ else -+ { -+ if (abort) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("SELinux: security policy violation"))); -+ result = false; -+ } -+ } -+ -+ return result; -+ } -+ -+ /* -+ * sepgsqlClientCreateSecid -+ * sepgsqlClientCreateLabel -+ */ -+ sepgsql_sid_t -+ sepgsqlClientCreateSecid(sepgsql_sid_t tsid, uint16 tclass, Oid nrelid) -+ { -+ avc_datum *cache; -+ -+ do { -+ cache = sepgsqlAvcLookup(current_page, tsid, tclass, nrelid); -+ if (!cache) -+ cache = sepgsqlAvcMakeEntry(current_page, tsid, tclass, nrelid); -+ } while (!sepgsqlAvcCheckValid()); -+ -+ return cache->nsid; -+ } -+ -+ security_context_t -+ sepgsqlClientCreateLabel(sepgsql_sid_t tsid, uint16 tclass) -+ { -+ avc_datum *cache; -+ -+ do { -+ cache = sepgsqlAvcLookup(current_page, tsid, tclass, InvalidOid); -+ if (!cache) -+ cache = sepgsqlAvcMakeEntry(current_page, tsid, tclass, InvalidOid); -+ } while (!sepgsqlAvcCheckValid()); -+ -+ return cache->ncontext; -+ } -+ -+ /* -+ * SELinux state monitoring process -+ * -+ * This process is forked from postmaster to monitor the state of SELinux. -+ * SELinux can make a notifier message to userspace object manager via -+ * netlink socket. When it receives the message, it updates selinux_state -+ * structure assigned on shared memory region to make any instance reset -+ * its AVC soon. -+ */ -+ static int -+ sepgsql_cb_log(int type, const char *fmt, ...) -+ { -+ char *c, buffer[1024]; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ vsnprintf(buffer, sizeof(buffer), fmt, ap); -+ va_end(ap); -+ -+ c = strrchr(buffer, '\n'); -+ if (c) -+ *c = '\0'; -+ -+ ereport(LOG,(errmsg("%s", buffer))); -+ -+ return 0; -+ } -+ -+ static int -+ sepgsql_cb_setenforce(int enforce) -+ { -+ /* switch enforcing/permissive */ -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ selinux_state->enforcing = (enforce ? true : false); -+ selinux_state->version++; -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return 0; -+ } -+ -+ static int -+ sepgsql_cb_policyload(int seqno) -+ { -+ /* invalidate local avc */ -+ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); -+ selinux_state->version++; -+ LWLockRelease(SepgsqlAvcLock); -+ -+ return 0; -+ } -+ -+ bool -+ sepgsqlReceiverStart(void) -+ { -+ return sepgsqlIsEnabled(); -+ } -+ -+ void -+ sepgsqlReceiverMain(void) -+ { -+ union selinux_callback cb; -+ -+ Assert(sepgsqlIsEnabled()); -+ -+ #ifdef HAVE_SETSID -+ if (setsid() < 0) -+ elog(FATAL, "setsid() failed: %m"); -+ #endif -+ -+ /* -+ * setup the signal handler -+ */ -+ pqinitmask(); -+ pqsignal(SIGHUP, SIG_IGN); -+ pqsignal(SIGINT, SIG_IGN); -+ pqsignal(SIGTERM, exit); -+ pqsignal(SIGQUIT, exit); -+ pqsignal(SIGUSR1, SIG_IGN); -+ pqsignal(SIGUSR2, SIG_IGN); -+ pqsignal(SIGCHLD, SIG_DFL); -+ PG_SETMASK(&UnBlockSig); -+ -+ /* -+ * map shared memory segment -+ */ -+ sepgsqlShmemInit(); -+ -+ ereport(LOG, (errmsg("SELinux: netlink receiver (pid=%u)", getpid()))); -+ -+ /* -+ * setup callback functions from avc_netlink_loop() -+ */ -+ cb.func_log = sepgsql_cb_log; -+ selinux_set_callback(SELINUX_CB_LOG, cb); -+ cb.func_setenforce = sepgsql_cb_setenforce; -+ selinux_set_callback(SELINUX_CB_SETENFORCE, cb); -+ cb.func_policyload = sepgsql_cb_policyload; -+ selinux_set_callback(SELINUX_CB_POLICYLOAD, cb); -+ -+ /* -+ * open netlink socket and wait for messages -+ */ -+ avc_netlink_open(1); -+ -+ avc_netlink_loop(); -+ -+ exit(0); -+ } -+ -+ /* -+ * sepgsqlInitialize -+ * -+ * It sets up the privilege (security context) of the client and initializes -+ * a few internal stuff. -+ */ -+ void -+ sepgsqlInitialize(void) -+ { -+ if (!sepgsqlIsEnabled()) -+ return; -+ -+ /* -+ * SE-PgSQL does not prevent anything in single-user mode. -+ */ -+ if (!MyProcPort) -+ sepostgresql_mode = SEPGSQL_MODE_INTERNAL; -+ -+ sepgsqlShmemInit(); -+ -+ AvcMemCtx = AllocSetContextCreate(TopMemoryContext, -+ "SE-PgSQL userspace AVC", -+ ALLOCSET_DEFAULT_MINSIZE, -+ ALLOCSET_DEFAULT_INITSIZE, -+ ALLOCSET_DEFAULT_MAXSIZE); -+ -+ RegisterXactCallback(sepgsqlAvcResetOnAbort, NULL); -+ RegisterSubXactCallback(sepgsqlAvcResetOnSubAbort, NULL); -+ -+ /* -+ * Set client's security context -+ */ -+ sepgsqlSetClientLabel(sepgsqlGetClientLabel()); -+ } -diff -Nrpc blob/src/backend/storage/file/fd.c sepgsql/src/backend/storage/file/fd.c -*** blob/src/backend/storage/file/fd.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/storage/file/fd.c Tue Dec 15 17:30:25 2009 -*************** FileTruncate(File file, off_t offset) -*** 1329,1334 **** ---- 1329,1341 ---- - return returnCode; - } - -+ int -+ FileRawDescriptor(File file) -+ { -+ Assert(FileIsValid(file)); -+ -+ return VfdCache[file].fd; -+ } - - /* - * Routines that want to use stdio (ie, FILE*) should use AllocateFile -diff -Nrpc blob/src/backend/storage/ipc/ipci.c sepgsql/src/backend/storage/ipc/ipci.c -*** blob/src/backend/storage/ipc/ipci.c Thu May 7 08:49:32 2009 ---- sepgsql/src/backend/storage/ipc/ipci.c Wed Jul 15 19:35:52 2009 -*************** -*** 25,30 **** ---- 25,31 ---- - #include "postmaster/autovacuum.h" - #include "postmaster/bgwriter.h" - #include "postmaster/postmaster.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/ipc.h" - #include "storage/pg_shmem.h" -*************** CreateSharedMemoryAndSemaphores(bool mak -*** 119,124 **** ---- 120,126 ---- - #ifdef EXEC_BACKEND - size = add_size(size, ShmemBackendArraySize()); - #endif -+ size = add_size(size, sepgsqlShmemSize()); - - /* freeze the addin request size and include it */ - addin_request_allowed = false; -diff -Nrpc blob/src/backend/storage/large_object/inv_api.c sepgsql/src/backend/storage/large_object/inv_api.c -*** blob/src/backend/storage/large_object/inv_api.c Fri Dec 18 09:40:55 2009 ---- sepgsql/src/backend/storage/large_object/inv_api.c Fri Dec 18 10:27:56 2009 -*************** getbytealen(bytea *data) -*** 197,210 **** - * in use. - */ - Oid -! inv_create(Oid lobjId) - { - Oid lobjId_new; - - /* - * Create a new largeobject with empty data pages - */ -! lobjId_new = LargeObjectCreate(lobjId); - - /* - * dependency on the owner of largeobject ---- 197,210 ---- - * in use. - */ - Oid -! inv_create(Oid lobjId, Oid secid) - { - Oid lobjId_new; - - /* - * Create a new largeobject with empty data pages - */ -! lobjId_new = LargeObjectCreate(lobjId, secid); - - /* - * dependency on the owner of largeobject -diff -Nrpc blob/src/backend/tcop/fastpath.c sepgsql/src/backend/tcop/fastpath.c -*** blob/src/backend/tcop/fastpath.c Sat Jan 3 13:01:35 2009 ---- sepgsql/src/backend/tcop/fastpath.c Thu Sep 17 17:04:16 2009 -*************** -*** 26,31 **** ---- 26,32 ---- - #include "libpq/pqformat.h" - #include "mb/pg_wchar.h" - #include "miscadmin.h" -+ #include "security/sepgsql.h" - #include "tcop/fastpath.h" - #include "tcop/tcopprot.h" - #include "utils/acl.h" -*************** HandleFunctionRequest(StringInfo msgBuf) -*** 343,353 **** ---- 344,356 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(fip->namespace)); -+ sepgsql_schema_search(fip->namespace, true); - - aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(fid)); -+ sepgsql_proc_execute(fid); - - /* - * Prepare function call info block and insert arguments. -diff -Nrpc blob/src/backend/tcop/pquery.c sepgsql/src/backend/tcop/pquery.c -*** blob/src/backend/tcop/pquery.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/tcop/pquery.c Wed Jul 15 19:30:50 2009 -*************** PortalStart(Portal portal, ParamListInfo -*** 573,579 **** - Assert(pstmt->returningLists); - portal->tupDesc = - ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), -! false); - } - - /* ---- 573,579 ---- - Assert(pstmt->returningLists); - portal->tupDesc = - ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), -! false, false); - } - - /* -diff -Nrpc blob/src/backend/tcop/utility.c sepgsql/src/backend/tcop/utility.c -*** blob/src/backend/tcop/utility.c Fri Dec 18 09:40:55 2009 ---- sepgsql/src/backend/tcop/utility.c Fri Dec 18 10:27:56 2009 -*************** -*** 50,55 **** ---- 50,56 ---- - #include "postmaster/bgwriter.h" - #include "rewrite/rewriteDefine.h" - #include "rewrite/rewriteRemove.h" -+ #include "security/sepgsql.h" - #include "storage/fd.h" - #include "tcop/pquery.h" - #include "tcop/utility.h" -*************** check_xact_readonly(Node *parsetree) -*** 162,167 **** ---- 163,169 ---- - case T_AlterRoleSetStmt: - case T_AlterObjectSchemaStmt: - case T_AlterOwnerStmt: -+ case T_AlterSecLabelStmt: - case T_AlterSeqStmt: - case T_AlterTableStmt: - case T_RenameStmt: -*************** ProcessUtility(Node *parsetree, -*** 634,639 **** ---- 636,645 ---- - ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree); - break; - -+ case T_AlterSecLabelStmt: -+ ExecAlterSecLabelStmt((AlterSecLabelStmt *) parsetree); -+ break; -+ - case T_AlterTableStmt: - { - List *stmts; -*************** ProcessUtility(Node *parsetree, -*** 917,922 **** ---- 923,929 ---- - LoadStmt *stmt = (LoadStmt *) parsetree; - - closeAllVfds(); /* probably not necessary... */ -+ - /* Allowed names are restricted if you're not superuser */ - load_file(stmt->filename, !superuser()); - } -*************** CreateCommandTag(Node *parsetree) -*** 1664,1669 **** ---- 1671,1701 ---- - } - break; - -+ case T_AlterSecLabelStmt: -+ switch (((AlterSecLabelStmt *) parsetree)->objectType) -+ { -+ case OBJECT_DATABASE: -+ tag = "ALTER DATABASE"; -+ break; -+ case OBJECT_SCHEMA: -+ tag = "ALTER SCHEMA"; -+ break; -+ case OBJECT_TABLE: -+ case OBJECT_COLUMN: -+ tag = "ALTER TABLE"; -+ break; -+ case OBJECT_SEQUENCE: -+ tag = "ALTER SEQUENCE"; -+ break; -+ case OBJECT_FUNCTION: -+ tag = "ALTER FUNCTION"; -+ break; -+ default: -+ tag = "???"; -+ break; -+ } -+ break; -+ - case T_AlterTableStmt: - switch (((AlterTableStmt *) parsetree)->relkind) - { -*************** GetCommandLogLevel(Node *parsetree) -*** 2242,2247 **** ---- 2274,2283 ---- - lev = LOGSTMT_DDL; - break; - -+ case T_AlterSecLabelStmt: -+ lev = LOGSTMT_DDL; -+ break; -+ - case T_AlterTableStmt: - lev = LOGSTMT_DDL; - break; -diff -Nrpc blob/src/backend/utils/adt/genfile.c sepgsql/src/backend/utils/adt/genfile.c -*** blob/src/backend/utils/adt/genfile.c Sat Jan 3 13:01:35 2009 ---- sepgsql/src/backend/utils/adt/genfile.c Mon Sep 28 09:29:32 2009 -*************** -*** 24,29 **** ---- 24,30 ---- - #include "funcapi.h" - #include "miscadmin.h" - #include "postmaster/syslogger.h" -+ #include "security/sepgsql.h" - #include "storage/fd.h" - #include "utils/builtins.h" - #include "utils/memutils.h" -*************** pg_read_file(PG_FUNCTION_ARGS) -*** 99,104 **** ---- 100,108 ---- - - filename = convert_and_check_filename(filename_t); - -+ /* SELinux: check file:{read} permission */ -+ sepgsql_file_read(filename); -+ - if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL) - ereport(ERROR, - (errcode_for_file_access(), -*************** pg_stat_file(PG_FUNCTION_ARGS) -*** 159,164 **** ---- 163,170 ---- - (errmsg("must be superuser to get file information")))); - - filename = convert_and_check_filename(filename_t); -+ /* SELinux: check file:{getattr} permission */ -+ sepgsql_file_stat(filename); - - if (stat(filename, &fst) < 0) - ereport(ERROR, -diff -Nrpc blob/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/adt/ri_triggers.c -*** blob/src/backend/utils/adt/ri_triggers.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/utils/adt/ri_triggers.c Tue Dec 15 17:30:25 2009 -*************** -*** 39,44 **** ---- 39,45 ---- - #include "parser/parse_coerce.h" - #include "parser/parse_relation.h" - #include "miscadmin.h" -+ #include "security/rowlevel.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/fmgroids.h" -*************** RI_Initial_Check(Trigger *trigger, Relat -*** 2627,2632 **** ---- 2628,2634 ---- - const char *sep; - int i; - int old_work_mem; -+ int save_rowlv; - char workmembuf[32]; - int spi_result; - SPIPlanPtr qplan; -*************** RI_Initial_Check(Trigger *trigger, Relat -*** 2759,2764 **** ---- 2761,2771 ---- - SPI_result, querybuf.data); - - /* -+ * Disables the Row-level stuff during the internal consistency checks. -+ */ -+ save_rowlv = rowlvSetPerformingMode(ROWLV_BYPASS_MODE); -+ -+ /* - * Run the plan. For safety we force a current snapshot to be used. (In - * serializable mode, this arguably violates serializability, but we - * really haven't got much choice.) We don't need to register the -*************** RI_Initial_Check(Trigger *trigger, Relat -*** 2771,2776 **** ---- 2778,2786 ---- - InvalidSnapshot, - true, false, 1); - -+ /* Restore Row-level stuff */ -+ rowlvSetPerformingMode(save_rowlv); -+ - /* Check result */ - if (spi_result != SPI_OK_SELECT) - elog(ERROR, "SPI_execute_snapshot returned %d", spi_result); -*************** ri_PerformCheck(RI_QueryKey *qkey, SPIPl -*** 3265,3270 **** ---- 3275,3281 ---- - int spi_result; - Oid save_userid; - int save_sec_context; -+ int save_rowlv, temp_rowlv; - Datum vals[RI_MAX_NUMKEYS * 2]; - char nulls[RI_MAX_NUMKEYS * 2]; - -*************** ri_PerformCheck(RI_QueryKey *qkey, SPIPl -*** 3348,3359 **** ---- 3359,3377 ---- - SetUserIdAndSecContext(RelationGetForm(query_rel)->relowner, - save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - -+ /* Switch Row-level stuff behavior on FK checks, if necessary */ -+ temp_rowlv = (detectNewRows ? ROWLV_ABORT_MODE : ROWLV_FILTER_MODE); -+ save_rowlv = rowlvSetPerformingMode(temp_rowlv); -+ - /* Finally we can run the query. */ - spi_result = SPI_execute_snapshot(qplan, - vals, nulls, - test_snapshot, crosscheck_snapshot, - false, false, limit); - -+ /* Restore Row-level stuff behavior */ -+ rowlvSetPerformingMode(save_rowlv); -+ - /* Restore UID and security context */ - SetUserIdAndSecContext(save_userid, save_sec_context); - -diff -Nrpc blob/src/backend/utils/adt/tid.c sepgsql/src/backend/utils/adt/tid.c -*** blob/src/backend/utils/adt/tid.c Sat Jan 3 13:01:35 2009 ---- sepgsql/src/backend/utils/adt/tid.c Sun Dec 20 16:30:19 2009 -*************** -*** 27,32 **** ---- 27,33 ---- - #include "libpq/pqformat.h" - #include "miscadmin.h" - #include "parser/parsetree.h" -+ #include "security/sepgsql.h" - #include "utils/acl.h" - #include "utils/builtins.h" - #include "utils/rel.h" -*************** currtid_byreloid(PG_FUNCTION_ARGS) -*** 347,352 **** ---- 348,355 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_CLASS, - RelationGetRelationName(rel)); -+ /* SELinux checks */ -+ sepgsql_relation_get_transaction_id(RelationGetRelid(rel)); - - if (rel->rd_rel->relkind == RELKIND_VIEW) - return currtid_for_view(rel, tid); -*************** currtid_byrelname(PG_FUNCTION_ARGS) -*** 377,382 **** ---- 380,387 ---- - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_CLASS, - RelationGetRelationName(rel)); -+ /* SELinux checks */ -+ sepgsql_relation_get_transaction_id(RelationGetRelid(rel)); - - if (rel->rd_rel->relkind == RELKIND_VIEW) - return currtid_for_view(rel, tid); -diff -Nrpc blob/src/backend/utils/adt/trigfuncs.c sepgsql/src/backend/utils/adt/trigfuncs.c -*** blob/src/backend/utils/adt/trigfuncs.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/backend/utils/adt/trigfuncs.c Tue Sep 8 23:55:48 2009 -*************** suppress_redundant_updates_trigger(PG_FU -*** 76,81 **** ---- 76,85 ---- - !OidIsValid(HeapTupleHeaderGetOid(newheader))) - HeapTupleHeaderSetOid(newheader, HeapTupleHeaderGetOid(oldheader)); - -+ if (HeapTupleHeaderHasSecid(newheader) && -+ !OidIsValid(HeapTupleHeaderGetSecid(newheader))) -+ HeapTupleHeaderSetSecid(newheader, HeapTupleHeaderGetSecid(oldheader)); -+ - /* if the tuple payload is the same ... */ - if (newtuple->t_len == oldtuple->t_len && - newheader->t_hoff == oldheader->t_hoff && -diff -Nrpc blob/src/backend/utils/cache/plancache.c sepgsql/src/backend/utils/cache/plancache.c -*** blob/src/backend/utils/cache/plancache.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/utils/cache/plancache.c Thu Mar 18 01:55:40 2010 -*************** PlanCacheComputeResultDesc(List *stmt_li -*** 859,870 **** - if (IsA(node, Query)) - { - query = (Query *) node; -! return ExecCleanTypeFromTL(query->targetList, false); - } - if (IsA(node, PlannedStmt)) - { - pstmt = (PlannedStmt *) node; -! return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false); - } - /* other cases shouldn't happen, but return NULL */ - break; ---- 859,870 ---- - if (IsA(node, Query)) - { - query = (Query *) node; -! return ExecCleanTypeFromTL(query->targetList, false, false); - } - if (IsA(node, PlannedStmt)) - { - pstmt = (PlannedStmt *) node; -! return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false, false); - } - /* other cases shouldn't happen, but return NULL */ - break; -*************** PlanCacheComputeResultDesc(List *stmt_li -*** 875,887 **** - { - query = (Query *) node; - Assert(query->returningList); -! return ExecCleanTypeFromTL(query->returningList, false); - } - if (IsA(node, PlannedStmt)) - { - pstmt = (PlannedStmt *) node; - Assert(pstmt->returningLists); -! return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), false); - } - /* other cases shouldn't happen, but return NULL */ - break; ---- 875,888 ---- - { - query = (Query *) node; - Assert(query->returningList); -! return ExecCleanTypeFromTL(query->returningList, false, false); - } - if (IsA(node, PlannedStmt)) - { - pstmt = (PlannedStmt *) node; - Assert(pstmt->returningLists); -! return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), -! false, false); - } - /* other cases shouldn't happen, but return NULL */ - break; -diff -Nrpc blob/src/backend/utils/cache/relcache.c sepgsql/src/backend/utils/cache/relcache.c -*** blob/src/backend/utils/cache/relcache.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/utils/cache/relcache.c Thu Mar 18 01:55:40 2010 -*************** -*** 48,53 **** ---- 48,54 ---- - #include "catalog/pg_operator.h" - #include "catalog/pg_proc.h" - #include "catalog/pg_rewrite.h" -+ #include "catalog/pg_security.h" - #include "catalog/pg_trigger.h" - #include "catalog/pg_type.h" - #include "commands/trigger.h" -*************** RelationBuildDesc(Oid targetRelId, bool -*** 862,867 **** ---- 863,872 ---- - /* extract reloptions if any */ - RelationParseRelOptions(relation, pg_class_tuple); - -+ /* Fixup relation->rd_att->tdhassecid */ -+ RelationGetDescr(relation)->tdhassecid -+ = securityTupleDescHasSecid(relid, relp->relkind); -+ - /* - * initialize the relation lock manager information - */ -*************** formrdesc(const char *relationName, Oid -*** 1456,1461 **** ---- 1461,1471 ---- - RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid; - relation->rd_rel->relfilenode = RelationGetRelid(relation); - -+ /* Fixup relation->rd_att->tdhassecid */ -+ RelationGetDescr(relation)->tdhassecid -+ = securityTupleDescHasSecid(RelationGetRelid(relation), -+ RELKIND_RELATION); -+ - /* - * initialize the relation lock manager information - */ -*************** BuildHardcodedDescriptor(int natts, Form -*** 2832,2837 **** ---- 2842,2854 ---- - result = CreateTemplateTupleDesc(natts, hasoids); - result->tdtypeid = RECORDOID; /* not right, but we don't care */ - result->tdtypmod = -1; -+ /* -+ * NOTE: we assume the returned TupleDesc is only used for -+ * references to toast'ed data, and it is not delivered to -+ * heap_form_tuple(), so TupleDesc->tdhassecid don't give us -+ * any effect. -+ * We omit to invoke securityTupleDescHasSecid() here. -+ */ - - for (i = 0; i < natts; i++) - { -*************** load_relcache_init_file(void) -*** 3586,3591 **** ---- 3603,3613 ---- - rel->rd_options = NULL; - } - -+ /* Fixup rel->rd_att->tdhassecid */ -+ RelationGetDescr(rel)->tdhassecid -+ = securityTupleDescHasSecid(RelationGetRelid(rel), -+ RelationGetForm(rel)->relkind); -+ - /* mark not-null status */ - if (has_not_null) - { -diff -Nrpc blob/src/backend/utils/fmgr/dfmgr.c sepgsql/src/backend/utils/fmgr/dfmgr.c -*** blob/src/backend/utils/fmgr/dfmgr.c Sun Sep 6 19:40:49 2009 ---- sepgsql/src/backend/utils/fmgr/dfmgr.c Thu Sep 17 17:04:16 2009 -*************** -*** 23,28 **** ---- 23,29 ---- - #endif - #include "lib/stringinfo.h" - #include "miscadmin.h" -+ #include "security/sepgsql.h" - #include "utils/dynamic_loader.h" - #include "utils/hsearch.h" - -*************** load_external_function(char *filename, c -*** 109,114 **** ---- 110,118 ---- - /* Expand the possibly-abbreviated filename to an exact path name */ - fullname = expand_dynamic_library_name(filename); - -+ /* SELinux checks db_database:{load_module} */ -+ sepgsql_database_load_module(MyDatabaseId, fullname); -+ - /* Load the shared library, unless we already did */ - lib_handle = internal_load_library(fullname); - -*************** load_file(const char *filename, bool res -*** 149,154 **** ---- 153,161 ---- - /* Expand the possibly-abbreviated filename to an exact path name */ - fullname = expand_dynamic_library_name(filename); - -+ /* SELinux checks db_database:{load_module} */ -+ sepgsql_database_load_module(MyDatabaseId, fullname); -+ - /* Unload the library if currently loaded */ - internal_unload_library(fullname); - -diff -Nrpc blob/src/backend/utils/fmgr/fmgr.c sepgsql/src/backend/utils/fmgr/fmgr.c -*** blob/src/backend/utils/fmgr/fmgr.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/backend/utils/fmgr/fmgr.c Sun Dec 20 16:30:19 2009 -*************** -*** 24,29 **** ---- 24,30 ---- - #include "miscadmin.h" - #include "nodes/nodeFuncs.h" - #include "pgstat.h" -+ #include "security/sepgsql.h" - #include "utils/builtins.h" - #include "utils/fmgrtab.h" - #include "utils/guc.h" -*************** fmgr_info_cxt_security(Oid functionId, F -*** 232,237 **** ---- 233,239 ---- - */ - if (!ignore_security && - (procedureStruct->prosecdef || -+ sepgsql_proc_entrypoint(procedureTuple) || - !heap_attisnull(procedureTuple, Anum_pg_proc_proconfig))) - { - finfo->fn_addr = fmgr_security_definer; -*************** struct fmgr_security_definer_cache -*** 860,865 **** ---- 862,868 ---- - { - FmgrInfo flinfo; /* lookup info for target function */ - Oid userid; /* userid to set, or InvalidOid */ -+ char *seclabel; /* security label to set, or NULL */ - ArrayType *proconfig; /* GUC values to set, or NULL */ - }; - -*************** fmgr_security_definer(PG_FUNCTION_ARGS) -*** 881,886 **** ---- 884,890 ---- - FmgrInfo *save_flinfo; - Oid save_userid; - int save_sec_context; -+ char *save_label = NULL; - volatile int save_nestlevel; - PgStat_FunctionCallUsage fcusage; - -*************** fmgr_security_definer(PG_FUNCTION_ARGS) -*** 910,915 **** ---- 914,922 ---- - if (procedureStruct->prosecdef) - fcache->userid = procedureStruct->proowner; - -+ fcache->seclabel -+ = sepgsql_proc_trusted(tuple, fcinfo->flinfo->fn_mcxt); -+ - datum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proconfig, - &isnull); - if (!isnull) -*************** fmgr_security_definer(PG_FUNCTION_ARGS) -*** 936,941 **** ---- 943,950 ---- - if (OidIsValid(fcache->userid)) - SetUserIdAndSecContext(fcache->userid, - save_sec_context | SECURITY_LOCAL_USERID_CHANGE); -+ if (fcache->seclabel) -+ save_label = sepgsqlSetClientLabel(fcache->seclabel); - - if (fcache->proconfig) - { -*************** fmgr_security_definer(PG_FUNCTION_ARGS) -*** 983,988 **** ---- 992,999 ---- - AtEOXact_GUC(true, save_nestlevel); - if (OidIsValid(fcache->userid)) - SetUserIdAndSecContext(save_userid, save_sec_context); -+ if (fcache->seclabel) -+ sepgsqlSetClientLabel(save_label); - - return result; - } -diff -Nrpc blob/src/backend/utils/init/postinit.c sepgsql/src/backend/utils/init/postinit.c -*** blob/src/backend/utils/init/postinit.c Sun Sep 6 19:40:49 2009 ---- sepgsql/src/backend/utils/init/postinit.c Sun Dec 20 00:41:22 2009 -*************** -*** 32,37 **** ---- 32,38 ---- - #include "pgstat.h" - #include "postmaster/autovacuum.h" - #include "postmaster/postmaster.h" -+ #include "security/sepgsql.h" - #include "storage/backendid.h" - #include "storage/bufmgr.h" - #include "storage/fd.h" -*************** CheckMyDatabase(const char *name, bool a -*** 201,207 **** - name))); - - /* -! * Check privilege to connect to the database. (The am_superuser test - * is redundant, but since we have the flag, might as well check it - * and save a few cycles.) - */ ---- 202,208 ---- - name))); - - /* -! * Check privilege to connect to the database. (The am_superuser test - * is redundant, but since we have the flag, might as well check it - * and save a few cycles.) - */ -*************** CheckMyDatabase(const char *name, bool a -*** 213,218 **** ---- 214,222 ---- - errmsg("permission denied for database \"%s\"", name), - errdetail("User does not have CONNECT privilege."))); - -+ /* SELinux: db_database:{access} */ -+ sepgsql_database_access(MyDatabaseId); -+ - /* - * Check connection limit for this database. - * -*************** InitPostgres(const char *in_dbname, Oid -*** 607,612 **** ---- 611,619 ---- - /* set up ACL framework (so CheckMyDatabase can check permissions) */ - initialize_acl(); - -+ /* Initialize SE-PostgreSQL */ -+ sepgsqlInitialize(); -+ - /* - * Read the real pg_database row for our database, check permissions and - * set up database-specific GUC settings. We can't do this until all the -diff -Nrpc blob/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc.c -*** blob/src/backend/utils/misc/guc.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/utils/misc/guc.c Thu Mar 18 01:55:40 2010 -*************** -*** 57,62 **** ---- 57,63 ---- - #include "postmaster/syslogger.h" - #include "postmaster/walwriter.h" - #include "regex/regex.h" -+ #include "security/sepgsql.h" - #include "storage/bufmgr.h" - #include "storage/fd.h" - #include "tcop/tcopprot.h" -*************** static const struct config_enum_entry is -*** 258,263 **** ---- 259,276 ---- - {NULL, 0} - }; - -+ #ifdef HAVE_SELINUX -+ static const struct config_enum_entry sepostgresql_mode_options [] = { -+ {"on", SEPGSQL_MODE_DEFAULT, true}, -+ {"off", SEPGSQL_MODE_DISABLED, true}, -+ {"default", SEPGSQL_MODE_DEFAULT, false}, -+ {"permissive", SEPGSQL_MODE_PERMISSIVE, false}, -+ {"enforcing", SEPGSQL_MODE_ENFORCING, false}, -+ {"disabled", SEPGSQL_MODE_DISABLED, false}, -+ {NULL, 0} -+ }; -+ #endif -+ - static const struct config_enum_entry session_replication_role_options[] = { - {"origin", SESSION_REPLICATION_ROLE_ORIGIN, false}, - {"replica", SESSION_REPLICATION_ROLE_REPLICA, false}, -*************** static struct config_bool ConfigureNames -*** 1222,1227 **** ---- 1235,1258 ---- - &IgnoreSystemIndexes, - false, NULL, NULL - }, -+ #ifdef HAVE_SELINUX -+ { -+ {"sepostgresql_row_level", PGC_POSTMASTER, CONN_AUTH_SECURITY, -+ gettext_noop("Row-level access controls on SE-PostgreSQL"), -+ NULL, -+ }, -+ &sepostgresql_row_level, -+ true, NULL, NULL -+ }, -+ { -+ {"sepostgresql_mcstrans", PGC_USERSET, CONN_AUTH_SECURITY, -+ gettext_noop("SE-PostgreSQL uses mcstrans on printing security labels"), -+ NULL, -+ }, -+ &sepostgresql_mcstrans, -+ true, NULL, NULL -+ }, -+ #endif - - { - {"lo_compat_privileges", PGC_SUSET, COMPAT_OPTIONS_PREVIOUS, -*************** static struct config_enum ConfigureNames -*** 2651,2657 **** - ®ex_flavor, - REG_ADVANCED, regex_flavor_options, NULL, NULL - }, -! - { - {"session_replication_role", PGC_SUSET, CLIENT_CONN_STATEMENT, - gettext_noop("Sets the session's behavior for triggers and rewrite rules."), ---- 2682,2698 ---- - ®ex_flavor, - REG_ADVANCED, regex_flavor_options, NULL, NULL - }, -! #ifdef HAVE_SELINUX -! { -! {"sepostgresql", PGC_POSTMASTER, CONN_AUTH_SECURITY, -! gettext_noop("SE-PostgreSQL performing mode"), -! NULL, -! }, -! &sepostgresql_mode, -! SEPGSQL_MODE_DISABLED, sepostgresql_mode_options, -! NULL, sepgsqlShowMode -! }, -! #endif - { - {"session_replication_role", PGC_SUSET, CLIENT_CONN_STATEMENT, - gettext_noop("Sets the session's behavior for triggers and rewrite rules."), -diff -Nrpc blob/src/backend/utils/misc/postgresql.conf.sample sepgsql/src/backend/utils/misc/postgresql.conf.sample -*** blob/src/backend/utils/misc/postgresql.conf.sample Thu Mar 18 09:43:03 2010 ---- sepgsql/src/backend/utils/misc/postgresql.conf.sample Thu Mar 18 01:55:40 2010 -*************** -*** 51,57 **** - - - #------------------------------------------------------------------------------ -! # CONNECTIONS AND AUTHENTICATION - #------------------------------------------------------------------------------ - - # - Connection Settings - ---- 51,57 ---- - - - #------------------------------------------------------------------------------ -! # CONNECTIONS, AUTHENTICATION AND SECURITY - #------------------------------------------------------------------------------ - - # - Connection Settings - -*************** -*** 96,102 **** - # 0 selects the system default - #tcp_keepalives_count = 0 # TCP_KEEPCNT; - # 0 selects the system default -! - - #------------------------------------------------------------------------------ - # RESOURCE USAGE (except WAL) ---- 96,102 ---- - # 0 selects the system default - #tcp_keepalives_count = 0 # TCP_KEEPCNT; - # 0 selects the system default -! #sepostgresql = off # SE-PostgreSQL support - - #------------------------------------------------------------------------------ - # RESOURCE USAGE (except WAL) -diff -Nrpc blob/src/bin/initdb/initdb.c sepgsql/src/bin/initdb/initdb.c -*** blob/src/bin/initdb/initdb.c Fri Dec 18 09:40:55 2009 ---- sepgsql/src/bin/initdb/initdb.c Fri Dec 18 10:27:56 2009 -*************** static bool debug = false; -*** 87,92 **** ---- 87,93 ---- - static bool noclean = false; - static bool show_setting = false; - static char *xlog_dir = ""; -+ static bool enable_selinux = false; - - - /* internal vars */ -*************** setup_config(void) -*** 1205,1210 **** ---- 1206,1218 ---- - "#default_text_search_config = 'pg_catalog.simple'", - repltok); - -+ if (enable_selinux) -+ { -+ strcpy(repltok, "sepostgresql = on"); -+ conflines = replace_token(conflines, -+ "#sepostgresql = off", repltok); -+ } -+ - snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); - - writefile(path, conflines); -*************** usage(const char *progname) -*** 2444,2449 **** ---- 2452,2458 ---- - printf(_(" -U, --username=NAME database superuser name\n")); - printf(_(" -W, --pwprompt prompt for a password for the new superuser\n")); - printf(_(" -X, --xlogdir=XLOGDIR location for the transaction log directory\n")); -+ printf(_(" --enable-selinux enables SELinux support, if compiled\n")); - printf(_("\nLess commonly used options:\n")); - printf(_(" -d, --debug generate lots of debugging output\n")); - printf(_(" -L DIRECTORY where to find the input files\n")); -*************** main(int argc, char *argv[]) -*** 2479,2484 **** ---- 2488,2494 ---- - {"auth", required_argument, NULL, 'A'}, - {"pwprompt", no_argument, NULL, 'W'}, - {"pwfile", required_argument, NULL, 9}, -+ {"enable-selinux", no_argument, NULL, 10}, - {"username", required_argument, NULL, 'U'}, - {"help", no_argument, NULL, '?'}, - {"version", no_argument, NULL, 'V'}, -*************** main(int argc, char *argv[]) -*** 2595,2600 **** ---- 2605,2613 ---- - case 9: - pwfilename = xstrdup(optarg); - break; -+ case 10: -+ enable_selinux = true; -+ break; - case 's': - show_setting = true; - break; -diff -Nrpc blob/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c -*** blob/src/bin/pg_dump/pg_dump.c Thu Mar 18 09:43:03 2010 ---- sepgsql/src/bin/pg_dump/pg_dump.c Thu Mar 18 01:55:40 2010 -*************** static int disable_dollar_quoting = 0; -*** 112,117 **** ---- 112,119 ---- - static int dump_inserts = 0; - static int column_inserts = 0; - -+ /* flag to turn on/off security_context */ -+ static int security_context = 0; - - static void help(const char *progname); - static void expand_schema_name_patterns(SimpleStringList *patterns, -*************** main(int argc, char **argv) -*** 277,282 **** ---- 279,285 ---- - {"no-tablespaces", no_argument, &outputNoTablespaces, 1}, - {"role", required_argument, NULL, 3}, - {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, -+ {"security-context", no_argument, &security_context, 1}, - - {NULL, 0, NULL, 0} - }; -*************** main(int argc, char **argv) -*** 425,430 **** ---- 428,435 ---- - outputNoTablespaces = 1; - else if (strcmp(optarg, "use-set-session-authorization") == 0) - use_setsessauth = 1; -+ else if (strcmp(optarg, "security-context") == 0) -+ security_context = 1; - else - { - fprintf(stderr, -*************** main(int argc, char **argv) -*** 573,578 **** ---- 578,605 ---- - std_strings = PQparameterStatus(g_conn, "standard_conforming_strings"); - g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0); - -+ /* Check availability of SE-PostgreSQL */ -+ if (security_context > 0) -+ { -+ PGresult *res; -+ -+ res = PQexec(g_conn, "SHOW sepostgresql"); -+ if (PQresultStatus(res) != PGRES_TUPLES_OK || -+ PQntuples(res) != 1 || -+ strcmp(PQgetvalue(res, 0, 0), "on") != 0) -+ { -+ write_msg(NULL, "SE-PostgreSQL is not available now."); -+ exit(1); -+ } -+ } -+ -+ /* -+ * It needs to force column insertion mode, when --inserts -+ * and either --security-label or --security-acl is given. -+ */ -+ if (security_context > 0 && dump_inserts) -+ column_inserts = 1; -+ - /* Set the role if requested */ - if (use_role && g_fout->remoteVersion >= 80100) - { -*************** help(const char *progname) -*** 826,831 **** ---- 853,860 ---- - printf(_(" --use-set-session-authorization\n" - " use SET SESSION AUTHORIZATION commands instead of\n" - " ALTER OWNER commands to set ownership\n")); -+ printf(_(" --security-label dump SE-PostgreSQL security labels\n")); -+ printf(_(" --security-acl dump row-level database ACLs\n")); - - printf(_("\nConnection options:\n")); - printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); -*************** dumpTableData_insert(Archive *fout, void -*** 1227,1233 **** - if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " -! "SELECT * FROM ONLY %s", - fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, - classname)); - } ---- 1256,1263 ---- - if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " -! "SELECT %s* FROM ONLY %s", -! (security_context > 0 ? "security_context, " : ""), - fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, - classname)); - } -*************** dumpDatabase(Archive *AH) -*** 1583,1589 **** - i_collate, - i_ctype, - i_frozenxid, -! i_tablespace; - CatalogId dbCatId; - DumpId dbDumpId; - const char *datname, ---- 1613,1620 ---- - i_collate, - i_ctype, - i_frozenxid, -! i_tablespace, -! i_seclabel; - CatalogId dbCatId; - DumpId dbDumpId; - const char *datname, -*************** dumpDatabase(Archive *AH) -*** 1591,1597 **** - *encoding, - *collate, - *ctype, -! *tablespace; - uint32 frozenxid; - - datname = PQdb(g_conn); ---- 1622,1629 ---- - *encoding, - *collate, - *ctype, -! *tablespace, -! *seclabel; - uint32 frozenxid; - - datname = PQdb(g_conn); -*************** dumpDatabase(Archive *AH) -*** 1610,1620 **** - "pg_encoding_to_char(encoding) AS encoding, " - "datcollate, datctype, datfrozenxid, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, " -! "shobj_description(oid, 'pg_database') AS description " -! - "FROM pg_database " - "WHERE datname = ", -! username_subquery); - appendStringLiteralAH(dbQry, datname, AH); - } - else if (g_fout->remoteVersion >= 80200) ---- 1642,1653 ---- - "pg_encoding_to_char(encoding) AS encoding, " - "datcollate, datctype, datfrozenxid, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, " -! "shobj_description(oid, 'pg_database') AS description, " -! "%s as security_context " - "FROM pg_database " - "WHERE datname = ", -! username_subquery, -! security_context ? "security_context" : "NULL"); - appendStringLiteralAH(dbQry, datname, AH); - } - else if (g_fout->remoteVersion >= 80200) -*************** dumpDatabase(Archive *AH) -*** 1624,1631 **** - "pg_encoding_to_char(encoding) AS encoding, " - "NULL AS datcollate, NULL AS datctype, datfrozenxid, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, " -! "shobj_description(oid, 'pg_database') AS description " -! - "FROM pg_database " - "WHERE datname = ", - username_subquery); ---- 1657,1664 ---- - "pg_encoding_to_char(encoding) AS encoding, " - "NULL AS datcollate, NULL AS datctype, datfrozenxid, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, " -! "shobj_description(oid, 'pg_database') AS description, " -! "NULL as security_context " - "FROM pg_database " - "WHERE datname = ", - username_subquery); -*************** dumpDatabase(Archive *AH) -*** 1637,1643 **** - "(%s datdba) AS dba, " - "pg_encoding_to_char(encoding) AS encoding, " - "NULL AS datcollate, NULL AS datctype, datfrozenxid, " -! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace " - "FROM pg_database " - "WHERE datname = ", - username_subquery); ---- 1670,1677 ---- - "(%s datdba) AS dba, " - "pg_encoding_to_char(encoding) AS encoding, " - "NULL AS datcollate, NULL AS datctype, datfrozenxid, " -! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, " -! "NULL as security_context " - "FROM pg_database " - "WHERE datname = ", - username_subquery); -*************** dumpDatabase(Archive *AH) -*** 1650,1656 **** - "pg_encoding_to_char(encoding) AS encoding, " - "NULL AS datcollate, NULL AS datctype, " - "0 AS datfrozenxid, " -! "NULL AS tablespace " - "FROM pg_database " - "WHERE datname = ", - username_subquery); ---- 1684,1691 ---- - "pg_encoding_to_char(encoding) AS encoding, " - "NULL AS datcollate, NULL AS datctype, " - "0 AS datfrozenxid, " -! "NULL AS tablespace, " -! "NULL AS security_context " - "FROM pg_database " - "WHERE datname = ", - username_subquery); -*************** dumpDatabase(Archive *AH) -*** 1665,1671 **** - "pg_encoding_to_char(encoding) AS encoding, " - "NULL AS datcollate, NULL AS datctype, " - "0 AS datfrozenxid, " -! "NULL AS tablespace " - "FROM pg_database " - "WHERE datname = ", - username_subquery); ---- 1700,1707 ---- - "pg_encoding_to_char(encoding) AS encoding, " - "NULL AS datcollate, NULL AS datctype, " - "0 AS datfrozenxid, " -! "NULL AS tablespace, " -! "NULL as security_context " - "FROM pg_database " - "WHERE datname = ", - username_subquery); -*************** dumpDatabase(Archive *AH) -*** 1699,1704 **** ---- 1735,1741 ---- - i_ctype = PQfnumber(res, "datctype"); - i_frozenxid = PQfnumber(res, "datfrozenxid"); - i_tablespace = PQfnumber(res, "tablespace"); -+ i_seclabel = PQfnumber(res, "security_context"); - - dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid)); - dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid)); -*************** dumpDatabase(Archive *AH) -*** 1708,1713 **** ---- 1745,1751 ---- - ctype = PQgetvalue(res, 0, i_ctype); - frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid)); - tablespace = PQgetvalue(res, 0, i_tablespace); -+ seclabel = PQgetvalue(res, 0, i_seclabel); - - appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0", - fmtId(datname)); -*************** dumpDatabase(Archive *AH) -*** 1729,1734 **** ---- 1767,1775 ---- - if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0) - appendPQExpBuffer(creaQry, " TABLESPACE = %s", - fmtId(tablespace)); -+ if (strlen(seclabel) > 0) -+ appendPQExpBuffer(creaQry, " SECURITY_CONTEXT = '%s'", seclabel); -+ - appendPQExpBuffer(creaQry, ";\n"); - - if (binary_upgrade) -*************** getTables(int *numTables) -*** 3230,3235 **** ---- 3271,3277 ---- - int i_reltablespace; - int i_reloptions; - int i_toastreloptions; -+ int i_relseclabel; - - /* Make sure we are in proper schema */ - selectSourceSchema("pg_catalog"); -*************** getTables(int *numTables) -*** 3271,3277 **** - "d.refobjsubid AS owning_col, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "array_to_string(c.reloptions, ', ') AS reloptions, " -! "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " ---- 3313,3320 ---- - "d.refobjsubid AS owning_col, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "array_to_string(c.reloptions, ', ') AS reloptions, " -! "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions, " -! "%s as security_context " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " -*************** getTables(int *numTables) -*** 3282,3287 **** ---- 3325,3331 ---- - "WHERE c.relkind in ('%c', '%c', '%c', '%c') " - "ORDER BY c.oid", - username_subquery, -+ security_context ? "c.security_context" : "NULL", - RELKIND_SEQUENCE, - RELKIND_RELATION, RELKIND_SEQUENCE, - RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); -*************** getTables(int *numTables) -*** 3303,3309 **** - "d.refobjsubid AS owning_col, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "array_to_string(c.reloptions, ', ') AS reloptions, " -! "NULL AS toast_reloptions " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " ---- 3347,3354 ---- - "d.refobjsubid AS owning_col, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "array_to_string(c.reloptions, ', ') AS reloptions, " -! "NULL AS toast_reloptions, " -! "NULL as security_context " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " -*************** getTables(int *numTables) -*** 3334,3340 **** - "d.refobjsubid AS owning_col, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "NULL AS reloptions, " -! "NULL AS toast_reloptions " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " ---- 3379,3386 ---- - "d.refobjsubid AS owning_col, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "NULL AS reloptions, " -! "NULL AS toast_reloptions, " -! "NULL as security_context " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " -*************** getTables(int *numTables) -*** 3365,3371 **** - "d.refobjsubid AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " -! "NULL AS toast_reloptions " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " ---- 3411,3418 ---- - "d.refobjsubid AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " -! "NULL AS toast_reloptions, " -! "NULL as security_context " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " -*************** getTables(int *numTables) -*** 3392,3398 **** - "NULL::int4 AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " -! "NULL AS toast_reloptions " - "FROM pg_class " - "WHERE relkind IN ('%c', '%c', '%c') " - "ORDER BY oid", ---- 3439,3446 ---- - "NULL::int4 AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " -! "NULL AS toast_reloptions, " -! "NULL AS security_context " - "FROM pg_class " - "WHERE relkind IN ('%c', '%c', '%c') " - "ORDER BY oid", -*************** getTables(int *numTables) -*** 3414,3420 **** - "NULL::int4 AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " -! "NULL AS toast_reloptions " - "FROM pg_class " - "WHERE relkind IN ('%c', '%c', '%c') " - "ORDER BY oid", ---- 3462,3469 ---- - "NULL::int4 AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " -! "NULL AS toast_reloptions, " -! "NULL AS security_context " - "FROM pg_class " - "WHERE relkind IN ('%c', '%c', '%c') " - "ORDER BY oid", -*************** getTables(int *numTables) -*** 3446,3452 **** - "NULL::int4 AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " -! "NULL AS toast_reloptions " - "FROM pg_class c " - "WHERE relkind IN ('%c', '%c') " - "ORDER BY oid", ---- 3495,3502 ---- - "NULL::int4 AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " -! "NULL AS toast_reloptions, " -! "NULL as security_context " - "FROM pg_class c " - "WHERE relkind IN ('%c', '%c') " - "ORDER BY oid", -*************** getTables(int *numTables) -*** 3491,3496 **** ---- 3541,3547 ---- - i_reltablespace = PQfnumber(res, "reltablespace"); - i_reloptions = PQfnumber(res, "reloptions"); - i_toastreloptions = PQfnumber(res, "toast_reloptions"); -+ i_relseclabel = PQfnumber(res, "security_context"); - - if (lockWaitTimeout && g_fout->remoteVersion >= 70300) - { -*************** getTables(int *numTables) -*** 3538,3543 **** ---- 3589,3595 ---- - tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace)); - tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions)); - tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions)); -+ tblinfo[i].relseclabel = strdup(PQgetvalue(res, i, i_relseclabel)); - - /* other fields were zeroed above */ - -*************** getTableAttrs(TableInfo *tblinfo, int nu -*** 4737,4742 **** ---- 4789,4795 ---- - int i_attlen; - int i_attalign; - int i_attislocal; -+ int i_attseclabel; - PGresult *res; - int ntups; - bool hasdefaults; -*************** getTableAttrs(TableInfo *tblinfo, int nu -*** 4781,4792 **** - "a.attstattarget, a.attstorage, t.typstorage, " - "a.attnotnull, a.atthasdef, a.attisdropped, " - "a.attlen, a.attalign, a.attislocal, " -! "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname " - "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t " - "ON a.atttypid = t.oid " - "WHERE a.attrelid = '%u'::pg_catalog.oid " - "AND a.attnum > 0::pg_catalog.int2 " - "ORDER BY a.attrelid, a.attnum", - tbinfo->dobj.catId.oid); - } - else if (g_fout->remoteVersion >= 70100) ---- 4834,4847 ---- - "a.attstattarget, a.attstorage, t.typstorage, " - "a.attnotnull, a.atthasdef, a.attisdropped, " - "a.attlen, a.attalign, a.attislocal, " -! "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, " -! "%s as security_context " - "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t " - "ON a.atttypid = t.oid " - "WHERE a.attrelid = '%u'::pg_catalog.oid " - "AND a.attnum > 0::pg_catalog.int2 " - "ORDER BY a.attrelid, a.attnum", -+ security_context ? "a.security_context" : "NULL", - tbinfo->dobj.catId.oid); - } - else if (g_fout->remoteVersion >= 70100) -*************** getTableAttrs(TableInfo *tblinfo, int nu -*** 4801,4807 **** - "t.typstorage, a.attnotnull, a.atthasdef, " - "false AS attisdropped, a.attlen, " - "a.attalign, false AS attislocal, " -! "format_type(t.oid,a.atttypmod) AS atttypname " - "FROM pg_attribute a LEFT JOIN pg_type t " - "ON a.atttypid = t.oid " - "WHERE a.attrelid = '%u'::oid " ---- 4856,4863 ---- - "t.typstorage, a.attnotnull, a.atthasdef, " - "false AS attisdropped, a.attlen, " - "a.attalign, false AS attislocal, " -! "format_type(t.oid,a.atttypmod) AS atttypname, " -! "NULL as security_context " - "FROM pg_attribute a LEFT JOIN pg_type t " - "ON a.atttypid = t.oid " - "WHERE a.attrelid = '%u'::oid " -*************** getTableAttrs(TableInfo *tblinfo, int nu -*** 4818,4824 **** - "attnotnull, atthasdef, false AS attisdropped, " - "attlen, attalign, " - "false AS attislocal, " -! "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname " - "FROM pg_attribute a " - "WHERE attrelid = '%u'::oid " - "AND attnum > 0::int2 " ---- 4874,4881 ---- - "attnotnull, atthasdef, false AS attisdropped, " - "attlen, attalign, " - "false AS attislocal, " -! "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, " -! "NULL as security_context " - "FROM pg_attribute a " - "WHERE attrelid = '%u'::oid " - "AND attnum > 0::int2 " -*************** getTableAttrs(TableInfo *tblinfo, int nu -*** 4844,4849 **** ---- 4901,4907 ---- - i_attlen = PQfnumber(res, "attlen"); - i_attalign = PQfnumber(res, "attalign"); - i_attislocal = PQfnumber(res, "attislocal"); -+ i_attseclabel = PQfnumber(res, "security_context"); - - tbinfo->numatts = ntups; - tbinfo->attnames = (char **) malloc(ntups * sizeof(char *)); -*************** getTableAttrs(TableInfo *tblinfo, int nu -*** 4856,4861 **** ---- 4914,4920 ---- - tbinfo->attlen = (int *) malloc(ntups * sizeof(int)); - tbinfo->attalign = (char *) malloc(ntups * sizeof(char)); - tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool)); -+ tbinfo->attseclabel = (char **) malloc(ntups * sizeof(char *)); - tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool)); - tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *)); - tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool)); -*************** getTableAttrs(TableInfo *tblinfo, int nu -*** 4881,4886 **** ---- 4940,4946 ---- - tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen)); - tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign)); - tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't'); -+ tbinfo->attseclabel[j] = strdup(PQgetvalue(res, j, i_attseclabel)); - tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't'); - tbinfo->attrdefs[j] = NULL; /* fix below */ - if (PQgetvalue(res, j, i_atthasdef)[0] == 't') -*************** dumpFunc(Archive *fout, FuncInfo *finfo) -*** 7131,7136 **** ---- 7191,7197 ---- - char *proconfig; - char *procost; - char *prorows; -+ char *proseclabel; - char *lanname; - char *rettypename; - int nallargs; -*************** dumpFunc(Archive *fout, FuncInfo *finfo) -*** 7167,7175 **** - "pg_catalog.pg_get_function_result(oid) AS funcresult, " - "proiswindow, provolatile, proisstrict, prosecdef, " - "proconfig, procost, prorows, " -! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); - } - else if (g_fout->remoteVersion >= 80300) ---- 7228,7238 ---- - "pg_catalog.pg_get_function_result(oid) AS funcresult, " - "proiswindow, provolatile, proisstrict, prosecdef, " - "proconfig, procost, prorows, " -! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname, " -! "%s as security_context " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", -+ security_context ? "security_context" : "NULL", - finfo->dobj.catId.oid); - } - else if (g_fout->remoteVersion >= 80300) -*************** dumpFunc(Archive *fout, FuncInfo *finfo) -*** 7180,7186 **** - "false AS proiswindow, " - "provolatile, proisstrict, prosecdef, " - "proconfig, procost, prorows, " -! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); ---- 7243,7250 ---- - "false AS proiswindow, " - "provolatile, proisstrict, prosecdef, " - "proconfig, procost, prorows, " -! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname, " -! "NULL AS security_context " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -*************** dumpFunc(Archive *fout, FuncInfo *finfo) -*** 7193,7199 **** - "false AS proiswindow, " - "provolatile, proisstrict, prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " -! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); ---- 7257,7264 ---- - "false AS proiswindow, " - "provolatile, proisstrict, prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " -! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname, " -! "NULL AS security_context " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -*************** dumpFunc(Archive *fout, FuncInfo *finfo) -*** 7208,7214 **** - "false AS proiswindow, " - "provolatile, proisstrict, prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " -! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); ---- 7273,7280 ---- - "false AS proiswindow, " - "provolatile, proisstrict, prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " -! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname, " -! "NULL AS security_context " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -*************** dumpFunc(Archive *fout, FuncInfo *finfo) -*** 7223,7229 **** - "false AS proiswindow, " - "provolatile, proisstrict, prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " -! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); ---- 7289,7296 ---- - "false AS proiswindow, " - "provolatile, proisstrict, prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " -! "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname, " -! "NULL AS security_context " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); -*************** dumpFunc(Archive *fout, FuncInfo *finfo) -*** 7240,7246 **** - "proisstrict, " - "false AS prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " -! "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname " - "FROM pg_proc " - "WHERE oid = '%u'::oid", - finfo->dobj.catId.oid); ---- 7307,7314 ---- - "proisstrict, " - "false AS prosecdef, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " -! "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname, " -! "NULL AS security_context " - "FROM pg_proc " - "WHERE oid = '%u'::oid", - finfo->dobj.catId.oid); -*************** dumpFunc(Archive *fout, FuncInfo *finfo) -*** 7257,7263 **** - "false AS proisstrict, " - "false AS prosecdef, " - "NULL AS proconfig, 0 AS procost, 0 AS prorows, " -! "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname " - "FROM pg_proc " - "WHERE oid = '%u'::oid", - finfo->dobj.catId.oid); ---- 7325,7332 ---- - "false AS proisstrict, " - "false AS prosecdef, " - "NULL AS proconfig, 0 AS procost, 0 AS prorows, " -! "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname, " -! "NULL AS security_context " - "FROM pg_proc " - "WHERE oid = '%u'::oid", - finfo->dobj.catId.oid); -*************** dumpFunc(Archive *fout, FuncInfo *finfo) -*** 7301,7306 **** ---- 7370,7376 ---- - proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig")); - procost = PQgetvalue(res, 0, PQfnumber(res, "procost")); - prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows")); -+ proseclabel = PQgetvalue(res, 0, PQfnumber(res, "security_context")); - lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname")); - - /* -*************** dumpFunc(Archive *fout, FuncInfo *finfo) -*** 7459,7464 **** ---- 7529,7537 ---- - if (prosecdef[0] == 't') - appendPQExpBuffer(q, " SECURITY DEFINER"); - -+ if (security_context > 0 && strlen(proseclabel) > 0) -+ appendPQExpBuffer(q, " SECURITY_CONTEXT = '%s'", proseclabel); -+ - /* - * COST and ROWS are emitted only if present and not default, so as not to - * break backwards-compatibility of the dump without need. Keep this code -*************** dumpTableSchema(Archive *fout, TableInfo -*** 9917,9922 **** ---- 9990,10006 ---- - if (tbinfo->notnull[j] && - (!tbinfo->inhNotNull[j] || binary_upgrade)) - appendPQExpBuffer(q, " NOT NULL"); -+ -+ /* -+ * Security label -- if SE-PostgreSQL enabled -+ */ -+ if (security_context > 0 && -+ strlen(tbinfo->attseclabel[j]) > 0 && -+ strcmp(tbinfo->relseclabel, tbinfo->attseclabel[j]) != 0) -+ appendPQExpBuffer(q, " SECURITY_CONTEXT = '%s'", -+ tbinfo->attseclabel[j]); -+ -+ actual_atts++; - } - } - -*************** dumpTableSchema(Archive *fout, TableInfo -*** 9979,9984 **** ---- 10063,10071 ---- - appendPQExpBuffer(q, ")"); - } - -+ if (security_context > 0 && strlen(tbinfo->relseclabel) > 0) -+ appendPQExpBuffer(q, " SECURITY_CONTEXT = '%s'", tbinfo->relseclabel); -+ - appendPQExpBuffer(q, ";\n"); - - /* -*************** fmtCopyColumnList(const TableInfo *ti) -*** 11550,11555 **** ---- 11637,11649 ---- - - appendPQExpBuffer(q, "("); - needComma = false; -+ -+ if (security_context > 0) -+ { -+ appendPQExpBuffer(q, "security_context"); -+ needComma = true; -+ } -+ - for (i = 0; i < numatts; i++) - { - if (attisdropped[i]) -diff -Nrpc blob/src/bin/pg_dump/pg_dump.h sepgsql/src/bin/pg_dump/pg_dump.h -*** blob/src/bin/pg_dump/pg_dump.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/bin/pg_dump/pg_dump.h Wed Jul 15 20:03:59 2009 -*************** typedef struct _tableInfo -*** 228,233 **** ---- 228,234 ---- - bool hasoids; /* does it have OIDs? */ - uint32 frozenxid; /* for restore frozen xid */ - int ncheck; /* # of CHECK expressions */ -+ char *relseclabel; /* security labels of relation */ - /* these two are set only if table is a sequence owned by a column: */ - Oid owning_tab; /* OID of table owning sequence */ - int owning_col; /* attr # of column owning sequence */ -*************** typedef struct _tableInfo -*** 249,254 **** ---- 250,256 ---- - int *attlen; /* attribute length, used by binary_upgrade */ - char *attalign; /* attribute align, used by binary_upgrade */ - bool *attislocal; /* true if attr has local definition */ -+ char **attseclabel; /* security labels of attributes */ - - /* - * Note: we need to store per-attribute notnull, default, and constraint -diff -Nrpc blob/src/bin/pg_dump/pg_dumpall.c sepgsql/src/bin/pg_dump/pg_dumpall.c -*** blob/src/bin/pg_dump/pg_dumpall.c Thu Jun 18 10:20:52 2009 ---- sepgsql/src/bin/pg_dump/pg_dumpall.c Wed Jul 15 20:03:59 2009 -*************** static int no_tablespaces = 0; -*** 69,74 **** ---- 69,77 ---- - static int use_setsessauth = 0; - static int server_version; - -+ static int security_label = 0; -+ static int security_acl = 0; -+ - static FILE *OPF; - static char *filename = NULL; - -*************** main(int argc, char *argv[]) -*** 130,135 **** ---- 133,140 ---- - {"no-tablespaces", no_argument, &no_tablespaces, 1}, - {"role", required_argument, NULL, 3}, - {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, -+ {"security-label", no_argument, &security_label, 1}, -+ {"security-acl", no_argument, &security_acl, 1}, - - {NULL, 0, NULL, 0} - }; -*************** main(int argc, char *argv[]) -*** 283,288 **** ---- 288,297 ---- - no_tablespaces = 1; - else if (strcmp(optarg, "use-set-session-authorization") == 0) - use_setsessauth = 1; -+ else if (strcmp(optarg, "security-label") == 0) -+ security_label = 1; -+ else if (strcmp(optarg, "security-acl") == 0) -+ security_acl = 1; - else - { - fprintf(stderr, -*************** main(int argc, char *argv[]) -*** 328,333 **** ---- 337,346 ---- - appendPQExpBuffer(pgdumpopts, " --no-tablespaces"); - if (use_setsessauth) - appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization"); -+ if (security_label) -+ appendPQExpBuffer(pgdumpopts, " --security-label"); -+ if (security_acl) -+ appendPQExpBuffer(pgdumpopts, " --security-acl"); - - if (optind < argc) - { -*************** main(int argc, char *argv[]) -*** 403,408 **** ---- 416,434 ---- - } - } - -+ if (security_label > 0) -+ { -+ PGresult *res -+ = PQexec(conn, "SHOW sepostgresql"); -+ if (PQresultStatus(res) != PGRES_TUPLES_OK || -+ PQntuples(res) != 1 || -+ strcmp(PQgetvalue(res, 0, 0), "on") != 0) -+ { -+ fprintf(stderr, "SE-PostgreSQL is not available now."); -+ exit(1); -+ } -+ } -+ - /* - * Open the output file if required, otherwise use stdout - */ -*************** dumpCreateDB(PGconn *conn) -*** 1130,1184 **** - - /* Now collect all the information about databases to dump */ - if (server_version >= 80400) -! res = executeQuery(conn, -! "SELECT datname, " - "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "datcollate, datctype, datfrozenxid, " - "datistemplate, datacl, datconnlimit, " -! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " - "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " -! "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 80100) -! res = executeQuery(conn, -! "SELECT datname, " - "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, datfrozenxid, " - "datistemplate, datacl, datconnlimit, " -! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " - "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 80000) -! res = executeQuery(conn, -! "SELECT datname, " - "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, datfrozenxid, " - "datistemplate, datacl, -1 as datconnlimit, " -! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " - "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 70300) -! res = executeQuery(conn, -! "SELECT datname, " - "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, datfrozenxid, " - "datistemplate, datacl, -1 as datconnlimit, " -! "'pg_default' AS dattablespace " - "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 70100) -! res = executeQuery(conn, -! "SELECT datname, " - "coalesce(" - "(select usename from pg_shadow where usesysid=datdba), " - "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, " - "datistemplate, '' as datacl, -1 as datconnlimit, " -! "'pg_default' AS dattablespace " - "FROM pg_database d " - "WHERE datallowconn ORDER BY 1"); - else ---- 1156,1211 ---- - - /* Now collect all the information about databases to dump */ - if (server_version >= 80400) -! appendPQExpBuffer(buf, "SELECT datname, " - "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "datcollate, datctype, datfrozenxid, " - "datistemplate, datacl, datconnlimit, " -! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace, " -! "%s AS security_label " - "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " -! "WHERE datallowconn ORDER BY 1", -! security_label ? "sepgsql_raw_to_trans(datselabel)" : "null::text"); - else if (server_version >= 80100) -! appendPQExpBuffer(buf, "SELECT datname, " - "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, datfrozenxid, " - "datistemplate, datacl, datconnlimit, " -! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace, " -! "null::text " - "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 80000) -! appendPQExpBuffer(buf, "SELECT datname, " - "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, datfrozenxid, " - "datistemplate, datacl, -1 as datconnlimit, " -! "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace, " -! "null::text " - "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 70300) -! appendPQExpBuffer(buf, "SELECT datname, " - "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, datfrozenxid, " - "datistemplate, datacl, -1 as datconnlimit, " -! "'pg_default' AS dattablespace, " -! "null::text " - "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 70100) -! appendPQExpBuffer(buf, "SELECT datname, " - "coalesce(" - "(select usename from pg_shadow where usesysid=datdba), " - "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, " - "datistemplate, '' as datacl, -1 as datconnlimit, " -! "'pg_default' AS dattablespace, " -! "null::text " - "FROM pg_database d " - "WHERE datallowconn ORDER BY 1"); - else -*************** dumpCreateDB(PGconn *conn) -*** 1187,1204 **** - * Note: 7.0 fails to cope with sub-select in COALESCE, so just deal - * with getting a NULL by not printing any OWNER clause. - */ -! res = executeQuery(conn, -! "SELECT datname, " - "(select usename from pg_shadow where usesysid=datdba), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, " - "'f' as datistemplate, " - "'' as datacl, -1 as datconnlimit, " -! "'pg_default' AS dattablespace " - "FROM pg_database d " - "ORDER BY 1"); - } - - for (i = 0; i < PQntuples(res); i++) - { - char *dbname = PQgetvalue(res, i, 0); ---- 1214,1233 ---- - * Note: 7.0 fails to cope with sub-select in COALESCE, so just deal - * with getting a NULL by not printing any OWNER clause. - */ -! appendPQExpBuffer(buf, "SELECT datname, " - "(select usename from pg_shadow where usesysid=datdba), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, " - "'f' as datistemplate, " - "'' as datacl, -1 as datconnlimit, " -! "'pg_default' AS dattablespace, " -! "null::text " - "FROM pg_database d " - "ORDER BY 1"); - } - -+ res = PQexec(conn, buf->data); -+ - for (i = 0; i < PQntuples(res); i++) - { - char *dbname = PQgetvalue(res, i, 0); -*************** dumpCreateDB(PGconn *conn) -*** 1211,1216 **** ---- 1240,1246 ---- - char *dbacl = PQgetvalue(res, i, 7); - char *dbconnlimit = PQgetvalue(res, i, 8); - char *dbtablespace = PQgetvalue(res, i, 9); -+ char *dbseclabel = PQgetvalue(res, i, 9); - char *fdbname; - - fdbname = strdup(fmtId(dbname)); -*************** dumpCreateDB(PGconn *conn) -*** 1266,1271 **** ---- 1296,1305 ---- - appendPQExpBuffer(buf, " CONNECTION LIMIT = %s", - dbconnlimit); - -+ if (security_label > 0 && strlen(dbseclabel) > 0) -+ appendPQExpBuffer(buf, " SECURITY_LABEL = '%s'", -+ dbseclabel); -+ - appendPQExpBuffer(buf, ";\n"); - - if (strcmp(dbistemplate, "t") == 0) -diff -Nrpc blob/src/include/access/htup.h sepgsql/src/include/access/htup.h -*** blob/src/include/access/htup.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/access/htup.h Tue Sep 8 23:55:48 2009 -*************** typedef HeapTupleHeaderData *HeapTupleHe -*** 163,169 **** - #define HEAP_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */ - #define HEAP_HASEXTERNAL 0x0004 /* has external stored attribute(s) */ - #define HEAP_HASOID 0x0008 /* has an object-id field */ -! /* bit 0x0010 is available */ - #define HEAP_COMBOCID 0x0020 /* t_cid is a combo cid */ - #define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */ - #define HEAP_XMAX_SHARED_LOCK 0x0080 /* xmax is shared locker */ ---- 163,169 ---- - #define HEAP_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */ - #define HEAP_HASEXTERNAL 0x0004 /* has external stored attribute(s) */ - #define HEAP_HASOID 0x0008 /* has an object-id field */ -! #define HEAP_HASSECID 0x0010 /* has an security-id field */ - #define HEAP_COMBOCID 0x0020 /* t_cid is a combo cid */ - #define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */ - #define HEAP_XMAX_SHARED_LOCK 0x0080 /* xmax is shared locker */ -*************** do { \ -*** 290,295 **** ---- 290,298 ---- - (tup)->t_choice.t_datum.datum_typmod = (typmod) \ - ) - -+ #define HeapTupleHeaderHasOid(tup) \ -+ ((tup)->t_infomask & HEAP_HASOID) -+ - #define HeapTupleHeaderGetOid(tup) \ - ( \ - ((tup)->t_infomask & HEAP_HASOID) ? \ -*************** do { \ -*** 349,354 **** ---- 352,376 ---- - (tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \ - ) - -+ #define HeapTupleHeaderHasSecid(tup) \ -+ ((tup)->t_infomask & HEAP_HASSECID) -+ -+ #define HeapTupleHeaderGetSecid(tup) \ -+ ( \ -+ HeapTupleHeaderHasSecid(tup) \ -+ ? (*(Oid *)((char *)(tup) + (tup)->t_hoff \ -+ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \ -+ - sizeof(Oid))) \ -+ : InvalidOid \ -+ ) -+ -+ #define HeapTupleHeaderSetSecid(tup, secid) \ -+ do { \ -+ Assert(HeapTupleHeaderHasSecid(tup)); \ -+ *((Oid *)((char *)(tup) + (tup)->t_hoff \ -+ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \ -+ - sizeof(Oid))) = (secid); \ -+ } while(0) - - /* - * BITMAPLEN(NATTS) - -*************** typedef HeapTupleData *HeapTuple; -*** 549,554 **** ---- 571,584 ---- - #define HeapTupleSetOid(tuple, oid) \ - HeapTupleHeaderSetOid((tuple)->t_data, (oid)) - -+ #define HeapTupleHasSecid(tuple) \ -+ HeapTupleHeaderHasSecid((tuple)->t_data) -+ -+ #define HeapTupleGetSecid(tuple) \ -+ HeapTupleHeaderGetSecid((tuple)->t_data) -+ -+ #define HeapTupleSetSecid(tuple, secid) \ -+ HeapTupleHeaderSetSecid((tuple)->t_data, (secid)) - - /* - * WAL record definitions for heapam.c's WAL operations -diff -Nrpc blob/src/include/access/sysattr.h sepgsql/src/include/access/sysattr.h -*** blob/src/include/access/sysattr.h Sat Jan 3 12:25:21 2009 ---- sepgsql/src/include/access/sysattr.h Wed Sep 9 16:47:01 2009 -*************** -*** 25,31 **** - #define MaxTransactionIdAttributeNumber (-5) - #define MaxCommandIdAttributeNumber (-6) - #define TableOidAttributeNumber (-7) -! #define FirstLowInvalidHeapAttributeNumber (-8) - - - #endif /* SYSATTR_H */ ---- 25,43 ---- - #define MaxTransactionIdAttributeNumber (-5) - #define MaxCommandIdAttributeNumber (-6) - #define TableOidAttributeNumber (-7) -! #define SecurityAttributeNumber (-8) -! #define FirstLowInvalidHeapAttributeNumber (-9) - -+ /* -+ * Attribute names for the system-defined attributes -+ */ -+ #define SelfItemPointerAttributeName "ctid" -+ #define ObjectIdAttributeName "oid" -+ #define MinTransactionIdAttributeName "xmin" -+ #define MinCommandIdAttributeName "cmin" -+ #define MaxTransactionIdAttributeName "xmax" -+ #define MaxCommandIdAttributeName "cmax" -+ #define TableOidAttributeName "tableoid" -+ #define SecurityAttributeName "security_context" - - #endif /* SYSATTR_H */ -diff -Nrpc blob/src/include/access/tupdesc.h sepgsql/src/include/access/tupdesc.h -*** blob/src/include/access/tupdesc.h Sat Jan 3 12:25:21 2009 ---- sepgsql/src/include/access/tupdesc.h Wed Sep 9 13:14:37 2009 -*************** typedef struct tupleDesc -*** 75,80 **** ---- 75,81 ---- - Oid tdtypeid; /* composite type ID for tuple type */ - int32 tdtypmod; /* typmod for tuple type */ - bool tdhasoid; /* tuple has oid attribute in its header */ -+ bool tdhassecid; /* tuple has secid attribute in its header */ - int tdrefcount; /* reference count, or -1 if not counting */ - } *TupleDesc; - -diff -Nrpc blob/src/include/bootstrap/bootstrap.h sepgsql/src/include/bootstrap/bootstrap.h -*** blob/src/include/bootstrap/bootstrap.h Sat Jan 3 12:25:21 2009 ---- sepgsql/src/include/bootstrap/bootstrap.h Tue Dec 8 14:04:25 2009 -*************** typedef enum -*** 70,76 **** - BootstrapProcess, - StartupProcess, - BgWriterProcess, -! WalWriterProcess - } AuxProcType; - - #endif /* BOOTSTRAP_H */ ---- 70,77 ---- - BootstrapProcess, - StartupProcess, - BgWriterProcess, -! WalWriterProcess, -! SelinuxReceiverProcess, - } AuxProcType; - - #endif /* BOOTSTRAP_H */ -diff -Nrpc blob/src/include/catalog/dependency.h sepgsql/src/include/catalog/dependency.h -*** blob/src/include/catalog/dependency.h Fri Dec 18 09:40:55 2009 ---- sepgsql/src/include/catalog/dependency.h Fri Dec 18 10:27:56 2009 -*************** typedef enum ObjectClass -*** 156,161 **** ---- 156,164 ---- - extern void performDeletion(const ObjectAddress *object, - DropBehavior behavior); - -+ extern void performDeletionNoPerms(const ObjectAddress *object, -+ DropBehavior behavior); -+ - extern void performMultipleDeletions(const ObjectAddresses *objects, - DropBehavior behavior); - -diff -Nrpc blob/src/include/catalog/heap.h sepgsql/src/include/catalog/heap.h -*** blob/src/include/catalog/heap.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/catalog/heap.h Wed Jul 15 19:38:52 2009 -*************** extern Oid heap_create_with_catalog(cons -*** 56,62 **** - int oidinhcount, - OnCommitAction oncommit, - Datum reloptions, -! bool allow_system_table_mods); - - extern void heap_drop_with_catalog(Oid relid); - ---- 56,63 ---- - int oidinhcount, - OnCommitAction oncommit, - Datum reloptions, -! bool allow_system_table_mods, -! Oid *secLabels); - - extern void heap_drop_with_catalog(Oid relid); - -*************** extern List *heap_truncate_find_FKs(List -*** 68,79 **** - - extern void InsertPgAttributeTuple(Relation pg_attribute_rel, - Form_pg_attribute new_attribute, -! CatalogIndexState indstate); - - extern void InsertPgClassTuple(Relation pg_class_desc, - Relation new_rel_desc, - Oid new_rel_oid, -! Datum reloptions); - - extern List *AddRelationNewConstraints(Relation rel, - List *newColDefaults, ---- 69,82 ---- - - extern void InsertPgAttributeTuple(Relation pg_attribute_rel, - Form_pg_attribute new_attribute, -! CatalogIndexState indstate, -! Oid new_att_secid); - - extern void InsertPgClassTuple(Relation pg_class_desc, - Relation new_rel_desc, - Oid new_rel_oid, -! Datum reloptions, -! Oid new_rel_secid); - - extern List *AddRelationNewConstraints(Relation rel, - List *newColDefaults, -*************** extern Form_pg_attribute SystemAttribute -*** 103,108 **** ---- 106,113 ---- - extern Form_pg_attribute SystemAttributeByName(const char *attname, - bool relhasoids); - -+ extern bool SystemAttributeIsWritable(AttrNumber attnum); -+ - extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind); - - extern void CheckAttributeType(const char *attname, Oid atttypid); -diff -Nrpc blob/src/include/catalog/indexing.h sepgsql/src/include/catalog/indexing.h -*** blob/src/include/catalog/indexing.h Fri Dec 18 09:40:55 2009 ---- sepgsql/src/include/catalog/indexing.h Sun Dec 20 23:35:32 2009 -*************** DECLARE_UNIQUE_INDEX(pg_type_oid_index, -*** 252,257 **** ---- 252,262 ---- - DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index, 2704, on pg_type using btree(typname name_ops, typnamespace oid_ops)); - #define TypeNameNspIndexId 2704 - -+ DECLARE_UNIQUE_INDEX(pg_security_secid_index, 3401, on pg_security using btree(secid oid_ops, datid oid_ops, relid oid_ops)); -+ #define SecuritySecidIndexId 3401 -+ DECLARE_INDEX(pg_security_secattr_index, 3402, on pg_security using btree(datid oid_ops, relid oid_ops, secattr text_ops)); -+ #define SecuritySecattrIndexId 3402 -+ - DECLARE_UNIQUE_INDEX(pg_foreign_data_wrapper_oid_index, 112, on pg_foreign_data_wrapper using btree(oid oid_ops)); - #define ForeignDataWrapperOidIndexId 112 - -diff -Nrpc blob/src/include/catalog/pg_attribute.h sepgsql/src/include/catalog/pg_attribute.h -*** blob/src/include/catalog/pg_attribute.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/catalog/pg_attribute.h Thu Sep 10 15:29:52 2009 -*************** DATA(insert ( 1247 cmin 29 0 4 -4 0 -*** 276,281 **** ---- 276,282 ---- - DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 _null_)); - DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 _null_)); - DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 _null_)); -+ DATA(insert ( 1247 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0 _null_)); - - /* ---------------- - * pg_proc -*************** DATA(insert ( 1255 cmin 29 0 4 -4 0 -*** 340,345 **** ---- 341,347 ---- - DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 _null_)); - DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 _null_)); - DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 _null_)); -+ DATA(insert ( 1255 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0 _null_)); - - /* ---------------- - * pg_attribute -*************** DATA(insert ( 1249 cmin 29 0 4 -4 0 -*** 390,395 **** ---- 392,398 ---- - DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 _null_)); - DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 _null_)); - DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 _null_)); -+ DATA(insert ( 1249 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0 _null_)); - - /* ---------------- - * pg_class -*************** DATA(insert ( 1259 cmin 29 0 4 -4 0 -*** 454,459 **** ---- 457,463 ---- - DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 _null_)); - DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 _null_)); - DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 _null_)); -+ DATA(insert ( 1259 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0 _null_)); - - /* ---------------- - * pg_index -diff -Nrpc blob/src/include/catalog/pg_conversion_fn.h sepgsql/src/include/catalog/pg_conversion_fn.h -*** blob/src/include/catalog/pg_conversion_fn.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/catalog/pg_conversion_fn.h Thu Sep 17 22:10:19 2009 -*************** -*** 17,23 **** - extern Oid ConversionCreate(const char *conname, Oid connamespace, - Oid conowner, - int32 conforencoding, int32 contoencoding, -! Oid conproc, bool def); - extern void RemoveConversionById(Oid conversionOid); - extern Oid FindConversion(const char *conname, Oid connamespace); - extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding); ---- 17,23 ---- - extern Oid ConversionCreate(const char *conname, Oid connamespace, - Oid conowner, - int32 conforencoding, int32 contoencoding, -! Oid conproc, Oid consecid, bool def); - extern void RemoveConversionById(Oid conversionOid); - extern Oid FindConversion(const char *conname, Oid connamespace); - extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding); -diff -Nrpc blob/src/include/catalog/pg_largeobject.h sepgsql/src/include/catalog/pg_largeobject.h -*** blob/src/include/catalog/pg_largeobject.h Fri Dec 18 09:40:55 2009 ---- sepgsql/src/include/catalog/pg_largeobject.h Fri Dec 18 10:27:56 2009 -*************** typedef FormData_pg_largeobject *Form_pg -*** 51,57 **** - #define Anum_pg_largeobject_pageno 2 - #define Anum_pg_largeobject_data 3 - -! extern Oid LargeObjectCreate(Oid loid); - extern void LargeObjectDrop(Oid loid); - extern void LargeObjectAlterOwner(Oid loid, Oid newOwnerId); - extern bool LargeObjectExists(Oid loid); ---- 51,57 ---- - #define Anum_pg_largeobject_pageno 2 - #define Anum_pg_largeobject_data 3 - -! extern Oid LargeObjectCreate(Oid loid, Oid secid); - extern void LargeObjectDrop(Oid loid); - extern void LargeObjectAlterOwner(Oid loid, Oid newOwnerId); - extern bool LargeObjectExists(Oid loid); -diff -Nrpc blob/src/include/catalog/pg_namespace.h sepgsql/src/include/catalog/pg_namespace.h -*** blob/src/include/catalog/pg_namespace.h Sat Jan 3 12:25:21 2009 ---- sepgsql/src/include/catalog/pg_namespace.h Wed Jul 15 19:35:52 2009 -*************** DESCR("standard public schema"); -*** 77,82 **** - /* - * prototypes for functions in pg_namespace.c - */ -! extern Oid NamespaceCreate(const char *nspName, Oid ownerId); - - #endif /* PG_NAMESPACE_H */ ---- 77,82 ---- - /* - * prototypes for functions in pg_namespace.c - */ -! extern Oid NamespaceCreate(const char *nspName, Oid ownerId, Oid nspsecid); - - #endif /* PG_NAMESPACE_H */ -diff -Nrpc blob/src/include/catalog/pg_proc.h sepgsql/src/include/catalog/pg_proc.h -*** blob/src/include/catalog/pg_proc.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/catalog/pg_proc.h Sun Dec 20 23:35:32 2009 -*************** DESCR("I/O"); -*** 4335,4340 **** ---- 4335,4353 ---- - DATA(insert OID = 2963 ( uuid_hash PGNSP PGUID 12 1 0 0 f f f t f i 1 0 23 "2950" _null_ _null_ _null_ _null_ uuid_hash _null_ _null_ _null_ )); - DESCR("hash"); - -+ /* SE-PostgreSQL related functions */ -+ DATA(insert OID = 3415 ( seclabel_to_secid PGNSP PGUID 12 1 0 0 f f f t f v 1 0 26 "2249" _null_ _null_ _null_ _null_ seclabel_to_secid _null_ _null_ _null_ )); -+ DATA(insert OID = 3416 ( sepgsql_getcon PGNSP PGUID 12 1 0 0 f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ sepgsql_getcon _null_ _null_ _null_ )); -+ DATA(insert OID = 3417 ( sepgsql_server_getcon PGNSP PGUID 12 1 0 0 f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ sepgsql_server_getcon _null_ _null_ _null_ )); -+ DATA(insert OID = 3418 ( sepgsql_get_user PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_ _null_ sepgsql_get_user _null_ _null_ _null_ )); -+ DATA(insert OID = 3419 ( sepgsql_set_user PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_ _null_ sepgsql_set_user _null_ _null_ _null_ )); -+ DATA(insert OID = 3420 ( sepgsql_get_role PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_ _null_ sepgsql_get_role _null_ _null_ _null_ )); -+ DATA(insert OID = 3421 ( sepgsql_set_role PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_ _null_ sepgsql_set_role _null_ _null_ _null_ )); -+ DATA(insert OID = 3422 ( sepgsql_get_type PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_ _null_ sepgsql_get_type _null_ _null_ _null_ )); -+ DATA(insert OID = 3423 ( sepgsql_set_type PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_ _null_ sepgsql_set_type _null_ _null_ _null_ )); -+ DATA(insert OID = 3424 ( sepgsql_get_range PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_ _null_ sepgsql_get_range _null_ _null_ _null_ )); -+ DATA(insert OID = 3425 ( sepgsql_set_range PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_ _null_ sepgsql_set_range _null_ _null_ _null_ )); -+ - /* enum related procs */ - DATA(insert OID = 3504 ( anyenum_in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3500 "2275" _null_ _null_ _null_ _null_ anyenum_in _null_ _null_ _null_ )); - DESCR("I/O"); -diff -Nrpc blob/src/include/catalog/pg_proc_fn.h sepgsql/src/include/catalog/pg_proc_fn.h -*** blob/src/include/catalog/pg_proc_fn.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/catalog/pg_proc_fn.h Wed Jul 15 19:37:35 2009 -*************** extern Oid ProcedureCreate(const char *p -*** 37,43 **** - List *parameterDefaults, - Datum proconfig, - float4 procost, -! float4 prorows); - - extern bool function_parse_error_transpose(const char *prosrc); - ---- 37,44 ---- - List *parameterDefaults, - Datum proconfig, - float4 procost, -! float4 prorows, -! Node *proseclabel); - - extern bool function_parse_error_transpose(const char *prosrc); - -diff -Nrpc blob/src/include/catalog/pg_security.h sepgsql/src/include/catalog/pg_security.h -*** blob/src/include/catalog/pg_security.h Thu Jan 1 09:00:00 1970 ---- sepgsql/src/include/catalog/pg_security.h Sun Dec 20 23:35:32 2009 -*************** -*** 0 **** ---- 1,89 ---- -+ /* -+ * src/include/catalog/pg_security.h -+ * Definition of the security label relation (pg_security) -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #ifndef PG_SECURITY_H -+ #define PG_SECURITY_H -+ -+ #include "catalog/genbki.h" -+ -+ #include "access/htup.h" -+ #include "nodes/parsenodes.h" -+ #include "utils/acl.h" -+ #include "utils/relcache.h" -+ -+ #define SecurityRelationId 3400 -+ -+ CATALOG(pg_security,3400) BKI_SHARED_RELATION BKI_WITHOUT_OIDS -+ { -+ /* Identifier of the security attribute */ -+ Oid secid; -+ -+ /* OID of the database which referes the entry */ -+ Oid datid; -+ -+ /* OID of the table which refers the entry */ -+ Oid relid; -+ -+ /* Text representation of security attribute */ -+ text secattr; -+ } FormData_pg_security; -+ -+ /* -+ * Form_pg_security corresponds to a pointer to a tuple with -+ * the format of pg_security relation. -+ */ -+ typedef FormData_pg_security *Form_pg_security; -+ -+ /* -+ * Compiler constants for pg_security -+ */ -+ #define Natts_pg_security 4 -+ #define Anum_pg_security_secid 1 -+ #define Anum_pg_security_datid 2 -+ #define Anum_pg_security_relid 3 -+ #define Anum_pg_security_secattr 4 -+ -+ /* -+ * Functions to translate between security label and identifier -+ */ -+ extern void -+ securityPostBootstrapingMode(void); -+ -+ extern void -+ securityOnCreateDatabase(Oid src_datid, Oid dst_datid); -+ -+ extern void -+ securityOnDropDatabase(Oid datid); -+ -+ extern bool -+ securityTupleDescHasSecid(Oid relid, char relkind); -+ -+ extern Oid -+ securityRawSecLabelIn(Oid relid, char *seclabel); -+ -+ extern char * -+ securityRawSecLabelOut(Oid relid, Oid secid); -+ -+ extern Oid -+ securityTransSecLabelIn(Oid relid, char *seclabel); -+ -+ extern char * -+ securityTransSecLabelOut(Oid relid, Oid secid); -+ -+ extern Datum -+ securitySysattSecLabelOut(Oid relid, HeapTuple tuple); -+ -+ extern void -+ securityReclaimOnDropTable(Oid relid); -+ -+ extern void -+ seclabelRelationReclaim(Oid relOid); -+ -+ extern Datum -+ seclabel_to_secid(PG_FUNCTION_ARGS); -+ -+ #endif /* PG_SECURITY_H */ -diff -Nrpc blob/src/include/catalog/toasting.h sepgsql/src/include/catalog/toasting.h -*** blob/src/include/catalog/toasting.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/catalog/toasting.h Wed Jul 15 19:30:50 2009 -*************** DECLARE_TOAST(pg_database, 2844, 2845); -*** 58,62 **** ---- 58,65 ---- - DECLARE_TOAST(pg_shdescription, 2846, 2847); - #define PgShdescriptionToastTable 2846 - #define PgShdescriptionToastIndex 2847 -+ DECLARE_TOAST(pg_security, 3403, 3404); -+ #define PgSecurityToastTable 3403 -+ #define PgSecurityToastIndex 3404 - - #endif /* TOASTING_H */ -diff -Nrpc blob/src/include/commands/alter.h sepgsql/src/include/commands/alter.h -*** blob/src/include/commands/alter.h Sat Jan 3 12:25:21 2009 ---- sepgsql/src/include/commands/alter.h Wed Jul 15 19:37:35 2009 -*************** -*** 19,23 **** ---- 19,24 ---- - extern void ExecRenameStmt(RenameStmt *stmt); - extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt); - extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt); -+ extern void ExecAlterSecLabelStmt(AlterSecLabelStmt *stmt); - - #endif /* ALTER_H */ -diff -Nrpc blob/src/include/commands/dbcommands.h sepgsql/src/include/commands/dbcommands.h -*** blob/src/include/commands/dbcommands.h Sat Jan 3 12:25:21 2009 ---- sepgsql/src/include/commands/dbcommands.h Wed Jul 15 19:37:35 2009 -*************** extern void RenameDatabase(const char *o -*** 58,63 **** ---- 58,64 ---- - extern void AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel); - extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt); - extern void AlterDatabaseOwner(const char *dbname, Oid newOwnerId); -+ extern void AlterDatabaseSecLabel(const char *dbname, DefElem *seclabel); - - extern Oid get_database_oid(const char *dbname); - extern char *get_database_name(Oid dbid); -diff -Nrpc blob/src/include/commands/defrem.h sepgsql/src/include/commands/defrem.h -*** blob/src/include/commands/defrem.h Thu Apr 9 00:13:21 2009 ---- sepgsql/src/include/commands/defrem.h Wed Jul 15 19:37:35 2009 -*************** extern void SetFunctionArgType(Oid funcO -*** 53,58 **** ---- 53,59 ---- - extern void RenameFunction(List *name, List *argtypes, const char *newname); - extern void AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId); - extern void AlterFunctionOwner_oid(Oid procOid, Oid newOwnerId); -+ extern void AlterFunctionSecLabel(List *name, List *argtypes, DefElem *seclabel); - extern void AlterFunction(AlterFunctionStmt *stmt); - extern void CreateCast(CreateCastStmt *stmt); - extern void DropCast(DropCastStmt *stmt); -diff -Nrpc blob/src/include/commands/schemacmds.h sepgsql/src/include/commands/schemacmds.h -*** blob/src/include/commands/schemacmds.h Sat Jan 3 12:25:21 2009 ---- sepgsql/src/include/commands/schemacmds.h Wed Jul 15 19:37:35 2009 -*************** extern void RemoveSchemaById(Oid schemaO -*** 26,30 **** ---- 26,31 ---- - extern void RenameSchema(const char *oldname, const char *newname); - extern void AlterSchemaOwner(const char *name, Oid newOwnerId); - extern void AlterSchemaOwner_oid(Oid schemaOid, Oid newOwnerId); -+ extern void AlterSchemaSecLabel(const char *name, DefElem *seclabel); - - #endif /* SCHEMACMDS_H */ -diff -Nrpc blob/src/include/commands/tablecmds.h sepgsql/src/include/commands/tablecmds.h -*** blob/src/include/commands/tablecmds.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/commands/tablecmds.h Wed Jul 15 19:37:35 2009 -*************** extern void AlterRelationNamespaceIntern -*** 35,40 **** ---- 35,43 ---- - Oid oldNspOid, Oid newNspOid, - bool hasDependEntry); - -+ extern void AlterRelationSecLabel(RangeVar *relation, const char *attname, -+ ObjectType objtype, DefElem *seclabel); -+ - extern void CheckTableNotInUse(Relation rel, const char *stmt); - - extern void ExecuteTruncate(TruncateStmt *stmt); -diff -Nrpc blob/src/include/executor/executor.h sepgsql/src/include/executor/executor.h -*** blob/src/include/executor/executor.h Sun Sep 6 19:40:49 2009 ---- sepgsql/src/include/executor/executor.h Wed Sep 9 13:14:37 2009 -*************** extern TupleHashEntry FindTupleHashEntry -*** 130,136 **** - /* - * prototypes from functions in execJunk.c - */ -! extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid, - TupleTableSlot *slot); - extern JunkFilter *ExecInitJunkFilterConversion(List *targetList, - TupleDesc cleanTupType, ---- 130,136 ---- - /* - * prototypes from functions in execJunk.c - */ -! extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid, bool hasseclabel, - TupleTableSlot *slot); - extern JunkFilter *ExecInitJunkFilterConversion(List *targetList, - TupleDesc cleanTupType, -*************** extern void InitResultRelInfo(ResultRelI -*** 163,168 **** ---- 163,169 ---- - bool doInstrument); - extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid); - extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids); -+ extern bool ExecContextForcesSecids(PlanState *planstate, bool *hassecids); - extern void ExecConstraints(ResultRelInfo *resultRelInfo, - TupleTableSlot *slot, EState *estate); - extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, -*************** extern void ExecInitScanTupleSlot(EState -*** 216,223 **** - extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate); - extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, - TupleDesc tupType); -! extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid); -! extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid); - extern TupleDesc ExecTypeFromExprList(List *exprList); - extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg); - ---- 217,224 ---- - extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate); - extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, - TupleDesc tupType); -! extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid, bool hasseclabel); -! extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hasseclabel); - extern TupleDesc ExecTypeFromExprList(List *exprList); - extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg); - -diff -Nrpc blob/src/include/executor/tuptable.h sepgsql/src/include/executor/tuptable.h -*** blob/src/include/executor/tuptable.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/executor/tuptable.h Wed Jul 15 19:38:52 2009 -*************** typedef struct TupleTableSlot -*** 127,132 **** ---- 127,133 ---- - MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */ - HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */ - long tts_off; /* saved state for slot_deform_tuple */ -+ Datum tts_seclabel; /* temp storage for the given security_label */ - } TupleTableSlot; - - #define TTS_HAS_PHYSICAL_TUPLE(slot) \ -diff -Nrpc blob/src/include/libpq/be-fsstubs.h sepgsql/src/include/libpq/be-fsstubs.h -*** blob/src/include/libpq/be-fsstubs.h Fri Dec 18 09:40:55 2009 ---- sepgsql/src/include/libpq/be-fsstubs.h Fri Dec 18 10:27:56 2009 -*************** extern Datum lo_tell(PG_FUNCTION_ARGS); -*** 37,42 **** ---- 37,45 ---- - extern Datum lo_unlink(PG_FUNCTION_ARGS); - extern Datum lo_truncate(PG_FUNCTION_ARGS); - -+ extern Datum lo_get_security(PG_FUNCTION_ARGS); -+ extern Datum lo_set_security(PG_FUNCTION_ARGS); -+ - /* - * compatibility option for access control - */ -diff -Nrpc blob/src/include/nodes/nodes.h sepgsql/src/include/nodes/nodes.h -*** blob/src/include/nodes/nodes.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/nodes/nodes.h Wed Jul 15 19:37:35 2009 -*************** typedef enum NodeTag -*** 337,342 **** ---- 337,343 ---- - T_CreateUserMappingStmt, - T_AlterUserMappingStmt, - T_DropUserMappingStmt, -+ T_AlterSecLabelStmt, - - /* - * TAGS FOR PARSE TREE NODES (parsenodes.h) -diff -Nrpc blob/src/include/nodes/parsenodes.h sepgsql/src/include/nodes/parsenodes.h -*** blob/src/include/nodes/parsenodes.h Fri Dec 18 09:40:55 2009 ---- sepgsql/src/include/nodes/parsenodes.h Thu Dec 24 21:59:25 2009 -*************** typedef struct ColumnDef -*** 463,468 **** ---- 463,469 ---- - Node *raw_default; /* default value (untransformed parse tree) */ - Node *cooked_default; /* default value (transformed expr tree) */ - List *constraints; /* other constraints on column */ -+ Node *secLabel; /* security label of column */ - } ColumnDef; - - /* -*************** typedef struct CreateSchemaStmt -*** 1069,1074 **** ---- 1070,1076 ---- - NodeTag type; - char *schemaname; /* the name of the schema to create */ - char *authid; /* the owner of the created schema */ -+ Node *secLabel; /* explicitly specified security label */ - List *schemaElts; /* schema components (list of parsenodes) */ - } CreateSchemaStmt; - -*************** typedef struct CreateStmt -*** 1335,1340 **** ---- 1337,1343 ---- - List *options; /* options from WITH clause */ - OnCommitAction oncommit; /* what do we do at COMMIT? */ - char *tablespacename; /* table space to use, or NULL */ -+ List *secLabel; /* explicitly specified security label */ - } CreateStmt; - - /* ---------- -*************** typedef struct CreateSeqStmt -*** 1639,1644 **** ---- 1642,1648 ---- - NodeTag type; - RangeVar *sequence; /* the sequence to create */ - List *options; -+ Node *secLabel; - } CreateSeqStmt; - - typedef struct AlterSeqStmt -*************** typedef struct AlterOwnerStmt -*** 1993,1998 **** ---- 1997,2016 ---- - char *newowner; /* the new owner */ - } AlterOwnerStmt; - -+ /* ---------------------- -+ * Alter Object Security Label Statement -+ * ---------------------- -+ */ -+ typedef struct AlterSecLabelStmt -+ { -+ NodeTag type; -+ ObjectType objectType; /* OBJECT_TABLE, OBJECT_COLUMN, etc */ -+ RangeVar *relation; /* in case it's a table */ -+ List *object; /* in case it's some other object */ -+ List *objarg; /* argument types, if applicable */ -+ char *subname; /* column name, if needed */ -+ Node *secLabel; /* the new security label */ -+ } AlterSecLabelStmt; - - /* ---------------------- - * Create Rule Statement -diff -Nrpc blob/src/include/nodes/plannodes.h sepgsql/src/include/nodes/plannodes.h -*** blob/src/include/nodes/plannodes.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/nodes/plannodes.h Wed Jul 15 19:39:56 2009 -*************** -*** 16,21 **** ---- 16,22 ---- - - #include "access/sdir.h" - #include "nodes/bitmapset.h" -+ #include "nodes/parsenodes.h" - #include "nodes/primnodes.h" - #include "storage/itemptr.h" - -*************** typedef struct Scan -*** 239,244 **** ---- 240,251 ---- - { - Plan plan; - Index scanrelid; /* relid is index into the range table */ -+ -+ /* -+ * Row-level access control stuff. Zero means we don't need -+ * to apply row-level access control on the Scan. -+ */ -+ uint32 rowlvPerms; - } Scan; - - /* ---------------- -diff -Nrpc blob/src/include/nodes/relation.h sepgsql/src/include/nodes/relation.h -*** blob/src/include/nodes/relation.h Thu Jun 18 10:20:52 2009 ---- sepgsql/src/include/nodes/relation.h Wed Jul 15 19:39:56 2009 -*************** typedef struct RelOptInfo -*** 383,388 **** ---- 383,397 ---- - * list just to avoid recomputing the best inner indexscan repeatedly for - * similar outer relations. See comments for InnerIndexscanInfo. - */ -+ -+ /* -+ * Permissions used in Row-level access control features both of DAC -+ * and MAC. The lower 16bit is used for DAC, and rest of upper bits -+ * are used for MAC. When rowlvPerms is zero, so it means we don't need -+ * to apply the row-level stuff on the relation in both of levels. -+ * It can be used as a hint for optimization stuff. -+ */ -+ uint32 rowlvPerms; - } RelOptInfo; - - /* -diff -Nrpc blob/src/include/parser/kwlist.h sepgsql/src/include/parser/kwlist.h -*** blob/src/include/parser/kwlist.h Thu Apr 9 00:13:21 2009 ---- sepgsql/src/include/parser/kwlist.h Thu Dec 24 21:59:25 2009 -*************** PG_KEYWORD("connection", CONNECTION, UNR -*** 88,93 **** ---- 88,94 ---- - PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD) - PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD) - PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD) -+ PG_KEYWORD("context", CONTEXT_P, UNRESERVED_KEYWORD) - PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD) - PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD) - PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD) -diff -Nrpc blob/src/include/pg_config.h.in sepgsql/src/include/pg_config.h.in -*** blob/src/include/pg_config.h.in Thu Mar 18 09:43:03 2010 ---- sepgsql/src/include/pg_config.h.in Thu Mar 18 01:55:40 2010 -*************** -*** 263,268 **** ---- 263,271 ---- - /* Define to 1 if you have the header file. */ - #undef HAVE_LDAP_H - -+ /* Define to 1 if you have the `audit' library (-laudit). */ -+ #undef HAVE_LIBAUDIT -+ - /* Define to 1 if you have the `crypto' library (-lcrypto). */ - #undef HAVE_LIBCRYPTO - -*************** -*** 391,396 **** ---- 394,402 ---- - /* Define to 1 if you have the header file. */ - #undef HAVE_SECURITY_PAM_APPL_H - -+ /* Define to 1 if you enable SELinux support */ -+ #undef HAVE_SELINUX -+ - /* Define to 1 if you have the `setproctitle' function. */ - #undef HAVE_SETPROCTITLE - -diff -Nrpc blob/src/include/security/rowlevel.h sepgsql/src/include/security/rowlevel.h -*** blob/src/include/security/rowlevel.h Thu Jan 1 09:00:00 1970 ---- sepgsql/src/include/security/rowlevel.h Thu Jul 16 17:22:29 2009 -*************** -*** 0 **** ---- 1,44 ---- -+ /* -+ * src/include/security/rowlevel.h -+ * Definition of the facility of row-level access controls -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #ifndef ROWLEVEL_H -+ #define ROWLEVEL_H -+ -+ #include "access/htup.h" -+ #include "executor/tuptable.h" -+ #include "nodes/plannodes.h" -+ #include "utils/relcache.h" -+ -+ #define ROWLV_BYPASS_MODE 1 -+ #define ROWLV_FILTER_MODE 2 -+ #define ROWLV_ABORT_MODE 3 -+ -+ extern int -+ rowlvGetPerformingMode(void); -+ -+ extern int -+ rowlvSetPerformingMode(int mode); -+ -+ extern uint32 -+ rowlvSetupPermissions(RangeTblEntry *rte); -+ -+ extern bool -+ rowlvExecScanFilter(Scan *scan, Relation rel, TupleTableSlot *slot); -+ -+ extern void -+ rowlvExecScanAbort(Scan *scan, Relation rel, TupleTableSlot *slot); -+ -+ extern void -+ rowlvHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal); -+ -+ extern void -+ rowlvHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup); -+ -+ extern bool -+ rowlvCopyToTuple(Relation rel, HeapTuple tuple); -+ -+ #endif /* ROWLEVEL_H */ -diff -Nrpc blob/src/include/security/sepgsql.h sepgsql/src/include/security/sepgsql.h -*** blob/src/include/security/sepgsql.h Thu Jan 1 09:00:00 1970 ---- sepgsql/src/include/security/sepgsql.h Thu Dec 24 21:59:25 2009 -*************** -*** 0 **** ---- 1,725 ---- -+ /* -+ * src/include/security/sepgsql.h -+ * Headers of SE-PostgreSQL -+ * -+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ */ -+ #ifndef SEPGSQL_H -+ #define SEPGSQL_H -+ -+ #include "access/htup.h" -+ #include "catalog/dependency.h" -+ #include "executor/execdesc.h" -+ #include "fmgr.h" -+ #include "nodes/parsenodes.h" -+ #include "storage/large_object.h" -+ #include "utils/relcache.h" -+ -+ #ifdef HAVE_SELINUX -+ -+ #include -+ -+ /* GUC parameter to turn on/off SE-PostgreSQL */ -+ extern int sepostgresql_mode; -+ -+ #define SEPGSQL_MODE_DEFAULT 1 -+ #define SEPGSQL_MODE_ENFORCING 2 -+ #define SEPGSQL_MODE_PERMISSIVE 3 -+ #define SEPGSQL_MODE_INTERNAL 4 -+ #define SEPGSQL_MODE_DISABLED 5 -+ -+ /* GUC parameter to turn on/off Row-level controls */ -+ extern bool sepostgresql_row_level; -+ -+ /* GUC parameter to turn on/off mcstrans */ -+ extern bool sepostgresql_mcstrans; -+ -+ /* Objject classes and permissions internally used */ -+ enum SepgsqlClasses -+ { -+ SEPG_CLASS_PROCESS = 0, -+ SEPG_CLASS_FILE, -+ SEPG_CLASS_DIR, -+ SEPG_CLASS_LNK_FILE, -+ SEPG_CLASS_CHR_FILE, -+ SEPG_CLASS_BLK_FILE, -+ SEPG_CLASS_SOCK_FILE, -+ SEPG_CLASS_FIFO_FILE, -+ SEPG_CLASS_DB_DATABASE, -+ SEPG_CLASS_DB_SCHEMA, -+ SEPG_CLASS_DB_TABLE, -+ SEPG_CLASS_DB_VIEW, -+ SEPG_CLASS_DB_SEQUENCE, -+ SEPG_CLASS_DB_PROCEDURE, -+ SEPG_CLASS_DB_COLUMN, -+ SEPG_CLASS_DB_TUPLE, -+ SEPG_CLASS_DB_BLOB, -+ SEPG_CLASS_MAX, -+ }; -+ -+ #define SEPG_PROCESS__TRANSITION (1<<0) -+ -+ #define SEPG_FILE__READ (1<<0) -+ #define SEPG_FILE__WRITE (1<<1) -+ #define SEPG_FILE__CREATE (1<<2) -+ #define SEPG_FILE__GETATTR (1<<3) -+ -+ #define SEPG_DIR__READ (SEPG_FILE__READ) -+ #define SEPG_DIR__WRITE (SEPG_FILE__WRITE) -+ #define SEPG_DIR__CREATE (SEPG_FILE__CREATE) -+ #define SEPG_DIR__GETATTR (SEPG_FILE__GETATTR) -+ -+ #define SEPG_LNK_FILE__READ (SEPG_FILE__READ) -+ #define SEPG_LNK_FILE__WRITE (SEPG_FILE__WRITE) -+ #define SEPG_LNK_FILE__CREATE (SEPG_FILE__CREATE) -+ #define SEPG_LNK_FILE__GETATTR (SEPG_FILE__GETATTR) -+ -+ #define SEPG_CHR_FILE__READ (SEPG_FILE__READ) -+ #define SEPG_CHR_FILE__WRITE (SEPG_FILE__WRITE) -+ #define SEPG_CHR_FILE__CREATE (SEPG_FILE__CREATE) -+ #define SEPG_CHR_FILE__GETATTR (SEPG_FILE__GETATTR) -+ -+ #define SEPG_BLK_FILE__READ (SEPG_FILE__READ) -+ #define SEPG_BLK_FILE__WRITE (SEPG_FILE__WRITE) -+ #define SEPG_BLK_FILE__CREATE (SEPG_FILE__CREATE) -+ #define SEPG_BLK_FILE__GETATTR (SEPG_FILE__GETATTR) -+ -+ #define SEPG_SOCK_FILE__READ (SEPG_FILE__READ) -+ #define SEPG_SOCK_FILE__WRITE (SEPG_FILE__WRITE) -+ #define SEPG_SOCK_FILE__CREATE (SEPG_FILE__CREATE) -+ #define SEPG_SOCK_FILE__GETATTR (SEPG_FILE__GETATTR) -+ -+ #define SEPG_FIFO_FILE__READ (SEPG_FILE__READ) -+ #define SEPG_FIFO_FILE__WRITE (SEPG_FILE__WRITE) -+ #define SEPG_FIFO_FILE__CREATE (SEPG_FILE__CREATE) -+ #define SEPG_FIFO_FILE__GETATTR (SEPG_FILE__GETATTR) -+ -+ #define SEPG_DB_DATABASE__CREATE (1<<0) -+ #define SEPG_DB_DATABASE__DROP (1<<1) -+ #define SEPG_DB_DATABASE__GETATTR (1<<2) -+ #define SEPG_DB_DATABASE__SETATTR (1<<3) -+ #define SEPG_DB_DATABASE__RELABELFROM (1<<4) -+ #define SEPG_DB_DATABASE__RELABELTO (1<<5) -+ #define SEPG_DB_DATABASE__ACCESS (1<<6) -+ #define SEPG_DB_DATABASE__LOAD_MODULE (1<<7) -+ -+ #define SEPG_DB_SCHEMA__CREATE (SEPG_DB_DATABASE__CREATE) -+ #define SEPG_DB_SCHEMA__DROP (SEPG_DB_DATABASE__DROP) -+ #define SEPG_DB_SCHEMA__GETATTR (SEPG_DB_DATABASE__GETATTR) -+ #define SEPG_DB_SCHEMA__SETATTR (SEPG_DB_DATABASE__SETATTR) -+ #define SEPG_DB_SCHEMA__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+ #define SEPG_DB_SCHEMA__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+ #define SEPG_DB_SCHEMA__SEARCH (1<<6) -+ #define SEPG_DB_SCHEMA__ADD_NAME (1<<7) -+ #define SEPG_DB_SCHEMA__REMOVE_NAME (1<<8) -+ -+ #define SEPG_DB_TABLE__CREATE (SEPG_DB_DATABASE__CREATE) -+ #define SEPG_DB_TABLE__DROP (SEPG_DB_DATABASE__DROP) -+ #define SEPG_DB_TABLE__GETATTR (SEPG_DB_DATABASE__GETATTR) -+ #define SEPG_DB_TABLE__SETATTR (SEPG_DB_DATABASE__SETATTR) -+ #define SEPG_DB_TABLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+ #define SEPG_DB_TABLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+ #define SEPG_DB_TABLE__SELECT (1<<6) -+ #define SEPG_DB_TABLE__UPDATE (1<<7) -+ #define SEPG_DB_TABLE__INSERT (1<<8) -+ #define SEPG_DB_TABLE__DELETE (1<<9) -+ #define SEPG_DB_TABLE__LOCK (1<<10) -+ #define SEPG_DB_TABLE__REFERENCE (1<<11) -+ -+ #define SEPG_DB_SEQUENCE__CREATE (SEPG_DB_DATABASE__CREATE) -+ #define SEPG_DB_SEQUENCE__DROP (SEPG_DB_DATABASE__DROP) -+ #define SEPG_DB_SEQUENCE__GETATTR (SEPG_DB_DATABASE__GETATTR) -+ #define SEPG_DB_SEQUENCE__SETATTR (SEPG_DB_DATABASE__SETATTR) -+ #define SEPG_DB_SEQUENCE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+ #define SEPG_DB_SEQUENCE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+ #define SEPG_DB_SEQUENCE__GET_VALUE (1<<6) -+ #define SEPG_DB_SEQUENCE__NEXT_VALUE (1<<7) -+ #define SEPG_DB_SEQUENCE__SET_VALUE (1<<8) -+ -+ #define SEPG_DB_VIEW__CREATE (SEPG_DB_DATABASE__CREATE) -+ #define SEPG_DB_VIEW__DROP (SEPG_DB_DATABASE__DROP) -+ #define SEPG_DB_VIEW__GETATTR (SEPG_DB_DATABASE__GETATTR) -+ #define SEPG_DB_VIEW__SETATTR (SEPG_DB_DATABASE__SETATTR) -+ #define SEPG_DB_VIEW__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+ #define SEPG_DB_VIEW__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+ #define SEPG_DB_VIEW__USAGE (1<<6) -+ -+ #define SEPG_DB_PROCEDURE__CREATE (SEPG_DB_DATABASE__CREATE) -+ #define SEPG_DB_PROCEDURE__DROP (SEPG_DB_DATABASE__DROP) -+ #define SEPG_DB_PROCEDURE__GETATTR (SEPG_DB_DATABASE__GETATTR) -+ #define SEPG_DB_PROCEDURE__SETATTR (SEPG_DB_DATABASE__SETATTR) -+ #define SEPG_DB_PROCEDURE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+ #define SEPG_DB_PROCEDURE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+ #define SEPG_DB_PROCEDURE__EXECUTE (1<<6) -+ #define SEPG_DB_PROCEDURE__ENTRYPOINT (1<<7) -+ #define SEPG_DB_PROCEDURE__INSTALL (1<<8) -+ -+ #define SEPG_DB_COLUMN__CREATE (SEPG_DB_DATABASE__CREATE) -+ #define SEPG_DB_COLUMN__DROP (SEPG_DB_DATABASE__DROP) -+ #define SEPG_DB_COLUMN__GETATTR (SEPG_DB_DATABASE__GETATTR) -+ #define SEPG_DB_COLUMN__SETATTR (SEPG_DB_DATABASE__SETATTR) -+ #define SEPG_DB_COLUMN__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+ #define SEPG_DB_COLUMN__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+ #define SEPG_DB_COLUMN__SELECT (1<<6) -+ #define SEPG_DB_COLUMN__UPDATE (1<<7) -+ #define SEPG_DB_COLUMN__INSERT (1<<8) -+ #define SEPG_DB_COLUMN__REFERENCE (1<<9) -+ -+ #define SEPG_DB_TUPLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+ #define SEPG_DB_TUPLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+ #define SEPG_DB_TUPLE__SELECT (SEPG_DB_DATABASE__GETATTR) -+ #define SEPG_DB_TUPLE__UPDATE (SEPG_DB_DATABASE__SETATTR) -+ #define SEPG_DB_TUPLE__INSERT (SEPG_DB_DATABASE__CREATE) -+ #define SEPG_DB_TUPLE__DELETE (SEPG_DB_DATABASE__DROP) -+ -+ #define SEPG_DB_BLOB__CREATE (SEPG_DB_DATABASE__CREATE) -+ #define SEPG_DB_BLOB__DROP (SEPG_DB_DATABASE__DROP) -+ #define SEPG_DB_BLOB__GETATTR (SEPG_DB_DATABASE__GETATTR) -+ #define SEPG_DB_BLOB__SETATTR (SEPG_DB_DATABASE__SETATTR) -+ #define SEPG_DB_BLOB__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) -+ #define SEPG_DB_BLOB__RELABELTO (SEPG_DB_DATABASE__RELABELTO) -+ #define SEPG_DB_BLOB__READ (1<<6) -+ #define SEPG_DB_BLOB__WRITE (1<<7) -+ #define SEPG_DB_BLOB__IMPORT (1<<8) -+ #define SEPG_DB_BLOB__EXPORT (1<<9) -+ -+ /* -+ * sepgsql_sid_t : alternative representation of security context -+ */ -+ typedef struct { -+ Oid relid; -+ Oid secid; -+ } sepgsql_sid_t; -+ -+ #define SidIsValid(sid) (OidIsValid((sid).relid) && OidIsValid((sid).secid)) -+ -+ /* -+ * selinux.c : communication to in-kernel SELinux -+ */ -+ extern void sepgsqlInitialize(void); -+ extern Size sepgsqlShmemSize(void); -+ extern bool sepgsqlIsEnabled(void); -+ extern bool sepgsqlIsEnabledBootstrap(void); -+ extern bool sepgsqlGetEnforce(void); -+ extern char *sepgsqlShowMode(void); -+ extern char *sepgsqlGetServerLabel(void); -+ extern char *sepgsqlGetClientLabel(void); -+ extern char *sepgsqlSetClientLabel(char *new_label); -+ extern bool -+ sepgsqlComputePerms(char *scontext, char *tcontext, -+ uint16 tclass, uint32 required, -+ const char *audit_name, bool abort); -+ extern char * -+ sepgsqlComputeCreate(char *scontext, char *tcontext, uint16 tclass); -+ extern bool -+ sepgsqlClientHasPerms(sepgsql_sid_t tsid, uint16 tclass, uint32 required, -+ const char *audit_name, bool abort); -+ extern sepgsql_sid_t -+ sepgsqlClientCreateSecid(sepgsql_sid_t tsid, uint16 tclass, Oid nrelid); -+ extern char * -+ sepgsqlClientCreateLabel(sepgsql_sid_t tsid, uint16 tclass); -+ -+ extern bool sepgsqlReceiverStart(void); -+ extern void sepgsqlReceiverMain(void); -+ -+ /* -+ * bridge.c : new style security hooks -+ */ -+ -+ /* pg_attribute */ -+ extern Oid -+ sepgsql_attribute_create(Oid relOid, ColumnDef *cdef); -+ extern void -+ sepgsql_attribute_alter(Oid relOid, const char *attname); -+ extern void -+ sepgsql_attribute_drop(Oid relOid, AttrNumber attnum); -+ extern void -+ sepgsql_attribute_grant(Oid relOid, AttrNumber attnum); -+ extern Oid -+ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, DefElem *newLabel); -+ -+ /* pg_cast */ -+ extern Oid -+ sepgsql_cast_create(Oid sourceTypOid, Oid targetTypOid, Oid funcOid); -+ extern void -+ sepgsql_cast_drop(Oid castOid); -+ -+ /* pg_class */ -+ extern Oid * -+ sepgsql_relation_create(const char *relName, -+ char relkind, -+ TupleDesc tupDesc, -+ Oid nspOid, -+ DefElem *relLabel, -+ List *colList, -+ bool createAs, -+ bool permission); -+ extern Oid * -+ sepgsql_relation_copy(Relation src); -+ extern void -+ sepgsql_relation_alter(Oid relOid, const char *newName, Oid newNsp); -+ extern void -+ sepgsql_relation_drop(Oid relOid); -+ extern void -+ sepgsql_relation_grant(Oid relOid); -+ extern Oid -+ sepgsql_relation_relabel(Oid relOid, DefElem *newLabel); -+ extern void -+ sepgsql_relation_get_transaction_id(Oid relOid); -+ extern void -+ sepgsql_relation_copy_definition(Oid relOid); -+ extern void -+ sepgsql_relation_truncate(Relation rel); -+ extern void -+ sepgsql_relation_references(Relation rel, int16 *attnums, int natts); -+ extern void -+ sepgsql_relation_lock(Oid relOid); -+ extern void -+ sepgsql_view_replace(Oid viewOid); -+ extern void -+ sepgsql_index_create(Oid relOid, Oid nspOid); -+ extern void -+ sepgsql_sequence_get_value(Oid seqOid); -+ extern void -+ sepgsql_sequence_next_value(Oid seqOid); -+ extern void -+ sepgsql_sequence_set_value(Oid seqOid); -+ -+ /* pg_conversion */ -+ extern Oid -+ sepgsql_conversion_create(const char *convName, Oid nspOid, Oid procOid); -+ extern void -+ sepgsql_conversion_alter(Oid convOid, const char *newName); -+ extern void -+ sepgsql_conversion_drop(Oid convOid); -+ -+ /* pg_database */ -+ extern Oid -+ sepgsql_database_create(const char *datName, Oid srcDatOid, DefElem *newLabel); -+ extern void -+ sepgsql_database_alter(Oid datOid); -+ extern void -+ sepgsql_database_drop(Oid datOid); -+ extern Oid -+ sepgsql_database_relabel(Oid datOid, DefElem *newLabel); -+ extern void -+ sepgsql_database_grant(Oid datOid); -+ extern void -+ sepgsql_database_access(Oid datOid); -+ extern bool -+ sepgsql_database_superuser(Oid datOid); -+ extern void -+ sepgsql_database_load_module(Oid datOid, const char *filename); -+ -+ /* pg_foreign_data_wrapper */ -+ extern Oid -+ sepgsql_fdw_create(const char *fdwName, Oid fdwValidator); -+ extern void -+ sepgsql_fdw_alter(Oid fdwOid, Oid newValidator); -+ extern void -+ sepgsql_fdw_drop(Oid fdwOid); -+ extern void -+ sepgsql_fdw_grant(Oid fdwOid); -+ -+ /* pg_foreign_server */ -+ extern Oid -+ sepgsql_foreign_server_create(const char *fsrvName); -+ extern void -+ sepgsql_foreign_server_alter(Oid fsrvOid); -+ extern void -+ sepgsql_foreign_server_drop(Oid fsrvOid); -+ extern void -+ sepgsql_foreign_server_grant(Oid fsrvOid); -+ -+ /* pg_language */ -+ extern Oid -+ sepgsql_language_create(const char *langName, Oid handlerOid, Oid validatorOid); -+ extern void -+ sepgsql_language_alter(Oid langOid); -+ extern void -+ sepgsql_language_drop(Oid langOid); -+ extern void -+ sepgsql_language_grant(Oid langOid); -+ -+ /* pg_largeobject */ -+ extern Oid -+ sepgsql_largeobject_create(Oid loid, Value *secLabel); -+ extern void -+ sepgsql_largeobject_alter(Oid loid); -+ extern void -+ sepgsql_largeobject_relabel(Oid loid, Value *secLabel); -+ extern void -+ sepgsql_largeobject_drop(Oid loid); -+ extern void -+ sepgsql_largeobject_read(Oid loid, Snapshot snapshot); -+ extern void -+ sepgsql_largeobject_write(Oid loid, Snapshot snapshot); -+ extern void -+ sepgsql_largeobject_export(Oid loid, const char *filename); -+ extern Oid -+ sepgsql_largeobject_import(Oid loid, const char *filename); -+ -+ /* pg_namespace */ -+ extern Oid -+ sepgsql_schema_create(const char *nspName, bool isTemp, DefElem *newLabel); -+ extern void -+ sepgsql_schema_alter(Oid nspOid); -+ extern void -+ sepgsql_schema_drop(Oid nspOid); -+ extern Oid -+ sepgsql_schema_relabel(Oid nspOid, DefElem *newLabel); -+ extern void -+ sepgsql_schema_grant(Oid nspOid); -+ extern bool -+ sepgsql_schema_search(Oid nspOid, bool abort); -+ -+ /* pg_opclass */ -+ extern Oid -+ sepgsql_opclass_create(const char *opcName, Oid nspOid); -+ extern void -+ sepgsql_opclass_alter(Oid opcOid, const char *newName); -+ extern void -+ sepgsql_opclass_drop(Oid opcOid); -+ -+ /* pg_opfamily */ -+ extern Oid -+ sepgsql_opfamily_create(const char *opfName, Oid nspOid); -+ extern void -+ sepgsql_opfamily_alter(Oid opfOid, const char *newName); -+ extern void -+ sepgsql_opfamily_drop(Oid opfOid); -+ extern void -+ sepgsql_opfamily_add_operator(Oid opfOid, Oid operOid); -+ extern void -+ sepgsql_opfamily_add_procedure(Oid opfOid, Oid procOid); -+ -+ /* pg_operator */ -+ extern Oid -+ sepgsql_operator_create(const char *oprName, Oid oprOid, Oid nspOid, -+ Oid codeFn, Oid restFn, Oid joinFn); -+ extern void -+ sepgsql_operator_alter(Oid oprOid); -+ extern void -+ sepgsql_operator_drop(Oid oprOid); -+ -+ /* pg_proc */ -+ extern Oid -+ sepgsql_proc_create(const char *procName, HeapTuple oldTup, -+ Oid nspOid, Oid langOid, DefElem *newLabel); -+ extern void -+ sepgsql_proc_alter(Oid procOid, const char *newName, Oid newNsp); -+ extern void -+ sepgsql_proc_drop(Oid procOid); -+ extern Oid -+ sepgsql_proc_relabel(Oid procOid, DefElem *newLabel); -+ extern void -+ sepgsql_proc_grant(Oid procOid); -+ extern void -+ sepgsql_proc_execute(Oid procOid); -+ extern bool -+ sepgsql_proc_hint_inlined(HeapTuple protup); -+ extern bool -+ sepgsql_proc_entrypoint(HeapTuple protup); -+ extern char * -+ sepgsql_proc_trusted(HeapTuple protup, MemoryContext mcxt); -+ -+ /* pg_rewrite */ -+ extern void -+ sepgsql_rule_create(Oid relOid, const char *ruleName); -+ extern void -+ sepgsql_rule_drop(Oid relOid, const char *ruleName); -+ -+ /* pg_trigger */ -+ extern void -+ sepgsql_trigger_create(Oid relOid, const char *trigName, Oid procOid); -+ extern void -+ sepgsql_trigger_alter(Oid relOid, const char *trigName); -+ extern void -+ sepgsql_trigger_drop(Oid relOid, const char *trigName); -+ -+ /* pg_ts_config */ -+ extern Oid -+ sepgsql_ts_config_create(const char *cfgName, Oid nspOid); -+ extern void -+ sepgsql_ts_config_alter(Oid cfgOid, const char *newName); -+ extern void -+ sepgsql_ts_config_drop(Oid cfgOid); -+ -+ /* pg_ts_dict */ -+ extern Oid -+ sepgsql_ts_dict_create(const char *dictName, Oid nspOid); -+ extern void -+ sepgsql_ts_dict_alter(Oid dictOid, const char *newName); -+ extern void -+ sepgsql_ts_dict_drop(Oid dictOid); -+ -+ /* pg_ts_parser */ -+ extern Oid -+ sepgsql_ts_parser_create(const char *prsName, Oid nspOid, -+ Oid startFn, Oid tokenFn, Oid sendFn, -+ Oid headlineFn, Oid lextypeFn); -+ extern void -+ sepgsql_ts_parser_alter(Oid prsOid, const char *newName); -+ extern void -+ sepgsql_ts_parser_drop(Oid prsOid); -+ -+ /* pg_ts_templace */ -+ extern Oid -+ sepgsql_ts_template_create(const char *tmplName, Oid nspOid, -+ Oid initFn, Oid lexizeFn); -+ extern void -+ sepgsql_ts_template_alter(Oid tmplOid, const char *newName); -+ extern void -+ sepgsql_ts_template_drop(Oid tmplOid); -+ -+ /* pg_type */ -+ extern Oid -+ sepgsql_type_create(const char *typName, HeapTuple oldTup, Oid nspOid, -+ Oid inputProc, Oid outputProc, Oid recvProc, Oid sendProc, -+ Oid modinProc, Oid modoutProc, Oid analyzeProc); -+ extern void -+ sepgsql_type_alter(Oid typOid, const char *newName, Oid newNsp); -+ extern void -+ sepgsql_type_drop(Oid typOid); -+ -+ /* misc objects */ -+ extern void -+ sepgsql_sysobj_drop(const ObjectAddress *object); -+ -+ /* filesystem objects */ -+ void -+ sepgsql_file_stat(const char *filename); -+ void -+ sepgsql_file_read(const char *filename); -+ void -+ sepgsql_file_write(const char *filename); -+ -+ /* -+ * checker.c : check permission on given queries -+ */ -+ extern void -+ sepgsqlCheckRTEPerms(RangeTblEntry *rte); -+ -+ extern void -+ sepgsqlCheckCopyTable(Relation rel, List *attnumlist, bool is_from); -+ -+ extern void -+ sepgsqlCheckSelectInto(Oid relaionId); -+ -+ extern bool -+ sepgsqlExecScan(Relation rel, HeapTuple tuple, uint32 required, bool abort); -+ -+ extern uint32 -+ sepgsqlSetupTuplePerms(RangeTblEntry *rte); -+ -+ extern void -+ sepgsqlHeapTupleInsert(Relation rel, HeapTuple newtup, bool internal); -+ -+ extern void -+ sepgsqlHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup); -+ -+ /* -+ * label.c : security label management -+ */ -+ extern bool sepgsqlTupleDescHasSecid(Oid relid, char relkind); -+ -+ extern void sepgsqlPostBootstrapingMode(void); -+ -+ extern void sepgsqlSetDefaultSecid(Relation rel, HeapTuple tuple); -+ extern sepgsql_sid_t sepgsqlGetDefaultDatabaseSecid(Oid src_database_oid); -+ extern sepgsql_sid_t sepgsqlGetDefaultSchemaSecid(Oid database_oid); -+ extern sepgsql_sid_t sepgsqlGetDefaultSchemaTempSecid(Oid database_oid); -+ extern sepgsql_sid_t sepgsqlGetDefaultTableSecid(Oid namespace_oid); -+ extern sepgsql_sid_t sepgsqlGetDefaultSequenceSecid(Oid namespace_oid); -+ extern sepgsql_sid_t sepgsqlGetDefaultProcedureSecid(Oid namespace_oid); -+ extern sepgsql_sid_t sepgsqlGetDefaultColumnSecid(Oid table_oid); -+ extern sepgsql_sid_t sepgsqlGetDefaultTupleSecid(Oid table_oid); -+ extern sepgsql_sid_t sepgsqlGetDefaultBlobSecid(Oid database_oid); -+ -+ extern Oid *sepgsqlCreateTableColumns(CreateStmt *stmt, -+ const char *relname, Oid namespace_oid, -+ TupleDesc tupdesc, char relkind); -+ extern Oid *sepgsqlCopyTableColumns(Relation source); -+ -+ extern sepgsql_sid_t -+ sepgsqlGetTupleSecid(Oid tableOid, HeapTuple tuple, uint16 *tclass); -+ extern sepgsql_sid_t -+ sepgsqlGetSysobjSecid(Oid tableOid, Oid objectId, int32 objsubId, uint16 *tclass); -+ -+ extern char *sepgsqlTransSecLabelIn(char *seclabel); -+ extern char *sepgsqlTransSecLabelOut(char *seclabel); -+ extern char *sepgsqlRawSecLabelIn(char *seclabel); -+ extern char *sepgsqlRawSecLabelOut(char *seclabel); -+ extern char *sepgsqlSysattSecLabelOut(Oid relid, HeapTuple tuple); -+ -+ #else /* HAVE_SELINUX */ -+ -+ /* avc.c */ -+ #define sepgsqlShmemSize() (0) -+ -+ /* checker.c */ -+ #define sepgsqlCheckRTEPerms(a) do {} while(0) -+ #define sepgsqlCheckCopyTable(a,b,c) do {} while(0) -+ #define sepgsqlCheckSelectInto(a) do {} while(0) -+ #define sepgsqlExecScan(a,b,c) (true) -+ #define sepgsqlSetupTuplePerms(a) (0) -+ #define sepgsqlHeapTupleInsert(a,b,c) do {} while(0) -+ #define sepgsqlHeapTupleUpdate(a,b,c) do {} while(0) -+ -+ /* core.c */ -+ #define sepgsqlIsEnabled() (false) -+ #define sepgsqlInitialize() do {} while(0) -+ -+ /* bridge.c */ -+ #define sepgsql_attribute_create(a,b) (InvalidOid) -+ #define sepgsql_attribute_alter(a,b) do {} while(0) -+ #define sepgsql_attribute_drop(a,b) do {} while(0) -+ #define sepgsql_attribute_grant(a,b) do {} while(0) -+ #define sepgsql_attribute_relabel(a,b,c) (InvalidOid) -+ -+ #define sepgsql_cast_create(a,b,c) (InvalidOid) -+ #define sepgsql_cast_drop(a) (InvalidOid) -+ -+ #define sepgsql_relation_create(a,b,c,d,e,f) (NULL) -+ #define sepgsql_relation_copy(a) (NULL) -+ #define sepgsql_relation_alter(a,b,c) do {} while(0) -+ #define sepgsql_relation_drop(a) do {} while(0) -+ #define sepgsql_relation_grant(a) do {} while(0) -+ #define sepgsql_relation_relabel(a,b) do {} while(0) -+ #define sepgsql_relation_get_transaction_id(a) do {} while(0) -+ #define sepgsql_relation_copy_definition(a) do {} while(0) -+ #define sepgsql_relation_truncate(a) do {} while(0) -+ #define sepgsql_relation_references(a,b,c) do {} while(0) -+ #define sepgsql_relation_lock(a) do {} while(0) -+ #define sepgsql_view_replace(a) do {} while(0) -+ #define sepgsql_index_create(a,b,c) do {} while(0) -+ #define sepgsql_sequence_get_value(a) do {} while(0) -+ #define sepgsql_sequence_next_value(a) do {} while(0) -+ #define sepgsql_sequence_set_value(a) do {} while(0) -+ -+ #define sepgsql_conversion_create(a,b,c) do {} while(0) -+ #define sepgsql_conversion_alter(a,b) do {} while(0) -+ #define sepgsql_conversion_drop(a) do {} while(0) -+ -+ #define sepgsql_database_create(a,b) (InvalidOid) -+ #define sepgsql_database_alter(a) do {} while(0) -+ #define sepgsql_database_drop(a) do {} while(0) -+ #define sepgsql_database_relabel(a,b) (InvalidOid) -+ #define sepgsql_database_grant(a) do {} while(0) -+ #define sepgsql_database_access(a) do {} while(0) -+ #define sepgsql_database_superuser(a) (true) -+ #define sepgsql_database_load_module(a,b) do {} while(0) -+ -+ #define sepgsql_fdw_create(a,b) (InvalidOid) -+ #define sepgsql_fdw_alter(a,b) do {} while(0) -+ #define sepgsql_fdw_drop(a) do {} while(0) -+ #define sepgsql_fdw_grant(a) do {} while(0) -+ -+ #define sepgsql_foreign_server_create(a) (InvalidOid) -+ #define sepgsql_foreign_server_alter(a) do {} while(0) -+ #define sepgsql_foreign_server_drop(a) do {} while(0) -+ #define sepgsql_foreign_server_grant(a) do {} while(0) -+ -+ #define sepgsql_language_create(a,b,c) (InvalidOid) -+ #define sepgsql_language_alter(a) do {} while(0) -+ #define sepgsql_language_drop(a) do {} while(0) -+ #define sepgsql_language_grant(a) do {} while(0) -+ -+ #define sepgsql_largeobject_create(a,b) (InvalidOid) -+ #define sepgsql_largeobject_alter(a,b) do {} while(0) -+ #define sepgsql_largeobject_drop(a) do {} while(0) -+ #define sepgsql_largeobject_read(a) do {} while(0) -+ #define sepgsql_largeobject_write(a) do {} while(0) -+ #define sepgsql_largeobject_export(a,b) do {} while(0) -+ #define sepgsql_largeobject_import(a,b) (InvalidOid) -+ -+ #define sepgsql_schema_create(a,b,c) (InvalidOid) -+ #define sepgsql_schema_alter(a) do {} while(0) -+ #define sepgsql_schema_drop(a) do {} while(0) -+ #define sepgsql_schema_relabel(a,b) (InvalidOid) -+ #define sepgsql_schema_grant(a) do {} while(0) -+ #define sepgsql_schema_search(a,b) (true) -+ -+ #define sepgsql_opclass_create(a,b) (InvalidOid) -+ #define sepgsql_opclass_alter(a,b) do {} while(0) -+ #define sepgsql_opclass_drop(a) do {} while(0) -+ -+ #define sepgsql_opfamily_create(a,b) (InvalidOid) -+ #define sepgsql_opfamily_alter(a,b) do {} while(0) -+ #define sepgsql_opfamily_drop(a) do {} while(0) -+ #define sepgsql_opfamily_add_operator(a,b) do {} while(0) -+ #define sepgsql_opfamily_add_procedure(a,b) do {} while(0) -+ -+ #define sepgsql_operator_create(a,b,c,d,e,f) (InvalidOid) -+ #define sepgsql_operator_alter(a) do {} while(0) -+ #define sepgsql_operator_drop(a) do {} while(0) -+ -+ #define sepgsql_proc_create(a,b,c,d,e) (InvalidOid) -+ #define sepgsql_proc_alter(a,b,c) do {} while(0) -+ #define sepgsql_proc_drop(a) do {} while(0) -+ #define sepgsql_proc_relabel(a,b) (InvalidOid) -+ #define sepgsql_proc_grant(a) do {} while(0) -+ #define sepgsql_proc_execute(a) do {} while(0) -+ #define sepgsql_proc_hint_inlined(a) (true) -+ #define sepgsql_proc_entrypoint(a,b) do {} while(0) -+ -+ #define sepgsql_rule_create(a,b) do {} while(0) -+ #define sepgsql_rule_drop(a,b) do {} while(0) -+ -+ #define sepgsql_trigger_create(a,b,c) do {} while(0) -+ #define sepgsql_trigger_alter(a,b) do {} while(0) -+ #define sepgsql_trigger_drop(a,b) do {} while(0) -+ -+ #define sepgsql_ts_config_create(a,b) (InvalidOid) -+ #define sepgsql_ts_config_alter(a,b) do {} while(0) -+ #define sepgsql_ts_config_drop(a) do {} while(0) -+ -+ #define sepgsql_ts_config_create(a,b) (InvalidOid) -+ #define sepgsql_ts_config_alter(a,b) do {} while(0) -+ #define sepgsql_ts_config_drop(a) do {} while(0) -+ -+ #define sepgsql_ts_dict_create(a,b) (InvalidOid) -+ #define sepgsql_ts_dict_alter(a,b) do {} while(0) -+ #define sepgsql_ts_dict_drop(a) do {} while(0) -+ -+ #define sepgsql_ts_parser_create(a,b,c,d,e,f,g) (InvalidOid) -+ #define sepgsql_ts_parser_alter(a,b) do {} while(0) -+ #define sepgsql_ts_parser_drop(a) do {} while(0) -+ -+ #define sepgsql_ts_template_create(a,b,c,d) (InvalidOid) -+ #define sepgsql_ts_template_alter(a,b) do {} while(0) -+ #define sepgsql_ts_template_drop(a) do {} while(0) -+ -+ #define sepgsql_type_create(a,b,c,d,e,f,g,h,i,j) (InvalidOid) -+ #define sepgsql_type_alter(a,b,c) do {} while(0) -+ #define sepgsql_type_drop(a) do {} while(0) -+ -+ #define sepgsql_sysobj_drop(a) do {} while(0) -+ -+ #define sepgsql_file_stat(a) do {} while(0) -+ #define sepgsql_file_read(a) do {} while(0) -+ #define sepgsql_file_write(a) do {} while(0) -+ -+ /* label.c */ -+ #define sepgsqlTupleDescHasSecLabel(a,b) (false) -+ #define sepgsqlSetDefaultSecLabel(a,b) do {} while(0) -+ #define sepgsqlTransSecLabelIn(a) (a) -+ #define sepgsqlTransSecLabelOut(a) (a) -+ #define sepgsqlRawSecLabelIn(a) (a) -+ #define sepgsqlRawSecLabelOut(a) (a) -+ -+ #endif /* HAVE_SELINUX */ -+ -+ extern Datum sepgsql_getcon(PG_FUNCTION_ARGS); -+ extern Datum sepgsql_server_getcon(PG_FUNCTION_ARGS); -+ extern Datum sepgsql_get_user(PG_FUNCTION_ARGS); -+ extern Datum sepgsql_get_role(PG_FUNCTION_ARGS); -+ extern Datum sepgsql_get_type(PG_FUNCTION_ARGS); -+ extern Datum sepgsql_get_range(PG_FUNCTION_ARGS); -+ extern Datum sepgsql_set_user(PG_FUNCTION_ARGS); -+ extern Datum sepgsql_set_role(PG_FUNCTION_ARGS); -+ extern Datum sepgsql_set_type(PG_FUNCTION_ARGS); -+ extern Datum sepgsql_set_range(PG_FUNCTION_ARGS); -+ -+ #endif /* SEPGSQL_H */ -diff -Nrpc blob/src/include/storage/fd.h sepgsql/src/include/storage/fd.h -*** blob/src/include/storage/fd.h Tue Jan 13 09:22:28 2009 ---- sepgsql/src/include/storage/fd.h Wed Jul 15 19:48:58 2009 -*************** extern int FileWrite(File file, char *bu -*** 68,73 **** ---- 68,74 ---- - extern int FileSync(File file); - extern off_t FileSeek(File file, off_t offset, int whence); - extern int FileTruncate(File file, off_t offset); -+ extern int FileRawDescriptor(File file); - - /* Operations that allow use of regular stdio --- USE WITH CAUTION */ - extern FILE *AllocateFile(const char *name, const char *mode); -diff -Nrpc blob/src/include/storage/large_object.h sepgsql/src/include/storage/large_object.h -*** blob/src/include/storage/large_object.h Sat Jan 3 12:25:21 2009 ---- sepgsql/src/include/storage/large_object.h Fri Dec 18 10:27:56 2009 -*************** typedef struct LargeObjectDesc -*** 70,76 **** - - /* inversion stuff in inv_api.c */ - extern void close_lo_relation(bool isCommit); -! extern Oid inv_create(Oid lobjId); - extern LargeObjectDesc *inv_open(Oid lobjId, int flags, MemoryContext mcxt); - extern void inv_close(LargeObjectDesc *obj_desc); - extern int inv_drop(Oid lobjId); ---- 70,76 ---- - - /* inversion stuff in inv_api.c */ - extern void close_lo_relation(bool isCommit); -! extern Oid inv_create(Oid lobjId, Oid secid); - extern LargeObjectDesc *inv_open(Oid lobjId, int flags, MemoryContext mcxt); - extern void inv_close(LargeObjectDesc *obj_desc); - extern int inv_drop(Oid lobjId); -diff -Nrpc blob/src/include/storage/lwlock.h sepgsql/src/include/storage/lwlock.h -*** blob/src/include/storage/lwlock.h Fri Mar 6 09:45:33 2009 ---- sepgsql/src/include/storage/lwlock.h Wed Jul 15 19:35:52 2009 -*************** typedef enum LWLockId -*** 67,72 **** ---- 67,73 ---- - AutovacuumLock, - AutovacuumScheduleLock, - SyncScanLock, -+ SepgsqlAvcLock, - /* Individual lock IDs end here */ - FirstBufMappingLock, - FirstLockMgrLock = FirstBufMappingLock + NUM_BUFFER_PARTITIONS, -diff -Nrpc blob/src/include/storage/proc.h sepgsql/src/include/storage/proc.h -*** blob/src/include/storage/proc.h Thu Feb 26 10:18:55 2009 ---- sepgsql/src/include/storage/proc.h Tue Dec 8 14:04:25 2009 -*************** typedef struct PROC_HDR -*** 143,150 **** - * normal operation. Startup process also consumes one slot, but WAL - * writer and autovacuum launcher are launched only after it has - * exited. - */ -! #define NUM_AUXILIARY_PROCS 3 - - - /* configurable options */ ---- 143,152 ---- - * normal operation. Startup process also consumes one slot, but WAL - * writer and autovacuum launcher are launched only after it has - * exited. -+ * In addition, a netlink receiver process may be launched, if SELinux -+ * support is enabled. - */ -! #define NUM_AUXILIARY_PROCS 4 - - - /* configurable options */ -diff -Nrpc blob/src/include/utils/errcodes.h sepgsql/src/include/utils/errcodes.h -*** blob/src/include/utils/errcodes.h Fri Mar 6 09:45:33 2009 ---- sepgsql/src/include/utils/errcodes.h Sun Dec 20 00:41:22 2009 -*************** -*** 301,306 **** ---- 301,307 ---- - #define ERRCODE_INVALID_SCHEMA_DEFINITION MAKE_SQLSTATE('4','2', 'P','1','5') - #define ERRCODE_INVALID_TABLE_DEFINITION MAKE_SQLSTATE('4','2', 'P','1','6') - #define ERRCODE_INVALID_OBJECT_DEFINITION MAKE_SQLSTATE('4','2', 'P','1','7') -+ #define ERRCODE_INVALID_SECURITY_LABEL MAKE_SQLSTATE('4','2', 'P','9','9') - - /* Class 44 - WITH CHECK OPTION Violation */ - #define ERRCODE_WITH_CHECK_OPTION_VIOLATION MAKE_SQLSTATE('4','4', '0','0','0') -diff -Nrpc blob/src/test/regress/GNUmakefile sepgsql/src/test/regress/GNUmakefile -*** blob/src/test/regress/GNUmakefile Sat Jan 3 13:01:35 2009 ---- sepgsql/src/test/regress/GNUmakefile Tue Dec 1 17:11:40 2009 -*************** ifdef NO_LOCALE -*** 38,43 **** ---- 38,49 ---- - NOLOCALE += --no-locale - endif - -+ # SELinux support -+ ENABLE_SELINUX = -+ ifdef SELINUX -+ ENABLE_SELINUX += --enable-selinux -+ endif -+ - # stuff to pass into build of pg_regress - EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \ - '-DMAKEPROG="$(MAKE)"' \ -*************** tablespace-setup: -*** 138,144 **** - ## Run tests - ## - -! pg_regress_call = ./pg_regress --inputdir=$(srcdir) --dlpath=. --multibyte=$(MULTIBYTE) --load-language=plpgsql $(NOLOCALE) - - check: all - $(pg_regress_call) --temp-install=./tmp_check --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule $(MAXCONNOPT) $(TEMP_CONF) ---- 144,150 ---- - ## Run tests - ## - -! pg_regress_call = ./pg_regress --inputdir=$(srcdir) --dlpath=. --multibyte=$(MULTIBYTE) --load-language=plpgsql $(NOLOCALE) $(ENABLE_SELINUX) - - check: all - $(pg_regress_call) --temp-install=./tmp_check --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule $(MAXCONNOPT) $(TEMP_CONF) -diff -Nrpc blob/src/test/regress/expected/sanity_check.out sepgsql/src/test/regress/expected/sanity_check.out -*** blob/src/test/regress/expected/sanity_check.out Fri Dec 18 09:40:55 2009 ---- sepgsql/src/test/regress/expected/sanity_check.out Fri Dec 18 10:27:56 2009 -*************** SELECT relname, relhasindex -*** 113,118 **** ---- 113,119 ---- - pg_pltemplate | t - pg_proc | t - pg_rewrite | t -+ pg_security | t - pg_shdepend | t - pg_shdescription | t - pg_statistic | t -diff -Nrpc blob/src/test/regress/pg_regress.c sepgsql/src/test/regress/pg_regress.c -*** blob/src/test/regress/pg_regress.c Tue Dec 15 17:16:51 2009 ---- sepgsql/src/test/regress/pg_regress.c Tue Dec 15 17:30:25 2009 -*************** static _stringlist *schedulelist = NULL; -*** 82,87 **** ---- 82,88 ---- - static _stringlist *extra_tests = NULL; - static char *temp_install = NULL; - static char *temp_config = NULL; -+ static bool enable_selinux = false; - static char *top_builddir = NULL; - static bool nolocale = false; - static char *hostname = NULL; -*************** help(void) -*** 1863,1868 **** ---- 1864,1870 ---- - printf(_(" --top-builddir=DIR (relative) path to top level build directory\n")); - printf(_(" --port=PORT start postmaster on PORT\n")); - printf(_(" --temp-config=PATH append contents of PATH to temporary config\n")); -+ printf(_(" --enable-selinux enables SELinux support, if available\n")); - printf(_("\n")); - printf(_("Options for using an existing installation:\n")); - printf(_(" --host=HOST use postmaster running on HOST\n")); -*************** regression_main(int argc, char *argv[], -*** 1907,1912 **** ---- 1909,1915 ---- - {"dlpath", required_argument, NULL, 17}, - {"create-role", required_argument, NULL, 18}, - {"temp-config", required_argument, NULL, 19}, -+ {"enable-selinux", optional_argument, NULL, 20}, - {NULL, 0, NULL, 0} - }; - -*************** regression_main(int argc, char *argv[], -*** 1997,2002 **** ---- 2000,2008 ---- - case 19: - temp_config = strdup(optarg); - break; -+ case 20: -+ enable_selinux = true; -+ break; - default: - /* getopt_long already emitted a complaint */ - fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"), -*************** regression_main(int argc, char *argv[], -*** 2086,2095 **** - /* initdb */ - header(_("initializing database system")); - snprintf(buf, sizeof(buf), -! SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE, - bindir, temp_install, datadir, - debug ? " --debug" : "", - nolocale ? " --no-locale" : "", - outputdir); - if (system(buf)) - { ---- 2092,2102 ---- - /* initdb */ - header(_("initializing database system")); - snprintf(buf, sizeof(buf), -! SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE, - bindir, temp_install, datadir, - debug ? " --debug" : "", - nolocale ? " --no-locale" : "", -+ enable_selinux ? " --enable-selinux" : "", - outputdir); - if (system(buf)) - { diff --git a/sepostgresql-9.0-fullset.patch b/sepostgresql-9.0-fullset.patch new file mode 100644 index 0000000..37109a4 --- /dev/null +++ b/sepostgresql-9.0-fullset.patch @@ -0,0 +1,19003 @@ +diff --git a/configure b/configure +index 7e34c4f..7bfa5ff 100755 +--- a/configure ++++ b/configure +@@ -707,6 +707,7 @@ LDFLAGS_SL + ELF_SYS + EGREP + GREP ++enable_selinux + with_zlib + with_system_tzdata + with_libxslt +@@ -842,6 +843,7 @@ with_libxml + with_libxslt + with_system_tzdata + with_zlib ++enable_selinux + with_gnu_ld + enable_largefile + enable_float4_byval +@@ -1498,6 +1500,7 @@ Optional Features: + --enable-depend turn on automatic dependency tracking + --enable-cassert enable assertion checks (for debugging) + --disable-thread-safety disable thread-safety in client libraries ++ --enable-selinux build with SELinux support + --disable-largefile omit support for large files + --disable-float4-byval disable float4 passed by value + --disable-float8-byval disable float8 passed by value +@@ -5608,6 +5611,201 @@ fi + + + # ++# SELinux support ++# ++ ++ ++# Check whether --enable-selinux was given. ++if test "${enable_selinux+set}" = set; then ++ enableval=$enable_selinux; ++ case $enableval in ++ yes) ++ : ++ ;; ++ no) ++ : ++ ;; ++ *) ++ { { $as_echo "$as_me:$LINENO: error: no argument expected for --enable-selinux option" >&5 ++$as_echo "$as_me: error: no argument expected for --enable-selinux option" >&2;} ++ { (exit 1); exit 1; }; } ++ ;; ++ esac ++ ++else ++ enable_selinux=no ++ ++fi ++ ++ ++if test "$enable_selinux" = yes; then ++ ++{ $as_echo "$as_me:$LINENO: checking for avc_open in -lselinux" >&5 ++$as_echo_n "checking for avc_open in -lselinux... " >&6; } ++if test "${ac_cv_lib_selinux_avc_open+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lselinux $LIBS" ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char avc_open (); ++int ++main () ++{ ++return avc_open (); ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext conftest$ac_exeext ++if { (ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest$ac_exeext && { ++ test "$cross_compiling" = yes || ++ $as_test_x conftest$ac_exeext ++ }; then ++ ac_cv_lib_selinux_avc_open=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_lib_selinux_avc_open=no ++fi ++ ++rm -rf conftest.dSYM ++rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_avc_open" >&5 ++$as_echo "$ac_cv_lib_selinux_avc_open" >&6; } ++if test "x$ac_cv_lib_selinux_avc_open" = x""yes; then ++ cat >>confdefs.h <<_ACEOF ++#define HAVE_LIBSELINUX 1 ++_ACEOF ++ ++ LIBS="-lselinux $LIBS" ++ ++else ++ { { $as_echo "$as_me:$LINENO: error: \"SELinux support requires libselinux.\"" >&5 ++$as_echo "$as_me: error: \"SELinux support requires libselinux.\"" >&2;} ++ { (exit 1); exit 1; }; } ++fi ++ ++ ++{ $as_echo "$as_me:$LINENO: checking for audit_open in -laudit" >&5 ++$as_echo_n "checking for audit_open in -laudit... " >&6; } ++if test "${ac_cv_lib_audit_audit_open+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-laudit $LIBS" ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char audit_open (); ++int ++main () ++{ ++return audit_open (); ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext conftest$ac_exeext ++if { (ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest$ac_exeext && { ++ test "$cross_compiling" = yes || ++ $as_test_x conftest$ac_exeext ++ }; then ++ ac_cv_lib_audit_audit_open=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_lib_audit_audit_open=no ++fi ++ ++rm -rf conftest.dSYM ++rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_audit_audit_open" >&5 ++$as_echo "$ac_cv_lib_audit_audit_open" >&6; } ++if test "x$ac_cv_lib_audit_audit_open" = x""yes; then ++ cat >>confdefs.h <<_ACEOF ++#define HAVE_LIBAUDIT 1 ++_ACEOF ++ ++ LIBS="-laudit $LIBS" ++ ++else ++ { { $as_echo "$as_me:$LINENO: error: \"SELinux support requires libaudit.\"" >&5 ++$as_echo "$as_me: error: \"SELinux support requires libaudit.\"" >&2;} ++ { (exit 1); exit 1; }; } ++fi ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define HAVE_SELINUX 1 ++_ACEOF ++ ++ ++fi ++ ++# + # Elf + # + +diff --git a/configure.in b/configure.in +index bbeea97..e499e10 100644 +--- a/configure.in ++++ b/configure.in +@@ -755,6 +755,19 @@ PGAC_ARG_BOOL(with, zlib, yes, + AC_SUBST(with_zlib) + + # ++# SELinux support ++# ++PGAC_ARG_BOOL(enable, selinux, no, [build with SELinux support]) ++if test "$enable_selinux" = yes; then ++ AC_CHECK_LIB(selinux, avc_open,, ++ AC_MSG_ERROR("SELinux support requires libselinux.")) ++ AC_CHECK_LIB(audit, audit_open,, ++ AC_MSG_ERROR("SELinux support requires libaudit.")) ++ AC_DEFINE_UNQUOTED(HAVE_SELINUX, 1, [SE-PostgreSQL feature is enabled]) ++ AC_SUBST(enable_selinux) ++fi ++ ++# + # Elf + # + +diff --git a/src/Makefile.global.in b/src/Makefile.global.in +index 1c38ac2..0e3bed5 100644 +--- a/src/Makefile.global.in ++++ b/src/Makefile.global.in +@@ -164,6 +164,7 @@ enable_nls = @enable_nls@ + enable_debug = @enable_debug@ + enable_dtrace = @enable_dtrace@ + enable_coverage = @enable_coverage@ ++enable_selinux = @enable_selinux@ + enable_thread_safety = @enable_thread_safety@ + + python_includespec = @python_includespec@ +diff --git a/src/backend/Makefile b/src/backend/Makefile +index 218544e..0b1dd31 100644 +--- a/src/backend/Makefile ++++ b/src/backend/Makefile +@@ -16,7 +16,7 @@ include $(top_builddir)/src/Makefile.global + + SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \ + main nodes optimizer port postmaster regex replication rewrite \ +- storage tcop tsearch utils $(top_builddir)/src/timezone ++ sepgsql storage tcop tsearch utils $(top_builddir)/src/timezone + + include $(srcdir)/common.mk + +@@ -40,6 +40,11 @@ LIBS := $(filter-out -lpgport, $(LIBS)) $(LDAP_LIBS_BE) + # The backend doesn't need everything that's in LIBS, however + LIBS := $(filter-out -lz -lreadline -ledit -ltermcap -lncurses -lcurses, $(LIBS)) + ++# SELinux needs libselinux and libaudit ++ifeq ($(enable_selinux), yes) ++LIBS := $(filter-out -lselinux -laudit, $(LIBS)) -lselinux -laudit ++endif ++ + ########################################################################## + + all: submake-libpgport submake-schemapg postgres $(POSTGRES_IMP) +diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c +index 6ec73f0..db0023f 100644 +--- a/src/backend/access/common/heaptuple.c ++++ b/src/backend/access/common/heaptuple.c +@@ -60,6 +60,7 @@ + #include "access/heapam.h" + #include "access/sysattr.h" + #include "access/tuptoaster.h" ++#include "catalog/pg_seclabel.h" + #include "executor/tuptable.h" + + +@@ -559,6 +560,9 @@ heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull) + case TableOidAttributeNumber: + result = ObjectIdGetDatum(tup->t_tableOid); + break; ++ case SecurityLabelAttributeNumber: ++ result = seclabelSysattOutput(tup->t_tableOid, tup); ++ break; + default: + elog(ERROR, "invalid attnum: %d", attnum); + result = 0; /* keep compiler quiet */ +@@ -682,6 +686,8 @@ heap_form_tuple(TupleDesc tupleDescriptor, + + if (tupleDescriptor->tdhasoid) + len += sizeof(Oid); ++ if (tupleDescriptor->tdhassecid) ++ len += sizeof(Oid)+1; + + hoff = len = MAXALIGN(len); /* align user data safely */ + +@@ -713,6 +719,8 @@ heap_form_tuple(TupleDesc tupleDescriptor, + + if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ + td->t_infomask = HEAP_HASOID; ++ if (tupleDescriptor->tdhassecid) ++ td->t_infomask |= HEAP_HASSECID; + + heap_fill_tuple(tupleDescriptor, + values, +@@ -824,6 +832,8 @@ heap_modify_tuple(HeapTuple tuple, + newTuple->t_tableOid = tuple->t_tableOid; + if (tupleDesc->tdhasoid) + HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple)); ++ if (tupleDesc->tdhassecid) ++ HeapTupleSetSecid(newTuple, HeapTupleGetSecid(tuple)); + + return newTuple; + } +@@ -1434,6 +1444,8 @@ heap_form_minimal_tuple(TupleDesc tupleDescriptor, + + if (tupleDescriptor->tdhasoid) + len += sizeof(Oid); ++ if (tupleDescriptor->tdhassecid) ++ len += sizeof(Oid); + + hoff = len = MAXALIGN(len); /* align user data safely */ + +@@ -1455,6 +1467,8 @@ heap_form_minimal_tuple(TupleDesc tupleDescriptor, + + if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ + tuple->t_infomask = HEAP_HASOID; ++ if (tupleDescriptor->tdhassecid) ++ tuple->t_infomask |= HEAP_HASSECID; + + heap_fill_tuple(tupleDescriptor, + values, +diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c +index 9a8611f..325dbde 100644 +--- a/src/backend/access/common/tupdesc.c ++++ b/src/backend/access/common/tupdesc.c +@@ -34,7 +34,7 @@ + * caller can overwrite this if needed. + */ + TupleDesc +-CreateTemplateTupleDesc(int natts, bool hasoid) ++CreateTemplateTupleDesc(int natts, bool hasoid, bool hassecid) + { + TupleDesc desc; + char *stg; +@@ -88,6 +88,7 @@ CreateTemplateTupleDesc(int natts, bool hasoid) + desc->tdtypeid = RECORDOID; + desc->tdtypmod = -1; + desc->tdhasoid = hasoid; ++ desc->tdhassecid = hassecid; + desc->tdrefcount = -1; /* assume not reference-counted */ + + return desc; +@@ -105,7 +106,8 @@ CreateTemplateTupleDesc(int natts, bool hasoid) + * caller can overwrite this if needed. + */ + TupleDesc +-CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs) ++CreateTupleDesc(int natts, bool hasoid, bool hassecid, ++ Form_pg_attribute *attrs) + { + TupleDesc desc; + +@@ -121,6 +123,7 @@ CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs) + desc->tdtypeid = RECORDOID; + desc->tdtypmod = -1; + desc->tdhasoid = hasoid; ++ desc->tdhassecid = hassecid; + desc->tdrefcount = -1; /* assume not reference-counted */ + + return desc; +@@ -139,7 +142,8 @@ CreateTupleDescCopy(TupleDesc tupdesc) + TupleDesc desc; + int i; + +- desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid); ++ desc = CreateTemplateTupleDesc(tupdesc->natts, ++ tupdesc->tdhasoid, tupdesc->tdhassecid); + + for (i = 0; i < desc->natts; i++) + { +@@ -150,6 +154,7 @@ CreateTupleDescCopy(TupleDesc tupdesc) + + desc->tdtypeid = tupdesc->tdtypeid; + desc->tdtypmod = tupdesc->tdtypmod; ++ desc->tdhassecid = tupdesc->tdhassecid; + + return desc; + } +@@ -166,7 +171,8 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) + TupleConstr *constr = tupdesc->constr; + int i; + +- desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid); ++ desc = CreateTemplateTupleDesc(tupdesc->natts, ++ tupdesc->tdhasoid, tupdesc->tdhassecid); + + for (i = 0; i < desc->natts; i++) + { +@@ -314,6 +320,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) + return false; + if (tupdesc1->tdhasoid != tupdesc2->tdhasoid) + return false; ++ if (tupdesc1->tdhassecid != tupdesc2->tdhassecid) ++ return false; + + for (i = 0; i < tupdesc1->natts; i++) + { +@@ -519,7 +527,7 @@ BuildDescForRelation(List *schema) + * allocate a new tuple descriptor + */ + natts = list_length(schema); +- desc = CreateTemplateTupleDesc(natts, false); ++ desc = CreateTemplateTupleDesc(natts, false, false); + has_not_null = false; + + attnum = 0; +@@ -604,7 +612,7 @@ BuildDescFromLists(List *names, List *types, List *typmods) + /* + * allocate a new tuple descriptor + */ +- desc = CreateTemplateTupleDesc(natts, false); ++ desc = CreateTemplateTupleDesc(natts, false, false); + + attnum = 0; + +diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c +index f01ed1e..4e8dfcb 100644 +--- a/src/backend/access/gin/ginutil.c ++++ b/src/backend/access/gin/ginutil.c +@@ -33,7 +33,7 @@ initGinState(GinState *state, Relation index) + + for (i = 0; i < index->rd_att->natts; i++) + { +- state->tupdesc[i] = CreateTemplateTupleDesc(2, false); ++ state->tupdesc[i] = CreateTemplateTupleDesc(2, false, false); + + TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 1, NULL, + INT2OID, -1, 0); +diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c +index bb57cb9..d17274f 100644 +--- a/src/backend/access/heap/heapam.c ++++ b/src/backend/access/heap/heapam.c +@@ -52,6 +52,7 @@ + #include "access/xlogutils.h" + #include "catalog/catalog.h" + #include "catalog/namespace.h" ++#include "catalog/pg_seclabel.h" + #include "miscadmin.h" + #include "pgstat.h" + #include "storage/bufmgr.h" +@@ -1862,6 +1863,22 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, + Assert(!(tup->t_data->t_infomask & HEAP_HASOID)); + } + ++ /* ++ * If this tuple has a capability to store its security id, but it has ++ * not been assigned yet, the default security id should be assigned. ++ * Note that this step does not apply any permission checks. All the ++ * caller of heap_insert() is trusted. ++ */ ++ if (relation->rd_rel->relhassecids) ++ { ++ if (!OidIsValid(HeapTupleGetSecid(tup))) ++ HeapTupleSetSecid(tup, seclabelGetNewSecid(relation, tup)); ++ } ++ else ++ { ++ Assert(!HeapTupleHasSecid(tup)); ++ } ++ + tup->t_data->t_infomask &= ~(HEAP_XACT_MASK); + tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK); + tup->t_data->t_infomask |= HEAP_XMAX_INVALID; +@@ -2560,6 +2577,20 @@ l2: + Assert(!(newtup->t_data->t_infomask & HEAP_HASOID)); + } + ++ /* ++ * Preserve security-id, if not changed ++ */ ++ if (relation->rd_rel->relhassecids) ++ { ++ if (!OidIsValid(HeapTupleGetSecid(newtup))) ++ HeapTupleSetSecid(newtup, HeapTupleGetSecid(&oldtup)); ++ } ++ else ++ { ++ /* check there is not space for a security-id */ ++ Assert(!HeapTupleHasSecid(newtup)); ++ } ++ + newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK); + newtup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK); + newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED); +@@ -3501,6 +3532,10 @@ heap_inplace_update(Relation relation, HeapTuple tuple) + memcpy((char *) htup + htup->t_hoff, + (char *) tuple->t_data + tuple->t_data->t_hoff, + newlen); ++ if (HeapTupleHeaderHasOid(htup)) ++ HeapTupleHeaderSetOid(htup, HeapTupleGetOid(tuple)); ++ if (HeapTupleHeaderHasSecid(htup)) ++ HeapTupleHeaderSetSecid(htup, HeapTupleGetSecid(tuple)); + + MarkBufferDirty(buffer); + +diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c +index 2af81df..18341f4 100644 +--- a/src/backend/access/heap/tuptoaster.c ++++ b/src/backend/access/heap/tuptoaster.c +@@ -591,6 +591,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, + hoff += BITMAPLEN(numAttrs); + if (newtup->t_data->t_infomask & HEAP_HASOID) + hoff += sizeof(Oid); ++ if (HeapTupleHasSecid(newtup)) ++ hoff += sizeof(Oid); + hoff = MAXALIGN(hoff); + Assert(hoff == newtup->t_data->t_hoff); + /* now convert to a limit on the tuple data size */ +@@ -868,6 +870,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, + new_len += BITMAPLEN(numAttrs); + if (olddata->t_infomask & HEAP_HASOID) + new_len += sizeof(Oid); ++ if (HeapTupleHeaderHasSecid(olddata)) ++ new_len += sizeof(Oid); + new_len = MAXALIGN(new_len); + Assert(new_len == olddata->t_hoff); + new_data_len = heap_compute_data_size(tupleDesc, +@@ -1019,6 +1023,8 @@ toast_flatten_tuple_attribute(Datum value, + new_len += BITMAPLEN(numAttrs); + if (olddata->t_infomask & HEAP_HASOID) + new_len += sizeof(Oid); ++ if (HeapTupleHeaderHasSecid(olddata)) ++ new_len += sizeof(Oid); + new_len = MAXALIGN(new_len); + Assert(new_len == olddata->t_hoff); + new_data_len = heap_compute_data_size(tupleDesc, +diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c +index e2566a4..c21054b 100644 +--- a/src/backend/access/transam/twophase.c ++++ b/src/backend/access/transam/twophase.c +@@ -605,7 +605,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS) + + /* build tupdesc for result tuples */ + /* this had better match pg_prepared_xacts view in system_views.sql */ +- tupdesc = CreateTemplateTupleDesc(5, false); ++ tupdesc = CreateTemplateTupleDesc(5, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "transaction", + XIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "gid", +diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c +index b88cff2..d6636f7 100644 +--- a/src/backend/access/transam/xact.c ++++ b/src/backend/access/transam/xact.c +@@ -36,6 +36,7 @@ + #include "libpq/be-fsstubs.h" + #include "miscadmin.h" + #include "pgstat.h" ++#include "sepgsql/hooks.h" + #include "storage/bufmgr.h" + #include "storage/fd.h" + #include "storage/lmgr.h" +@@ -140,6 +141,8 @@ typedef struct TransactionStateData + int maxChildXids; /* allocated size of childXids[] */ + Oid prevUser; /* previous CurrentUserId setting */ + int prevSecContext; /* previous SecurityRestrictionContext */ ++ char *prevSecLabel; /* previous security label of client */ ++ int prevRowlvMode; /* previous row-level access control mode */ + bool prevXactReadOnly; /* entry-time xact r/o state */ + bool startedInRecovery; /* did we start in recovery? */ + struct TransactionStateData *parent; /* back link to parent */ +@@ -169,6 +172,8 @@ static TransactionStateData TopTransactionStateData = { + 0, /* allocated size of childXids[] */ + InvalidOid, /* previous CurrentUserId setting */ + 0, /* previous SecurityRestrictionContext */ ++ NULL, /* previous security label of the client */ ++ 0, /* previous row-level access control mode */ + false, /* entry-time xact r/o state */ + false, /* startedInRecovery */ + NULL /* link to parent state block */ +@@ -1658,6 +1663,10 @@ StartTransaction(void) + /* SecurityRestrictionContext should never be set outside a transaction */ + Assert(s->prevSecContext == 0); + ++ /* Save status of SELinux */ ++ s->prevSecLabel = sepgsql_get_client_label(); ++ s->prevRowlvMode = sepgsql_rowlv_get_mode(); ++ + /* + * initialize other subsystems for new transaction + */ +@@ -2162,6 +2171,10 @@ AbortTransaction(void) + */ + SetUserIdAndSecContext(s->prevUser, s->prevSecContext); + ++ /* Reset SELinux status */ ++ sepgsql_set_client_label(s->prevSecLabel); ++ sepgsql_rowlv_set_mode(s->prevRowlvMode); ++ + /* + * do abort processing + */ +@@ -4006,6 +4019,10 @@ AbortSubTransaction(void) + */ + SetUserIdAndSecContext(s->prevUser, s->prevSecContext); + ++ /* Reset SELinux status */ ++ sepgsql_set_client_label(s->prevSecLabel); ++ sepgsql_rowlv_set_mode(s->prevRowlvMode); ++ + /* + * We can skip all this stuff if the subxact failed before creating a + * ResourceOwner... +@@ -4145,6 +4162,8 @@ PushTransaction(void) + s->state = TRANS_DEFAULT; + s->blockState = TBLOCK_SUBBEGIN; + GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext); ++ s->prevSecLabel = sepgsql_get_client_label(); ++ s->prevRowlvMode = sepgsql_rowlv_get_mode(); + s->prevXactReadOnly = XactReadOnly; + + CurrentTransactionState = s; +diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c +index abdf4d8..1b5b84c 100644 +--- a/src/backend/access/transam/xlog.c ++++ b/src/backend/access/transam/xlog.c +@@ -8427,7 +8427,7 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS) + * Construct a tuple descriptor for the result row. This must match this + * function's pg_proc entry! + */ +- resultTupleDesc = CreateTemplateTupleDesc(2, false); ++ resultTupleDesc = CreateTemplateTupleDesc(2, false, false); + TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "file_name", + TEXTOID, -1, 0); + TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "file_offset", +diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y +index 387d43e..aecb449 100644 +--- a/src/backend/bootstrap/bootparse.y ++++ b/src/backend/bootstrap/bootparse.y +@@ -32,6 +32,7 @@ + #include "catalog/pg_authid.h" + #include "catalog/pg_class.h" + #include "catalog/pg_namespace.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/pg_tablespace.h" + #include "catalog/toasting.h" + #include "commands/defrem.h" +@@ -187,10 +188,11 @@ Boot_CreateStmt: + TupleDesc tupdesc; + bool shared_relation; + bool mapped_relation; ++ bool hassecid = seclabelCatalogHasSysAttr($3); + + do_start(); + +- tupdesc = CreateTupleDesc(numattr, !($6), attrtypes); ++ tupdesc = CreateTupleDesc(numattr, !($6), hassecid, attrtypes); + + shared_relation = $5; + +@@ -245,7 +247,8 @@ Boot_CreateStmt: + ONCOMMIT_NOOP, + (Datum) 0, + false, +- true); ++ true, ++ NULL); + elog(DEBUG4, "relation created with oid %u", id); + } + do_end(); +diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c +index 46e8bae..5f8c824 100644 +--- a/src/backend/bootstrap/bootstrap.c ++++ b/src/backend/bootstrap/bootstrap.c +@@ -33,6 +33,7 @@ + #include "postmaster/bgwriter.h" + #include "postmaster/walwriter.h" + #include "replication/walreceiver.h" ++#include "sepgsql/hooks.h" + #include "storage/bufmgr.h" + #include "storage/ipc.h" + #include "storage/proc.h" +@@ -319,6 +320,9 @@ AuxiliaryProcessMain(int argc, char *argv[]) + case WalReceiverProcess: + statmsg = "wal receiver process"; + break; ++ case SecurityWorkerProcess: ++ statmsg = "security worker process"; ++ break; + default: + statmsg = "??? process"; + break; +@@ -429,6 +433,10 @@ AuxiliaryProcessMain(int argc, char *argv[]) + WalReceiverMain(); + proc_exit(1); /* should never return */ + ++ case SecurityWorkerProcess: ++ sepgsql_worker_main(); ++ proc_exit(1); /* should never return */ ++ + default: + elog(PANIC, "unrecognized process type: %d", auxType); + proc_exit(1); +@@ -493,6 +501,11 @@ BootstrapModeMain(void) + boot_yyparse(); + + /* ++ * Initial security labeling ++ */ ++ sepgsql_post_bootstraping(); ++ ++ /* + * We should now know about all mapped relations, so it's okay to write + * out the initial relation mapping files. + */ +@@ -794,6 +807,7 @@ InsertOneTuple(Oid objectid) + + tupDesc = CreateTupleDesc(numattr, + RelationGetForm(boot_reldesc)->relhasoids, ++ RelationGetForm(boot_reldesc)->relhassecids, + attrtypes); + tuple = heap_form_tuple(tupDesc, values, Nulls); + if (objectid != (Oid) 0) +diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile +index dafae3f..c2aea7a 100644 +--- a/src/backend/catalog/Makefile ++++ b/src/backend/catalog/Makefile +@@ -13,7 +13,7 @@ include $(top_builddir)/src/Makefile.global + OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \ + pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \ + pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \ +- pg_db_role_setting.o pg_shdepend.o pg_type.o storage.o toasting.o ++ pg_db_role_setting.o pg_seclabel.o pg_shdepend.o pg_type.o storage.o toasting.o + + BKIFILES = postgres.bki postgres.description postgres.shdescription + +@@ -34,7 +34,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ + pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \ + pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \ + pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \ +- pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ ++ pg_seclabel.h pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ + pg_ts_parser.h pg_ts_template.h \ + pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ + pg_default_acl.h \ +diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c +index d16b03b..a9d5184 100644 +--- a/src/backend/catalog/aclchk.c ++++ b/src/backend/catalog/aclchk.c +@@ -38,6 +38,7 @@ + #include "catalog/pg_operator.h" + #include "catalog/pg_opfamily.h" + #include "catalog/pg_proc.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/pg_tablespace.h" + #include "catalog/pg_type.h" + #include "catalog/pg_ts_config.h" +@@ -46,6 +47,7 @@ + #include "foreign/foreign.h" + #include "miscadmin.h" + #include "parser/parse_func.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/fmgroids.h" + #include "utils/lsyscache.h" +@@ -1460,6 +1462,10 @@ expand_all_col_privileges(Oid table_oid, Form_pg_class classForm, + if (curr_att == ObjectIdAttributeNumber && !classForm->relhasoids) + continue; + ++ /* Skip security label column, if it doesn't exist */ ++ if (curr_att == SecurityLabelAttributeNumber && !classForm->relhassecids) ++ continue; ++ + /* Views don't have any system columns at all */ + if (classForm->relkind == RELKIND_VIEW && curr_att < 0) + continue; +@@ -1560,6 +1566,8 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, + relOid, grantorId, ACL_KIND_COLUMN, + relname, attnum, + NameStr(pg_attribute_tuple->attname)); ++ /* SELinux checks */ ++ sepgsql_attribute_grant(relOid, attnum); + + /* + * Generate new ACL. +@@ -1813,6 +1821,8 @@ ExecGrant_Relation(InternalGrant *istmt) + ? ACL_KIND_SEQUENCE : ACL_KIND_CLASS, + NameStr(pg_class_tuple->relname), + 0, NULL); ++ /* SELinux checks */ ++ sepgsql_relation_grant(relOid); + + /* + * Generate new ACL. +@@ -1999,6 +2009,8 @@ ExecGrant_Database(InternalGrant *istmt) + datId, grantorId, ACL_KIND_DATABASE, + NameStr(pg_database_tuple->datname), + 0, NULL); ++ /* SELinux checks */ ++ sepgsql_database_grant(datId); + + /* + * Generate new ACL. +@@ -2116,6 +2128,8 @@ ExecGrant_Fdw(InternalGrant *istmt) + fdwid, grantorId, ACL_KIND_FDW, + NameStr(pg_fdw_tuple->fdwname), + 0, NULL); ++ /* SELinux checks */ ++ sepgsql_fdw_grant(fdwid); + + /* + * Generate new ACL. +@@ -2233,6 +2247,8 @@ ExecGrant_ForeignServer(InternalGrant *istmt) + srvid, grantorId, ACL_KIND_FOREIGN_SERVER, + NameStr(pg_server_tuple->srvname), + 0, NULL); ++ /* SELinux checks */ ++ sepgsql_fserver_grant(srvid); + + /* + * Generate new ACL. +@@ -2719,6 +2735,8 @@ ExecGrant_Namespace(InternalGrant *istmt) + nspid, grantorId, ACL_KIND_NAMESPACE, + NameStr(pg_namespace_tuple->nspname), + 0, NULL); ++ /* SELinux checks */ ++ sepgsql_schema_grant(nspid); + + /* + * Generate new ACL. +@@ -2835,6 +2853,8 @@ ExecGrant_Tablespace(InternalGrant *istmt) + tblId, grantorId, ACL_KIND_TABLESPACE, + NameStr(pg_tablespace_tuple->spcname), + 0, NULL); ++ /* SELinux checks */ ++ sepgsql_tablespace_grant(tblId); + + /* + * Generate new ACL. +diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c +index 7efdf67..9376f6c 100644 +--- a/src/backend/catalog/catalog.c ++++ b/src/backend/catalog/catalog.c +@@ -32,6 +32,7 @@ + #include "catalog/pg_namespace.h" + #include "catalog/pg_pltemplate.h" + #include "catalog/pg_db_role_setting.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/pg_shdepend.h" + #include "catalog/pg_shdescription.h" + #include "catalog/pg_tablespace.h" +@@ -306,6 +307,7 @@ IsSharedRelation(Oid relationId) + relationId == AuthMemRelationId || + relationId == DatabaseRelationId || + relationId == PLTemplateRelationId || ++ relationId == SecLabelRelationId || + relationId == SharedDescriptionRelationId || + relationId == SharedDependRelationId || + relationId == TableSpaceRelationId || +@@ -319,6 +321,8 @@ IsSharedRelation(Oid relationId) + relationId == DatabaseNameIndexId || + relationId == DatabaseOidIndexId || + relationId == PLTemplateNameIndexId || ++ relationId == SecLabelSecidIndexId || ++ relationId == SecLabelLabelIndexId || + relationId == SharedDescriptionObjIndexId || + relationId == SharedDependDependerIndexId || + relationId == SharedDependReferenceIndexId || +@@ -331,6 +335,8 @@ IsSharedRelation(Oid relationId) + relationId == PgAuthidToastIndex || + relationId == PgDatabaseToastTable || + relationId == PgDatabaseToastIndex || ++ relationId == PgSecLabelToastTable || ++ relationId == PgSecLabelToastIndex || + relationId == PgShdescriptionToastTable || + relationId == PgShdescriptionToastIndex || + relationId == PgDbRoleSettingToastTable || +diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl +index 9eb805d..30a0779 100644 +--- a/src/backend/catalog/genbki.pl ++++ b/src/backend/catalog/genbki.pl +@@ -216,7 +216,8 @@ foreach my $catname ( @{ $catalogs->{names} } ) + {cmin => 'cid'}, + {xmax => 'xid'}, + {cmax => 'cid'}, +- {tableoid => 'oid'} ++ {tableoid => 'oid'}, ++ {security_label => 'text'} + ); + foreach my $attr (@SYS_ATTRS) + { +diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c +index ec89e49..35bc618 100644 +--- a/src/backend/catalog/heap.c ++++ b/src/backend/catalog/heap.c +@@ -43,6 +43,7 @@ + #include "catalog/pg_constraint.h" + #include "catalog/pg_inherits.h" + #include "catalog/pg_namespace.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/pg_statistic.h" + #include "catalog/pg_tablespace.h" + #include "catalog/pg_type.h" +@@ -82,14 +83,16 @@ static void AddNewRelationTuple(Relation pg_class_desc, + Oid relowner, + char relkind, + Datum relacl, +- Datum reloptions); ++ Datum reloptions, ++ Oid *secLabels); + static Oid AddNewRelationType(const char *typeName, + Oid typeNamespace, + Oid new_rel_oid, + char new_rel_kind, + Oid ownerid, + Oid new_row_type, +- Oid new_array_type); ++ Oid new_array_type, ++ Oid securityId); + static void RelationRemoveInheritance(Oid relid); + static void StoreRelCheck(Relation rel, char *ccname, Node *expr, + bool is_local, int inhcount); +@@ -173,7 +176,16 @@ static FormData_pg_attribute a7 = { + true, 'p', 'i', true, false, false, true, 0 + }; + +-static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; ++/* ++ * Security Label system column ++ */ ++static FormData_pg_attribute a8 = { ++ 0, {"security_label"}, TEXTOID, 0, -1, ++ SecurityLabelAttributeNumber, 0, -1, -1, ++ false, 'x', 'i', true, false, false, true, 0 ++}; ++ ++static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8}; + + /* + * This function returns a Form_pg_attribute pointer for a system attribute. +@@ -181,12 +193,14 @@ static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; + * happen if there's a problem upstream. + */ + Form_pg_attribute +-SystemAttributeDefinition(AttrNumber attno, bool relhasoids) ++SystemAttributeDefinition(AttrNumber attno, bool relhasoids, bool relhassecids) + { + if (attno >= 0 || attno < -(int) lengthof(SysAtt)) + elog(ERROR, "invalid system attribute number %d", attno); + if (attno == ObjectIdAttributeNumber && !relhasoids) + elog(ERROR, "invalid system attribute number %d", attno); ++ if (attno == SecurityLabelAttributeNumber && !relhassecids) ++ elog(ERROR, "invalid system attribute number %d", attno); + return SysAtt[-attno - 1]; + } + +@@ -195,7 +209,7 @@ SystemAttributeDefinition(AttrNumber attno, bool relhasoids) + * pointer for a prototype definition. If not, return NULL. + */ + Form_pg_attribute +-SystemAttributeByName(const char *attname, bool relhasoids) ++SystemAttributeByName(const char *attname, bool relhasoids, bool relhassecids) + { + int j; + +@@ -203,16 +217,29 @@ SystemAttributeByName(const char *attname, bool relhasoids) + { + Form_pg_attribute att = SysAtt[j]; + +- if (relhasoids || att->attnum != ObjectIdAttributeNumber) +- { +- if (strcmp(NameStr(att->attname), attname) == 0) +- return att; +- } ++ if (!relhasoids && att->attnum == ObjectIdAttributeNumber) ++ continue; ++ if (!relhassecids && att->attnum == SecurityLabelAttributeNumber) ++ continue; ++ ++ if (strcmp(NameStr(att->attname), attname) == 0) ++ return att; + } + + return NULL; + } + ++/* ++ * If the given attribute is writable system attribute, it returns true. ++ */ ++bool ++SystemAttributeWritable(AttrNumber attnum, bool hasoids, bool hassecids) ++{ ++ if (hassecids && attnum == SecurityLabelAttributeNumber) ++ return true; ++ ++ return false; ++} + + /* ---------------------------------------------------------------- + * XXX END OF UGLY HARD CODED BADNESS XXX +@@ -391,7 +418,8 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, + for (i = 0; i < natts; i++) + { + if (SystemAttributeByName(NameStr(tupdesc->attrs[i]->attname), +- tupdesc->tdhasoid) != NULL) ++ tupdesc->tdhasoid, ++ tupdesc->tdhassecid) != NULL) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_COLUMN), + errmsg("column name \"%s\" conflicts with a system column name", +@@ -509,7 +537,8 @@ CheckAttributeType(const char *attname, Oid atttypid, + void + InsertPgAttributeTuple(Relation pg_attribute_rel, + Form_pg_attribute new_attribute, +- CatalogIndexState indstate) ++ CatalogIndexState indstate, ++ Oid securityId) + { + Datum values[Natts_pg_attribute]; + bool nulls[Natts_pg_attribute]; +@@ -542,6 +571,8 @@ InsertPgAttributeTuple(Relation pg_attribute_rel, + nulls[Anum_pg_attribute_attoptions - 1] = true; + + tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls); ++ if (HeapTupleHasSecid(tup)) ++ HeapTupleSetSecid(tup, securityId); + + /* finally insert the new tuple, update the indexes, and clean up */ + simple_heap_insert(pg_attribute_rel, tup); +@@ -566,13 +597,15 @@ AddNewAttributeTuples(Oid new_rel_oid, + TupleDesc tupdesc, + char relkind, + bool oidislocal, +- int oidinhcount) ++ int oidinhcount, ++ Oid *secLabels) + { + Form_pg_attribute attr; + int i; + Relation rel; + CatalogIndexState indstate; + int natts = tupdesc->natts; ++ Oid secid; + ObjectAddress myself, + referenced; + +@@ -596,7 +629,10 @@ AddNewAttributeTuples(Oid new_rel_oid, + attr->attstattarget = -1; + attr->attcacheoff = -1; + +- InsertPgAttributeTuple(rel, attr, indstate); ++ secid = (!secLabels ? InvalidOid : ++ secLabels[i - FirstLowInvalidHeapAttributeNumber]); ++ ++ InsertPgAttributeTuple(rel, attr, indstate, secid); + + /* Add dependency info */ + myself.classId = RelationRelationId; +@@ -624,6 +660,11 @@ AddNewAttributeTuples(Oid new_rel_oid, + SysAtt[i]->attnum == ObjectIdAttributeNumber) + continue; + ++ /* skip security label where appropriate */ ++ if (!tupdesc->tdhassecid && ++ SysAtt[i]->attnum == SecurityLabelAttributeNumber) ++ continue; ++ + memcpy(&attStruct, (char *) SysAtt[i], sizeof(FormData_pg_attribute)); + + /* Fill in the correct relation OID in the copied tuple */ +@@ -636,7 +677,10 @@ AddNewAttributeTuples(Oid new_rel_oid, + attStruct.attinhcount = oidinhcount; + } + +- InsertPgAttributeTuple(rel, &attStruct, indstate); ++ secid = (!secLabels ? InvalidOid ++ : secLabels[SysAtt[i]->attnum - FirstLowInvalidHeapAttributeNumber]); ++ ++ InsertPgAttributeTuple(rel, &attStruct, indstate, secid); + } + } + +@@ -666,7 +710,8 @@ InsertPgClassTuple(Relation pg_class_desc, + Relation new_rel_desc, + Oid new_rel_oid, + Datum relacl, +- Datum reloptions) ++ Datum reloptions, ++ Oid securityId) + { + Form_pg_class rd_rel = new_rel_desc->rd_rel; + Datum values[Natts_pg_class]; +@@ -696,6 +741,7 @@ InsertPgClassTuple(Relation pg_class_desc, + values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts); + values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks); + values[Anum_pg_class_relhasoids - 1] = BoolGetDatum(rd_rel->relhasoids); ++ values[Anum_pg_class_relhassecids - 1] = BoolGetDatum(rd_rel->relhassecids); + values[Anum_pg_class_relhaspkey - 1] = BoolGetDatum(rd_rel->relhaspkey); + values[Anum_pg_class_relhasexclusion - 1] = BoolGetDatum(rd_rel->relhasexclusion); + values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules); +@@ -719,6 +765,9 @@ InsertPgClassTuple(Relation pg_class_desc, + */ + HeapTupleSetOid(tup, new_rel_oid); + ++ if (HeapTupleHasSecid(tup)) ++ HeapTupleSetSecid(tup, securityId); ++ + /* finally insert the new tuple, update the indexes, and clean up */ + simple_heap_insert(pg_class_desc, tup); + +@@ -743,9 +792,11 @@ AddNewRelationTuple(Relation pg_class_desc, + Oid relowner, + char relkind, + Datum relacl, +- Datum reloptions) ++ Datum reloptions, ++ Oid *secLabels) + { + Form_pg_class new_rel_reltup; ++ Oid secid; + + /* + * first we update some of the information in our uncataloged relation's +@@ -803,9 +854,11 @@ AddNewRelationTuple(Relation pg_class_desc, + + new_rel_desc->rd_att->tdtypeid = new_type_oid; + ++ secid = (!secLabels ? InvalidOid : secLabels[0]); ++ + /* Now build and insert the tuple */ + InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, +- relacl, reloptions); ++ relacl, reloptions, secid); + } + + +@@ -822,7 +875,8 @@ AddNewRelationType(const char *typeName, + char new_rel_kind, + Oid ownerid, + Oid new_row_type, +- Oid new_array_type) ++ Oid new_array_type, ++ Oid securityId) + { + return + TypeCreate(new_row_type, /* optional predetermined OID */ +@@ -854,7 +908,8 @@ AddNewRelationType(const char *typeName, + 'x', /* fully TOASTable */ + -1, /* typmod */ + 0, /* array dimensions for typBaseType */ +- false); /* Type NOT NULL */ ++ false, /* Type NOT NULL */ ++ securityId); /* security-id of the type */ + } + + /* -------------------------------- +@@ -903,7 +958,8 @@ heap_create_with_catalog(const char *relname, + OnCommitAction oncommit, + Datum reloptions, + bool use_user_acl, +- bool allow_system_table_mods) ++ bool allow_system_table_mods, ++ Oid *secLabels) + { + Relation pg_class_desc; + Relation new_rel_desc; +@@ -911,6 +967,7 @@ heap_create_with_catalog(const char *relname, + Oid old_type_oid; + Oid new_type_oid; + Oid new_array_oid = InvalidOid; ++ Oid type_secid = InvalidOid; + + pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock); + +@@ -1030,6 +1087,11 @@ heap_create_with_catalog(const char *relname, + relkind == RELKIND_COMPOSITE_TYPE)) + new_array_oid = AssignTypeArrayOid(); + ++ /* security context of the relation type */ ++ if (secLabels) ++ type_secid = seclabelMoveSecid(TypeRelationId, ++ RelationRelationId, secLabels[0]); ++ + /* + * Since defining a relation also defines a complex type, we add a new + * system type corresponding to the new relation. The OID of the type can +@@ -1046,7 +1108,8 @@ heap_create_with_catalog(const char *relname, + relkind, + ownerid, + reltypeid, +- new_array_oid); ++ new_array_oid, ++ type_secid); + + /* + * Now make the array type if wanted. +@@ -1086,7 +1149,8 @@ heap_create_with_catalog(const char *relname, + 'x', /* fully TOASTable */ + -1, /* typmod */ + 0, /* array dimensions for typBaseType */ +- false); /* Type NOT NULL */ ++ false, /* Type NOT NULL */ ++ type_secid); /* security-id of the type */ + + pfree(relarrayname); + } +@@ -1106,13 +1170,14 @@ heap_create_with_catalog(const char *relname, + ownerid, + relkind, + PointerGetDatum(relacl), +- reloptions); ++ reloptions, ++ secLabels); + + /* + * now add tuples to pg_attribute for the attributes in our new relation. + */ + AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind, +- oidislocal, oidinhcount); ++ oidislocal, oidinhcount, secLabels); + + /* + * Make a dependency link to force the relation to be deleted if its +@@ -1590,6 +1655,11 @@ heap_drop_with_catalog(Oid relid) + * delete relation tuple + */ + DeleteRelationTuple(relid); ++ ++ /* ++ * delete orphan pg_seclabel entries ++ */ ++ seclabelOnDropTable(relid); + } + + +diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c +index 69946fe..23fb19b 100644 +--- a/src/backend/catalog/index.c ++++ b/src/backend/catalog/index.c +@@ -39,6 +39,7 @@ + #include "catalog/pg_constraint.h" + #include "catalog/pg_operator.h" + #include "catalog/pg_opclass.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/pg_tablespace.h" + #include "catalog/pg_trigger.h" + #include "catalog/pg_type.h" +@@ -90,7 +91,8 @@ static TupleDesc ConstructTupleDescriptor(Relation heapRelation, + Oid *classObjectId); + static void InitializeAttributeOids(Relation indexRelation, + int numatts, Oid indexoid); +-static void AppendAttributeTuples(Relation indexRelation, int numatts); ++static void AppendAttributeTuples(Relation indexRelation, ++ int numatts, Oid securityId); + static void UpdateIndexRelation(Oid indexoid, Oid heapoid, + IndexInfo *indexInfo, + Oid *classOids, +@@ -155,7 +157,7 @@ ConstructTupleDescriptor(Relation heapRelation, + /* + * allocate the new tuple descriptor + */ +- indexTupDesc = CreateTemplateTupleDesc(numatts, false); ++ indexTupDesc = CreateTemplateTupleDesc(numatts, false, false); + + /* + * For simple index columns, we copy the pg_attribute row from the parent +@@ -182,7 +184,8 @@ ConstructTupleDescriptor(Relation heapRelation, + * here we are indexing on a system attribute (-1...-n) + */ + from = SystemAttributeDefinition(atnum, +- heapRelation->rd_rel->relhasoids); ++ heapRelation->rd_rel->relhasoids, ++ heapRelation->rd_rel->relhassecids); + } + else + { +@@ -339,13 +342,16 @@ InitializeAttributeOids(Relation indexRelation, + * ---------------------------------------------------------------- + */ + static void +-AppendAttributeTuples(Relation indexRelation, int numatts) ++AppendAttributeTuples(Relation indexRelation, int numatts, Oid securityId) + { + Relation pg_attribute; + CatalogIndexState indstate; + TupleDesc indexTupDesc; + int i; + ++ /* copy security id */ ++ securityId = seclabelMoveSecid(AttributeRelationId, ++ RelationRelationId, securityId); + /* + * open the attribute relation and its indexes + */ +@@ -367,7 +373,8 @@ AppendAttributeTuples(Relation indexRelation, int numatts) + Assert(indexTupDesc->attrs[i]->attnum == i + 1); + Assert(indexTupDesc->attrs[i]->attcacheoff == -1); + +- InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], indstate); ++ InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], ++ indstate, securityId); + } + + CatalogCloseIndexes(indstate); +@@ -545,6 +552,7 @@ index_create(Oid heapRelationId, + bool mapped_relation; + bool is_exclusion; + Oid namespaceId; ++ Oid securityId; + int i; + + is_exclusion = (indexInfo->ii_ExclusionOps != NULL); +@@ -682,15 +690,21 @@ index_create(Oid heapRelationId, + indexRelation->rd_rel->relam = accessMethodObjectId; + indexRelation->rd_rel->relkind = RELKIND_INDEX; + indexRelation->rd_rel->relhasoids = false; ++ indexRelation->rd_rel->relhassecids = false; + indexRelation->rd_rel->relhasexclusion = is_exclusion; + + /* ++ * Index always has same security id of the relation to be indexed on. ++ */ ++ securityId = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(heapRelationId)); ++ ++ /* + * store index's pg_class entry + */ + InsertPgClassTuple(pg_class, indexRelation, + RelationGetRelid(indexRelation), + (Datum) 0, +- reloptions); ++ reloptions, securityId); + + /* done with pg_class */ + heap_close(pg_class, RowExclusiveLock); +@@ -706,7 +720,7 @@ index_create(Oid heapRelationId, + /* + * append ATTRIBUTE tuples for the index + */ +- AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs); ++ AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs, securityId); + + /* ---------------- + * update pg_index +diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c +index 5581346..cf1910a 100644 +--- a/src/backend/catalog/namespace.c ++++ b/src/backend/catalog/namespace.c +@@ -40,6 +40,7 @@ + #include "miscadmin.h" + #include "nodes/makefuncs.h" + #include "parser/parse_func.h" ++#include "sepgsql/hooks.h" + #include "storage/backendid.h" + #include "storage/ipc.h" + #include "utils/acl.h" +@@ -2311,6 +2312,9 @@ LookupExplicitNamespace(const char *nspname) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + nspname); + ++ /* SELinux checks */ ++ sepgsql_schema_search(namespaceId, true); ++ + return namespaceId; + } + +@@ -2903,7 +2907,8 @@ recomputeNamespacePath(void) + if (OidIsValid(namespaceId) && + !list_member_oid(oidlist, namespaceId) && + pg_namespace_aclcheck(namespaceId, roleid, +- ACL_USAGE) == ACLCHECK_OK) ++ ACL_USAGE) == ACLCHECK_OK && ++ sepgsql_schema_search(namespaceId, false)) + oidlist = lappend_oid(oidlist, namespaceId); + } + } +@@ -2930,7 +2935,8 @@ recomputeNamespacePath(void) + if (OidIsValid(namespaceId) && + !list_member_oid(oidlist, namespaceId) && + pg_namespace_aclcheck(namespaceId, roleid, +- ACL_USAGE) == ACLCHECK_OK) ++ ACL_USAGE) == ACLCHECK_OK && ++ sepgsql_schema_search(namespaceId, false)) + oidlist = lappend_oid(oidlist, namespaceId); + } + } +@@ -2996,9 +3002,12 @@ InitTempTableNamespace(void) + char namespaceName[NAMEDATALEN]; + Oid namespaceId; + Oid toastspaceId; ++ Oid secid; + + Assert(!OidIsValid(myTempNamespace)); + ++ snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId); ++ + /* + * First, do permission check to see if we are authorized to make temp + * tables. We use a nonstandard error message here since "databasename: +@@ -3016,6 +3025,9 @@ InitTempTableNamespace(void) + errmsg("permission denied to create temporary tables in database \"%s\"", + get_database_name(MyDatabaseId)))); + ++ /* SELinux checks */ ++ secid = sepgsql_schema_create(namespaceName, true); ++ + /* + * Do not allow a Hot Standby slave session to make temp tables. Aside + * from problems with modifying the system catalogs, there is a naming +@@ -3031,8 +3043,6 @@ InitTempTableNamespace(void) + (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), + errmsg("cannot create temporary tables during recovery"))); + +- snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId); +- + namespaceId = GetSysCacheOid1(NAMESPACENAME, + CStringGetDatum(namespaceName)); + if (!OidIsValid(namespaceId)) +@@ -3045,7 +3055,9 @@ InitTempTableNamespace(void) + * temp tables. This works because the places that access the temp + * namespace for my own backend skip permissions checks on it. + */ +- namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID); ++ namespaceId = NamespaceCreate(namespaceName, ++ BOOTSTRAP_SUPERUSERID, ++ secid); + /* Advance command counter to make namespace visible */ + CommandCounterIncrement(); + } +@@ -3070,7 +3082,9 @@ InitTempTableNamespace(void) + CStringGetDatum(namespaceName)); + if (!OidIsValid(toastspaceId)) + { +- toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID); ++ toastspaceId = NamespaceCreate(namespaceName, ++ BOOTSTRAP_SUPERUSERID, ++ secid); + /* Advance command counter to make namespace visible */ + CommandCounterIncrement(); + } +diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c +index 582d894..d7b6bd1 100644 +--- a/src/backend/catalog/pg_aggregate.c ++++ b/src/backend/catalog/pg_aggregate.c +@@ -27,6 +27,7 @@ + #include "parser/parse_coerce.h" + #include "parser/parse_func.h" + #include "parser/parse_oper.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/lsyscache.h" +@@ -67,6 +68,7 @@ AggregateCreate(const char *aggName, + Oid *fnArgs; + int nargs_transfn; + Oid procOid; ++ Oid procSecid; + TupleDesc tupDesc; + int i; + ObjectAddress myself, +@@ -161,6 +163,10 @@ AggregateCreate(const char *aggName, + } + Assert(OidIsValid(finaltype)); + ++ /* SELinux checks */ ++ procSecid = sepgsql_aggregate_create(aggName, aggNamespace, ++ transfn, finalfn); ++ + /* + * If finaltype (i.e. aggregate return type) is polymorphic, inputs must + * be polymorphic also, else parser will fail to deduce result type. +@@ -229,7 +235,8 @@ AggregateCreate(const char *aggName, + NIL, /* parameterDefaults */ + PointerGetDatum(NULL), /* proconfig */ + 1, /* procost */ +- 0); /* prorows */ ++ 0, /* prorows */ ++ procSecid); /* security-id */ + + /* + * Okay to create the pg_aggregate entry. +diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c +index 99085c9..b4c0b3a 100644 +--- a/src/backend/catalog/pg_conversion.c ++++ b/src/backend/catalog/pg_conversion.c +@@ -40,7 +40,7 @@ Oid + ConversionCreate(const char *conname, Oid connamespace, + Oid conowner, + int32 conforencoding, int32 contoencoding, +- Oid conproc, bool def) ++ Oid conproc, bool def, Oid securityId) + { + int i; + Relation rel; +@@ -104,6 +104,8 @@ ConversionCreate(const char *conname, Oid connamespace, + + tup = heap_form_tuple(tupDesc, values, nulls); + ++ HeapTupleSetSecid(tup, securityId); ++ + /* insert a new tuple */ + oid = simple_heap_insert(rel, tup); + Assert(OidIsValid(oid)); +diff --git a/src/backend/catalog/pg_largeobject.c b/src/backend/catalog/pg_largeobject.c +index e3f18bf..572ce01 100644 +--- a/src/backend/catalog/pg_largeobject.c ++++ b/src/backend/catalog/pg_largeobject.c +@@ -21,10 +21,13 @@ + #include "catalog/dependency.h" + #include "catalog/indexing.h" + #include "catalog/pg_authid.h" ++#include "catalog/pg_description.h" + #include "catalog/pg_largeobject.h" + #include "catalog/pg_largeobject_metadata.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/toasting.h" + #include "miscadmin.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/bytea.h" + #include "utils/fmgroids.h" +@@ -40,7 +43,7 @@ + * will appear to exist with size 0. + */ + Oid +-LargeObjectCreate(Oid loid) ++LargeObjectCreate(Oid loid, Oid securityId) + { + Relation pg_lo_meta; + HeapTuple ntup; +@@ -66,6 +69,8 @@ LargeObjectCreate(Oid loid) + if (OidIsValid(loid)) + HeapTupleSetOid(ntup, loid); + ++ HeapTupleSetSecid(ntup, securityId); ++ + loid_new = simple_heap_insert(pg_lo_meta, ntup); + Assert(!OidIsValid(loid) || loid == loid_new); + +@@ -245,6 +250,64 @@ LargeObjectAlterOwner(Oid loid, Oid newOwnerId) + } + + /* ++ * LargeObjectAlterSecLabel ++ * ++ * Implementation of ALTER LARGE OBJECT xxx SECURITY LABEL ++ */ ++void ++LargeObjectAlterSecLabel(Oid loid, char *new_label) ++{ ++ Relation pg_lo_meta; ++ ScanKeyData skey; ++ SysScanDesc scan; ++ HeapTuple oldtup; ++ HeapTuple newtup; ++ Oid securityId; ++ ++ pg_lo_meta = heap_open(LargeObjectMetadataRelationId, ++ RowExclusiveLock); ++ ++ ScanKeyInit(&skey, ++ ObjectIdAttributeNumber, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(loid)); ++ ++ scan = systable_beginscan(pg_lo_meta, ++ LargeObjectMetadataOidIndexId, true, ++ SnapshotNow, 1, &skey); ++ ++ oldtup = systable_getnext(scan); ++ if (!HeapTupleIsValid(oldtup)) ++ ereport(ERROR, ++ (errcode(ERRCODE_UNDEFINED_OBJECT), ++ errmsg("large object %u does not exist", loid))); ++ ++ /* Must be owner of the large object */ ++ if (!pg_largeobject_ownercheck(loid, GetUserId())) ++ ereport(ERROR, ++ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ++ errmsg("must be owner of large object %u", loid))); ++ ++ /* SELinux checks */ ++ securityId = sepgsql_largeobject_relabel(loid, new_label); ++ ++ /* update the tuple */ ++ newtup = heap_copytuple(oldtup); ++ ++ HeapTupleSetSecid(newtup, securityId); ++ ++ simple_heap_update(pg_lo_meta, &newtup->t_self, newtup); ++ ++ CatalogUpdateIndexes(pg_lo_meta, newtup); ++ ++ heap_freetuple(newtup); ++ ++ systable_endscan(scan); ++ ++ heap_close(pg_lo_meta, RowExclusiveLock); ++} ++ ++/* + * LargeObjectExists + * + * We don't use the system cache to for large object metadata, for fear of +diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c +index 22111a3..cba7274 100644 +--- a/src/backend/catalog/pg_namespace.c ++++ b/src/backend/catalog/pg_namespace.c +@@ -28,7 +28,7 @@ + * --------------- + */ + Oid +-NamespaceCreate(const char *nspName, Oid ownerId) ++NamespaceCreate(const char *nspName, Oid ownerId, Oid secid) + { + Relation nspdesc; + HeapTuple tup; +@@ -64,6 +64,8 @@ NamespaceCreate(const char *nspName, Oid ownerId) + tupDesc = nspdesc->rd_att; + + tup = heap_form_tuple(tupDesc, values, nulls); ++ if (HeapTupleHasSecid(tup)) ++ HeapTupleSetSecid(tup, secid); + + nspoid = simple_heap_insert(nspdesc, tup); + Assert(OidIsValid(nspoid)); +diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c +index 2362268..f6df55e 100644 +--- a/src/backend/catalog/pg_operator.c ++++ b/src/backend/catalog/pg_operator.c +@@ -28,6 +28,7 @@ + #include "catalog/pg_type.h" + #include "miscadmin.h" + #include "parser/parse_oper.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/lsyscache.h" +@@ -204,6 +205,7 @@ OperatorShellMake(const char *operatorName, + { + Relation pg_operator_desc; + Oid operatorObjectId; ++ Oid securityId; + int i; + HeapTuple tup; + Datum values[Natts_pg_operator]; +@@ -220,6 +222,12 @@ OperatorShellMake(const char *operatorName, + errmsg("\"%s\" is not a valid operator name", + operatorName))); + ++ /* SELinux checks */ ++ securityId = sepgsql_operator_create(operatorName, InvalidOid, ++ operatorNamespace, ++ InvalidOid, InvalidOid, InvalidOid, ++ InvalidOid, InvalidOid); ++ + /* + * initialize our *nulls and *values arrays + */ +@@ -261,6 +269,8 @@ OperatorShellMake(const char *operatorName, + */ + tup = heap_form_tuple(tupDesc, values, nulls); + ++ HeapTupleSetSecid(tup, securityId); ++ + /* + * insert our "shell" operator tuple + */ +@@ -340,6 +350,7 @@ OperatorCreate(const char *operatorName, + bool replaces[Natts_pg_operator]; + Datum values[Natts_pg_operator]; + Oid operatorObjectId; ++ Oid securityId; + bool operatorAlreadyDefined; + Oid operResultType; + Oid commutatorId, +@@ -476,6 +487,12 @@ OperatorCreate(const char *operatorName, + else + negatorId = InvalidOid; + ++ /* SELinux checks */ ++ securityId = sepgsql_operator_create(operatorName, operatorObjectId, ++ operatorNamespace, ++ procedureId, restrictionId, joinId, ++ commutatorId, negatorId); ++ + /* + * set up values in the operator tuple + */ +@@ -516,6 +533,8 @@ OperatorCreate(const char *operatorName, + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for operator %u", + operatorObjectId); ++ if (securityId != HeapTupleHasSecid(tup)) ++ elog(ERROR, "Bug? security-id was mismatched."); + + tup = heap_modify_tuple(tup, + RelationGetDescr(pg_operator_desc), +@@ -530,6 +549,8 @@ OperatorCreate(const char *operatorName, + tupDesc = pg_operator_desc->rd_att; + tup = heap_form_tuple(tupDesc, values, nulls); + ++ HeapTupleSetSecid(tup, securityId); ++ + operatorObjectId = simple_heap_insert(pg_operator_desc, tup); + } + +diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c +index 3772c32..d99c351 100644 +--- a/src/backend/catalog/pg_proc.c ++++ b/src/backend/catalog/pg_proc.c +@@ -84,7 +84,8 @@ ProcedureCreate(const char *procedureName, + List *parameterDefaults, + Datum proconfig, + float4 procost, +- float4 prorows) ++ float4 prorows, ++ Oid prosecid) + { + Oid retval; + int parameterCount; +@@ -364,6 +365,8 @@ ProcedureCreate(const char *procedureName, + if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner)) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, + procedureName); ++ if (prosecid != HeapTupleGetSecid(oldtup)) ++ elog(ERROR, "Bug? security-id was tried to be changed."); + + /* + * Not okay to change the return type of the existing proc, since +@@ -548,6 +551,9 @@ ProcedureCreate(const char *procedureName, + nulls[Anum_pg_proc_proacl - 1] = true; + + tup = heap_form_tuple(tupDesc, values, nulls); ++ ++ HeapTupleSetSecid(tup, prosecid); ++ + simple_heap_insert(rel, tup); + is_update = false; + } +diff --git a/src/backend/catalog/pg_seclabel.c b/src/backend/catalog/pg_seclabel.c +new file mode 100644 +index 0000000..4816635 +--- /dev/null ++++ b/src/backend/catalog/pg_seclabel.c +@@ -0,0 +1,646 @@ ++/* ++ * pg_seclabel.c ++ * ++ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group ++ * Portions Copyright (c) 1994, Regents of the University of California ++ */ ++#include "postgres.h" ++ ++#include "access/genam.h" ++#include "access/heapam.h" ++#include "access/sysattr.h" ++#include "access/tupdesc.h" ++#include "catalog/catalog.h" ++#include "catalog/indexing.h" ++#include "catalog/pg_aggregate.h" ++#include "catalog/pg_amop.h" ++#include "catalog/pg_amproc.h" ++#include "catalog/pg_attrdef.h" ++#include "catalog/pg_auth_members.h" ++#include "catalog/pg_constraint.h" ++#include "catalog/pg_db_role_setting.h" ++#include "catalog/pg_depend.h" ++#include "catalog/pg_description.h" ++#include "catalog/pg_enum.h" ++#include "catalog/pg_index.h" ++#include "catalog/pg_inherits.h" ++#include "catalog/pg_largeobject.h" ++#include "catalog/pg_namespace.h" ++#include "catalog/pg_rewrite.h" ++#include "catalog/pg_seclabel.h" ++#include "catalog/pg_shdepend.h" ++#include "catalog/pg_shdescription.h" ++#include "catalog/pg_trigger.h" ++#include "catalog/pg_ts_config_map.h" ++#include "executor/spi.h" ++#include "miscadmin.h" ++#include "sepgsql/sepgsql.h" ++#include "sepgsql/hooks.h" ++#include "utils/builtins.h" ++#include "utils/fmgroids.h" ++#include "utils/lsyscache.h" ++#include "utils/rel.h" ++#include "utils/syscache.h" ++#include "utils/tqual.h" ++ ++bool ignore_security_label_input; ++ ++void ++seclabelOnCreateDatabase(Oid src_datid, Oid dst_datid) ++{ ++ Relation rel; ++ ScanKeyData keys[1]; ++ SysScanDesc scan; ++ HeapTuple oldtup, newtup; ++ Datum values[Natts_pg_seclabel]; ++ bool nulls[Natts_pg_seclabel]; ++ bool replaces[Natts_pg_seclabel]; ++ ++ /* Scan all entries with pg_seclabel.datid = src_datid */ ++ ScanKeyInit(&keys[0], ++ Anum_pg_seclabel_datid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(src_datid)); ++ ++ rel = heap_open(SecLabelRelationId, RowExclusiveLock); ++ ++ scan = systable_beginscan(rel, SecLabelSecidIndexId, true, ++ SnapshotNow, 1, keys); ++ ++ /* corresponding entries will be inserted with new datid */ ++ memset(values, 0, sizeof(values)); ++ memset(nulls, false, sizeof(nulls)); ++ memset(replaces, false, sizeof(replaces)); ++ ++ values[Anum_pg_seclabel_datid - 1] = ObjectIdGetDatum(dst_datid); ++ replaces[Anum_pg_seclabel_datid - 1] = true; ++ while (HeapTupleIsValid(oldtup = systable_getnext(scan))) ++ { ++ newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), ++ values, nulls, replaces); ++ simple_heap_insert(rel, newtup); ++ ++ CatalogUpdateIndexes(rel, newtup); ++ ++ heap_freetuple(newtup); ++ } ++ systable_endscan(scan); ++ ++ heap_close(rel, RowExclusiveLock); ++} ++ ++void ++seclabelOnDropDatabase(Oid datid) ++{ ++ Relation rel; ++ ScanKeyData keys[1]; ++ SysScanDesc scan; ++ HeapTuple tuple; ++ ++ /* Scan all entries with pg_seclabel.datid = datid */ ++ ScanKeyInit(&keys[0], ++ Anum_pg_seclabel_datid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(datid)); ++ ++ rel = heap_open(SecLabelRelationId, RowExclusiveLock); ++ ++ scan = systable_beginscan(rel, SecLabelSecidIndexId, true, ++ SnapshotNow, 1, keys); ++ ++ while (HeapTupleIsValid(tuple = systable_getnext(scan))) ++ { ++ simple_heap_delete(rel, &tuple->t_self); ++ } ++ ++ systable_endscan(scan); ++ ++ heap_close(rel, RowExclusiveLock); ++} ++ ++void ++seclabelOnDropTable(Oid relid) ++{ ++ Relation rel; ++ SysScanDesc scan; ++ ScanKeyData key[2]; ++ HeapTuple tuple; ++ Oid database_oid; ++ ++ database_oid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId); ++ ScanKeyInit(&key[0], ++ Anum_pg_seclabel_datid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(database_oid)); ++ ScanKeyInit(&key[1], ++ Anum_pg_seclabel_relid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(relid)); ++ ++ rel = heap_open(SecLabelRelationId, RowExclusiveLock); ++ scan = systable_beginscan(rel, SecLabelLabelIndexId, true, ++ SnapshotNow, 2, key); ++ ++ while (HeapTupleIsValid(tuple = systable_getnext(scan))) ++ simple_heap_delete(rel, &tuple->t_self); ++ ++ systable_endscan(scan); ++ ++ heap_close(rel, RowExclusiveLock); ++} ++ ++/* ++ * XXX - it should be replaced by BKI scripts ++ */ ++bool ++seclabelCatalogHasSysAttr(Oid relOid) ++{ ++ switch (relOid) ++ { ++ case AggregateRelationId: ++ /* pg_aggregate is property of pg_proc */ ++ case AccessMethodOperatorRelationId: ++ /* pg_amop is property of pg_opfamily */ ++ case AccessMethodProcedureRelationId: ++ /* pg_amproc is property of pg_opfamily */ ++ case AttrDefaultRelationId: ++ /* pg_attrdef is property of pg_attribute */ ++ case AuthMemRelationId: ++ /* pg_auth_members is property of pg_auth */ ++ case ConstraintRelationId: ++ /* ++ * CHECK constraint is property of pg_class ++ * DOMAIN constraint is property of pg_type ++ * Global assertion is property of pg_database ++ */ ++ case DbRoleSettingRelationId: ++ /* pg_db_role_setting is property of pg_auth or pg_database */ ++ case DependRelationId: ++ /* property of the depending object */ ++ case DescriptionRelationId: ++ /* property of the object commented on */ ++ case EnumRelationId: ++ /* pg_enum is property of pg_type */ ++ case IndexRelationId: ++ /* pg_index is property of pg_class with RELKIND_INDEX */ ++ case InheritsRelationId: ++ /* pg_inherits is property of the child relation */ ++ case LargeObjectRelationId: ++ /* pg_largeobject is data chunk of pg_largeobject_metadata */ ++ case RewriteRelationId: ++ /* pg_rewrite is property of pg_class */ ++ case SecLabelRelationId: ++ /* No security attribute has no security label */ ++ case SharedDependRelationId: ++ /* property of the depending shared object */ ++ case SharedDescriptionRelationId: ++ /* property of the shared object commented on */ ++ case TriggerRelationId: ++ /* pg_trigger is property of pg_class */ ++ case TSConfigMapRelationId: ++ /* pg_ts_config_map is property of pg_ts_config */ ++ return false; ++ ++ default: ++ return true; ++ } ++} ++ ++Oid * ++seclabelMakeRelationDefaults(TupleDesc tupdesc, List *supOids) ++{ ++ ListCell *l; ++ Oid *secLabels; ++ Oid securityId; ++ int index, attno, nitems; ++ ++ nitems = tupdesc->natts - FirstLowInvalidHeapAttributeNumber; ++ secLabels = palloc0(sizeof(Oid) * nitems); ++ ++ foreach (l, supOids) ++ { ++ Oid relOid = lfirst_oid(l); ++ ++ securityId = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(relOid)); ++ ++ if (!OidIsValid(secLabels[0])) ++ secLabels[0] = securityId; ++ else if (!seclabelCompareSecid(RelationRelationId, secLabels[0], ++ RelationRelationId, securityId)) ++ ereport(ERROR, ++ (errcode(ERRCODE_WRONG_OBJECT_TYPE), ++ errmsg("cannot inherit relations with different label"))); ++ ++ for (index = 1; index < nitems; index++) ++ { ++ attno = index + FirstLowInvalidHeapAttributeNumber; ++ ++ if (attno < 0) ++ securityId = GetSysCacheSecid2(ATTNUM, ++ ObjectIdGetDatum(relOid), ++ Int16GetDatum(attno)); ++ else ++ { ++ const char *attname = NameStr(tupdesc->attrs[attno]->attname); ++ securityId = GetSysCacheSecid2(ATTNAME, ++ ObjectIdGetDatum(relOid), ++ PointerGetDatum(attname)); ++ } ++ ++ if (!OidIsValid(securityId)) ++ continue; ++ ++ if (!OidIsValid(secLabels[index])) ++ secLabels[index] = securityId; ++ else if (!seclabelCompareSecid(AttributeRelationId, secLabels[index], ++ AttributeRelationId, securityId)) ++ ereport(ERROR, ++ (errcode(ERRCODE_WRONG_OBJECT_TYPE), ++ errmsg("cannot inherit attribute with different label"))); ++ } ++ } ++ return secLabels; ++} ++ ++Oid * ++seclabelMakeToastDefaults(TupleDesc tupdesc, Oid relOid) ++{ ++ Oid *secLabels; ++ Oid securityId; ++ int index, nitems; ++ ++ nitems = tupdesc->natts + 1 - FirstLowInvalidHeapAttributeNumber; ++ secLabels = palloc0(sizeof(Oid) * nitems); ++ ++ securityId = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(relOid)); ++ secLabels[0] = securityId; ++ ++ securityId = seclabelMoveSecid(AttributeRelationId, ++ RelationRelationId, ++ securityId); ++ for (index = 1; index < nitems; index++) ++ secLabels[index] = securityId; ++ ++ return secLabels; ++} ++ ++Oid ++seclabelGetNewSecid(Relation rel, HeapTuple tuple) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled() && ++ !IsBootstrapProcessingMode()) ++ { ++ return sepgsql_get_default_secid(rel, tuple); ++ } ++#endif ++ return InvalidOid; ++} ++ ++static Oid ++inputSecurityLabel(Oid relid, const char *seclabel) ++{ ++ LOCKMODE lockmode = AccessShareLock; ++ Relation rel; ++ ScanKeyData skey[3]; ++ SysScanDesc scan; ++ HeapTuple tuple; ++ Oid datid; ++ Oid secid; ++ Datum values[Natts_pg_seclabel]; ++ bool nulls[Natts_pg_seclabel]; ++ ++ datid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId); ++ ++retry: ++ /* ++ * Lookup pg_seclabel first, then insert a new entry if not found. ++ * An exclusive lock is not necessary for the first read-only path, ++ * and we assume most of trials are read-only. ++ */ ++ rel = heap_open(SecLabelRelationId, lockmode); ++ ++ ScanKeyInit(&skey[0], ++ Anum_pg_seclabel_datid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(datid)); ++ ScanKeyInit(&skey[1], ++ Anum_pg_seclabel_relid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(relid)); ++ ScanKeyInit(&skey[2], ++ Anum_pg_seclabel_label, ++ BTEqualStrategyNumber, F_TEXTEQ, ++ CStringGetTextDatum(seclabel)); ++ ++ scan = systable_beginscan(rel, SecLabelLabelIndexId, true, ++ SnapshotToast, 3, skey); ++ ++ tuple = systable_getnext(scan); ++ if (HeapTupleIsValid(tuple)) ++ { ++ secid = ((Form_pg_seclabel) GETSTRUCT(tuple))->secid; ++ systable_endscan(scan); ++ heap_close(rel, lockmode); ++ return secid; ++ } ++ ++ /* ++ * If not exist, try to insert a new entry. ++ */ ++ if (lockmode == AccessShareLock) ++ { ++ systable_endscan(scan); ++ heap_close(rel, lockmode); ++ lockmode = RowExclusiveLock; ++ goto retry; ++ } ++ ++ memset(nulls, false, sizeof(nulls)); ++ secid = GetNewOidWithIndex(rel, SecLabelSecidIndexId, ++ Anum_pg_seclabel_secid); ++ values[Anum_pg_seclabel_secid - 1] = ObjectIdGetDatum(secid); ++ values[Anum_pg_seclabel_datid - 1] = ObjectIdGetDatum(datid); ++ values[Anum_pg_seclabel_relid - 1] = ObjectIdGetDatum(relid); ++ values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(seclabel); ++ ++ tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); ++ ++ simple_heap_insert(rel, tuple); ++ ++ CatalogUpdateIndexes(rel, tuple); ++ ++ systable_endscan(scan); ++ ++ heap_close(rel, lockmode); ++ ++ return secid; ++} ++ ++static char * ++outputSecurityLabel(Oid relid, Oid secid) ++{ ++ Relation rel; ++ ScanKeyData skey[3]; ++ SysScanDesc scan; ++ HeapTuple tuple; ++ Oid datid; ++ char *result = NULL; ++ ++ datid = (IsSharedRelation(relid) ? InvalidOid : MyDatabaseId); ++ ++ /* ++ * Lookup pg_seclabel for the given datid/relid/secid ++ */ ++ rel = heap_open(SecLabelRelationId, AccessShareLock); ++ ++ ScanKeyInit(&skey[0], ++ Anum_pg_seclabel_secid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(secid)); ++ ScanKeyInit(&skey[1], ++ Anum_pg_seclabel_datid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(datid)); ++ ScanKeyInit(&skey[2], ++ Anum_pg_seclabel_relid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(relid)); ++ ++ scan = systable_beginscan(rel, SecLabelSecidIndexId, true, ++ SnapshotToast, 3, skey); ++ tuple = systable_getnext(scan); ++ if (HeapTupleIsValid(tuple)) ++ { ++ Datum datum; ++ bool isnull; ++ ++ datum = heap_getattr(tuple, ++ Anum_pg_seclabel_label, ++ RelationGetDescr(rel), &isnull); ++ if (!isnull) ++ result = TextDatumGetCString(datum); ++ } ++ systable_endscan(scan); ++ ++ heap_close(rel, AccessShareLock); ++ ++ return result; ++} ++ ++Oid ++seclabelRawInput(Oid relid, char *seclabel) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ seclabel = sepgsql_rawlabel_in(seclabel); ++#endif ++ return inputSecurityLabel(relid, seclabel); ++} ++ ++char * ++seclabelRawOutput(Oid relid, Oid secid) ++{ ++ char *seclabel = outputSecurityLabel(relid, secid); ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ seclabel = sepgsql_rawlabel_out(seclabel); ++#endif ++ return seclabel; ++} ++ ++Oid ++seclabelTransInput(Oid relid, char *seclabel) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ seclabel = sepgsql_mcstrans_in(seclabel); ++#endif ++ return seclabelRawInput(relid, seclabel); ++} ++ ++char * ++seclabelTransOutput(Oid relid, Oid secid) ++{ ++ char *seclabel = seclabelRawOutput(relid, secid); ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ seclabel = sepgsql_mcstrans_out(seclabel); ++#endif ++ return seclabel; ++} ++ ++Oid ++seclabelMoveSecid(Oid dst_relid, Oid src_relid, Oid secid) ++{ ++ char *label = seclabelRawOutput(src_relid, secid); ++ ++ if (!label) ++ return InvalidOid; ++ ++ secid = seclabelRawInput(dst_relid, label); ++ ++ pfree(label); ++ ++ return secid; ++} ++ ++bool ++seclabelCompareSecid(Oid relid1, Oid secid1, Oid relid2, Oid secid2) ++{ ++ char *label1 = seclabelRawOutput(relid1, secid1); ++ char *label2 = seclabelRawOutput(relid2, secid2); ++ bool retval = false; ++ ++ if (label1 && label2 && strcmp(label1, label2) == 0) ++ retval = true; ++ else if (!label1 && !label2) ++ retval = false; ++ ++ if (label1) ++ pfree(label1); ++ if (label2) ++ pfree(label2); ++ ++ return retval; ++} ++ ++Datum ++seclabelSysattOutput(Oid relid, HeapTuple tuple) ++{ ++ Oid secid; ++ char *seclabel; ++ ++ secid = HeapTupleGetSecid(tuple); ++ ++ seclabel = seclabelTransOutput(relid, secid); ++ if (!seclabel) ++ seclabel = "unlabeled"; ++ ++ return CStringGetTextDatum(seclabel); ++} ++ ++/* ++ * seclabelRelationReclaim ++ * ++ * It reclaims security labels already referenced to. ++ * It has to be called under the VACUUM FULL context that means the relation ++ * to be reclaimed is already locked exclusively. ++ */ ++void ++seclabelRelationReclaim(Oid relOid) ++{ ++ StringInfoData query; ++ const char *nspname_reclaimed; ++ const char *relname_reclaimed; ++ const char *nspname_pg_seclabel; ++ const char *relname_pg_seclabel; ++ const char *attname_secid; ++ const char *attname_datid; ++ const char *attname_relid; ++ const char *attname_label; ++ const char *nspname_to_secid; ++ const char *proname_to_secid; ++ Oid databaseId; ++ Oid namespaceId; ++ int index; ++ int save_sepgsql_mode; ++ ++ if (SPI_connect() != SPI_OK_CONNECT) ++ elog(ERROR, "SPI_connect() failed"); ++ ++ /* ++ * DELETE orphan entries ++ */ ++ databaseId = (IsSharedRelation(relOid) ? InvalidOid : MyDatabaseId); ++ ++ namespaceId = get_rel_namespace(relOid); ++ nspname_reclaimed = get_namespace_name(namespaceId); ++ relname_reclaimed = get_rel_name(relOid); ++ ++ namespaceId = get_rel_namespace(SecLabelRelationId); ++ nspname_pg_seclabel = get_namespace_name(namespaceId); ++ relname_pg_seclabel = get_rel_name(SecLabelRelationId); ++ ++ attname_secid = get_attname(SecLabelRelationId, Anum_pg_seclabel_secid); ++ attname_datid = get_attname(SecLabelRelationId, Anum_pg_seclabel_datid); ++ attname_relid = get_attname(SecLabelRelationId, Anum_pg_seclabel_relid); ++ attname_label = get_attname(SecLabelRelationId, Anum_pg_seclabel_label); ++ ++ namespaceId = get_func_namespace(F_SECLABEL_TO_SECID); ++ nspname_to_secid = get_namespace_name(namespaceId); ++ proname_to_secid = get_func_name(F_SECLABEL_TO_SECID); ++ ++ initStringInfo(&query); ++ appendStringInfo(&query, ++ "DELETE FROM %s.%s " ++ "WHERE %s = %u AND %s = %u AND %s NOT IN " ++ "(SELECT %s.%s(%s) FROM ONLY %s.%s) " ++ "RETURNING %s,%s", ++ quote_identifier(nspname_pg_seclabel), ++ quote_identifier(relname_pg_seclabel), ++ quote_identifier(attname_datid), ++ databaseId, ++ quote_identifier(attname_relid), ++ relOid, ++ quote_identifier(attname_secid), ++ quote_identifier(nspname_to_secid), ++ quote_identifier(proname_to_secid), ++ quote_identifier(relname_reclaimed), ++ quote_identifier(nspname_reclaimed), ++ quote_identifier(relname_reclaimed), ++ quote_identifier(attname_secid), ++ quote_identifier(attname_label)); ++ /* ++ * Run the query ++ */ ++ elog(DEBUG1, "query: %s", query.data); ++ ++ save_sepgsql_mode = sepostgresql_mode; ++ ++ PG_TRY(); ++ { ++ sepostgresql_mode = SEPGSQL_MODE_INTERNAL; ++ ++ if (SPI_execute(query.data, false, 0) != SPI_OK_DELETE_RETURNING) ++ elog(ERROR, "Failed to run: %s", query.data); ++ } ++ PG_CATCH(); ++ { ++ sepostgresql_mode = save_sepgsql_mode; ++ ++ PG_RE_THROW(); ++ } ++ PG_END_TRY(); ++ ++ sepostgresql_mode = save_sepgsql_mode; ++ ++ for (index = 0; index < SPI_processed; index++) ++ { ++ HeapTuple tuple = SPI_tuptable->vals[index]; ++ char *label; ++ Oid secid; ++ Datum datum; ++ bool isnull; ++ ++ datum = heap_getattr(tuple, 1, SPI_tuptable->tupdesc, &isnull); ++ secid = (isnull ? InvalidOid : DatumGetObjectId(datum)); ++ ++ datum = heap_getattr(tuple, 2, SPI_tuptable->tupdesc, &isnull); ++ label = (isnull ? NULL : TextDatumGetCString(datum)); ++ ++ elog(DEBUG1, "seclabel: \"%s\"was reclaimed (secid=%u)", ++ label, secid); ++ } ++ ++ if (SPI_finish() != SPI_OK_FINISH) ++ elog(ERROR, "SPI_finish() failed"); ++} ++ ++Datum ++seclabel_to_secid(PG_FUNCTION_ARGS) ++{ ++ HeapTupleHeader htup = PG_GETARG_HEAPTUPLEHEADER(0); ++ ++ PG_RETURN_OID(HeapTupleHeaderGetSecid(htup)); ++} +diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c +index 76f9e06..0b4dcc3 100644 +--- a/src/backend/catalog/pg_type.c ++++ b/src/backend/catalog/pg_type.c +@@ -25,6 +25,7 @@ + #include "commands/typecmds.h" + #include "miscadmin.h" + #include "parser/scansup.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/fmgroids.h" +@@ -57,10 +58,17 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) + Datum values[Natts_pg_type]; + bool nulls[Natts_pg_type]; + Oid typoid; ++ Oid secid; + NameData name; + + Assert(PointerIsValid(typeName)); + ++ /* SELinux checks */ ++ secid = sepgsql_type_create(typeName, InvalidOid, ++ typeNamespace, TYPTYPE_PSEUDO, ++ F_SHELL_IN, F_SHELL_OUT, ++ InvalidOid, InvalidOid, ++ InvalidOid, InvalidOid, InvalidOid); + /* + * open pg_type + */ +@@ -126,6 +134,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) + binary_upgrade_next_pg_type_oid = InvalidOid; + } + ++ HeapTupleSetSecid(tup, secid); ++ + /* + * insert the tuple in the relation and get the tuple's oid. + */ +@@ -204,7 +214,8 @@ TypeCreate(Oid newTypeOid, + char storage, + int32 typeMod, + int32 typNDims, /* Array dimensions for baseType */ +- bool typeNotNull) ++ bool typeNotNull, ++ Oid securityId) + { + Relation pg_type_desc; + Oid typeObjectId; +@@ -389,6 +400,8 @@ TypeCreate(Oid newTypeOid, + */ + if (((Form_pg_type) GETSTRUCT(tup))->typowner != ownerId) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName); ++ if (HeapTupleGetSecid(tup) != securityId) ++ elog(ERROR, "Bug? security-id was mismatched"); + + /* trouble if caller wanted to force the OID */ + if (OidIsValid(newTypeOid)) +@@ -425,6 +438,8 @@ TypeCreate(Oid newTypeOid, + } + /* else allow system to assign oid */ + ++ HeapTupleSetSecid(tup, securityId); ++ + typeObjectId = simple_heap_insert(pg_type_desc, tup); + } + +diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c +index 435dfdd..5d86354 100644 +--- a/src/backend/catalog/toasting.c ++++ b/src/backend/catalog/toasting.c +@@ -24,6 +24,7 @@ + #include "catalog/namespace.h" + #include "catalog/pg_namespace.h" + #include "catalog/pg_opclass.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/pg_type.h" + #include "catalog/toasting.h" + #include "miscadmin.h" +@@ -127,6 +128,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio + int16 coloptions[2]; + ObjectAddress baseobject, + toastobject; ++ Oid *secLabels; + + /* + * Toast table is shared if and only if its parent is. +@@ -168,7 +170,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio + "pg_toast_%u_index", relOid); + + /* this is pretty painful... need a tuple descriptor */ +- tupdesc = CreateTemplateTupleDesc(3, false); ++ tupdesc = CreateTemplateTupleDesc(3, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, + "chunk_id", + OIDOID, +@@ -206,6 +208,11 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio + binary_upgrade_next_pg_type_toast_oid = InvalidOid; + } + ++ /* ++ * Toast inherits security-id from the heap relation ++ */ ++ secLabels = seclabelMakeToastDefaults(tupdesc, relOid); ++ + toast_relid = heap_create_with_catalog(toast_relname, + namespaceid, + rel->rd_rel->reltablespace, +@@ -223,7 +230,8 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio + ONCOMMIT_NOOP, + reloptions, + false, +- true); ++ true, ++ secLabels); + + /* make the toast relation visible, else index creation will fail */ + CommandCounterIncrement(); +diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c +index 4964fb3..390a1c1 100644 +--- a/src/backend/commands/aggregatecmds.c ++++ b/src/backend/commands/aggregatecmds.c +@@ -32,6 +32,7 @@ + #include "miscadmin.h" + #include "parser/parse_func.h" + #include "parser/parse_type.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/lsyscache.h" +@@ -307,6 +308,9 @@ RenameAggregate(List *name, List *args, const char *newname) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + ++ /* SELinux checks */ ++ sepgsql_proc_alter_rename(procOid, newname); ++ + /* rename */ + namestrcpy(&(((Form_pg_proc) GETSTRUCT(tup))->proname), newname); + simple_heap_update(rel, &tup->t_self, tup); +diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c +index 17e1e77..c1c8bfd 100644 +--- a/src/backend/commands/alter.c ++++ b/src/backend/commands/alter.c +@@ -289,3 +289,64 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt) + (int) stmt->objectType); + } + } ++ ++/* ++ * ExecAlterSecLabelStmt ++ * ++ * Execute ALTER xxx SECURITY LABEL TO statement ++ */ ++void ++ExecAlterSecLabelStmt(AlterSecLabelStmt *stmt) ++{ ++ const char *name; ++ char *seclabel; ++ ++ Assert(IsA(stmt->secLabel, String)); ++ seclabel = strVal(stmt->secLabel); ++ ++ switch (stmt->objectType) ++ { ++ case OBJECT_DATABASE: ++ name = strVal(linitial(stmt->object)); ++ AlterDatabaseSecLabel(name, seclabel); ++ break; ++ ++ case OBJECT_SCHEMA: ++ name = strVal(linitial(stmt->object)); ++ AlterSchemaSecLabel(name, seclabel); ++ break; ++ ++ case OBJECT_TABLE: ++ case OBJECT_SEQUENCE: ++ case OBJECT_VIEW: ++ case OBJECT_COLUMN: ++ AlterRelationSecLabel(stmt->relation, stmt->addname, ++ stmt->objectType, seclabel); ++ break; ++ ++ case OBJECT_AGGREGATE: ++ AlterFunctionSecLabel(stmt->object, stmt->objarg, true, seclabel); ++ break; ++ ++ case OBJECT_FUNCTION: ++ AlterFunctionSecLabel(stmt->object, stmt->objarg, false, seclabel); ++ break; ++ ++ case OBJECT_LARGEOBJECT: ++ LargeObjectAlterSecLabel(intVal(linitial(stmt->object)), seclabel); ++ break; ++ ++ case OBJECT_TYPE: ++ case OBJECT_DOMAIN: ++ AlterTypeSecLabel(stmt->object, seclabel); ++ break; ++ ++ case OBJECT_TABLESPACE: ++ AlterTableSpaceSecLabel(strVal(linitial(stmt->object)), seclabel); ++ break; ++ ++ default: ++ elog(ERROR, "unrecognized AlterSecLabelStmt type: %d", ++ (int) stmt->objectType); ++ } ++} +diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c +index 30a00ab..da39665 100644 +--- a/src/backend/commands/cluster.c ++++ b/src/backend/commands/cluster.c +@@ -30,12 +30,14 @@ + #include "catalog/indexing.h" + #include "catalog/namespace.h" + #include "catalog/pg_namespace.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/toasting.h" + #include "commands/cluster.h" + #include "commands/tablecmds.h" + #include "commands/trigger.h" + #include "commands/vacuum.h" + #include "miscadmin.h" ++#include "sepgsql/hooks.h" + #include "storage/bufmgr.h" + #include "storage/procarray.h" + #include "storage/smgr.h" +@@ -116,6 +118,9 @@ cluster(ClusterStmt *stmt, bool isTopLevel) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(rel)); + ++ /* SELinux checks */ ++ sepgsql_relation_cluster(tableOid, true); ++ + /* + * Reject clustering a remote temp table ... their local buffer + * manager is not going to cope. +@@ -290,7 +295,8 @@ cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose, + Form_pg_index indexForm; + + /* Check that the user still owns the relation */ +- if (!pg_class_ownercheck(tableOid, GetUserId())) ++ if (!pg_class_ownercheck(tableOid, GetUserId()) || ++ !sepgsql_relation_cluster(tableOid, false)) + { + relation_close(OldHeap, AccessExclusiveLock); + return; +@@ -632,6 +638,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace) + HeapTuple tuple; + Datum reloptions; + bool isNull; ++ Oid *secLabels; + + OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock); + OldHeapDesc = RelationGetDescr(OldHeap); +@@ -657,6 +664,11 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace) + reloptions = (Datum) 0; + + /* ++ * The new heap copies all the security-id from the original ++ */ ++ secLabels = seclabelMakeRelationDefaults(tupdesc, ++ list_make1_oid(OIDOldHeap)); ++ /* + * Create the new heap, using a temporary name in the same namespace as + * the existing table. NOTE: there is some risk of collision with user + * relnames. Working around this seems more trouble than it's worth; in +@@ -687,7 +699,8 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace) + ONCOMMIT_NOOP, + reloptions, + false, +- true); ++ true, ++ secLabels); + + ReleaseSysCache(tuple); + +@@ -994,6 +1007,9 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, + /* Preserve OID, if any */ + if (NewHeap->rd_rel->relhasoids) + HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple)); ++ /* Preserve security-id, if any */ ++ if (NewHeap->rd_rel->relhassecids) ++ HeapTupleSetSecid(copiedTuple, HeapTupleGetSecid(tuple)); + + /* The heap rewrite module does the rest */ + rewrite_heap_tuple(rwstate, tuple, copiedTuple); +@@ -1481,7 +1497,8 @@ get_tables_to_cluster(MemoryContext cluster_context) + { + index = (Form_pg_index) GETSTRUCT(indexTuple); + +- if (!pg_class_ownercheck(index->indrelid, GetUserId())) ++ if (!pg_class_ownercheck(index->indrelid, GetUserId()) || ++ !sepgsql_relation_cluster(index->indrelid, false)) + continue; + + /* +diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c +index 64792f2..6d71642 100644 +--- a/src/backend/commands/comment.c ++++ b/src/backend/commands/comment.c +@@ -49,6 +49,7 @@ + #include "parser/parse_func.h" + #include "parser/parse_oper.h" + #include "parser/parse_type.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/fmgroids.h" +@@ -548,6 +549,9 @@ CommentRelation(int objtype, List *relname, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(relation)); + ++ /* SELinux checks */ ++ sepgsql_relation_comment(RelationGetRelid(relation)); ++ + /* Next, verify that the relation type matches the intent */ + + switch (objtype) +@@ -651,6 +655,9 @@ CommentAttribute(List *qualname, char *comment) + errmsg("column \"%s\" of relation \"%s\" does not exist", + attrname, RelationGetRelationName(relation)))); + ++ /* SELinux checks */ ++ sepgsql_attribute_comment(RelationGetRelid(relation), attnum); ++ + /* Create the comment using the relation's oid */ + CreateComments(RelationGetRelid(relation), RelationRelationId, + (int32) attnum, comment); +@@ -704,6 +711,9 @@ CommentDatabase(List *qualname, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + database); + ++ /* SELinux checks */ ++ sepgsql_database_comment(oid); ++ + /* Call CreateSharedComments() to create/drop the comments */ + CreateSharedComments(oid, DatabaseRelationId, comment); + } +@@ -742,6 +752,9 @@ CommentTablespace(List *qualname, char *comment) + if (!pg_tablespace_ownercheck(oid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, tablespace); + ++ /* SELinux checks */ ++ sepgsql_tablespace_comment(oid); ++ + /* Call CreateSharedComments() to create/drop the comments */ + CreateSharedComments(oid, TableSpaceRelationId, comment); + } +@@ -774,6 +787,9 @@ CommentRole(List *qualname, char *comment) + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be member of role \"%s\" to comment upon it", role))); + ++ /* SELinux checks */ ++ sepgsql_role_comment(oid); ++ + /* Call CreateSharedComments() to create/drop the comments */ + CreateSharedComments(oid, AuthIdRelationId, comment); + } +@@ -810,6 +826,9 @@ CommentNamespace(List *qualname, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, + namespace); + ++ /* SELinux checks */ ++ sepgsql_schema_comment(oid); ++ + /* Call CreateComments() to create/drop the comments */ + CreateComments(oid, NamespaceRelationId, 0, comment); + } +@@ -919,6 +938,9 @@ CommentRule(List *qualname, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + get_rel_name(reloid)); + ++ /* SELinux checks */ ++ sepgsql_rule_comment(reloid, rulename); ++ + /* Call CreateComments() to create/drop the comments */ + CreateComments(ruleoid, RewriteRelationId, 0, comment); + +@@ -953,6 +975,9 @@ CommentType(List *typename, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, + format_type_be(oid)); + ++ /* SELinux checks */ ++ sepgsql_type_comment(oid); ++ + /* Call CreateComments() to create/drop the comments */ + CreateComments(oid, TypeRelationId, 0, comment); + } +@@ -977,6 +1002,9 @@ CommentAggregate(List *aggregate, List *arguments, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, + NameListToString(aggregate)); + ++ /* SELinux checks */ ++ sepgsql_proc_comment(oid); ++ + /* Call CreateComments() to create/drop the comments */ + CreateComments(oid, ProcedureRelationId, 0, comment); + } +@@ -1005,6 +1033,9 @@ CommentProc(List *function, List *arguments, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, + NameListToString(function)); + ++ /* SELinux checks */ ++ sepgsql_proc_comment(oid); ++ + /* Call CreateComments() to create/drop the comments */ + CreateComments(oid, ProcedureRelationId, 0, comment); + } +@@ -1036,6 +1067,9 @@ CommentOperator(List *opername, List *arguments, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER, + NameListToString(opername)); + ++ /* SELinux checks */ ++ sepgsql_operator_comment(oid); ++ + /* Call CreateComments() to create/drop the comments */ + CreateComments(oid, OperatorRelationId, 0, comment); + } +@@ -1080,6 +1114,9 @@ CommentTrigger(List *qualname, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(relation)); + ++ /* SELinux checks */ ++ sepgsql_trigger_comment(RelationGetRelid(relation), trigname); ++ + /* + * Fetch the trigger tuple from pg_trigger. There can be only one because + * of the unique index. +@@ -1153,6 +1190,9 @@ CommentConstraint(List *qualname, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(relation)); + ++ /* SELinux checks */ ++ sepgsql_constraint_comment(RelationGetRelid(relation), conName); ++ + conOid = GetConstraintByName(RelationGetRelid(relation), conName); + + /* Call CreateComments() to create/drop the comments */ +@@ -1188,6 +1228,9 @@ CommentConversion(List *qualname, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, + NameListToString(qualname)); + ++ /* SELinux checks */ ++ sepgsql_conversion_comment(conversionOid); ++ + /* Call CreateComments() to create/drop the comments */ + CreateComments(conversionOid, ConversionRelationId, 0, comment); + } +@@ -1304,6 +1347,9 @@ CommentOpClass(List *qualname, List *arguments, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, + NameListToString(qualname)); + ++ /* SELinux checks */ ++ sepgsql_opclass_comment(opcID); ++ + ReleaseSysCache(tuple); + + /* Call CreateComments() to create/drop the comments */ +@@ -1385,6 +1431,9 @@ CommentOpFamily(List *qualname, List *arguments, char *comment) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY, + NameListToString(qualname)); + ++ /* SELinux checks */ ++ sepgsql_opfamily_comment(opfID); ++ + ReleaseSysCache(tuple); + + /* Call CreateComments() to create/drop the comments */ +@@ -1505,6 +1554,9 @@ CommentCast(List *qualname, List *arguments, char *comment) + format_type_be(sourcetypeid), + format_type_be(targettypeid)))); + ++ /* SELinux checks */ ++ sepgsql_cast_comment(sourcetypeid, targettypeid); ++ + ReleaseSysCache(tuple); + + /* Call CreateComments() to create/drop the comments */ +@@ -1522,6 +1574,8 @@ CommentTSParser(List *qualname, char *comment) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to comment on text search parser"))); ++ /* SELinux checks */ ++ sepgsql_ts_parser_comment(prsId); + + CreateComments(prsId, TSParserRelationId, 0, comment); + } +@@ -1536,6 +1590,8 @@ CommentTSDictionary(List *qualname, char *comment) + if (!pg_ts_dict_ownercheck(dictId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY, + NameListToString(qualname)); ++ /* SELinux checks */ ++ sepgsql_ts_dict_comment(dictId); + + CreateComments(dictId, TSDictionaryRelationId, 0, comment); + } +@@ -1551,6 +1607,8 @@ CommentTSTemplate(List *qualname, char *comment) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to comment on text search template"))); ++ /* SELinux checks */ ++ sepgsql_ts_template_comment(tmplId); + + CreateComments(tmplId, TSTemplateRelationId, 0, comment); + } +@@ -1565,6 +1623,8 @@ CommentTSConfiguration(List *qualname, char *comment) + if (!pg_ts_config_ownercheck(cfgId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, + NameListToString(qualname)); ++ /* SELinux checks */ ++ sepgsql_ts_config_comment(cfgId); + + CreateComments(cfgId, TSConfigRelationId, 0, comment); + } +diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c +index 57ddab0..0c10a64 100644 +--- a/src/backend/commands/conversioncmds.c ++++ b/src/backend/commands/conversioncmds.c +@@ -24,6 +24,7 @@ + #include "mb/pg_wchar.h" + #include "miscadmin.h" + #include "parser/parse_func.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/lsyscache.h" +@@ -45,6 +46,7 @@ CreateConversionCommand(CreateConversionStmt *stmt) + int from_encoding; + int to_encoding; + Oid funcoid; ++ Oid secid; + const char *from_encoding_name = stmt->for_encoding_name; + const char *to_encoding_name = stmt->to_encoding_name; + List *func_name = stmt->func_name; +@@ -96,6 +98,10 @@ CreateConversionCommand(CreateConversionStmt *stmt) + aclcheck_error(aclresult, ACL_KIND_PROC, + NameListToString(func_name)); + ++ /* SELinux checks */ ++ secid = sepgsql_conversion_create(conversion_name, ++ namespaceId, funcoid); ++ + /* + * Check that the conversion function is suitable for the requested source + * and target encodings. We do that by calling the function with an empty +@@ -114,7 +120,7 @@ CreateConversionCommand(CreateConversionStmt *stmt) + * name) + */ + ConversionCreate(conversion_name, namespaceId, GetUserId(), +- from_encoding, to_encoding, funcoid, stmt->def); ++ from_encoding, to_encoding, funcoid, stmt->def, secid); + } + + /* +@@ -174,6 +180,9 @@ DropConversionsCommand(DropStmt *drop) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, + NameStr(con->conname)); + ++ /* SELinux checks */ ++ sepgsql_conversion_drop(conversionOid, false); ++ + object.classId = ConversionRelationId; + object.objectId = conversionOid; + object.objectSubId = 0; +@@ -235,6 +244,9 @@ RenameConversion(List *name, const char *newname) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + ++ /* SELinux checks */ ++ sepgsql_conversion_alter_rename(conversionOid, newname); ++ + /* rename */ + namestrcpy(&(((Form_pg_conversion) GETSTRUCT(tup))->conname), newname); + simple_heap_update(rel, &tup->t_self, tup); +@@ -329,6 +341,8 @@ AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(convForm->connamespace)); + } ++ /* SELinux checks */ ++ sepgsql_conversion_alter(HeapTupleGetOid(tup)); + + /* + * Modify the owner --- okay to scribble on tup because it's a copy +diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c +index 84a83f1..7cf7a89 100644 +--- a/src/backend/commands/copy.c ++++ b/src/backend/commands/copy.c +@@ -22,7 +22,10 @@ + + #include "access/heapam.h" + #include "access/xact.h" ++#include "access/sysattr.h" ++#include "catalog/heap.h" + #include "catalog/namespace.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/pg_type.h" + #include "commands/copy.h" + #include "commands/defrem.h" +@@ -35,6 +38,7 @@ + #include "optimizer/planner.h" + #include "parser/parse_relation.h" + #include "rewrite/rewriteHandler.h" ++#include "sepgsql/hooks.h" + #include "storage/fd.h" + #include "tcop/tcopprot.h" + #include "utils/acl.h" +@@ -161,6 +165,12 @@ typedef struct CopyStateData + char *raw_buf; + int raw_buf_index; /* next byte to process */ + int raw_buf_len; /* total # of bytes stored */ ++ ++ /* ++ * Dump/Restore support for security_label ++ */ ++ FmgrInfo seclabel_out_function; ++ bool seclabel_force_quot; + } CopyStateData; + + typedef CopyStateData *CopyState; +@@ -244,7 +254,7 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0"; + /* 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, HeapTuple tuple, + Datum *values, bool *nulls); + static void CopyFrom(CopyState cstate); + static bool CopyReadLine(CopyState cstate); +@@ -988,6 +998,10 @@ DoCopy(const CopyStmt *stmt, const char *queryString) + + if (stmt->relation) + { ++ Bitmapset *columnsSet = NULL; ++ List *attnums; ++ ListCell *cur; ++ + Assert(!stmt->query); + cstate->queryDesc = NULL; + +@@ -998,16 +1012,20 @@ DoCopy(const CopyStmt *stmt, const char *queryString) + tupDesc = RelationGetDescr(cstate->rel); + + /* Check relation permissions. */ ++ attnums = CopyGetAttnums(tupDesc, cstate->rel, attnamelist); ++ foreach(cur, attnums) ++ { ++ int index = lfirst_int(cur) ++ - FirstLowInvalidHeapAttributeNumber; ++ columnsSet = bms_add_member(columnsSet, index); ++ } ++ + relPerms = pg_class_aclmask(RelationGetRelid(cstate->rel), GetUserId(), + required_access, ACLMASK_ALL); + remainingPerms = required_access & ~relPerms; + if (remainingPerms != 0) + { + /* We don't have table permissions, check per-column permissions */ +- List *attnums; +- ListCell *cur; +- +- attnums = CopyGetAttnums(tupDesc, cstate->rel, attnamelist); + foreach(cur, attnums) + { + int attnum = lfirst_int(cur); +@@ -1021,6 +1039,13 @@ DoCopy(const CopyStmt *stmt, const char *queryString) + } + } + ++ if (is_from) ++ sepgsql_relation_perms(RelationGetRelid(cstate->rel), ++ ACL_INSERT, NULL, columnsSet, true); ++ else ++ sepgsql_relation_perms(RelationGetRelid(cstate->rel), ++ ACL_SELECT, columnsSet, NULL, true); ++ + /* check read-only transaction */ + if (XactReadOnly && is_from && !cstate->rel->rd_islocaltemp) + PreventCommandIfReadOnly("COPY FROM"); +@@ -1130,11 +1155,24 @@ DoCopy(const CopyStmt *stmt, const char *queryString) + int attnum = lfirst_int(cur); + + if (!list_member_int(cstate->attnumlist, attnum)) ++ { ++ Form_pg_attribute attForm; ++ ++ if (attnum > 0) ++ attForm = tupDesc->attrs[attnum - 1]; ++ else ++ attForm = SystemAttributeDefinition(attnum, true, true); ++ + ereport(ERROR, + (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), + errmsg("FORCE QUOTE column \"%s\" not referenced by COPY", +- NameStr(tupDesc->attrs[attnum - 1]->attname)))); +- cstate->force_quote_flags[attnum - 1] = true; ++ NameStr(attForm->attname)))); ++ } ++ ++ if (attnum == SecurityLabelAttributeNumber) ++ cstate->seclabel_force_quot = true; ++ else ++ cstate->force_quote_flags[attnum - 1] = true; + } + } + +@@ -1152,10 +1190,24 @@ DoCopy(const CopyStmt *stmt, const char *queryString) + int attnum = lfirst_int(cur); + + if (!list_member_int(cstate->attnumlist, attnum)) ++ { ++ Form_pg_attribute attForm; ++ ++ if (attnum > 0) ++ attForm = tupDesc->attrs[attnum - 1]; ++ else ++ attForm = SystemAttributeDefinition(attnum, ++ tupDesc->tdhasoid, ++ tupDesc->tdhassecid); ++ + ereport(ERROR, + (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), + errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY", +- NameStr(tupDesc->attrs[attnum - 1]->attname)))); ++ NameStr(attForm->attname)))); ++ } ++ /* ignore system columns, if specified */ ++ if (attnum <= 0) ++ continue; + cstate->force_notnull_flags[attnum - 1] = true; + } + } +@@ -1347,16 +1399,29 @@ CopyTo(CopyState cstate) + int attnum = lfirst_int(cur); + Oid out_func_oid; + bool isvarlena; ++ FmgrInfo *out_fmgr; ++ Form_pg_attribute attForm; ++ ++ if (attnum == SecurityLabelAttributeNumber) ++ { ++ attForm = SystemAttributeDefinition(attnum, true, true); ++ out_fmgr = &cstate->seclabel_out_function; ++ } ++ else ++ { ++ attForm = attr[attnum - 1]; ++ out_fmgr = &cstate->out_functions[attnum - 1]; ++ } + + if (cstate->binary) +- getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid, ++ getTypeBinaryOutputInfo(attForm->atttypid, + &out_func_oid, + &isvarlena); + else +- getTypeOutputInfo(attr[attnum - 1]->atttypid, ++ getTypeOutputInfo(attForm->atttypid, + &out_func_oid, + &isvarlena); +- fmgr_info(out_func_oid, &cstate->out_functions[attnum - 1]); ++ fmgr_info(out_func_oid, out_fmgr); + } + + /* +@@ -1411,7 +1476,17 @@ CopyTo(CopyState cstate) + CopySendChar(cstate, cstate->delim[0]); + hdr_delim = true; + +- colname = NameStr(attr[attnum - 1]->attname); ++ if (SystemAttributeWritable(attnum, ++ tupDesc->tdhasoid, ++ tupDesc->tdhassecid)) ++ { ++ Form_pg_attribute attForm ++ = SystemAttributeDefinition(attnum, true, true); ++ ++ colname = NameStr(attForm->attname); ++ } ++ else ++ colname = NameStr(attr[attnum - 1]->attname); + + CopyAttributeOutCSV(cstate, colname, false, + list_length(cstate->attnumlist) == 1); +@@ -1441,7 +1516,7 @@ CopyTo(CopyState cstate) + heap_deform_tuple(tuple, tupDesc, values, nulls); + + /* Format and send the data */ +- CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls); ++ CopyOneRowTo(cstate, tuple, values, nulls); + } + + heap_endscan(scandesc); +@@ -1467,13 +1542,17 @@ CopyTo(CopyState cstate) + * Emit one row during CopyTo(). + */ + static void +-CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) ++CopyOneRowTo(CopyState cstate, HeapTuple tuple, Datum *values, bool *nulls) + { + bool need_delim = false; + FmgrInfo *out_functions = cstate->out_functions; + MemoryContext oldcontext; + ListCell *cur; + char *string; ++ Oid tupleOid = InvalidOid; ++ ++ if (HeapTupleIsValid(tuple)) ++ tupleOid = HeapTupleGetOid(tuple); + + MemoryContextReset(cstate->rowcontext); + oldcontext = MemoryContextSwitchTo(cstate->rowcontext); +@@ -1506,8 +1585,10 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) + 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) + { +@@ -1516,6 +1597,21 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) + need_delim = true; + } + ++ if (attnum == SecurityLabelAttributeNumber) ++ { ++ value = seclabelSysattOutput(RelationGetRelid(cstate->rel), tuple); ++ isnull = false; ++ force_quot = cstate->seclabel_force_quot; ++ out_fmgr = &cstate->seclabel_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) +@@ -1527,11 +1623,9 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) + { + 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); +@@ -1540,8 +1634,7 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) + { + 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); +@@ -1675,8 +1768,10 @@ CopyFrom(CopyState cstate) + num_defaults; + FmgrInfo *in_functions; + FmgrInfo oid_in_function; ++ FmgrInfo seclabel_in_function; + Oid *typioparams; + Oid oid_typioparam; ++ Oid seclabel_typioparam; + int attnum; + int i; + Oid in_func_oid; +@@ -1919,6 +2014,19 @@ CopyFrom(CopyState cstate) + fmgr_info(in_func_oid, &oid_in_function); + } + ++ if (list_member_int(cstate->attnumlist, SecurityLabelAttributeNumber)) ++ { ++ if (!cstate->binary) ++ getTypeInputInfo(TEXTOID, &in_func_oid, &seclabel_typioparam); ++ else ++ getTypeBinaryInputInfo(TEXTOID, &in_func_oid, &seclabel_typioparam); ++ ++ fmgr_info(in_func_oid, &seclabel_in_function); ++ } ++ ++ ++ ++ + values = (Datum *) palloc(num_phys_attrs * sizeof(Datum)); + nulls = (bool *) palloc(num_phys_attrs * sizeof(bool)); + +@@ -1953,6 +2061,7 @@ CopyFrom(CopyState cstate) + { + bool skip_tuple; + Oid loaded_oid = InvalidOid; ++ Oid loaded_secid = InvalidOid; + + CHECK_FOR_INTERRUPTS(); + +@@ -2024,14 +2133,20 @@ CopyFrom(CopyState cstate) + /* Loop to read the user attributes on the line. */ + foreach(cur, cstate->attnumlist) + { ++ Form_pg_attribute attForm; + int attnum = lfirst_int(cur); + int m = attnum - 1; + ++ if (attnum == SecurityLabelAttributeNumber) ++ attForm = SystemAttributeDefinition(attnum, true, true); ++ else ++ attForm = attr[m]; ++ + if (fieldno >= fldct) + ereport(ERROR, + (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), + errmsg("missing data for column \"%s\"", +- NameStr(attr[m]->attname)))); ++ NameStr(attForm->attname)))); + string = field_strings[fieldno++]; + + if (cstate->csv_mode && string == NULL && +@@ -2041,14 +2156,38 @@ CopyFrom(CopyState cstate) + string = cstate->null_print; + } + +- cstate->cur_attname = NameStr(attr[m]->attname); ++ cstate->cur_attname = NameStr(attForm->attname); + cstate->cur_attval = string; +- values[m] = InputFunctionCall(&in_functions[m], +- string, +- typioparams[m], +- attr[m]->atttypmod); +- if (string != NULL) +- nulls[m] = false; ++ ++ if (attnum == SecurityLabelAttributeNumber) ++ { ++ if (string && !ignore_security_label_input) ++ { ++ Datum datum = InputFunctionCall(&seclabel_in_function, ++ string, ++ seclabel_typioparam, ++ attForm->atttypmod); ++ loaded_secid ++ = seclabelTransInput(RelationGetRelid(cstate->rel), ++ TextDatumGetCString(datum)); ++ } ++ } ++ else ++ { ++ if (cstate->csv_mode && string == NULL && ++ cstate->force_notnull_flags[m]) ++ { ++ /* Go ahead and read the NULL string */ ++ string = cstate->null_print; ++ } ++ ++ values[m] = InputFunctionCall(&in_functions[m], ++ string, ++ typioparams[m], ++ attForm->atttypmod); ++ if (string != NULL) ++ nulls[m] = false; ++ } + cstate->cur_attname = NULL; + cstate->cur_attval = NULL; + } +@@ -2094,17 +2233,38 @@ CopyFrom(CopyState cstate) + i = 0; + foreach(cur, cstate->attnumlist) + { ++ Form_pg_attribute attForm; + int attnum = lfirst_int(cur); + int m = attnum - 1; + +- cstate->cur_attname = NameStr(attr[m]->attname); ++ if (attnum == SecurityLabelAttributeNumber) ++ attForm = SystemAttributeDefinition(attnum, true, true); ++ else ++ attForm = attr[m]; ++ ++ cstate->cur_attname = NameStr(attForm->attname); + i++; +- values[m] = CopyReadBinaryAttribute(cstate, +- i, +- &in_functions[m], +- typioparams[m], +- attr[m]->atttypmod, +- &nulls[m]); ++ ++ if (attnum == SecurityLabelAttributeNumber) ++ { ++ Datum datum = CopyReadBinaryAttribute(cstate, i, ++ &seclabel_in_function, ++ seclabel_typioparam, ++ attForm->atttypmod, ++ &isnull); ++ if (!isnull && !ignore_security_label_input) ++ loaded_secid ++ = seclabelTransInput(RelationGetRelid(cstate->rel), ++ TextDatumGetCString(datum)); ++ } ++ else ++ { ++ values[m] = CopyReadBinaryAttribute(cstate, i, ++ &in_functions[m], ++ typioparams[m], ++ attr[m]->atttypmod, ++ &nulls[m]); ++ } + cstate->cur_attname = NULL; + } + } +@@ -2125,6 +2285,8 @@ CopyFrom(CopyState cstate) + + if (cstate->oids && file_has_oids) + HeapTupleSetOid(tuple, loaded_oid); ++ if (HeapTupleHasSecid(tuple)) ++ HeapTupleSetSecid(tuple, loaded_secid); + + /* Triggers and stuff need to be invoked in query context. */ + MemoryContextSwitchTo(oldcontext); +@@ -2149,6 +2311,9 @@ CopyFrom(CopyState cstate) + } + + if (!skip_tuple) ++ sepgsql_tuple_insert(cstate->rel, tuple); ++ ++ if (!skip_tuple) + { + List *recheckIndexes = NIL; + +@@ -3442,6 +3607,17 @@ CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist) + } + if (attnum == InvalidAttrNumber) + { ++ Form_pg_attribute attForm; ++ bool hasoid = tupDesc->tdhasoid; ++ bool hassecid = tupDesc->tdhassecid; ++ ++ attForm = SystemAttributeByName(name, hasoid, hassecid); ++ if (attForm && ++ SystemAttributeWritable(attForm->attnum, hasoid, hassecid)) ++ attnum = attForm->attnum; ++ } ++ if (attnum == InvalidAttrNumber) ++ { + if (rel != NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), +@@ -3489,7 +3665,7 @@ copy_dest_receive(TupleTableSlot *slot, DestReceiver *self) + slot_getallattrs(slot); + + /* And send the data */ +- CopyOneRowTo(cstate, InvalidOid, slot->tts_values, slot->tts_isnull); ++ CopyOneRowTo(cstate, slot->tts_tuple, slot->tts_values, slot->tts_isnull); + } + + /* +diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c +index e7dac22..16360db 100644 +--- a/src/backend/commands/dbcommands.c ++++ b/src/backend/commands/dbcommands.c +@@ -35,6 +35,8 @@ + #include "catalog/pg_authid.h" + #include "catalog/pg_database.h" + #include "catalog/pg_db_role_setting.h" ++#include "catalog/pg_seclabel.h" ++#include "catalog/pg_shdescription.h" + #include "catalog/pg_tablespace.h" + #include "commands/comment.h" + #include "commands/dbcommands.h" +@@ -43,6 +45,7 @@ + #include "miscadmin.h" + #include "pgstat.h" + #include "postmaster/bgwriter.h" ++#include "sepgsql/hooks.h" + #include "storage/bufmgr.h" + #include "storage/fd.h" + #include "storage/lmgr.h" +@@ -111,6 +114,7 @@ createdb(const CreatedbStmt *stmt) + Datum new_record[Natts_pg_database]; + bool new_record_nulls[Natts_pg_database]; + Oid dboid; ++ Oid dbsecid; + Oid datdba; + ListCell *option; + DefElem *dtablespacename = NULL; +@@ -486,6 +490,9 @@ createdb(const CreatedbStmt *stmt) + /* Note there is no additional permission check in this path */ + } + ++ /* SELinux permission checks */ ++ dbsecid = sepgsql_database_create(dbname, src_dboid); ++ + /* + * Check for db name conflict. This is just to give a more friendly error + * message than "unique index violation". There's a race condition but +@@ -560,6 +567,8 @@ createdb(const CreatedbStmt *stmt) + new_record, new_record_nulls); + + HeapTupleSetOid(tuple, dboid); ++ if (HeapTupleHasSecid(tuple)) ++ HeapTupleSetSecid(tuple, dbsecid); + + simple_heap_insert(pg_database_rel, tuple); + +@@ -576,6 +585,9 @@ createdb(const CreatedbStmt *stmt) + /* Create pg_shdepend entries for objects within database */ + copyTemplateDependencies(src_dboid, dboid); + ++ /* Create pg_seclabel entries for objects within database */ ++ seclabelOnCreateDatabase(src_dboid, dboid); ++ + /* + * Force a checkpoint before starting the copy. This will force dirty + * buffers out to disk, to ensure source database is up-to-date on disk +@@ -777,6 +789,9 @@ dropdb(const char *dbname, bool missing_ok) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + dbname); + ++ /* SELinux checks */ ++ sepgsql_database_drop(db_id, false); ++ + /* + * Disallow dropping a DB that is marked istemplate. This is just to + * prevent people from accidentally dropping template0 or template1; they +@@ -833,6 +848,11 @@ dropdb(const char *dbname, bool missing_ok) + dropDatabaseDependencies(db_id); + + /* ++ * Remove pg_seclabel entries for the database ++ */ ++ seclabelOnDropDatabase(db_id); ++ ++ /* + * Drop pages for this database that are in the shared buffer cache. This + * is important to ensure that no remaining backend tries to write out a + * dirty buffer to the dead database later... +@@ -915,6 +935,9 @@ RenameDatabase(const char *oldname, const char *newname) + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to rename database"))); + ++ /* SELinux checks */ ++ sepgsql_database_alter(db_id); ++ + /* + * Make sure the new name doesn't exist. See notes for same error in + * CREATE DATABASE. +@@ -1053,6 +1076,9 @@ movedb(const char *dbname, const char *tblspcname) + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_global cannot be used as default tablespace"))); + ++ /* SELinux checks */ ++ sepgsql_database_alter(db_id); ++ + /* + * No-op if same tablespace + */ +@@ -1369,6 +1395,9 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + stmt->dbname); + ++ /* SELinux checks */ ++ sepgsql_database_alter(HeapTupleGetOid(tuple)); ++ + /* + * Build an updated tuple, perusing the information just obtained + */ +@@ -1419,6 +1448,9 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + stmt->dbname); + ++ /* SELinux checks */ ++ sepgsql_database_alter(datid); ++ + AlterSetting(datid, InvalidOid, stmt->setstmt); + + UnlockSharedObject(DatabaseRelationId, datid, 0, AccessShareLock); +@@ -1494,6 +1526,9 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId) + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to change owner of database"))); + ++ /* SELinux checks */ ++ sepgsql_database_alter(HeapTupleGetOid(tuple)); ++ + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + +@@ -1533,6 +1568,58 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId) + heap_close(rel, NoLock); + } + ++/* ++ * ALTER DATABASE SECURITY LABEL TO ++ */ ++void ++AlterDatabaseSecLabel(const char *dbname, char *new_label) ++{ ++ Relation rel; ++ HeapTuple oldtup; ++ HeapTuple newtup; ++ ScanKeyData skey; ++ SysScanDesc scan; ++ Oid databaseId; ++ Oid securityId; ++ ++ /* Fetch the old tuple */ ++ rel = heap_open(DatabaseRelationId, RowExclusiveLock); ++ ScanKeyInit(&skey, ++ Anum_pg_database_datname, ++ BTEqualStrategyNumber, F_NAMEEQ, ++ NameGetDatum(dbname)); ++ scan = systable_beginscan(rel, DatabaseNameIndexId, true, ++ SnapshotNow, 1, &skey); ++ oldtup = systable_getnext(scan); ++ if (!HeapTupleIsValid(oldtup)) ++ ereport(ERROR, ++ (errcode(ERRCODE_UNDEFINED_DATABASE), ++ errmsg("database \"%s\" does not exist", dbname))); ++ ++ newtup = heap_copytuple(oldtup); ++ ++ systable_endscan(scan); ++ ++ databaseId = HeapTupleGetOid(newtup); ++ ++ /* DAC permission checks */ ++ if (!pg_database_ownercheck(databaseId, GetUserId())) ++ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname); ++ ++ /* SELinux checks */ ++ securityId = sepgsql_database_relabel(databaseId, new_label); ++ ++ /* Update it */ ++ HeapTupleSetSecid(newtup, securityId); ++ ++ simple_heap_update(rel, &newtup->t_self, newtup); ++ ++ CatalogUpdateIndexes(rel, newtup); ++ ++ heap_freetuple(newtup); ++ ++ heap_close(rel, RowExclusiveLock); ++} + + /* + * Helper functions +diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c +index 0bda24a..334b123 100644 +--- a/src/backend/commands/explain.c ++++ b/src/backend/commands/explain.c +@@ -257,7 +257,7 @@ ExplainResultDesc(ExplainStmt *stmt) + } + + /* Need a tuple descriptor representing a single TEXT or XML column */ +- tupdesc = CreateTemplateTupleDesc(1, false); ++ tupdesc = CreateTemplateTupleDesc(1, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN", + xml ? XMLOID : TEXTOID, -1, 0); + return tupdesc; +diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c +index 14356a2..d1f255e 100644 +--- a/src/backend/commands/foreigncmds.c ++++ b/src/backend/commands/foreigncmds.c +@@ -27,6 +27,7 @@ + #include "foreign/foreign.h" + #include "miscadmin.h" + #include "parser/parse_func.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/lsyscache.h" +@@ -230,6 +231,9 @@ AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId) + fdwId = HeapTupleGetOid(tup); + form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup); + ++ /* SELinux checks */ ++ sepgsql_fdw_alter(fdwId, InvalidOid); ++ + if (form->fdwowner != newOwnerId) + { + form->fdwowner = newOwnerId; +@@ -294,6 +298,8 @@ AlterForeignServerOwner(const char *name, Oid newOwnerId) + aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname); + } + } ++ /* SELinux checks */ ++ sepgsql_fserver_alter(srvId); + + form->srvowner = newOwnerId; + +@@ -339,6 +345,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) + Oid fdwvalidator; + Datum fdwoptions; + Oid ownerId; ++ Oid securityId; + + /* Must be super user */ + if (!superuser()) +@@ -391,8 +398,13 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) + else + nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true; + ++ /* SELinux checks */ ++ securityId = sepgsql_fdw_create(stmt->fdwname, fdwvalidator); ++ + tuple = heap_form_tuple(rel->rd_att, values, nulls); + ++ HeapTupleSetSecid(tuple, securityId); ++ + fdwId = simple_heap_insert(rel, tuple); + CatalogUpdateIndexes(rel, tuple); + +@@ -511,6 +523,8 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) + + repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true; + } ++ /* SELinux checks */ ++ sepgsql_fdw_alter(fdwId, fdwvalidator); + + /* Everything looks good - update the tuple */ + +@@ -559,6 +573,8 @@ RemoveForeignDataWrapper(DropFdwStmt *stmt) + stmt->fdwname))); + return; + } ++ /* SELinux checks */ ++ sepgsql_fdw_drop(fdwId, false); + + /* + * Do the deletion +@@ -608,6 +624,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt) + HeapTuple tuple; + Oid srvId; + Oid ownerId; ++ Oid securityId; + AclResult aclresult; + ObjectAddress myself; + ObjectAddress referenced; +@@ -635,6 +652,9 @@ CreateForeignServer(CreateForeignServerStmt *stmt) + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname); + ++ /* SELinux checks */ ++ securityId = sepgsql_fserver_create(stmt->servername, fdw->fdwid); ++ + /* + * Insert tuple into pg_foreign_server. + */ +@@ -678,6 +698,8 @@ CreateForeignServer(CreateForeignServerStmt *stmt) + + tuple = heap_form_tuple(rel->rd_att, values, nulls); + ++ HeapTupleSetSecid(tuple, securityId); ++ + srvId = simple_heap_insert(rel, tuple); + + CatalogUpdateIndexes(rel, tuple); +@@ -732,6 +754,9 @@ AlterForeignServer(AlterForeignServerStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER, + stmt->servername); + ++ /* SELinux checks */ ++ sepgsql_fserver_alter(srvId); ++ + memset(repl_val, 0, sizeof(repl_val)); + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); +@@ -823,6 +848,8 @@ RemoveForeignServer(DropForeignServerStmt *stmt) + if (!pg_foreign_server_ownercheck(srvId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER, + stmt->servername); ++ /* SELinux checks */ ++ sepgsql_fserver_drop(srvId, false); + + object.classId = ForeignServerRelationId; + object.objectId = srvId; +@@ -896,6 +923,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt) + HeapTuple tuple; + Oid useId; + Oid umId; ++ Oid securityId; + ObjectAddress myself; + ObjectAddress referenced; + ForeignServer *srv; +@@ -908,6 +936,9 @@ CreateUserMapping(CreateUserMappingStmt *stmt) + + user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername); + ++ /* SELinux checks */ ++ securityId = sepgsql_user_mapping_create(useId, srv->serverid); ++ + /* + * Check that the user mapping is unique within server. + */ +@@ -947,6 +978,8 @@ CreateUserMapping(CreateUserMappingStmt *stmt) + + tuple = heap_form_tuple(rel->rd_att, values, nulls); + ++ HeapTupleSetSecid(tuple, securityId); ++ + umId = simple_heap_insert(rel, tuple); + + CatalogUpdateIndexes(rel, tuple); +@@ -1000,6 +1033,9 @@ AlterUserMapping(AlterUserMappingStmt *stmt) + + user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername); + ++ /* SELinux checks */ ++ sepgsql_user_mapping_alter(umId); ++ + tp = SearchSysCacheCopy1(USERMAPPINGOID, ObjectIdGetDatum(umId)); + + if (!HeapTupleIsValid(tp)) +@@ -1114,6 +1150,9 @@ RemoveUserMapping(DropUserMappingStmt *stmt) + + user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername); + ++ /* SELinux checks */ ++ sepgsql_user_mapping_drop(umId, false); ++ + /* + * Do the deletion + */ +diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c +index 9a584ed..f914280 100644 +--- a/src/backend/commands/functioncmds.c ++++ b/src/backend/commands/functioncmds.c +@@ -43,6 +43,7 @@ + #include "catalog/pg_namespace.h" + #include "catalog/pg_proc.h" + #include "catalog/pg_proc_fn.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/pg_type.h" + #include "catalog/pg_type_fn.h" + #include "commands/defrem.h" +@@ -53,6 +54,7 @@ + #include "parser/parse_expr.h" + #include "parser/parse_func.h" + #include "parser/parse_type.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/fmgroids.h" +@@ -788,6 +790,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) + ArrayType *parameterNames; + List *parameterDefaults; + Oid requiredResultType; ++ Oid replacedFunc = InvalidOid; ++ Oid prosecid; + bool isWindowFunc, + isStrict, + security; +@@ -933,6 +937,18 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) + errmsg("ROWS is not applicable when function does not return a set"))); + + /* ++ * SELinux checks ++ */ ++ if (stmt->replace) ++ replacedFunc = GetSysCacheOid3(PROCNAMEARGSNSP, ++ PointerGetDatum(funcname), ++ PointerGetDatum(parameterTypes), ++ ObjectIdGetDatum(namespaceId)); ++ ++ prosecid = sepgsql_proc_create(funcname, replacedFunc, ++ namespaceId, languageOid); ++ ++ /* + * And now that we have all the parameters, and know we're permitted to do + * so, go ahead and create the function. + */ +@@ -957,7 +973,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) + parameterDefaults, + PointerGetDatum(proconfig), + procost, +- prorows); ++ prorows, ++ prosecid); + } + + +@@ -999,6 +1016,9 @@ RemoveFunction(RemoveFuncStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, + NameListToString(functionName)); + ++ /* SELinux checks */ ++ sepgsql_proc_drop(funcOid, false); ++ + if (((Form_pg_proc) GETSTRUCT(tup))->proisagg) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), +@@ -1135,6 +1155,9 @@ RenameFunction(List *name, List *argtypes, const char *newname) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + ++ /* SELinux checks */ ++ sepgsql_proc_alter_rename(procOid, newname); ++ + /* rename */ + namestrcpy(&(procForm->proname), newname); + simple_heap_update(rel, &tup->t_self, tup); +@@ -1239,6 +1262,8 @@ AlterFunctionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(procForm->pronamespace)); + } ++ /* SELinux checks */ ++ sepgsql_proc_alter(procOid); + + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); +@@ -1277,6 +1302,49 @@ AlterFunctionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) + } + + /* ++ * ALTER FUNCTION f(...) SECURITY LABEL TO ++ */ ++void ++AlterFunctionSecLabel(List *name, List *argtypes, bool isagg, char *new_label) ++{ ++ Relation rel; ++ HeapTuple tuple; ++ Oid procOid; ++ Oid securityId; ++ ++ /* open pg_proc system catalog */ ++ rel = heap_open(ProcedureRelationId, RowExclusiveLock); ++ ++ /* get function OID */ ++ if (isagg) ++ procOid = LookupAggNameTypeNames(name, argtypes, false); ++ else ++ procOid = LookupFuncNameTypeNames(name, argtypes, false); ++ ++ tuple = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for function %u", procOid); ++ ++ /* Must be owner */ ++ if (!pg_proc_ownercheck(procOid, GetUserId())) ++ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, ++ get_func_name(procOid)); ++ ++ /* SELinux checks */ ++ securityId = sepgsql_proc_relabel(procOid, new_label); ++ ++ /* Update it */ ++ HeapTupleSetSecid(tuple, securityId); ++ ++ simple_heap_update(rel, &tuple->t_self, tuple); ++ CatalogUpdateIndexes(rel, tuple); ++ ++ heap_freetuple(tuple); ++ ++ heap_close(rel, RowExclusiveLock); ++} ++ ++/* + * Implements the ALTER FUNCTION utility command (except for the + * RENAME and OWNER clauses, which are handled as part of the generic + * ALTER framework). +@@ -1313,6 +1381,9 @@ AlterFunction(AlterFunctionStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, + NameListToString(stmt->func->funcname)); + ++ /* SELinux checks */ ++ sepgsql_proc_alter(funcOid); ++ + if (procForm->proisagg) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), +@@ -1659,6 +1730,9 @@ CreateCast(CreateCastStmt *stmt) + errmsg("array data types are not binary-compatible"))); + } + ++ /* SELinux checks */ ++ sepgsql_cast_create(sourcetypeid, targettypeid, castmethod, funcid); ++ + /* + * Allow source and target types to be same only for length coercion + * functions. We assume a multi-arg function does length coercion. +@@ -1795,6 +1869,9 @@ DropCast(DropCastStmt *stmt) + format_type_be(sourcetypeid), + format_type_be(targettypeid)))); + ++ /* SELinux checks */ ++ sepgsql_cast_drop(sourcetypeid, targettypeid, false); ++ + /* + * Do the deletion + */ +@@ -1873,6 +1950,9 @@ AlterFunctionNamespace(List *name, List *argtypes, bool isagg, + /* get schema OID and check its permissions */ + nspOid = LookupCreationNamespace(newschema); + ++ /* SELinux checks */ ++ sepgsql_proc_alter_schema(procOid, nspOid); ++ + if (oldNspOid == nspOid) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_FUNCTION), +diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c +index 94657b8..7cb3634 100644 +--- a/src/backend/commands/indexcmds.c ++++ b/src/backend/commands/indexcmds.c +@@ -39,6 +39,7 @@ + #include "parser/parse_func.h" + #include "parser/parse_oper.h" + #include "parser/parsetree.h" ++#include "sepgsql/hooks.h" + #include "storage/lmgr.h" + #include "storage/proc.h" + #include "storage/procarray.h" +@@ -242,6 +243,10 @@ DefineIndex(RangeVar *heapRelation, + get_tablespace_name(tablespaceId)); + } + ++ /* SELinux checks */ ++ if (check_rights) ++ sepgsql_index_create(relationId, namespaceId); ++ + /* + * Force shared indexes into the pg_global tablespace. This is a bit of a + * hack but seems simpler than marking them in the BKI commands. On the +@@ -363,7 +368,9 @@ DefineIndex(RangeVar *heapRelation, + errmsg("primary keys cannot be expressions"))); + + /* System attributes are never null, so no problem */ +- if (SystemAttributeByName(key->name, rel->rd_rel->relhasoids)) ++ if (SystemAttributeByName(key->name, ++ rel->rd_rel->relhasoids, ++ rel->rd_rel->relhassecids)) + continue; + + atttuple = SearchSysCacheAttName(relationId, key->name); +@@ -1572,6 +1579,9 @@ ReindexIndex(RangeVar *indexRelation) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + indexRelation->relname); + ++ /* SELinux checks */ ++ sepgsql_index_reindex(indOid); ++ + ReleaseSysCache(tuple); + + reindex_index(indOid, false); +@@ -1604,6 +1614,9 @@ ReindexTable(RangeVar *relation) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + relation->relname); + ++ /* SELinux checks */ ++ sepgsql_relation_reindex(heapOid); ++ + ReleaseSysCache(tuple); + + if (!reindex_relation(heapOid, true, false)) +@@ -1642,6 +1655,9 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + databaseName); + ++ /* SELinux checks */ ++ sepgsql_database_reindex(MyDatabaseId); ++ + /* + * Create a memory context that will survive forced transaction commits we + * do below. Since it is a child of PortalContext, it will go away +diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c +index 283947a..657ff95 100644 +--- a/src/backend/commands/lockcmds.c ++++ b/src/backend/commands/lockcmds.c +@@ -20,6 +20,7 @@ + #include "commands/lockcmds.h" + #include "miscadmin.h" + #include "parser/parse_clause.h" ++#include "sepgsql/hooks.h" + #include "storage/lmgr.h" + #include "utils/acl.h" + #include "utils/lsyscache.h" +@@ -149,6 +150,9 @@ LockTableRecurse(Oid reloid, RangeVar *rv, + errmsg("\"%s\" is not a table", + RelationGetRelationName(rel)))); + ++ /* SELinux checks */ ++ sepgsql_relation_lock(rel); ++ + /* + * If requested, recurse to children. We use find_inheritance_children + * not find_all_inheritors to avoid taking locks far in advance of +diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c +index ac0270f..25b84fd 100644 +--- a/src/backend/commands/opclasscmds.c ++++ b/src/backend/commands/opclasscmds.c +@@ -35,6 +35,7 @@ + #include "parser/parse_func.h" + #include "parser/parse_oper.h" + #include "parser/parse_type.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/fmgroids.h" +@@ -164,7 +165,8 @@ OpClassCacheLookup(Oid amID, List *opclassname) + * Caller must have done permissions checks etc. already. + */ + static Oid +-CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid) ++CreateOpFamily(char *amname, char *opfname, ++ Oid namespaceoid, Oid amoid, Oid securityId) + { + Oid opfamilyoid; + Relation rel; +@@ -204,6 +206,8 @@ CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid) + + tup = heap_form_tuple(rel->rd_att, values, nulls); + ++ HeapTupleSetSecid(tup, securityId); ++ + opfamilyoid = simple_heap_insert(rel, tup); + + CatalogUpdateIndexes(rel, tup); +@@ -369,11 +373,16 @@ DefineOpClass(CreateOpClassStmt *stmt) + } + else + { ++ Oid securityId; ++ ++ /* SELinux checks */ ++ securityId = sepgsql_opfamily_create(opcname, namespaceoid, amoid); ++ + /* + * Create it ... again no need for more permissions ... + */ + opfamilyoid = CreateOpFamily(stmt->amname, opcname, +- namespaceoid, amoid); ++ namespaceoid, amoid, securityId); + } + } + +@@ -505,6 +514,12 @@ DefineOpClass(CreateOpClassStmt *stmt) + stmt->amname))); + } + ++ /* SELinux checks */ ++ sepgsql_opfamily_alter(opfamilyoid, false, amoid, ++ operators, procedures); ++ sepgsql_opclass_create(opcname, namespaceoid, ++ typeoid, opfamilyoid, storageoid); ++ + rel = heap_open(OperatorClassRelationId, RowExclusiveLock); + + /* +@@ -650,6 +665,7 @@ DefineOpFamily(CreateOpFamilyStmt *stmt) + NameData opfName; + ObjectAddress myself, + referenced; ++ Oid securityId; + + /* Convert list of names to a name and namespace */ + namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname, +@@ -701,6 +717,9 @@ DefineOpFamily(CreateOpFamilyStmt *stmt) + errmsg("operator family \"%s\" for access method \"%s\" already exists", + opfname, stmt->amname))); + ++ /* SELinux checks */ ++ securityId = sepgsql_opfamily_create(opfname, namespaceoid, amoid); ++ + /* + * Okay, let's create the pg_opfamily entry. + */ +@@ -715,6 +734,8 @@ DefineOpFamily(CreateOpFamilyStmt *stmt) + + tup = heap_form_tuple(rel->rd_att, values, nulls); + ++ HeapTupleSetSecid(tup, securityId); ++ + opfamilyoid = simple_heap_insert(rel, tup); + + CatalogUpdateIndexes(rel, tup); +@@ -925,6 +946,9 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid, + break; + } + } ++ /* SELinux checks */ ++ sepgsql_opfamily_alter(opfamilyoid, false, amoid, ++ operators, procedures); + + /* + * Add tuples to pg_amop and pg_amproc tying in the operators and +@@ -1002,6 +1026,9 @@ AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid, + } + } + ++ /* SELinux checks */ ++ sepgsql_opfamily_alter(opfamilyoid, true, amoid, operators, procedures); ++ + /* + * Remove tuples from pg_amop and pg_amproc. + */ +@@ -1522,6 +1549,9 @@ RemoveOpClass(RemoveOpClassStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, + NameListToString(stmt->opclassname)); + ++ /* SELinux checks */ ++ sepgsql_opclass_drop(opcID, false); ++ + ReleaseSysCache(tuple); + + /* +@@ -1583,6 +1613,9 @@ RemoveOpFamily(RemoveOpFamilyStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY, + NameListToString(stmt->opfamilyname)); + ++ /* SELinux checks */ ++ sepgsql_opfamily_drop(opfID, false); ++ + ReleaseSysCache(tuple); + + /* +@@ -1781,6 +1814,9 @@ RenameOpClass(List *name, const char *access_method, const char *newname) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + ++ /* SELinux checks */ ++ sepgsql_opclass_alter_rename(opcOid, newname); ++ + /* rename */ + namestrcpy(&(((Form_pg_opclass) GETSTRUCT(tup))->opcname), newname); + simple_heap_update(rel, &tup->t_self, tup); +@@ -1875,6 +1911,9 @@ RenameOpFamily(List *name, const char *access_method, const char *newname) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + ++ /* SELinux checks */ ++ sepgsql_opfamily_alter_rename(opfOid, newname); ++ + /* rename */ + namestrcpy(&(((Form_pg_opfamily) GETSTRUCT(tup))->opfname), newname); + simple_heap_update(rel, &tup->t_self, tup); +@@ -1990,6 +2029,8 @@ AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + } ++ /* SELinux checks */ ++ sepgsql_opclass_alter(HeapTupleGetOid(tup)); + + /* + * Modify the owner --- okay to scribble on tup because it's a copy +@@ -2112,7 +2153,8 @@ AlterOpFamilyOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + } +- ++ /* SELinux checks */ ++ sepgsql_opfamily_alter_owner(HeapTupleGetOid(tup), newOwnerId); + /* + * Modify the owner --- okay to scribble on tup because it's a copy + */ +diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c +index 9c07cf3..2e19448 100644 +--- a/src/backend/commands/operatorcmds.c ++++ b/src/backend/commands/operatorcmds.c +@@ -45,6 +45,7 @@ + #include "parser/parse_func.h" + #include "parser/parse_oper.h" + #include "parser/parse_type.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/lsyscache.h" + #include "utils/rel.h" +@@ -319,6 +320,9 @@ RemoveOperator(RemoveFuncStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER, + NameListToString(operatorName)); + ++ /* SELinux checks */ ++ sepgsql_operator_drop(operOid, false); ++ + ReleaseSysCache(tup); + + /* +@@ -426,6 +430,8 @@ AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(oprForm->oprnamespace)); + } ++ /* SELinux checks */ ++ sepgsql_operator_alter(operOid); + + /* + * Modify the owner --- okay to scribble on tup because it's a copy +diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c +index e765382..a54dd3f 100644 +--- a/src/backend/commands/prepare.c ++++ b/src/backend/commands/prepare.c +@@ -759,7 +759,7 @@ pg_prepared_statement(PG_FUNCTION_ARGS) + * build tupdesc for result tuples. This must match the definition of the + * pg_prepared_statements view in system_views.sql + */ +- tupdesc = CreateTemplateTupleDesc(5, false); ++ tupdesc = CreateTemplateTupleDesc(5, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement", +diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c +index 633a093..a3375b2 100644 +--- a/src/backend/commands/proclang.c ++++ b/src/backend/commands/proclang.c +@@ -29,6 +29,7 @@ + #include "miscadmin.h" + #include "parser/parse_func.h" + #include "parser/parser.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/fmgroids.h" +@@ -145,7 +146,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) + NIL, + PointerGetDatum(NULL), + 1, +- 0); ++ 0, ++ InvalidOid); + } + + /* +@@ -180,7 +182,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) + NIL, + PointerGetDatum(NULL), + 1, +- 0); ++ 0, ++ InvalidOid); + } + } + else +@@ -218,7 +221,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) + NIL, + PointerGetDatum(NULL), + 1, +- 0); ++ 0, ++ InvalidOid); + } + } + else +diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c +index b0a9a22..57951fe 100644 +--- a/src/backend/commands/schemacmds.c ++++ b/src/backend/commands/schemacmds.c +@@ -21,10 +21,12 @@ + #include "catalog/indexing.h" + #include "catalog/namespace.h" + #include "catalog/pg_namespace.h" ++#include "catalog/pg_seclabel.h" + #include "commands/dbcommands.h" + #include "commands/schemacmds.h" + #include "miscadmin.h" + #include "parser/parse_utilcmd.h" ++#include "sepgsql/hooks.h" + #include "tcop/utility.h" + #include "utils/acl.h" + #include "utils/builtins.h" +@@ -49,6 +51,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) + Oid owner_uid; + Oid saved_uid; + int save_sec_context; ++ Oid secid; + AclResult aclresult; + + GetUserIdAndSecContext(&saved_uid, &save_sec_context); +@@ -75,6 +78,9 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) + + check_is_member_of_role(saved_uid, owner_uid); + ++ /* SELinux checks */ ++ secid = sepgsql_schema_create(schemaName, false); ++ + /* Additional check to protect reserved schema names */ + if (!allowSystemTableMods && IsReservedName(schemaName)) + ereport(ERROR, +@@ -95,7 +101,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) + save_sec_context | SECURITY_LOCAL_USERID_CHANGE); + + /* Create the schema's namespace */ +- namespaceId = NamespaceCreate(schemaName, owner_uid); ++ namespaceId = NamespaceCreate(schemaName, owner_uid, secid); + + /* Advance cmd counter to make the namespace visible */ + CommandCounterIncrement(); +@@ -204,6 +210,9 @@ RemoveSchemas(DropStmt *drop) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, + namespaceName); + ++ /* SELinux checks */ ++ sepgsql_schema_drop(namespaceId, false); ++ + object.classId = NamespaceRelationId; + object.objectId = namespaceId; + object.objectSubId = 0; +@@ -288,6 +297,9 @@ RenameSchema(const char *oldname, const char *newname) + errmsg("unacceptable schema name \"%s\"", newname), + errdetail("The prefix \"pg_\" is reserved for system schemas."))); + ++ /* SELinux checks */ ++ sepgsql_schema_alter(HeapTupleGetOid(tup)); ++ + /* rename */ + namestrcpy(&(((Form_pg_namespace) GETSTRUCT(tup))->nspname), newname); + simple_heap_update(rel, &tup->t_self, tup); +@@ -389,6 +401,9 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId) + aclcheck_error(aclresult, ACL_KIND_DATABASE, + get_database_name(MyDatabaseId)); + ++ /* SELinux checks */ ++ sepgsql_schema_alter(HeapTupleGetOid(tup)); ++ + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + +@@ -423,3 +438,43 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId) + } + + } ++ ++/* ++ * ALTER SCHEMA SECURITY LABEL TO ++ */ ++void ++AlterSchemaSecLabel(const char *name, char *new_label) ++{ ++ Relation rel; ++ HeapTuple tuple; ++ Oid namespaceId; ++ Oid securityId; ++ ++ /* open pg_namespace relation */ ++ rel = heap_open(NamespaceRelationId, RowExclusiveLock); ++ tuple = SearchSysCacheCopy1(NAMESPACENAME, ++ CStringGetDatum(name)); ++ if (!HeapTupleIsValid(tuple)) ++ ereport(ERROR, ++ (errcode(ERRCODE_UNDEFINED_SCHEMA), ++ errmsg("schema \"%s\" does not exist", name))); ++ namespaceId = HeapTupleGetOid(tuple); ++ ++ /* DAC permission check */ ++ if (!pg_namespace_ownercheck(namespaceId, GetUserId())) ++ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, name); ++ ++ /* SELinux checks */ ++ securityId = sepgsql_schema_relabel(namespaceId, new_label); ++ ++ /* Update it */ ++ HeapTupleSetSecid(tuple, securityId); ++ ++ simple_heap_update(rel, &tuple->t_self, tuple); ++ ++ CatalogUpdateIndexes(rel, tuple); ++ ++ heap_freetuple(tuple); ++ ++ heap_close(rel, RowExclusiveLock); ++} +diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c +index f52e1d8..ecff05d 100644 +--- a/src/backend/commands/sequence.c ++++ b/src/backend/commands/sequence.c +@@ -26,6 +26,7 @@ + #include "commands/tablecmds.h" + #include "miscadmin.h" + #include "nodes/makefuncs.h" ++#include "sepgsql/hooks.h" + #include "storage/bufmgr.h" + #include "storage/lmgr.h" + #include "storage/proc.h" +@@ -331,6 +332,9 @@ AlterSequence(AlterSeqStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + stmt->sequence->relname); + ++ /* SELinux checks */ ++ sepgsql_relation_alter(relid); ++ + /* do the work */ + AlterSequenceInternal(relid, stmt->options); + } +@@ -469,6 +473,9 @@ nextval_internal(Oid relid) + errmsg("permission denied for sequence %s", + RelationGetRelationName(seqrel)))); + ++ /* SELinux checks */ ++ sepgsql_sequence_next_value(elm->relid); ++ + /* read-only transactions may only modify temp sequences */ + if (!seqrel->rd_islocaltemp) + PreventCommandIfReadOnly("nextval()"); +@@ -668,6 +675,9 @@ currval_oid(PG_FUNCTION_ARGS) + errmsg("permission denied for sequence %s", + RelationGetRelationName(seqrel)))); + ++ /* SELinux checks */ ++ sepgsql_sequence_get_value(elm->relid); ++ + if (!elm->last_valid) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), +@@ -710,6 +720,9 @@ lastval(PG_FUNCTION_ARGS) + errmsg("permission denied for sequence %s", + RelationGetRelationName(seqrel)))); + ++ /* SELinux checks */ ++ sepgsql_sequence_get_value(last_used_seq->relid); ++ + result = last_used_seq->last; + relation_close(seqrel, NoLock); + +@@ -746,6 +759,9 @@ do_setval(Oid relid, int64 next, bool iscalled) + errmsg("permission denied for sequence %s", + RelationGetRelationName(seqrel)))); + ++ /* SELinux checks */ ++ sepgsql_sequence_set_value(elm->relid); ++ + /* read-only transactions may only modify temp sequences */ + if (!seqrel->rd_islocaltemp) + PreventCommandIfReadOnly("setval()"); +diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c +index 25b2807..cbe483b 100644 +--- a/src/backend/commands/tablecmds.c ++++ b/src/backend/commands/tablecmds.c +@@ -32,6 +32,7 @@ + #include "catalog/pg_inherits_fn.h" + #include "catalog/pg_namespace.h" + #include "catalog/pg_opclass.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/pg_tablespace.h" + #include "catalog/pg_trigger.h" + #include "catalog/pg_type.h" +@@ -62,12 +63,14 @@ + #include "parser/parser.h" + #include "rewrite/rewriteDefine.h" + #include "rewrite/rewriteHandler.h" ++#include "sepgsql/hooks.h" + #include "storage/bufmgr.h" + #include "storage/lmgr.h" + #include "storage/smgr.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/fmgroids.h" ++#include "utils/guc.h" + #include "utils/inval.h" + #include "utils/lsyscache.h" + #include "utils/memutils.h" +@@ -223,7 +226,7 @@ static const struct dropmsgstrings dropmsgstringarray[] = { + + static void truncate_check_rel(Relation rel); + static List *MergeAttributes(List *schema, List *supers, bool istemp, +- List **supOids, List **supconstr, int *supOidCount); ++ List **supOids, List **supconstr, int *supOidCount, int *supSecidCount); + static bool MergeCheckConstraint(List *constraints, char *name, Node *expr); + static bool change_varattnos_walker(Node *node, const AttrNumber *newattno); + static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel); +@@ -271,10 +274,12 @@ static void ATOneLevelRecursion(List **wqueue, Relation rel, + static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, + AlterTableCmd *cmd); + static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel, +- ColumnDef *colDef, bool isOid); ++ ColumnDef *colDef, bool isOid, bool isSecid); + static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid); + static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse, + AlterTableCmd *cmd); ++static void ATPrepAddSecLabel(List **wqueue, Relation rel, bool recurse, ++ AlterTableCmd *cmd); + static void ATExecDropNotNull(Relation rel, const char *colName); + static void ATExecSetNotNull(AlteredTableInfo *tab, Relation rel, + const char *colName); +@@ -355,6 +360,7 @@ DefineRelation(CreateStmt *stmt, char relkind) + List *old_constraints; + bool localHasOids; + int parentOidCount; ++ int parentSecidCount; + List *rawDefaults; + List *cookedDefaults; + Datum reloptions; +@@ -362,6 +368,7 @@ DefineRelation(CreateStmt *stmt, char relkind) + AttrNumber attnum; + static char *validnsps[] = HEAP_RELOPT_NAMESPACES; + Oid ofTypeId; ++ Oid *secLabels; + + /* + * Truncate relname to appropriate length (probably a waste of time, as +@@ -461,7 +468,8 @@ DefineRelation(CreateStmt *stmt, char relkind) + */ + schema = MergeAttributes(schema, stmt->inhRelations, + stmt->relation->istemp, +- &inheritOids, &old_constraints, &parentOidCount); ++ &inheritOids, &old_constraints, ++ &parentOidCount, &parentSecidCount); + + /* + * Create a tuple descriptor from the relation schema. Note that this +@@ -473,6 +481,16 @@ DefineRelation(CreateStmt *stmt, char relkind) + localHasOids = interpretOidsOption(stmt->options); + descriptor->tdhasoid = (localHasOids || parentOidCount > 0); + ++ if ((relkind == RELKIND_RELATION && default_with_secids) || parentSecidCount > 0) ++ descriptor->tdhassecid = true; ++ ++ /* SELinux permission checks */ ++ secLabels = sepgsql_relation_create(relname, ++ relkind, ++ descriptor, ++ namespaceId, ++ inheritOids, ++ false); + /* + * Find columns with default values and prepare for insertion of the + * defaults. Pre-cooked (that is, inherited) defaults go into a list of +@@ -546,7 +564,8 @@ DefineRelation(CreateStmt *stmt, char relkind) + stmt->oncommit, + reloptions, + true, +- allowSystemTableMods); ++ allowSystemTableMods, ++ secLabels); + + StoreCatalogInheritance(relationId, inheritOids); + +@@ -755,6 +774,9 @@ RemoveRelations(DropStmt *drop) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + rel->relname); + ++ /* SELinux checks */ ++ sepgsql_relation_drop(relOid, false); ++ + if (!allowSystemTableMods && IsSystemClass(classform)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), +@@ -918,6 +940,9 @@ ExecuteTruncate(TruncateStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(seq_rel)); + ++ /* SELinux checks */ ++ sepgsql_relation_alter(seq_relid); ++ + seq_relids = lappend_oid(seq_relids, seq_relid); + + relation_close(seq_rel, NoLock); +@@ -1086,6 +1111,8 @@ truncate_check_rel(Relation rel) + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_CLASS, + RelationGetRelationName(rel)); ++ /* SELinux checks */ ++ sepgsql_relation_truncate(rel); + + if (!allowSystemTableMods && IsSystemRelation(rel)) + ereport(ERROR, +@@ -1146,6 +1173,7 @@ storage_name(char c) + * 'supconstr' receives a list of constraints belonging to the parents, + * updated as necessary to be valid for the child. + * 'supOidCount' is set to the number of parents that have OID columns. ++ * 'supSecidCount' is set to the number of parents that have SID columns. + * + * Return value: + * Completed schema list. +@@ -1191,13 +1219,15 @@ storage_name(char c) + */ + static List * + MergeAttributes(List *schema, List *supers, bool istemp, +- List **supOids, List **supconstr, int *supOidCount) ++ List **supOids, List **supconstr, ++ int *supOidCount, int *supSecidCount) + { + ListCell *entry; + List *inhSchema = NIL; + List *parentOids = NIL; + List *constraints = NIL; + int parentsWithOids = 0; ++ int parentsWithSecids = 0; + bool have_bogus_defaults = false; + int child_attno; + static Node bogus_marker = {0}; /* marks conflicting defaults */ +@@ -1325,6 +1355,8 @@ MergeAttributes(List *schema, List *supers, bool istemp, + + if (relation->rd_rel->relhasoids) + parentsWithOids++; ++ if (relation->rd_rel->relhassecids) ++ parentsWithSecids++; + + tupleDesc = RelationGetDescr(relation); + constr = tupleDesc->constr; +@@ -1626,6 +1658,7 @@ MergeAttributes(List *schema, List *supers, bool istemp, + *supOids = parentOids; + *supconstr = constraints; + *supOidCount = parentsWithOids; ++ *supSecidCount = parentsWithSecids; + return schema; + } + +@@ -1985,6 +2018,9 @@ renameatt(Oid myrelid, + errmsg("permission denied: \"%s\" is a system catalog", + RelationGetRelationName(targetrelation)))); + ++ /* SELinux checks */ ++ sepgsql_attribute_alter(myrelid, oldattname); ++ + /* + * if the 'recurse' flag is set then we are supposed to rename this + * attribute in all classes that inherit from 'relname' (as well as in +@@ -2136,6 +2172,9 @@ RenameRelation(Oid myrelid, const char *newrelname, ObjectType reltype) + errmsg("\"%s\" is not a view", + RelationGetRelationName(targetrelation)))); + ++ /* SELinux checks */ ++ sepgsql_relation_alter_rename(myrelid, newrelname); ++ + /* + * Don't allow ALTER TABLE on composite types. We want people to use ALTER + * TYPE for that. +@@ -2566,6 +2605,27 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, + } + pass = AT_PASS_DROP; + break; ++ case AT_AddSecLabel: ++ ATSimplePermissions(rel, false); ++ /* Performs own recursion */ ++ if (!rel->rd_rel->relhassecids || recursing) ++ ATPrepAddSecLabel(wqueue, rel, recurse, cmd); ++ pass = AT_PASS_ADD_COL; ++ break; ++ case AT_DropSecLabel: ++ ATSimplePermissions(rel, false); ++ /* Performs own recursion */ ++ if (rel->rd_rel->relhassecids) ++ { ++ AlterTableCmd *dropCmd = makeNode(AlterTableCmd); ++ ++ dropCmd->subtype = AT_DropColumn; ++ dropCmd->name = pstrdup("security_label"); ++ dropCmd->behavior = cmd->behavior; ++ ATPrepCmd(wqueue, rel, dropCmd, recurse, false); ++ } ++ pass = AT_PASS_DROP; ++ break; + case AT_SetTableSpace: /* SET TABLESPACE */ + ATSimplePermissionsRelationOrIndex(rel); + /* This command never recurses */ +@@ -2690,7 +2750,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, + case AT_AddColumn: /* ADD COLUMN */ + case AT_AddColumnToView: /* add column via CREATE OR REPLACE + * VIEW */ +- ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, false); ++ ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, false, false); + break; + case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */ + ATExecColumnDefault(rel, cmd->name, cmd->def); +@@ -2762,17 +2822,22 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, + case AT_AddOids: /* SET WITH OIDS */ + /* Use the ADD COLUMN code, unless prep decided to do nothing */ + if (cmd->def != NULL) +- ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, true); ++ ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, true, false); ++ break; ++ case AT_AddSecLabel: /* SET WITH SECURITY LABEL */ ++ /* Use the ADD COLUMN code, unless prep decided to do nothing */ ++ if (cmd->def != NULL) ++ ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, false, true); + break; + case AT_DropOids: /* SET WITHOUT OIDS */ +- ++ case AT_DropSecLabel: /* SET WITHOUT SECURITY LABEL */ + /* + * Nothing to do here; we'll have generated a DropColumn + * subcommand to do the real work + */ + break; + case AT_SetTableSpace: /* SET TABLESPACE */ +- ++ sepgsql_relation_alter(RelationGetRelid(rel)); + /* + * Nothing to do here; Phase 3 does the work + */ +@@ -3126,6 +3191,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) + MemoryContext oldCxt; + List *dropped_attrs = NIL; + ListCell *lc; ++ Oid tupSecidInherit = InvalidOid; + + econtext = GetPerTupleExprContext(estate); + +@@ -3156,6 +3222,19 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) + } + + /* ++ * If this routine is called due to ALTER TABLE SET WITH SECURITY LABEL, ++ * security label of the relation shall be assigned tuples. ++ */ ++ if (!oldTupDesc->tdhassecid && newTupDesc->tdhassecid) ++ { ++ Oid relSecid = GetSysCacheSecid1(RELOID, ++ ObjectIdGetDatum(tab->relid)); ++ ++ tupSecidInherit = seclabelMoveSecid(RelationGetRelid(oldrel), ++ RelationRelationId, relSecid); ++ } ++ ++ /* + * Scan through the rows, generating a new row if needed and then + * checking all the constraints. + */ +@@ -3172,11 +3251,16 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) + if (newrel) + { + Oid tupOid = InvalidOid; ++ Oid tupSecid = InvalidOid; + + /* Extract data from old tuple */ + heap_deform_tuple(tuple, oldTupDesc, values, isnull); + if (oldTupDesc->tdhasoid) + tupOid = HeapTupleGetOid(tuple); ++ if (oldTupDesc->tdhassecid) ++ tupSecid = HeapTupleGetSecid(tuple); ++ else ++ tupSecid = tupSecidInherit; + + /* Set dropped attributes to null in new tuple */ + foreach(lc, dropped_attrs) +@@ -3208,6 +3292,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) + /* Preserve OID, if any */ + if (newTupDesc->tdhasoid) + HeapTupleSetOid(tuple, tupOid); ++ /* Preserve security-id, if any */ ++ if (newTupDesc->tdhassecid) ++ HeapTupleSetSecid(tuple, tupSecid); + } + + /* Now check any constraints on the possibly-changed tuple */ +@@ -3608,7 +3695,7 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, + + static void + ATExecAddColumn(AlteredTableInfo *tab, Relation rel, +- ColumnDef *colDef, bool isOid) ++ ColumnDef *colDef, bool isOid, bool isSecid) + { + Oid myrelid = RelationGetRelid(rel); + Relation pgclass, +@@ -3622,12 +3709,16 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, + int32 typmod; + Form_pg_type tform; + Expr *defval; ++ Oid securityId; + + if (rel->rd_rel->reloftype) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot add column to typed table"))); + ++ /* SELinux permission check */ ++ securityId = sepgsql_attribute_create(myrelid, colDef->colname); ++ + attrdesc = heap_open(AttributeRelationId, RowExclusiveLock); + + /* +@@ -3655,6 +3746,13 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, + errmsg("child table \"%s\" has different type for column \"%s\"", + RelationGetRelationName(rel), colDef->colname))); + ++ if (!seclabelCompareSecid(AttributeRelationId, securityId, ++ AttributeRelationId, HeapTupleGetSecid(tuple))) ++ ereport(ERROR, ++ (errcode(ERRCODE_DATATYPE_MISMATCH), ++ errmsg("child table \"%s\" has different label for column \"%s\"", ++ RelationGetRelationName(rel), colDef->colname))); ++ + /* If it's OID, child column must actually be OID */ + if (isOid && childatt->attnum != ObjectIdAttributeNumber) + ereport(ERROR, +@@ -3662,6 +3760,13 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, + errmsg("child table \"%s\" has a conflicting \"%s\" column", + RelationGetRelationName(rel), colDef->colname))); + ++ /* If it's SecID, child column must actually be SecID */ ++ if (isSecid && childatt->attnum != SecurityLabelAttributeNumber) ++ ereport(ERROR, ++ (errcode(ERRCODE_DATATYPE_MISMATCH), ++ errmsg("child table \"%s\" has a conflicting \"%s\" column", ++ RelationGetRelationName(rel), colDef->colname))); ++ + /* Bump the existing child att's inhcount */ + childatt->attinhcount++; + simple_heap_update(attrdesc, &tuple->t_self, tuple); +@@ -3701,6 +3806,8 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, + /* Determine the new attribute's number */ + if (isOid) + newattnum = ObjectIdAttributeNumber; ++ else if (isSecid) ++ newattnum = SecurityLabelAttributeNumber; + else + { + newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1; +@@ -3740,7 +3847,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, + + ReleaseSysCache(typeTuple); + +- InsertPgAttributeTuple(attrdesc, &attribute, NULL); ++ InsertPgAttributeTuple(attrdesc, &attribute, NULL, securityId); + + heap_close(attrdesc, RowExclusiveLock); + +@@ -3749,6 +3856,8 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, + */ + if (isOid) + ((Form_pg_class) GETSTRUCT(reltup))->relhasoids = true; ++ else if (isSecid) ++ ((Form_pg_class) GETSTRUCT(reltup))->relhassecids = true; + else + ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum; + +@@ -3860,7 +3969,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, + * If we are adding an OID column, we have to tell Phase 3 to rewrite the + * table to fix that. + */ +- if (isOid) ++ if (isOid || isSecid) + tab->new_changeoids = true; + + /* +@@ -3913,6 +4022,31 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd) + } + + /* ++ * ALTER TABLE SET WITH SECURITY LABEL ++ * ++ * Basically this is an ADD COLUMN for the special SecLabel column. ++ * We have to cons up a ColumnDef node because the ADD COLUMN code needs one. ++ */ ++static void ++ATPrepAddSecLabel(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd) ++{ ++ /* If we're recursing to a child table, the ColumnDef is already set up */ ++ if (cmd->def == NULL) ++ { ++ ColumnDef *cdef = makeNode(ColumnDef); ++ ++ cdef->colname = pstrdup("security_label"); ++ cdef->typeName = makeTypeNameFromOid(TEXTOID, -1); ++ cdef->inhcount = 0; ++ cdef->is_local = true; ++ cdef->is_not_null = true; ++ cdef->storage = 0; ++ cmd->def = (Node *) cdef; ++ } ++ ATPrepAddColumn(wqueue, rel, recurse, cmd); ++} ++ ++/* + * ALTER TABLE ALTER COLUMN DROP NOT NULL + */ + static void +@@ -3924,6 +4058,9 @@ ATExecDropNotNull(Relation rel, const char *colName) + List *indexoidlist; + ListCell *indexoidscan; + ++ /* SELinux checks */ ++ sepgsql_attribute_alter(RelationGetRelid(rel), colName); ++ + /* + * lookup the attribute + */ +@@ -4014,6 +4151,9 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel, + AttrNumber attnum; + Relation attr_rel; + ++ /* SELinux checks */ ++ sepgsql_attribute_alter(RelationGetRelid(rel), colName); ++ + /* + * lookup the attribute + */ +@@ -4064,6 +4204,9 @@ ATExecColumnDefault(Relation rel, const char *colName, + { + AttrNumber attnum; + ++ /* SELinux checks */ ++ sepgsql_attribute_alter(RelationGetRelid(rel), colName); ++ + /* + * get the number of the attribute + */ +@@ -4138,6 +4281,9 @@ ATExecSetStatistics(Relation rel, const char *colName, Node *newValue) + HeapTuple tuple; + Form_pg_attribute attrtuple; + ++ /* SELinux checks */ ++ sepgsql_attribute_alter(RelationGetRelid(rel), colName); ++ + Assert(IsA(newValue, Integer)); + newtarget = intVal(newValue); + +@@ -4204,6 +4350,9 @@ ATExecSetOptions(Relation rel, const char *colName, Node *options, + bool repl_null[Natts_pg_attribute]; + bool repl_repl[Natts_pg_attribute]; + ++ /* SELinux checks */ ++ sepgsql_attribute_alter(RelationGetRelid(rel), colName); ++ + attrelation = heap_open(AttributeRelationId, RowExclusiveLock); + + tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName); +@@ -4263,6 +4412,9 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue) + HeapTuple tuple; + Form_pg_attribute attrtuple; + ++ /* SELinux checks */ ++ sepgsql_attribute_alter(RelationGetRelid(rel), colName); ++ + Assert(IsA(newValue, String)); + storagemode = strVal(newValue); + +@@ -4353,6 +4505,9 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, + if (recursing) + ATSimplePermissions(rel, false); + ++ /* SELinux checks */ ++ sepgsql_attribute_drop(RelationGetRelid(rel), colName, false); ++ + /* + * get the number of the attribute + */ +@@ -4378,8 +4533,10 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, + + attnum = targetatt->attnum; + +- /* Can't drop a system attribute, except OID */ +- if (attnum <= 0 && attnum != ObjectIdAttributeNumber) ++ /* Can't drop a system attribute, except OID/SecID */ ++ if (attnum <= 0 && ++ attnum != ObjectIdAttributeNumber && ++ attnum != SecurityLabelAttributeNumber) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot drop system column \"%s\"", +@@ -4495,7 +4652,8 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, + * If we dropped the OID column, must adjust pg_class.relhasoids and tell + * Phase 3 to physically get rid of the column. + */ +- if (attnum == ObjectIdAttributeNumber) ++ if (attnum == ObjectIdAttributeNumber || ++ attnum == SecurityLabelAttributeNumber) + { + Relation class_rel; + Form_pg_class tuple_class; +@@ -4510,7 +4668,11 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, + RelationGetRelid(rel)); + tuple_class = (Form_pg_class) GETSTRUCT(tuple); + +- tuple_class->relhasoids = false; ++ if (attnum == ObjectIdAttributeNumber) ++ tuple_class->relhasoids = false; ++ if (attnum == SecurityLabelAttributeNumber) ++ tuple_class->relhassecids = false; ++ + simple_heap_update(class_rel, &tuple->t_self, tuple); + + /* Keep the catalog indexes up to date */ +@@ -4657,6 +4819,9 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, + if (recursing) + ATSimplePermissions(rel, false); + ++ /* SELinux checks */ ++ sepgsql_relation_alter(RelationGetRelid(rel)); ++ + /* + * Call AddRelationNewConstraints to do the work, making sure it works on + * a copy of the Constraint so transformExpr can't modify the original. It +@@ -4854,6 +5019,9 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, + checkFkeyPermissions(pkrel, pkattnum, numpks); + checkFkeyPermissions(rel, fkattnum, numfks); + ++ /* SELinux checks */ ++ sepgsql_relation_alter(RelationGetRelid(rel)); ++ + /* + * Look up the equality operators to use in the constraint. + * +@@ -5599,6 +5767,9 @@ ATExecDropConstraint(Relation rel, const char *constrName, + if (recursing) + ATSimplePermissions(rel, false); + ++ /* SELinux checks */ ++ sepgsql_relation_alter(RelationGetRelid(rel)); ++ + conrel = heap_open(ConstraintRelationId, RowExclusiveLock); + + /* +@@ -5931,6 +6102,9 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, + SysScanDesc scan; + HeapTuple depTup; + ++ /* SELinux checks */ ++ sepgsql_attribute_alter(RelationGetRelid(rel), colName); ++ + attrelation = heap_open(AttributeRelationId, RowExclusiveLock); + + /* Look up the target column */ +@@ -6544,6 +6718,8 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + } ++ /* SELinux checks */ ++ sepgsql_relation_alter(relationOid); + } + + memset(repl_null, false, sizeof(repl_null)); +@@ -6709,6 +6885,9 @@ ATExecClusterOn(Relation rel, const char *indexName) + { + Oid indexOid; + ++ /* SELinux checks */ ++ sepgsql_relation_alter(RelationGetRelid(rel)); ++ + indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace); + + if (!OidIsValid(indexOid)) +@@ -6733,6 +6912,9 @@ ATExecClusterOn(Relation rel, const char *indexName) + static void + ATExecDropCluster(Relation rel) + { ++ /* SELinux checks */ ++ sepgsql_relation_alter(RelationGetRelid(rel)); ++ + mark_index_clustered(rel, InvalidOid); + } + +@@ -6783,6 +6965,9 @@ ATExecSetRelOptions(Relation rel, List *defList, bool isReset) + bool repl_repl[Natts_pg_class]; + static char *validnsps[] = HEAP_RELOPT_NAMESPACES; + ++ /* SELinux checks */ ++ sepgsql_relation_alter(RelationGetRelid(rel)); ++ + if (defList == NIL) + return; /* nothing to do */ + +@@ -7115,6 +7300,9 @@ static void + ATExecEnableDisableTrigger(Relation rel, char *trigname, + char fires_when, bool skip_system) + { ++ /* SELinux checks */ ++ sepgsql_relation_alter(RelationGetRelid(rel)); ++ + EnableDisableTrigger(rel, trigname, fires_when, skip_system); + } + +@@ -7127,6 +7315,9 @@ static void + ATExecEnableDisableRule(Relation rel, char *trigname, + char fires_when) + { ++ /* SELinux checks */ ++ sepgsql_relation_alter(RelationGetRelid(rel)); ++ + EnableDisableRule(rel, trigname, fires_when); + } + +@@ -7160,6 +7351,10 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent) + */ + ATSimplePermissions(parent_rel, false); + ++ /* SELinux checks */ ++ sepgsql_relation_alter_inherit(RelationGetRelid(child_rel), ++ RelationGetRelid(parent_rel)); ++ + /* Permanent rels cannot inherit from temporary ones */ + if (parent_rel->rd_istemp && !child_rel->rd_istemp) + ereport(ERROR, +@@ -7512,6 +7707,9 @@ ATExecDropInherit(Relation rel, RangeVar *parent) + List *connames; + bool found = false; + ++ /* SELinux checks */ ++ sepgsql_relation_alter(RelationGetRelid(rel)); ++ + /* + * AccessShareLock on the parent is probably enough, seeing that DROP + * TABLE doesn't lock parent tables at all. We need some lock since we'll +@@ -7809,6 +8007,9 @@ AlterTableNamespace(RangeVar *relation, const char *newschema, + /* get schema OID and check its permissions */ + nspOid = LookupCreationNamespace(newschema); + ++ /* SELinux checks */ ++ sepgsql_relation_alter_schema(RelationGetRelid(rel), nspOid); ++ + if (oldNspOid == nspOid) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_TABLE), +@@ -8006,6 +8207,282 @@ AlterSeqNamespaces(Relation classRel, Relation rel, + relation_close(depRel, AccessShareLock); + } + ++/* ++ * ALTER TABLE/SEQUENCE/VIEW SECURITY LABEL TO ++ */ ++void ++AlterRelationSecLabelInternal(Oid relOid, Oid securityId, int expected_parents) ++{ ++ Form_pg_class classForm; ++ Relation targetRel; ++ Relation inhRel; ++ Relation classRel; ++ SysScanDesc scan; ++ ScanKeyData skey; ++ HeapTuple tuple; ++ List *indexList; ++ ListCell *cell; ++ int inhcount = 0; ++ ++ /* ++ * Grab an exclusive lock on the target table ++ */ ++ targetRel = relation_open(relOid, AccessExclusiveLock); ++ ++ /* ++ * Check num of inheritors ++ */ ++ inhRel = heap_open(InheritsRelationId, AccessShareLock); ++ ++ ScanKeyInit(&skey, ++ Anum_pg_inherits_inhrelid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(relOid)); ++ ++ scan = systable_beginscan(inhRel, InheritsRelidSeqnoIndexId, ++ true, SnapshotNow, 1, &skey); ++ while (HeapTupleIsValid(systable_getnext(scan))) ++ inhcount++; ++ ++ systable_endscan(scan); ++ ++ heap_close(inhRel, AccessShareLock); ++ ++ if (inhcount != expected_parents) ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_TABLE_DEFINITION), ++ errmsg("cannot relabel inherited relation"))); ++ ++ /* ++ * Update pg_class relation ++ */ ++ classRel = heap_open(RelationRelationId, RowExclusiveLock); ++ ++ tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for relation %u", relOid); ++ ++ classForm = (Form_pg_class) GETSTRUCT(tuple); ++ ++ HeapTupleSetSecid(tuple, securityId); ++ ++ simple_heap_update(classRel, &tuple->t_self, tuple); ++ ++ CatalogUpdateIndexes(classRel, tuple); ++ ++ heap_close(classRel, RowExclusiveLock); ++ ++ /* ++ * Also update TOAST and INDEX ++ */ ++ if (OidIsValid(classForm->reltoastrelid)) ++ AlterRelationSecLabelInternal(classForm->reltoastrelid, ++ securityId, 0); ++ ++ indexList = RelationGetIndexList(targetRel); ++ foreach (cell, indexList) ++ AlterRelationSecLabelInternal(lfirst_oid(cell), securityId, 0); ++ ++ /* ++ * Also update pg_attribute, if not RELKIND_RELATION ++ */ ++ if (classForm->relkind != RELKIND_RELATION) ++ { ++ Relation attRel; ++ HeapTuple oldtup, newtup; ++ Oid attsecid; ++ ++ /* move security-id to pg_attribtue catalog */ ++ attsecid = seclabelMoveSecid(AttributeRelationId, ++ RelationRelationId, ++ securityId); ++ ++ attRel = heap_open(AttributeRelationId, RowExclusiveLock); ++ ++ ScanKeyInit(&skey, ++ Anum_pg_attribute_attrelid, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(RelationGetRelid(targetRel))); ++ ++ scan = systable_beginscan(attRel, AttributeRelidNumIndexId, true, ++ SnapshotNow, 1, &skey); ++ while (HeapTupleIsValid(oldtup = systable_getnext(scan))) ++ { ++ Form_pg_attribute attForm ++ = (Form_pg_attribute) GETSTRUCT(oldtup); ++ ++ if (attForm->attinhcount > 0) ++ elog(ERROR, "Bug? attinhcount is %d at %s of %s", ++ attForm->attinhcount, NameStr(attForm->attname), ++ RelationGetRelationName(targetRel)); ++ ++ newtup = heap_copytuple(oldtup); ++ ++ HeapTupleSetSecid(newtup, attsecid); ++ ++ simple_heap_update(attRel, &newtup->t_self, newtup); ++ ++ CatalogUpdateIndexes(attRel, newtup); ++ } ++ systable_endscan(scan); ++ ++ heap_close(attRel, RowExclusiveLock); ++ } ++ ++ heap_close(targetRel, NoLock); /* close rel but keep lock */ ++} ++ ++void ++AlterAttributeSecLabelInternal(Oid relOid, const char *attname, ++ Oid securityId, int expected_parents) ++{ ++ Form_pg_attribute attForm; ++ Relation targetRel; ++ Relation attRel; ++ HeapTuple tuple; ++ ++ /* ++ * Grab an exclusive lock on the target table, which we will NOT ++ * release until end of transaction. ++ */ ++ targetRel = heap_open(relOid, AccessExclusiveLock); ++ ++ attRel = heap_open(AttributeRelationId, RowExclusiveLock); ++ ++ tuple = SearchSysCacheCopyAttName(relOid, attname); ++ if (!HeapTupleIsValid(tuple)) ++ ereport(ERROR, ++ (errcode(ERRCODE_UNDEFINED_COLUMN), ++ errmsg("column \"%s\" does not exist", attname))); ++ ++ attForm = (Form_pg_attribute) GETSTRUCT(tuple); ++#if 0 ++ /* ++ * XXX - here is no active reason why we forbid to relabel ++ * system columns. ++ */ ++ if (attForm->attnum <= 0) ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("cannot relabel system column \"%s\"", attname))); ++#endif ++ if (attForm->attinhcount > expected_parents) ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_TABLE_DEFINITION), ++ errmsg("cannot relabel inherited column \"%s\"", attname))); ++ ++ /* update pg_attribute */ ++ HeapTupleSetSecid(tuple, securityId); ++ ++ simple_heap_update(attRel, &tuple->t_self, tuple); ++ ++ CatalogUpdateIndexes(attRel, tuple); ++ ++ heap_close(attRel, RowExclusiveLock); ++ ++ heap_close(targetRel, NoLock); /* close rel but keep lock */ ++} ++ ++void ++AlterRelationSecLabel(RangeVar *relation, const char *attname, ++ ObjectType objtype, char *new_label) ++{ ++ Oid relOid = RangeVarGetRelid(relation, false); ++ Oid securityId; ++ char relkind; ++ List *child_oids, *child_numparents; ++ ListCell *lo, *li; ++ ++ /* ++ * Sanity checks for relation types ++ */ ++ relkind = get_rel_relkind(relOid); ++ switch (objtype) ++ { ++ case OBJECT_TABLE: ++ Assert(attname == NULL); ++ if (relkind != RELKIND_RELATION && ++ relkind != RELKIND_SEQUENCE && ++ relkind != RELKIND_VIEW) ++ ereport(ERROR, ++ (errcode(ERRCODE_WRONG_OBJECT_TYPE), ++ errmsg("\"%s\" is not a table, sequence or view", ++ get_rel_name(relOid)))); ++ break; ++ ++ case OBJECT_SEQUENCE: ++ Assert(attname == NULL); ++ if (relkind != RELKIND_SEQUENCE) ++ ereport(ERROR, ++ (errcode(ERRCODE_WRONG_OBJECT_TYPE), ++ errmsg("\"%s\" is not a sequence", ++ get_rel_name(relOid)))); ++ break; ++ ++ case OBJECT_VIEW: ++ Assert(attname == NULL); ++ if (relkind != RELKIND_VIEW) ++ ereport(ERROR, ++ (errcode(ERRCODE_WRONG_OBJECT_TYPE), ++ errmsg("\"%s\" is not a view", ++ get_rel_name(relOid)))); ++ break; ++ ++ case OBJECT_COLUMN: ++ Assert(attname != NULL); ++ if (relkind != RELKIND_RELATION) ++ ereport(ERROR, ++ (errcode(ERRCODE_WRONG_OBJECT_TYPE), ++ errmsg("\"%s\" is not a table", ++ get_rel_name(relOid)))); ++ break; ++ ++ default: ++ elog(ERROR, "Bug? unexpected object type %d", objtype); ++ break; ++ } ++ ++ /* ++ * Recursive calls to child relations including myself ++ */ ++ child_oids = find_all_inheritors(relOid, ++ AccessExclusiveLock, ++ &child_numparents); ++ forboth (lo, child_oids, li, child_numparents) ++ { ++ Oid childOid = lfirst_oid(lo); ++ int numParents = lfirst_int(li); ++ Oid relnsp = get_rel_namespace(childOid); ++ ++ /* Permission checks */ ++ if (!pg_class_ownercheck(childOid, GetUserId())) ++ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, ++ get_rel_name(childOid)); ++ ++ if (!allowSystemTableMods && ++ (IsSystemNamespace(relnsp) || IsToastNamespace(relnsp))) ++ ereport(ERROR, ++ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ++ errmsg("permission denied: \"%s\" is a system catalog", ++ get_rel_name(childOid)))); ++ ++ /* SELinux checks */ ++ if (objtype != OBJECT_COLUMN) ++ securityId = sepgsql_relation_relabel(childOid, ++ new_label); ++ else ++ securityId = sepgsql_attribute_relabel(childOid, attname, ++ new_label); ++ ++ /* Do work */ ++ if (objtype != OBJECT_COLUMN) ++ AlterRelationSecLabelInternal(childOid, ++ securityId, numParents); ++ else ++ AlterAttributeSecLabelInternal(childOid, attname, ++ securityId, numParents); ++ } ++} + + /* + * This code supports +diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c +index 862cd2d..8ea4118 100644 +--- a/src/backend/commands/tablespace.c ++++ b/src/backend/commands/tablespace.c +@@ -65,6 +65,7 @@ + #include "commands/tablespace.h" + #include "miscadmin.h" + #include "postmaster/bgwriter.h" ++#include "sepgsql/hooks.h" + #include "storage/fd.h" + #include "storage/procarray.h" + #include "storage/standby.h" +@@ -235,6 +236,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) + Oid tablespaceoid; + char *location; + Oid ownerId; ++ Oid securityId; + + /* Must be super user */ + if (!superuser()) +@@ -244,6 +246,9 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) + stmt->tablespacename), + errhint("Must be superuser to create a tablespace."))); + ++ /* SELinux check */ ++ securityId = sepgsql_tablespace_create(stmt->tablespacename); ++ + /* However, the eventual owner of the tablespace need not be */ + if (stmt->owner) + ownerId = get_roleid_checked(stmt->owner); +@@ -324,6 +329,8 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) + + tuple = heap_form_tuple(rel->rd_att, values, nulls); + ++ HeapTupleSetSecid(tuple, securityId); ++ + tablespaceoid = simple_heap_insert(rel, tuple); + + CatalogUpdateIndexes(rel, tuple); +@@ -429,6 +436,9 @@ DropTableSpace(DropTableSpaceStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, + tablespacename); + ++ /* SELinux checks */ ++ sepgsql_tablespace_drop(tablespaceoid, false); ++ + /* Disallow drop of the standard tablespaces, even by superuser */ + if (tablespaceoid == GLOBALTABLESPACE_OID || + tablespaceoid == DEFAULTTABLESPACE_OID) +@@ -787,6 +797,9 @@ RenameTableSpace(const char *oldname, const char *newname) + if (!pg_tablespace_ownercheck(HeapTupleGetOid(newtuple), GetUserId())) + aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, oldname); + ++ /* SELinux checks */ ++ sepgsql_tablespace_alter(HeapTupleGetOid(newtuple)); ++ + /* Validate new name */ + if (!allowSystemTableMods && IsReservedName(newname)) + ereport(ERROR, +@@ -868,6 +881,9 @@ AlterTableSpaceOwner(const char *name, Oid newOwnerId) + /* Must be able to become new owner */ + check_is_member_of_role(GetUserId(), newOwnerId); + ++ /* SELinux checks */ ++ sepgsql_tablespace_alter(HeapTupleGetOid(tup)); ++ + /* + * Normally we would also check for create permissions here, but there + * are none for tablespaces so we follow what rename tablespace does +@@ -985,6 +1001,54 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) + } + + /* ++ * ALTER TABLESPACE xxx SECURITY LABEL TO ... ++ */ ++void ++AlterTableSpaceSecLabel(const char *tspaceName, char *newLabel) ++{ ++ Relation rel; ++ ScanKeyData skey; ++ HeapScanDesc scan; ++ HeapTuple oldtup; ++ HeapTuple newtup; ++ Oid securityId; ++ ++ rel = heap_open(TableSpaceRelationId, RowExclusiveLock); ++ ++ /* scan pg_tablespace catalog */ ++ ScanKeyInit(&skey, ++ Anum_pg_tablespace_spcname, ++ BTEqualStrategyNumber, F_NAMEEQ, ++ CStringGetDatum(tspaceName)); ++ scan = heap_beginscan(rel, SnapshotNow, 1, &skey); ++ oldtup = heap_getnext(scan, ForwardScanDirection); ++ if (!HeapTupleIsValid(oldtup)) ++ ereport(ERROR, ++ (errcode(ERRCODE_UNDEFINED_OBJECT), ++ errmsg("tablespace \"%s\" does not exist", tspaceName))); ++ ++ /* Must be owner */ ++ if (!pg_tablespace_ownercheck(HeapTupleGetOid(oldtup), GetUserId())) ++ aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, tspaceName); ++ ++ /* SELinux checks */ ++ securityId = sepgsql_tablespace_relabel(HeapTupleGetSecid(oldtup), newLabel); ++ ++ /* update it */ ++ newtup = heap_copytuple(oldtup); ++ ++ HeapTupleSetSecid(newtup, securityId); ++ ++ simple_heap_update(rel, &newtup->t_self, newtup); ++ ++ CatalogUpdateIndexes(rel, newtup); ++ ++ heap_endscan(scan); ++ ++ heap_close(rel, RowExclusiveLock); ++} ++ ++/* + * Routines for handling the GUC variable 'default_tablespace'. + */ + +diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c +index 2cbc192..2ea9e6e 100644 +--- a/src/backend/commands/trigger.c ++++ b/src/backend/commands/trigger.c +@@ -40,6 +40,7 @@ + #include "parser/parsetree.h" + #include "pgstat.h" + #include "rewrite/rewriteManip.h" ++#include "sepgsql/hooks.h" + #include "storage/bufmgr.h" + #include "tcop/utility.h" + #include "utils/acl.h" +@@ -330,6 +331,10 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, + NameListToString(stmt->funcname)))); + } + ++ /* SELinux checks */ ++ sepgsql_trigger_create(RelationGetRelid(rel), stmt->trigname, ++ constrrelid, funcoid); ++ + /* + * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that + * references one of the built-in RI_FKey trigger functions, assume it is +@@ -1007,6 +1012,9 @@ DropTrigger(Oid relid, const char *trigname, DropBehavior behavior, + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + get_rel_name(relid)); + ++ /* SELinux checks */ ++ sepgsql_trigger_drop(relid, trigname, false); ++ + object.classId = TriggerRelationId; + object.objectId = HeapTupleGetOid(tup); + object.objectSubId = 0; +@@ -1116,6 +1124,9 @@ renametrig(Oid relid, + SysScanDesc tgscan; + ScanKeyData key[2]; + ++ /* SELinux checks */ ++ sepgsql_trigger_alter(relid, oldname); ++ + /* + * Grab an exclusive lock on the target table, which we will NOT release + * until end of transaction. +diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c +index ba3de63..19bebb4 100644 +--- a/src/backend/commands/tsearchcmds.c ++++ b/src/backend/commands/tsearchcmds.c +@@ -35,6 +35,7 @@ + #include "miscadmin.h" + #include "nodes/makefuncs.h" + #include "parser/parse_func.h" ++#include "sepgsql/hooks.h" + #include "tsearch/ts_cache.h" + #include "tsearch/ts_public.h" + #include "tsearch/ts_utils.h" +@@ -171,6 +172,7 @@ DefineTSParser(List *names, List *parameters) + NameData pname; + Oid prsOid; + Oid namespaceoid; ++ Oid securityId; + + if (!superuser()) + ereport(ERROR, +@@ -250,6 +252,14 @@ DefineTSParser(List *names, List *parameters) + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("text search parser lextypes method is required"))); + ++ /* SELinux checks */ ++ securityId = sepgsql_ts_parser_create(prsname, namespaceoid, ++ DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1]), ++ DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1]), ++ DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1]), ++ DatumGetObjectId(values[Anum_pg_ts_parser_prsheadline - 1]), ++ DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1])); ++ + /* + * Looks good, insert + */ +@@ -257,6 +267,8 @@ DefineTSParser(List *names, List *parameters) + + tup = heap_form_tuple(prsRel->rd_att, values, nulls); + ++ HeapTupleSetSecid(tup, securityId); ++ + prsOid = simple_heap_insert(prsRel, tup); + + CatalogUpdateIndexes(prsRel, tup); +@@ -314,6 +326,8 @@ RemoveTSParsers(DropStmt *drop) + } + continue; + } ++ /* SELinux checks */ ++ sepgsql_ts_parser_drop(prsOid, false); + + object.classId = TSParserRelationId; + object.objectId = prsOid; +@@ -366,10 +380,13 @@ RenameTSParser(List *oldname, const char *newname) + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to rename text search parsers"))); + +- rel = heap_open(TSParserRelationId, RowExclusiveLock); +- + prsId = TSParserGetPrsid(oldname, false); + ++ /* SELinux checks */ ++ sepgsql_ts_parser_alter_rename(prsId, newname); ++ ++ rel = heap_open(TSParserRelationId, RowExclusiveLock); ++ + tup = SearchSysCacheCopy1(TSPARSEROID, ObjectIdGetDatum(prsId)); + + if (!HeapTupleIsValid(tup)) /* should not happen */ +@@ -496,6 +513,7 @@ DefineTSDictionary(List *names, List *parameters) + List *dictoptions = NIL; + Oid dictOid; + Oid namespaceoid; ++ Oid securityId; + AclResult aclresult; + char *dictname; + +@@ -508,6 +526,9 @@ DefineTSDictionary(List *names, List *parameters) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceoid)); + ++ /* SELinux checks */ ++ securityId = sepgsql_ts_dict_create(dictname, namespaceoid); ++ + /* + * loop over the definition list and extract the information we need. + */ +@@ -557,6 +578,8 @@ DefineTSDictionary(List *names, List *parameters) + + tup = heap_form_tuple(dictRel->rd_att, values, nulls); + ++ HeapTupleSetSecid(tup, securityId); ++ + dictOid = simple_heap_insert(dictRel, tup); + + CatalogUpdateIndexes(dictRel, tup); +@@ -610,6 +633,8 @@ RenameTSDictionary(List *oldname, const char *newname) + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); ++ /* SELinux checks */ ++ sepgsql_ts_dict_alter_rename(dictId, newname); + + namestrcpy(&(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname), newname); + simple_heap_update(rel, &tup->t_self, tup); +@@ -674,6 +699,8 @@ RemoveTSDictionaries(DropStmt *drop) + !pg_namespace_ownercheck(namespaceId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY, + NameListToString(names)); ++ /* SELinux checks */ ++ sepgsql_ts_dict_drop(dictOid, false); + + object.classId = TSDictionaryRelationId; + object.objectId = dictOid; +@@ -745,6 +772,8 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt) + if (!pg_ts_dict_ownercheck(dictId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY, + NameListToString(stmt->dictname)); ++ /* SELinux checks */ ++ sepgsql_ts_dict_alter(dictId); + + /* deserialize the existing set of options */ + opt = SysCacheGetAttr(TSDICTOID, tup, +@@ -871,6 +900,8 @@ AlterTSDictionaryOwner(List *name, Oid newOwnerId) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + } ++ /* SELinux checks */ ++ sepgsql_ts_dict_alter(dictId); + + form->dictowner = newOwnerId; + +@@ -982,6 +1013,7 @@ DefineTSTemplate(List *names, List *parameters) + int i; + Oid dictOid; + Oid namespaceoid; ++ Oid securityId; + char *tmplname; + + if (!superuser()) +@@ -1036,6 +1068,10 @@ DefineTSTemplate(List *names, List *parameters) + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("text search template lexize method is required"))); + ++ /* SELinux checks */ ++ securityId = sepgsql_ts_template_create(tmplname, namespaceoid, ++ DatumGetObjectId(values[Anum_pg_ts_template_tmplinit - 1]), ++ DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1])); + /* + * Looks good, insert + */ +@@ -1044,6 +1080,8 @@ DefineTSTemplate(List *names, List *parameters) + + tup = heap_form_tuple(tmplRel->rd_att, values, nulls); + ++ HeapTupleSetSecid(tup, securityId); ++ + dictOid = simple_heap_insert(tmplRel, tup); + + CatalogUpdateIndexes(tmplRel, tup); +@@ -1075,6 +1113,9 @@ RenameTSTemplate(List *oldname, const char *newname) + + tmplId = TSTemplateGetTmplid(oldname, false); + ++ /* SELinux checks */ ++ sepgsql_ts_template_alter_rename(tmplId, newname); ++ + tup = SearchSysCacheCopy1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId)); + + if (!HeapTupleIsValid(tup)) /* should not happen */ +@@ -1145,6 +1186,8 @@ RemoveTSTemplates(DropStmt *drop) + } + continue; + } ++ /* SELinux checks */ ++ sepgsql_ts_template_drop(tmplOid, false); + + object.classId = TSTemplateRelationId; + object.objectId = tmplOid; +@@ -1305,6 +1348,7 @@ DefineTSConfiguration(List *names, List *parameters) + bool nulls[Natts_pg_ts_config]; + AclResult aclresult; + Oid namespaceoid; ++ Oid securityId; + char *cfgname; + NameData cname; + Oid sourceOid = InvalidOid; +@@ -1321,6 +1365,9 @@ DefineTSConfiguration(List *names, List *parameters) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceoid)); + ++ /* SELinux checks */ ++ securityId = sepgsql_ts_config_create(cfgname, namespaceoid); ++ + /* + * loop over the definition list and extract the information we need. + */ +@@ -1388,6 +1435,8 @@ DefineTSConfiguration(List *names, List *parameters) + + tup = heap_form_tuple(cfgRel->rd_att, values, nulls); + ++ HeapTupleSetSecid(tup, securityId); ++ + cfgOid = simple_heap_insert(cfgRel, tup); + + CatalogUpdateIndexes(cfgRel, tup); +@@ -1489,6 +1538,9 @@ RenameTSConfiguration(List *oldname, const char *newname) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + ++ /* SELinux checks */ ++ sepgsql_ts_config_alter_rename(cfgId, newname); ++ + namestrcpy(&(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname), newname); + simple_heap_update(rel, &tup->t_self, tup); + CatalogUpdateIndexes(rel, tup); +@@ -1549,6 +1601,9 @@ RemoveTSConfigurations(DropStmt *drop) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, + NameListToString(names)); + ++ /* SELinux checks */ ++ sepgsql_ts_config_drop(cfgOid, false); ++ + object.classId = TSConfigRelationId; + object.objectId = cfgOid; + object.objectSubId = 0; +@@ -1656,6 +1711,8 @@ AlterTSConfigurationOwner(List *name, Oid newOwnerId) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(namespaceOid)); + } ++ /* SELinux checks */ ++ sepgsql_ts_config_alter(cfgId); + + form->cfgowner = newOwnerId; + +@@ -1693,6 +1750,9 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, + NameListToString(stmt->cfgname)); + ++ /* SELinux checks */ ++ sepgsql_ts_config_alter(HeapTupleGetOid(tup)); ++ + relMap = heap_open(TSConfigMapRelationId, RowExclusiveLock); + + /* Add or drop mappings */ +diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c +index 1e14dca..f7429f0 100644 +--- a/src/backend/commands/typecmds.c ++++ b/src/backend/commands/typecmds.c +@@ -56,6 +56,7 @@ + #include "parser/parse_expr.h" + #include "parser/parse_func.h" + #include "parser/parse_type.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/fmgroids.h" +@@ -143,6 +144,8 @@ DefineType(List *names, List *parameters) + char *array_type; + Oid array_oid; + Oid typoid; ++ Oid type_replaced; ++ Oid securityId; + Oid resulttype; + ListCell *pl; + +@@ -520,6 +523,15 @@ DefineType(List *names, List *parameters) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, + NameListToString(analyzeName)); + #endif ++ /* SELinux checks */ ++ type_replaced = GetSysCacheOid2(TYPENAMENSP, ++ CStringGetDatum(typeName), ++ ObjectIdGetDatum(typeNamespace)); ++ securityId = sepgsql_type_create(typeName, type_replaced, ++ typeNamespace, TYPTYPE_BASE, ++ inputOid, outputOid, ++ receiveOid, sendOid, ++ typmodinOid, typmodoutOid, analyzeOid); + + array_oid = AssignTypeArrayOid(); + +@@ -562,7 +574,8 @@ DefineType(List *names, List *parameters) + storage, /* TOAST strategy */ + -1, /* typMod (Domains only) */ + 0, /* Array Dimensions of typbasetype */ +- false); /* Type NOT NULL */ ++ false, /* Type NOT NULL */ ++ securityId); /* security-id of the type */ + + /* + * Create the array type that goes with it. +@@ -601,7 +614,8 @@ DefineType(List *names, List *parameters) + 'x', /* ARRAY is always toastable */ + -1, /* typMod (Domains only) */ + 0, /* Array dimensions of typbasetype */ +- false); /* Type NOT NULL */ ++ false, /* Type NOT NULL */ ++ securityId); /* security-id of the type */ + + pfree(array_type); + } +@@ -668,6 +682,9 @@ RemoveTypes(DropStmt *drop) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, + format_type_be(typeoid)); + ++ /* SELinux checks */ ++ sepgsql_type_drop(typeoid, false); ++ + if (drop->removeType == OBJECT_DOMAIN) + { + /* Check that this is actually a domain */ +@@ -766,6 +783,7 @@ DefineDomain(CreateDomainStmt *stmt) + Oid basetypeoid; + Oid domainoid; + Oid old_type_oid; ++ Oid securityId; + Form_pg_type baseType; + int32 basetypeMod; + +@@ -1011,6 +1029,13 @@ DefineDomain(CreateDomainStmt *stmt) + } + } + ++ /* SELinux checks */ ++ securityId = sepgsql_type_create(domainName, InvalidOid, ++ domainNamespace, TYPTYPE_DOMAIN, ++ inputProcedure, outputProcedure, ++ receiveProcedure, sendProcedure, ++ InvalidOid, InvalidOid, analyzeProcedure); ++ + /* + * Have TypeCreate do all the real work. + */ +@@ -1044,7 +1069,8 @@ DefineDomain(CreateDomainStmt *stmt) + storage, /* TOAST strategy */ + basetypeMod, /* typeMod value */ + typNDims, /* Array dimensions for base type */ +- typNotNull); /* Type NOT NULL */ ++ typNotNull, /* Type NOT NULL */ ++ securityId); /* security-id of the type */ + + /* + * Process constraints which refer to the domain ID returned by TypeCreate +@@ -1094,6 +1120,7 @@ DefineEnum(CreateEnumStmt *stmt) + AclResult aclresult; + Oid old_type_oid; + Oid enumArrayOid; ++ Oid securityId; + + /* Convert list of names to a name and namespace */ + enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName, +@@ -1120,6 +1147,13 @@ DefineEnum(CreateEnumStmt *stmt) + errmsg("type \"%s\" already exists", enumName))); + } + ++ /* SELinux checks */ ++ securityId = sepgsql_type_create(enumName, old_type_oid, ++ enumNamespace, TYPTYPE_ENUM, ++ F_ENUM_IN, F_ENUM_OUT, ++ F_ENUM_RECV, F_ENUM_SEND, ++ InvalidOid, InvalidOid, InvalidOid); ++ + enumArrayOid = AssignTypeArrayOid(); + + /* Create the pg_type entry */ +@@ -1153,7 +1187,8 @@ DefineEnum(CreateEnumStmt *stmt) + 'p', /* TOAST strategy always plain */ + -1, /* typMod (Domains only) */ + 0, /* Array dimensions of typbasetype */ +- false); /* Type NOT NULL */ ++ false, /* Type NOT NULL */ ++ securityId); /* security-id of the type */ + + /* Enter the enum's values into pg_enum */ + EnumValuesCreate(enumTypeOid, stmt->vals, InvalidOid); +@@ -1192,7 +1227,8 @@ DefineEnum(CreateEnumStmt *stmt) + 'x', /* ARRAY is always toastable */ + -1, /* typMod (Domains only) */ + 0, /* Array dimensions of typbasetype */ +- false); /* Type NOT NULL */ ++ false, /* Type NOT NULL */ ++ securityId); /* security-id of the type */ + + pfree(enumArrayName); + } +@@ -1585,6 +1621,8 @@ AlterDomainDefault(List *names, Node *defaultRaw) + /* Check it's a domain and check user has permission for ALTER DOMAIN */ + checkDomainOwner(tup, typename); + ++ sepgsql_type_alter(domainoid); ++ + /* Setup new tuple */ + MemSet(new_record, (Datum) 0, sizeof(new_record)); + MemSet(new_record_nulls, false, sizeof(new_record_nulls)); +@@ -1711,6 +1749,8 @@ AlterDomainNotNull(List *names, bool notNull) + /* Check it's a domain and check user has permission for ALTER DOMAIN */ + checkDomainOwner(tup, typename); + ++ sepgsql_type_alter(domainoid); ++ + /* Is the domain already set to the desired constraint? */ + if (typTup->typnotnull == notNull) + { +@@ -1810,6 +1850,8 @@ AlterDomainDropConstraint(List *names, const char *constrName, + /* Check it's a domain and check user has permission for ALTER DOMAIN */ + checkDomainOwner(tup, typename); + ++ sepgsql_type_alter(domainoid); ++ + /* Grab an appropriate lock on the pg_constraint relation */ + conrel = heap_open(ConstraintRelationId, RowExclusiveLock); + +@@ -1884,6 +1926,8 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) + /* Check it's a domain and check user has permission for ALTER DOMAIN */ + checkDomainOwner(tup, typename); + ++ sepgsql_type_alter(domainoid); ++ + if (!IsA(newConstraint, Constraint)) + elog(ERROR, "unrecognized node type: %d", + (int) nodeTag(newConstraint)); +@@ -2507,6 +2551,9 @@ RenameType(List *names, const char *newTypeName) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, + format_type_be(typeOid)); + ++ /* SELinux checks */ ++ sepgsql_type_alter_rename(typeOid, newTypeName); ++ + /* + * If it's a composite type, we need to check that it really is a + * free-standing composite type, and not a table's rowtype. We want people +@@ -2627,6 +2674,8 @@ AlterTypeOwner(List *names, Oid newOwnerId) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(typTup->typnamespace)); + } ++ /* SELinux checks */ ++ sepgsql_type_alter(HeapTupleGetOid(tup)); + + /* + * If it's a composite type, invoke ATExecChangeOwner so that we fix +@@ -2731,6 +2780,9 @@ AlterTypeNamespace(List *names, const char *newschema) + /* get schema OID and check its permissions */ + nspOid = LookupCreationNamespace(newschema); + ++ /* SELinux checks */ ++ sepgsql_type_alter_schema(typeOid, nspOid); ++ + /* don't allow direct alteration of array types */ + elemOid = get_element_type(typeOid); + if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid) +@@ -2882,3 +2934,100 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, + if (OidIsValid(arrayOid)) + AlterTypeNamespaceInternal(arrayOid, nspOid, true, true); + } ++ ++/* ++ * ALTER TYPE xxx SECURITY LABEL TO ... ++ */ ++void ++AlterTypeSecLabelInternal(Oid typeOid, Oid securityId) ++{ ++ Relation typeRel; ++ Form_pg_type typeForm; ++ HeapTuple tuple; ++ ++ typeRel = heap_open(TypeRelationId, RowExclusiveLock); ++ ++ tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for type %u", typeOid); ++ typeForm = (Form_pg_type) GETSTRUCT(tuple); ++ ++ /* update it */ ++ HeapTupleSetSecid(tuple, securityId); ++ ++ simple_heap_update(typeRel, &tuple->t_self, tuple); ++ ++ CatalogUpdateIndexes(typeRel, tuple); ++ ++ /* if it is a composit type, update pg_class too */ ++ if (OidIsValid(typeForm->typrelid)) ++ { ++ Oid classSecId = seclabelMoveSecid(RelationRelationId, ++ TypeRelationId, ++ securityId); ++ AlterRelationSecLabelInternal(typeForm->typrelid, classSecId, 0); ++ } ++ ++ /* if it has an array type, update that too */ ++ if (OidIsValid(typeForm->typarray)) ++ AlterTypeSecLabelInternal(typeForm->typarray, securityId); ++ ++ heap_freetuple(tuple); ++ ++ heap_close(typeRel, RowExclusiveLock); ++} ++ ++void ++AlterTypeSecLabel(List *names, char *new_label) ++{ ++ Form_pg_type typeForm; ++ HeapTuple typtup; ++ TypeName *typename; ++ Oid typeOid; ++ Oid securityId; ++ ++ /* resolve type name */ ++ typename = makeTypeNameFromNameList(names); ++ typtup = LookupTypeName(NULL, typename, NULL); ++ if (!HeapTupleIsValid(typtup)) ++ ereport(ERROR, ++ (errcode(ERRCODE_UNDEFINED_OBJECT), ++ errmsg("type \"%s\" does not exist", ++ TypeNameToString(typename)))); ++ ++ typeForm = (Form_pg_type) GETSTRUCT(typtup); ++ typeOid = HeapTupleGetOid(typtup); ++ ++ /* ++ * If it's a composite type, we need to check that it really is a ++ * free-standing composite type, and not a table's rowtype. We want people ++ * to use ALTER TABLE not ALTER TYPE for that case. ++ */ ++ if (typeForm->typtype == TYPTYPE_COMPOSITE && ++ get_rel_relkind(typeForm->typrelid) != RELKIND_COMPOSITE_TYPE) ++ ereport(ERROR, ++ (errcode(ERRCODE_WRONG_OBJECT_TYPE), ++ errmsg("%s is a table's row type", ++ format_type_be(typeOid)), ++ errhint("Use ALTER TABLE instead."))); ++ ++ /* don't allow direct alteration of array types, either */ ++ if (OidIsValid(typeForm->typelem) && ++ get_array_type(typeForm->typelem) == typeOid) ++ ereport(ERROR, ++ (errcode(ERRCODE_WRONG_OBJECT_TYPE), ++ errmsg("cannot alter array type %s", ++ format_type_be(typeOid)))); ++ ++ /* DAC permission checks */ ++ if (!pg_type_ownercheck(typeOid, GetUserId())) ++ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, ++ format_type_be(typeOid)); ++ ++ /* SELinux checks */ ++ securityId = sepgsql_type_relabel(typeOid, new_label); ++ ++ AlterTypeSecLabelInternal(typeOid, securityId); ++ ++ ReleaseSysCache(typtup); ++} +diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c +index 2f0788e..8de31ae 100644 +--- a/src/backend/commands/user.c ++++ b/src/backend/commands/user.c +@@ -21,11 +21,13 @@ + #include "catalog/pg_authid.h" + #include "catalog/pg_database.h" + #include "catalog/pg_db_role_setting.h" ++#include "catalog/pg_seclabel.h" + #include "commands/comment.h" + #include "commands/dbcommands.h" + #include "commands/user.h" + #include "libpq/md5.h" + #include "miscadmin.h" ++#include "sepgsql/hooks.h" + #include "storage/lmgr.h" + #include "utils/acl.h" + #include "utils/builtins.h" +@@ -111,6 +113,7 @@ CreateRole(CreateRoleStmt *stmt) + DefElem *drolemembers = NULL; + DefElem *dadminmembers = NULL; + DefElem *dvalidUntil = NULL; ++ Oid securityId; + + /* The defaults can vary depending on the original statement type */ + switch (stmt->stmt_type) +@@ -279,6 +282,9 @@ CreateRole(CreateRoleStmt *stmt) + errmsg("permission denied to create role"))); + } + ++ /* SELinux checks */ ++ securityId = sepgsql_role_create(stmt->role); ++ + if (strcmp(stmt->role, "public") == 0 || + strcmp(stmt->role, "none") == 0) + ereport(ERROR, +@@ -365,6 +371,8 @@ CreateRole(CreateRoleStmt *stmt) + + tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls); + ++ HeapTupleSetSecid(tuple, securityId); ++ + /* + * Insert new record in the pg_authid table + */ +@@ -606,6 +614,8 @@ AlterRole(AlterRoleStmt *stmt) + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied"))); + } ++ /* SELinux checks */ ++ sepgsql_role_alter(roleid); + + /* Convert validuntil to internal form */ + if (validUntil) +@@ -791,6 +801,8 @@ AlterRoleSet(AlterRoleSetStmt *stmt) + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied"))); + } ++ /* SELinux checks */ ++ sepgsql_role_alter(HeapTupleGetOid(roletuple)); + + /* look up and lock the database, if specified */ + if (stmt->database != NULL) +@@ -886,6 +898,9 @@ DropRole(DropRoleStmt *stmt) + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to drop superusers"))); + ++ /* SELinux checks */ ++ sepgsql_role_drop(roleid, false); ++ + /* + * Lock the role, so nobody can add dependencies to her while we drop + * her. We keep the lock until the end of transaction. +@@ -1282,6 +1297,9 @@ AddRoleMems(const char *rolename, Oid roleid, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to set grantor"))); + ++ /* SELinux checks */ ++ sepgsql_role_grant(roleid, true, memberIds); ++ + pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock); + pg_authmem_dsc = RelationGetDescr(pg_authmem_rel); + +@@ -1412,6 +1430,8 @@ DelRoleMems(const char *rolename, Oid roleid, + errmsg("must have admin option on role \"%s\"", + rolename))); + } ++ /* SELinux checks */ ++ sepgsql_role_grant(roleid, false, memberIds); + + pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock); + pg_authmem_dsc = RelationGetDescr(pg_authmem_rel); +diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c +index 49a206e..4646c41 100644 +--- a/src/backend/commands/vacuum.c ++++ b/src/backend/commands/vacuum.c +@@ -980,6 +980,12 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound, + relation_close(onerel, NoLock); + + /* ++ * VACUUM FULL also reclaim orphan security labels, if exist ++ */ ++ if (vacstmt->options & VACOPT_FULL) ++ seclabelRelationReclaim(relid); ++ ++ /* + * Complete the transaction and free all temporary memory used. + */ + PopActiveSnapshot(); +diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c +index d7a06bc..5480c83 100644 +--- a/src/backend/commands/view.c ++++ b/src/backend/commands/view.c +@@ -28,6 +28,7 @@ + #include "rewrite/rewriteDefine.h" + #include "rewrite/rewriteManip.h" + #include "rewrite/rewriteSupport.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/lsyscache.h" +@@ -167,6 +168,9 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(rel)); + ++ /* SELinux checks */ ++ sepgsql_view_replace(viewOid); ++ + /* Also check it's not in use already */ + CheckTableNotInUse(rel, "CREATE OR REPLACE VIEW"); + +diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c +index 5e555ad..963096d 100644 +--- a/src/backend/executor/execJunk.c ++++ b/src/backend/executor/execJunk.c +@@ -58,7 +58,8 @@ + * An optional resultSlot can be passed as well. + */ + JunkFilter * +-ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot) ++ExecInitJunkFilter(List *targetList, bool hasoid, bool hassecid, ++ TupleTableSlot *slot) + { + JunkFilter *junkfilter; + TupleDesc cleanTupType; +@@ -70,7 +71,7 @@ ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot) + /* + * Compute the tuple descriptor for the cleaned tuple. + */ +- cleanTupType = ExecCleanTypeFromTL(targetList, hasoid); ++ cleanTupType = ExecCleanTypeFromTL(targetList, hasoid, hassecid); + + /* + * Use the given slot, or make a new slot if we weren't given one. +diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c +index d5e7e3a..96d4ba8 100644 +--- a/src/backend/executor/execMain.c ++++ b/src/backend/executor/execMain.c +@@ -38,6 +38,7 @@ + #include "access/xact.h" + #include "catalog/heap.h" + #include "catalog/namespace.h" ++#include "catalog/pg_seclabel.h" + #include "catalog/toasting.h" + #include "commands/tablespace.h" + #include "commands/trigger.h" +@@ -47,11 +48,13 @@ + #include "optimizer/clauses.h" + #include "parser/parse_clause.h" + #include "parser/parsetree.h" ++#include "sepgsql/hooks.h" + #include "storage/bufmgr.h" + #include "storage/lmgr.h" + #include "storage/smgr.h" + #include "tcop/utility.h" + #include "utils/acl.h" ++#include "utils/guc.h" + #include "utils/lsyscache.h" + #include "utils/memutils.h" + #include "utils/snapmgr.h" +@@ -414,7 +417,16 @@ ExecCheckRTPerms(List *rangeTable) + + foreach(l, rangeTable) + { +- ExecCheckRTEPerms((RangeTblEntry *) lfirst(l)); ++ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); ++ ++ ExecCheckRTEPerms(rte); ++ ++ if (rte->rtekind == RTE_RELATION) ++ sepgsql_relation_perms(rte->relid, ++ rte->requiredPerms, ++ rte->selectedCols, ++ rte->modifiedCols, ++ true); + } + } + +@@ -829,6 +841,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) + + j = ExecInitJunkFilter(planstate->plan->targetlist, + tupType->tdhasoid, ++ tupType->tdhassecid, + ExecInitExtraTupleSlot(estate)); + estate->es_junkFilter = j; + +@@ -1065,6 +1078,37 @@ ExecContextForcesOids(PlanState *planstate, bool *hasoids) + return false; + } + ++/* ++ * ExecContextForcesSecids ++ * ++ * It is same with ExecContextForcesOids, except for it checks space ++ * for security id of the tuples. ++ */ ++bool ++ExecContextForcesSecids(PlanState *planstate, bool *hassecid) ++{ ++ ResultRelInfo *ri = planstate->state->es_result_relation_info; ++ ++ if (ri != NULL) ++ { ++ Relation rel = ri->ri_RelationDesc; ++ ++ if (rel != NULL) ++ { ++ *hassecid = RelationGetForm(rel)->relhassecids; ++ return true; ++ } ++ } ++ ++ if (planstate->state->es_select_into) ++ { ++ *hassecid = default_with_secids; ++ return true; ++ } ++ ++ return false; ++} ++ + /* ---------------------------------------------------------------- + * ExecEndPlan + * +@@ -2073,6 +2117,7 @@ OpenIntoRel(QueryDesc *queryDesc) + Oid intoRelationId; + TupleDesc tupdesc; + DR_intorel *myState; ++ Oid *secLabels; + static char *validnsps[] = HEAP_RELOPT_NAMESPACES; + + Assert(into); +@@ -2144,6 +2189,14 @@ OpenIntoRel(QueryDesc *queryDesc) + get_tablespace_name(tablespaceId)); + } + ++ /* SELinux checks */ ++ secLabels = sepgsql_relation_create(intoName, ++ RELKIND_RELATION, ++ queryDesc->tupDesc, ++ namespaceId, ++ NIL, ++ true); ++ + /* Parse and validate any reloptions */ + reloptions = transformRelOptions((Datum) 0, + into->options, +@@ -2174,7 +2227,8 @@ OpenIntoRel(QueryDesc *queryDesc) + into->onCommit, + reloptions, + true, +- allowSystemTableMods); ++ allowSystemTableMods, ++ secLabels); + + FreeTupleDesc(tupdesc); + +@@ -2305,6 +2359,11 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self) + */ + if (myState->rel->rd_rel->relhasoids) + HeapTupleSetOid(tuple, InvalidOid); ++ if (myState->rel->rd_rel->relhassecids) ++ HeapTupleSetSecid(tuple, InvalidOid); ++ ++ /* SELinux checks */ ++ sepgsql_tuple_insert(myState->rel, tuple); + + heap_insert(myState->rel, + tuple, +diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c +index 005e15e..6e93932 100644 +--- a/src/backend/executor/execQual.c ++++ b/src/backend/executor/execQual.c +@@ -49,6 +49,7 @@ + #include "optimizer/planner.h" + #include "parser/parse_coerce.h" + #include "pgstat.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/lsyscache.h" +@@ -1177,6 +1178,9 @@ init_fcache(Oid foid, FuncExprState *fcache, + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid)); + ++ /* SELinux checks */ ++ sepgsql_proc_execute(foid); ++ + /* + * Safety check on nargs. Under normal circumstances this should never + * fail, as parser should check sooner. But possibly it might fail if +@@ -1221,7 +1225,7 @@ init_fcache(Oid foid, FuncExprState *fcache, + else if (functypclass == TYPEFUNC_SCALAR) + { + /* Base data type, i.e. scalar */ +- tupdesc = CreateTemplateTupleDesc(1, false); ++ tupdesc = CreateTemplateTupleDesc(1, false, false); + TupleDescInitEntry(tupdesc, + (AttrNumber) 1, + NULL, +@@ -2111,7 +2115,7 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, + /* + * Scalar type, so make a single-column descriptor + */ +- tupdesc = CreateTemplateTupleDesc(1, false); ++ tupdesc = CreateTemplateTupleDesc(1, false, false); + TupleDescInitEntry(tupdesc, + (AttrNumber) 1, + "column", +@@ -4108,6 +4112,9 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, + aclcheck_error(aclresult, ACL_KIND_PROC, + get_func_name(acoerce->elemfuncid)); + ++ /* SELinux checks */ ++ sepgsql_proc_execute(acoerce->elemfuncid); ++ + /* Set up the primary fmgr lookup information */ + fmgr_info_cxt(acoerce->elemfuncid, &(astate->elemfunc), + econtext->ecxt_per_query_memory); +diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c +index 53fe195..cb63671 100644 +--- a/src/backend/executor/execScan.c ++++ b/src/backend/executor/execScan.c +@@ -258,6 +258,7 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc + int numattrs = tupdesc->natts; + int attrno; + bool hasoid; ++ bool hassecid; + ListCell *tlist_item = list_head(tlist); + + /* Check the tlist attributes */ +@@ -307,6 +308,9 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc + if (ExecContextForcesOids(ps, &hasoid) && + hasoid != tupdesc->tdhasoid) + return false; ++ if (ExecContextForcesSecids(ps, &hassecid) && ++ hassecid != tupdesc->tdhassecid) ++ return false; + + return true; + } +diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c +index 1caf976..64f6468 100644 +--- a/src/backend/executor/execTuples.c ++++ b/src/backend/executor/execTuples.c +@@ -98,7 +98,7 @@ + + + static TupleDesc ExecTypeFromTLInternal(List *targetList, +- bool hasoid, bool skipjunk); ++ bool hasoid, bool hassecid, bool skipjunk); + + + /* ---------------------------------------------------------------- +@@ -899,9 +899,9 @@ ExecInitNullTupleSlot(EState *estate, TupleDesc tupType) + * ---------------------------------------------------------------- + */ + TupleDesc +-ExecTypeFromTL(List *targetList, bool hasoid) ++ExecTypeFromTL(List *targetList, bool hasoid, bool hassecid) + { +- return ExecTypeFromTLInternal(targetList, hasoid, false); ++ return ExecTypeFromTLInternal(targetList, hasoid, hassecid, false); + } + + /* ---------------------------------------------------------------- +@@ -911,13 +911,14 @@ ExecTypeFromTL(List *targetList, bool hasoid) + * ---------------------------------------------------------------- + */ + TupleDesc +-ExecCleanTypeFromTL(List *targetList, bool hasoid) ++ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hassecid) + { +- return ExecTypeFromTLInternal(targetList, hasoid, true); ++ return ExecTypeFromTLInternal(targetList, hasoid, hassecid, true); + } + + static TupleDesc +-ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk) ++ExecTypeFromTLInternal(List *targetList, ++ bool hasoid, bool hassecid, bool skipjunk) + { + TupleDesc typeInfo; + ListCell *l; +@@ -928,7 +929,7 @@ ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk) + len = ExecCleanTargetListLength(targetList); + else + len = ExecTargetListLength(targetList); +- typeInfo = CreateTemplateTupleDesc(len, hasoid); ++ typeInfo = CreateTemplateTupleDesc(len, hasoid, hassecid); + + foreach(l, targetList) + { +@@ -960,7 +961,7 @@ ExecTypeFromExprList(List *exprList) + int cur_resno = 1; + char fldname[NAMEDATALEN]; + +- typeInfo = CreateTemplateTupleDesc(list_length(exprList), false); ++ typeInfo = CreateTemplateTupleDesc(list_length(exprList), false, false); + + foreach(l, exprList) + { +diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c +index 98e4a64..14f9404 100644 +--- a/src/backend/executor/execUtils.c ++++ b/src/backend/executor/execUtils.c +@@ -444,6 +444,7 @@ void + ExecAssignResultTypeFromTL(PlanState *planstate) + { + bool hasoid; ++ bool hassecid; + TupleDesc tupDesc; + + if (ExecContextForcesOids(planstate, &hasoid)) +@@ -456,12 +457,15 @@ ExecAssignResultTypeFromTL(PlanState *planstate) + hasoid = false; + } + ++ if (!ExecContextForcesSecids(planstate, &hassecid)) ++ hassecid = false; ++ + /* + * ExecTypeFromTL needs the parse-time representation of the tlist, not a + * list of ExprStates. This is good because some plan nodes don't bother + * to set up planstate->targetlist ... + */ +- tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid); ++ tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid, hassecid); + ExecAssignResultType(planstate, tupDesc); + } + +diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c +index d552698..ed1913f 100644 +--- a/src/backend/executor/functions.c ++++ b/src/backend/executor/functions.c +@@ -1153,7 +1153,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList, + + /* Set up junk filter if needed */ + if (junkFilter) +- *junkFilter = ExecInitJunkFilter(tlist, false, NULL); ++ *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL); + } + else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID) + { +@@ -1192,7 +1192,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList, + } + /* Set up junk filter if needed */ + if (junkFilter) +- *junkFilter = ExecInitJunkFilter(tlist, false, NULL); ++ *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL); + return false; /* NOT returning whole tuple */ + } + } +@@ -1205,7 +1205,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList, + * what the caller expects will happen at runtime. + */ + if (junkFilter) +- *junkFilter = ExecInitJunkFilter(tlist, false, NULL); ++ *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL); + return true; + } + Assert(tupdesc); +diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c +index ddd91fc..cfb685e 100644 +--- a/src/backend/executor/nodeAgg.c ++++ b/src/backend/executor/nodeAgg.c +@@ -89,6 +89,7 @@ + #include "optimizer/tlist.h" + #include "parser/parse_agg.h" + #include "parser/parse_coerce.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/lsyscache.h" +@@ -1641,6 +1642,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) + get_func_name(finalfn_oid)); + } + } ++ /* SELinux checks */ ++ sepgsql_aggregate_execute(aggref->aggfnoid); + + /* resolve actual type of transition state, if polymorphic */ + aggtranstype = aggform->aggtranstype; +@@ -1722,7 +1725,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) + * Get a tupledesc corresponding to the inputs (including sort + * expressions) of the agg. + */ +- peraggstate->evaldesc = ExecTypeFromTL(aggref->args, false); ++ peraggstate->evaldesc = ExecTypeFromTL(aggref->args, false, false); + + /* Create slot we're going to do argument evaluation in */ + peraggstate->evalslot = ExecInitExtraTupleSlot(estate); +diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c +index 66e6b74..a31907c 100644 +--- a/src/backend/executor/nodeFunctionscan.c ++++ b/src/backend/executor/nodeFunctionscan.c +@@ -178,7 +178,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) + /* Base data type, i.e. scalar */ + char *attname = strVal(linitial(node->funccolnames)); + +- tupdesc = CreateTemplateTupleDesc(1, false); ++ tupdesc = CreateTemplateTupleDesc(1, false, false); + TupleDescInitEntry(tupdesc, + (AttrNumber) 1, + attname, +diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c +index ca6b0f8..b5c79d0 100644 +--- a/src/backend/executor/nodeMergejoin.c ++++ b/src/backend/executor/nodeMergejoin.c +@@ -98,6 +98,7 @@ + #include "executor/execdefs.h" + #include "executor/nodeMergejoin.h" + #include "miscadmin.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/lsyscache.h" + #include "utils/memutils.h" +@@ -216,6 +217,9 @@ MJExamineQuals(List *mergeclauses, + aclcheck_error(aclresult, ACL_KIND_PROC, + get_func_name(cmpproc)); + ++ /* SELinux permissions */ ++ sepgsql_proc_execute(cmpproc); ++ + /* Set up the fmgr lookup information */ + fmgr_info(cmpproc, &(clause->cmpfinfo)); + +diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c +index 7856b66..eee2739 100644 +--- a/src/backend/executor/nodeModifyTable.c ++++ b/src/backend/executor/nodeModifyTable.c +@@ -38,11 +38,13 @@ + #include "postgres.h" + + #include "access/xact.h" ++#include "catalog/pg_seclabel.h" + #include "commands/trigger.h" + #include "executor/executor.h" + #include "executor/nodeModifyTable.h" + #include "miscadmin.h" + #include "nodes/nodeFuncs.h" ++#include "sepgsql/hooks.h" + #include "storage/bufmgr.h" + #include "utils/builtins.h" + #include "utils/memutils.h" +@@ -160,7 +162,8 @@ ExecProcessReturning(ProjectionInfo *projectReturning, + static TupleTableSlot * + ExecInsert(TupleTableSlot *slot, + TupleTableSlot *planSlot, +- EState *estate) ++ EState *estate, ++ Oid securityId) + { + HeapTuple tuple; + ResultRelInfo *resultRelInfo; +@@ -194,6 +197,8 @@ ExecInsert(TupleTableSlot *slot, + */ + if (resultRelationDesc->rd_rel->relhasoids) + HeapTupleSetOid(tuple, InvalidOid); ++ if (resultRelationDesc->rd_rel->relhassecids) ++ HeapTupleSetSecid(tuple, securityId); + + /* BEFORE ROW INSERT Triggers */ + if (resultRelInfo->ri_TrigDesc && +@@ -224,6 +229,8 @@ ExecInsert(TupleTableSlot *slot, + tuple = newtuple; + } + } ++ /* SELinux checks */ ++ sepgsql_tuple_insert(resultRelationDesc, tuple); + + /* + * Check the constraints of the tuple +@@ -421,7 +428,8 @@ ExecUpdate(ItemPointer tupleid, + TupleTableSlot *slot, + TupleTableSlot *planSlot, + EPQState *epqstate, +- EState *estate) ++ EState *estate, ++ Oid securityId) + { + HeapTuple tuple; + ResultRelInfo *resultRelInfo; +@@ -449,6 +457,13 @@ ExecUpdate(ItemPointer tupleid, + resultRelInfo = estate->es_result_relation_info; + resultRelationDesc = resultRelInfo->ri_RelationDesc; + ++ /* ++ * If the result relation has writable system attributes, ++ * we store user given value (or InvalidOid) on the tuple. ++ */ ++ if (resultRelationDesc->rd_rel->relhassecids) ++ HeapTupleSetSecid(tuple, securityId); ++ + /* BEFORE ROW UPDATE Triggers */ + if (resultRelInfo->ri_TrigDesc && + resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0) +@@ -479,6 +494,8 @@ ExecUpdate(ItemPointer tupleid, + tuple = newtuple; + } + } ++ /* SELinux checks */ ++ sepgsql_tuple_update(resultRelationDesc, tupleid, tuple); + + /* + * Check the constraints of the tuple +@@ -635,6 +652,42 @@ fireASTriggers(ModifyTableState *node) + } + } + ++/* ++ * FetchWritableSecLabel ++ * ++ * It moves user given security label into slot-> ++ */ ++static Oid ++FetchWritableSecLabel(Relation relation, ++ JunkFilter *junkfilter, ++ TupleTableSlot *slot) ++{ ++ Oid securityId = InvalidOid; ++ AttrNumber attno; ++ Datum datum; ++ bool isnull; ++ char *label; ++ ++ /* ++ * If no explicit label was given, set a default label later ++ */ ++ attno = ExecFindJunkAttribute(junkfilter, "security_label"); ++ if (attno != InvalidAttrNumber && !ignore_security_label_input) ++ { ++ datum = ExecGetJunkAttribute(slot, attno, &isnull); ++ if (isnull) ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("Unable to set NULL on \"security_label\""))); ++ ++ label = TextDatumGetCString(datum); ++ ++ securityId = seclabelTransInput(RelationGetRelid(relation), label); ++ ++ pfree(label); ++ } ++ return securityId; ++} + + /* ---------------------------------------------------------------- + * ExecModifyTable +@@ -682,6 +735,8 @@ ExecModifyTable(ModifyTableState *node) + */ + for (;;) + { ++ Oid securityId = InvalidOid; ++ + planSlot = ExecProcNode(subplanstate); + + if (TupIsNull(planSlot)) +@@ -705,6 +760,14 @@ ExecModifyTable(ModifyTableState *node) + + if (junkfilter != NULL) + { ++ Relation targetRel ++ = estate->es_result_relation_info->ri_RelationDesc; ++ ++ /* ++ * extract writable system column ++ */ ++ securityId = FetchWritableSecLabel(targetRel, junkfilter, slot); ++ + /* + * extract the 'ctid' junk attribute. + */ +@@ -734,11 +797,11 @@ ExecModifyTable(ModifyTableState *node) + switch (operation) + { + case CMD_INSERT: +- slot = ExecInsert(slot, planSlot, estate); ++ slot = ExecInsert(slot, planSlot, estate, securityId); + break; + case CMD_UPDATE: + slot = ExecUpdate(tupleid, slot, planSlot, +- &node->mt_epqstate, estate); ++ &node->mt_epqstate, estate, securityId); + break; + case CMD_DELETE: + slot = ExecDelete(tupleid, planSlot, +@@ -850,7 +913,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) + * RETURNING list. We assume the rest will look the same. + */ + tupDesc = ExecTypeFromTL((List *) linitial(node->returningLists), +- false); ++ false, false); + + /* Set up a slot for the output of the RETURNING projection(s) */ + ExecInitResultTupleSlot(estate, &mtstate->ps); +@@ -884,7 +947,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) + * We still must construct a dummy result tuple type, because InitPlan + * expects one (maybe should change that?). + */ +- tupDesc = ExecTypeFromTL(NIL, false); ++ tupDesc = ExecTypeFromTL(NIL, false, false); + ExecInitResultTupleSlot(estate, &mtstate->ps); + ExecAssignResultType(&mtstate->ps, tupDesc); + +@@ -976,6 +1039,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) + + j = ExecInitJunkFilter(subplan->targetlist, + resultRelInfo->ri_RelationDesc->rd_att->tdhasoid, ++ resultRelInfo->ri_RelationDesc->rd_att->tdhassecid, + ExecInitExtraTupleSlot(estate)); + + if (operation == CMD_UPDATE || operation == CMD_DELETE) +diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c +index 9f1ff16..bef704b 100644 +--- a/src/backend/executor/nodeSubplan.c ++++ b/src/backend/executor/nodeSubplan.c +@@ -859,7 +859,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) + * (hack alert!). The righthand expressions will be evaluated in our + * own innerecontext. + */ +- tupDesc = ExecTypeFromTL(leftptlist, false); ++ tupDesc = ExecTypeFromTL(leftptlist, false, false); + slot = ExecInitExtraTupleSlot(estate); + ExecSetSlotDescriptor(slot, tupDesc); + sstate->projLeft = ExecBuildProjectionInfo(lefttlist, +@@ -867,7 +867,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) + slot, + NULL); + +- tupDesc = ExecTypeFromTL(rightptlist, false); ++ tupDesc = ExecTypeFromTL(rightptlist, false, false); + slot = ExecInitExtraTupleSlot(estate); + ExecSetSlotDescriptor(slot, tupDesc); + sstate->projRight = ExecBuildProjectionInfo(righttlist, +diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c +index 712bab1..e69f3c7 100644 +--- a/src/backend/executor/nodeWindowAgg.c ++++ b/src/backend/executor/nodeWindowAgg.c +@@ -43,6 +43,7 @@ + #include "optimizer/clauses.h" + #include "parser/parse_agg.h" + #include "parser/parse_coerce.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/datum.h" +@@ -1554,6 +1555,12 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) + aclcheck_error(aclresult, ACL_KIND_PROC, + get_func_name(wfunc->winfnoid)); + ++ /* SELinux checks */ ++ if (wfunc->winagg) ++ sepgsql_aggregate_execute(wfunc->winfnoid); ++ else ++ sepgsql_proc_execute(wfunc->winfnoid); ++ + /* Fill in the perfuncstate data */ + perfuncstate->wfuncstate = wfuncstate; + perfuncstate->wfunc = wfunc; +diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c +index 7f0b5e4..2e2c63b 100644 +--- a/src/backend/executor/spi.c ++++ b/src/backend/executor/spi.c +@@ -767,6 +767,8 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, + mtuple->t_tableOid = tuple->t_tableOid; + if (rel->rd_att->tdhasoid) + HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple)); ++ if (rel->rd_att->tdhassecid) ++ HeapTupleSetSecid(mtuple, HeapTupleGetSecid(tuple)); + } + else + { +@@ -795,7 +797,8 @@ SPI_fnumber(TupleDesc tupdesc, const char *fname) + return res + 1; + } + +- sysatt = SystemAttributeByName(fname, true /* "oid" will be accepted */ ); ++ /* "oid" and "security_label" will be accepted */ ++ sysatt = SystemAttributeByName(fname, true, true); + if (sysatt != NULL) + return sysatt->attnum; + +@@ -820,7 +823,7 @@ SPI_fname(TupleDesc tupdesc, int fnumber) + if (fnumber > 0) + att = tupdesc->attrs[fnumber - 1]; + else +- att = SystemAttributeDefinition(fnumber, true); ++ att = SystemAttributeDefinition(fnumber, true, true); + + return pstrdup(NameStr(att->attname)); + } +@@ -852,7 +855,7 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber) + if (fnumber > 0) + typoid = tupdesc->attrs[fnumber - 1]->atttypid; + else +- typoid = (SystemAttributeDefinition(fnumber, true))->atttypid; ++ typoid = (SystemAttributeDefinition(fnumber, true, true))->atttypid; + + getTypeOutputInfo(typoid, &foutoid, &typisvarlena); + +@@ -909,7 +912,7 @@ SPI_gettype(TupleDesc tupdesc, int fnumber) + if (fnumber > 0) + typoid = tupdesc->attrs[fnumber - 1]->atttypid; + else +- typoid = (SystemAttributeDefinition(fnumber, true))->atttypid; ++ typoid = (SystemAttributeDefinition(fnumber, true, true))->atttypid; + + typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid)); + +@@ -939,7 +942,7 @@ SPI_gettypeid(TupleDesc tupdesc, int fnumber) + if (fnumber > 0) + return tupdesc->attrs[fnumber - 1]->atttypid; + else +- return (SystemAttributeDefinition(fnumber, true))->atttypid; ++ return (SystemAttributeDefinition(fnumber, true, true))->atttypid; + } + + char * +diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c +index f4f50f8..4ab5698 100644 +--- a/src/backend/libpq/be-fsstubs.c ++++ b/src/backend/libpq/be-fsstubs.c +@@ -46,6 +46,7 @@ + #include "libpq/be-fsstubs.h" + #include "libpq/libpq-fs.h" + #include "miscadmin.h" ++#include "sepgsql/hooks.h" + #include "storage/fd.h" + #include "storage/large_object.h" + #include "utils/acl.h" +@@ -172,6 +173,8 @@ lo_read(int fd, char *buf, int len) + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for large object %u", + cookies[fd]->id))); ++ /* SELinux checks */ ++ sepgsql_largeobject_read(cookies[fd]->id, cookies[fd]->snapshot); + + status = inv_read(cookies[fd], buf, len); + +@@ -204,6 +207,8 @@ lo_write(int fd, const char *buf, int len) + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for large object %u", + cookies[fd]->id))); ++ /* SELinux checks */ ++ sepgsql_largeobject_write(cookies[fd]->id, cookies[fd]->snapshot); + + status = inv_write(cookies[fd], buf, len); + +@@ -233,6 +238,7 @@ Datum + lo_creat(PG_FUNCTION_ARGS) + { + Oid lobjId; ++ Oid securityId; + + /* + * We don't actually need to store into fscxt, but create it anyway to +@@ -240,7 +246,10 @@ lo_creat(PG_FUNCTION_ARGS) + */ + CreateFSContext(); + +- lobjId = inv_create(InvalidOid); ++ /* SELinux checks */ ++ securityId = sepgsql_largeobject_create(InvalidOid); ++ ++ lobjId = inv_create(InvalidOid, securityId); + + PG_RETURN_OID(lobjId); + } +@@ -249,6 +258,7 @@ Datum + lo_create(PG_FUNCTION_ARGS) + { + Oid lobjId = PG_GETARG_OID(0); ++ Oid securityId; + + /* + * We don't actually need to store into fscxt, but create it anyway to +@@ -256,7 +266,10 @@ lo_create(PG_FUNCTION_ARGS) + */ + CreateFSContext(); + +- lobjId = inv_create(lobjId); ++ /* SELinux checks */ ++ securityId = sepgsql_largeobject_create(lobjId); ++ ++ lobjId = inv_create(lobjId, securityId); + + PG_RETURN_OID(lobjId); + } +@@ -286,6 +299,9 @@ lo_unlink(PG_FUNCTION_ARGS) + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be owner of large object %u", lobjId))); + ++ /* SELinux checks */ ++ sepgsql_largeobject_drop(lobjId, false); ++ + /* + * If there are any open LO FDs referencing that ID, close 'em. + */ +@@ -381,9 +397,10 @@ lo_import_internal(text *filename, Oid lobjOid) + int nbytes, + tmp; + char buf[BUFSIZE]; +- char fnamebuf[MAXPGPATH]; ++ char *fnamebuf = text_to_cstring(filename); + LargeObjectDesc *lobj; + Oid oid; ++ Oid securityId; + + #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS + if (!superuser()) +@@ -392,13 +409,14 @@ lo_import_internal(text *filename, Oid lobjOid) + errmsg("must be superuser to use server-side lo_import()"), + errhint("Anyone can use the client-side lo_import() provided by libpq."))); + #endif +- + CreateFSContext(); + ++ /* SELinux checks */ ++ securityId = sepgsql_largeobject_import(lobjOid, fnamebuf); ++ + /* + * open the file to be read in + */ +- text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); + fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666); + if (fd < 0) + ereport(ERROR, +@@ -409,7 +427,7 @@ lo_import_internal(text *filename, Oid lobjOid) + /* + * create an inversion object + */ +- oid = inv_create(lobjOid); ++ oid = inv_create(lobjOid, securityId); + + /* + * read in from the filesystem and write to the inversion object +@@ -447,7 +465,7 @@ lo_export(PG_FUNCTION_ARGS) + int nbytes, + tmp; + char buf[BUFSIZE]; +- char fnamebuf[MAXPGPATH]; ++ char *fnamebuf = text_to_cstring(filename); + LargeObjectDesc *lobj; + mode_t oumask; + +@@ -458,7 +476,6 @@ lo_export(PG_FUNCTION_ARGS) + errmsg("must be superuser to use server-side lo_export()"), + errhint("Anyone can use the client-side lo_export() provided by libpq."))); + #endif +- + CreateFSContext(); + + /* +@@ -466,6 +483,9 @@ lo_export(PG_FUNCTION_ARGS) + */ + lobj = inv_open(lobjId, INV_READ, fscxt); + ++ /* SELinux checks */ ++ sepgsql_largeobject_export(lobj->id, lobj->snapshot, fnamebuf); ++ + /* + * open the file to be written to + * +@@ -473,7 +493,6 @@ lo_export(PG_FUNCTION_ARGS) + * 022. This code used to drop it all the way to 0, but creating + * world-writable export files doesn't seem wise. + */ +- text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); + oumask = umask((mode_t) 0022); + fd = PathNameOpenFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666); + umask(oumask); +@@ -528,6 +547,9 @@ lo_truncate(PG_FUNCTION_ARGS) + errmsg("permission denied for large object %u", + cookies[fd]->id))); + ++ /* SELinux checks */ ++ sepgsql_largeobject_write(cookies[fd]->id, cookies[fd]->snapshot); ++ + inv_truncate(cookies[fd], len); + + PG_RETURN_INT32(0); +diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c +index e770e89..9642a66 100644 +--- a/src/backend/nodes/copyfuncs.c ++++ b/src/backend/nodes/copyfuncs.c +@@ -1823,6 +1823,7 @@ _copyRangeTblEntry(RangeTblEntry *from) + COPY_SCALAR_FIELD(checkAsUser); + COPY_BITMAPSET_FIELD(selectedCols); + COPY_BITMAPSET_FIELD(modifiedCols); ++ COPY_SCALAR_FIELD(rowlvPerms); + + return newnode; + } +@@ -2755,6 +2756,21 @@ _copyAlterOwnerStmt(AlterOwnerStmt *from) + return newnode; + } + ++static AlterSecLabelStmt * ++_copyAlterSecLabelStmt(AlterSecLabelStmt *from) ++{ ++ AlterSecLabelStmt *newnode = makeNode(AlterSecLabelStmt); ++ ++ COPY_SCALAR_FIELD(objectType); ++ COPY_NODE_FIELD(relation); ++ COPY_NODE_FIELD(object); ++ COPY_NODE_FIELD(objarg); ++ COPY_STRING_FIELD(addname); ++ COPY_NODE_FIELD(secLabel); ++ ++ return newnode; ++} ++ + static RuleStmt * + _copyRuleStmt(RuleStmt *from) + { +@@ -3968,6 +3984,9 @@ copyObject(void *from) + case T_AlterOwnerStmt: + retval = _copyAlterOwnerStmt(from); + break; ++ case T_AlterSecLabelStmt: ++ retval = _copyAlterSecLabelStmt(from); ++ break; + case T_RuleStmt: + retval = _copyRuleStmt(from); + break; +diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c +index 5d83727..fd4071d 100644 +--- a/src/backend/nodes/equalfuncs.c ++++ b/src/backend/nodes/equalfuncs.c +@@ -1308,6 +1308,19 @@ _equalAlterOwnerStmt(AlterOwnerStmt *a, AlterOwnerStmt *b) + } + + static bool ++_equalAlterSecLabelStmt(AlterSecLabelStmt *a, AlterSecLabelStmt *b) ++{ ++ COMPARE_SCALAR_FIELD(objectType); ++ COMPARE_NODE_FIELD(relation); ++ COMPARE_NODE_FIELD(object); ++ COMPARE_NODE_FIELD(objarg); ++ COMPARE_STRING_FIELD(addname); ++ COMPARE_NODE_FIELD(secLabel); ++ ++ return true; ++} ++ ++static bool + _equalRuleStmt(RuleStmt *a, RuleStmt *b) + { + COMPARE_NODE_FIELD(relation); +@@ -2186,6 +2199,7 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b) + COMPARE_SCALAR_FIELD(checkAsUser); + COMPARE_BITMAPSET_FIELD(selectedCols); + COMPARE_BITMAPSET_FIELD(modifiedCols); ++ COMPARE_SCALAR_FIELD(rowlvPerms); + + return true; + } +@@ -2657,6 +2671,9 @@ equal(void *a, void *b) + case T_AlterOwnerStmt: + retval = _equalAlterOwnerStmt(a, b); + break; ++ case T_AlterSecLabelStmt: ++ retval = _equalAlterSecLabelStmt(a, b); ++ break; + case T_RuleStmt: + retval = _equalRuleStmt(a, b); + break; +diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c +index e7dae4b..4e8b350 100644 +--- a/src/backend/nodes/outfuncs.c ++++ b/src/backend/nodes/outfuncs.c +@@ -2135,6 +2135,7 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node) + WRITE_OID_FIELD(checkAsUser); + WRITE_BITMAPSET_FIELD(selectedCols); + WRITE_BITMAPSET_FIELD(modifiedCols); ++ WRITE_UINT_FIELD(rowlvPerms); + } + + static void +diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c +index bc6e2a6..792b9ff 100644 +--- a/src/backend/nodes/readfuncs.c ++++ b/src/backend/nodes/readfuncs.c +@@ -1171,6 +1171,7 @@ _readRangeTblEntry(void) + READ_OID_FIELD(checkAsUser); + READ_BITMAPSET_FIELD(selectedCols); + READ_BITMAPSET_FIELD(modifiedCols); ++ READ_UINT_FIELD(rowlvPerms); + + READ_DONE(); + } +diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c +index a0e31a2..086b313 100644 +--- a/src/backend/optimizer/plan/createplan.c ++++ b/src/backend/optimizer/plan/createplan.c +@@ -32,6 +32,7 @@ + #include "optimizer/var.h" + #include "parser/parse_clause.h" + #include "parser/parsetree.h" ++#include "sepgsql/hooks.h" + #include "utils/lsyscache.h" + + +@@ -305,6 +306,9 @@ create_scan_plan(PlannerInfo *root, Path *best_path) + break; + } + ++ /* Append row-level access control policy */ ++ sepgsql_rowlv_add_policy(root, (Scan *)plan); ++ + /* + * If there are any pseudoconstant clauses attached to this node, insert a + * gating Result node that evaluates the pseudoconstants as one-time +diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c +index e525ba6..6474fbc 100644 +--- a/src/backend/optimizer/util/clauses.c ++++ b/src/backend/optimizer/util/clauses.c +@@ -38,6 +38,7 @@ + #include "parser/parse_coerce.h" + #include "parser/parse_func.h" + #include "rewrite/rewriteManip.h" ++#include "sepgsql/hooks.h" + #include "tcop/tcopprot.h" + #include "utils/acl.h" + #include "utils/builtins.h" +@@ -3712,6 +3713,10 @@ inline_function(Oid funcid, Oid result_type, List *args, + if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK) + return NULL; + ++ /* SELinux checks */ ++ if (!sepgsql_proc_be_inlined(func_tuple)) ++ return NULL; ++ + /* + * Make a temporary memory context, so that we don't leak all the stuff + * that parsing might create. +@@ -4164,7 +4169,8 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) + funcform->provolatile == PROVOLATILE_VOLATILE || + funcform->prosecdef || + !funcform->proretset || +- !heap_attisnull(func_tuple, Anum_pg_proc_proconfig)) ++ !heap_attisnull(func_tuple, Anum_pg_proc_proconfig) || ++ !sepgsql_proc_be_inlined(func_tuple)) + { + ReleaseSysCache(func_tuple); + return NULL; +diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c +index 6b99a10..4eb9d24 100644 +--- a/src/backend/parser/analyze.c ++++ b/src/backend/parser/analyze.c +@@ -25,6 +25,7 @@ + #include "postgres.h" + + #include "access/sysattr.h" ++#include "catalog/heap.h" + #include "catalog/pg_type.h" + #include "nodes/makefuncs.h" + #include "nodes/nodeFuncs.h" +@@ -40,6 +41,7 @@ + #include "parser/parse_target.h" + #include "parser/parsetree.h" + #include "rewrite/rewriteManip.h" ++#include "utils/guc.h" + #include "utils/rel.h" + + +@@ -651,7 +653,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) + tle = makeTargetEntry(expr, + attr_num, + col->name, +- false); ++ attr_num < 0 ? true : false); + qry->targetList = lappend(qry->targetList, tle); + + rte->modifiedCols = bms_add_member(rte->modifiedCols, +diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y +index b793c4d..866e0ba 100644 +--- a/src/backend/parser/gram.y ++++ b/src/backend/parser/gram.y +@@ -183,8 +183,8 @@ static TypeName *TableFuncTypeName(List *columns); + %type stmt schema_stmt + AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterFdwStmt + AlterForeignServerStmt AlterGroupStmt +- AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt +- AlterUserStmt AlterUserMappingStmt AlterUserSetStmt ++ AlterObjectSchemaStmt AlterOwnerStmt AlterSecLabelStmt AlterSeqStmt ++ AlterTableStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt + AlterRoleStmt AlterRoleSetStmt + AlterDefaultPrivilegesStmt DefACLAction + AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt +@@ -422,6 +422,8 @@ static TypeName *TableFuncTypeName(List *columns); + %type OptTableSpace OptConsTableSpace OptTableSpaceOwner + %type opt_check_option + ++%type SecLabelItem ++ + %type xml_attribute_el + %type xml_attribute_list xml_attributes + %type xml_root_version opt_xml_root_standalone +@@ -498,7 +500,7 @@ static TypeName *TableFuncTypeName(List *columns); + + KEY + +- LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING ++ LABEL LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING + LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP + LOCATION LOCK_P LOGIN_P + +@@ -654,6 +656,7 @@ stmt : + | AlterGroupStmt + | AlterObjectSchemaStmt + | AlterOwnerStmt ++ | AlterSecLabelStmt + | AlterSeqStmt + | AlterTableStmt + | AlterRoleSetStmt +@@ -1758,6 +1761,20 @@ alter_table_cmd: + n->subtype = AT_DropOids; + $$ = (Node *)n; + } ++ /* ALTER TABLE SET WITH SECURITY LABEL */ ++ | SET WITH SECURITY LABEL ++ { ++ AlterTableCmd *n = makeNode(AlterTableCmd); ++ n->subtype = AT_AddSecLabel; ++ $$ = (Node *)n; ++ } ++ /* ALTER TABLE SET WITHOUT SECURITY LABEL */ ++ | SET WITHOUT SECURITY LABEL ++ { ++ AlterTableCmd *n = makeNode(AlterTableCmd); ++ n->subtype = AT_DropSecLabel; ++ $$ = (Node *)n; ++ } + /* ALTER TABLE CLUSTER ON */ + | CLUSTER ON name + { +@@ -6022,6 +6039,102 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId + } + ; + ++/***************************************************************************** ++ * ++ * ALTER THING name SECURITY LABEL TO new_label ++ * ++ *****************************************************************************/ ++ ++AlterSecLabelStmt: ALTER DATABASE database_name SecLabelItem ++ { ++ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); ++ n->objectType = OBJECT_DATABASE; ++ n->object = list_make1(makeString($3)); ++ n->secLabel = $4; ++ $$ = (Node *)n; ++ } ++ | ALTER SCHEMA name SecLabelItem ++ { ++ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); ++ n->objectType = OBJECT_SCHEMA; ++ n->object = list_make1(makeString($3)); ++ n->secLabel = $4; ++ $$ = (Node *)n; ++ } ++ | ALTER TABLE relation_expr SecLabelItem ++ { ++ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); ++ n->objectType = OBJECT_TABLE; ++ n->relation = $3; ++ n->secLabel = $4; ++ $$ = (Node *)n; ++ } ++ | ALTER TABLE relation_expr ALTER opt_column ColId SecLabelItem ++ { ++ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); ++ n->objectType = OBJECT_COLUMN; ++ n->relation = $3; ++ n->addname = $6; ++ n->secLabel = $7; ++ $$ = (Node *)n; ++ } ++ | ALTER SEQUENCE qualified_name SecLabelItem ++ { ++ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); ++ n->objectType = OBJECT_SEQUENCE; ++ n->relation = $3; ++ n->secLabel = $4; ++ $$ = (Node *)n; ++ } ++ | ALTER VIEW qualified_name SecLabelItem ++ { ++ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); ++ n->objectType = OBJECT_VIEW; ++ n->relation = $3; ++ n->secLabel = $4; ++ $$ = (Node *)n; ++ } ++ | ALTER FUNCTION function_with_argtypes SecLabelItem ++ { ++ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); ++ n->objectType = OBJECT_FUNCTION; ++ n->object = $3->funcname; ++ n->objarg = $3->funcargs; ++ n->secLabel = $4; ++ $$ = (Node *)n; ++ } ++ | ALTER AGGREGATE func_name aggr_args SecLabelItem ++ { ++ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); ++ n->objectType = OBJECT_AGGREGATE; ++ n->object = $3; ++ n->objarg = $4; ++ n->secLabel = $5; ++ $$ = (Node *)n; ++ } ++ | ALTER LARGE_P OBJECT_P Iconst SecLabelItem ++ { ++ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); ++ n->objectType = OBJECT_LARGEOBJECT; ++ n->object = list_make1(makeInteger($4)); ++ n->secLabel = $5; ++ $$ = (Node *)n; ++ } ++ | ALTER TYPE_P any_name SecLabelItem ++ { ++ AlterSecLabelStmt *n = makeNode(AlterSecLabelStmt); ++ n->objectType = OBJECT_TYPE; ++ n->object = $3; ++ n->secLabel = $4; ++ $$ = (Node *)n; ++ } ++ ; ++ ++SecLabelItem: SECURITY LABEL TO Sconst ++ { ++ $$ = makeString($4); ++ } ++ ; + + /***************************************************************************** + * +@@ -10921,6 +11034,7 @@ unreserved_keyword: + | INVOKER + | ISOLATION + | KEY ++ | LABEL + | LANGUAGE + | LARGE_P + | LAST_P +diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c +index eb6505a..1962055 100644 +--- a/src/backend/parser/parse_relation.c ++++ b/src/backend/parser/parse_relation.c +@@ -2302,8 +2302,8 @@ specialAttNum(const char *attname) + { + Form_pg_attribute sysatt; + +- sysatt = SystemAttributeByName(attname, +- true /* "oid" will be accepted */ ); ++ /* "oid" and "security_label" will be accepted */ ++ sysatt = SystemAttributeByName(attname, true, true); + if (sysatt != NULL) + return sysatt->attnum; + return InvalidAttrNumber; +@@ -2324,7 +2324,9 @@ attnumAttName(Relation rd, int attid) + { + Form_pg_attribute sysatt; + +- sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids); ++ sysatt = SystemAttributeDefinition(attid, ++ rd->rd_rel->relhasoids, ++ rd->rd_rel->relhassecids); + return &sysatt->attname; + } + if (attid > rd->rd_att->natts) +@@ -2346,7 +2348,9 @@ attnumTypeId(Relation rd, int attid) + { + Form_pg_attribute sysatt; + +- sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids); ++ sysatt = SystemAttributeDefinition(attid, ++ rd->rd_rel->relhasoids, ++ rd->rd_rel->relhassecids); + return sysatt->atttypid; + } + if (attid > rd->rd_att->natts) +diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c +index e542dc0..8191f94 100644 +--- a/src/backend/parser/parse_target.c ++++ b/src/backend/parser/parse_target.c +@@ -14,6 +14,7 @@ + */ + #include "postgres.h" + ++#include "catalog/heap.h" + #include "catalog/pg_type.h" + #include "commands/dbcommands.h" + #include "funcapi.h" +@@ -365,16 +366,34 @@ transformAssignedExpr(ParseState *pstate, + Oid attrtype; /* type of target column */ + int32 attrtypmod; + Relation rd = pstate->p_target_relation; ++ bool relhasoids = RelationGetForm(rd)->relhasoids; ++ bool relhassecids = RelationGetForm(rd)->relhassecids; + + 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 ++ { ++ Form_pg_attribute attr; ++ ++ attr = SystemAttributeDefinition(attrno, relhasoids, relhassecids); ++ if (attr && SystemAttributeWritable(attrno, relhasoids, relhassecids)) ++ { ++ attrtype = attr->atttypid; ++ attrtypmod = attr->atttypmod; ++ } ++ else ++ { ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("cannot assign to system column \"%s\"", colname), ++ parser_errposition(pstate, location))); ++ return NULL; ++ } ++ } + + /* + * If the expression is a DEFAULT placeholder, insert the attribute's +@@ -503,6 +522,10 @@ updateTargetListEntry(ParseState *pstate, + List *indirection, + int location) + { ++ Relation rel = pstate->p_target_relation; ++ bool relhasoids = RelationGetForm(rel)->relhasoids; ++ bool relhassecids = RelationGetForm(rel)->relhassecids; ++ + /* Fix up expression as needed */ + tle->expr = transformAssignedExpr(pstate, + tle->expr, +@@ -519,6 +542,9 @@ updateTargetListEntry(ParseState *pstate, + */ + tle->resno = (AttrNumber) attrno; + tle->resname = colname; ++ ++ if (SystemAttributeWritable(attrno, relhasoids, relhassecids)) ++ tle->resjunk = true; + } + + +@@ -793,6 +819,7 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos) + Bitmapset *wholecols = NULL; + Bitmapset *partialcols = NULL; + ListCell *tl; ++ uint32 system_attrs = 0UL; + + foreach(tl, cols) + { +@@ -801,14 +828,42 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos) + int attrno; + + /* Lookup column name, ereport on failure */ +- attrno = attnameAttNum(pstate->p_target_relation, name, false); ++ attrno = attnameAttNum(pstate->p_target_relation, name, true); + if (attrno == InvalidAttrNumber) ++ { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + name, + RelationGetRelationName(pstate->p_target_relation)), + parser_errposition(pstate, col->location))); ++ } ++ else if (attrno < 0) ++ { ++ Relation rel = pstate->p_target_relation; ++ bool relhasoids = RelationGetForm(rel)->relhasoids; ++ bool relhassecids = RelationGetForm(rel)->relhassecids; ++ ++ if (SystemAttributeWritable(attrno, relhasoids, relhassecids)) ++ { ++ uint32 mask = (1<<(-attrno)); ++ ++ if ((system_attrs & mask) != 0) ++ ereport(ERROR, ++ (errcode(ERRCODE_DUPLICATE_COLUMN), ++ errmsg("column \"%s\" specified more than once", ++ name), ++ parser_errposition(pstate, col->location))); ++ system_attrs |= mask; ++ *attrnos = lappend_int(*attrnos, attrno); ++ continue; ++ } ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), ++ errmsg("column \"%s\" of relation \"%s\" is system column", ++ name, RelationGetRelationName(rel)), ++ parser_errposition(pstate, col->location))); ++ } + + /* + * Check for duplicates, but only of whole columns --- we allow +@@ -1263,7 +1318,7 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup) + expandRTE(rte, var->varno, 0, var->location, false, + &names, &vars); + +- tupleDesc = CreateTemplateTupleDesc(list_length(vars), false); ++ tupleDesc = CreateTemplateTupleDesc(list_length(vars), false, false); + i = 1; + forboth(lname, names, lvar, vars) + { +diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c +index 90d5c76..b78f9ba 100644 +--- a/src/backend/parser/parse_utilcmd.c ++++ b/src/backend/parser/parse_utilcmd.c +@@ -53,8 +53,10 @@ + #include "parser/parse_utilcmd.h" + #include "parser/parser.h" + #include "rewrite/rewriteManip.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" ++#include "utils/guc.h" + #include "utils/lsyscache.h" + #include "utils/relcache.h" + #include "utils/syscache.h" +@@ -70,6 +72,7 @@ typedef struct + List *inhRelations; /* relations to inherit from */ + bool isalter; /* true if altering existing table */ + bool hasoids; /* does relation have an OID column? */ ++ bool hassecids; /* does relation have an security label? */ + List *columns; /* ColumnDef items */ + List *ckconstraints; /* CHECK constraints */ + List *fkconstraints; /* FOREIGN KEY constraints */ +@@ -185,6 +188,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) + cxt.alist = NIL; + cxt.pkey = NULL; + cxt.hasoids = interpretOidsOption(stmt->options); ++ cxt.hassecids = default_with_secids; + + Assert(!stmt->ofTypename || !stmt->inhRelations); /* grammar enforces */ + +@@ -587,6 +591,9 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, + aclcheck_error(aclresult, ACL_KIND_CLASS, + RelationGetRelationName(relation)); + ++ /* SELinux checks */ ++ sepgsql_relation_getattr(RelationGetRelid(relation)); ++ + tupleDesc = RelationGetDescr(relation); + constr = tupleDesc->constr; + +@@ -1368,7 +1375,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) + if (constraint->contype == CONSTR_PRIMARY) + column->is_not_null = TRUE; + } +- else if (SystemAttributeByName(key, cxt->hasoids) != NULL) ++ else if (SystemAttributeByName(key, cxt->hasoids, cxt->hassecids) != NULL) + { + /* + * column will be a system column in the new table, so accept it. +@@ -1945,6 +1952,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) + cxt.inhRelations = NIL; + cxt.isalter = true; + cxt.hasoids = false; /* need not be right */ ++ cxt.hassecids = false; /* need not be right */ + cxt.columns = NIL; + cxt.ckconstraints = NIL; + cxt.fkconstraints = NIL; +diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c +index 98ab484..44c7a56 100644 +--- a/src/backend/postmaster/postmaster.c ++++ b/src/backend/postmaster/postmaster.c +@@ -109,6 +109,7 @@ + #include "postmaster/postmaster.h" + #include "postmaster/syslogger.h" + #include "replication/walsender.h" ++#include "sepgsql/hooks.h" + #include "storage/fd.h" + #include "storage/ipc.h" + #include "storage/pg_shmem.h" +@@ -212,7 +213,8 @@ static pid_t StartupPID = 0, + AutoVacPID = 0, + PgArchPID = 0, + PgStatPID = 0, +- SysLoggerPID = 0; ++ SysLoggerPID = 0, ++ SecWorkerPID = 0; + + /* Startup/shutdown state */ + #define NoShutdown 0 +@@ -466,6 +468,7 @@ static void ShmemBackendArrayRemove(Backend *bn); + #define StartBackgroundWriter() StartChildProcess(BgWriterProcess) + #define StartWalWriter() StartChildProcess(WalWriterProcess) + #define StartWalReceiver() StartChildProcess(WalReceiverProcess) ++#define StartSecurityWorker() StartChildProcess(SecurityWorkerProcess) + + /* Macros to check exit status of a child process */ + #define EXIT_STATUS_0(st) ((st) == 0) +@@ -1473,6 +1476,11 @@ ServerLoop(void) + if (PgStatPID == 0 && pmState == PM_RUN) + PgStatPID = pgstat_start(); + ++ /* If we have lost security worker, try to start a new one */ ++ if (SecWorkerPID == 0 && pmState == PM_RUN && ++ sepgsql_worker_needed()) ++ SecWorkerPID = StartSecurityWorker(); ++ + /* If we need to signal the autovacuum launcher, do so now */ + if (avlauncher_needs_signal) + { +@@ -2113,6 +2121,8 @@ SIGHUP_handler(SIGNAL_ARGS) + signal_child(SysLoggerPID, SIGHUP); + if (PgStatPID != 0) + signal_child(PgStatPID, SIGHUP); ++ if (SecWorkerPID != 0) ++ signal_child(SecWorkerPID, SIGHUP); + + /* Reload authentication config files too */ + if (!load_hba()) +@@ -2173,6 +2183,9 @@ pmdie(SIGNAL_ARGS) + /* and the walwriter too */ + if (WalWriterPID != 0) + signal_child(WalWriterPID, SIGTERM); ++ /* and the security worker too */ ++ if (SecWorkerPID != 0) ++ signal_child(SecWorkerPID, SIGTERM); + pmState = PM_WAIT_BACKUP; + } + +@@ -2223,6 +2236,9 @@ pmdie(SIGNAL_ARGS) + /* and the walwriter too */ + if (WalWriterPID != 0) + signal_child(WalWriterPID, SIGTERM); ++ /* and the security worker too */ ++ if (SecWorkerPID != 0) ++ signal_child(SecWorkerPID, SIGTERM); + pmState = PM_WAIT_BACKENDS; + } + +@@ -2258,6 +2274,8 @@ pmdie(SIGNAL_ARGS) + signal_child(PgArchPID, SIGQUIT); + if (PgStatPID != 0) + signal_child(PgStatPID, SIGQUIT); ++ if (SecWorkerPID != 0) ++ signal_child(SecWorkerPID, SIGQUIT); + ExitPostmaster(0); + break; + } +@@ -2529,6 +2547,16 @@ reaper(SIGNAL_ARGS) + continue; + } + ++ /* Was it the security worker process? */ ++ if (pid == SecWorkerPID) ++ { ++ SecWorkerPID = 0; ++ if (!EXIT_STATUS_0(exitstatus)) ++ LogChildExit(LOG, _("security worker process"), ++ pid, exitstatus); ++ continue; ++ } ++ + /* + * Else do standard backend child cleanup. + */ +@@ -2732,6 +2760,18 @@ HandleChildCrash(int pid, int exitstatus, const char *procname) + signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT)); + } + ++ /* Take care of the security worker process too */ ++ if (pid == SecWorkerPID) ++ SecWorkerPID = 0; ++ else if (SecWorkerPID != 0 && !FatalError) ++ { ++ ereport(DEBUG2, ++ (errmsg_internal("sending %s to process %d", ++ (SendStop ? "SIGSTOP" : "SIGQUIT"), ++ (int) SecWorkerPID))); ++ signal_child(SecWorkerPID, (SendStop ? SIGSTOP : SIGQUIT)); ++ } ++ + /* + * Force a power-cycle of the pgarch process too. (This isn't absolutely + * necessary, but it seems like a good idea for robustness, and it +@@ -2867,7 +2907,8 @@ PostmasterStateMachine(void) + WalReceiverPID == 0 && + (BgWriterPID == 0 || !FatalError) && + WalWriterPID == 0 && +- AutoVacPID == 0) ++ AutoVacPID == 0 && ++ SecWorkerPID == 0) + { + if (FatalError) + { +diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c +index 68be146..6ba1d2f 100644 +--- a/src/backend/rewrite/rewriteDefine.c ++++ b/src/backend/rewrite/rewriteDefine.c +@@ -27,6 +27,7 @@ + #include "rewrite/rewriteDefine.h" + #include "rewrite/rewriteManip.h" + #include "rewrite/rewriteSupport.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/inval.h" +@@ -265,6 +266,9 @@ DefineQueryRewrite(char *rulename, + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(event_relation)); + ++ /* SELinux checks */ ++ sepgsql_rule_create(event_relid, rulename); ++ + /* + * No rule actions that modify OLD or NEW + */ +diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c +index 25b44dd..e35f7c5 100644 +--- a/src/backend/rewrite/rewriteHandler.c ++++ b/src/backend/rewrite/rewriteHandler.c +@@ -23,6 +23,7 @@ + #include "rewrite/rewriteDefine.h" + #include "rewrite/rewriteHandler.h" + #include "rewrite/rewriteManip.h" ++#include "sepgsql/hooks.h" + #include "utils/builtins.h" + #include "utils/lsyscache.h" + #include "commands/trigger.h" +@@ -1938,6 +1939,7 @@ QueryRewrite(Query *parsetree) + foreach(l, results) + { + Query *query = (Query *) lfirst(l); ++ ListCell *cell; + + if (query->querySource == QSRC_ORIGINAL) + { +@@ -1956,7 +1958,16 @@ QueryRewrite(Query *parsetree) + query->querySource == QSRC_QUAL_INSTEAD_RULE)) + lastInstead = query; + } ++ ++ /* Fixup row-level access control permissions */ ++ foreach (cell, query->rtable) ++ { ++ RangeTblEntry *rte = lfirst(cell); ++ ++ rte->rowlvPerms = sepgsql_rowlv_permissions(rte); ++ } + } ++ sepgsql_proxy_queries(results); + + if (!foundOriginalQuery && lastInstead != NULL) + lastInstead->canSetTag = true; +diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c +index c1c5ce9..0f6a446 100644 +--- a/src/backend/rewrite/rewriteRemove.c ++++ b/src/backend/rewrite/rewriteRemove.c +@@ -22,6 +22,7 @@ + #include "catalog/pg_rewrite.h" + #include "miscadmin.h" + #include "rewrite/rewriteRemove.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/fmgroids.h" + #include "utils/inval.h" +@@ -77,6 +78,9 @@ RemoveRewriteRule(Oid owningRel, const char *ruleName, DropBehavior behavior, + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + get_rel_name(eventRelationOid)); + ++ /* SELinux checks */ ++ sepgsql_rule_drop(eventRelationOid, ruleName, false); ++ + /* + * Do the deletion + */ +diff --git a/src/backend/sepgsql/Makefile b/src/backend/sepgsql/Makefile +new file mode 100644 +index 0000000..f7119da +--- /dev/null ++++ b/src/backend/sepgsql/Makefile +@@ -0,0 +1,21 @@ ++# ++# Makefile for security subsystem ++# ++ ++subdir = src/backend/sepgsql ++top_builddir = ../../.. ++include $(top_builddir)/src/Makefile.global ++ ++ifeq ($(enable_selinux), yes) ++OBJS = selinux.o avc.o label.o ++else ++OBJS = dummy.o ++endif ++ ++OBJS += proxy.o rowlv.o ++ ++OBJS += misc.o database.o schema.o relation.o attribute.o proc.o \ ++ type.o tablespace.o operator.o role.o blob.o conversion.o \ ++ tsearch.o fdw.o ++ ++include $(top_srcdir)/src/backend/common.mk +diff --git a/src/backend/sepgsql/attribute.c b/src/backend/sepgsql/attribute.c +new file mode 100644 +index 0000000..3b9c916 +--- /dev/null ++++ b/src/backend/sepgsql/attribute.c +@@ -0,0 +1,260 @@ ++/* ++ * attribute.c ++ * ++ * SELinux hooks related to attribute ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "access/heapam.h" ++#include "access/sysattr.h" ++#include "catalog/pg_attribute.h" ++#include "catalog/pg_class.h" ++#include "catalog/pg_seclabel.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/lsyscache.h" ++#include "utils/syscache.h" ++#include "utils/tqual.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_attribute_common(Oid relOid, AttrNumber attno, ++ uint32 required, bool abort) ++{ ++ Form_pg_attribute attForm; ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ char auname[NAMEDATALEN * 2 + 10]; ++ bool retval; ++ ++ Assert(get_rel_relkind(relOid) == RELKIND_RELATION); ++ ++ tuple = SearchSysCache2(ATTNUM, ++ ObjectIdGetDatum(relOid), ++ Int16GetDatum(attno)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for attribute %d of relation %u", ++ attno, relOid); ++ attForm = (Form_pg_attribute) GETSTRUCT(tuple); ++ ++ tsid.relid = AttributeRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ snprintf(auname, sizeof(auname), "%s.%s", ++ get_rel_name(relOid), NameStr(attForm->attname)); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_COLUMN, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++#endif ++ ++Oid ++sepgsql_attribute_create(Oid relOid, const char *attName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ char auname[NAMEDATALEN * 2 + 10]; ++ ++ if (get_rel_relkind(relOid) != RELKIND_RELATION) ++ { ++ sepgsql_relation_common(relOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ nsid.relid = RelationRelationId; ++ nsid.secid = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(relOid)); ++ ++ nsid = sepgsql_move_secid(AttributeRelationId, nsid); ++ ++ return nsid.secid; ++ } ++ ++ nsid = sepgsql_get_default_column_secid(relOid); ++ snprintf(auname, sizeof(auname), "%s.%s", ++ get_rel_name(relOid), attName); ++ ++ /* db_column:{create} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_COLUMN, ++ SEPG_DB_COLUMN__CREATE, ++ auname, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_attribute_alter(Oid relOid, const char *attName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ AttrNumber attnum = get_attnum(relOid, attName); ++ ++ if (attnum == InvalidAttrNumber) ++ return; /* to be failed later */ ++ ++ if (get_rel_relkind(relOid) == RELKIND_RELATION) ++ sepgsql_attribute_common(relOid, attnum, ++ SEPG_DB_COLUMN__SETATTR, true); ++ else ++ sepgsql_relation_common(relOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_attribute_relabel(Oid relOid, const char *attName, char *new_label) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ AttrNumber attnum = get_attnum(relOid, attName); ++ sepgsql_sid_t nsid; ++ char auname[NAMEDATALEN * 2 + 10]; ++ ++ Assert(get_rel_relkind(relOid) == RELKIND_RELATION); ++ if (attnum == InvalidAttrNumber) ++ return InvalidOid; /* to be failed later */ ++ ++ nsid.relid = AttributeRelationId; ++ nsid.secid = seclabelTransInput(nsid.relid, new_label); ++ ++ snprintf(auname, sizeof(auname), "%s.%s", ++ get_rel_name(relOid), get_attname(relOid, attnum)); ++ ++ /* db_column:{setattr relabelfrom} */ ++ sepgsql_attribute_common(relOid, attnum, ++ SEPG_DB_COLUMN__SETATTR | ++ SEPG_DB_COLUMN__RELABELFROM, ++ true); ++ ++ /* db_column:{relabelto} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_COLUMN, ++ SEPG_DB_COLUMN__RELABELTO, ++ auname, ++ true); ++ return nsid.secid; ++ } ++#endif ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("SE-PostgreSQL is not available"))); ++ return InvalidOid; ++} ++ ++void ++sepgsql_attribute_drop(Oid relOid, const char *attName, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ AttrNumber attnum = get_attnum(relOid, attName); ++ ++ /* ++ * If not found, the caller raises an error with an appropriate ++ * error message. ++ */ ++ if (attnum == InvalidAttrNumber) ++ return; ++ ++ if (get_rel_relkind(relOid) == RELKIND_RELATION) ++ { ++ sepgsql_attribute_common(relOid, attnum, ++ SEPG_DB_COLUMN__DROP, true); ++ /* ++ * ALTER TABLE SET WITHOUT SECURITY LABEL is equivalent to ++ * relabel all the tuples within the target relation. ++ * In this case, we need to check {relabelfrom relabelto} ++ */ ++ if (!cascade && ++ attnum == SecurityLabelAttributeNumber) ++ { ++ Relation rel; ++ HeapScanDesc scan; ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ ++ rel = heap_open(relOid, AccessShareLock); ++ ++ scan = heap_beginscan(rel, SnapshotNow, 0, NULL); ++ ++ while (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection))) ++ { ++ /* db_tuple:{update relabelfrom} */ ++ tsid.relid = relOid; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__UPDATE | ++ SEPG_DB_TUPLE__RELABELFROM, ++ NULL, ++ true); ++ } ++ heap_endscan(scan); ++ ++ heap_close(rel, AccessShareLock); ++ ++ /* db_tuple:{relabelto} */ ++ tsid.relid = RelationRelationId; ++ tsid.secid = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(relOid)); ++ ++ sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__RELABELTO, ++ NULL, ++ true); ++ } ++ } ++ else if (!cascade) ++ sepgsql_relation_common(relOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_attribute_grant(Oid relOid, AttrNumber attnum) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ if (get_rel_relkind(relOid) == RELKIND_RELATION) ++ sepgsql_attribute_common(relOid, attnum, ++ SEPG_DB_COLUMN__SETATTR, true); ++ else ++ sepgsql_relation_common(relOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_attribute_comment(Oid relOid, AttrNumber attnum) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ if (get_rel_relkind(relOid) == RELKIND_RELATION) ++ sepgsql_attribute_common(relOid, attnum, ++ SEPG_DB_COLUMN__SETATTR, true); ++ else ++ sepgsql_relation_common(relOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/avc.c b/src/backend/sepgsql/avc.c +new file mode 100644 +index 0000000..5f58974 +--- /dev/null ++++ b/src/backend/sepgsql/avc.c +@@ -0,0 +1,503 @@ ++/* ++ * avc.c ++ * userspace access vector cache ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "access/hash.h" ++#include "access/xact.h" ++#include "catalog/pg_seclabel.h" ++#include "libpq/libpq-be.h" ++#include "libpq/pqsignal.h" ++#include "miscadmin.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "storage/shmem.h" ++#include "storage/lock.h" ++#include "utils/memutils.h" ++ ++#include ++#include ++#include ++ ++/* ------------------------------------------------------------ ++ * ++ * Userspace Access Vector Cache ++ * ++ * ------------------------------------------------------------ ++ */ ++static MemoryContext AvcMemCtx = NULL; ++ ++#define AVC_HASH_NUM_SLOTS 256 ++#define AVC_HASH_NUM_NODES 180 ++ ++#define avc_hash_key(trelid, tsecid, tclass, nrelid) \ ++ (hash_uint32((trelid) ^ (tsecid) ^ ((tclass) << 3) ^ (nrelid))) ++ ++typedef struct _avc_datum ++{ ++ uint32 hash_key; ++ ++ uint16 tclass; ++ sepgsql_sid_t tsid; ++ sepgsql_sid_t nsid; ++ char *tcontext; ++ char *ncontext; ++ ++ uint32 allowed; ++ uint32 auditallow; ++ uint32 auditdeny; ++ bool permissive; ++ ++ bool hot_cache; ++} avc_datum; ++ ++typedef struct _avc_page ++{ ++ struct _avc_page *next; ++ ++ List *slot[AVC_HASH_NUM_SLOTS]; ++ ++ uint32 avc_count; ++ uint32 lru_hint; ++ ++ char scontext[1]; ++} avc_page; ++ ++static avc_page *current_page = NULL; ++ ++static int avc_version = -1; ++ ++/* ++ * selinux_state ++ * ++ * It is deployed on the shared memory region, to show the system ++ * state of SELinux and its security policy. ++ */ ++struct ++{ ++ int version; ++ ++ bool enforcing; ++} *selinux_state = NULL; ++ ++Size ++sepgsql_shmem_size(void) ++{ ++ return sizeof(*selinux_state); ++} ++ ++static void ++sepgsql_shmem_init(void) ++{ ++ bool found; ++ ++ selinux_state = ShmemInitStruct("SELinux system state", ++ sepgsql_shmem_size(), &found); ++ if (!found) ++ { ++ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); ++ ++ selinux_state->version = 0; ++ selinux_state->enforcing = (security_getenforce() > 0); ++ ++ LWLockRelease(SepgsqlAvcLock); ++ } ++} ++ ++void ++sepgsql_avc_switch(const char *scontext) ++{ ++ avc_page *new_page; ++ int i, length; ++ ++ if (current_page) ++ { ++ new_page = current_page; ++ do { ++ if (strcmp(new_page->scontext, scontext) == 0) ++ { ++ current_page = new_page; ++ return; ++ } ++ new_page = new_page->next; ++ } while (new_page != current_page); ++ } ++ ++ /* ++ * Not found, so create a new avc_page ++ */ ++ length = sizeof(avc_page) + strlen(scontext); ++ new_page = MemoryContextAllocZero(AvcMemCtx, length); ++ ++ strcpy(new_page->scontext, scontext); ++ for (i = 0; i < AVC_HASH_NUM_SLOTS; i++) ++ new_page->slot[i] = NIL; ++ ++ if (!current_page) ++ new_page->next = new_page; ++ else ++ { ++ new_page->next = current_page->next; ++ current_page->next = new_page; ++ } ++ current_page = new_page; ++} ++ ++ ++static void ++sepgsql_avc_reset(void) ++{ ++ Assert(AvcMemCtx != NULL); ++ ++ MemoryContextReset(AvcMemCtx); ++ ++ current_page = NULL; ++ ++ sepgsql_avc_switch(sepgsql_get_client_label()); ++} ++ ++static bool ++sepgsql_avc_is_valid(void) ++{ ++ bool result = true; ++ ++ LWLockAcquire(SepgsqlAvcLock, LW_SHARED); ++ if (avc_version != selinux_state->version) ++ { ++ sepgsql_avc_reset(); ++ ++ /* copy current version to local variable */ ++ avc_version = selinux_state->version; ++ ++ result = false; ++ } ++ LWLockRelease(SepgsqlAvcLock); ++ ++ return result; ++} ++ ++ ++static void ++sepgsql_avc_reclaim(avc_page *page) ++{ ++ ListCell *l; ++ ++ while (page->avc_count > AVC_HASH_NUM_NODES - 10) ++ { ++ foreach (l, page->slot[page->lru_hint]) ++ { ++ avc_datum *cache = lfirst(l); ++ ++ if (cache->hot_cache) ++ cache->hot_cache = false; ++ { ++ list_delete_ptr(page->slot[page->lru_hint], cache); ++ pfree(cache); ++ page->avc_count--; ++ } ++ } ++ page->lru_hint = (page->lru_hint + 1) % AVC_HASH_NUM_SLOTS; ++ } ++} ++ ++static avc_datum * ++sepgsql_avc_make_entry(avc_page *page, ++ sepgsql_sid_t tsid, uint16 tclass, Oid nrelid) ++{ ++ struct av_decision avd; ++ MemoryContext oldctx; ++ char *scontext; ++ char *tcontext; ++ char *ncontext; ++ avc_datum *cache; ++ uint32 hash_key, index; ++ ++ hash_key = avc_hash_key(tsid.relid, tsid.secid, tclass, nrelid); ++ index = hash_key % AVC_HASH_NUM_SLOTS; ++ ++ oldctx = MemoryContextSwitchTo(AvcMemCtx); ++ ++ scontext = page->scontext; ++ tcontext = seclabelRawOutput(tsid.relid, tsid.secid); ++ ncontext = sepgsql_compute_create(scontext, tcontext, tclass); ++ ++ sepgsql_compute_avd(scontext, tcontext, tclass, &avd); ++ ++ cache = palloc0(sizeof(avc_datum)); ++ ++ cache->hash_key = hash_key; ++ ++ cache->tclass = tclass; ++ ++ cache->hot_cache = true; ++ cache->tcontext = tcontext; ++ cache->ncontext = ncontext; ++ ++ cache->tsid.relid = tsid.relid; ++ cache->tsid.secid = tsid.secid; ++ ++ if (OidIsValid(nrelid)) ++ { ++ cache->nsid.relid = nrelid; ++ cache->nsid.secid = seclabelRawInput(nrelid, ncontext); ++ } ++ ++ cache->allowed = avd.allowed; ++ cache->auditallow = avd.auditallow; ++ cache->auditdeny = avd.auditdeny; ++ if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) ++ cache->permissive = true; ++ ++ if (page->avc_count > AVC_HASH_NUM_NODES) ++ sepgsql_avc_reclaim(page); ++ ++ page->slot[index] = lcons(cache, page->slot[index]); ++ page->avc_count++; ++ ++ MemoryContextSwitchTo(oldctx); ++ ++ return cache; ++} ++ ++static avc_datum * ++sepgsql_avc_lookup(avc_page *page, ++ sepgsql_sid_t tsid, uint16 tclass, Oid nrelid) ++{ ++ avc_datum *cache = NULL; ++ uint32 hash_key, index; ++ ListCell *l; ++ ++ hash_key = avc_hash_key(tsid.relid, tsid.secid, tclass, nrelid); ++ index = hash_key % AVC_HASH_NUM_SLOTS; ++ ++ foreach (l, page->slot[index]) ++ { ++ cache = lfirst(l); ++ if (cache->hash_key == hash_key && ++ cache->tclass == tclass && ++ cache->tsid.relid == tsid.relid && ++ cache->tsid.secid == tsid.secid && ++ cache->nsid.relid == nrelid) ++ { ++ cache->hot_cache = true; ++ return cache; ++ } ++ } ++ return NULL; ++} ++ ++bool ++sepgsql_client_perms(sepgsql_sid_t tsid, ++ uint16 tclass, uint32 required, ++ const char *audit_name, bool abort) ++{ ++ avc_datum *cache; ++ uint32 denied, audited; ++ bool result = true; ++ ++ do { ++ cache = sepgsql_avc_lookup(current_page, ++ tsid, tclass, InvalidOid); ++ if (!cache) ++ cache = sepgsql_avc_make_entry(current_page, ++ tsid, tclass, InvalidOid); ++ } while (!sepgsql_avc_is_valid()); ++ ++ denied = required & ~cache->allowed; ++ if (sepgsql_debug_audit && tclass != SEPG_CLASS_DB_TUPLE) ++ audited = (denied ? (denied & ~0) : (required & ~0)); ++ else ++ audited = (denied ? (denied & cache->auditdeny) ++ : (required & cache->auditallow)); ++ ++ if (audited) ++ { ++ sepgsql_audit_log(!!denied, ++ current_page->scontext, ++ seclabelRawOutput(tsid.relid, tsid.secid), ++ tclass, audited, audit_name); ++ } ++ ++ if (denied) ++ { ++ if (!sepgsql_get_enforce() || cache->permissive) ++ cache->allowed |= required; /* prevent flood of audit log */ ++ else ++ { ++ if (abort) ++ ereport(ERROR, ++ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ++ errmsg("SELinux: security policy violation"))); ++ result = false; ++ } ++ } ++ ++ return result; ++} ++ ++sepgsql_sid_t ++sepgsql_client_create_secid(sepgsql_sid_t tsid, uint16 tclass, Oid nrelid) ++{ ++ avc_datum *cache; ++ ++ do { ++ cache = sepgsql_avc_lookup(current_page, tsid, tclass, nrelid); ++ ++ if (!cache) ++ cache = sepgsql_avc_make_entry(current_page, ++ tsid, tclass, nrelid); ++ } while (!sepgsql_avc_is_valid()); ++ ++ return cache->nsid; ++} ++ ++char * ++sepgsql_client_create_label(sepgsql_sid_t tsid, uint16 tclass) ++{ ++ avc_datum *cache; ++ ++ do { ++ cache = sepgsql_avc_lookup(current_page, tsid, tclass, InvalidOid); ++ ++ if (!cache) ++ cache = sepgsql_avc_make_entry(current_page, ++ tsid, tclass, InvalidOid); ++ } while (!sepgsql_avc_is_valid()); ++ ++ return cache->ncontext; ++} ++ ++static void ++sepgsql_avc_xact_callback(XactEvent event, void *arg) ++{ ++ if (event == XACT_EVENT_ABORT) ++ sepgsql_avc_reset(); ++} ++ ++static void ++sepgsql_avc_sub_xact_callback(SubXactEvent event, SubTransactionId mySubid, ++ SubTransactionId parentSubid, void *arg) ++{ ++ if (event == SUBXACT_EVENT_ABORT_SUB) ++ sepgsql_avc_reset(); ++} ++ ++void ++sepgsql_avc_init(void) ++{ ++ sepgsql_shmem_init(); ++ ++ AvcMemCtx = AllocSetContextCreate(TopMemoryContext, ++ "Userspace AVC", ++ ALLOCSET_DEFAULT_MINSIZE, ++ ALLOCSET_DEFAULT_INITSIZE, ++ ALLOCSET_DEFAULT_MAXSIZE); ++ /* ++ * userspace avc should be invalidate when the current transaction ++ * is aborted on errors, because sid to be created shall be rollbacked. ++ */ ++ RegisterXactCallback(sepgsql_avc_xact_callback, NULL); ++ RegisterSubXactCallback(sepgsql_avc_sub_xact_callback, NULL); ++} ++ ++/* ------------------------------------------------------------ ++ * ++ * SELinux state monitor process ++ * ++ * ------------------------------------------------------------ ++ */ ++static int ++sepgsql_cb_log(int type, const char *fmt, ...) ++{ ++ char *c, buffer[1024]; ++ va_list ap; ++ ++ va_start(ap, fmt); ++ vsnprintf(buffer, sizeof(buffer), fmt, ap); ++ va_end(ap); ++ ++ c = strrchr(buffer, '\n'); ++ if (c) ++ *c = '\0'; ++ ++ ereport(LOG,(errmsg("%s", buffer))); ++ ++ return 0; ++} ++ ++static int ++sepgsql_cb_setenforce(int enforce) ++{ ++ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); ++ selinux_state->enforcing = (enforce ? true : false); ++ selinux_state->version++; ++ LWLockRelease(SepgsqlAvcLock); ++ ++ return 0; ++} ++ ++static int ++sepgsql_cb_policyload(int seqno) ++{ ++ LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE); ++ selinux_state->version++; ++ LWLockRelease(SepgsqlAvcLock); ++ ++ return 0; ++} ++ ++void ++sepgsql_avc_worker_main(void) ++{ ++ union selinux_callback cb; ++ ++ Assert(sepgsql_is_enabled()); ++ ++#ifdef HAVE_SETSID ++ if (setsid() < 0) ++ elog(FATAL, "setsid() failed: %m"); ++#endif ++ ++ /* ++ * setup the signal handler ++ */ ++ pqinitmask(); ++ pqsignal(SIGHUP, SIG_IGN); ++ pqsignal(SIGINT, SIG_IGN); ++ pqsignal(SIGTERM, exit); ++ pqsignal(SIGQUIT, exit); ++ pqsignal(SIGUSR1, SIG_IGN); ++ pqsignal(SIGUSR2, SIG_IGN); ++ pqsignal(SIGCHLD, SIG_DFL); ++ PG_SETMASK(&UnBlockSig); ++ ++ /* ++ * map shared memory segment ++ */ ++ sepgsql_shmem_init(); ++ ++ ereport(LOG, (errmsg("SELinux: netlink receiver (pid=%u)", getpid()))); ++ ++ /* ++ * setup callback functions from avc_netlink_loop() ++ */ ++ cb.func_log = sepgsql_cb_log; ++ selinux_set_callback(SELINUX_CB_LOG, cb); ++ cb.func_setenforce = sepgsql_cb_setenforce; ++ selinux_set_callback(SELINUX_CB_SETENFORCE, cb); ++ cb.func_policyload = sepgsql_cb_policyload; ++ selinux_set_callback(SELINUX_CB_POLICYLOAD, cb); ++ ++ /* ++ * open netlink socket and wait for messages ++ */ ++ avc_netlink_open(1); ++ ++ avc_netlink_loop(); ++ ++ exit(0); ++} +diff --git a/src/backend/sepgsql/blob.c b/src/backend/sepgsql/blob.c +new file mode 100644 +index 0000000..e60e9cc +--- /dev/null ++++ b/src/backend/sepgsql/blob.c +@@ -0,0 +1,245 @@ ++/* ++ * blob.c ++ * ++ * SELinux hooks related to large objects ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "access/genam.h" ++#include "access/heapam.h" ++#include "access/sysattr.h" ++#include "catalog/indexing.h" ++#include "catalog/pg_largeobject.h" ++#include "catalog/pg_largeobject_metadata.h" ++#include "catalog/pg_seclabel.h" ++#include "miscadmin.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/fmgroids.h" ++#include "utils/tqual.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_largeobject_common(Oid loid, Snapshot snapshot, ++ uint32 required, bool abort) ++{ ++ Relation pg_lo_meta; ++ ScanKeyData skey; ++ SysScanDesc scan; ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ char auname[NAMEDATALEN]; ++ bool retval; ++ ++ snprintf(auname, sizeof(auname), "blob_%u", loid); ++ ++ pg_lo_meta = heap_open(LargeObjectMetadataRelationId, ++ AccessShareLock); ++ ++ ScanKeyInit(&skey, ++ ObjectIdAttributeNumber, ++ BTEqualStrategyNumber, F_OIDEQ, ++ ObjectIdGetDatum(loid)); ++ ++ scan = systable_beginscan(pg_lo_meta, ++ LargeObjectMetadataOidIndexId, true, ++ snapshot, 1, &skey); ++ ++ tuple = systable_getnext(scan); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "large object %u does not exist", loid); ++ ++ tsid.relid = LargeObjectMetadataRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_BLOB, ++ required, ++ auname, ++ abort); ++ systable_endscan(scan); ++ ++ heap_close(pg_lo_meta, AccessShareLock); ++ ++ return retval; ++} ++#endif ++ ++Oid ++sepgsql_largeobject_create(Oid loid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ char auname[NAMEDATALEN]; ++ ++ nsid = sepgsql_get_default_blob_secid(MyDatabaseId); ++ snprintf(auname, sizeof(auname), "blob_%u", loid); ++ ++ /* db_blob:{create} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_BLOB, ++ SEPG_DB_BLOB__CREATE, ++ auname, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_largeobject_alter(Oid loid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_largeobject_common(loid, SnapshotNow, ++ SEPG_DB_BLOB__SETATTR, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_largeobject_relabel(Oid loid, char *newLabel) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ char auname[NAMEDATALEN]; ++ ++ nsid.relid = LargeObjectMetadataRelationId; ++ nsid.secid = seclabelTransInput(nsid.relid, newLabel); ++ ++ snprintf(auname, sizeof(auname), "blob_%u", loid); ++ ++ /* db_blob:{setattr relabelfrom} */ ++ sepgsql_largeobject_common(loid, ++ SnapshotNow, ++ SEPG_DB_BLOB__SETATTR | ++ SEPG_DB_BLOB__RELABELFROM, ++ true); ++ /* db_blob:{relabelto} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_BLOB, ++ SEPG_DB_BLOB__RELABELTO, ++ auname, ++ true); ++ return nsid.secid; ++ } ++#endif ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("SE-PostgreSQL is not available"))); ++ return InvalidOid; ++} ++ ++void ++sepgsql_largeobject_drop(Oid loid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_largeobject_common(loid, SnapshotNow, ++ SEPG_DB_BLOB__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_largeobject_read(Oid loid, Snapshot snapshot) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_largeobject_common(loid, snapshot, ++ SEPG_DB_BLOB__READ, true); ++ } ++#endif ++} ++ ++void ++sepgsql_largeobject_write(Oid loid, Snapshot snapshot) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_largeobject_common(loid, snapshot, ++ SEPG_DB_BLOB__WRITE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_largeobject_import(Oid loid, const char *filename) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ char auname[NAMEDATALEN]; ++ ++ nsid = sepgsql_get_default_blob_secid(MyDatabaseId); ++ snprintf(auname, sizeof(auname), "blob_%u", loid); ++ ++ /* db_blob:{create} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_BLOB, ++ SEPG_DB_BLOB__CREATE | ++ SEPG_DB_BLOB__WRITE | ++ SEPG_DB_BLOB__IMPORT, ++ auname, ++ true); ++ /* db_file:{read} */ ++ // XXX - todo: add file read checks ++ ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_largeobject_export(Oid loid, Snapshot snapshot, const char *filename) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_blob:{read export} */ ++ sepgsql_largeobject_common(loid, snapshot, ++ SEPG_DB_BLOB__READ | ++ SEPG_DB_BLOB__EXPORT, true); ++ /* file:{write} */ ++ // TODO: add security checks ++ } ++#endif ++} ++ ++void ++sepgsql_largeobject_grant(Oid loid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_largeobject_common(loid, SnapshotNow, ++ SEPG_DB_BLOB__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_largeobject_comment(Oid loid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_largeobject_common(loid, SnapshotNow, ++ SEPG_DB_BLOB__SETATTR, true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/conversion.c b/src/backend/sepgsql/conversion.c +new file mode 100644 +index 0000000..6a60284 +--- /dev/null ++++ b/src/backend/sepgsql/conversion.c +@@ -0,0 +1,147 @@ ++/* ++ * conversion.c ++ * ++ * SELinux hooks related to conversion ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_conversion.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/syscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_conversion_common(Oid convOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ HeapTuple tuple; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(convOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for conversion %u", convOid); ++ ++ tsid.relid = ConversionRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_conversion) GETSTRUCT(tuple))->conname); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++static Oid ++get_conversion_namespace(Oid convOid) ++{ ++ HeapTuple tuple; ++ Oid namespaceId = InvalidOid; ++ ++ tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(convOid)); ++ if (HeapTupleIsValid(tuple)) ++ { ++ namespaceId = ((Form_pg_conversion) GETSTRUCT(tuple))->connamespace; ++ ++ ReleaseSysCache(tuple); ++ } ++ return namespaceId; ++} ++#endif ++ ++Oid ++sepgsql_conversion_create(const char *convName, ++ Oid namespaceId, Oid conversionFunc) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ ++ nsid = sepgsql_get_default_tuple_secid(ConversionRelationId); ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, ++ SEPG_DB_SCHEMA__ADD_NAME, true); ++ /* db_procedure:{install} */ ++ sepgsql_proc_common(conversionFunc, ++ SEPG_DB_PROCEDURE__INSTALL, true); ++ /* db_tuple:{insert} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ convName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_conversion_alter(Oid convOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_conversion_common(convOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_conversion_alter_rename(Oid convOid, const char *newName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_conversion_namespace(convOid); ++ ++ /* db_schema:{add_name remove_name} */ ++ sepgsql_schema_common(namespaceId, ++ SEPG_DB_SCHEMA__ADD_NAME | ++ SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{update} */ ++ sepgsql_conversion_common(convOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_conversion_drop(Oid convOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_conversion_namespace(convOid); ++ ++ /* db_schema:{remove_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{delete} */ ++ sepgsql_conversion_common(convOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_conversion_comment(Oid convOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_conversion_common(convOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/database.c b/src/backend/sepgsql/database.c +new file mode 100644 +index 0000000..bee9d36 +--- /dev/null ++++ b/src/backend/sepgsql/database.c +@@ -0,0 +1,201 @@ ++/* ++ * database.c ++ * ++ * SELinux hooks related to database ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_database.h" ++#include "catalog/pg_seclabel.h" ++#include "commands/dbcommands.h" ++#include "miscadmin.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/syscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_database_common(Oid datOid, uint32 required, bool abort) ++{ ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(DATABASEOID, ++ ObjectIdGetDatum(datOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for database %u", datOid); ++ ++ tsid.relid = DatabaseRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname); ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_DATABASE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++#endif ++ ++Oid ++sepgsql_database_create(const char *datName, Oid templateOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ ++ /* compute a default security context */ ++ nsid = sepgsql_get_default_database_secid(templateOid); ++ ++ /* db_database:{create} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_DATABASE, ++ SEPG_DB_DATABASE__CREATE, ++ datName, true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_database_alter(Oid databaseOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_database_common(databaseOid, ++ SEPG_DB_DATABASE__SETATTR, ++ true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_database_relabel(Oid databaseOid, char *new_label) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ char *auname; ++ ++ nsid.relid = DatabaseRelationId; ++ nsid.secid = seclabelTransInput(nsid.relid, new_label); ++ ++ auname = get_database_name(databaseOid); ++ ++ /* db_database:{setattr relabelfrom} */ ++ sepgsql_database_common(databaseOid, ++ SEPG_DB_DATABASE__SETATTR | ++ SEPG_DB_DATABASE__RELABELFROM, ++ true); ++ ++ /* db_database:{relabelto} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_DATABASE, ++ SEPG_DB_DATABASE__RELABELTO, ++ auname, ++ true); ++ pfree(auname); ++ ++ return nsid.secid; ++ } ++#endif ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("SE-PostgreSQL is not available"))); ++ return InvalidOid; ++} ++ ++void ++sepgsql_database_drop(Oid databaseOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_database_common(databaseOid, ++ SEPG_DB_DATABASE__DROP, ++ true); ++ } ++#endif ++} ++ ++void ++sepgsql_database_grant(Oid databaseOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_database_common(databaseOid, ++ SEPG_DB_DATABASE__SETATTR, ++ true); ++ } ++#endif ++} ++ ++void ++sepgsql_database_comment(Oid databaseOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_database_common(databaseOid, ++ SEPG_DB_DATABASE__SETATTR, ++ true); ++ } ++#endif ++} ++ ++void ++sepgsql_database_connect(Oid databaseOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ if (!sepgsql_database_common(databaseOid, ++ SEPG_DB_DATABASE__ACCESS, ++ false)) ++ ereport(FATAL, ++ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ++ errmsg("permission denied for database \"%s\"", ++ get_database_name(databaseOid)))); ++ } ++#endif ++} ++ ++void ++sepgsql_database_reindex(Oid databaseOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ // TODO: check db_table:{indexon} for each ++ ++ ++ ++ } ++#endif ++} ++ ++void ++sepgsql_database_getattr(Oid databaseOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_database_common(databaseOid, ++ SEPG_DB_DATABASE__GETATTR, ++ true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/fdw.c b/src/backend/sepgsql/fdw.c +new file mode 100644 +index 0000000..be4a34b +--- /dev/null ++++ b/src/backend/sepgsql/fdw.c +@@ -0,0 +1,296 @@ ++/* ++ * fdw.c ++ * ++ * SELinux hooks related to foreign data wrapper ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_foreign_data_wrapper.h" ++#include "catalog/pg_foreign_server.h" ++#include "catalog/pg_user_mapping.h" ++#include "miscadmin.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/syscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_fdw_common(Oid fdwOid, uint32 required, bool abort) ++{ ++ Form_pg_foreign_data_wrapper fdwForm; ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ bool retval; ++ ++ tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for foreign-data-wrapper %u", fdwOid); ++ fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple); ++ ++ tsid.relid = ForeignDataWrapperRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ NameStr(fdwForm->fdwname), ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++bool ++sepgsql_fserver_common(Oid fservOid, uint32 required, bool abort) ++{ ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(fservOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for foreign-server %u", fservOid); ++ ++ tsid.relid = ForeignServerRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_foreign_server) GETSTRUCT(tuple))->srvname); ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++static char * ++get_fserver_name(Oid fservOid) ++{ ++ Form_pg_foreign_server servForm; ++ HeapTuple tuple; ++ char *srvname = NULL; ++ ++ tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(fservOid)); ++ if (HeapTupleIsValid(tuple)) ++ { ++ servForm = (Form_pg_foreign_server) GETSTRUCT(tuple); ++ ++ srvname = pstrdup(NameStr(servForm->srvname)); ++ ++ ReleaseSysCache(tuple); ++ } ++ return srvname; ++} ++ ++bool ++sepgsql_user_mapping_common(Oid umapOid, uint32 required, bool abort) ++{ ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ Oid umuser; ++ Oid umserver; ++ char auname[NAMEDATALEN * 2 + 10]; ++ bool retval; ++ ++ tuple = SearchSysCache1(USERMAPPINGOID, ObjectIdGetDatum(umapOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for user mapping %u", umapOid); ++ ++ tsid.relid = UserMappingRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ umuser = ((Form_pg_user_mapping) GETSTRUCT(tuple))->umuser; ++ umserver = ((Form_pg_user_mapping) GETSTRUCT(tuple))->umserver; ++ ++ snprintf(auname, sizeof(auname), "%s@%s", ++ OidIsValid(umuser) ? GetUserNameFromId(umuser) : "public", ++ get_fserver_name(umserver)); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++#endif ++ ++Oid ++sepgsql_fdw_create(const char *fdwName, Oid validatorFunc) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid ++ = sepgsql_get_default_tuple_secid(ForeignDataWrapperRelationId); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(validatorFunc)) ++ sepgsql_proc_common(validatorFunc, ++ SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* db_tuple:{insert} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ fdwName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_fdw_alter(Oid fdwOid, Oid newValidator) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_procedure:{install} */ ++ if (OidIsValid(newValidator)) ++ sepgsql_proc_common(newValidator, ++ SEPG_DB_PROCEDURE__INSTALL, true); ++ /* db_tuple:{update} */ ++ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_fdw_drop(Oid fdwOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{delete} */ ++ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_fdw_grant(Oid fdwOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_fdw_common(fdwOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_fserver_create(const char *fservName, Oid fdwOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid ++ = sepgsql_get_default_tuple_secid(ForeignServerRelationId); ++ ++ /* db_tuple:{insert} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ fservName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_fserver_alter(Oid fservOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_fserver_common(fservOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_fserver_drop(Oid fservOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_fserver_common(fservOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_fserver_grant(Oid fservOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_fserver_common(fservOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_user_mapping_create(Oid umuserId, Oid fservOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ char auname[NAMEDATALEN * 2 + 10]; ++ sepgsql_sid_t nsid ++ = sepgsql_get_default_tuple_secid(UserMappingRelationId); ++ ++ snprintf(auname, sizeof(auname), "%s@%s", ++ OidIsValid(umuserId) ? GetUserNameFromId(umuserId) : "public", ++ get_fserver_name(fservOid)); ++ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ auname, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_user_mapping_alter(Oid umapOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_user_mapping_common(umapOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_user_mapping_drop(Oid umapOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{delete} */ ++ sepgsql_user_mapping_common(umapOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/label.c b/src/backend/sepgsql/label.c +new file mode 100644 +index 0000000..9a61902 +--- /dev/null ++++ b/src/backend/sepgsql/label.c +@@ -0,0 +1,656 @@ ++/* ++ * label.c ++ * SE-PostgreSQL security label management ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "access/relscan.h" ++#include "access/xact.h" ++#include "catalog/pg_attribute.h" ++#include "catalog/pg_class.h" ++#include "catalog/pg_database.h" ++#include "catalog/pg_largeobject_metadata.h" ++#include "catalog/pg_namespace.h" ++#include "catalog/pg_proc.h" ++#include "catalog/pg_seclabel.h" ++#include "catalog/pg_type.h" ++#include "commands/dbcommands.h" ++#include "miscadmin.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/fmgroids.h" ++#include "utils/lsyscache.h" ++#include "utils/rel.h" ++#include "utils/syscache.h" ++#include "utils/tqual.h" ++#include // for workaround hack ++#include ++ ++/* ++ * guc parameter to turn on/off mcstrans ++ */ ++bool sepgsql_mcstrans; ++ ++sepgsql_sid_t ++sepgsql_move_secid(Oid dst_relid, sepgsql_sid_t ssid) ++{ ++ char *label; ++ sepgsql_sid_t dsid = { .relid = dst_relid, ++ .secid = InvalidOid }; ++ ++ label = seclabelRawOutput(ssid.relid, ssid.secid); ++ if (label) ++ { ++ dsid.secid = seclabelRawInput(dsid.relid, label); ++ ++ pfree(label); ++ } ++ return dsid; ++} ++ ++static sepgsql_sid_t ++get_default_secid_with_database(Oid relOid, Oid databaseOid, uint16 tclass) ++{ ++ HeapTuple tuple; ++ sepgsql_sid_t datsid; ++ ++ tuple = SearchSysCache1(DATABASEOID, ++ ObjectIdGetDatum(databaseOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for database: %u", databaseOid); ++ ++ datsid.relid = DatabaseRelationId; ++ datsid.secid = HeapTupleGetSecid(tuple); ++ ++ ReleaseSysCache(tuple); ++ ++ return sepgsql_client_create_secid(datsid, tclass, relOid); ++} ++ ++static sepgsql_sid_t ++get_default_secid_with_schema(Oid relOid, Oid namespaceOid, uint16 tclass) ++{ ++ HeapTuple tuple; ++ sepgsql_sid_t nspsid; ++ ++ tuple = SearchSysCache1(NAMESPACEOID, ++ ObjectIdGetDatum(namespaceOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for namespace: %u", namespaceOid); ++ ++ nspsid.relid = NamespaceRelationId; ++ nspsid.secid = HeapTupleGetSecid(tuple); ++ ++ ReleaseSysCache(tuple); ++ ++ return sepgsql_client_create_secid(nspsid, tclass, relOid); ++} ++ ++static sepgsql_sid_t ++get_default_secid_with_table(Oid relOid, Oid tableOid, uint16 tclass) ++{ ++ HeapTuple tuple; ++ sepgsql_sid_t tblsid; ++ ++ tuple = SearchSysCache1(RELOID, ++ ObjectIdGetDatum(tableOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for relation: %u", tableOid); ++ ++ tblsid.relid = RelationRelationId; ++ tblsid.secid = HeapTupleGetSecid(tuple); ++ ++ ReleaseSysCache(tuple); ++ ++ return sepgsql_client_create_secid(tblsid, tclass, relOid); ++} ++ ++sepgsql_sid_t ++sepgsql_get_default_database_secid(Oid templateOid) ++{ ++ return get_default_secid_with_database(DatabaseRelationId, ++ templateOid, ++ SEPG_CLASS_DB_DATABASE); ++} ++ ++sepgsql_sid_t ++sepgsql_get_default_schema_secid(Oid databaseOid) ++{ ++ return get_default_secid_with_database(NamespaceRelationId, ++ databaseOid, ++ SEPG_CLASS_DB_SCHEMA); ++} ++ ++sepgsql_sid_t ++sepgsql_get_default_table_secid(Oid namespaceOid) ++{ ++ return get_default_secid_with_schema(RelationRelationId, ++ namespaceOid, ++ SEPG_CLASS_DB_TABLE); ++} ++ ++sepgsql_sid_t ++sepgsql_get_default_sequence_secid(Oid namespaceOid) ++{ ++ return get_default_secid_with_schema(RelationRelationId, ++ namespaceOid, ++ SEPG_CLASS_DB_SEQUENCE); ++} ++ ++sepgsql_sid_t ++sepgsql_get_default_view_secid(Oid namespaceOid) ++{ ++ return get_default_secid_with_schema(RelationRelationId, ++ namespaceOid, ++ SEPG_CLASS_DB_VIEW); ++} ++ ++sepgsql_sid_t ++sepgsql_get_default_proc_secid(Oid namespaceOid) ++{ ++ return get_default_secid_with_schema(ProcedureRelationId, ++ namespaceOid, ++ SEPG_CLASS_DB_PROCEDURE); ++} ++ ++sepgsql_sid_t ++sepgsql_get_default_column_secid(Oid tableOid) ++{ ++ return get_default_secid_with_table(AttributeRelationId, ++ tableOid, ++ SEPG_CLASS_DB_COLUMN); ++} ++ ++sepgsql_sid_t ++sepgsql_get_default_tuple_secid(Oid tableOid) ++{ ++ return get_default_secid_with_table(tableOid, ++ tableOid, ++ SEPG_CLASS_DB_TUPLE); ++} ++ ++sepgsql_sid_t ++sepgsql_get_default_blob_secid(Oid databaseOid) ++{ ++ return get_default_secid_with_database(LargeObjectMetadataRelationId, ++ databaseOid, ++ SEPG_CLASS_DB_BLOB); ++} ++ ++Oid ++sepgsql_get_default_secid(Relation rel, HeapTuple tuple) ++{ ++ Oid namespaceId; ++ sepgsql_sid_t nsid ++ = { .relid = RelationGetRelid(rel), .secid = InvalidOid }; ++ ++ switch (RelationGetRelid(rel)) ++ { ++ case DatabaseRelationId: ++ case RelationRelationId: ++ case AttributeRelationId: ++ elog(WARNING, "Bug? a new tuple without security id on \"%s\"", ++ RelationGetRelationName(rel)); ++ break; ++ ++ case NamespaceRelationId: ++ nsid = sepgsql_get_default_schema_secid(MyDatabaseId); ++ break; ++ ++ case ProcedureRelationId: ++ namespaceId = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace; ++ nsid = sepgsql_get_default_proc_secid(namespaceId); ++ break; ++ ++ case LargeObjectMetadataRelationId: ++ nsid = sepgsql_get_default_blob_secid(MyDatabaseId); ++ break; ++ ++ default: ++ nsid = sepgsql_get_default_tuple_secid(RelationGetRelid(rel)); ++ break; ++ } ++ return nsid.secid; ++} ++ ++/* ++ * a workaround implementation until libselinux/refpolicy don't ++ * support db_schema or other object classes. ++ */ ++static struct { ++ uint16 tclass; ++ char *pattern; ++ char *context; ++} initial_label_catalog[] = { ++ {SEPG_CLASS_DB_DATABASE, "*", ++ "system_u:object_r:sepgsql_db_t:s0"}, ++ {SEPG_CLASS_DB_SCHEMA, "*.*", ++ "system_u:object_r:sepgsql_db_t:s0"}, ++ {SEPG_CLASS_DB_TABLE, "*.pg_catalog.*", ++ "system_u:object_r:sepgsql_sysobj_t:s0"}, ++ {SEPG_CLASS_DB_TABLE, "*.*.*", ++ "system_u:object_r:sepgsql_table_t:s0"}, ++ {SEPG_CLASS_DB_VIEW, "*.*.*", ++ "system_u:object_r:sepgsql_db_t:s0"}, ++ {SEPG_CLASS_DB_SEQUENCE, "*.*.*", ++ "system_u:object_r:sepgsql_db_t:s0"}, ++ {SEPG_CLASS_DB_PROCEDURE, "*.pg_catalog.*", ++ "system_u:object_r:sepgsql_proc_exec_t:s0"}, ++ {SEPG_CLASS_DB_PROCEDURE, "*.*.*", ++ "system_u:object_r:sepgsql_user_proc_exec_t:s0"}, ++ {SEPG_CLASS_DB_COLUMN, "*.pg_catalog.*.*", ++ "system_u:object_r:sepgsql_sysobj_t:s0"}, ++ {SEPG_CLASS_DB_COLUMN, "*.*.*.*", ++ "system_u:object_r:sepgsql_table_t:s0"}, ++ {SEPG_CLASS_DB_TUPLE, "*.pg_catalog.*", ++ "system_u:object_r:sepgsql_sysobj_t:s0"}, ++ {SEPG_CLASS_DB_TUPLE, "*.*.*", ++ "system_u:object_r:sepgsql_table_t:s0"}, ++ {SEPG_CLASS_DB_BLOB, "*.*", ++ "system_u:object_r:sepgsql_blob_t:s0"}, ++ {0, NULL, NULL}, ++}; ++ ++static char * ++lookup_init_catalog(uint16 tclass, const char *name) ++{ ++ int i; ++ ++ for (i = 0; initial_label_catalog[i].pattern; i++) ++ { ++ if (initial_label_catalog[i].tclass == tclass && ++ fnmatch(initial_label_catalog[i].pattern, name, 0) == 0) ++ return initial_label_catalog[i].context; ++ } ++ elog(ERROR, "no valid initial security context for %s (tclass=%d)", ++ name, tclass); ++ return NULL; /* for compiler quiet */ ++} ++ ++static char * ++lookup_init_tuple_label(Oid relOid, HeapTuple tuple) ++{ ++ Oid relNsp = get_rel_namespace(relOid); ++ char namebuf[NAMEDATALEN * 3 + 10]; ++ ++ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s", ++ get_database_name(MyDatabaseId), ++ get_namespace_name(relNsp), ++ get_rel_name(relOid)); ++ ++ return lookup_init_catalog(SEPG_CLASS_DB_TABLE, namebuf); ++} ++ ++static char * ++lookup_init_database_label(HeapTuple tuple) ++{ ++ Form_pg_database datForm = (Form_pg_database) GETSTRUCT(tuple); ++ ++ return lookup_init_catalog(SEPG_CLASS_DB_DATABASE, ++ NameStr(datForm->datname)); ++} ++ ++static char * ++lookup_init_schema_label(HeapTuple tuple) ++{ ++ Form_pg_namespace nspForm = (Form_pg_namespace) GETSTRUCT(tuple); ++ char namebuf[NAMEDATALEN * 2 + 10]; ++ ++ snprintf(namebuf, sizeof(namebuf), "%s.%s", ++ get_database_name(MyDatabaseId), ++ NameStr(nspForm->nspname)); ++ ++ return lookup_init_catalog(SEPG_CLASS_DB_SCHEMA, namebuf); ++} ++ ++static char * ++lookup_init_relation_label(HeapTuple tuple) ++{ ++ Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple); ++ const char *relName = NameStr(classForm->relname); ++ Oid relNsp = classForm->relnamespace; ++ char *seclabel; ++ char namebuf[NAMEDATALEN * 3 + 10]; ++ ++ switch (classForm->relkind) ++ { ++ case RELKIND_RELATION: ++ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s", ++ get_database_name(MyDatabaseId), ++ get_namespace_name(relNsp), relName); ++ seclabel = lookup_init_catalog(SEPG_CLASS_DB_TABLE, namebuf); ++ break; ++ ++ case RELKIND_SEQUENCE: ++ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s", ++ get_database_name(MyDatabaseId), ++ get_namespace_name(relNsp), relName); ++ seclabel = lookup_init_catalog(SEPG_CLASS_DB_SEQUENCE, namebuf); ++ break; ++ ++ case RELKIND_VIEW: ++ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s", ++ get_database_name(MyDatabaseId), ++ get_namespace_name(relNsp), relName); ++ seclabel = lookup_init_catalog(SEPG_CLASS_DB_VIEW, namebuf); ++ break; ++ ++ case RELKIND_INDEX: { ++ HeapTuple tbltup; ++ HeapTuple indtup; ++ Oid tblOid; ++ Oid indOid = HeapTupleGetOid(tuple); ++ ++ indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indOid)); ++ if (!HeapTupleIsValid(indtup)) ++ elog(ERROR, "cache lookup failed for index %u", indOid); ++ ++ tblOid = ((Form_pg_index) GETSTRUCT(indtup))->indrelid; ++ tbltup = SearchSysCache1(RELOID, ObjectIdGetDatum(tblOid)); ++ if (!HeapTupleIsValid(tbltup)) ++ elog(ERROR, "cache lookup failed for relation %u", tblOid); ++ ++ seclabel = lookup_init_relation_label(tbltup); ++ ++ ReleaseSysCache(tbltup); ++ ReleaseSysCache(indtup); ++ ++ break; ++ } ++ case RELKIND_TOASTVALUE: { ++ HeapTuple tbltup; ++ Oid tblOid; ++ ++ /* ++ * XXX - we assume all the toast relation's name is ++ * "pg_toast_%u", and the "%u" shall be replaced by OID ++ * of the relation which owns the toast relation ++ */ ++ tblOid = strtoul(relName + 9, NULL, 10); ++ ++ tbltup = SearchSysCache1(RELOID, ++ ObjectIdGetDatum(tblOid)); ++ if (!HeapTupleIsValid(tbltup)) ++ elog(ERROR, "cache lookup failed for relation %u", tblOid); ++ ++ seclabel = lookup_init_relation_label(tbltup); ++ ++ ReleaseSysCache(tbltup); ++ ++ break; ++ } ++ case RELKIND_COMPOSITE_TYPE: { ++ Oid typOid = classForm->reltype; ++ HeapTuple typtup; ++ ++ typtup = SearchSysCache1(TYPEOID, ++ ObjectIdGetDatum(typOid)); ++ if (!HeapTupleIsValid(typtup)) ++ elog(ERROR, "cache lookup failed for type %u", typOid); ++ ++ seclabel = lookup_init_tuple_label(TypeRelationId, typtup); ++ ++ ReleaseSysCache(typtup); ++ ++ break; ++ } ++ default: ++ elog(ERROR, "unexpected relkind %c of \"%s\"", ++ classForm->relkind, relName); ++ seclabel = NULL; /* compiler quiet */ ++ break; ++ } ++ return seclabel; ++} ++ ++static char * ++lookup_init_attribute_label(HeapTuple tuple) ++{ ++ Form_pg_attribute attForm = (Form_pg_attribute) GETSTRUCT(tuple); ++ Oid tblOid = attForm->attrelid; ++ char *seclabel; ++ char namebuf[NAMEDATALEN * 4 + 10]; ++ ++ if (get_rel_relkind(tblOid) == RELKIND_RELATION) ++ { ++ Oid tblNsp = get_rel_namespace(tblOid); ++ ++ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s.%s", ++ get_database_name(MyDatabaseId), ++ get_namespace_name(tblNsp), ++ get_rel_name(tblOid), ++ NameStr(attForm->attname)); ++ ++ seclabel = lookup_init_catalog(SEPG_CLASS_DB_COLUMN, namebuf); ++ } ++ else ++ { ++ HeapTuple tbltup; ++ ++ tbltup = SearchSysCache1(RELOID, ObjectIdGetDatum(tblOid)); ++ if (!HeapTupleIsValid(tbltup)) ++ elog(ERROR, "cache lookup failed for relation %u", tblOid); ++ ++ seclabel = lookup_init_relation_label(tbltup); ++ ++ ReleaseSysCache(tbltup); ++ } ++ return seclabel; ++} ++ ++static char * ++lookup_init_procedure_label(HeapTuple tuple) ++{ ++ Form_pg_proc proForm = (Form_pg_proc) GETSTRUCT(tuple); ++ Oid proNsp = proForm->pronamespace; ++ char namebuf[NAMEDATALEN * 3 + 10]; ++ ++ snprintf(namebuf, sizeof(namebuf), "%s.%s.%s", ++ get_database_name(MyDatabaseId), ++ get_namespace_name(proNsp), ++ NameStr(proForm->proname)); ++ ++ return lookup_init_catalog(SEPG_CLASS_DB_PROCEDURE, namebuf); ++} ++ ++static char * ++lookup_init_largeobject_label(HeapTuple tuple) ++{ ++ char namebuf[NAMEDATALEN + 20]; ++ ++ snprintf(namebuf, sizeof(namebuf), "%s.%u", ++ get_database_name(MyDatabaseId), ++ HeapTupleGetOid(tuple)); ++ ++ return lookup_init_catalog(SEPG_CLASS_DB_BLOB, namebuf); ++} ++ ++void ++sepgsql_initial_labeling(void) ++{ ++ Relation classRel; ++ SysScanDesc classScan; ++ ScanKeyData classSkey; ++ HeapTuple classTup; ++ Relation rel; ++ HeapScanDesc scan; ++ HeapTuple oldtup; ++ HeapTuple newtup; ++ ++ Assert(IsBootstrapProcessingMode()); ++ ++ StartTransactionCommand(); ++ ++ classRel = heap_open(RelationRelationId, AccessShareLock); ++ ++ ScanKeyInit(&classSkey, ++ Anum_pg_class_relhassecids, ++ BTEqualStrategyNumber, F_BOOLEQ, ++ BoolGetDatum(true)); ++ ++ classScan = systable_beginscan(classRel, InvalidOid, false, ++ SnapshotNow, 1, &classSkey); ++ ++ while (HeapTupleIsValid(classTup = systable_getnext(classScan))) ++ { ++ Oid relOid = HeapTupleGetOid(classTup); ++ ++ Assert(((Form_pg_class) GETSTRUCT(classTup))->relhassecids); ++ ++ rel = heap_open(relOid, RowExclusiveLock); ++ ++ scan = heap_beginscan(rel, SnapshotNow, 0, NULL); ++ ++ while (HeapTupleIsValid(oldtup = heap_getnext(scan, ForwardScanDirection))) ++ { ++ char *label; ++ Oid secid; ++ ++ switch (relOid) ++ { ++ case DatabaseRelationId: ++ label = lookup_init_database_label(oldtup); ++ break; ++ ++ case NamespaceRelationId: ++ label = lookup_init_schema_label(oldtup); ++ break; ++ ++ case RelationRelationId: ++ label = lookup_init_relation_label(oldtup); ++ break; ++ ++ case AttributeRelationId: ++ label = lookup_init_attribute_label(oldtup); ++ break; ++ ++ case ProcedureRelationId: ++ label = lookup_init_procedure_label(oldtup); ++ break; ++ ++ case LargeObjectMetadataRelationId: ++ label = lookup_init_largeobject_label(oldtup); ++ break; ++ ++ default: ++ label = lookup_init_tuple_label(relOid, oldtup); ++ break; ++ } ++ /* ++ * inplace-updating ++ */ ++ newtup = heap_copytuple(oldtup); ++ ++ secid = seclabelTransInput(relOid, label); ++ ++ HeapTupleSetSecid(newtup, secid); ++ ++ heap_inplace_update(rel, newtup); ++ ++ heap_freetuple(newtup); ++ } ++ heap_endscan(scan); ++ ++ heap_close(rel, RowExclusiveLock); ++ } ++ systable_endscan(classScan); ++ ++ heap_close(classRel, AccessShareLock); ++ ++ CommitTransactionCommand(); ++} ++ ++char * ++sepgsql_mcstrans_in(char *trans_label) ++{ ++ security_context_t raw_label; ++ security_context_t result; ++ ++ if (!sepgsql_mcstrans) ++ return trans_label; ++ ++ if (selinux_trans_to_raw_context(trans_label, &raw_label) < 0) ++ ereport(ERROR, ++ (errcode(ERRCODE_INTERNAL_ERROR), ++ errmsg("SELinux: unable to translate \"%s\"", trans_label))); ++ PG_TRY(); ++ { ++ result = pstrdup(raw_label); ++ } ++ PG_CATCH(); ++ { ++ freecon(raw_label); ++ PG_RE_THROW(); ++ } ++ PG_END_TRY(); ++ freecon(raw_label); ++ ++ return result; ++} ++ ++char * ++sepgsql_mcstrans_out(char *raw_label) ++{ ++ security_context_t trans_label; ++ security_context_t result; ++ ++ if (!sepgsql_mcstrans) ++ return raw_label; ++ ++ if (selinux_raw_to_trans_context(raw_label, &trans_label) < 0) ++ ereport(ERROR, ++ (errcode(ERRCODE_INTERNAL_ERROR), ++ errmsg("SELinux: unable to translate \"%s\"", raw_label))); ++ PG_TRY(); ++ { ++ result = pstrdup(trans_label); ++ } ++ PG_CATCH(); ++ { ++ freecon(trans_label); ++ PG_RE_THROW(); ++ } ++ PG_END_TRY(); ++ freecon(trans_label); ++ ++ return result; ++} ++ ++char * ++sepgsql_rawlabel_in(char *label) ++{ ++ if (!label || security_check_context_raw(label) < 0) ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_NAME), ++ errmsg("invalid security context \"%s\"", label))); ++ return label; ++} ++ ++char * ++sepgsql_rawlabel_out(char *label) ++{ ++ if (!label || security_check_context_raw(label) < 0) ++ { ++ security_context_t unlabeled_label; ++ ++ if (security_get_initial_context_raw("unlabeled", ++ &unlabeled_label) < 0) ++ ereport(ERROR, ++ (errcode(ERRCODE_INTERNAL_ERROR), ++ errmsg("unable to get unlabeled security context"))); ++ PG_TRY(); ++ { ++ label = pstrdup(unlabeled_label); ++ } ++ PG_CATCH(); ++ { ++ freecon(unlabeled_label); ++ PG_RE_THROW(); ++ } ++ PG_END_TRY(); ++ freecon(unlabeled_label); ++ } ++ return label; ++} +diff --git a/src/backend/sepgsql/misc.c b/src/backend/sepgsql/misc.c +new file mode 100644 +index 0000000..4f29cd7 +--- /dev/null ++++ b/src/backend/sepgsql/misc.c +@@ -0,0 +1,123 @@ ++/* ++ * misc.c ++ * ++ * SELinux hooks related to misc features ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "libpq/libpq-be.h" ++#include "miscadmin.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/guc.h" ++ ++#include ++ ++/* ++ * sepgsql_client_label ++ * ++ * security context of the peer process ++ */ ++static char *sepgsql_client_label = NULL; ++ ++char * ++sepgsql_get_client_label(void) ++{ ++ return sepgsql_client_label; ++} ++ ++char * ++sepgsql_set_client_label(char *new_label) ++{ ++ char *old_label = sepgsql_client_label; ++ ++ sepgsql_client_label = new_label; ++ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_avc_switch(new_label); ++ } ++#endif ++ return old_label; ++} ++ ++void ++sepgsql_post_bootstraping(void) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ sepgsql_initial_labeling(); ++#endif ++} ++ ++void ++sepgsql_initialize(void) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ security_context_t context; ++ ++ /* init userspace avc */ ++ sepgsql_avc_init(); ++ ++ /* init privilege of the client */ ++ if (!MyProcPort) ++ { ++ /* ++ * SE-PgSQL does not prevent anything in single-user mode. ++ */ ++ sepostgresql_mode = SEPGSQL_MODE_INTERNAL; ++ ++ if (getprevcon_raw(&context) < 0) ++ ereport(ERROR, ++ (errcode(ERRCODE_INTERNAL_ERROR), ++ errmsg("SELinux: could not get server context"))); ++ } ++ else ++ { ++ if (getpeercon_raw(MyProcPort->sock, &context) < 0) ++ ereport(ERROR, ++ (errcode(ERRCODE_INTERNAL_ERROR), ++ errmsg("SELinux: could not get client context"))); ++ } ++ sepgsql_set_client_label(context); ++ ++ return; ++ } ++#endif ++ if (default_with_secids) ++ { ++ default_with_secids = false; ++ elog(LOG, "guc: default_with_secid was turned off " ++ "because no label based access control is availabel now"); ++ } ++} ++ ++bool ++sepgsql_worker_needed(void) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ return true; ++#endif ++ return false; ++} ++ ++void ++sepgsql_worker_main(void) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_avc_worker_main(); ++ return; ++ } ++#endif ++ elog(FATAL, "Bug? try to launch worker process without security provider"); ++} ++ +diff --git a/src/backend/sepgsql/operator.c b/src/backend/sepgsql/operator.c +new file mode 100644 +index 0000000..7960525 +--- /dev/null ++++ b/src/backend/sepgsql/operator.c +@@ -0,0 +1,454 @@ ++/* ++ * operator.c ++ * ++ * SELinux hooks related to operators ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_operator.h" ++#include "catalog/pg_opclass.h" ++#include "catalog/pg_opfamily.h" ++#include "catalog/pg_seclabel.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/builtins.h" ++#include "utils/lsyscache.h" ++#include "utils/syscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_operator_common(Oid operOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ char *auname; ++ bool retval; ++ ++ tsid.relid = OperatorRelationId; ++ tsid.secid = GetSysCacheSecid1(OPEROID, ObjectIdGetDatum(operOid)); ++ ++ auname = format_operator(operOid); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ pfree(auname); ++ ++ return retval; ++} ++ ++bool ++sepgsql_opclass_common(Oid opcOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ HeapTuple tuple; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for operator class %u", opcOid); ++ ++ tsid.relid = OperatorClassRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++bool ++sepgsql_opfamily_common(Oid opfOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ HeapTuple tuple; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for operator family %u", opfOid); ++ ++ tsid.relid = OperatorFamilyRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_opfamily) GETSTRUCT(tuple))->opfname); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++static Oid ++get_operator_namespace(Oid operOid) ++{ ++ HeapTuple tuple; ++ Oid namespaceId; ++ ++ tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); ++ if (HeapTupleIsValid(tuple)) ++ { ++ namespaceId = ((Form_pg_operator) GETSTRUCT(tuple))->oprnamespace; ++ ++ ReleaseSysCache(tuple); ++ } ++ return namespaceId; ++} ++ ++static Oid ++get_opclass_namespace(Oid opcOid) ++{ ++ HeapTuple tuple; ++ Oid namespaceId = InvalidOid; ++ ++ tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcOid)); ++ if (HeapTupleIsValid(tuple)) ++ { ++ namespaceId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcnamespace; ++ ++ ReleaseSysCache(tuple); ++ } ++ return namespaceId; ++} ++ ++static Oid ++get_opfamily_namespace(Oid opfOid) ++{ ++ HeapTuple tuple; ++ Oid namespaceId = InvalidOid; ++ ++ tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfOid)); ++ if (HeapTupleIsValid(tuple)) ++ { ++ namespaceId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfnamespace; ++ ++ ReleaseSysCache(tuple); ++ } ++ return namespaceId; ++} ++ ++#endif ++ ++Oid ++sepgsql_operator_create(const char *operName, Oid replaced, Oid namespaceId, ++ Oid codeFunc, Oid restrictFunc, Oid joinFunc, ++ Oid commutatorOp, Oid negatorOp) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ uint32 required; ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_tuple:{insert} */ ++ if (OidIsValid(replaced)) ++ { ++ nsid.relid = OperatorRelationId; ++ nsid.secid = GetSysCacheSecid1(OPEROID, ++ ObjectIdGetDatum(replaced)); ++ required = SEPG_DB_TUPLE__UPDATE; ++ } ++ else ++ { ++ nsid = sepgsql_get_default_tuple_secid(OperatorRelationId); ++ required = SEPG_DB_TUPLE__INSERT; ++ } ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ operName, ++ true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(codeFunc)) ++ sepgsql_proc_common(codeFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ if (OidIsValid(restrictFunc)) ++ sepgsql_proc_common(restrictFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ if (OidIsValid(joinFunc)) ++ sepgsql_proc_common(joinFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* ++ * XXX - we should check anything on he commutatorOp/negatorOp ++ */ ++ ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_operator_alter(Oid operOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_operator_common(operOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_operator_relabel(Oid operOid, char *newLabel) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ ++ nsid.relid = OperatorRelationId; ++ nsid.secid = seclabelTransInput(OperatorRelationId, newLabel); ++ ++ /* db_tuple:{update relabelfrom} */ ++ sepgsql_operator_common(operOid, ++ SEPG_DB_TUPLE__UPDATE | ++ SEPG_DB_TUPLE__RELABELFROM, ++ true); ++ ++ /* db_tuple:{relabelto} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__RELABELTO, ++ format_operator(operOid), ++ true); ++ return nsid.secid; ++ } ++#endif ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("SE-PostgreSQL is not available"))); ++ return InvalidOid; ++} ++ ++void ++sepgsql_operator_drop(Oid operOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_operator_namespace(operOid); ++ ++ /* db_namespace:{remove_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{delete} */ ++ sepgsql_operator_common(operOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_operator_comment(Oid operOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_operator_common(operOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_opclass_create(const char *opcName, Oid namespaceId, ++ Oid typeOid, Oid opfamilyOid, Oid storageOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_TUPLE__UPDATE, true); ++ ++ /* db_tuple:{insert} */ ++ nsid = sepgsql_get_default_tuple_secid(OperatorRelationId); ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ opcName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_opclass_alter(Oid opcOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_opclass_common(opcOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_opclass_alter_rename(Oid opcOid, const char *newName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_opclass_namespace(opcOid); ++ ++ /* db_schema:{add_name remove_name} */ ++ sepgsql_schema_common(namespaceId, ++ SEPG_DB_SCHEMA__ADD_NAME | ++ SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{update} */ ++ sepgsql_opclass_common(opcOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_opclass_drop(Oid opcOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_opclass_namespace(opcOid); ++ ++ /* db_schema:{remove_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{drop} */ ++ sepgsql_opclass_common(opcOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_opclass_comment(Oid opcOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_opclass_common(opcOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_opfamily_create(const char *opfName, Oid namespaceId, Oid amOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_tuple:{insert} */ ++ nsid = sepgsql_get_default_tuple_secid(OperatorFamilyRelationId); ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ opfName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_opfamily_alter(Oid opfOid, bool isDrop, Oid amOid, ++ List *operators, List *procedures) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_opfamily_common(opfOid, SEPG_DB_TUPLE__UPDATE, true); ++ ++ /* XXX - to do we should install checks? */ ++ } ++#endif ++} ++ ++void ++sepgsql_opfamily_alter_rename(Oid opfOid, const char *newName) ++{ ++ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_opfamily_namespace(opfOid); ++ ++ /* db_schema:{add_name remove_name} */ ++ sepgsql_schema_common(namespaceId, ++ SEPG_DB_SCHEMA__ADD_NAME | ++ SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{update} */ ++ sepgsql_opfamily_common(opfOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_opfamily_alter_owner(Oid opfOid, Oid newOwner) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_opfamily_common(opfOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_opfamily_drop(Oid opfOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_opfamily_namespace(opfOid); ++ ++ /* db_schema:{remove_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{delete} */ ++ sepgsql_opfamily_common(opfOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_opfamily_comment(Oid opfOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_opfamily_common(opfOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/proc.c b/src/backend/sepgsql/proc.c +new file mode 100644 +index 0000000..1149571 +--- /dev/null ++++ b/src/backend/sepgsql/proc.c +@@ -0,0 +1,366 @@ ++/* ++ * proc.c ++ * ++ * SELinux hooks related to procedures ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_aggregate.h" ++#include "catalog/pg_language.h" ++#include "catalog/pg_namespace.h" ++#include "catalog/pg_proc.h" ++#include "catalog/pg_seclabel.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/builtins.h" ++#include "utils/syscache.h" ++#include "utils/lsyscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_proc_common(Oid procOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ char *auname; ++ bool retval; ++ ++ tsid.relid = ProcedureRelationId; ++ tsid.secid = GetSysCacheSecid1(PROCOID, ++ ObjectIdGetDatum(procOid)); ++ ++ auname = format_procedure(procOid); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_PROCEDURE, ++ required, ++ auname, ++ abort); ++ pfree(auname); ++ ++ return retval; ++} ++#endif ++ ++Oid ++sepgsql_proc_create(const char *proName, Oid replaced, ++ Oid namespaceId, Oid languageId) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ HeapTuple tuple; ++ sepgsql_sid_t nsid; ++ char *scontext; ++ char *tcontext; ++ uint32 required; ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_procedure:{create or setattr} */ ++ if (OidIsValid(replaced)) ++ { ++ nsid.relid = ProcedureRelationId; ++ nsid.secid = GetSysCacheSecid1(PROCOID, ++ ObjectIdGetDatum(replaced)); ++ required = SEPG_DB_PROCEDURE__SETATTR; ++ } ++ else ++ { ++ nsid = sepgsql_get_default_proc_secid(namespaceId); ++ required = SEPG_DB_PROCEDURE__CREATE; ++ } ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_PROCEDURE, ++ required, ++ proName, ++ true); ++ ++ /* db_language:{implemente} */ ++ tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(languageId)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for language %u", languageId); ++ ++ scontext = seclabelRawOutput(LanguageRelationId, ++ HeapTupleGetSecid(tuple)); ++ tcontext = seclabelRawOutput(nsid.relid, nsid.secid); ++ ++ sepgsql_compute_perms(scontext, tcontext, ++ SEPG_CLASS_DB_LANGUAGE, ++ SEPG_DB_LANGUAGE__IMPLEMENTE, ++ proName, true); ++ ++ ReleaseSysCache(tuple); ++ ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_proc_alter(Oid procOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_proc_alter_rename(Oid procOid, const char *newName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_func_namespace(procOid); ++ ++ /* db_schema:{remove_name add_name} */ ++ sepgsql_schema_common(namespaceId, ++ SEPG_DB_SCHEMA__REMOVE_NAME | ++ SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_procedure:{setattr} */ ++ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_proc_alter_schema(Oid procOid, Oid newSchema) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_func_namespace(procOid); ++ ++ /* db_schema:{remove_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(newSchema, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_procedure:{setattr} */ ++ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_proc_relabel(Oid procOid, char *new_label) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t tsid; ++ ++ tsid.relid = ProcedureRelationId; ++ tsid.secid = seclabelTransInput(tsid.relid, new_label); ++ ++ /* db_procedure:{setattr relabelfrom} */ ++ sepgsql_proc_common(procOid, ++ SEPG_DB_PROCEDURE__SETATTR | ++ SEPG_DB_PROCEDURE__RELABELFROM, true); ++ ++ /* db_procedure:{relabelto} */ ++ sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_PROCEDURE, ++ SEPG_DB_PROCEDURE__RELABELTO, ++ format_procedure(procOid), ++ true); ++ return tsid.secid; ++ } ++#endif ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("SE-PostgreSQL is not available"))); ++ return InvalidOid; ++} ++ ++void ++sepgsql_proc_drop(Oid procOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_func_namespace(procOid); ++ ++ /* db_schema:{remove_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_procedure:{proc} */ ++ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__DROP, true); ++ } ++#endif ++} ++ ++void ++sepgsql_proc_grant(Oid procOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_proc_comment(Oid procOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_proc_execute(Oid procOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_proc_common(procOid, SEPG_DB_PROCEDURE__EXECUTE, true); ++ } ++#endif ++} ++ ++bool ++sepgsql_proc_be_inlined(HeapTuple protup) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t tsid; ++ char *old_label; ++ char *new_label; ++ const char *auname ++ = NameStr(((Form_pg_proc) GETSTRUCT(protup))->proname); ++ ++ tsid.relid = ProcedureRelationId; ++ tsid.secid = HeapTupleGetSecid(protup); ++ ++ if (!sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_PROCEDURE, ++ SEPG_DB_PROCEDURE__EXECUTE, ++ auname, false)) ++ return false; ++ ++ old_label = sepgsql_get_client_label(); ++ new_label = sepgsql_client_create_label(tsid, SEPG_CLASS_PROCESS); ++ if (strcmp(old_label, new_label) != 0) ++ return false; ++ ++ return true; ++ } ++#endif ++ return true; ++} ++ ++char * ++sepgsql_proc_domtrans(HeapTuple protup, MemoryContext mcxt) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t tsid; ++ char *old_label = sepgsql_get_client_label(); ++ char *new_label; ++ char *auname ++ = NameStr(((Form_pg_proc) GETSTRUCT(protup))->proname); ++ ++ tsid.relid = ProcedureRelationId; ++ tsid.secid = HeapTupleGetSecid(protup); ++ ++ new_label = sepgsql_client_create_label(tsid, SEPG_CLASS_PROCESS); ++ ++ if (strcmp(old_label, new_label) == 0) ++ return NULL; ++ ++ /* db_procedure:{entrypoint} */ ++ sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_PROCEDURE, ++ SEPG_DB_PROCEDURE__ENTRYPOINT, ++ auname, ++ true); ++ ++ /* db_process:{transition} */ ++ sepgsql_compute_perms(old_label, ++ new_label, ++ SEPG_CLASS_PROCESS, ++ SEPG_PROCESS__TRANSITION, ++ NULL, ++ true); ++ ++ return MemoryContextStrdup(mcxt, new_label); ++ } ++#endif ++ return NULL; ++} ++ ++Oid ++sepgsql_aggregate_create(const char *aggName, Oid namespaceId, ++ Oid transFunc, Oid finalFunc) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid securityId; ++ ++ /* check normal creation permission */ ++ securityId = sepgsql_proc_create(aggName, InvalidOid, ++ namespaceId, INTERNALlanguageId); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(transFunc)) ++ sepgsql_proc_common(transFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(finalFunc)) ++ sepgsql_proc_common(finalFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ return securityId; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_aggregate_execute(Oid aggOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Form_pg_aggregate aggForm; ++ HeapTuple tuple; ++ ++ tuple = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(aggOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for aggregate %u", aggOid); ++ ++ aggForm = (Form_pg_aggregate) GETSTRUCT(tuple); ++ ++ /* pg_proc:{execute} */ ++ sepgsql_proc_common(aggOid, SEPG_DB_PROCEDURE__EXECUTE, true); ++ ++ /* pg_proc:{execute} */ ++ if (OidIsValid(aggForm->aggtransfn)) ++ sepgsql_proc_common(aggForm->aggtransfn, ++ SEPG_DB_PROCEDURE__EXECUTE, true); ++ ++ /* pg_proc:{execute} */ ++ if (OidIsValid(aggForm->aggfinalfn)) ++ sepgsql_proc_common(aggForm->aggfinalfn, ++ SEPG_DB_PROCEDURE__EXECUTE, true); ++ ++ ReleaseSysCache(tuple); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/proxy.c b/src/backend/sepgsql/proxy.c +new file mode 100644 +index 0000000..32bb57a +--- /dev/null ++++ b/src/backend/sepgsql/proxy.c +@@ -0,0 +1,129 @@ ++/* ++ * proxy.c ++ * ++ * mandatory query rewriting support ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/namespace.h" ++#include "lib/stringinfo.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/builtins.h" ++#include "utils/lsyscache.h" ++#include "tcop/tcopprot.h" ++ ++#ifdef HAVE_SELINUX ++/* ++ * If row-level access control is configured, COPY TO statement ++ * shall be rewritten to SELECT * statement. ++ */ ++static void ++sepgsql_proxy_copy_stmt(CopyStmt *stmt) ++{ ++ Oid relOid; ++ Oid namespaceId; ++ List *queries; ++ ListCell *l, *p = NULL; ++ bool with_oids = false; ++ StringInfoData qbuf; ++ ++ /* no need to do nothing */ ++ if (stmt->is_from || !stmt->relation) ++ return; ++ ++ /* obtain relaion ID */ ++ relOid = RangeVarGetRelid(stmt->relation, false); ++ ++ namespaceId = get_rel_namespace(relOid); ++ ++ /* Is there WITH OID option? */ ++retry: ++ foreach (l, stmt->options) ++ { ++ DefElem *defel = (DefElem *) lfirst(l); ++ ++ Assert(IsA(defel, DefElem)); ++ if (strcmp(defel->defname, "oids") == 0) ++ { ++ with_oids = true; ++ stmt->options = list_delete_cell(stmt->options, l, p); ++ goto retry; ++ } ++ p = l; ++ } ++ ++ /* Make a query */ ++ initStringInfo(&qbuf); ++ ++ appendStringInfo(&qbuf, "SELECT %s", with_oids ? "oid" : ""); ++ ++ if (stmt->attlist == NIL) ++ appendStringInfo(&qbuf, "%s*", with_oids ? "," : ""); ++ else ++ { ++ bool need_comma = with_oids; ++ ++ foreach (l, stmt->attlist) ++ { ++ appendStringInfo(&qbuf, "%s%s", ++ need_comma ? "," : "", ++ strVal(lfirst(l))); ++ need_comma = true; ++ } ++ } ++ ++ appendStringInfo(&qbuf, " FROM ONLY %s.%s", ++ quote_identifier(get_namespace_name(namespaceId)), ++ quote_identifier(get_rel_name(relOid))); ++ ++ queries = pg_parse_query(qbuf.data); ++ ++ Assert(list_length(queries) == 1); ++ ++ /* update CopyStmt */ ++ stmt->query = lfirst(list_head(queries)); ++ stmt->relation = NULL; ++} ++#endif ++ ++void ++sepgsql_proxy_queries(List *queryList) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ ListCell *l; ++ ++ foreach (l, queryList) ++ { ++ Query *qry = lfirst(l); ++ ++ switch (qry->commandType) ++ { ++ case CMD_SELECT: ++ break; ++ ++ case CMD_UPDATE: ++ case CMD_INSERT: ++ case CMD_DELETE: ++ /* we have no rewrite policy */ ++ break; ++ ++ case CMD_UTILITY: ++ Assert(qry->utilityStmt != NULL); ++ if (IsA(qry->utilityStmt, CopyStmt)) ++ sepgsql_proxy_copy_stmt((CopyStmt *)qry->utilityStmt); ++ break; ++ ++ default: ++ /* CMD_UNKNOWN or CMD_NOTHING */ ++ break; ++ } ++ } ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/relation.c b/src/backend/sepgsql/relation.c +new file mode 100644 +index 0000000..2604749 +--- /dev/null ++++ b/src/backend/sepgsql/relation.c +@@ -0,0 +1,819 @@ ++/* ++ * relation.c ++ * ++ * SELinux hooks related to relation ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "access/sysattr.h" ++#include "catalog/catalog.h" ++#include "catalog/heap.h" ++#include "catalog/pg_attribute.h" ++#include "catalog/pg_class.h" ++#include "catalog/pg_seclabel.h" ++#include "catalog/pg_type.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/lsyscache.h" ++#include "utils/syscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_relation_common(Oid relOid, uint32 required, bool abort) ++{ ++ Form_pg_class classForm; ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ uint16 tclass; ++ bool retval; ++ ++ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for relation %u", relOid); ++ classForm = (Form_pg_class) GETSTRUCT(tuple); ++ ++ tsid.relid = RelationRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ switch (classForm->relkind) ++ { ++ case RELKIND_SEQUENCE: ++ tclass = SEPG_CLASS_DB_SEQUENCE; ++ break; ++ ++ case RELKIND_VIEW: ++ tclass = SEPG_CLASS_DB_VIEW; ++ break; ++ ++ case RELKIND_COMPOSITE_TYPE: ++ tclass = SEPG_CLASS_DB_TUPLE; ++ break; ++ ++ default: ++ tclass = SEPG_CLASS_DB_TABLE; ++ break; ++ } ++ ++ retval = sepgsql_client_perms(tsid, ++ tclass, ++ required, ++ NameStr(classForm->relname), ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++static Bitmapset * ++fixup_whole_row_reference(Oid relOid, int natts, Bitmapset *columns) ++{ ++ Bitmapset *result; ++ AttrNumber attno; ++ ++ attno = InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber; ++ if (!bms_is_member(attno, columns)) ++ return columns; /* no need to fixup */ ++ ++ result = bms_copy(columns); ++ result = bms_del_member(result, attno); ++ ++ for (attno=1; attno <= natts; attno++) ++ { ++ Form_pg_attribute attForm; ++ HeapTuple atttup; ++ ++ atttup = SearchSysCache2(ATTNUM, ++ ObjectIdGetDatum(relOid), ++ Int16GetDatum(attno)); ++ if (!HeapTupleIsValid(atttup)) ++ continue; ++ ++ attForm = (Form_pg_attribute) GETSTRUCT(atttup); ++ if (!attForm->attisdropped) ++ { ++ int cindex = attno - FirstLowInvalidHeapAttributeNumber; ++ result = bms_add_member(result, cindex); ++ } ++ ReleaseSysCache(atttup); ++ } ++ ++ return result; ++} ++#endif ++ ++bool ++sepgsql_relation_perms(Oid relOid, AclMode aclmask, ++ Bitmapset *selectedCols, ++ Bitmapset *modifiedCols, bool abort) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Form_pg_class relForm; ++ HeapTuple tuple; ++ sepgsql_sid_t rsid; ++ Bitmapset *selColsEx; ++ Bitmapset *modColsEx; ++ Bitmapset *columns; ++ AttrNumber nattrs; ++ AttrNumber attno; ++ const char *auname; ++ char relkind; ++ uint16 tclass = 0; ++ uint32 required = 0; ++ bool rc = true; ++ ++ /* ++ * Hardwired policy: ++ * SE-PostgreSQL enforces clients cannot modify system catalogs ++ * and access toast values using DML statements in enforcing mode. ++ * Note that it performs in permissive mode during initdb phase. ++ */ ++ if (sepgsql_get_enforce()) ++ { ++ if (IsSystemNamespace(get_rel_namespace(relOid)) && ++ (aclmask & (ACL_UPDATE | ACL_INSERT | ACL_DELETE)) != 0) ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("not allowed to modify system catalog \"%s\"", ++ get_rel_name(relOid)))); ++ ++ if (get_rel_relkind(relOid) == RELKIND_TOASTVALUE) ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("not allowed to access toast values \"%s\"", ++ get_rel_name(relOid)))); ++ } ++ ++ /* ++ * check relation's permissions ++ */ ++ tuple = SearchSysCache1(RELOID, ++ ObjectIdGetDatum(relOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for relation %u", relOid); ++ ++ rsid.relid = RelationRelationId; ++ rsid.secid = HeapTupleGetSecid(tuple); ++ ++ relForm = (Form_pg_class) GETSTRUCT(tuple); ++ auname = NameStr(relForm->relname); ++ relkind = relForm->relkind; ++ nattrs = relForm->relnatts; ++ ++ switch (relkind) ++ { ++ case RELKIND_RELATION: ++ tclass = SEPG_CLASS_DB_TABLE; ++ ++ if (aclmask & ACL_SELECT) ++ required |= SEPG_DB_TABLE__SELECT; ++ if (aclmask & ACL_INSERT) ++ required |= SEPG_DB_TABLE__INSERT; ++ if (aclmask & ACL_UPDATE) ++ required |= (!modifiedCols ++ ? SEPG_DB_TABLE__LOCK ++ : SEPG_DB_TABLE__UPDATE); ++ if (aclmask & ACL_DELETE) ++ required |= SEPG_DB_TABLE__DELETE; ++ break; ++ ++ case RELKIND_SEQUENCE: ++ tclass = SEPG_CLASS_DB_SEQUENCE; ++ if (aclmask & ACL_SELECT) ++ required |= SEPG_DB_SEQUENCE__GET_VALUE; ++ break; ++ ++ case RELKIND_VIEW: ++ tclass = SEPG_CLASS_DB_VIEW; ++ if (aclmask != 0) ++ required |= SEPG_DB_VIEW__EXPAND; ++ break; ++ ++ default: ++ elog(ERROR, "Bug? unexpected relkind %c", relkind); ++ return false; ++ } ++ ++ if (required != 0) ++ rc = sepgsql_client_perms(rsid, tclass, required, auname, abort); ++ ++ ReleaseSysCache(tuple); ++ ++ if (!rc || relkind != RELKIND_RELATION) ++ return rc; ++ ++ /* ++ * Check column's permissions ++ */ ++ selColsEx = fixup_whole_row_reference(relOid, nattrs, ++ selectedCols); ++ modColsEx = fixup_whole_row_reference(relOid, nattrs, ++ modifiedCols); ++ columns = bms_union(selColsEx, modColsEx); ++ ++ while ((attno = bms_first_member(columns)) >= 0) ++ { ++ required = 0; ++ ++ if (bms_is_member(attno, selColsEx)) ++ required |= SEPG_DB_COLUMN__SELECT; ++ if (bms_is_member(attno, modColsEx)) ++ { ++ if (aclmask & ACL_UPDATE) ++ required |= SEPG_DB_COLUMN__UPDATE; ++ if (aclmask & ACL_INSERT) ++ required |= SEPG_DB_COLUMN__INSERT; ++ } ++ if (required == 0) ++ continue; ++ ++ attno += FirstLowInvalidHeapAttributeNumber; ++ rc = sepgsql_attribute_common(relOid, attno, required, abort); ++ if (!rc) ++ break; ++ } ++ ++ if (selColsEx != selectedCols) ++ bms_free(selColsEx); ++ if (modColsEx != modifiedCols) ++ bms_free(modColsEx); ++ bms_free(columns); ++ ++ return rc; ++ } ++#endif ++ return true; ++} ++ ++Oid * ++sepgsql_relation_create(const char *relName, ++ char relkind, ++ TupleDesc tupDesc, ++ Oid namespaceId, ++ List *supOids, ++ bool createAs) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t tsid; ++ sepgsql_sid_t csid; ++ Oid *secLabels; ++ uint16 tclass; ++ uint32 perms; ++ AttrNumber index, attno, nitems; ++ ++ /* ++ * The secLabeld array stores security identifiers to be ++ * assigned on the new table and columns. ++ * ++ * secLabels[0] is security-id of the relation. ++ * secLabels[attnum - FirstLowInvalidHeapAttributeNumber] ++ * is security-id of the columns. ++ */ ++ secLabels = seclabelMakeRelationDefaults(tupDesc, supOids); ++ nitems = tupDesc->natts - FirstLowInvalidHeapAttributeNumber; ++ ++ switch (relkind) ++ { ++ case RELKIND_RELATION: ++ if (!OidIsValid(secLabels[0])) ++ { ++ tsid = sepgsql_get_default_table_secid(namespaceId); ++ secLabels[0] = tsid.secid; ++ } ++ tclass = SEPG_CLASS_DB_TABLE; ++ perms = SEPG_DB_TABLE__CREATE; ++ if (createAs) ++ perms |= SEPG_DB_TABLE__INSERT; ++ break; ++ ++ case RELKIND_SEQUENCE: ++ if (!OidIsValid(secLabels[0])) ++ { ++ tsid = sepgsql_get_default_sequence_secid(namespaceId); ++ secLabels[0] = tsid.secid; ++ } ++ tclass = SEPG_CLASS_DB_SEQUENCE; ++ perms = SEPG_DB_SEQUENCE__CREATE; ++ break; ++ ++ case RELKIND_VIEW: ++ if (!OidIsValid(secLabels[0])) ++ { ++ tsid = sepgsql_get_default_view_secid(namespaceId); ++ secLabels[0] = tsid.secid; ++ } ++ tclass = SEPG_CLASS_DB_VIEW; ++ perms = SEPG_DB_VIEW__CREATE; ++ break; ++ ++ case RELKIND_COMPOSITE_TYPE: ++ if (!OidIsValid(secLabels[0])) ++ { ++ tsid = sepgsql_get_default_tuple_secid(TypeRelationId); ++ secLabels[0] = seclabelMoveSecid(RelationRelationId, ++ TypeRelationId, tsid.secid); ++ } ++ tclass = SEPG_CLASS_DB_TUPLE; ++ perms = SEPG_DB_TUPLE__INSERT; ++ break; ++ ++ default: ++ elog(ERROR, "Bug? unexpected relkind %c", relkind); ++ return NULL; ++ } ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_table:{create} or others */ ++ tsid.relid = RelationRelationId; ++ tsid.secid = secLabels[0]; ++ sepgsql_client_perms(tsid, tclass, perms, relName, true); ++ ++ /* no individual security-id except for RELKIND_RELATION */ ++ if (relkind != RELKIND_RELATION) ++ { ++ Oid securityId = seclabelMoveSecid(AttributeRelationId, ++ RelationRelationId, secLabels[0]); ++ ++ for (index = 1; index < nitems; index++) ++ secLabels[index] = securityId; ++ ++ return secLabels; ++ } ++ ++ /* ++ * security context of the columns ++ */ ++ for (index = 1; index < nitems; index++) ++ { ++ Form_pg_attribute attForm; ++ char auname[NAMEDATALEN * 2 + 10]; ++ ++ attno = index + FirstLowInvalidHeapAttributeNumber; ++ ++ /* skip unnecessary system columns */ ++ if ((attno == ObjectIdAttributeNumber && !tupDesc->tdhasoid) || ++ (attno == SecurityLabelAttributeNumber && !tupDesc->tdhassecid)) ++ continue; ++ ++ if (!OidIsValid(secLabels[index])) ++ { ++ csid = sepgsql_client_create_secid(tsid, ++ SEPG_CLASS_DB_COLUMN, ++ AttributeRelationId); ++ secLabels[index] = csid.secid; ++ } ++ ++ if (attno < 0) ++ attForm = SystemAttributeDefinition(attno, ++ tupDesc->tdhasoid, ++ tupDesc->tdhassecid); ++ else ++ attForm = tupDesc->attrs[attno]; ++ ++ /* db_column:{create (insert)} permission */ ++ csid.relid = AttributeRelationId; ++ csid.secid = secLabels[index]; ++ ++ perms = SEPG_DB_COLUMN__CREATE; ++ if (createAs && attno >= 0) ++ perms |= SEPG_DB_COLUMN__INSERT; ++ ++ snprintf(auname, sizeof(auname), "%s.%s", ++ relName, NameStr(attForm->attname)); ++ ++ sepgsql_client_perms(csid, ++ SEPG_CLASS_DB_COLUMN, ++ perms, ++ auname, ++ true); ++ } ++ return secLabels; ++ } ++#endif ++ return NULL; ++} ++ ++void ++sepgsql_relation_alter(Oid relationOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_relation_alter_schema(Oid relationOid, Oid newSchema) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_relation_alter_rename(Oid relationOid, const char *newName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_relation_alter_inherit(Oid childOid, Oid parentOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_relation_common(childOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_relation_relabel(Oid relationOid, char *new_label) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ char *auname; ++ char relkind; ++ uint16 tclass = 0; ++ ++ nsid.relid = RelationRelationId; ++ nsid.secid = seclabelTransInput(nsid.relid, new_label); ++ ++ auname = get_rel_name(relationOid); ++ relkind = get_rel_relkind(relationOid); ++ ++ switch (relkind) ++ { ++ case RELKIND_RELATION: ++ tclass = SEPG_CLASS_DB_TABLE; ++ break; ++ ++ case RELKIND_SEQUENCE: ++ tclass = SEPG_CLASS_DB_SEQUENCE; ++ break; ++ ++ case RELKIND_VIEW: ++ tclass = SEPG_CLASS_DB_VIEW; ++ break; ++ ++ case RELKIND_COMPOSITE_TYPE: ++ tclass = SEPG_CLASS_DB_TUPLE; ++ break; ++ ++ default: ++ elog(ERROR, "unexpected relkind %c", relkind); ++ break;; ++ } ++ /* db_xxx:{setattr relabelfrom} */ ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR | ++ SEPG_DB_TABLE__RELABELFROM, true); ++ ++ /* db_xxx:{relabelto} */ ++ sepgsql_client_perms(nsid, ++ tclass, ++ SEPG_DB_TABLE__RELABELTO, ++ auname, true); ++ pfree(auname); ++ ++ return nsid.secid; ++ } ++#endif ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("SE-PostgreSQL is not available"))); ++ return InvalidOid; ++} ++ ++void ++sepgsql_relation_drop(Oid relationOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__DROP, true); ++ } ++#endif ++} ++ ++void ++sepgsql_relation_getattr(Oid relationOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__GETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_relation_grant(Oid relationOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_relation_comment(Oid relationOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++bool ++sepgsql_relation_cluster(Oid relationOid, bool abort) ++{ ++#ifdef HAVE_SELINUX ++ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); ++ ++ if (sepgsql_is_enabled()) ++ { ++ bool retval = ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__INDEXON, true); ++ return retval; ++ } ++#endif ++ return true; ++} ++ ++void ++sepgsql_relation_truncate(Relation rel) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(RelationGetForm(rel)->relkind == RELKIND_RELATION); ++ ++ /* db_table:{delete} */ ++ sepgsql_relation_common(RelationGetRelid(rel), ++ SEPG_DB_TABLE__DELETE, true); ++ /* db_tuple:{delete} */ ++ } ++#endif ++} ++ ++void ++sepgsql_relation_lock(Relation rel) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(RelationGetForm(rel)->relkind == RELKIND_RELATION); ++ ++ /* db_table:{lock} */ ++ sepgsql_relation_common(RelationGetRelid(rel), ++ SEPG_DB_TABLE__LOCK, true); ++ } ++#endif ++} ++ ++void ++sepgsql_relation_reindex(Oid relationOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); ++ ++ /* db_table:{indexon} */ ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__INDEXON, true); ++ } ++#endif ++} ++ ++void ++sepgsql_view_replace(Oid viewOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(get_rel_relkind(viewOid) == RELKIND_VIEW); ++ /* db_view:{setattr} */ ++ sepgsql_relation_common(viewOid, ++ SEPG_DB_VIEW__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_index_create(Oid relationOid, Oid namespaceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceOid, ++ SEPG_DB_SCHEMA__ADD_NAME, true); ++ /* db_table:{setattr indexon} */ ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR | ++ SEPG_DB_TABLE__INDEXON, true); ++ } ++#endif ++} ++ ++void ++sepgsql_index_reindex(Oid indexOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ HeapTuple tuple; ++ Oid relationOid; ++ ++ tuple = SearchSysCache1(INDEXRELID, indexOid); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for index %u", indexOid); ++ relationOid = ((Form_pg_index) GETSTRUCT(tuple))->indrelid; ++ ReleaseSysCache(tuple); ++ ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__INDEXON, true); ++ } ++#endif ++} ++ ++void ++sepgsql_sequence_get_value(Oid sequenceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(get_rel_relkind(sequenceOid) == RELKIND_SEQUENCE); ++ sepgsql_relation_common(sequenceOid, ++ SEPG_DB_SEQUENCE__GET_VALUE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_sequence_next_value(Oid sequenceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(get_rel_relkind(sequenceOid) == RELKIND_SEQUENCE); ++ sepgsql_relation_common(sequenceOid, ++ SEPG_DB_SEQUENCE__NEXT_VALUE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_sequence_set_value(Oid sequenceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(get_rel_relkind(sequenceOid) == RELKIND_SEQUENCE); ++ sepgsql_relation_common(sequenceOid, ++ SEPG_DB_SEQUENCE__SET_VALUE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_rule_create(Oid relationOid, const char *ruleName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_rule_drop(Oid relationOid, const char *ruleName, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled() && !cascade) ++ { ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_rule_comment(Oid relationOid, const char *ruleName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_trigger_create(Oid relationOid, const char *triggerName, ++ Oid constrrelid, Oid funcOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); ++ ++ /* db_table:{setattr} */ ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ /* db_procedure:{install} */ ++ // sepgsql_procedure_common... ++ } ++#endif ++} ++ ++void ++sepgsql_trigger_alter(Oid relationOid, const char *triggerName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_trigger_drop(Oid relationOid, const char *triggerName, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled() && !cascade) ++ { ++ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_trigger_comment(Oid relationOid, const char *triggerName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} ++ ++void ++sepgsql_constraint_comment(Oid relationOid, const char *constName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Assert(get_rel_relkind(relationOid) == RELKIND_RELATION); ++ sepgsql_relation_common(relationOid, ++ SEPG_DB_TABLE__SETATTR, true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/role.c b/src/backend/sepgsql/role.c +new file mode 100644 +index 0000000..3c4891c +--- /dev/null ++++ b/src/backend/sepgsql/role.c +@@ -0,0 +1,142 @@ ++/* ++ * role.c ++ * ++ * SELinux hooks related to roles ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_authid.h" ++#include "catalog/pg_seclabel.h" ++#include "miscadmin.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/lsyscache.h" ++#include "utils/syscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_role_common(Oid roleOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ HeapTuple tuple; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for role %u", roleOid); ++ ++ tsid.relid = AuthIdRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++#endif ++ ++Oid ++sepgsql_role_create(const char *roleName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ ++ nsid = sepgsql_get_default_tuple_secid(AuthIdRelationId); ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ roleName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_role_alter(Oid roleOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_role_common(roleOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_role_relabel(Oid roleOid, char *newLabel) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t tsid; ++ ++ tsid.relid = AuthIdRelationId; ++ tsid.secid = seclabelTransInput(tsid.relid, newLabel); ++ ++ /* db_tuple:{update relabelfrom} */ ++ sepgsql_role_common(roleOid, ++ SEPG_DB_TUPLE__UPDATE | ++ SEPG_DB_TUPLE__RELABELFROM, ++ true); ++ ++ /* db_tuple:{relabelto} */ ++ sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__RELABELTO, ++ GetUserNameFromId(roleOid), ++ true); ++ return tsid.secid; ++ } ++#endif ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("SE-PostgreSQL is not available"))); ++ return InvalidOid; ++} ++ ++void ++sepgsql_role_drop(Oid roleOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_role_common(roleOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_role_grant(Oid roleOid, bool is_grant, List *memberIds) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_role_common(roleOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_role_comment(Oid roleOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_role_common(roleOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/rowlv.c b/src/backend/sepgsql/rowlv.c +new file mode 100644 +index 0000000..9ace5e4 +--- /dev/null ++++ b/src/backend/sepgsql/rowlv.c +@@ -0,0 +1,367 @@ ++/* ++ * rowlv.c ++ * ++ * Row-level access control facilities ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "access/heapam.h" ++#include "access/sysattr.h" ++#include "catalog/pg_attribute.h" ++#include "catalog/pg_class.h" ++#include "catalog/pg_database.h" ++#include "catalog/pg_language.h" ++#include "catalog/pg_largeobject_metadata.h" ++#include "catalog/pg_namespace.h" ++#include "catalog/pg_proc.h" ++#include "catalog/pg_seclabel.h" ++#include "catalog/pg_type.h" ++#include "nodes/makefuncs.h" ++#include "parser/parsetree.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "storage/bufmgr.h" ++#include "utils/fmgroids.h" ++#include "utils/lsyscache.h" ++#include "utils/syscache.h" ++#include "utils/tqual.h" ++ ++static int sepgsql_rowlv_mode = SEPGSQL_ROWLV_FILTER; ++ ++int ++sepgsql_rowlv_get_mode(void) ++{ ++ return sepgsql_rowlv_mode; ++} ++ ++int ++sepgsql_rowlv_set_mode(int new_mode) ++{ ++ int old_mode = sepgsql_rowlv_mode; ++ ++ Assert(new_mode == SEPGSQL_ROWLV_FILTER || ++ new_mode == SEPGSQL_ROWLV_ABORT || ++ new_mode == SEPGSQL_ROWLV_BYPASS); ++ ++ sepgsql_rowlv_mode = new_mode; ++ ++ return old_mode; ++} ++ ++void ++sepgsql_rowlv_add_policy(PlannerInfo *root, Scan *scan) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled() && scan->scanrelid > 0) ++ { ++ RangeTblEntry *rte = planner_rt_fetch(scan->scanrelid, root); ++ Form_pg_class classForm; ++ HeapTuple tuple; ++ FuncExpr *func; ++ Var *v1; /* tableoid */ ++ Var *v2; /* row reference */ ++ Const *c3; /* required permissions */ ++ Const *c4; /* abort? or filter? */ ++ bool abort; ++ bool relhassecids; ++ Oid reltype; ++ ++ if (sepgsql_rowlv_mode == SEPGSQL_ROWLV_BYPASS) ++ return; ++ ++ Assert(IsA(rte, RangeTblEntry)); ++ if (rte->rowlvPerms == 0) ++ return; ++ ++ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(rte->relid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for relation %u", rte->relid); ++ ++ classForm = (Form_pg_class) GETSTRUCT(tuple); ++ reltype = classForm->reltype; ++ relhassecids = classForm->relhassecids; ++ ++ ReleaseSysCache(tuple); ++ ++ /* ++ * In the case when tuples have no individual security labels, ++ * sepgsql_relation_perms() checks permissions on the relation's ++ * label, as if it is security label of the whole tuples. ++ */ ++ if (!relhassecids) ++ return; ++ ++ /* 1st argument : tableoid */ ++ v1 = makeVar(scan->scanrelid, ++ TableOidAttributeNumber, ++ OIDOID, ++ -1, ++ 0); ++ ++ /* 2nd argument : whole row reference */ ++ v2 = makeVar(scan->scanrelid, ++ InvalidAttrNumber, ++ reltype, ++ -1, ++ 0); ++ ++ /* 3rd argument : required permissions */ ++ c3 = makeConst(INT4OID, ++ -1, ++ sizeof(int32), ++ Int32GetDatum(rte->rowlvPerms), ++ false, ++ true); ++ ++ /* 4th argument : abort/filter mode */ ++ abort = (sepgsql_rowlv_mode != SEPGSQL_ROWLV_FILTER); ++ c4 = makeConst(BOOLOID, ++ -1, ++ sizeof(bool), ++ BoolGetDatum(abort), ++ false, ++ true); ++ ++ /* sepgsql_tuple_perms(tableoid, , ) */ ++ func = makeFuncExpr(F_SEPGSQL_TUPLE_PERMS, ++ BOOLOID, ++ list_make4(v1, v2, c3, c4), ++ COERCE_DONTCARE); ++ ++ /* append row-level access control policy */ ++ if (abort) ++ scan->plan.qual = lappend(scan->plan.qual, func); ++ else ++ scan->plan.qual = lcons(func, scan->plan.qual); ++ } ++#endif ++} ++ ++uint32 ++sepgsql_rowlv_permissions(RangeTblEntry *rte) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ uint32 required = 0; ++ ++ if (!OidIsValid(rte->relid) || ++ get_rel_relkind(rte->relid) != RELKIND_RELATION) ++ return 0; ++ ++ if (rte->requiredPerms & ACL_SELECT) ++ required |= SEPG_DB_TUPLE__SELECT; ++ ++ if (rte->requiredPerms & ACL_UPDATE && ++ !bms_is_empty(rte->modifiedCols)) ++ required |= SEPG_DB_TUPLE__UPDATE; ++ ++ if (rte->requiredPerms & ACL_DELETE) ++ required |= SEPG_DB_TUPLE__DELETE; ++ ++ return required; ++ } ++#endif ++ return 0; ++} ++ ++void ++sepgsql_tuple_insert(Relation rel, HeapTuple tuple) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ Oid relOid = RelationGetRelid(rel); ++ ++ if (!RelationGetForm(rel)->relhassecids) ++ { ++ nsid.relid = RelationRelationId; ++ nsid.secid = GetSysCacheSecid1(RELOID, ObjectIdGetDatum(relOid)); ++ } ++ else if (OidIsValid(HeapTupleGetSecid(tuple))) ++ { ++ nsid.relid = relOid; ++ nsid.secid = HeapTupleGetSecid(tuple); ++ } ++ else ++ { ++ nsid = sepgsql_get_default_tuple_secid(relOid); ++ HeapTupleSetSecid(tuple, nsid.secid); ++ } ++ /* db_tuple:{insert} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ NULL, ++ true); ++ } ++#endif ++} ++ ++void ++sepgsql_tuple_update(Relation rel, ItemPointer otid, HeapTuple newtup) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t tsid; ++ HeapTupleData oldtup; ++ Buffer oldbuf; ++ Oid newSecId = HeapTupleGetSecid(newtup); ++ Oid oldSecId; ++ ++ /* ++ * heap_update() preserves security id of the original tuple, ++ * if no explicit security label was given, so we don't need ++ * to check anything. ++ * At this point, db_tuple:{update} is already checked. ++ */ ++ if (!OidIsValid(newSecId)) ++ return; ++ ++ /* ++ * User gave an explicit security label ++ */ ++ ItemPointerCopy(otid, &oldtup.t_self); ++ if (!heap_fetch(rel, SnapshotAny, &oldtup, &oldbuf, false, NULL)) ++ elog(ERROR, "failed to fetch old version of the tuple"); ++ ++ tsid.relid = RelationGetRelid(rel); ++ oldSecId = HeapTupleGetSecid(&oldtup); ++ ++ if (!seclabelCompareSecid(tsid.relid, oldSecId, ++ tsid.relid, newSecId)) ++ { ++ /* db_tuple:{relabelfrom} */ ++ tsid.secid = oldSecId; ++ sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__RELABELFROM, ++ NULL, ++ true); ++ ++ /* db_tuple:{relabelto} */ ++ tsid.secid = newSecId; ++ sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__RELABELTO, ++ NULL, ++ true); ++ } ++ ReleaseBuffer(oldbuf); ++ } ++#endif ++} ++ ++Datum ++sepgsql_tuple_perms(PG_FUNCTION_ARGS) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Form_pg_class relForm; ++ Form_pg_attribute attForm; ++ sepgsql_sid_t tsid; ++ HeapTupleHeader htup; ++ HeapTupleData tuple; ++ uint16 tclass; ++ uint32 required; ++ Oid tableOid; ++ bool abort; ++ bool result; ++ ++ /* function arguments */ ++ tableOid = PG_GETARG_OID(0); ++ htup = PG_GETARG_HEAPTUPLEHEADER(1); ++ required = PG_GETARG_UINT32(2); ++ abort = PG_GETARG_BOOL(3); ++ ++ /* set up pseudo tuple */ ++ tuple.t_len = HeapTupleHeaderGetDatumLength(htup); ++ ItemPointerSetInvalid(&(tuple.t_self)); ++ tuple.t_tableOid = tableOid; ++ tuple.t_data = htup; ++ ++ /* object class? */ ++ switch (tableOid) ++ { ++ case DatabaseRelationId: ++ tclass = SEPG_CLASS_DB_DATABASE; ++ break; ++ ++ case NamespaceRelationId: ++ tclass = SEPG_CLASS_DB_SCHEMA; ++ break; ++ ++ case RelationRelationId: ++ relForm = (Form_pg_class) GETSTRUCT(&tuple); ++ switch (relForm->relkind) ++ { ++ case RELKIND_RELATION: ++ tclass = SEPG_CLASS_DB_TABLE; ++ break; ++ case RELKIND_SEQUENCE: ++ tclass = SEPG_CLASS_DB_SEQUENCE; ++ break; ++ case RELKIND_VIEW: ++ tclass = SEPG_CLASS_DB_VIEW; ++ break; ++ case RELKIND_COMPOSITE_TYPE: ++ tclass = SEPG_CLASS_DB_TUPLE; ++ break; ++ default: /* index, toast */ ++ tclass = SEPG_CLASS_DB_TABLE; ++ break; ++ } ++ break; ++ ++ case AttributeRelationId: ++ attForm = (Form_pg_attribute) GETSTRUCT(&tuple); ++ switch (get_rel_relkind(attForm->attrelid)) ++ { ++ case RELKIND_RELATION: ++ tclass = SEPG_CLASS_DB_COLUMN; ++ break; ++ case RELKIND_SEQUENCE: ++ tclass = SEPG_CLASS_DB_SEQUENCE; ++ break; ++ case RELKIND_VIEW: ++ tclass = SEPG_CLASS_DB_VIEW; ++ break; ++ case RELKIND_COMPOSITE_TYPE: ++ tclass = SEPG_CLASS_DB_TUPLE; ++ break; ++ default: /* index, toast */ ++ tclass = SEPG_CLASS_DB_TABLE; ++ break; ++ } ++ break; ++ ++ case LanguageRelationId: ++ tclass = SEPG_CLASS_DB_LANGUAGE; ++ break; ++ ++ case LargeObjectMetadataRelationId: ++ tclass = SEPG_CLASS_DB_BLOB; ++ break; ++ ++ default: ++ tclass = SEPG_CLASS_DB_TUPLE; ++ break; ++ } ++ ++ /* do permission check */ ++ tsid.relid = tableOid; ++ tsid.secid = HeapTupleGetSecid(&tuple); ++ ++ result = sepgsql_client_perms(tsid, tclass, required, NULL, abort); ++ ++ PG_RETURN_BOOL(result); ++ } ++#endif ++ PG_RETURN_BOOL(true); ++} +diff --git a/src/backend/sepgsql/schema.c b/src/backend/sepgsql/schema.c +new file mode 100644 +index 0000000..24878f9 +--- /dev/null ++++ b/src/backend/sepgsql/schema.c +@@ -0,0 +1,173 @@ ++/* ++ * schema.c ++ * ++ * SELinux hooks related to schema ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_namespace.h" ++#include "catalog/pg_seclabel.h" ++#include "miscadmin.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/lsyscache.h" ++#include "utils/syscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_schema_common(Oid namespaceOid, uint32 required, bool abort) ++{ ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(NAMESPACEOID, ++ ObjectIdGetDatum(namespaceOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for namespace %u", namespaceOid); ++ ++ tsid.relid = NamespaceRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname); ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_SCHEMA, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++#endif ++ ++Oid ++sepgsql_schema_create(const char *nspName, bool is_temp) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ ++ /* compute default security context */ ++ nsid = sepgsql_get_default_schema_secid(MyDatabaseId); ++ ++ /* db_schema:{create} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_SCHEMA, ++ SEPG_DB_SCHEMA__CREATE, ++ nspName, true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_schema_alter(Oid namespaceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_schema_common(namespaceOid, ++ SEPG_DB_SCHEMA__SETATTR, ++ true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_schema_relabel(Oid namespaceOid, char *new_label) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ char *auname; ++ ++ nsid.relid = NamespaceRelationId; ++ nsid.secid = seclabelTransInput(nsid.relid, new_label); ++ ++ auname = get_namespace_name(namespaceOid); ++ ++ /* db_schema:{setattr relabelfrom} */ ++ sepgsql_schema_common(namespaceOid, ++ SEPG_DB_SCHEMA__SETATTR | ++ SEPG_DB_SCHEMA__RELABELFROM, ++ true); ++ ++ /* db_schema:{relabelto} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_SCHEMA, ++ SEPG_DB_SCHEMA__RELABELTO, ++ auname, ++ true); ++ pfree(auname); ++ ++ return nsid.secid; ++ } ++#endif ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("SE-PostgreSQL is not available"))); ++ return InvalidOid; ++} ++ ++void ++sepgsql_schema_drop(Oid namespaceOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_schema_common(namespaceOid, ++ SEPG_DB_SCHEMA__DROP, ++ true); ++ } ++#endif ++} ++ ++void ++sepgsql_schema_grant(Oid namespaceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_schema_common(namespaceOid, ++ SEPG_DB_SCHEMA__SETATTR, ++ true); ++ } ++#endif ++} ++ ++bool ++sepgsql_schema_search(Oid namespaceOid, bool abort) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ bool retval = ++ sepgsql_schema_common(namespaceOid, ++ SEPG_DB_SCHEMA__SEARCH, ++ abort); ++ return retval; ++ } ++#endif ++ return true; ++} ++ ++void ++sepgsql_schema_comment(Oid namespaceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_schema_common(namespaceOid, ++ SEPG_DB_SCHEMA__SETATTR, ++ true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/selinux.c b/src/backend/sepgsql/selinux.c +new file mode 100644 +index 0000000..ea9c9da +--- /dev/null ++++ b/src/backend/sepgsql/selinux.c +@@ -0,0 +1,670 @@ ++/* ++ * src/backend/security/sepgsql/selinux.c ++ * Routines to communicate with SELinux. ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_seclabel.h" ++#include "libpq/libpq.h" ++#include "miscadmin.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/guc.h" ++#include "utils/memutils.h" ++ ++#include ++ ++/* ++ * selinux_catalog ++ * ++ * This static translation lookup table enables to associate a certain ++ * object class/permission name with its internal code, such as ++ * SEPG_CLASS_DB_SCHEMA. ++ * ++ * SELinux requires applications to represent object class and a set of ++ * permissions in code, instead of its name, when we ask SELinux's decision. ++ * ++ * See the definition of security_compute_av(3) API in libselinux. ++ * We need to gives a code of object class, and interpret what permissions ++ * are allowed on the object class from av_decision structure. ++ * Actual values of the code depend on the security policy. In other words, ++ * we cannot know what number is assigned on a certain object class and ++ * permissions. ++ * The string_to_security_class(3) and string_to_av_perm(3) APIs takes ++ * arguments with the name of object class/permission, and returns the ++ * code for the given object class/permissions. ++ * For example, we can know what code is assigned on the "db_table" class ++ * using these functions as follows: ++ * ++ * uint16 tclass_ex = string_to_security_class("db_table"); ++ * ++ * On the other hand, we use an alternative code internally to simplify ++ * the implementation, such as SEPG_CLASS_* for object class. ++ * The following selinux_catalog is used to translate the 'internal' ++ * code and the 'external' code. ++ * ++ * It allows to lookup name of the object class or permission corresponding ++ * to a certain 'internal' code. Then, we can give the name to SELinux's ++ * API to obtain 'external' code which can be used to ask in-kernel SELinux. ++ */ ++static struct ++{ ++ const char *class_name; ++ uint16 class_code; ++ struct ++ { ++ const char *perm_name; ++ uint32 perm_code; ++ } perms[32]; ++} selinux_catalog[] = { ++ { ++ "process", SEPG_CLASS_PROCESS, ++ { ++ { "translation", SEPG_PROCESS__TRANSITION }, ++ { NULL, 0UL } ++ } ++ }, ++ { ++ "file", SEPG_CLASS_FILE, ++ { ++ { "read", SEPG_FILE__READ }, ++ { "write", SEPG_FILE__WRITE }, ++ { "create", SEPG_FILE__CREATE }, ++ { "getattr", SEPG_FILE__GETATTR }, ++ { NULL, 0UL } ++ } ++ }, ++ { ++ "dir", SEPG_CLASS_DIR, ++ { ++ { "read", SEPG_DIR__READ }, ++ { "write", SEPG_DIR__WRITE }, ++ { "create", SEPG_DIR__CREATE }, ++ { "getattr", SEPG_DIR__GETATTR }, ++ { NULL, 0UL } ++ } ++ }, ++ { ++ "lnk_file", SEPG_CLASS_LNK_FILE, ++ { ++ { "read", SEPG_LNK_FILE__READ }, ++ { "write", SEPG_LNK_FILE__WRITE }, ++ { "create", SEPG_LNK_FILE__CREATE }, ++ { "getattr", SEPG_LNK_FILE__GETATTR }, ++ { NULL, 0UL } ++ } ++ }, ++ { ++ "chr_file", SEPG_CLASS_CHR_FILE, ++ { ++ { "read", SEPG_CHR_FILE__READ }, ++ { "write", SEPG_CHR_FILE__WRITE }, ++ { "create", SEPG_CHR_FILE__CREATE }, ++ { "getattr", SEPG_CHR_FILE__GETATTR }, ++ { NULL, 0UL } ++ } ++ }, ++ { ++ "blk_file", SEPG_CLASS_BLK_FILE, ++ { ++ { "read", SEPG_BLK_FILE__READ }, ++ { "write", SEPG_BLK_FILE__WRITE }, ++ { "create", SEPG_BLK_FILE__CREATE }, ++ { "getattr", SEPG_BLK_FILE__GETATTR }, ++ { NULL, 0UL } ++ } ++ }, ++ { ++ "sock_file", SEPG_CLASS_SOCK_FILE, ++ { ++ { "read", SEPG_SOCK_FILE__READ }, ++ { "write", SEPG_SOCK_FILE__WRITE }, ++ { "create", SEPG_SOCK_FILE__CREATE }, ++ { "getattr", SEPG_SOCK_FILE__GETATTR }, ++ { NULL, 0UL } ++ } ++ }, ++ { ++ "fifo_file", SEPG_CLASS_FIFO_FILE, ++ { ++ { "read", SEPG_FIFO_FILE__READ }, ++ { "write", SEPG_FIFO_FILE__WRITE }, ++ { "create", SEPG_FIFO_FILE__CREATE }, ++ { "getattr", SEPG_FIFO_FILE__GETATTR }, ++ { NULL, 0UL } ++ } ++ }, ++ { ++ "db_database", SEPG_CLASS_DB_DATABASE, ++ { ++ { "create", SEPG_DB_DATABASE__CREATE }, ++ { "drop", SEPG_DB_DATABASE__DROP }, ++ { "getattr", SEPG_DB_DATABASE__GETATTR }, ++ { "setattr", SEPG_DB_DATABASE__SETATTR }, ++ { "relabelfrom", SEPG_DB_DATABASE__RELABELFROM }, ++ { "relabelto", SEPG_DB_DATABASE__RELABELTO }, ++ { "access", SEPG_DB_DATABASE__ACCESS }, ++ { "load_module", SEPG_DB_DATABASE__LOAD_MODULE }, ++ { NULL, 0UL }, ++ } ++ }, ++ { ++ "db_schema", SEPG_CLASS_DB_SCHEMA, ++ { ++ { "create", SEPG_DB_SCHEMA__CREATE }, ++ { "drop", SEPG_DB_SCHEMA__DROP }, ++ { "getattr", SEPG_DB_SCHEMA__GETATTR }, ++ { "setattr", SEPG_DB_SCHEMA__SETATTR }, ++ { "relabelfrom", SEPG_DB_SCHEMA__RELABELFROM }, ++ { "relabelto", SEPG_DB_SCHEMA__RELABELTO }, ++ { "search", SEPG_DB_SCHEMA__SEARCH }, ++ { "add_name", SEPG_DB_SCHEMA__ADD_NAME }, ++ { "remove_name", SEPG_DB_SCHEMA__REMOVE_NAME }, ++ { NULL, 0UL }, ++ } ++ }, ++ { ++ "db_table", SEPG_CLASS_DB_TABLE, ++ { ++ { "create", SEPG_DB_TABLE__CREATE }, ++ { "drop", SEPG_DB_TABLE__DROP }, ++ { "getattr", SEPG_DB_TABLE__GETATTR }, ++ { "setattr", SEPG_DB_TABLE__SETATTR }, ++ { "relabelfrom", SEPG_DB_TABLE__RELABELFROM }, ++ { "relabelto", SEPG_DB_TABLE__RELABELTO }, ++ { "select", SEPG_DB_TABLE__SELECT }, ++ { "update", SEPG_DB_TABLE__UPDATE }, ++ { "insert", SEPG_DB_TABLE__INSERT }, ++ { "delete", SEPG_DB_TABLE__DELETE }, ++ { "lock", SEPG_DB_TABLE__LOCK }, ++ { "indexon", SEPG_DB_TABLE__INDEXON }, ++ { NULL, 0UL }, ++ } ++ }, ++ { ++ "db_view", SEPG_CLASS_DB_VIEW, ++ { ++ { "create", SEPG_DB_VIEW__CREATE }, ++ { "drop", SEPG_DB_VIEW__DROP }, ++ { "getattr", SEPG_DB_VIEW__GETATTR }, ++ { "setattr", SEPG_DB_VIEW__SETATTR }, ++ { "relabelfrom", SEPG_DB_VIEW__RELABELFROM }, ++ { "relabelto", SEPG_DB_VIEW__RELABELTO }, ++ { "expand", SEPG_DB_VIEW__EXPAND }, ++ { NULL, 0UL }, ++ } ++ }, ++ { ++ "db_sequence", SEPG_CLASS_DB_SEQUENCE, ++ { ++ { "create", SEPG_DB_SEQUENCE__CREATE }, ++ { "drop", SEPG_DB_SEQUENCE__DROP }, ++ { "getattr", SEPG_DB_SEQUENCE__GETATTR }, ++ { "setattr", SEPG_DB_SEQUENCE__SETATTR }, ++ { "relabelfrom", SEPG_DB_SEQUENCE__RELABELFROM }, ++ { "relabelto", SEPG_DB_SEQUENCE__RELABELTO }, ++ { "get_value", SEPG_DB_SEQUENCE__GET_VALUE }, ++ { "next_value", SEPG_DB_SEQUENCE__NEXT_VALUE }, ++ { "set_value", SEPG_DB_SEQUENCE__SET_VALUE }, ++ { NULL, 0UL }, ++ } ++ }, ++ { ++ "db_procedure", SEPG_CLASS_DB_PROCEDURE, ++ { ++ { "create", SEPG_DB_PROCEDURE__CREATE }, ++ { "drop", SEPG_DB_PROCEDURE__DROP }, ++ { "getattr", SEPG_DB_PROCEDURE__GETATTR }, ++ { "setattr", SEPG_DB_PROCEDURE__SETATTR }, ++ { "relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM }, ++ { "relabelto", SEPG_DB_PROCEDURE__RELABELTO }, ++ { "execute", SEPG_DB_PROCEDURE__EXECUTE }, ++ { "entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT }, ++ { "install", SEPG_DB_PROCEDURE__INSTALL }, ++ { NULL, 0UL }, ++ } ++ }, ++ { ++ "db_column", SEPG_CLASS_DB_COLUMN, ++ { ++ { "create", SEPG_DB_COLUMN__CREATE }, ++ { "drop", SEPG_DB_COLUMN__DROP }, ++ { "getattr", SEPG_DB_COLUMN__GETATTR }, ++ { "setattr", SEPG_DB_COLUMN__SETATTR }, ++ { "relabelfrom", SEPG_DB_COLUMN__RELABELFROM }, ++ { "relabelto", SEPG_DB_COLUMN__RELABELTO }, ++ { "select", SEPG_DB_COLUMN__SELECT }, ++ { "update", SEPG_DB_COLUMN__UPDATE }, ++ { "insert", SEPG_DB_COLUMN__INSERT }, ++ { NULL, 0UL }, ++ } ++ }, ++ { ++ "db_tuple", SEPG_CLASS_DB_TUPLE, ++ { ++ { "relabelfrom", SEPG_DB_TUPLE__RELABELFROM }, ++ { "relabelto", SEPG_DB_TUPLE__RELABELTO }, ++ { "select", SEPG_DB_TUPLE__SELECT }, ++ { "update", SEPG_DB_TUPLE__UPDATE }, ++ { "insert", SEPG_DB_TUPLE__INSERT }, ++ { "delete", SEPG_DB_TUPLE__DELETE }, ++ { NULL, 0UL }, ++ } ++ }, ++ { ++ "db_blob", SEPG_CLASS_DB_BLOB, ++ { ++ { "create", SEPG_DB_BLOB__CREATE }, ++ { "drop", SEPG_DB_BLOB__DROP }, ++ { "getattr", SEPG_DB_BLOB__GETATTR }, ++ { "setattr", SEPG_DB_BLOB__SETATTR }, ++ { "relabelfrom", SEPG_DB_BLOB__RELABELFROM }, ++ { "relabelto", SEPG_DB_BLOB__RELABELTO }, ++ { "read", SEPG_DB_BLOB__READ }, ++ { "write", SEPG_DB_BLOB__WRITE }, ++ { "import", SEPG_DB_BLOB__IMPORT }, ++ { "export", SEPG_DB_BLOB__EXPORT }, ++ { NULL, 0UL }, ++ } ++ }, ++ { ++ "db_language", SEPG_CLASS_DB_LANGUAGE, ++ { ++ { "create", SEPG_DB_LANGUAGE__CREATE }, ++ { "drop", SEPG_DB_LANGUAGE__DROP }, ++ { "getattr", SEPG_DB_LANGUAGE__GETATTR }, ++ { "setattr", SEPG_DB_LANGUAGE__SETATTR }, ++ { "relabelfrom", SEPG_DB_LANGUAGE__RELABELFROM }, ++ { "relabelto", SEPG_DB_LANGUAGE__RELABELTO }, ++ { "implement", SEPG_DB_LANGUAGE__IMPLEMENTE }, ++ { "execute", SEPG_DB_LANGUAGE__EXECUTE }, ++ { NULL, 0UL }, ++ } ++ }, ++}; ++ ++/* ++ * GUC option: sepostgresql = [default|enforcing|permissive|disabled] ++ * ++ * SEPGSQL_MODE_DEFAULT : It follows system setting ++ * SEPGSQL_MODE_ENFORCING : Use enforcing mode always ++ * SEPGSQL_MODE_PERMISSIVE : Use permissive mode always ++ * SEPGSQL_MODE_INTERNAL : Internally used mode. Same as permissive mode ++ * except for silence in audit logs ++ * SEPGSQL_MODE_DISABLED : It always disables SE-PgSQL configuration ++ */ ++int sepostgresql_mode; ++ ++/* ++ * sepgsql_is_enabled ++ * ++ * If it returns true, SE-PgSQL is enabled. Otherwise, it is disabled. ++ */ ++bool ++sepgsql_is_enabled(void) ++{ ++ static int enabled = -1; ++ ++ /* ++ * If sepostgresql = disabled, it always returns FALSE ++ * independently from the system status. ++ */ ++ if (sepostgresql_mode == SEPGSQL_MODE_DISABLED) ++ return false; ++ ++ /* ++ * SE-PgSQL needs SELinux is enabled on the operating system. ++ * If it is disabled, SE-PgSQL has to be also disabled, even if ++ * 'enforcing' or 'permissive' are specified. ++ */ ++ if (enabled < 0) ++ enabled = is_selinux_enabled(); ++ ++ return enabled > 0 ? true : false; ++} ++ ++/* ++ * sepgsql_get_enforce ++ * ++ * It returns true, if SE-PgSQL performs in enforcing mode. ++ * ++ * In enforcing mode, SE-PgSQL performs as expected. It checks permissions ++ * on the required action, and it prevents them if violated. ++ * In permissive mode, SE-PgSQL also checks permissions, but it does not ++ * prevent anything, even if violated. It generates audit logs for access ++ * violations, so we can use this mode to debug security policy itself. ++ */ ++bool ++sepgsql_get_enforce(void) ++{ ++ if (sepostgresql_mode == SEPGSQL_MODE_DEFAULT) ++ { ++ if (security_getenforce() == 1) ++ return true; ++ } ++ else if (sepostgresql_mode == SEPGSQL_MODE_ENFORCING) ++ return true; ++ ++ return false; ++} ++ ++/* ++ * sepgsql_show_mode ++ * ++ * It returns the current performing mode ('selinux_support') ++ * in human readable form. ++ */ ++const char * ++sepgsql_show_mode(void) ++{ ++ if (!sepgsql_is_enabled()) ++ return "disabled"; ++ ++ if (!sepgsql_get_enforce()) ++ return "permissive"; ++ ++ return "enforcing"; ++} ++ ++/* ++ * GUC parameter to turn on/off debuging audit generation ++ */ ++bool sepgsql_debug_audit; ++ ++/* ++ * sepgsql_audit_log ++ * ++ * It generates a security audit record. In the default, it writes out ++ * audit records into standard PG's logfile. It also allows to set up ++ * external audit log receiver, such as auditd in Linux, using the ++ * sepgsql_audit_hook. ++ * ++ * SELinux can control what should be audited and should not using ++ * "auditdeny" and "auditallow" rules in the security policy. In the ++ * default, all the access violations are audited, and all the access ++ * allowed are not audited. But we can set up the security policy, so ++ * we can have exceptions. So, it is necessary to follow the suggestion ++ * come from the security policy. (av_decision.auditallow and auditdeny) ++ * ++ * Security audit is an important feature, because it enables us to check ++ * what was happen if we have a security incident. In fact, ISO/IEC15408 ++ * defines several security functionalities for audit features. ++ */ ++void ++sepgsql_audit_log(bool denied, char *scontext, char *tcontext, ++ uint16 tclass, uint32 audited, const char *audit_name) ++{ ++ StringInfoData buf; ++ const char *tclass_name; ++ const char *perm_name; ++ int level = LOG; ++ int i; ++ ++ /* ++ * translation of security contexts to human readable format, ++ * if sepgsql_mcstrans is turned on. ++ */ ++ scontext = sepgsql_mcstrans_out(scontext); ++ tcontext = sepgsql_mcstrans_out(tcontext); ++ ++ /* lookup name of the object class */ ++ tclass_name = selinux_catalog[tclass].class_name; ++ ++ /* lookup name of the permissions */ ++ initStringInfo(&buf); ++ appendStringInfo(&buf, "{"); ++ ++ for (i=0; selinux_catalog[tclass].perms[i].perm_name; i++) ++ { ++ if (audited & (1UL << i)) ++ { ++ perm_name = selinux_catalog[tclass].perms[i].perm_name; ++ appendStringInfo(&buf, " %s", perm_name); ++ } ++ } ++ appendStringInfo(&buf, " }"); ++ ++ /* ++ * Call external audit module, if loaded ++ */ ++ appendStringInfo(&buf, " scontext=%s tcontext=%s tclass=%s", ++ scontext, tcontext, tclass_name); ++ if (audit_name) ++ appendStringInfo(&buf, " name=%s", audit_name); ++ ++ if (sepgsql_debug_audit) ++ level = client_min_messages; ++ ++ ereport(level, ++ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ++ errmsg("SELinux: %s %s", ++ (denied ? "denied" : "allowed"), buf.data))); ++} ++ ++/* ++ * sepgsql_compute_avd ++ * ++ * It actually asks SELinux what permissions are allowed on a pair of ++ * the security contexts and object class. It also returns what permissions ++ * should be audited on access violation or allowed. ++ * In most cases, subject's security context (scontext) is a client, and ++ * target security context (tcontext) is a database object. ++ * ++ * The access control decision shall be set on the given av_decision. ++ * The av_decision.allowed has a bitmask of SEPG___ ++ * to suggest a set of allowed actions in this object class. ++ */ ++void ++sepgsql_compute_avd(char *scontext, char *tcontext, ++ uint16 tclass, struct av_decision *avd) ++{ ++ const char *tclass_name; ++ security_class_t tclass_ex; ++ struct av_decision avd_ex; ++ int i, deny_unknown = security_deny_unknown(); ++ ++ /* Get external code of the object class*/ ++ Assert(tclass < SEPG_CLASS_MAX); ++ ++ tclass_name = selinux_catalog[tclass].class_name; ++ tclass_ex = string_to_security_class(tclass_name); ++ ++ if (tclass_ex == 0) ++ { ++ /* ++ * If the current security policy does not support permissions ++ * corresponding to database objects, we fill up them with dummy ++ * data. ++ * If security_deny_unknown() returns positive value, undefined ++ * permissions should be denied. Otherwise, allowed ++ */ ++ avd->allowed = (deny_unknown > 0 ? 0 : ~0U); ++ avd->auditallow = 0U; ++ avd->auditdeny = ~0U; ++ avd->flags = 0; ++ ++ return; ++ } ++ ++ /* ++ * Ask SELinux what is allowed set of permissions on a pair of the ++ * security contexts and the given object class. ++ */ ++ if (security_compute_av_flags_raw(scontext, tcontext, ++ tclass_ex, 0, &avd_ex) < 0) ++ ereport(ERROR, ++ (errcode(ERRCODE_INTERNAL_ERROR), ++ errmsg("SELinux could not compute av_decision: " ++ "scontext=%s tcontext=%s tclass=%s", ++ scontext, tcontext, tclass_name))); ++ ++ /* ++ * SELinux returns its access control decision as a set of permissions ++ * represented in external code which depends on run-time environment. ++ * So, we need to translate it to the internal representation before ++ * returning results for the caller. ++ */ ++ memset(avd, 0, sizeof(struct av_decision)); ++ ++ for (i=0; selinux_catalog[tclass].perms[i].perm_name; i++) ++ { ++ access_vector_t perm_code_ex; ++ const char *perm_name = selinux_catalog[tclass].perms[i].perm_name; ++ uint32 perm_code = selinux_catalog[tclass].perms[i].perm_code; ++ ++ perm_code_ex = string_to_av_perm(tclass_ex, perm_name); ++ if (perm_code_ex == 0) ++ { ++ /* fill up undefined permissions */ ++ if (!deny_unknown) ++ avd->allowed |= perm_code; ++ avd->auditdeny |= perm_code; ++ ++ continue; ++ } ++ ++ if (avd_ex.allowed & perm_code_ex) ++ avd->allowed |= perm_code; ++ if (avd_ex.auditallow & perm_code_ex) ++ avd->auditallow |= perm_code; ++ if (avd_ex.auditdeny & perm_code_ex) ++ avd->auditdeny |= perm_code; ++ } ++ ++ return; ++} ++ ++/* ++ * sepgsql_compute_perms ++ * ++ * It makes access control decision communicating with SELinux. ++ * If SELinux does not allow required permissions on a pair of the security ++ * contexts, it raises an error or returns false. ++ * ++ * scontext : The security context of subject. In most cases, it is client. ++ * tcontext : The security context of target database object. ++ * tclass : One of the object class code (SEPG_CLASS_*) declared in the ++ * header file. ++ * required : A bitmap of the required permissions (SEPG___) ++ * declared in the header file. ++ * audit_name : A human readable name of the database object for auditing. ++ * abort : True, if caller want to raise an error on access violation. ++ */ ++bool ++sepgsql_compute_perms(char *scontext, char *tcontext, ++ uint16 tclass, uint32 required, ++ const char *audit_name, bool abort) ++{ ++ struct av_decision avd; ++ uint32 denied; ++ uint32 audited; ++ ++ sepgsql_compute_avd(scontext, tcontext, tclass, &avd); ++ ++ /* ++ * It logs a security audit record for the given request, if necessary. ++ * When SE-PgSQL performs 'internal' mode, it needs to keep silent. ++ */ ++ denied = required & ~avd.allowed; ++ if (sepgsql_debug_audit && tclass != SEPG_CLASS_DB_TUPLE) ++ audited = (denied ? (denied & ~0) : (required & ~0)); ++ else ++ audited = (denied ? (denied & avd.auditdeny) ++ : (required & avd.auditallow)); ++ ++ if (audited && sepostgresql_mode != SEPGSQL_MODE_INTERNAL) ++ { ++ sepgsql_audit_log(!!denied, scontext, tcontext, ++ tclass, audited, audit_name); ++ } ++ ++ /* ++ * If here is no policy violations, or SE-PgSQL performs in permissive ++ * mode, or the client process peforms in permissive domain, it returns ++ * normally with 'true'. ++ */ ++ if (!denied || ++ !sepgsql_get_enforce() || ++ (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) != 0) ++ return true; ++ ++ /* ++ * Otherwise, it raises an error or returns 'false', depending on the ++ * caller's indication by 'abort'. ++ */ ++ if (abort) ++ ereport(ERROR, ++ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ++ errmsg("SELinux: security policy violation"))); ++ ++ return false; ++} ++ ++/* ++ * sepgsql_compute_create ++ * ++ * It returns a default security context to be assigned on a new database ++ * object. SELinux compute it based on a combination of client, upper object ++ * which owns the new object and object class. ++ * ++ * For example, when a client (staff_u:staff_r:staff_t:s0) tries to create ++ * a new table within a schema (system_u:object_r:sepgsql_schema_t:s0), ++ * SELinux looks-up its security policy. If it has a special rule on the ++ * combination of these security contexts and object class (db_table), ++ * it returns the security context suggested by the special rule. ++ * Otherwise, it returns the security context of schema, as is. ++ * ++ * We expect the caller already applies sanity/validation checks on the ++ * given security context. ++ * ++ * scontext : The security context of subject. In most cases, it is client. ++ * tcontext : The security context of the parent database object.. ++ * tclass : One of the object class code (SEPG_CLASS_*) declared in the ++ * header file. ++ */ ++char * ++sepgsql_compute_create(char *scontext, char *tcontext, uint16 tclass) ++{ ++ security_context_t ncontext; ++ security_class_t tclass_ex; ++ const char *tclass_name; ++ char *result; ++ ++ /* Get external code of the object class*/ ++ Assert(tclass < SEPG_CLASS_MAX); ++ ++ tclass_name = selinux_catalog[tclass].class_name; ++ tclass_ex = string_to_security_class(tclass_name); ++ ++ /* ++ * Ask SELinux what is the default context for the given object class ++ * on a pair of security contexts ++ */ ++ if (security_compute_create_raw(scontext, tcontext, ++ tclass_ex, &ncontext)) ++ ereport(ERROR, ++ (errcode(ERRCODE_INTERNAL_ERROR), ++ errmsg("SELinux could not compute a new context: " ++ "scontext=%s tcontext=%s tclass=%s", ++ scontext, tcontext, tclass_name))); ++ ++ /* ++ * libselinux returns malloc()'ed string, so we need to copy it ++ * on the palloc()'ed region. ++ */ ++ PG_TRY(); ++ { ++ result = pstrdup(ncontext); ++ } ++ PG_CATCH(); ++ { ++ freecon(ncontext); ++ PG_RE_THROW(); ++ } ++ PG_END_TRY(); ++ freecon(ncontext); ++ ++ return result; ++} +diff --git a/src/backend/sepgsql/tablespace.c b/src/backend/sepgsql/tablespace.c +new file mode 100644 +index 0000000..1d3a35e +--- /dev/null ++++ b/src/backend/sepgsql/tablespace.c +@@ -0,0 +1,157 @@ ++/* ++ * tablespace.c ++ * ++ * SELinux hooks related to tablespaces ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_tablespace.h" ++#include "catalog/pg_seclabel.h" ++#include "commands/tablespace.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/syscache.h" ++#include "utils/lsyscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_tablespace_common(Oid tablespaceOid, uint32 required, bool abort) ++{ ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ bool retval; ++ const char *auname; ++ ++ tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tablespaceOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for tablespace %u", tablespaceOid); ++ ++ tsid.relid = TableSpaceRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname); ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++#endif ++ ++Oid ++sepgsql_tablespace_create(const char *tablespaceName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ ++ nsid = sepgsql_get_default_tuple_secid(TableSpaceRelationId); ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ tablespaceName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_tablespace_alter(Oid tablespaceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_tablespace_common(tablespaceOid, ++ SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_tablespace_relabel(Oid tablespaceOid, char *newLabel) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t tsid; ++ ++ tsid.relid = TableSpaceRelationId; ++ tsid.secid = seclabelTransInput(tsid.relid, newLabel); ++ ++ /* db_tuple:{update relabelfrom} */ ++ sepgsql_tablespace_common(tablespaceOid, ++ SEPG_DB_TUPLE__UPDATE | ++ SEPG_DB_TUPLE__RELABELFROM, true); ++ ++ /* db_procedure:{relabelto} */ ++ sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__RELABELTO, ++ get_tablespace_name(tablespaceOid), ++ true); ++ return tsid.secid; ++ } ++#endif ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("SE-PostgreSQL is not available"))); ++ return InvalidOid; ++} ++ ++void ++sepgsql_tablespace_drop(Oid tablespaceOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_tablespace_common(tablespaceOid, ++ SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_tablespace_grant(Oid tablespaceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_tablespace_common(tablespaceOid, ++ SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_tablespace_getattr(Oid tablespaceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_tablespace_common(tablespaceOid, ++ SEPG_DB_TUPLE__SELECT, true); ++ } ++#endif ++} ++ ++void ++sepgsql_tablespace_comment(Oid tablespaceOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_tablespace_common(tablespaceOid, ++ SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/tsearch.c b/src/backend/sepgsql/tsearch.c +new file mode 100644 +index 0000000..3d4180d +--- /dev/null ++++ b/src/backend/sepgsql/tsearch.c +@@ -0,0 +1,524 @@ ++/* ++ * tsearch.c ++ * ++ * SELinux hooks related to text searches ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_ts_config.h" ++#include "catalog/pg_ts_dict.h" ++#include "catalog/pg_ts_parser.h" ++#include "catalog/pg_ts_template.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/syscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_ts_config_common(Oid confOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ HeapTuple tuple; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(confOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for text search configuration %u", confOid); ++ ++ tsid.relid = TSConfigRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_ts_config) GETSTRUCT(tuple))->cfgname); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++static Oid ++get_ts_config_namespace(Oid confOid) ++{ ++ HeapTuple tuple; ++ Oid namespaceId = InvalidOid; ++ ++ tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(confOid)); ++ if (HeapTupleIsValid(tuple)) ++ { ++ namespaceId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgnamespace; ++ ++ ReleaseSysCache(tuple); ++ } ++ return namespaceId; ++} ++ ++bool ++sepgsql_ts_dict_common(Oid dictOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ HeapTuple tuple; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for text search dictionary %u", dictOid); ++ ++ tsid.relid = TSDictionaryRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_ts_dict) GETSTRUCT(tuple))->dictname); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++static Oid ++get_ts_dict_namespace(Oid dictOid) ++{ ++ HeapTuple tuple; ++ Oid namespaceId = InvalidOid; ++ ++ tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictOid)); ++ if (HeapTupleIsValid(tuple)) ++ { ++ namespaceId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictnamespace; ++ ++ ReleaseSysCache(tuple); ++ } ++ return namespaceId; ++} ++ ++bool ++sepgsql_ts_parser_common(Oid parseOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ HeapTuple tuple; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(parseOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for text search parser %u", parseOid); ++ ++ tsid.relid = TSParserRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_ts_parser) GETSTRUCT(tuple))->prsname); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++static Oid ++get_ts_parser_namespace(Oid parseOid) ++{ ++ HeapTuple tuple; ++ Oid namespaceId = InvalidOid; ++ ++ tuple = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(parseOid)); ++ if (HeapTupleIsValid(tuple)) ++ { ++ namespaceId = ((Form_pg_ts_parser) GETSTRUCT(tuple))->prsnamespace; ++ ++ ReleaseSysCache(tuple); ++ } ++ return namespaceId; ++} ++ ++bool ++sepgsql_ts_template_common(Oid templateOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ HeapTuple tuple; ++ const char *auname; ++ bool retval; ++ ++ tuple = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(templateOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for text search template %u", templateOid); ++ ++ tsid.relid = TSDictionaryRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ auname = NameStr(((Form_pg_ts_dict) GETSTRUCT(tuple))->dictname); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++static Oid ++get_ts_template_namespace(Oid templateOid) ++{ ++ HeapTuple tuple; ++ Oid namespaceId = InvalidOid; ++ ++ tuple = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(templateOid)); ++ if (HeapTupleIsValid(tuple)) ++ { ++ namespaceId = ((Form_pg_ts_template) GETSTRUCT(tuple))->tmplnamespace; ++ ++ ReleaseSysCache(tuple); ++ } ++ return namespaceId; ++} ++ ++#endif ++ ++Oid ++sepgsql_ts_config_create(const char *confName, Oid namespaceId) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid ++ = sepgsql_get_default_tuple_secid(TSConfigRelationId); ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_tuple:{insert} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ confName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_ts_config_alter(Oid confOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_ts_config_common(confOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_ts_config_alter_rename(Oid confOid, const char *newName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_ts_config_namespace(confOid); ++ ++ /* db_schema:{add_name remove_name} */ ++ sepgsql_schema_common(namespaceId, ++ SEPG_DB_SCHEMA__ADD_NAME | ++ SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{update} */ ++ sepgsql_ts_config_common(confOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_ts_config_drop(Oid confOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_ts_config_namespace(confOid); ++ ++ /* db_schema:{remove_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{delete} */ ++ sepgsql_ts_config_common(confOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_ts_config_comment(Oid confOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_ts_config_common(confOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_ts_dict_create(const char *dictName, Oid namespaceId) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid ++ = sepgsql_get_default_tuple_secid(TSDictionaryRelationId); ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_tuple:{insert} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ dictName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_ts_dict_alter(Oid dictOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_ts_dict_common(dictOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_ts_dict_alter_rename(Oid dictOid, const char *newName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_ts_dict_namespace(dictOid); ++ ++ /* db_schema:{add_name remove_name} */ ++ sepgsql_schema_common(namespaceId, ++ SEPG_DB_SCHEMA__ADD_NAME | ++ SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{update} */ ++ sepgsql_ts_dict_common(dictOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_ts_dict_drop(Oid dictOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_ts_dict_namespace(dictOid); ++ ++ /* db_schema:{remove_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{delete} */ ++ sepgsql_ts_dict_common(dictOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_ts_dict_comment(Oid dictOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_ts_dict_common(dictOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_ts_parser_create(const char *parseName, Oid namespaceId, ++ Oid startFunc, Oid tokenFunc, Oid endFunc, ++ Oid headlineFunc, Oid lextypeFunc) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid ++ = sepgsql_get_default_tuple_secid(TSParserRelationId); ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(startFunc)) ++ sepgsql_proc_common(startFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ if (OidIsValid(tokenFunc)) ++ sepgsql_proc_common(tokenFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ if (OidIsValid(endFunc)) ++ sepgsql_proc_common(endFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ if (OidIsValid(headlineFunc)) ++ sepgsql_proc_common(headlineFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ if (OidIsValid(lextypeFunc)) ++ sepgsql_proc_common(lextypeFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* db_tuple:{insert} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ parseName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_ts_parser_alter_rename(Oid parseOid, const char *newName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_ts_parser_namespace(parseOid); ++ ++ /* db_schema:{add_name remove_name} */ ++ sepgsql_schema_common(namespaceId, ++ SEPG_DB_SCHEMA__ADD_NAME | ++ SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{update} */ ++ sepgsql_ts_parser_common(parseOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_ts_parser_drop(Oid parseOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_ts_parser_namespace(parseOid); ++ ++ /* db_schema:{remove_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{delete} */ ++ sepgsql_ts_parser_common(parseOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_ts_parser_comment(Oid parseOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_ts_parser_common(parseOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_ts_template_create(const char *templateName, Oid namespaceId, ++ Oid initFunc, Oid lexizeFunc) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid ++ = sepgsql_get_default_tuple_secid(TSTemplateRelationId); ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(initFunc)) ++ sepgsql_proc_common(initFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ if (OidIsValid(lexizeFunc)) ++ sepgsql_proc_common(lexizeFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* db_tuple:{insert} */ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ templateName, ++ true); ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_ts_template_alter_rename(Oid templateOid, const char *newName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_ts_template_namespace(templateOid); ++ ++ /* db_schema:{add_name remove_name} */ ++ sepgsql_schema_common(namespaceId, ++ SEPG_DB_SCHEMA__ADD_NAME | ++ SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{update} */ ++ sepgsql_ts_template_common(templateOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_ts_template_drop(Oid templateOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_ts_template_namespace(templateOid); ++ ++ /* db_schema:{remove_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{delete} */ ++ sepgsql_ts_template_common(templateOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_ts_template_comment(Oid templateOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_ts_template_common(templateOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} +diff --git a/src/backend/sepgsql/type.c b/src/backend/sepgsql/type.c +new file mode 100644 +index 0000000..8cd65ae +--- /dev/null ++++ b/src/backend/sepgsql/type.c +@@ -0,0 +1,314 @@ ++/* ++ * type.c ++ * ++ * SELinux hooks related to types ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#include "postgres.h" ++ ++#include "catalog/pg_cast.h" ++#include "catalog/pg_seclabel.h" ++#include "catalog/pg_type.h" ++#include "sepgsql/hooks.h" ++#include "sepgsql/sepgsql.h" ++#include "utils/builtins.h" ++#include "utils/lsyscache.h" ++#include "utils/syscache.h" ++ ++#ifdef HAVE_SELINUX ++bool ++sepgsql_type_common(Oid typeOid, uint32 required, bool abort) ++{ ++ sepgsql_sid_t tsid; ++ char *auname; ++ bool retval; ++ ++ tsid.relid = TypeRelationId; ++ tsid.secid = GetSysCacheSecid1(TYPEOID, ++ ObjectIdGetDatum(typeOid)); ++ ++ auname = format_type_be(typeOid); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ auname, ++ abort); ++ pfree(auname); ++ ++ return retval; ++} ++ ++bool ++sepgsql_cast_common(Oid srcTypeOid, Oid dstTypeOid, ++ uint32 required, bool abort) ++{ ++ HeapTuple tuple; ++ sepgsql_sid_t tsid; ++ bool retval; ++ ++ tuple = SearchSysCache2(CASTSOURCETARGET, ++ ObjectIdGetDatum(srcTypeOid), ++ ObjectIdGetDatum(dstTypeOid)); ++ if (!HeapTupleIsValid(tuple)) ++ elog(ERROR, "cache lookup failed for cast (%u,%u)", ++ srcTypeOid, dstTypeOid); ++ ++ tsid.relid = CastRelationId; ++ tsid.secid = HeapTupleGetSecid(tuple); ++ ++ retval = sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ NULL, ++ abort); ++ ReleaseSysCache(tuple); ++ ++ return retval; ++} ++ ++static Oid ++get_type_namespace(Oid typeOid) ++{ ++ HeapTuple tuple; ++ Oid namespaceId; ++ ++ tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid)); ++ if (!HeapTupleIsValid(tuple)) ++ return InvalidOid; ++ ++ namespaceId = ((Form_pg_type) GETSTRUCT(tuple))->typnamespace; ++ ++ ReleaseSysCache(tuple); ++ ++ return namespaceId; ++} ++#endif ++ ++Oid ++sepgsql_type_create(const char *typeName, Oid replaced, ++ Oid namespaceId, char typeType, ++ Oid inputFunc, Oid outputFunc, ++ Oid recvFunc, Oid sendFunc, ++ Oid modinFunc, Oid modoutFunc, Oid analyzeFunc) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ uint32 required; ++ ++ /* db_schema:{add_name} */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_tuple:{insert or update} */ ++ if (!OidIsValid(replaced)) ++ { ++ nsid = sepgsql_get_default_tuple_secid(TypeRelationId); ++ required = SEPG_DB_TUPLE__INSERT; ++ } ++ else ++ { ++ nsid.relid = TypeRelationId; ++ nsid.secid = GetSysCacheSecid1(TYPEOID, ++ ObjectIdGetDatum(replaced)); ++ required = SEPG_DB_TUPLE__UPDATE; ++ } ++ ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ required, ++ typeName, ++ true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(inputFunc)) ++ sepgsql_proc_common(inputFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(outputFunc)) ++ sepgsql_proc_common(outputFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(recvFunc)) ++ sepgsql_proc_common(recvFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(sendFunc)) ++ sepgsql_proc_common(sendFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(modinFunc)) ++ sepgsql_proc_common(modinFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(modoutFunc)) ++ sepgsql_proc_common(modoutFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ /* db_procedure:{install} */ ++ if (OidIsValid(analyzeFunc)) ++ sepgsql_proc_common(analyzeFunc, SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_type_alter(Oid typeOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_type_common(typeOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_type_alter_rename(Oid typeOid, const char *newName) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_type_namespace(typeOid); ++ ++ /* db_schema:{add_name remove_name} */ ++ sepgsql_schema_common(namespaceId, ++ SEPG_DB_SCHEMA__ADD_NAME | ++ SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_tuple:{update} */ ++ sepgsql_type_common(typeOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_type_alter_schema(Oid typeOid, Oid newSchema) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ Oid namespaceId = get_type_namespace(typeOid); ++ ++ /* db_schema:{ remove_name } */ ++ sepgsql_schema_common(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); ++ ++ /* db_schema:{ add_name } */ ++ sepgsql_schema_common(newSchema, SEPG_DB_SCHEMA__ADD_NAME, true); ++ ++ /* db_tuple:{update} */ ++ sepgsql_type_common(typeOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_type_relabel(Oid typeOid, char *newLabel) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t tsid; ++ ++ tsid.relid = TypeRelationId; ++ tsid.secid = seclabelTransInput(tsid.relid, newLabel); ++ ++ /* db_tuple:{update relabelfrom} */ ++ sepgsql_type_common(typeOid, ++ SEPG_DB_TUPLE__UPDATE | ++ SEPG_DB_TUPLE__RELABELFROM, true); ++ ++ /* db_procedure:{relabelto} */ ++ sepgsql_client_perms(tsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__RELABELTO, ++ format_type_be(typeOid), ++ true); ++ return tsid.secid; ++ } ++#endif ++ ereport(ERROR, ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ errmsg("SE-PostgreSQL is not available"))); ++ return InvalidOid; ++} ++ ++void ++sepgsql_type_drop(Oid typeOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{delete} */ ++ sepgsql_type_common(typeOid, SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_type_comment(Oid typeOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ /* db_tuple:{update} */ ++ sepgsql_type_common(typeOid, SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} ++ ++Oid ++sepgsql_cast_create(Oid sourceTypeOid, Oid targetTypeOid, ++ char castMethod, Oid castFuncOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_sid_t nsid; ++ ++ /* db_tuple:{insert} */ ++ nsid = sepgsql_get_default_tuple_secid(CastRelationId); ++ sepgsql_client_perms(nsid, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_DB_TUPLE__INSERT, ++ NULL, ++ true); ++ /* db_procedure:{install} */ ++ if (OidIsValid(castFuncOid)) ++ sepgsql_proc_common(castFuncOid, ++ SEPG_DB_PROCEDURE__INSTALL, true); ++ ++ return nsid.secid; ++ } ++#endif ++ return InvalidOid; ++} ++ ++void ++sepgsql_cast_drop(Oid sourceTypeOid, Oid targetTypeOid, bool cascade) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_cast_common(sourceTypeOid, targetTypeOid, ++ SEPG_DB_TUPLE__DELETE, true); ++ } ++#endif ++} ++ ++void ++sepgsql_cast_comment(Oid sourceTypeOid, Oid targetTypeOid) ++{ ++#ifdef HAVE_SELINUX ++ if (sepgsql_is_enabled()) ++ { ++ sepgsql_cast_common(sourceTypeOid, targetTypeOid, ++ SEPG_DB_TUPLE__UPDATE, true); ++ } ++#endif ++} +diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c +index ca48cdd..bb0688f 100644 +--- a/src/backend/storage/large_object/inv_api.c ++++ b/src/backend/storage/large_object/inv_api.c +@@ -197,14 +197,14 @@ getbytealen(bytea *data) + * in use. + */ + Oid +-inv_create(Oid lobjId) ++inv_create(Oid lobjId, Oid securityId) + { + Oid lobjId_new; + + /* + * Create a new largeobject with empty data pages + */ +- lobjId_new = LargeObjectCreate(lobjId); ++ lobjId_new = LargeObjectCreate(lobjId, securityId); + + /* + * dependency on the owner of largeobject +diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c +index 575fa86..eb2b5e8 100644 +--- a/src/backend/tcop/fastpath.c ++++ b/src/backend/tcop/fastpath.c +@@ -26,6 +26,7 @@ + #include "libpq/pqformat.h" + #include "mb/pg_wchar.h" + #include "miscadmin.h" ++#include "sepgsql/hooks.h" + #include "tcop/fastpath.h" + #include "tcop/tcopprot.h" + #include "utils/acl.h" +@@ -347,6 +348,10 @@ HandleFunctionRequest(StringInfo msgBuf) + aclcheck_error(aclresult, ACL_KIND_PROC, + get_func_name(fid)); + ++ /* SELinux checks */ ++ sepgsql_schema_search(fip->namespace, true); ++ sepgsql_proc_execute(fid); ++ + /* + * Prepare function call info block and insert arguments. + */ +diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c +index dd00b2d..ed76bca 100644 +--- a/src/backend/tcop/postgres.c ++++ b/src/backend/tcop/postgres.c +@@ -699,6 +699,9 @@ pg_rewrite_query(Query *query) + { + /* don't rewrite utilities, just dump 'em into result list */ + querytree_list = list_make1(query); ++ ++ /* SE-PostgreSQL may rewrite the query */ ++ sepgsql_proxy_queries(querytree_list); + } + else + { +diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c +index 8ad4915..54961d8 100644 +--- a/src/backend/tcop/pquery.c ++++ b/src/backend/tcop/pquery.c +@@ -575,7 +575,7 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot) + Assert(pstmt->hasReturning); + portal->tupDesc = + ExecCleanTypeFromTL(pstmt->planTree->targetlist, +- false); ++ false, false); + } + + /* +diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c +index 8960246..e8f8ea3 100644 +--- a/src/backend/tcop/utility.c ++++ b/src/backend/tcop/utility.c +@@ -165,6 +165,7 @@ check_xact_readonly(Node *parsetree) + case T_AlterRoleSetStmt: + case T_AlterObjectSchemaStmt: + case T_AlterOwnerStmt: ++ case T_AlterSecLabelStmt: + case T_AlterSeqStmt: + case T_AlterTableStmt: + case T_RenameStmt: +@@ -696,6 +697,10 @@ standard_ProcessUtility(Node *parsetree, + ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree); + break; + ++ case T_AlterSecLabelStmt: ++ ExecAlterSecLabelStmt((AlterSecLabelStmt *) parsetree); ++ break; ++ + case T_AlterTableStmt: + { + List *stmts; +@@ -1760,6 +1765,46 @@ CreateCommandTag(Node *parsetree) + } + break; + ++ case T_AlterSecLabelStmt: ++ switch (((AlterSecLabelStmt *) parsetree)->objectType) ++ { ++ case OBJECT_DATABASE: ++ tag = "ALTER DATABASE"; ++ break; ++ case OBJECT_SCHEMA: ++ tag = "ALTER SCHEMA"; ++ break; ++ case OBJECT_TABLE: ++ case OBJECT_COLUMN: ++ tag = "ALTER TABLE"; ++ break; ++ case OBJECT_SEQUENCE: ++ tag = "ALTER SEQUENCE"; ++ break; ++ case OBJECT_VIEW: ++ tag = "ALTER VIEW"; ++ break; ++ case OBJECT_FUNCTION: ++ tag = "ALTER FUNCTION"; ++ break; ++ case OBJECT_AGGREGATE: ++ tag = "ALTER AGGREGATE"; ++ break; ++ case OBJECT_LARGEOBJECT: ++ tag = "ALTER LARGE OBJECT"; ++ break; ++ case OBJECT_TYPE: ++ tag = "ALTER TYPE"; ++ break; ++ case OBJECT_DOMAIN: ++ tag = "ALTER DOMAIN"; ++ break; ++ default: ++ tag = "???"; ++ break; ++ } ++ break; ++ + case T_AlterTableStmt: + switch (((AlterTableStmt *) parsetree)->relkind) + { +@@ -2352,6 +2397,10 @@ GetCommandLogLevel(Node *parsetree) + lev = LOGSTMT_DDL; + break; + ++ case T_AlterSecLabelStmt: ++ lev = LOGSTMT_DDL; ++ break; ++ + case T_AlterTableStmt: + lev = LOGSTMT_DDL; + break; +diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c +index 0fed35c..ca9e9d1 100644 +--- a/src/backend/tsearch/wparser.c ++++ b/src/backend/tsearch/wparser.c +@@ -59,7 +59,7 @@ tt_setup_firstcall(FuncCallContext *funcctx, Oid prsid) + (Datum) 0)); + funcctx->user_fctx = (void *) st; + +- tupdesc = CreateTemplateTupleDesc(3, false); ++ tupdesc = CreateTemplateTupleDesc(3, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "alias", +@@ -205,7 +205,7 @@ prs_setup_firstcall(FuncCallContext *funcctx, Oid prsid, text *txt) + st->cur = 0; + + funcctx->user_fctx = (void *) st; +- tupdesc = CreateTemplateTupleDesc(2, false); ++ tupdesc = CreateTemplateTupleDesc(2, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "token", +diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c +index faad11e..53e6944 100644 +--- a/src/backend/utils/adt/acl.c ++++ b/src/backend/utils/adt/acl.c +@@ -1695,7 +1695,7 @@ aclexplode(PG_FUNCTION_ARGS) + * build tupdesc for result tuples (matches out parameters in pg_proc + * entry) + */ +- tupdesc = CreateTemplateTupleDesc(4, false); ++ tupdesc = CreateTemplateTupleDesc(4, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee", +diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c +index ed81ced..f3d4b99 100644 +--- a/src/backend/utils/adt/datetime.c ++++ b/src/backend/utils/adt/datetime.c +@@ -4193,7 +4193,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS) + * build tupdesc for result tuples. This must match this function's + * pg_proc entry! + */ +- tupdesc = CreateTemplateTupleDesc(3, false); ++ tupdesc = CreateTemplateTupleDesc(3, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "abbrev", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "utc_offset", +@@ -4286,7 +4286,7 @@ pg_timezone_names(PG_FUNCTION_ARGS) + * build tupdesc for result tuples. This must match this function's + * pg_proc entry! + */ +- tupdesc = CreateTemplateTupleDesc(4, false); ++ tupdesc = CreateTemplateTupleDesc(4, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "abbrev", +diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c +index a4e0252..36d07b7 100644 +--- a/src/backend/utils/adt/dbsize.c ++++ b/src/backend/utils/adt/dbsize.c +@@ -21,6 +21,7 @@ + #include "commands/dbcommands.h" + #include "commands/tablespace.h" + #include "miscadmin.h" ++#include "sepgsql/hooks.h" + #include "storage/fd.h" + #include "utils/acl.h" + #include "utils/builtins.h" +@@ -90,6 +91,9 @@ calculate_database_size(Oid dbOid) + aclcheck_error(aclresult, ACL_KIND_DATABASE, + get_database_name(dbOid)); + ++ /* SELinux checks */ ++ sepgsql_database_getattr(dbOid); ++ + /* Shared storage in pg_global is not counted */ + + /* Include pg_default storage */ +@@ -178,6 +182,8 @@ calculate_tablespace_size(Oid tblspcOid) + aclcheck_error(aclresult, ACL_KIND_TABLESPACE, + get_tablespace_name(tblspcOid)); + } ++ /* SELinux checks */ ++ sepgsql_tablespace_getattr(tblspcOid); + + if (tblspcOid == DEFAULTTABLESPACE_OID) + snprintf(tblspcPath, MAXPGPATH, "base"); +diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c +index e074b79..0b58f1c 100644 +--- a/src/backend/utils/adt/genfile.c ++++ b/src/backend/utils/adt/genfile.c +@@ -173,7 +173,7 @@ pg_stat_file(PG_FUNCTION_ARGS) + * This record type had better match the output parameters declared for me + * in pg_proc.h. + */ +- tupdesc = CreateTemplateTupleDesc(6, false); ++ tupdesc = CreateTemplateTupleDesc(6, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, + "size", INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, +diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c +index 07e6aab..e5c8182 100644 +--- a/src/backend/utils/adt/lockfuncs.c ++++ b/src/backend/utils/adt/lockfuncs.c +@@ -85,7 +85,7 @@ pg_lock_status(PG_FUNCTION_ARGS) + + /* build tupdesc for result tuples */ + /* this had better match pg_locks view in system_views.sql */ +- tupdesc = CreateTemplateTupleDesc(14, false); ++ tupdesc = CreateTemplateTupleDesc(14, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database", +diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c +index 11342b2..0ddf907 100644 +--- a/src/backend/utils/adt/misc.c ++++ b/src/backend/utils/adt/misc.c +@@ -322,7 +322,7 @@ pg_get_keywords(PG_FUNCTION_ARGS) + funcctx = SRF_FIRSTCALL_INIT(); + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + +- tupdesc = CreateTemplateTupleDesc(3, false); ++ tupdesc = CreateTemplateTupleDesc(3, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode", +diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c +index 8379407..d44655b 100644 +--- a/src/backend/utils/adt/pgstatfuncs.c ++++ b/src/backend/utils/adt/pgstatfuncs.c +@@ -419,7 +419,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) + + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + +- tupdesc = CreateTemplateTupleDesc(11, false); ++ tupdesc = CreateTemplateTupleDesc(11, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid", OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "procpid", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "usesysid", OIDOID, -1, 0); +diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c +index 9db070d..9df61c6 100644 +--- a/src/backend/utils/adt/ri_triggers.c ++++ b/src/backend/utils/adt/ri_triggers.c +@@ -30,6 +30,7 @@ + + #include "postgres.h" + ++#include "access/sysattr.h" + #include "access/xact.h" + #include "catalog/pg_constraint.h" + #include "catalog/pg_operator.h" +@@ -39,6 +40,7 @@ + #include "parser/parse_coerce.h" + #include "parser/parse_relation.h" + #include "miscadmin.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/fmgroids.h" +@@ -2624,6 +2626,8 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) + char fkrelname[MAX_QUOTED_REL_NAME_LEN]; + char pkattname[MAX_QUOTED_NAME_LEN + 3]; + char fkattname[MAX_QUOTED_NAME_LEN + 3]; ++ Bitmapset *pkColumns = NULL; ++ Bitmapset *fkColumns = NULL; + const char *sep; + int i; + int old_work_mem; +@@ -2645,6 +2649,18 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) + + ri_FetchConstraintInfo(&riinfo, trigger, fk_rel, false); + ++ for (i = 0; i < riinfo.nkeys; i++) ++ { ++ fkColumns = bms_add_member(fkColumns, riinfo.fk_attnums[i] ++ - FirstLowInvalidHeapAttributeNumber); ++ pkColumns = bms_add_member(pkColumns, riinfo.pk_attnums[i] ++ - FirstLowInvalidHeapAttributeNumber); ++ } ++ ++ if (!sepgsql_relation_perms(RelationGetRelid(pk_rel), ++ ACL_SELECT, pkColumns, NULL, false)) ++ return false; ++ + /*---------- + * The query string built is: + * SELECT fk.keycols FROM ONLY relname fk +@@ -3204,6 +3220,7 @@ ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes, + Relation query_rel; + Oid save_userid; + int save_sec_context; ++ int save_rowlv_mode; + + /* + * The query is always run against the FK table except when this is an +@@ -3220,6 +3237,12 @@ ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes, + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(RelationGetForm(query_rel)->relowner, + save_sec_context | SECURITY_LOCAL_USERID_CHANGE); ++ /* ++ * When we scan FK relation, switch row-level access control mode ++ * into abort-on-violation mode, to keep referencial integrity. ++ */ ++ if (query_rel == fk_rel) ++ save_rowlv_mode = sepgsql_rowlv_set_mode(SEPGSQL_ROWLV_ABORT); + + /* Create the plan */ + qplan = SPI_prepare(querystr, nargs, argtypes); +@@ -3229,6 +3252,8 @@ ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes, + + /* Restore UID and security context */ + SetUserIdAndSecContext(save_userid, save_sec_context); ++ if (query_rel == fk_rel) ++ sepgsql_rowlv_set_mode(save_rowlv_mode); + + /* Save the plan if requested */ + if (cache_plan) +diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c +index c837e67..1bf4eb8 100644 +--- a/src/backend/utils/adt/tid.c ++++ b/src/backend/utils/adt/tid.c +@@ -27,6 +27,7 @@ + #include "libpq/pqformat.h" + #include "miscadmin.h" + #include "parser/parsetree.h" ++#include "sepgsql/hooks.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/rel.h" +@@ -347,6 +348,8 @@ currtid_byreloid(PG_FUNCTION_ARGS) + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_CLASS, + RelationGetRelationName(rel)); ++ /* SELinux checks */ ++ sepgsql_relation_getattr(RelationGetRelid(rel)); + + if (rel->rd_rel->relkind == RELKIND_VIEW) + return currtid_for_view(rel, tid); +@@ -377,6 +380,8 @@ currtid_byrelname(PG_FUNCTION_ARGS) + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_CLASS, + RelationGetRelationName(rel)); ++ /* SELinux checks */ ++ sepgsql_relation_getattr(RelationGetRelid(rel)); + + if (rel->rd_rel->relkind == RELKIND_VIEW) + return currtid_for_view(rel, tid); +diff --git a/src/backend/utils/adt/trigfuncs.c b/src/backend/utils/adt/trigfuncs.c +index 70246fb..b996537 100644 +--- a/src/backend/utils/adt/trigfuncs.c ++++ b/src/backend/utils/adt/trigfuncs.c +@@ -76,6 +76,10 @@ suppress_redundant_updates_trigger(PG_FUNCTION_ARGS) + !OidIsValid(HeapTupleHeaderGetOid(newheader))) + HeapTupleHeaderSetOid(newheader, HeapTupleHeaderGetOid(oldheader)); + ++ if (trigdata->tg_relation->rd_rel->relhassecids && ++ !OidIsValid(HeapTupleHeaderGetSecid(newheader))) ++ HeapTupleHeaderSetSecid(newheader, HeapTupleHeaderGetSecid(oldheader)); ++ + /* if the tuple payload is the same ... */ + if (newtuple->t_len == oldtuple->t_len && + newheader->t_hoff == oldheader->t_hoff && +diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c +index 78f08f4..4a44810 100644 +--- a/src/backend/utils/adt/tsvector_op.c ++++ b/src/backend/utils/adt/tsvector_op.c +@@ -975,7 +975,7 @@ ts_setup_firstcall(FunctionCallInfo fcinfo, FuncCallContext *funcctx, + } + Assert(stat->stackpos <= stat->maxdepth); + +- tupdesc = CreateTemplateTupleDesc(3, false); ++ tupdesc = CreateTemplateTupleDesc(3, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "ndoc", +diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c +index 88d8d8b..281acb0 100644 +--- a/src/backend/utils/cache/plancache.c ++++ b/src/backend/utils/cache/plancache.c +@@ -924,12 +924,12 @@ PlanCacheComputeResultDesc(List *stmt_list) + if (IsA(node, Query)) + { + query = (Query *) node; +- return ExecCleanTypeFromTL(query->targetList, false); ++ return ExecCleanTypeFromTL(query->targetList, false, false); + } + if (IsA(node, PlannedStmt)) + { + pstmt = (PlannedStmt *) node; +- return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false); ++ return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false, false); + } + /* other cases shouldn't happen, but return NULL */ + break; +@@ -940,13 +940,13 @@ PlanCacheComputeResultDesc(List *stmt_list) + { + query = (Query *) node; + Assert(query->returningList); +- return ExecCleanTypeFromTL(query->returningList, false); ++ return ExecCleanTypeFromTL(query->returningList, false, false); + } + if (IsA(node, PlannedStmt)) + { + pstmt = (PlannedStmt *) node; + Assert(pstmt->hasReturning); +- return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false); ++ return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false, false); + } + /* other cases shouldn't happen, but return NULL */ + break; +diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c +index 073d25a..249b4c0 100644 +--- a/src/backend/utils/cache/relcache.c ++++ b/src/backend/utils/cache/relcache.c +@@ -213,7 +213,7 @@ static void write_relcache_init_file(bool shared); + static void write_item(const void *data, Size len, FILE *fp); + + static void formrdesc(const char *relationName, Oid relationReltype, +- bool isshared, bool hasoids, ++ bool isshared, bool hasoids, bool hassecids, + int natts, const FormData_pg_attribute *attrs); + + static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK); +@@ -352,7 +352,8 @@ AllocateRelationDesc(Form_pg_class relp) + + /* and allocate attribute tuple form storage */ + relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts, +- relationForm->relhasoids); ++ relationForm->relhasoids, ++ relationForm->relhassecids); + /* which we mark as a reference-counted tupdesc */ + relation->rd_att->tdrefcount = 1; + +@@ -434,6 +435,7 @@ RelationBuildTupleDesc(Relation relation) + relation->rd_att->tdtypeid = relation->rd_rel->reltype; + relation->rd_att->tdtypmod = -1; /* unnecessary, but... */ + relation->rd_att->tdhasoid = relation->rd_rel->relhasoids; ++ relation->rd_att->tdhassecid = relation->rd_rel->relhassecids; + + constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext, + sizeof(TupleConstr)); +@@ -1392,7 +1394,7 @@ LookupOpclassInfo(Oid operatorClassOid, + */ + static void + formrdesc(const char *relationName, Oid relationReltype, +- bool isshared, bool hasoids, ++ bool isshared, bool hasoids, bool hassecids, + int natts, const FormData_pg_attribute *attrs) + { + Relation relation; +@@ -1455,6 +1457,7 @@ formrdesc(const char *relationName, Oid relationReltype, + relation->rd_rel->reltuples = 1; + relation->rd_rel->relkind = RELKIND_RELATION; + relation->rd_rel->relhasoids = hasoids; ++ relation->rd_rel->relhassecids = hassecids; + relation->rd_rel->relnatts = (int16) natts; + + /* +@@ -1464,7 +1467,7 @@ formrdesc(const char *relationName, Oid relationReltype, + * because it will never be replaced. The input values must be correctly + * defined by macros in src/include/catalog/ headers. + */ +- relation->rd_att = CreateTemplateTupleDesc(natts, hasoids); ++ relation->rd_att = CreateTemplateTupleDesc(natts, hasoids, hassecids); + relation->rd_att->tdrefcount = 1; /* mark as refcounted */ + + relation->rd_att->tdtypeid = relationReltype; +@@ -2527,6 +2530,7 @@ RelationBuildLocalRelation(const char *relname, + + rel->rd_rel->relkind = RELKIND_UNCATALOGED; + rel->rd_rel->relhasoids = rel->rd_att->tdhasoid; ++ rel->rd_rel->relhassecids = rel->rd_att->tdhassecid; + rel->rd_rel->relnatts = natts; + rel->rd_rel->reltype = InvalidOid; + /* needed when bootstrapping: */ +@@ -2767,7 +2771,7 @@ RelationCacheInitializePhase2(void) + if (!load_relcache_init_file(true)) + { + formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true, +- true, Natts_pg_database, Desc_pg_database); ++ true, true, Natts_pg_database, Desc_pg_database); + + #define NUM_CRITICAL_SHARED_RELS 1 /* fix if you change list above */ + } +@@ -2818,13 +2822,13 @@ RelationCacheInitializePhase3(void) + needNewCacheFile = true; + + formrdesc("pg_class", RelationRelation_Rowtype_Id, false, +- true, Natts_pg_class, Desc_pg_class); ++ true, true, Natts_pg_class, Desc_pg_class); + formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false, +- false, Natts_pg_attribute, Desc_pg_attribute); ++ false, true, Natts_pg_attribute, Desc_pg_attribute); + formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false, +- true, Natts_pg_proc, Desc_pg_proc); ++ true, true, Natts_pg_proc, Desc_pg_proc); + formrdesc("pg_type", TypeRelation_Rowtype_Id, false, +- true, Natts_pg_type, Desc_pg_type); ++ true, true, Natts_pg_type, Desc_pg_type); + + #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */ + } +@@ -2969,6 +2973,7 @@ RelationCacheInitializePhase3(void) + Assert(relation->rd_att->tdtypeid == relp->reltype); + Assert(relation->rd_att->tdtypmod == -1); + Assert(relation->rd_att->tdhasoid == relp->relhasoids); ++ Assert(relation->rd_att->tdhassecid == relp->relhassecids); + + ReleaseSysCache(htup); + +@@ -3079,7 +3084,7 @@ load_critical_index(Oid indexoid, Oid heapoid) + */ + static TupleDesc + BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs, +- bool hasoids) ++ bool hasoids, bool hassecids) + { + TupleDesc result; + MemoryContext oldcxt; +@@ -3087,7 +3092,7 @@ BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs, + + oldcxt = MemoryContextSwitchTo(CacheMemoryContext); + +- result = CreateTemplateTupleDesc(natts, hasoids); ++ result = CreateTemplateTupleDesc(natts, hasoids, hassecids); + result->tdtypeid = RECORDOID; /* not right, but we don't care */ + result->tdtypmod = -1; + +@@ -3117,7 +3122,7 @@ GetPgClassDescriptor(void) + if (pgclassdesc == NULL) + pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class, + Desc_pg_class, +- true); ++ true, true); + + return pgclassdesc; + } +@@ -3131,7 +3136,7 @@ GetPgIndexDescriptor(void) + if (pgindexdesc == NULL) + pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index, + Desc_pg_index, +- false); ++ false, false); + + return pgindexdesc; + } +@@ -3947,7 +3952,8 @@ load_relcache_init_file(bool shared) + + /* initialize attribute tuple forms */ + rel->rd_att = CreateTemplateTupleDesc(relform->relnatts, +- relform->relhasoids); ++ relform->relhasoids, ++ relform->relhassecids); + rel->rd_att->tdrefcount = 1; /* mark as refcounted */ + + rel->rd_att->tdtypeid = relform->reltype; +diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c +index 61b06ac..b08654b 100644 +--- a/src/backend/utils/cache/syscache.c ++++ b/src/backend/utils/cache/syscache.c +@@ -895,6 +895,30 @@ GetSysCacheOid(int cacheId, + return result; + } + ++/* ++ * GetSysCacheSecid ++ * ++ * A convenience routine that does SearchSysCache and returns the ++ * security-id of the found tuple, or InvalidOid if no tuple could ++ * be found. No lock is retained on the syscache entry. ++ */ ++Oid ++GetSysCacheSecid(int cacheId, ++ Datum key1, ++ Datum key2, ++ Datum key3, ++ Datum key4) ++{ ++ HeapTuple tuple; ++ Oid result; ++ ++ tuple = SearchSysCache(cacheId, key1, key2, key3, key4); ++ if (!HeapTupleIsValid(tuple)) ++ return InvalidOid; ++ result = HeapTupleGetSecid(tuple); ++ ReleaseSysCache(tuple); ++ return result; ++} + + /* + * SearchSysCacheAttName +diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c +index c3c0440..fb5b762 100644 +--- a/src/backend/utils/fmgr/fmgr.c ++++ b/src/backend/utils/fmgr/fmgr.c +@@ -24,6 +24,7 @@ + #include "miscadmin.h" + #include "nodes/nodeFuncs.h" + #include "pgstat.h" ++#include "sepgsql/hooks.h" + #include "utils/builtins.h" + #include "utils/fmgrtab.h" + #include "utils/guc.h" +@@ -190,6 +191,7 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt, + finfo->fn_extra = NULL; + finfo->fn_mcxt = mcxt; + finfo->fn_expr = NULL; /* caller may set this later */ ++ finfo->fn_seclabel = NULL; + + if ((fbp = fmgr_isbuiltin(functionId)) != NULL) + { +@@ -228,15 +230,22 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt, + * ability to set the track_functions GUC as a local GUC parameter of an + * interesting function and have the right things happen. + */ +- if (!ignore_security && +- (procedureStruct->prosecdef || +- !heap_attisnull(procedureTuple, Anum_pg_proc_proconfig))) ++ if (!ignore_security) + { +- finfo->fn_addr = fmgr_security_definer; +- finfo->fn_stats = TRACK_FUNC_ALL; /* ie, never track */ +- finfo->fn_oid = functionId; +- ReleaseSysCache(procedureTuple); +- return; ++ char *seclabel ++ = sepgsql_proc_domtrans(procedureTuple, mcxt); ++ ++ if (procedureStruct->prosecdef || ++ !heap_attisnull(procedureTuple, Anum_pg_proc_proconfig) || ++ seclabel != NULL) ++ { ++ finfo->fn_addr = fmgr_security_definer; ++ finfo->fn_stats = TRACK_FUNC_ALL; /* ie, never track */ ++ finfo->fn_oid = functionId; ++ finfo->fn_seclabel = seclabel; ++ ReleaseSysCache(procedureTuple); ++ return; ++ } + } + + switch (procedureStruct->prolang) +@@ -877,6 +886,7 @@ fmgr_security_definer(PG_FUNCTION_ARGS) + FmgrInfo *save_flinfo; + Oid save_userid; + int save_sec_context; ++ char *save_seclabel; + volatile int save_nestlevel; + PgStat_FunctionCallUsage fcusage; + +@@ -939,6 +949,10 @@ fmgr_security_definer(PG_FUNCTION_ARGS) + PGC_S_SESSION, + GUC_ACTION_SAVE); + } ++ if (fcinfo->flinfo->fn_seclabel) ++ save_seclabel = sepgsql_set_client_label(fcinfo->flinfo->fn_seclabel); ++ else ++ save_seclabel = NULL; + + /* + * We don't need to restore GUC or userid settings on error, because the +@@ -978,6 +992,8 @@ fmgr_security_definer(PG_FUNCTION_ARGS) + AtEOXact_GUC(true, save_nestlevel); + if (OidIsValid(fcache->userid)) + SetUserIdAndSecContext(save_userid, save_sec_context); ++ if (fcinfo->flinfo->fn_seclabel) ++ sepgsql_set_client_label(save_seclabel); + + return result; + } +diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c +index 382008c..e6eba47 100644 +--- a/src/backend/utils/fmgr/funcapi.c ++++ b/src/backend/utils/fmgr/funcapi.c +@@ -1105,7 +1105,7 @@ build_function_result_tupdesc_d(Datum proallargtypes, + if (numoutargs < 2) + return NULL; + +- desc = CreateTemplateTupleDesc(numoutargs, false); ++ desc = CreateTemplateTupleDesc(numoutargs, false, false); + for (i = 0; i < numoutargs; i++) + { + TupleDescInitEntry(desc, i + 1, +@@ -1220,7 +1220,7 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases) + /* OK, get the column alias */ + attname = strVal(linitial(colaliases)); + +- tupdesc = CreateTemplateTupleDesc(1, false); ++ tupdesc = CreateTemplateTupleDesc(1, false, false); + TupleDescInitEntry(tupdesc, + (AttrNumber) 1, + attname, +diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c +index ed99b91..2bc5127 100644 +--- a/src/backend/utils/init/postinit.c ++++ b/src/backend/utils/init/postinit.c +@@ -37,6 +37,7 @@ + #include "postmaster/autovacuum.h" + #include "postmaster/postmaster.h" + #include "replication/walsender.h" ++#include "sepgsql/hooks.h" + #include "storage/bufmgr.h" + #include "storage/fd.h" + #include "storage/ipc.h" +@@ -304,6 +305,9 @@ CheckMyDatabase(const char *name, bool am_superuser) + errmsg("permission denied for database \"%s\"", name), + errdetail("User does not have CONNECT privilege."))); + ++ /* SELinux checks */ ++ sepgsql_database_connect(MyDatabaseId); ++ + /* + * Check connection limit for this database. + * +@@ -735,6 +739,9 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, + /* set up ACL framework (so CheckMyDatabase can check permissions) */ + initialize_acl(); + ++ /* set up enhanced security feature */ ++ sepgsql_initialize(); ++ + /* Process pg_db_role_setting options */ + process_settings(MyDatabaseId, GetSessionUserId()); + +diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c +index f198c9c..8a8d45d 100644 +--- a/src/backend/utils/misc/guc.c ++++ b/src/backend/utils/misc/guc.c +@@ -31,6 +31,7 @@ + #include "access/twophase.h" + #include "access/xact.h" + #include "catalog/namespace.h" ++#include "catalog/pg_seclabel.h" + #include "commands/async.h" + #include "commands/prepare.h" + #include "commands/vacuum.h" +@@ -56,6 +57,7 @@ + #include "postmaster/syslogger.h" + #include "postmaster/walwriter.h" + #include "replication/walsender.h" ++#include "sepgsql/sepgsql.h" + #include "storage/bufmgr.h" + #include "storage/fd.h" + #include "tcop/tcopprot.h" +@@ -337,6 +339,18 @@ static const struct config_enum_entry constraint_exclusion_options[] = { + {NULL, 0, false} + }; + ++#ifdef HAVE_SELINUX ++static const struct config_enum_entry sepostgresql_options[] = { ++ {"default", SEPGSQL_MODE_DEFAULT, false}, ++ {"enforcing", SEPGSQL_MODE_ENFORCING, false}, ++ {"permissive", SEPGSQL_MODE_PERMISSIVE, false}, ++ {"disabled", SEPGSQL_MODE_DISABLED, false}, ++ {"on", SEPGSQL_MODE_DEFAULT, true}, ++ {"off", SEPGSQL_MODE_DISABLED, true}, ++ {NULL, 0, false}, ++}; ++#endif ++ + /* + * Options for enum values stored in other modules + */ +@@ -365,6 +379,7 @@ bool log_btree_build_stats = false; + + bool check_function_bodies = true; + bool default_with_oids = false; ++bool default_with_secids = true; + bool SQL_inheritance = true; + + bool Password_encryption = true; +@@ -1085,6 +1100,14 @@ static struct config_bool ConfigureNamesBool[] = + false, NULL, NULL + }, + { ++ {"default_with_secids", PGC_USERSET, CONN_AUTH_SETTINGS, ++ gettext_noop("Create new tables with security-ids by default."), ++ NULL ++ }, ++ &default_with_secids, ++ true, NULL, NULL ++ }, ++ { + {"logging_collector", PGC_POSTMASTER, LOGGING_WHERE, + gettext_noop("Start a subprocess to capture stderr output and/or csvlogs into log files."), + NULL +@@ -1254,6 +1277,36 @@ static struct config_bool ConfigureNamesBool[] = + false, NULL, NULL + }, + ++ { ++ {"ignore_security_label_input", PGC_USERSET, CONN_AUTH_SECURITY, ++ gettext_noop("Disables to assign used provided security label"), ++ NULL, ++ GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE ++ }, ++ &ignore_security_label_input, ++ false, NULL, NULL ++ }, ++#ifdef HAVE_SELINUX ++ { ++ {"sepostgresql_mcstrans", PGC_USERSET, CONN_AUTH_SECURITY, ++ gettext_noop("Enables to show security context in human-readable form"), ++ NULL, ++ GUC_NOT_IN_SAMPLE ++ }, ++ &sepgsql_mcstrans, ++ true, NULL, NULL ++ }, ++ { ++ {"sepostgresql_debug_audit", PGC_USERSET, CONN_AUTH_SECURITY, ++ gettext_noop("Enables to show audit logs for debugging"), ++ NULL, ++ GUC_NOT_IN_SAMPLE ++ }, ++ &sepgsql_debug_audit, ++ false, NULL, NULL ++ }, ++#endif ++ + /* End-of-list marker */ + { + {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL +@@ -2795,7 +2848,16 @@ static struct config_enum ConfigureNamesEnum[] = + &xmloption, + XMLOPTION_CONTENT, xmloption_options, NULL, NULL + }, +- ++#ifdef HAVE_SELINUX ++ { ++ {"sepostgresql", PGC_POSTMASTER, CONN_AUTH_SECURITY, ++ gettext_noop("Enables to set SE-PostgreSQL's mode"), ++ NULL ++ }, ++ &sepostgresql_mode, ++ SEPGSQL_MODE_DEFAULT, sepostgresql_options, NULL, sepgsql_show_mode ++ }, ++#endif + + /* End-of-list marker */ + { +@@ -6070,7 +6132,7 @@ GetPGVariableResultDesc(const char *name) + if (guc_name_compare(name, "all") == 0) + { + /* need a tuple descriptor representing three TEXT columns */ +- tupdesc = CreateTemplateTupleDesc(3, false); ++ tupdesc = CreateTemplateTupleDesc(3, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting", +@@ -6086,7 +6148,7 @@ GetPGVariableResultDesc(const char *name) + (void) GetConfigOptionByName(name, &varname); + + /* need a tuple descriptor representing a single TEXT column */ +- tupdesc = CreateTemplateTupleDesc(1, false); ++ tupdesc = CreateTemplateTupleDesc(1, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, + TEXTOID, -1, 0); + } +@@ -6109,7 +6171,7 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest) + value = GetConfigOptionByName(name, &varname); + + /* need a tuple descriptor representing a single TEXT column */ +- tupdesc = CreateTemplateTupleDesc(1, false); ++ tupdesc = CreateTemplateTupleDesc(1, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, + TEXTOID, -1, 0); + +@@ -6136,7 +6198,7 @@ ShowAllGUCConfig(DestReceiver *dest) + bool isnull[3] = {false, false, false}; + + /* need a tuple descriptor representing three TEXT columns */ +- tupdesc = CreateTemplateTupleDesc(3, false); ++ tupdesc = CreateTemplateTupleDesc(3, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting", +@@ -6531,7 +6593,7 @@ show_all_settings(PG_FUNCTION_ARGS) + * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns + * of the appropriate types + */ +- tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS, false); ++ tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting", +diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample +index 02f1df0..f8a27c8 100644 +--- a/src/backend/utils/misc/postgresql.conf.sample ++++ b/src/backend/utils/misc/postgresql.conf.sample +@@ -76,6 +76,8 @@ + + # - Security and Authentication - + ++#sepostgresql = disabled # default|enforcing|permissive|disabled ++ + #authentication_timeout = 1min # 1s-600s + #ssl = off # (change requires restart) + #ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers +diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c +index ac62d45..f05a094 100644 +--- a/src/backend/utils/mmgr/portalmem.c ++++ b/src/backend/utils/mmgr/portalmem.c +@@ -894,7 +894,7 @@ pg_cursor(PG_FUNCTION_ARGS) + * build tupdesc for result tuples. This must match the definition of the + * pg_cursors view in system_views.sql + */ +- tupdesc = CreateTemplateTupleDesc(6, false); ++ tupdesc = CreateTemplateTupleDesc(6, false, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement", +diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c +index f40ad87..497bdf0 100644 +--- a/src/bin/initdb/initdb.c ++++ b/src/bin/initdb/initdb.c +@@ -87,6 +87,7 @@ static bool debug = false; + static bool noclean = false; + static bool show_setting = false; + static char *xlog_dir = ""; ++static bool enable_selinux = false; + + + /* internal vars */ +@@ -1163,6 +1164,13 @@ setup_config(void) + "#default_text_search_config = 'pg_catalog.simple'", + repltok); + ++ if (enable_selinux) ++ { ++ strcpy(repltok, "sepostgresql = default"); ++ conflines = replace_token(conflines, ++ "#sepostgresql = disabled", repltok); ++ } ++ + snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); + + writefile(path, conflines); +@@ -2394,6 +2402,7 @@ usage(const char *progname) + printf(_(" -U, --username=NAME database superuser name\n")); + printf(_(" -W, --pwprompt prompt for a password for the new superuser\n")); + printf(_(" -X, --xlogdir=XLOGDIR location for the transaction log directory\n")); ++ printf(_(" --enable-selinux enables SELinux support\n")); + printf(_("\nLess commonly used options:\n")); + printf(_(" -d, --debug generate lots of debugging output\n")); + printf(_(" -L DIRECTORY where to find the input files\n")); +@@ -2436,6 +2445,7 @@ main(int argc, char *argv[]) + {"show", no_argument, NULL, 's'}, + {"noclean", no_argument, NULL, 'n'}, + {"xlogdir", required_argument, NULL, 'X'}, ++ {"enable-selinux", no_argument, NULL, 10}, + {NULL, 0, NULL, 0} + }; + +@@ -2545,6 +2555,9 @@ main(int argc, char *argv[]) + case 9: + pwfilename = xstrdup(optarg); + break; ++ case 10: ++ enable_selinux = true; ++ break; + case 's': + show_setting = true; + break; +diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h +index 14fe652..40b7b40 100644 +--- a/src/bin/pg_dump/pg_backup.h ++++ b/src/bin/pg_dump/pg_backup.h +@@ -103,6 +103,7 @@ typedef struct _restoreOptions + * restore */ + int use_setsessauth;/* Use SET SESSION AUTHORIZATION commands + * instead of OWNER TO */ ++ int noSecLabel; /* Don't try to restore security labels */ + char *superuser; /* Username to use as superuser */ + char *use_role; /* Issue SET ROLE to this */ + int dataOnly; +@@ -167,7 +168,7 @@ extern void ArchiveEntry(Archive *AHX, + CatalogId catalogId, DumpId dumpId, + const char *tag, + const char *namespace, const char *tablespace, +- const char *owner, bool withOids, ++ const char *owner, bool withOids, bool withSecids, + const char *desc, teSection section, + const char *defn, + const char *dropStmt, const char *copyStmt, +diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c +index d83f4dc..cc0cbae 100644 +--- a/src/bin/pg_dump/pg_backup_archiver.c ++++ b/src/bin/pg_dump/pg_backup_archiver.c +@@ -540,6 +540,8 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, + } + else + { ++ bool need_reset = false; ++ + _disableTriggersIfNecessary(AH, te, ropt); + + /* Select owner and schema as necessary */ +@@ -575,6 +577,16 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, + "ONLY " : ""), + fmtId(te->tag)); + } ++ /* ++ * If data section has security_label, but pg_restore works ++ * with --no-security-label, we set server flag to ignore ++ * the security label input. ++ */ ++ if (ropt->noSecLabel && te->withSecids) ++ { ++ ahprintf(AH, "SET ignore_security_label_input = on;\n\n"); ++ need_reset = true; ++ } + + /* + * If we have a copy statement, use it. As of V1.3, these +@@ -595,6 +607,9 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, + + AH->writingCopyData = false; + ++ if (need_reset) ++ ahprintf(AH, "RESET ignore_security_label_input;\n\n"); ++ + /* close out the transaction started above */ + if (is_parallel && te->created) + CommitTransaction(AH); +@@ -712,7 +727,7 @@ ArchiveEntry(Archive *AHX, + const char *tag, + const char *namespace, + const char *tablespace, +- const char *owner, bool withOids, ++ const char *owner, bool withOids, bool withSecids, + const char *desc, teSection section, + const char *defn, + const char *dropStmt, const char *copyStmt, +@@ -744,6 +759,7 @@ ArchiveEntry(Archive *AHX, + newToc->tablespace = tablespace ? strdup(tablespace) : NULL; + newToc->owner = strdup(owner); + newToc->withOids = withOids; ++ newToc->withSecids = withSecids; + newToc->desc = strdup(desc); + newToc->defn = strdup(defn); + newToc->dropStmt = strdup(dropStmt); +@@ -2027,6 +2043,7 @@ WriteToc(ArchiveHandle *AH) + WriteStr(AH, te->tablespace); + WriteStr(AH, te->owner); + WriteStr(AH, te->withOids ? "true" : "false"); ++ WriteStr(AH, te->withSecids ? "true" : "false"); + + /* Dump list of dependencies */ + for (i = 0; i < te->nDeps; i++) +@@ -2138,6 +2155,16 @@ ReadToc(ArchiveHandle *AH) + else + te->withOids = true; + ++ if (AH->version >= K_VERS_1_13) ++ { ++ if (strcmp(ReadStr(AH), "true") == 0) ++ te->withSecids = true; ++ else ++ te->withSecids = false; ++ } ++ else ++ te->withSecids = false; ++ + /* Read TOC entry dependencies */ + if (AH->version >= K_VERS_1_5) + { +@@ -2256,6 +2283,9 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls) + if ((!include_acls || ropt->aclsSkip) && _tocEntryIsACL(te)) + return 0; + ++ if (ropt->noSecLabel && strcmp(te->desc, "LABEL") == 0) ++ return 0; ++ + /* Ignore DATABASE entry unless we should create it */ + if (!ropt->create && strcmp(te->desc, "DATABASE") == 0) + return 0; +@@ -2322,6 +2352,8 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls) + (strcmp(te->desc, "ACL") == 0 && + strncmp(te->tag, "LARGE OBJECT ", 13) == 0) || + (strcmp(te->desc, "COMMENT") == 0 && ++ strncmp(te->tag, "LARGE OBJECT ", 13) == 0) || ++ (strcmp(te->desc, "LABEL") == 0 && + strncmp(te->tag, "LARGE OBJECT ", 13) == 0)) + res = res & REQ_DATA; + else +@@ -2473,6 +2505,36 @@ _doSetWithOids(ArchiveHandle *AH, const bool withOids) + destroyPQExpBuffer(cmd); + } + ++/* ++ * Issue a SET default_with_secids command. Caller is responsible ++ * for updating state if appropriate. ++ */ ++static void ++_doSetWithSecids(ArchiveHandle *AH, const bool withSecids) ++{ ++ PQExpBuffer cmd = createPQExpBuffer(); ++ ++ appendPQExpBuffer(cmd, "SET default_with_secids = %s;", withSecids ? ++ "true" : "false"); ++ ++ if (RestoringToDB(AH)) ++ { ++ PGresult *res; ++ ++ res = PQexec(AH->connection, cmd->data); ++ ++ if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) ++ warn_or_die_horribly(AH, modulename, ++ "could not set default_with_secids: %s", ++ PQerrorMessage(AH->connection)); ++ ++ PQclear(res); ++ } ++ else ++ ahprintf(AH, "%s\n\n", cmd->data); ++ ++ destroyPQExpBuffer(cmd); ++} + + /* + * Issue the commands to connect to the specified database. +@@ -2571,6 +2633,18 @@ _setWithOids(ArchiveHandle *AH, TocEntry *te) + } + } + ++/* ++ * Set the proper default_with_secids value for the table. ++ */ ++static void ++_setWithSecids(ArchiveHandle *AH, TocEntry *te) ++{ ++ if (AH->currWithSecids != te->withSecids) ++ { ++ _doSetWithSecids(AH, te->withSecids); ++ AH->currWithSecids = te->withSecids; ++ } ++} + + /* + * Issue the commands to select the specified schema as the current schema +@@ -2808,9 +2882,12 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat + _selectOutputSchema(AH, te->namespace); + _selectTablespace(AH, te->tablespace); + +- /* Set up OID mode too */ ++ /* Set up OID/SECID mode too */ + if (strcmp(te->desc, "TABLE") == 0) ++ { + _setWithOids(AH, te); ++ _setWithSecids(AH, te); ++ } + + /* Emit header comment for item */ + if (!AH->noTocComments) +diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h +index 2e944c1..67f62ac 100644 +--- a/src/bin/pg_dump/pg_backup_archiver.h ++++ b/src/bin/pg_dump/pg_backup_archiver.h +@@ -63,7 +63,7 @@ typedef z_stream *z_streamp; + + /* Current archive version number (the format we can output) */ + #define K_VERS_MAJOR 1 +-#define K_VERS_MINOR 12 ++#define K_VERS_MINOR 13 + #define K_VERS_REV 0 + + /* Data block types */ +@@ -89,9 +89,10 @@ typedef z_stream *z_streamp; + * indicator */ + #define K_VERS_1_12 (( (1 * 256 + 12) * 256 + 0) * 256 + 0) /* add separate BLOB + * entries */ +- ++#define K_VERS_1_13 (( (1 * 256 + 13) * 256 + 0) * 256 + 0) /* add security label ++ * support */ + /* Newest format we can read */ +-#define K_VERS_MAX (( (1 * 256 + 12) * 256 + 255) * 256 + 0) ++#define K_VERS_MAX (( (1 * 256 + 13) * 256 + 255) * 256 + 0) + + + /* Flags to indicate disposition of offsets stored in files */ +@@ -278,6 +279,7 @@ typedef struct _archiveHandle + char *currSchema; /* current schema, or NULL */ + char *currTablespace; /* current tablespace, or NULL */ + bool currWithOids; /* current default_with_oids setting */ ++ bool currWithSecids; /* current default_with_secids setting */ + + void *lo_buf; + size_t lo_buf_used; +@@ -305,6 +307,7 @@ typedef struct _tocEntry + * means use database default */ + char *owner; + bool withOids; /* Used only by "TABLE" tags */ ++ bool withSecids; /* Used only by "TABLE" tags */ + char *desc; + char *defn; + char *dropStmt; +diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c +index 2431d71..e7ef296 100644 +--- a/src/bin/pg_dump/pg_dump.c ++++ b/src/bin/pg_dump/pg_dump.c +@@ -125,7 +125,7 @@ static int binary_upgrade = 0; + static int disable_dollar_quoting = 0; + static int dump_inserts = 0; + static int column_inserts = 0; +- ++static int security_label = 0; + + static void help(const char *progname); + static void expand_schema_name_patterns(SimpleStringList *patterns, +@@ -183,6 +183,11 @@ static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId, + const char *tag, const char *nspname, const char *owner, + const char *acls); + ++static void dumpSecLabel(Archive *fout, DumpId objDumpId, ++ const char *target, ++ const char *namespace, ++ const char *seclabel); ++ + static void getDependencies(void); + static void getDomainConstraints(TypeInfo *tyinfo); + static void getTableData(TableInfo *tblinfo, int numTables, bool oids); +@@ -215,7 +220,7 @@ static bool binary_upgrade_set_type_oids_by_rel_oid( + static void binary_upgrade_set_relfilenodes(PQExpBuffer upgrade_buffer, + Oid pg_class_oid, bool is_index); + static const char *getAttrName(int attrnum, TableInfo *tblInfo); +-static const char *fmtCopyColumnList(const TableInfo *ti); ++static const char *fmtCopyColumnList(const TableInfo *ti, bool secids); + static void do_sql_command(PGconn *conn, const char *query); + static void check_sql_result(PGresult *res, PGconn *conn, const char *query, + ExecStatusType expected); +@@ -299,6 +304,7 @@ main(int argc, char **argv) + {"no-tablespaces", no_argument, &outputNoTablespaces, 1}, + {"role", required_argument, NULL, 3}, + {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, ++ {"security-label", no_argument, &security_label, 1}, + + {NULL, 0, NULL, 0} + }; +@@ -447,6 +453,8 @@ main(int argc, char **argv) + outputNoTablespaces = 1; + else if (strcmp(optarg, "use-set-session-authorization") == 0) + use_setsessauth = 1; ++ else if (strcmp(optarg, "security-label") == 0) ++ security_label = 1; + else + { + fprintf(stderr, +@@ -515,6 +523,10 @@ main(int argc, char **argv) + exit(1); + } + ++ /* Force column insertion mode, when --security-label mode is given. */ ++ if (security_label && dump_inserts) ++ column_inserts = 1; ++ + /* open the output file */ + if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0) + { +@@ -833,6 +845,7 @@ help(const char *progname) + printf(_(" --use-set-session-authorization\n" + " use SET SESSION AUTHORIZATION commands instead of\n" + " ALTER OWNER commands to set ownership\n")); ++ printf(_(" --security-label dump schema/data with security label\n")); + + printf(_("\nConnection options:\n")); + printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); +@@ -1127,7 +1140,7 @@ dumpTableData_copy(Archive *fout, void *dcontext) + * cases involving ADD COLUMN and inheritance.) + */ + if (g_fout->remoteVersion >= 70300) +- column_list = fmtCopyColumnList(tbinfo); ++ column_list = fmtCopyColumnList(tbinfo, tdinfo->secids); + else + column_list = ""; /* can't select columns in COPY */ + +@@ -1251,14 +1264,16 @@ dumpTableData_insert(Archive *fout, void *dcontext) + if (fout->remoteVersion >= 70100) + { + appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " +- "SELECT * FROM ONLY %s", ++ "SELECT %s* FROM ONLY %s", ++ (tdinfo->secids ? "security_label," : ""), + fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, + classname)); + } + else + { + appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " +- "SELECT * FROM %s", ++ "SELECT %s* FROM %s", ++ (tdinfo->secids ? "security_label," : ""), + fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, + classname)); + } +@@ -1398,7 +1413,7 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo) + appendPQExpBuffer(copyBuf, "COPY %s ", + fmtId(tbinfo->dobj.name)); + appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n", +- fmtCopyColumnList(tbinfo), ++ fmtCopyColumnList(tbinfo, tdinfo->secids), + (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : ""); + copyStmt = copyBuf->data; + } +@@ -1412,7 +1427,7 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo) + ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId, + tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name, + NULL, tbinfo->rolname, +- false, "TABLE DATA", SECTION_DATA, ++ false, tdinfo->secids, "TABLE DATA", SECTION_DATA, + "", "", copyStmt, + tdinfo->dobj.dependencies, tdinfo->dobj.nDeps, + dumpFn, tdinfo); +@@ -1457,6 +1472,7 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids) + tdinfo->dobj.namespace = tblinfo[i].dobj.namespace; + tdinfo->tdtable = &(tblinfo[i]); + tdinfo->oids = oids; ++ tdinfo->secids = (security_label && tblinfo[i].hassecids) ? true : false; + addObjectDependency(&tdinfo->dobj, tblinfo[i].dobj.dumpId); + + tblinfo[i].dataObj = tdinfo; +@@ -1780,6 +1796,7 @@ dumpDatabase(Archive *AH) + NULL, /* Tablespace */ + dba, /* Owner */ + false, /* with oids */ ++ false, /* with secids */ + "DATABASE", /* Desc */ + SECTION_PRE_DATA, /* Section */ + creaQry->data, /* Create */ +@@ -1825,7 +1842,7 @@ dumpDatabase(Archive *AH) + LargeObjectRelationId); + ArchiveEntry(AH, nilCatalogId, createDumpId(), + "pg_largeobject", NULL, NULL, "", +- false, "pg_largeobject", SECTION_PRE_DATA, ++ false, false, "pg_largeobject", SECTION_PRE_DATA, + loOutQry->data, "", NULL, + NULL, 0, + NULL, NULL); +@@ -1857,7 +1874,7 @@ dumpDatabase(Archive *AH) + appendPQExpBuffer(dbQry, ";\n"); + + ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL, +- dba, false, "COMMENT", SECTION_NONE, ++ dba, false, false, "COMMENT", SECTION_NONE, + dbQry->data, "", NULL, + &dbDumpId, 1, NULL, NULL); + } +@@ -1896,7 +1913,7 @@ dumpEncoding(Archive *AH) + + ArchiveEntry(AH, nilCatalogId, createDumpId(), + "ENCODING", NULL, NULL, "", +- false, "ENCODING", SECTION_PRE_DATA, ++ false, false, "ENCODING", SECTION_PRE_DATA, + qry->data, "", NULL, + NULL, 0, + NULL, NULL); +@@ -1923,7 +1940,7 @@ dumpStdStrings(Archive *AH) + + ArchiveEntry(AH, nilCatalogId, createDumpId(), + "STDSTRINGS", NULL, NULL, "", +- false, "STDSTRINGS", SECTION_PRE_DATA, ++ false, false, "STDSTRINGS", SECTION_PRE_DATA, + qry->data, "", NULL, + NULL, 0, + NULL, NULL); +@@ -1956,16 +1973,17 @@ getBlobs(Archive *AH) + /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */ + if (AH->remoteVersion >= 90000) + appendPQExpBuffer(blobQry, +- "SELECT oid, (%s lomowner) AS rolname, lomacl" ++ "SELECT oid, (%s lomowner) AS rolname, lomacl, %s" + " FROM pg_largeobject_metadata", +- username_subquery); ++ username_subquery, ++ security_label ? "security_label" : "NULL"); + else if (AH->remoteVersion >= 70100) + appendPQExpBuffer(blobQry, +- "SELECT DISTINCT loid, NULL::oid, NULL::oid" ++ "SELECT DISTINCT loid, NULL::oid, NULL::oid, NULL::text" + " FROM pg_largeobject"); + else + appendPQExpBuffer(blobQry, +- "SELECT oid, NULL::oid, NULL::oid" ++ "SELECT oid, NULL::oid, NULL::oid, NULL::text" + " FROM pg_class WHERE relkind = 'l'"); + + res = PQexec(g_conn, blobQry->data); +@@ -1995,6 +2013,11 @@ getBlobs(Archive *AH) + binfo[i].blobacl = strdup(PQgetvalue(res, i, 2)); + else + binfo[i].blobacl = NULL; ++ ++ if (!PQgetisnull(res, i, 3)) ++ binfo[i].seclabel = strdup(PQgetvalue(res, i, 3)); ++ else ++ binfo[i].seclabel = NULL; + } + + /* +@@ -2034,7 +2057,7 @@ dumpBlob(Archive *AH, BlobInfo *binfo) + ArchiveEntry(AH, binfo->dobj.catId, binfo->dobj.dumpId, + binfo->dobj.name, + NULL, NULL, +- binfo->rolname, false, ++ binfo->rolname, false, false, + "BLOB", SECTION_PRE_DATA, + cquery->data, dquery->data, NULL, + binfo->dobj.dependencies, binfo->dobj.nDeps, +@@ -2049,6 +2072,10 @@ dumpBlob(Archive *AH, BlobInfo *binfo) + NULL, binfo->rolname, + binfo->dobj.catId, 0, binfo->dobj.dumpId); + ++ /* Dump security label if any */ ++ dumpSecLabel(AH, binfo->dobj.dumpId, ++ cquery->data, NULL, binfo->seclabel); ++ + /* Dump ACL if any */ + if (binfo->blobacl) + dumpACL(AH, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT", +@@ -2356,6 +2383,7 @@ getNamespaces(int *numNamespaces) + int i_nspname; + int i_rolname; + int i_nspacl; ++ int i_seclabel; + + /* + * Before 7.3, there are no real namespaces; create two dummy entries, one +@@ -2372,6 +2400,7 @@ getNamespaces(int *numNamespaces) + nsinfo[0].dobj.name = strdup("public"); + nsinfo[0].rolname = strdup(""); + nsinfo[0].nspacl = strdup(""); ++ nsinfo[0].seclabel = strdup(""); + + selectDumpableNamespace(&nsinfo[0]); + +@@ -2382,6 +2411,7 @@ getNamespaces(int *numNamespaces) + nsinfo[1].dobj.name = strdup("pg_catalog"); + nsinfo[1].rolname = strdup(""); + nsinfo[1].nspacl = strdup(""); ++ nsinfo[1].seclabel = strdup(""); + + selectDumpableNamespace(&nsinfo[1]); + +@@ -2402,8 +2432,8 @@ getNamespaces(int *numNamespaces) + */ + appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, " + "(%s nspowner) AS rolname, " +- "nspacl FROM pg_namespace", +- username_subquery); ++ "nspacl, %s AS seclabel FROM pg_namespace", ++ username_subquery, security_label ? "security_label" : "NULL"); + + res = PQexec(g_conn, query->data); + check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK); +@@ -2417,6 +2447,7 @@ getNamespaces(int *numNamespaces) + i_nspname = PQfnumber(res, "nspname"); + i_rolname = PQfnumber(res, "rolname"); + i_nspacl = PQfnumber(res, "nspacl"); ++ i_seclabel = PQfnumber(res, "seclabel"); + + for (i = 0; i < ntups; i++) + { +@@ -2427,6 +2458,7 @@ getNamespaces(int *numNamespaces) + nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname)); + nsinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); + nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl)); ++ nsinfo[i].seclabel = strdup(PQgetvalue(res, i, i_seclabel)); + + /* Decide whether to dump this namespace */ + selectDumpableNamespace(&nsinfo[i]); +@@ -2515,6 +2547,7 @@ getTypes(int *numTypes) + int i_typtype; + int i_typisdefined; + int i_isarray; ++ int i_seclabel; + + /* + * we include even the built-in types because those may be used as array +@@ -2547,8 +2580,10 @@ getTypes(int *numTypes) + "typtype, typisdefined, " + "typname[0] = '_' AND typelem != 0 AND " + "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray " ++ ",%s AS seclabel " + "FROM pg_type", +- username_subquery); ++ username_subquery, ++ security_label ? "security_label" : "NULL"); + } + else if (g_fout->remoteVersion >= 70300) + { +@@ -2561,6 +2596,7 @@ getTypes(int *numTypes) + "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " + "typtype, typisdefined, " + "typname[0] = '_' AND typelem != 0 AS isarray " ++ ",NULL AS seclabel " + "FROM pg_type", + username_subquery); + } +@@ -2575,6 +2611,7 @@ getTypes(int *numTypes) + "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " + "typtype, typisdefined, " + "typname[0] = '_' AND typelem != 0 AS isarray " ++ ",NULL AS seclabel " + "FROM pg_type", + username_subquery); + } +@@ -2591,6 +2628,7 @@ getTypes(int *numTypes) + "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " + "typtype, typisdefined, " + "typname[0] = '_' AND typelem != 0 AS isarray " ++ ",NULL AS seclabel " + "FROM pg_type", + username_subquery); + } +@@ -2615,6 +2653,7 @@ getTypes(int *numTypes) + i_typtype = PQfnumber(res, "typtype"); + i_typisdefined = PQfnumber(res, "typisdefined"); + i_isarray = PQfnumber(res, "isarray"); ++ i_seclabel = PQfnumber(res, "seclabel"); + + for (i = 0; i < ntups; i++) + { +@@ -2642,6 +2681,8 @@ getTypes(int *numTypes) + else + tyinfo[i].isArray = false; + ++ tyinfo[i].seclabel = strdup(PQgetvalue(res, i, i_seclabel)); ++ + /* Decide whether we want to dump it */ + selectDumpableType(&tyinfo[i]); + +@@ -3407,6 +3448,7 @@ getTables(int *numTables) + int i_relhasindex; + int i_relhasrules; + int i_relhasoids; ++ int i_relhassecids; + int i_relfrozenxid; + int i_owning_tab; + int i_owning_col; +@@ -3414,6 +3456,7 @@ getTables(int *numTables) + int i_reloptions; + int i_toastreloptions; + int i_reloftype; ++ int i_seclabel; + + /* Make sure we are in proper schema */ + selectSourceSchema("pg_catalog"); +@@ -3450,6 +3493,7 @@ getTables(int *numTables) + "(%s c.relowner) AS rolname, " + "c.relchecks, c.relhastriggers, " + "c.relhasindex, c.relhasrules, c.relhasoids, " ++ "c.relhassecids, " + "c.relfrozenxid, " + "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, " + "d.refobjid AS owning_tab, " +@@ -3457,6 +3501,7 @@ getTables(int *numTables) + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " + "array_to_string(c.reloptions, ', ') AS reloptions, " + "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions " ++ ",%s AS seclabel " + "FROM pg_class c " + "LEFT JOIN pg_depend d ON " + "(c.relkind = '%c' AND " +@@ -3467,6 +3512,7 @@ getTables(int *numTables) + "WHERE c.relkind in ('%c', '%c', '%c', '%c') " + "ORDER BY c.oid", + username_subquery, ++ security_label ? "c.security_label" : "NULL", + RELKIND_SEQUENCE, + RELKIND_RELATION, RELKIND_SEQUENCE, + RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); +@@ -3483,6 +3529,7 @@ getTables(int *numTables) + "(%s c.relowner) AS rolname, " + "c.relchecks, c.relhastriggers, " + "c.relhasindex, c.relhasrules, c.relhasoids, " ++ "false AS relhasecids, " + "c.relfrozenxid, " + "NULL AS reloftype, " + "d.refobjid AS owning_tab, " +@@ -3490,6 +3537,7 @@ getTables(int *numTables) + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " + "array_to_string(c.reloptions, ', ') AS reloptions, " + "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions " ++ ",%s AS seclabel " + "FROM pg_class c " + "LEFT JOIN pg_depend d ON " + "(c.relkind = '%c' AND " +@@ -3500,6 +3548,7 @@ getTables(int *numTables) + "WHERE c.relkind in ('%c', '%c', '%c', '%c') " + "ORDER BY c.oid", + username_subquery, ++ security_label ? "security_label" : "NULL", + RELKIND_SEQUENCE, + RELKIND_RELATION, RELKIND_SEQUENCE, + RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); +@@ -3516,6 +3565,7 @@ getTables(int *numTables) + "(%s relowner) AS rolname, " + "relchecks, (reltriggers <> 0) AS relhastriggers, " + "relhasindex, relhasrules, relhasoids, " ++ "false AS relhassecids, " + "relfrozenxid, " + "NULL AS reloftype, " + "d.refobjid AS owning_tab, " +@@ -3523,6 +3573,7 @@ getTables(int *numTables) + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " + "array_to_string(c.reloptions, ', ') AS reloptions, " + "NULL AS toast_reloptions " ++ ",NULL AS seclabel " + "FROM pg_class c " + "LEFT JOIN pg_depend d ON " + "(c.relkind = '%c' AND " +@@ -3548,6 +3599,7 @@ getTables(int *numTables) + "(%s relowner) AS rolname, " + "relchecks, (reltriggers <> 0) AS relhastriggers, " + "relhasindex, relhasrules, relhasoids, " ++ "false AS relhassecids, " + "0 AS relfrozenxid, " + "NULL AS reloftype, " + "d.refobjid AS owning_tab, " +@@ -3555,6 +3607,7 @@ getTables(int *numTables) + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " + "NULL AS reloptions, " + "NULL AS toast_reloptions " ++ ",NULL AS seclabel " + "FROM pg_class c " + "LEFT JOIN pg_depend d ON " + "(c.relkind = '%c' AND " +@@ -3580,6 +3633,7 @@ getTables(int *numTables) + "(%s relowner) AS rolname, " + "relchecks, (reltriggers <> 0) AS relhastriggers, " + "relhasindex, relhasrules, relhasoids, " ++ "false AS relhassecids, " + "0 AS relfrozenxid, " + "NULL AS reloftype, " + "d.refobjid AS owning_tab, " +@@ -3587,6 +3641,7 @@ getTables(int *numTables) + "NULL AS reltablespace, " + "NULL AS reloptions, " + "NULL AS toast_reloptions " ++ ",NULL AS seclabel " + "FROM pg_class c " + "LEFT JOIN pg_depend d ON " + "(c.relkind = '%c' AND " +@@ -3608,6 +3663,7 @@ getTables(int *numTables) + "(%s relowner) AS rolname, " + "relchecks, (reltriggers <> 0) AS relhastriggers, " + "relhasindex, relhasrules, relhasoids, " ++ "false AS relhassecids, " + "0 AS relfrozenxid, " + "NULL AS reloftype, " + "NULL::oid AS owning_tab, " +@@ -3615,6 +3671,7 @@ getTables(int *numTables) + "NULL AS reltablespace, " + "NULL AS reloptions, " + "NULL AS toast_reloptions " ++ ",NULL AS seclabel " + "FROM pg_class " + "WHERE relkind IN ('%c', '%c', '%c') " + "ORDER BY oid", +@@ -3631,6 +3688,7 @@ getTables(int *numTables) + "relchecks, (reltriggers <> 0) AS relhastriggers, " + "relhasindex, relhasrules, " + "'t'::bool AS relhasoids, " ++ "'f'::bool AS relhassecids, " + "0 AS relfrozenxid, " + "NULL AS reloftype, " + "NULL::oid AS owning_tab, " +@@ -3638,6 +3696,7 @@ getTables(int *numTables) + "NULL AS reltablespace, " + "NULL AS reloptions, " + "NULL AS toast_reloptions " ++ ",NULL AS seclabel " + "FROM pg_class " + "WHERE relkind IN ('%c', '%c', '%c') " + "ORDER BY oid", +@@ -3671,6 +3730,7 @@ getTables(int *numTables) + "NULL AS reltablespace, " + "NULL AS reloptions, " + "NULL AS toast_reloptions " ++ ",NULL AS seclabel " + "FROM pg_class c " + "WHERE relkind IN ('%c', '%c') " + "ORDER BY oid", +@@ -3709,6 +3769,7 @@ getTables(int *numTables) + i_relhasindex = PQfnumber(res, "relhasindex"); + i_relhasrules = PQfnumber(res, "relhasrules"); + i_relhasoids = PQfnumber(res, "relhasoids"); ++ i_relhassecids = PQfnumber(res, "relhassecids"); + i_relfrozenxid = PQfnumber(res, "relfrozenxid"); + i_owning_tab = PQfnumber(res, "owning_tab"); + i_owning_col = PQfnumber(res, "owning_col"); +@@ -3716,6 +3777,7 @@ getTables(int *numTables) + i_reloptions = PQfnumber(res, "reloptions"); + i_toastreloptions = PQfnumber(res, "toast_reloptions"); + i_reloftype = PQfnumber(res, "reloftype"); ++ i_seclabel = PQfnumber(res, "seclabel"); + + if (lockWaitTimeout && g_fout->remoteVersion >= 70300) + { +@@ -3748,6 +3810,7 @@ getTables(int *numTables) + tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0); + tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0); + tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0); ++ tblinfo[i].hassecids = (strcmp(PQgetvalue(res, i, i_relhassecids), "t")==0); + tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid)); + if (PQgetisnull(res, i, i_reloftype)) + tblinfo[i].reloftype = NULL; +@@ -3767,6 +3830,7 @@ getTables(int *numTables) + tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace)); + tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions)); + tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions)); ++ tblinfo[i].rellabel = strdup(PQgetvalue(res, i, i_seclabel)); + + /* other fields were zeroed above */ + +@@ -5082,6 +5146,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) + int i_attalign; + int i_attislocal; + int i_attoptions; ++ int i_seclabel; + PGresult *res; + int ntups; + bool hasdefaults; +@@ -5128,11 +5193,13 @@ getTableAttrs(TableInfo *tblinfo, int numTables) + "a.attlen, a.attalign, a.attislocal, " + "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, " + "array_to_string(attoptions, ', ') AS attoptions " ++ ",%s AS seclabel " + "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t " + "ON a.atttypid = t.oid " + "WHERE a.attrelid = '%u'::pg_catalog.oid " + "AND a.attnum > 0::pg_catalog.int2 " + "ORDER BY a.attrelid, a.attnum", ++ security_label ? "a.security_label" : "NULL", + tbinfo->dobj.catId.oid); + } + else if (g_fout->remoteVersion >= 70300) +@@ -5144,6 +5211,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) + "a.attlen, a.attalign, a.attislocal, " + "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, " + "'' AS attoptions " ++ ",NULL AS seclabel " + "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t " + "ON a.atttypid = t.oid " + "WHERE a.attrelid = '%u'::pg_catalog.oid " +@@ -5165,6 +5233,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) + "a.attalign, false AS attislocal, " + "format_type(t.oid,a.atttypmod) AS atttypname, " + "'' AS attoptions " ++ ",NULL AS seclabel " + "FROM pg_attribute a LEFT JOIN pg_type t " + "ON a.atttypid = t.oid " + "WHERE a.attrelid = '%u'::oid " +@@ -5183,6 +5252,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) + "false AS attislocal, " + "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, " + "'' AS attoptions " ++ ",NULL AS seclabel " + "FROM pg_attribute a " + "WHERE attrelid = '%u'::oid " + "AND attnum > 0::int2 " +@@ -5209,6 +5279,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) + i_attalign = PQfnumber(res, "attalign"); + i_attislocal = PQfnumber(res, "attislocal"); + i_attoptions = PQfnumber(res, "attoptions"); ++ i_seclabel = PQfnumber(res, "seclabel"); + + tbinfo->numatts = ntups; + tbinfo->attnames = (char **) malloc(ntups * sizeof(char *)); +@@ -5227,6 +5298,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) + tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool)); + tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool)); + tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool)); ++ tbinfo->attlabels = (char **) malloc(ntups * sizeof(char *)); + hasdefaults = false; + + for (j = 0; j < ntups; j++) +@@ -5256,6 +5328,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) + tbinfo->inhAttrs[j] = false; + tbinfo->inhAttrDef[j] = false; + tbinfo->inhNotNull[j] = false; ++ tbinfo->attlabels[j] = strdup(PQgetvalue(res, j, i_seclabel)); + } + + PQclear(res); +@@ -6146,7 +6219,7 @@ dumpComment(Archive *fout, const char *target, + */ + ArchiveEntry(fout, nilCatalogId, createDumpId(), + target, namespace, NULL, owner, +- false, "COMMENT", SECTION_NONE, ++ false, false, "COMMENT", SECTION_NONE, + query->data, "", NULL, + &(dumpId), 1, + NULL, NULL); +@@ -6207,7 +6280,7 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo, + target->data, + tbinfo->dobj.namespace->dobj.name, + NULL, tbinfo->rolname, +- false, "COMMENT", SECTION_NONE, ++ false, false, "COMMENT", SECTION_NONE, + query->data, "", NULL, + &(tbinfo->dobj.dumpId), 1, + NULL, NULL); +@@ -6229,7 +6302,7 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo, + target->data, + tbinfo->dobj.namespace->dobj.name, + NULL, tbinfo->rolname, +- false, "COMMENT", SECTION_NONE, ++ false, false, "COMMENT", SECTION_NONE, + query->data, "", NULL, + &(tbinfo->dobj.dumpId), 1, + NULL, NULL); +@@ -6509,7 +6582,7 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj) + case DO_BLOB_DATA: + ArchiveEntry(fout, dobj->catId, dobj->dumpId, + dobj->name, NULL, NULL, "", +- false, "BLOBS", SECTION_DATA, ++ false, false, "BLOBS", SECTION_DATA, + "", "", NULL, + dobj->dependencies, dobj->nDeps, + dumpBlobs, NULL); +@@ -6549,7 +6622,7 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo) + nspinfo->dobj.name, + NULL, NULL, + nspinfo->rolname, +- false, "SCHEMA", SECTION_PRE_DATA, ++ false, false, "SCHEMA", SECTION_PRE_DATA, + q->data, delq->data, NULL, + nspinfo->dobj.dependencies, nspinfo->dobj.nDeps, + NULL, NULL); +@@ -6561,6 +6634,9 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo) + NULL, nspinfo->rolname, + nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId); + ++ dumpSecLabel(fout, nspinfo->dobj.dumpId, ++ q->data, NULL, nspinfo->seclabel); ++ + dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA", + qnspname, NULL, nspinfo->dobj.name, NULL, + nspinfo->rolname, nspinfo->nspacl); +@@ -6678,7 +6754,7 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo) + tyinfo->dobj.name, + tyinfo->dobj.namespace->dobj.name, + NULL, +- tyinfo->rolname, false, ++ tyinfo->rolname, false, false, + "TYPE", SECTION_PRE_DATA, + q->data, delq->data, NULL, + tyinfo->dobj.dependencies, tyinfo->dobj.nDeps, +@@ -6692,6 +6768,12 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo) + tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, + tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId); + ++ /* Dump type security label */ ++ dumpSecLabel(fout, tyinfo->dobj.dumpId, ++ q->data, ++ tyinfo->dobj.namespace->dobj.name, ++ tyinfo->seclabel); ++ + PQclear(res); + destroyPQExpBuffer(q); + destroyPQExpBuffer(delq); +@@ -7054,7 +7136,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) + tyinfo->dobj.name, + tyinfo->dobj.namespace->dobj.name, + NULL, +- tyinfo->rolname, false, ++ tyinfo->rolname, false, false, + "TYPE", SECTION_PRE_DATA, + q->data, delq->data, NULL, + tyinfo->dobj.dependencies, tyinfo->dobj.nDeps, +@@ -7068,6 +7150,12 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) + tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, + tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId); + ++ /* Dump type security label */ ++ dumpSecLabel(fout, tyinfo->dobj.dumpId, ++ q->data, ++ tyinfo->dobj.namespace->dobj.name, ++ tyinfo->seclabel); ++ + PQclear(res); + destroyPQExpBuffer(q); + destroyPQExpBuffer(delq); +@@ -7178,7 +7266,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) + tyinfo->dobj.name, + tyinfo->dobj.namespace->dobj.name, + NULL, +- tyinfo->rolname, false, ++ tyinfo->rolname, false, false, + "DOMAIN", SECTION_PRE_DATA, + q->data, delq->data, NULL, + tyinfo->dobj.dependencies, tyinfo->dobj.nDeps, +@@ -7192,6 +7280,12 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) + tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, + tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId); + ++ /* Dump domain security label */ ++ dumpSecLabel(fout, tyinfo->dobj.dumpId, ++ q->data, ++ tyinfo->dobj.namespace->dobj.name, ++ tyinfo->seclabel); ++ + destroyPQExpBuffer(q); + destroyPQExpBuffer(delq); + destroyPQExpBuffer(query); +@@ -7283,7 +7377,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) + tyinfo->dobj.name, + tyinfo->dobj.namespace->dobj.name, + NULL, +- tyinfo->rolname, false, ++ tyinfo->rolname, false, false, + "TYPE", SECTION_PRE_DATA, + q->data, delq->data, NULL, + tyinfo->dobj.dependencies, tyinfo->dobj.nDeps, +@@ -7298,6 +7392,12 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) + tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, + tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId); + ++ /* Dump type security label */ ++ dumpSecLabel(fout, tyinfo->dobj.dumpId, ++ q->data, ++ tyinfo->dobj.namespace->dobj.name, ++ tyinfo->seclabel); ++ + PQclear(res); + destroyPQExpBuffer(q); + destroyPQExpBuffer(delq); +@@ -7402,7 +7502,7 @@ dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo) + target->data, + tyinfo->dobj.namespace->dobj.name, + NULL, tyinfo->rolname, +- false, "COMMENT", SECTION_NONE, ++ false, false, "COMMENT", SECTION_NONE, + query->data, "", NULL, + &(tyinfo->dobj.dumpId), 1, + NULL, NULL); +@@ -7454,7 +7554,7 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo) + stinfo->dobj.name, + stinfo->dobj.namespace->dobj.name, + NULL, +- stinfo->baseType->rolname, false, ++ stinfo->baseType->rolname, false, false, + "SHELL TYPE", SECTION_PRE_DATA, + q->data, "", NULL, + stinfo->dobj.dependencies, stinfo->dobj.nDeps, +@@ -7609,7 +7709,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) + ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId, + plang->dobj.name, + lanschema, NULL, plang->lanowner, +- false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA, ++ false, false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA, + defqry->data, delqry->data, NULL, + plang->dobj.dependencies, plang->dobj.nDeps, + NULL, NULL); +@@ -7795,6 +7895,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + char **argmodes = NULL; + char **argnames = NULL; + char **configitems = NULL; ++ char *proseclabel; + int nconfigitems = 0; + int i; + +@@ -7825,8 +7926,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + "proiswindow, provolatile, proisstrict, prosecdef, " + "proconfig, procost, prorows, " + "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " ++ ",%s AS seclabel " + "FROM pg_catalog.pg_proc " + "WHERE oid = '%u'::pg_catalog.oid", ++ security_label ? "security_label" : "NULL", + finfo->dobj.catId.oid); + } + else if (g_fout->remoteVersion >= 80300) +@@ -7838,6 +7941,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + "provolatile, proisstrict, prosecdef, " + "proconfig, procost, prorows, " + "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " ++ ",NULL AS seclabel " + "FROM pg_catalog.pg_proc " + "WHERE oid = '%u'::pg_catalog.oid", + finfo->dobj.catId.oid); +@@ -7851,6 +7955,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + "provolatile, proisstrict, prosecdef, " + "null AS proconfig, 0 AS procost, 0 AS prorows, " + "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " ++ ",NULL AS seclabel " + "FROM pg_catalog.pg_proc " + "WHERE oid = '%u'::pg_catalog.oid", + finfo->dobj.catId.oid); +@@ -7866,6 +7971,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + "provolatile, proisstrict, prosecdef, " + "null AS proconfig, 0 AS procost, 0 AS prorows, " + "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " ++ ",NULL AS seclabel " + "FROM pg_catalog.pg_proc " + "WHERE oid = '%u'::pg_catalog.oid", + finfo->dobj.catId.oid); +@@ -7881,6 +7987,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + "provolatile, proisstrict, prosecdef, " + "null AS proconfig, 0 AS procost, 0 AS prorows, " + "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " ++ ",NULL AS seclabel " + "FROM pg_catalog.pg_proc " + "WHERE oid = '%u'::pg_catalog.oid", + finfo->dobj.catId.oid); +@@ -7898,6 +8005,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + "false AS prosecdef, " + "null AS proconfig, 0 AS procost, 0 AS prorows, " + "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname " ++ ",NULL AS seclabel " + "FROM pg_proc " + "WHERE oid = '%u'::oid", + finfo->dobj.catId.oid); +@@ -7915,6 +8023,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + "false AS prosecdef, " + "NULL AS proconfig, 0 AS procost, 0 AS prorows, " + "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname " ++ ",NULL AS seclabel " + "FROM pg_proc " + "WHERE oid = '%u'::oid", + finfo->dobj.catId.oid); +@@ -7959,6 +8068,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + procost = PQgetvalue(res, 0, PQfnumber(res, "procost")); + prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows")); + lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname")); ++ proseclabel = PQgetvalue(res, 0, PQfnumber(res, "seclabel")); + + /* + * See backend/commands/functioncmds.c for details of how the 'AS' clause +@@ -8169,7 +8279,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + funcsig_tag, + finfo->dobj.namespace->dobj.name, + NULL, +- finfo->rolname, false, ++ finfo->rolname, false, false, + "FUNCTION", SECTION_PRE_DATA, + q->data, delqry->data, NULL, + finfo->dobj.dependencies, finfo->dobj.nDeps, +@@ -8182,6 +8292,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo) + finfo->dobj.namespace->dobj.name, finfo->rolname, + finfo->dobj.catId, 0, finfo->dobj.dumpId); + ++ /* Dump Function security label */ ++ dumpSecLabel(fout, finfo->dobj.dumpId, ++ q->data, ++ finfo->dobj.namespace->dobj.name, ++ proseclabel); ++ + dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION", + funcsig, NULL, funcsig_tag, + finfo->dobj.namespace->dobj.name, +@@ -8323,7 +8439,7 @@ dumpCast(Archive *fout, CastInfo *cast) + ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId, + castsig->data, + "pg_catalog", NULL, "", +- false, "CAST", SECTION_PRE_DATA, ++ false, false, "CAST", SECTION_PRE_DATA, + defqry->data, delqry->data, NULL, + cast->dobj.dependencies, cast->dobj.nDeps, + NULL, NULL); +@@ -8567,7 +8683,7 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) + oprinfo->dobj.namespace->dobj.name, + NULL, + oprinfo->rolname, +- false, "OPERATOR", SECTION_PRE_DATA, ++ false, false, "OPERATOR", SECTION_PRE_DATA, + q->data, delq->data, NULL, + oprinfo->dobj.dependencies, oprinfo->dobj.nDeps, + NULL, NULL); +@@ -9026,7 +9142,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) + opcinfo->dobj.namespace->dobj.name, + NULL, + opcinfo->rolname, +- false, "OPERATOR CLASS", SECTION_PRE_DATA, ++ false, false, "OPERATOR CLASS", SECTION_PRE_DATA, + q->data, delq->data, NULL, + opcinfo->dobj.dependencies, opcinfo->dobj.nDeps, + NULL, NULL); +@@ -9307,7 +9423,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo) + opfinfo->dobj.namespace->dobj.name, + NULL, + opfinfo->rolname, +- false, "OPERATOR FAMILY", SECTION_PRE_DATA, ++ false, false, "OPERATOR FAMILY", SECTION_PRE_DATA, + q->data, delq->data, NULL, + opfinfo->dobj.dependencies, opfinfo->dobj.nDeps, + NULL, NULL); +@@ -9423,7 +9539,7 @@ dumpConversion(Archive *fout, ConvInfo *convinfo) + convinfo->dobj.namespace->dobj.name, + NULL, + convinfo->rolname, +- false, "CONVERSION", SECTION_PRE_DATA, ++ false, false, "CONVERSION", SECTION_PRE_DATA, + q->data, delq->data, NULL, + convinfo->dobj.dependencies, convinfo->dobj.nDeps, + NULL, NULL); +@@ -9504,11 +9620,13 @@ dumpAgg(Archive *fout, AggInfo *agginfo) + int i_aggtranstype; + int i_agginitval; + int i_convertok; ++ int i_seclabel; + const char *aggtransfn; + const char *aggfinalfn; + const char *aggsortop; + const char *aggtranstype; + const char *agginitval; ++ const char *seclabel; + bool convertok; + + /* Skip if not to be dumped */ +@@ -9531,9 +9649,11 @@ dumpAgg(Archive *fout, AggInfo *agginfo) + "aggsortop::pg_catalog.regoperator, " + "agginitval, " + "'t'::boolean AS convertok " ++ ",%s AS seclabel " + "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " + "WHERE a.aggfnoid = p.oid " + "AND p.oid = '%u'::pg_catalog.oid", ++ security_label ? "p.security_label" : "NULL", + agginfo->aggfn.dobj.catId.oid); + } + else if (g_fout->remoteVersion >= 70300) +@@ -9543,6 +9663,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) + "0 AS aggsortop, " + "agginitval, " + "'t'::boolean AS convertok " ++ ",NULL AS seclabel " + "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " + "WHERE a.aggfnoid = p.oid " + "AND p.oid = '%u'::pg_catalog.oid", +@@ -9555,6 +9676,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) + "0 AS aggsortop, " + "agginitval, " + "'t'::boolean AS convertok " ++ ",NULL AS seclabel " + "FROM pg_aggregate " + "WHERE oid = '%u'::oid", + agginfo->aggfn.dobj.catId.oid); +@@ -9567,6 +9689,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) + "0 AS aggsortop, " + "agginitval1 AS agginitval, " + "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok " ++ ",NULL AS seclabel " + "FROM pg_aggregate " + "WHERE oid = '%u'::oid", + agginfo->aggfn.dobj.catId.oid); +@@ -9592,6 +9715,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) + i_aggtranstype = PQfnumber(res, "aggtranstype"); + i_agginitval = PQfnumber(res, "agginitval"); + i_convertok = PQfnumber(res, "convertok"); ++ i_seclabel = PQfnumber(res, "seclabel"); + + aggtransfn = PQgetvalue(res, 0, i_aggtransfn); + aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn); +@@ -9599,6 +9723,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) + aggtranstype = PQgetvalue(res, 0, i_aggtranstype); + agginitval = PQgetvalue(res, 0, i_agginitval); + convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't'); ++ seclabel = PQgetvalue(res, 0, i_seclabel); + + aggsig = format_aggregate_signature(agginfo, fout, true); + aggsig_tag = format_aggregate_signature(agginfo, fout, false); +@@ -9667,7 +9792,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) + agginfo->aggfn.dobj.namespace->dobj.name, + NULL, + agginfo->aggfn.rolname, +- false, "AGGREGATE", SECTION_PRE_DATA, ++ false, false, "AGGREGATE", SECTION_PRE_DATA, + q->data, delq->data, NULL, + agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps, + NULL, NULL); +@@ -9679,6 +9804,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo) + agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname, + agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId); + ++ /* Dump Aggregate security label */ ++ dumpSecLabel(fout, agginfo->aggfn.dobj.dumpId, ++ q->data, ++ agginfo->aggfn.dobj.namespace->dobj.name, ++ seclabel); ++ + /* + * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL + * command look like a function's GRANT; in particular this affects the +@@ -9755,7 +9886,7 @@ dumpTSParser(Archive *fout, TSParserInfo *prsinfo) + prsinfo->dobj.namespace->dobj.name, + NULL, + "", +- false, "TEXT SEARCH PARSER", SECTION_PRE_DATA, ++ false, false, "TEXT SEARCH PARSER", SECTION_PRE_DATA, + q->data, delq->data, NULL, + prsinfo->dobj.dependencies, prsinfo->dobj.nDeps, + NULL, NULL); +@@ -9847,7 +9978,7 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo) + dictinfo->dobj.namespace->dobj.name, + NULL, + dictinfo->rolname, +- false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA, ++ false, false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA, + q->data, delq->data, NULL, + dictinfo->dobj.dependencies, dictinfo->dobj.nDeps, + NULL, NULL); +@@ -9907,7 +10038,7 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo) + tmplinfo->dobj.namespace->dobj.name, + NULL, + "", +- false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA, ++ false, false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA, + q->data, delq->data, NULL, + tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps, + NULL, NULL); +@@ -10040,7 +10171,7 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo) + cfginfo->dobj.namespace->dobj.name, + NULL, + cfginfo->rolname, +- false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA, ++ false, false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA, + q->data, delq->data, NULL, + cfginfo->dobj.dependencies, cfginfo->dobj.nDeps, + NULL, NULL); +@@ -10096,7 +10227,7 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo) + NULL, + NULL, + fdwinfo->rolname, +- false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA, ++ false, false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA, + q->data, delq->data, NULL, + fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps, + NULL, NULL); +@@ -10183,7 +10314,7 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo) + NULL, + NULL, + srvinfo->rolname, +- false, "SERVER", SECTION_PRE_DATA, ++ false, false, "SERVER", SECTION_PRE_DATA, + q->data, delq->data, NULL, + srvinfo->dobj.dependencies, srvinfo->dobj.nDeps, + NULL, NULL); +@@ -10279,7 +10410,7 @@ dumpUserMappings(Archive *fout, const char *target, + tag->data, + namespace, + NULL, +- owner, false, ++ owner, false, false, + "USER MAPPING", SECTION_PRE_DATA, + q->data, delq->data, NULL, + &dumpId, 1, +@@ -10350,7 +10481,7 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo) + daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL, + NULL, + daclinfo->defaclrole, +- false, "DEFAULT ACL", SECTION_NONE, ++ false, false, "DEFAULT ACL", SECTION_NONE, + q->data, "", NULL, + daclinfo->dobj.dependencies, daclinfo->dobj.nDeps, + NULL, NULL); +@@ -10407,7 +10538,7 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId, + tag, nspname, + NULL, + owner ? owner : "", +- false, "ACL", SECTION_NONE, ++ false, false, "ACL", SECTION_NONE, + sql->data, "", NULL, + &(objDumpId), 1, + NULL, NULL); +@@ -10416,6 +10547,123 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId, + } + + /* ++ * dumpSecLabel ++ * ++ * write out security label of the objects ++ */ ++static void ++dumpSecLabel(Archive *fout, DumpId objDumpId, ++ const char *target, const char *namespace, ++ const char *seclabel) ++{ ++ PQExpBuffer qry; ++ ++ /* Do nothing, if security label dump is not given */ ++ if (!security_label || strlen(seclabel) == 0) ++ return; ++ ++ /* Do nothing, if --data-only for schemas, or --schema-only for blobs */ ++ if (strncmp(target, "LARGE OBJECT", 13) == 0) ++ { ++ if (schemaOnly) ++ return; ++ } ++ else ++ { ++ if (dataOnly) ++ return; ++ } ++ ++ /* Make ALTER xxx SECURITY LABEL TO command */ ++ qry = createPQExpBuffer(); ++ ++ appendPQExpBuffer(qry, "ALTER %s SECURITY LABEL TO '%s';", ++ target, seclabel); ++ ++ ArchiveEntry(fout, ++ nilCatalogId, /* catalog ID */ ++ createDumpId(), /* dump ID */ ++ target, /* name */ ++ namespace, /* namespace */ ++ NULL, /* tablespace */ ++ "", /* owner */ ++ false, /* with oids */ ++ false, /* with secids */ ++ "LABEL", /* desc */ ++ SECTION_NONE, /* section */ ++ qry->data, /* create */ ++ "", /* delete*/ ++ NULL, /* copy */ ++ &(objDumpId), /* dependency */ ++ 1, /* # deps */ ++ NULL, /* dumper Func */ ++ NULL); /* dumper Arg */ ++ ++ destroyPQExpBuffer(qry); ++} ++ ++/* ++ * dumpTableSecLabel ++ * ++ * write out security label of the table ++ */ ++static void ++dumpTableSecLabel(Archive *fout, DumpId objDumpId, ++ const char *namespace, ++ const char *table_name, ++ const char **column_names, int ncolumns, ++ const char *table_label, const char **column_labels) ++{ ++ PQExpBuffer qry; ++ PQExpBuffer tag; ++ int i; ++ ++ if (!security_label || dataOnly) ++ return; ++ ++ /* Make ALTER xxx SECURITY LABEL TO command */ ++ qry = createPQExpBuffer(); ++ tag = createPQExpBuffer(); ++ ++ appendPQExpBuffer(tag, "TABLE %s", table_name); ++ ++ if (strlen(table_label) > 0) ++ appendPQExpBuffer(qry, "ALTER TABLE %s SECURITY LABEL TO '%s';\n", ++ table_name, table_label); ++ for (i = 0; i < ncolumns; i++) ++ { ++ if (strlen(column_labels[i]) > 0) ++ appendPQExpBuffer(qry, "ALTER TABLE %s ALTER %s SECURITY LABEL TO '%s';\n", ++ table_name, ++ column_names[i], ++ column_labels[i]); ++ } ++ ++ if (qry->len > 0) ++ ArchiveEntry(fout, ++ nilCatalogId, /* catalog ID */ ++ createDumpId(), /* dump ID */ ++ tag->data, /* name */ ++ namespace, /* namespace */ ++ NULL, /* tablespace */ ++ "", /* owner */ ++ false, /* with oids */ ++ false, /* with secids */ ++ "LABEL", /* desc */ ++ SECTION_NONE, /* section */ ++ qry->data, /* create */ ++ "", /* delete*/ ++ NULL, /* copy */ ++ &(objDumpId), /* dependency */ ++ 1, /* # deps */ ++ NULL, /* dumper Func */ ++ NULL); /* dumper Arg */ ++ ++ destroyPQExpBuffer(qry); ++ destroyPQExpBuffer(tag); ++} ++ ++/* + * dumpTable + * write out to fout the declarations (not data) of a user-defined table + */ +@@ -10571,7 +10819,6 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) + + appendPQExpBuffer(q, "CREATE VIEW %s AS\n %s\n", + fmtId(tbinfo->dobj.name), viewdef); +- + PQclear(res); + } + else +@@ -10922,6 +11169,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) + (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace, + tbinfo->rolname, + (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false, ++ (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hassecids : false, + reltypename, SECTION_PRE_DATA, + q->data, delq->data, NULL, + tbinfo->dobj.dependencies, tbinfo->dobj.nDeps, +@@ -10942,6 +11190,27 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) + dumpTableConstraintComment(fout, constr); + } + ++ /* Dump relation/attribute's security labels */ ++ if (tbinfo->relkind == RELKIND_RELATION) ++ { ++ dumpTableSecLabel(fout, tbinfo->dobj.dumpId, ++ tbinfo->dobj.namespace->dobj.name, ++ tbinfo->dobj.name, ++ tbinfo->attnames, tbinfo->numatts, ++ tbinfo->rellabel, tbinfo->attlabels); ++ } ++ else ++ { ++ PQExpBuffer target = createPQExpBuffer(); ++ ++ appendPQExpBuffer(target, "%s %s", reltypename, fmtId(tbinfo->dobj.name)); ++ dumpSecLabel(fout, tbinfo->dobj.dumpId, ++ target->data, ++ tbinfo->dobj.namespace->dobj.name, ++ tbinfo->rellabel); ++ destroyPQExpBuffer(target); ++ } ++ + destroyPQExpBuffer(query); + destroyPQExpBuffer(q); + destroyPQExpBuffer(delq); +@@ -10990,7 +11259,7 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo) + tbinfo->dobj.namespace->dobj.name, + NULL, + tbinfo->rolname, +- false, "DEFAULT", SECTION_PRE_DATA, ++ false, false, "DEFAULT", SECTION_PRE_DATA, + q->data, delq->data, NULL, + adinfo->dobj.dependencies, adinfo->dobj.nDeps, + NULL, NULL); +@@ -11086,7 +11355,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) + indxinfo->dobj.name, + tbinfo->dobj.namespace->dobj.name, + indxinfo->tablespace, +- tbinfo->rolname, false, ++ tbinfo->rolname, false, false, + "INDEX", SECTION_POST_DATA, + q->data, delq->data, NULL, + indxinfo->dobj.dependencies, indxinfo->dobj.nDeps, +@@ -11211,7 +11480,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) + coninfo->dobj.name, + tbinfo->dobj.namespace->dobj.name, + indxinfo->tablespace, +- tbinfo->rolname, false, ++ tbinfo->rolname, false, false, + "CONSTRAINT", SECTION_POST_DATA, + q->data, delq->data, NULL, + coninfo->dobj.dependencies, coninfo->dobj.nDeps, +@@ -11244,7 +11513,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) + coninfo->dobj.name, + tbinfo->dobj.namespace->dobj.name, + NULL, +- tbinfo->rolname, false, ++ tbinfo->rolname, false, false, + "FK CONSTRAINT", SECTION_POST_DATA, + q->data, delq->data, NULL, + coninfo->dobj.dependencies, coninfo->dobj.nDeps, +@@ -11279,7 +11548,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) + coninfo->dobj.name, + tbinfo->dobj.namespace->dobj.name, + NULL, +- tbinfo->rolname, false, ++ tbinfo->rolname, false, false, + "CHECK CONSTRAINT", SECTION_POST_DATA, + q->data, delq->data, NULL, + coninfo->dobj.dependencies, coninfo->dobj.nDeps, +@@ -11315,7 +11584,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) + coninfo->dobj.name, + tyinfo->dobj.namespace->dobj.name, + NULL, +- tyinfo->rolname, false, ++ tyinfo->rolname, false, false, + "CHECK CONSTRAINT", SECTION_POST_DATA, + q->data, delq->data, NULL, + coninfo->dobj.dependencies, coninfo->dobj.nDeps, +@@ -11601,7 +11870,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) + tbinfo->dobj.namespace->dobj.name, + NULL, + tbinfo->rolname, +- false, "SEQUENCE", SECTION_PRE_DATA, ++ false, false, "SEQUENCE", SECTION_PRE_DATA, + query->data, delqry->data, NULL, + tbinfo->dobj.dependencies, tbinfo->dobj.nDeps, + NULL, NULL); +@@ -11637,7 +11906,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) + tbinfo->dobj.namespace->dobj.name, + NULL, + tbinfo->rolname, +- false, "SEQUENCE OWNED BY", SECTION_PRE_DATA, ++ false, false, "SEQUENCE OWNED BY", SECTION_PRE_DATA, + query->data, "", NULL, + &(tbinfo->dobj.dumpId), 1, + NULL, NULL); +@@ -11650,6 +11919,12 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) + dumpComment(fout, query->data, + tbinfo->dobj.namespace->dobj.name, tbinfo->rolname, + tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId); ++ ++ /* Dump sequence security label */ ++ dumpSecLabel(fout, tbinfo->dobj.dumpId, ++ query->data, ++ tbinfo->dobj.namespace->dobj.name, ++ tbinfo->rellabel); + } + + if (!schemaOnly) +@@ -11665,7 +11940,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) + tbinfo->dobj.namespace->dobj.name, + NULL, + tbinfo->rolname, +- false, "SEQUENCE SET", SECTION_PRE_DATA, ++ false, false, "SEQUENCE SET", SECTION_PRE_DATA, + query->data, "", NULL, + &(tbinfo->dobj.dumpId), 1, + NULL, NULL); +@@ -11849,7 +12124,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) + tginfo->dobj.name, + tbinfo->dobj.namespace->dobj.name, + NULL, +- tbinfo->rolname, false, ++ tbinfo->rolname, false, false, + "TRIGGER", SECTION_POST_DATA, + query->data, delqry->data, NULL, + tginfo->dobj.dependencies, tginfo->dobj.nDeps, +@@ -11969,7 +12244,7 @@ dumpRule(Archive *fout, RuleInfo *rinfo) + rinfo->dobj.name, + tbinfo->dobj.namespace->dobj.name, + NULL, +- tbinfo->rolname, false, ++ tbinfo->rolname, false, false, + "RULE", SECTION_POST_DATA, + cmd->data, delcmd->data, NULL, + rinfo->dobj.dependencies, rinfo->dobj.nDeps, +@@ -12334,7 +12609,7 @@ fmtQualifiedId(const char *schema, const char *id) + * "", not an invalid "()" column list. + */ + static const char * +-fmtCopyColumnList(const TableInfo *ti) ++fmtCopyColumnList(const TableInfo *ti, bool secids) + { + static PQExpBuffer q = NULL; + int numatts = ti->numatts; +@@ -12350,6 +12625,11 @@ fmtCopyColumnList(const TableInfo *ti) + + appendPQExpBuffer(q, "("); + needComma = false; ++ if (secids) ++ { ++ appendPQExpBuffer(q, "security_label"); ++ needComma = true; ++ } + for (i = 0; i < numatts; i++) + { + if (attisdropped[i]) +diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h +index c93bada..78a50bd 100644 +--- a/src/bin/pg_dump/pg_dump.h ++++ b/src/bin/pg_dump/pg_dump.h +@@ -137,6 +137,7 @@ typedef struct _namespaceInfo + DumpableObject dobj; + char *rolname; /* name of owner, or empty string */ + char *nspacl; ++ char *seclabel; + } NamespaceInfo; + + typedef struct _typeInfo +@@ -153,6 +154,7 @@ typedef struct _typeInfo + char typrelkind; /* 'r', 'v', 'c', etc */ + char typtype; /* 'b', 'c', etc */ + bool isArray; /* true if auto-generated array type */ ++ char *seclabel; + bool isDefined; /* true if typisdefined */ + /* If it's a dumpable base type, we create a "shell type" entry for it */ + struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */ +@@ -227,9 +229,11 @@ typedef struct _tableInfo + bool hasrules; /* does it have any rules? */ + bool hastriggers; /* does it have any triggers? */ + bool hasoids; /* does it have OIDs? */ ++ bool hassecids; /* does it have security-Id? */ + uint32 frozenxid; /* for restore frozen xid */ + int ncheck; /* # of CHECK expressions */ + char *reloftype; /* underlying type for typed table */ ++ char *rellabel; /* relation's security label */ + /* these two are set only if table is a sequence owned by a column: */ + Oid owning_tab; /* OID of table owning sequence */ + int owning_col; /* attr # of column owning sequence */ +@@ -252,6 +256,7 @@ typedef struct _tableInfo + char *attalign; /* attribute align, used by binary_upgrade */ + bool *attislocal; /* true if attr has local definition */ + char **attoptions; /* per-attribute options */ ++ char **attlabels; /* attribute's security label */ + + /* + * Note: we need to store per-attribute notnull, default, and constraint +@@ -287,6 +292,7 @@ typedef struct _tableDataInfo + DumpableObject dobj; + TableInfo *tdtable; /* link to table to dump */ + bool oids; /* include OIDs in data? */ ++ bool secids; /* include SecIDs in data? */ + } TableDataInfo; + + typedef struct _indxInfo +@@ -448,6 +454,7 @@ typedef struct _blobInfo + DumpableObject dobj; + char *rolname; + char *blobacl; ++ char *seclabel; + } BlobInfo; + + /* global decls */ +diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c +index 0c3f63f..83f1678 100644 +--- a/src/bin/pg_dump/pg_dumpall.c ++++ b/src/bin/pg_dump/pg_dumpall.c +@@ -69,6 +69,7 @@ static int disable_triggers = 0; + static int inserts = 0; + static int no_tablespaces = 0; + static int use_setsessauth = 0; ++static int security_label = 0; + static int server_version; + + static FILE *OPF; +@@ -132,6 +133,7 @@ main(int argc, char *argv[]) + {"no-tablespaces", no_argument, &no_tablespaces, 1}, + {"role", required_argument, NULL, 3}, + {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, ++ {"security-label", no_argument, &security_label, 1}, + + {NULL, 0, NULL, 0} + }; +@@ -285,6 +287,8 @@ main(int argc, char *argv[]) + no_tablespaces = 1; + else if (strcmp(optarg, "use-set-session-authorization") == 0) + use_setsessauth = 1; ++ else if (strcmp(optarg, "security-label") == 0) ++ security_label = 1; + else + { + fprintf(stderr, +@@ -330,6 +334,8 @@ main(int argc, char *argv[]) + appendPQExpBuffer(pgdumpopts, " --no-tablespaces"); + if (use_setsessauth) + appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization"); ++ if (security_label) ++ appendPQExpBuffer(pgdumpopts, " --security-label"); + + if (optind < argc) + { +@@ -561,6 +567,7 @@ help(void) + printf(_(" --use-set-session-authorization\n" + " use SET SESSION AUTHORIZATION commands instead of\n" + " ALTER OWNER commands to set ownership\n")); ++ printf(_(" --security-label dump schema/data with security label\n")); + + printf(_("\nConnection options:\n")); + printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); +@@ -949,6 +956,7 @@ dropTablespaces(PGconn *conn) + static void + dumpTablespaces(PGconn *conn) + { ++ PQExpBuffer qry = createPQExpBuffer(); + PGresult *res; + int i; + +@@ -957,31 +965,37 @@ dumpTablespaces(PGconn *conn) + * pg_xxx) + */ + if (server_version >= 90000) +- res = executeQuery(conn, "SELECT spcname, " ++ appendPQExpBuffer(qry, "SELECT spcname, " + "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " + "spclocation, spcacl, " + "array_to_string(spcoptions, ', ')," + "pg_catalog.shobj_description(oid, 'pg_tablespace') " ++ ",%s AS seclabel " + "FROM pg_catalog.pg_tablespace " + "WHERE spcname !~ '^pg_' " +- "ORDER BY 1"); ++ "ORDER BY 1", ++ security_label ? "security_label" : "NULL"); + else if (server_version >= 80200) +- res = executeQuery(conn, "SELECT spcname, " ++ appendPQExpBuffer(qry, "SELECT spcname, " + "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " + "spclocation, spcacl, null, " + "pg_catalog.shobj_description(oid, 'pg_tablespace') " ++ ",NULL AS seclabel" + "FROM pg_catalog.pg_tablespace " + "WHERE spcname !~ '^pg_' " + "ORDER BY 1"); + else +- res = executeQuery(conn, "SELECT spcname, " ++ appendPQExpBuffer(qry, "SELECT spcname, " + "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " + "spclocation, spcacl, " + "null, null " ++ ",NULL AS seclabel" + "FROM pg_catalog.pg_tablespace " + "WHERE spcname !~ '^pg_' " + "ORDER BY 1"); + ++ res = PQexec(conn, qry->data); ++ + if (PQntuples(res) > 0) + fprintf(OPF, "--\n-- Tablespaces\n--\n\n"); + +@@ -994,6 +1008,7 @@ dumpTablespaces(PGconn *conn) + char *spcacl = PQgetvalue(res, i, 3); + char *spcoptions = PQgetvalue(res, i, 4); + char *spccomment = PQgetvalue(res, i, 5); ++ char *spcseclabel = PQgetvalue(res, i, 6); + char *fspcname; + + /* needed for buildACLCommands() */ +@@ -1010,6 +1025,10 @@ dumpTablespaces(PGconn *conn) + appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n", + fspcname, spcoptions); + ++ if (security_label && strlen(spcseclabel) > 0) ++ appendPQExpBuffer(buf, "ALTER TABLESPACE %s SECURITY LABEL TO '%s';\n", ++ fspcname, spcseclabel); ++ + if (!skip_acls && + !buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, spcowner, + "", server_version, buf)) +@@ -1153,48 +1172,48 @@ dumpCreateDB(PGconn *conn) + + /* Now collect all the information about databases to dump */ + if (server_version >= 80400) +- res = executeQuery(conn, +- "SELECT datname, " ++ appendPQExpBuffer(buf, "SELECT datname, " + "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), " + "pg_encoding_to_char(d.encoding), " + "datcollate, datctype, datfrozenxid, " + "datistemplate, datacl, datconnlimit, " + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " ++ ",%s AS seclabel " + "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " +- "WHERE datallowconn ORDER BY 1"); ++ "WHERE datallowconn ORDER BY 1", ++ security_label ? "d.security_label" : "NULL"); + else if (server_version >= 80100) +- res = executeQuery(conn, +- "SELECT datname, " ++ appendPQExpBuffer(buf, "SELECT datname, " + "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), " + "pg_encoding_to_char(d.encoding), " + "null::text AS datcollate, null::text AS datctype, datfrozenxid, " + "datistemplate, datacl, datconnlimit, " + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " ++ ",NULL AS seclabel " + "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " + "WHERE datallowconn ORDER BY 1"); + else if (server_version >= 80000) +- res = executeQuery(conn, +- "SELECT datname, " ++ appendPQExpBuffer(buf, "SELECT datname, " + "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " + "pg_encoding_to_char(d.encoding), " + "null::text AS datcollate, null::text AS datctype, datfrozenxid, " + "datistemplate, datacl, -1 as datconnlimit, " + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " ++ ",NULL AS seclabel " + "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " + "WHERE datallowconn ORDER BY 1"); + else if (server_version >= 70300) +- res = executeQuery(conn, +- "SELECT datname, " ++ appendPQExpBuffer(buf, "SELECT datname, " + "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " + "pg_encoding_to_char(d.encoding), " + "null::text AS datcollate, null::text AS datctype, datfrozenxid, " + "datistemplate, datacl, -1 as datconnlimit, " + "'pg_default' AS dattablespace " ++ ",NULL AS seclabel " + "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " + "WHERE datallowconn ORDER BY 1"); + else if (server_version >= 70100) +- res = executeQuery(conn, +- "SELECT datname, " ++ appendPQExpBuffer(buf, "SELECT datname, " + "coalesce(" + "(select usename from pg_shadow where usesysid=datdba), " + "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " +@@ -1202,6 +1221,7 @@ dumpCreateDB(PGconn *conn) + "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, " + "datistemplate, '' as datacl, -1 as datconnlimit, " + "'pg_default' AS dattablespace " ++ ",NULL AS seclabel " + "FROM pg_database d " + "WHERE datallowconn ORDER BY 1"); + else +@@ -1210,18 +1230,20 @@ 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, +- "SELECT datname, " ++ appendPQExpBuffer(buf, "SELECT datname, " + "(select usename from pg_shadow where usesysid=datdba), " + "pg_encoding_to_char(d.encoding), " + "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, " + "'f' as datistemplate, " + "'' as datacl, -1 as datconnlimit, " + "'pg_default' AS dattablespace " ++ ",NULL AS seclabel " + "FROM pg_database d " + "ORDER BY 1"); + } + ++ res = PQexec(conn, buf->data); ++ + for (i = 0; i < PQntuples(res); i++) + { + char *dbname = PQgetvalue(res, i, 0); +@@ -1234,6 +1256,7 @@ dumpCreateDB(PGconn *conn) + char *dbacl = PQgetvalue(res, i, 7); + char *dbconnlimit = PQgetvalue(res, i, 8); + char *dbtablespace = PQgetvalue(res, i, 9); ++ char *dbseclabel = PQgetvalue(res, i, 10); + char *fdbname; + + fdbname = strdup(fmtId(dbname)); +@@ -1309,6 +1332,9 @@ dumpCreateDB(PGconn *conn) + appendPQExpBuffer(buf, ";\n"); + } + } ++ if (security_label && strlen(dbseclabel) > 0) ++ appendPQExpBuffer(buf, "ALTER DATABASE %s SECURITY LABEL TO '%s';\n", ++ dbname, dbseclabel); + + if (!skip_acls && + !buildACLCommands(fdbname, NULL, "DATABASE", dbacl, dbowner, +diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c +index b0bcbc2..cdb2592 100644 +--- a/src/bin/pg_dump/pg_restore.c ++++ b/src/bin/pg_dump/pg_restore.c +@@ -76,6 +76,7 @@ main(int argc, char **argv) + static int no_data_for_failed_tables = 0; + static int outputNoTablespaces = 0; + static int use_setsessauth = 0; ++ static int no_security_label = 0; + + struct option cmdopts[] = { + {"clean", 0, NULL, 'c'}, +@@ -116,6 +117,7 @@ main(int argc, char **argv) + {"no-tablespaces", no_argument, &outputNoTablespaces, 1}, + {"role", required_argument, NULL, 2}, + {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, ++ {"no-security-label", no_argument, &no_security_label, 1}, + + {NULL, 0, NULL, 0} + }; +@@ -262,6 +264,8 @@ main(int argc, char **argv) + outputNoTablespaces = 1; + else if (strcmp(optarg, "use-set-session-authorization") == 0) + use_setsessauth = 1; ++ else if (strcmp(optarg, "no-security-label") == 0) ++ no_security_label = 1; + else + { + fprintf(stderr, +@@ -326,6 +330,7 @@ main(int argc, char **argv) + opts->noDataForFailedTables = no_data_for_failed_tables; + opts->noTablespace = outputNoTablespaces; + opts->use_setsessauth = use_setsessauth; ++ opts->noSecLabel = no_security_label; + + if (opts->formatName) + { +@@ -437,6 +442,7 @@ usage(const char *progname) + " ALTER OWNER commands to set ownership\n")); + printf(_(" -1, --single-transaction\n" + " restore as a single transaction\n")); ++ printf(_(" --no-security-label skip restoration of security labels\n")); + + printf(_("\nConnection options:\n")); + printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); +diff --git a/src/include/access/htup.h b/src/include/access/htup.h +index d87e888..270ff67 100644 +--- a/src/include/access/htup.h ++++ b/src/include/access/htup.h +@@ -163,7 +163,7 @@ typedef HeapTupleHeaderData *HeapTupleHeader; + #define HEAP_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */ + #define HEAP_HASEXTERNAL 0x0004 /* has external stored attribute(s) */ + #define HEAP_HASOID 0x0008 /* has an object-id field */ +-/* bit 0x0010 is available */ ++#define HEAP_HASSECID 0x0010 /* has an security-id field */ + #define HEAP_COMBOCID 0x0020 /* t_cid is a combo cid */ + #define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */ + #define HEAP_XMAX_SHARED_LOCK 0x0080 /* xmax is shared locker */ +@@ -292,6 +292,9 @@ do { \ + (tup)->t_choice.t_datum.datum_typmod = (typmod) \ + ) + ++#define HeapTupleHeaderHasOid(tup) \ ++ ((tup)->t_infomask & HEAP_HASOID) ++ + #define HeapTupleHeaderGetOid(tup) \ + ( \ + ((tup)->t_infomask & HEAP_HASOID) ? \ +@@ -351,6 +354,25 @@ do { \ + (tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \ + ) + ++#define HeapTupleHeaderHasSecid(tup) \ ++ ((tup)->t_infomask & HEAP_HASSECID) ++ ++#define HeapTupleHeaderGetSecid(tup) \ ++ ( \ ++ HeapTupleHeaderHasSecid(tup) \ ++ ? (*(Oid *)((char *)(tup) + (tup)->t_hoff \ ++ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \ ++ - sizeof(Oid))) \ ++ : InvalidOid \ ++ ) ++ ++#define HeapTupleHeaderSetSecid(tup, secid) \ ++ do { \ ++ Assert(HeapTupleHeaderHasSecid(tup)); \ ++ *((Oid *)((char *)(tup) + (tup)->t_hoff \ ++ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \ ++ - sizeof(Oid))) = (secid); \ ++ } while(0) + + /* + * BITMAPLEN(NATTS) - +@@ -545,12 +567,23 @@ typedef HeapTupleData *HeapTuple; + #define HeapTupleClearHeapOnly(tuple) \ + HeapTupleHeaderClearHeapOnly((tuple)->t_data) + ++#define HeapTupleHasOid(tuple) \ ++ HeapTupleHeaderHasOid((tuple)->t_data) ++ + #define HeapTupleGetOid(tuple) \ + HeapTupleHeaderGetOid((tuple)->t_data) + + #define HeapTupleSetOid(tuple, oid) \ + HeapTupleHeaderSetOid((tuple)->t_data, (oid)) + ++#define HeapTupleHasSecid(tuple) \ ++ HeapTupleHeaderHasSecid((tuple)->t_data) ++ ++#define HeapTupleGetSecid(tuple) \ ++ HeapTupleHeaderGetSecid((tuple)->t_data) ++ ++#define HeapTupleSetSecid(tuple, secid) \ ++ HeapTupleHeaderSetSecid((tuple)->t_data, (secid)) + + /* + * WAL record definitions for heapam.c's WAL operations +diff --git a/src/include/access/sysattr.h b/src/include/access/sysattr.h +index 59cd2cd..ad5903b 100644 +--- a/src/include/access/sysattr.h ++++ b/src/include/access/sysattr.h +@@ -25,7 +25,8 @@ + #define MaxTransactionIdAttributeNumber (-5) + #define MaxCommandIdAttributeNumber (-6) + #define TableOidAttributeNumber (-7) +-#define FirstLowInvalidHeapAttributeNumber (-8) ++#define SecurityLabelAttributeNumber (-8) ++#define FirstLowInvalidHeapAttributeNumber (-9) + + + #endif /* SYSATTR_H */ +diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h +index 53e0be6..dea713b 100644 +--- a/src/include/access/tupdesc.h ++++ b/src/include/access/tupdesc.h +@@ -75,13 +75,14 @@ typedef struct tupleDesc + Oid tdtypeid; /* composite type ID for tuple type */ + int32 tdtypmod; /* typmod for tuple type */ + bool tdhasoid; /* tuple has oid attribute in its header */ ++ bool tdhassecid; /* tuple has security id in its header */ + int tdrefcount; /* reference count, or -1 if not counting */ + } *TupleDesc; + + +-extern TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid); ++extern TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid, bool hassecid); + +-extern TupleDesc CreateTupleDesc(int natts, bool hasoid, ++extern TupleDesc CreateTupleDesc(int natts, bool hasoid, bool hassecid, + Form_pg_attribute *attrs); + + extern TupleDesc CreateTupleDescCopy(TupleDesc tupdesc); +diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h +index 49a32e3..f088876 100644 +--- a/src/include/bootstrap/bootstrap.h ++++ b/src/include/bootstrap/bootstrap.h +@@ -24,6 +24,7 @@ typedef enum + BgWriterProcess, + WalWriterProcess, + WalReceiverProcess, ++ SecurityWorkerProcess, + + NUM_AUXPROCTYPES /* Must be last! */ + } AuxProcType; +diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h +index 8292273..e2a86e8 100644 +--- a/src/include/catalog/heap.h ++++ b/src/include/catalog/heap.h +@@ -61,7 +61,8 @@ extern Oid heap_create_with_catalog(const char *relname, + OnCommitAction oncommit, + Datum reloptions, + bool use_user_acl, +- bool allow_system_table_mods); ++ bool allow_system_table_mods, ++ Oid *secLabels); + + extern void heap_drop_with_catalog(Oid relid); + +@@ -75,13 +76,15 @@ extern List *heap_truncate_find_FKs(List *relationIds); + + extern void InsertPgAttributeTuple(Relation pg_attribute_rel, + Form_pg_attribute new_attribute, +- CatalogIndexState indstate); ++ CatalogIndexState indstate, ++ Oid securityId); + + extern void InsertPgClassTuple(Relation pg_class_desc, + Relation new_rel_desc, + Oid new_rel_oid, + Datum relacl, +- Datum reloptions); ++ Datum reloptions, ++ Oid securityId); + + extern List *AddRelationNewConstraints(Relation rel, + List *newColDefaults, +@@ -106,10 +109,13 @@ extern void RemoveAttrDefaultById(Oid attrdefId); + extern void RemoveStatistics(Oid relid, AttrNumber attnum); + + extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, +- bool relhasoids); ++ bool relhasoids, bool relhassecids); + + extern Form_pg_attribute SystemAttributeByName(const char *attname, +- bool relhasoids); ++ bool relhasoids, bool relhassecids); ++ ++extern bool SystemAttributeWritable(AttrNumber attno, ++ bool relhasoids, bool relhassecids); + + extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, + bool allow_system_table_mods); +diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h +index 4f437fd..069256f 100644 +--- a/src/include/catalog/indexing.h ++++ b/src/include/catalog/indexing.h +@@ -255,6 +255,11 @@ DECLARE_UNIQUE_INDEX(pg_type_oid_index, 2703, on pg_type using btree(oid oid_ops + 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_seclabel_secid_index, 3401, on pg_seclabel using btree(secid oid_ops, datid oid_ops, relid oid_ops)); ++#define SecLabelSecidIndexId 3401 ++DECLARE_INDEX(pg_seclabel_label_index, 3402, on pg_seclabel using btree(datid oid_ops, relid oid_ops, label text_ops)); ++#define SecLabelLabelIndexId 3402 ++ + DECLARE_UNIQUE_INDEX(pg_foreign_data_wrapper_oid_index, 112, on pg_foreign_data_wrapper using btree(oid oid_ops)); + #define ForeignDataWrapperOidIndexId 112 + +diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h +index 5ea514d..0f07482 100644 +--- a/src/include/catalog/pg_class.h ++++ b/src/include/catalog/pg_class.h +@@ -60,6 +60,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO + */ + int2 relchecks; /* # of CHECK constraints for class */ + bool relhasoids; /* T if we generate OIDs for rows of rel */ ++ bool relhassecids; /* T if we generate SIDs for rows of rel */ + bool relhaspkey; /* has (or has had) PRIMARY KEY index */ + bool relhasexclusion; /* has (or has had) exclusion constraint */ + bool relhasrules; /* has (or has had) any rules */ +@@ -93,7 +94,7 @@ typedef FormData_pg_class *Form_pg_class; + * ---------------- + */ + +-#define Natts_pg_class 27 ++#define Natts_pg_class 28 + #define Anum_pg_class_relname 1 + #define Anum_pg_class_relnamespace 2 + #define Anum_pg_class_reltype 3 +@@ -113,14 +114,15 @@ typedef FormData_pg_class *Form_pg_class; + #define Anum_pg_class_relnatts 17 + #define Anum_pg_class_relchecks 18 + #define Anum_pg_class_relhasoids 19 +-#define Anum_pg_class_relhaspkey 20 +-#define Anum_pg_class_relhasexclusion 21 +-#define Anum_pg_class_relhasrules 22 +-#define Anum_pg_class_relhastriggers 23 +-#define Anum_pg_class_relhassubclass 24 +-#define Anum_pg_class_relfrozenxid 25 +-#define Anum_pg_class_relacl 26 +-#define Anum_pg_class_reloptions 27 ++#define Anum_pg_class_relhassecids 20 ++#define Anum_pg_class_relhaspkey 21 ++#define Anum_pg_class_relhasexclusion 22 ++#define Anum_pg_class_relhasrules 23 ++#define Anum_pg_class_relhastriggers 24 ++#define Anum_pg_class_relhassubclass 25 ++#define Anum_pg_class_relfrozenxid 26 ++#define Anum_pg_class_relacl 27 ++#define Anum_pg_class_reloptions 28 + + /* ---------------- + * initial contents of pg_class +@@ -132,13 +134,13 @@ typedef FormData_pg_class *Form_pg_class; + */ + + /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ +-DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f f r 28 0 t f f f f f 3 _null_ _null_ )); ++DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f f r 28 0 t t f f f f f 3 _null_ _null_ )); + DESCR(""); +-DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f f r 19 0 f f f f f f 3 _null_ _null_ )); ++DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f f r 19 0 f t f f f f f 3 _null_ _null_ )); + DESCR(""); +-DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f f r 25 0 t f f f f f 3 _null_ _null_ )); ++DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f f r 25 0 t t f f f f f 3 _null_ _null_ )); + DESCR(""); +-DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f f r 27 0 t f f f f f 3 _null_ _null_ )); ++DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f f r 28 0 t t f f f f f 3 _null_ _null_ )); + DESCR(""); + + #define RELKIND_INDEX 'i' /* secondary index */ +diff --git a/src/include/catalog/pg_conversion_fn.h b/src/include/catalog/pg_conversion_fn.h +index d40dea6..add5fd9 100644 +--- a/src/include/catalog/pg_conversion_fn.h ++++ b/src/include/catalog/pg_conversion_fn.h +@@ -17,7 +17,7 @@ + extern Oid ConversionCreate(const char *conname, Oid connamespace, + Oid conowner, + int32 conforencoding, int32 contoencoding, +- Oid conproc, bool def); ++ Oid conproc, bool def, Oid securityId); + extern void RemoveConversionById(Oid conversionOid); + extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding); + +diff --git a/src/include/catalog/pg_largeobject.h b/src/include/catalog/pg_largeobject.h +index c4c4a26..6025f56 100644 +--- a/src/include/catalog/pg_largeobject.h ++++ b/src/include/catalog/pg_largeobject.h +@@ -51,9 +51,10 @@ typedef FormData_pg_largeobject *Form_pg_largeobject; + #define Anum_pg_largeobject_pageno 2 + #define Anum_pg_largeobject_data 3 + +-extern Oid LargeObjectCreate(Oid loid); ++extern Oid LargeObjectCreate(Oid loid, Oid securityId); + extern void LargeObjectDrop(Oid loid); + extern void LargeObjectAlterOwner(Oid loid, Oid newOwnerId); ++extern void LargeObjectAlterSecLabel(Oid loid, char *new_label); + extern bool LargeObjectExists(Oid loid); + + #endif /* PG_LARGEOBJECT_H */ +diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h +index 425f039..0f8043d 100644 +--- a/src/include/catalog/pg_namespace.h ++++ b/src/include/catalog/pg_namespace.h +@@ -77,6 +77,6 @@ DESCR("standard public schema"); + /* + * prototypes for functions in pg_namespace.c + */ +-extern Oid NamespaceCreate(const char *nspName, Oid ownerId); ++extern Oid NamespaceCreate(const char *nspName, Oid ownerId, Oid secid); + + #endif /* PG_NAMESPACE_H */ +diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h +index f2751a4..d7e7db8 100644 +--- a/src/include/catalog/pg_proc.h ++++ b/src/include/catalog/pg_proc.h +@@ -3719,6 +3719,10 @@ DESCR("current user privilege on role by role name"); + DATA(insert OID = 2710 ( pg_has_role PGNSP PGUID 12 1 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ pg_has_role_id _null_ _null_ _null_ )); + DESCR("current user privilege on role by role oid"); + ++/* SE-PostgreSQL related stuff */ ++DATA(insert OID = 3405 ( sepgsql_tuple_perms PGNSP PGUID 12 0 0 0 f f f t f v 4 0 16 "26 2249 23 16" _null_ _null_ _null_ _null_ sepgsql_tuple_perms _null_ _null_ _null_ )); ++DATA(insert OID = 3406 ( seclabel_to_secid PGNSP PGUID 12 0 0 0 f f f t f v 1 0 26 "2249" _null_ _null_ _null_ _null_ seclabel_to_secid _null_ _null_ _null_ )); ++ + DATA(insert OID = 1269 ( pg_column_size PGNSP PGUID 12 1 0 0 f f f t f s 1 0 23 "2276" _null_ _null_ _null_ _null_ pg_column_size _null_ _null_ _null_ )); + DESCR("bytes required to store the value, perhaps with compression"); + DATA(insert OID = 2322 ( pg_tablespace_size PGNSP PGUID 12 1 0 0 f f f t f v 1 0 20 "26" _null_ _null_ _null_ _null_ pg_tablespace_size_oid _null_ _null_ _null_ )); +diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h +index c886f81..f2351c1 100644 +--- a/src/include/catalog/pg_proc_fn.h ++++ b/src/include/catalog/pg_proc_fn.h +@@ -37,7 +37,8 @@ extern Oid ProcedureCreate(const char *procedureName, + List *parameterDefaults, + Datum proconfig, + float4 procost, +- float4 prorows); ++ float4 prorows, ++ Oid prosecid); + + extern bool function_parse_error_transpose(const char *prosrc); + +diff --git a/src/include/catalog/pg_seclabel.h b/src/include/catalog/pg_seclabel.h +new file mode 100644 +index 0000000..21b25de +--- /dev/null ++++ b/src/include/catalog/pg_seclabel.h +@@ -0,0 +1,79 @@ ++/* ++ * pg_seclabel.h ++ * Definition of the security label relation (pg_seclabel) ++ * ++ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group ++ * Portions Copyright (c) 1994, Regents of the University of California ++ */ ++#ifndef PG_SECLABEL_H ++#define PG_SECLABEL_H ++ ++#include "catalog/genbki.h" ++ ++#include "access/htup.h" ++#include "access/skey.h" ++#include "utils/relcache.h" ++ ++#define SecLabelRelationId 3400 ++ ++CATALOG(pg_seclabel,3400) BKI_SHARED_RELATION BKI_WITHOUT_OIDS ++{ ++ /* Identifier of the security label */ ++ Oid secid; ++ ++ /* OID of the database which referes the entry */ ++ Oid datid; ++ ++ /* OID of the table which refers the entry */ ++ Oid relid; ++ ++ /* Text representation of the security label */ ++ text label; ++} FormData_pg_seclabel; ++ ++/* ++ * Form_pg_seclabel corresponds to a pointer to a tuple with ++ * the format of pg_seclabel relation. ++ */ ++typedef FormData_pg_seclabel *Form_pg_seclabel; ++ ++/* ++ * Compiler constants for pg_seclabel ++ */ ++#define Natts_pg_seclabel 4 ++#define Anum_pg_seclabel_secid 1 ++#define Anum_pg_seclabel_datid 2 ++#define Anum_pg_seclabel_relid 3 ++#define Anum_pg_seclabel_label 4 ++ ++/* ++ * Functions to translate between security label and identifier ++ */ ++extern bool ignore_security_label_input; ++ ++extern bool seclabelCatalogHasSysAttr(Oid relOid); ++extern void seclabelPostBootstrap(void); ++extern void seclabelOnCreateDatabase(Oid src_datOid, Oid dst_datOid); ++extern void seclabelOnDropDatabase(Oid datOid); ++extern void seclabelOnDropTable(Oid relOid); ++ ++extern Oid *seclabelMakeRelationDefaults(TupleDesc tupdesc, List *supOids); ++extern Oid *seclabelMakeToastDefaults(TupleDesc tupdesc, Oid relOid); ++ ++extern Oid seclabelGetNewSecid(Relation rel, HeapTuple tuple); ++ ++extern Oid seclabelRawInput(Oid relOid, char *seclabel); ++extern char *seclabelRawOutput(Oid relOid, Oid secid); ++extern Oid seclabelTransInput(Oid relOid, char *seclabel); ++extern char *seclabelTransOutput(Oid relOid, Oid secid); ++ ++extern Oid seclabelMoveSecid(Oid dst_relid, Oid src_relid, Oid secid); ++extern bool seclabelCompareSecid(Oid relid1, Oid secid1, ++ Oid relid2, Oid secid2); ++ ++extern Datum seclabelSysattOutput(Oid relOid, HeapTuple tuple); ++ ++extern void seclabelRelationReclaim(Oid relOid); ++extern Datum seclabel_to_secid(PG_FUNCTION_ARGS); ++ ++#endif /* PG_SECLABEL_H */ +diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h +index 5cf90af..1ca2dd4 100644 +--- a/src/include/catalog/pg_type_fn.h ++++ b/src/include/catalog/pg_type_fn.h +@@ -50,7 +50,8 @@ extern Oid TypeCreate(Oid newTypeOid, + char storage, + int32 typeMod, + int32 typNDims, +- bool typeNotNull); ++ bool typeNotNull, ++ Oid securityId); + + extern void GenerateTypeDependencies(Oid typeNamespace, + Oid typeObjectId, +diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h +index 95f86d3..ef9cd9b 100644 +--- a/src/include/catalog/toasting.h ++++ b/src/include/catalog/toasting.h +@@ -61,5 +61,8 @@ DECLARE_TOAST(pg_shdescription, 2846, 2847); + DECLARE_TOAST(pg_db_role_setting, 2966, 2967); + #define PgDbRoleSettingToastTable 2966 + #define PgDbRoleSettingToastIndex 2967 ++DECLARE_TOAST(pg_seclabel, 3403, 3404); ++#define PgSecLabelToastTable 3403 ++#define PgSecLabelToastIndex 3404 + + #endif /* TOASTING_H */ +diff --git a/src/include/commands/alter.h b/src/include/commands/alter.h +index b1e04fb..6cd19ba 100644 +--- a/src/include/commands/alter.h ++++ b/src/include/commands/alter.h +@@ -19,5 +19,6 @@ + extern void ExecRenameStmt(RenameStmt *stmt); + extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt); + extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt); ++extern void ExecAlterSecLabelStmt(AlterSecLabelStmt *stmt); + + #endif /* ALTER_H */ +diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h +index 542fc27..874e07a 100644 +--- a/src/include/commands/dbcommands.h ++++ b/src/include/commands/dbcommands.h +@@ -58,6 +58,7 @@ extern void RenameDatabase(const char *oldname, const char *newname); + extern void AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel); + extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt); + extern void AlterDatabaseOwner(const char *dbname, Oid newOwnerId); ++extern void AlterDatabaseSecLabel(const char *dbname, char *new_label); + + extern Oid get_database_oid(const char *dbname); + extern char *get_database_name(Oid dbid); +diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h +index e8dbe81..7fc4922 100644 +--- a/src/include/commands/defrem.h ++++ b/src/include/commands/defrem.h +@@ -60,6 +60,8 @@ extern void SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType); + extern void RenameFunction(List *name, List *argtypes, const char *newname); + extern void AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId); + extern void AlterFunctionOwner_oid(Oid procOid, Oid newOwnerId); ++extern void AlterFunctionSecLabel(List *name, List *argtypes, ++ bool isagg, char *new_label); + extern void AlterFunction(AlterFunctionStmt *stmt); + extern void CreateCast(CreateCastStmt *stmt); + extern void DropCast(DropCastStmt *stmt); +diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h +index c914bd5..edd5abd 100644 +--- a/src/include/commands/schemacmds.h ++++ b/src/include/commands/schemacmds.h +@@ -26,5 +26,6 @@ extern void RemoveSchemaById(Oid schemaOid); + extern void RenameSchema(const char *oldname, const char *newname); + extern void AlterSchemaOwner(const char *name, Oid newOwnerId); + extern void AlterSchemaOwner_oid(Oid schemaOid, Oid newOwnerId); ++extern void AlterSchemaSecLabel(const char *name, char *new_label); + + #endif /* SCHEMACMDS_H */ +diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h +index f9269cc..a531f45 100644 +--- a/src/include/commands/tablecmds.h ++++ b/src/include/commands/tablecmds.h +@@ -35,6 +35,13 @@ extern void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, + Oid oldNspOid, Oid newNspOid, + bool hasDependEntry); + ++extern void AlterRelationSecLabel(RangeVar *relation, const char *attname, ++ ObjectType objtype, char *new_label); ++extern void AlterRelationSecLabelInternal(Oid relOid, Oid securityId, ++ int expected_parents); ++extern void AlterAttributeSecLabelInternal(Oid relOid, const char *attname, ++ Oid securityId, int expected_parents); ++ + extern void CheckTableNotInUse(Relation rel, const char *stmt); + + extern void ExecuteTruncate(TruncateStmt *stmt); +diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h +index cf005ee..e9e8a55 100644 +--- a/src/include/commands/tablespace.h ++++ b/src/include/commands/tablespace.h +@@ -44,6 +44,7 @@ extern void DropTableSpace(DropTableSpaceStmt *stmt); + extern void RenameTableSpace(const char *oldname, const char *newname); + extern void AlterTableSpaceOwner(const char *name, Oid newOwnerId); + extern void AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt); ++extern void AlterTableSpaceSecLabel(const char *tspaceName, char *newLabel); + + extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo); + +diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h +index 8e5b610..f8c5872 100644 +--- a/src/include/commands/typecmds.h ++++ b/src/include/commands/typecmds.h +@@ -43,5 +43,7 @@ extern void AlterTypeNamespace(List *names, const char *newschema); + extern void AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, + bool isImplicitArray, + bool errorOnTableType); ++extern void AlterTypeSecLabel(List *name, char *new_label); ++extern void AlterTypeSecLabelInternal(Oid typeOid, Oid securityId); + + #endif /* TYPECMDS_H */ +diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h +index 820314c..7873b44 100644 +--- a/src/include/executor/executor.h ++++ b/src/include/executor/executor.h +@@ -131,8 +131,8 @@ extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable, + /* + * prototypes from functions in execJunk.c + */ +-extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid, +- TupleTableSlot *slot); ++extern JunkFilter *ExecInitJunkFilter(List *targetList, ++ bool hasoid, bool hassecid, TupleTableSlot *slot); + extern JunkFilter *ExecInitJunkFilterConversion(List *targetList, + TupleDesc cleanTupType, + TupleTableSlot *slot); +@@ -164,6 +164,7 @@ extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, + int instrument_options); + extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid); + extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids); ++extern bool ExecContextForcesSecids(PlanState *planstate, bool *hassecid); + extern void ExecConstraints(ResultRelInfo *resultRelInfo, + TupleTableSlot *slot, EState *estate); + extern TupleTableSlot *EvalPlanQual(EState *estate, EPQState *epqstate, +@@ -234,8 +235,8 @@ extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate); + extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate); + extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, + TupleDesc tupType); +-extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid); +-extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid); ++extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid, bool hassecid); ++extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hassecid); + extern TupleDesc ExecTypeFromExprList(List *exprList); + extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg); + +diff --git a/src/include/fmgr.h b/src/include/fmgr.h +index d1a0dc1..e9de809 100644 +--- a/src/include/fmgr.h ++++ b/src/include/fmgr.h +@@ -51,6 +51,7 @@ typedef struct FmgrInfo + bool fn_retset; /* function returns a set */ + unsigned char fn_stats; /* collect stats if track_functions > this */ + void *fn_extra; /* extra space for use by handler */ ++ char *fn_seclabel; /* function is trusted procedure, or NULL */ + MemoryContext fn_mcxt; /* memory context to store fn_extra in */ + fmNodePtr fn_expr; /* expression parse tree for call, or NULL */ + } FmgrInfo; +diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h +index 1b5e476..37ffdfa 100644 +--- a/src/include/nodes/nodes.h ++++ b/src/include/nodes/nodes.h +@@ -346,6 +346,7 @@ typedef enum NodeTag + T_AlterUserMappingStmt, + T_DropUserMappingStmt, + T_AlterTableSpaceOptionsStmt, ++ T_AlterSecLabelStmt, + + /* + * TAGS FOR PARSE TREE NODES (parsenodes.h) +diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h +index b591073..53609e8 100644 +--- a/src/include/nodes/parsenodes.h ++++ b/src/include/nodes/parsenodes.h +@@ -731,6 +731,7 @@ typedef struct RangeTblEntry + Oid checkAsUser; /* if valid, check access as this role */ + Bitmapset *selectedCols; /* columns needing SELECT permission */ + Bitmapset *modifiedCols; /* columns needing INSERT/UPDATE permission */ ++ uint32 rowlvPerms; /* permissions for row-level access controls */ + } RangeTblEntry; + + /* +@@ -1134,6 +1135,8 @@ typedef enum AlterTableType + AT_DropCluster, /* SET WITHOUT CLUSTER */ + AT_AddOids, /* SET WITH OIDS */ + AT_DropOids, /* SET WITHOUT OIDS */ ++ AT_AddSecLabel, /* SET WITH SECURITY LABEL */ ++ AT_DropSecLabel, /* SET WITHOUT SECURITY LABEL */ + AT_SetTableSpace, /* SET TABLESPACE */ + AT_SetRelOptions, /* SET (...) -- AM specific parameters */ + AT_ResetRelOptions, /* RESET (...) -- AM specific parameters */ +@@ -2073,6 +2076,20 @@ typedef struct AlterOwnerStmt + char *newowner; /* the new owner */ + } AlterOwnerStmt; + ++/* ---------------------- ++ * Alter Security Label Statement ++ * ---------------------- ++ */ ++typedef struct AlterSecLabelStmt ++{ ++ NodeTag type; ++ ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */ ++ RangeVar *relation; /* in case it's a table */ ++ List *object; /* in case it's some other object */ ++ List *objarg; /* argument types, if applicable */ ++ char *addname; /* additional name if needed */ ++ Value *secLabel; /* the new security label */ ++} AlterSecLabelStmt; + + /* ---------------------- + * Create Rule Statement +diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h +index 49d4b6c..13c88a1 100644 +--- a/src/include/parser/kwlist.h ++++ b/src/include/parser/kwlist.h +@@ -208,6 +208,7 @@ PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD) + PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD) + PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD) + PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD) ++PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD) + PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD) + PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD) + PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD) +diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in +index 684aed4..2080c95 100644 +--- a/src/include/pg_config.h.in ++++ b/src/include/pg_config.h.in +@@ -412,6 +412,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SECURITY_PAM_APPL_H + ++/* Define to 1 if you enable SELinux support */ ++#undef HAVE_SELINUX ++ + /* Define to 1 if you have the `setproctitle' function. */ + #undef HAVE_SETPROCTITLE + +diff --git a/src/include/sepgsql/hooks.h b/src/include/sepgsql/hooks.h +new file mode 100644 +index 0000000..4e983f8 +--- /dev/null ++++ b/src/include/sepgsql/hooks.h +@@ -0,0 +1,284 @@ ++/* ++ * sepgsql/hooks.h ++ * ++ * Header of SE-PostgreSQL Hooks ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#ifndef SEPGSQL_HOOKS_H ++#define SEPGSQL_HOOKS_H ++ ++#include "nodes/plannodes.h" ++#include "nodes/relation.h" ++#include "storage/fd.h" ++#include "utils/acl.h" ++#include "utils/rel.h" ++#include "utils/snapshot.h" ++ ++/* ++ * misc.c ++ */ ++extern char *sepgsql_get_client_label(void); ++extern char *sepgsql_set_client_label(char *new_label); ++extern void sepgsql_post_bootstraping(void); ++extern void sepgsql_initialize(void); ++extern bool sepgsql_worker_needed(void); ++extern void sepgsql_worker_main(void); ++ ++/* ++ * database.c ++ */ ++extern Oid sepgsql_database_create(const char *datName, Oid templateOid); ++extern void sepgsql_database_alter(Oid databaseOid); ++extern Oid sepgsql_database_relabel(Oid databaseOid, char *new_label); ++extern void sepgsql_database_drop(Oid databaseOid, bool cascade); ++extern void sepgsql_database_grant(Oid databaseOid); ++extern void sepgsql_database_comment(Oid databaseOid); ++extern void sepgsql_database_connect(Oid databaseOid); ++extern void sepgsql_database_reindex(Oid databaseOid); ++extern void sepgsql_database_getattr(Oid databaseOid); ++ ++/* ++ * schema.c ++ */ ++extern Oid sepgsql_schema_create(const char *nspName, bool is_temp); ++extern void sepgsql_schema_alter(Oid namespaceOid); ++extern Oid sepgsql_schema_relabel(Oid namespaceOid, char *new_label); ++extern void sepgsql_schema_drop(Oid namespaceOid, bool cascade); ++extern void sepgsql_schema_grant(Oid namespaceOid); ++extern bool sepgsql_schema_search(Oid namespaceOid, bool abort); ++extern void sepgsql_schema_comment(Oid namespaceOid); ++ ++/* ++ * relation.c ++ */ ++extern bool sepgsql_relation_perms(Oid relOid, AclMode aclmask, ++ Bitmapset *selectedCols, ++ Bitmapset *modifiedCols, bool abort); ++extern Oid *sepgsql_relation_create(const char *relName, ++ char relkind, ++ TupleDesc tupDesc, ++ Oid namespaceId, ++ List *supOids, ++ bool createAs); ++extern void sepgsql_relation_alter(Oid relationOid); ++extern void sepgsql_relation_alter_schema(Oid relationOid, Oid newSchema); ++extern void sepgsql_relation_alter_rename(Oid relationOid, ++ const char *newName); ++extern void sepgsql_relation_alter_inherit(Oid childOid, Oid parentOid); ++extern Oid sepgsql_relation_relabel(Oid relationOid, char *new_label); ++extern void sepgsql_relation_drop(Oid relationOid, bool cascade); ++extern void sepgsql_relation_getattr(Oid relationOid); ++extern void sepgsql_relation_grant(Oid relationOid); ++extern void sepgsql_relation_comment(Oid relationOid); ++extern bool sepgsql_relation_cluster(Oid relationOid, bool abort); ++extern void sepgsql_relation_truncate(Relation rel); ++extern void sepgsql_relation_lock(Relation rel); ++extern void sepgsql_relation_reindex(Oid relOid); ++extern void sepgsql_view_replace(Oid viewOid); ++extern void sepgsql_index_create(Oid relationOid, Oid namespaceOid); ++extern void sepgsql_index_reindex(Oid indexOid); ++extern void sepgsql_sequence_get_value(Oid sequenceOid); ++extern void sepgsql_sequence_next_value(Oid sequenceOid); ++extern void sepgsql_sequence_set_value(Oid sequenceOid); ++extern void sepgsql_rule_create(Oid relationOid, ++ const char *ruleName); ++extern void sepgsql_rule_drop(Oid relationOid, ++ const char *ruleName, bool cascade); ++extern void sepgsql_rule_comment(Oid relationOid, const char *ruleName); ++extern void sepgsql_trigger_create(Oid relationOid, const char *triggerName, ++ Oid constrrelid, Oid funcOid); ++extern void sepgsql_trigger_alter(Oid relOid, const char *tgName); ++extern void sepgsql_trigger_drop(Oid relOid, const char *tgName, bool cascade); ++extern void sepgsql_trigger_comment(Oid relOid, const char *tgName); ++extern void sepgsql_constraint_comment(Oid relOid, const char *constName); ++ ++/* ++ * attribute.c ++ */ ++extern Oid sepgsql_attribute_create(Oid relOid, const char *attName); ++extern void sepgsql_attribute_alter(Oid relOid, const char *attName); ++extern Oid sepgsql_attribute_relabel(Oid relOid, const char *attName, ++ char *new_label); ++extern void sepgsql_attribute_drop(Oid relOid, const char *attName, bool cascade); ++extern void sepgsql_attribute_grant(Oid relOid, AttrNumber attnum); ++extern void sepgsql_attribute_comment(Oid relOid, AttrNumber attnum); ++ ++/* ++ * proc.c ++ */ ++extern Oid sepgsql_proc_create(const char *proName, Oid replaced, ++ Oid namespaceOid, Oid langageOid); ++extern void sepgsql_proc_alter(Oid procOid); ++extern void sepgsql_proc_alter_rename(Oid procOid, const char *newName); ++extern void sepgsql_proc_alter_schema(Oid procOid, Oid newSchema); ++extern Oid sepgsql_proc_relabel(Oid procOid, char *new_label); ++extern void sepgsql_proc_drop(Oid procOid, bool cascade); ++extern void sepgsql_proc_grant(Oid procOid); ++extern void sepgsql_proc_comment(Oid procOid); ++extern void sepgsql_proc_execute(Oid procOid); ++extern bool sepgsql_proc_be_inlined(HeapTuple protup); ++extern char *sepgsql_proc_domtrans(HeapTuple protup, MemoryContext mcxt); ++extern Oid sepgsql_aggregate_create(const char *aggName, Oid namespaceId, ++ Oid transFunc, Oid finalFunc); ++extern void sepgsql_aggregate_execute(Oid aggOid); ++ ++/* ++ * type.c ++ */ ++extern Oid sepgsql_type_create(const char *typeName, Oid replaced, ++ Oid namespaceId, char typeType, ++ Oid inputFunc, Oid outputFunc, ++ Oid recvFunc, Oid sendFunc, ++ Oid modinFunc, Oid modoutFunc, ++ Oid analyzeFunc); ++extern void sepgsql_type_alter(Oid typeOid); ++extern void sepgsql_type_alter_rename(Oid typeOid, const char *newName); ++extern void sepgsql_type_alter_schema(Oid typeOid, Oid newSchema); ++extern Oid sepgsql_type_relabel(Oid typeOid, char *newLabel); ++extern void sepgsql_type_drop(Oid typeOid, bool cascade); ++extern void sepgsql_type_comment(Oid typeOid); ++extern Oid sepgsql_cast_create(Oid sourceTypeOid, Oid targetTypeOid, ++ char castMethod, Oid castFuncOid); ++extern void sepgsql_cast_drop(Oid srcTypeOid, Oid dstTypeOid, bool cascade); ++extern void sepgsql_cast_comment(Oid srcTypeOid, Oid dstTypeOid); ++ ++/* ++ * tablespace.h ++ */ ++extern Oid sepgsql_tablespace_create(const char *tablespaceName); ++extern void sepgsql_tablespace_alter(Oid tablespaceOid); ++extern Oid sepgsql_tablespace_relabel(Oid tablespaceOid, char *newLabel); ++extern void sepgsql_tablespace_drop(Oid tablespaceOid, bool cascade); ++extern void sepgsql_tablespace_grant(Oid tablespaceOid); ++extern void sepgsql_tablespace_getattr(Oid tablespaceOid); ++extern void sepgsql_tablespace_comment(Oid tablespaceOid); ++ ++/* ++ * operator.h ++ */ ++extern Oid sepgsql_operator_create(const char *operName, Oid replaced, ++ Oid namespaceId, ++ Oid codeFn, Oid restrictFn, Oid joinFn, ++ Oid commutatorOp, Oid negatorOp); ++extern void sepgsql_operator_alter(Oid operOid); ++extern Oid sepgsql_operator_relabel(Oid operOid, char *newLabel); ++extern void sepgsql_operator_drop(Oid operOid, bool cascade); ++extern void sepgsql_operator_comment(Oid operOid); ++ ++extern Oid sepgsql_opclass_create(const char *opcName, Oid namespaceId, ++ Oid typeOid, Oid opfamilyOid, Oid storageOid); ++extern void sepgsql_opclass_alter(Oid opcOid); ++extern void sepgsql_opclass_alter_rename(Oid opcOid, const char *newName); ++extern void sepgsql_opclass_drop(Oid opcOid, bool cascade); ++extern void sepgsql_opclass_comment(Oid opcOid); ++ ++extern Oid sepgsql_opfamily_create(const char *opfName, ++ Oid namespaceId, Oid amOid); ++extern void sepgsql_opfamily_alter(Oid opfOid, bool isDrop, Oid amOid, ++ List *operators, List *procedures); ++extern void sepgsql_opfamily_alter_rename(Oid opfOid, const char *newName); ++extern void sepgsql_opfamily_alter_owner(Oid opfOid, Oid newOwner); ++extern void sepgsql_opfamily_drop(Oid opfOid, bool cascade); ++extern void sepgsql_opfamily_comment(Oid opfOid); ++ ++/* ++ * role.c ++ */ ++extern Oid sepgsql_role_create(const char *roleName); ++extern void sepgsql_role_alter(Oid roleOid); ++extern Oid sepgsql_role_relabel(Oid roleOid, char *newLabel); ++extern void sepgsql_role_drop(Oid roleOid, bool cascade); ++extern void sepgsql_role_grant(Oid roleOid, bool is_grant, List *memberIds); ++extern void sepgsql_role_comment(Oid roleOid); ++ ++/* ++ * blob.c ++ */ ++extern Oid sepgsql_largeobject_create(Oid loid); ++extern void sepgsql_largeobject_alter(Oid loid); ++extern Oid sepgsql_largeobject_relabel(Oid loid, char *newLabel); ++extern void sepgsql_largeobject_drop(Oid loid, bool cascade); ++extern void sepgsql_largeobject_read(Oid loid, Snapshot snapshot); ++extern void sepgsql_largeobject_write(Oid loid, Snapshot snapshot); ++extern Oid sepgsql_largeobject_import(Oid loid, const char *filename); ++extern void sepgsql_largeobject_export(Oid loid, Snapshot snapshot, ++ const char *filename); ++extern void sepgsql_largeobject_grant(Oid loid); ++extern void sepgsql_largeobject_comment(Oid loid); ++ ++/* ++ * conversion.c ++ */ ++extern Oid sepgsql_conversion_create(const char *convName, ++ Oid namespaceId, Oid conversionFunc); ++extern void sepgsql_conversion_alter(Oid convOid); ++extern void sepgsql_conversion_alter_rename(Oid convOid, const char *newName); ++extern void sepgsql_conversion_drop(Oid convOid, bool cascade); ++extern void sepgsql_conversion_comment(Oid convOid); ++ ++/* ++ * tsearch.c ++ */ ++extern Oid sepgsql_ts_config_create(const char *confName, Oid namespaceId); ++extern void sepgsql_ts_config_alter(Oid confOid); ++extern void sepgsql_ts_config_alter_rename(Oid confOid, const char *newName); ++extern void sepgsql_ts_config_drop(Oid confOid, bool cascade); ++extern void sepgsql_ts_config_comment(Oid confOid); ++extern Oid sepgsql_ts_dict_create(const char *dictName, Oid namespaceId); ++extern void sepgsql_ts_dict_alter(Oid dictOid); ++extern void sepgsql_ts_dict_alter_rename(Oid dictOid, const char *newName); ++extern void sepgsql_ts_dict_drop(Oid dictOid, bool cascade); ++extern void sepgsql_ts_dict_comment(Oid dictOid); ++extern Oid sepgsql_ts_parser_create(const char *parseName, Oid namespaceId, ++ Oid startFunc, Oid tokenFunc, Oid endFunc, ++ Oid headlineFunc, Oid lextypeFunc); ++extern void sepgsql_ts_parser_alter_rename(Oid parseOid, const char *newName); ++extern void sepgsql_ts_parser_drop(Oid parseOid, bool cascade); ++extern void sepgsql_ts_parser_comment(Oid parseOid); ++extern Oid sepgsql_ts_template_create(const char *templateName, ++ Oid namespaceId, ++ Oid initFunc, Oid lexizeFunc); ++extern void sepgsql_ts_template_alter_rename(Oid templateOid, ++ const char *newName); ++extern void sepgsql_ts_template_drop(Oid templateOid, bool cascade); ++extern void sepgsql_ts_template_comment(Oid templateOid); ++ ++/* ++ * fdw.c ++ */ ++extern Oid sepgsql_fdw_create(const char *fdwName, Oid validatorFunc); ++extern void sepgsql_fdw_alter(Oid fdwOid, Oid newValidator); ++extern void sepgsql_fdw_drop(Oid fdwOid, bool cascade); ++extern void sepgsql_fdw_grant(Oid fdwOid); ++ ++extern Oid sepgsql_fserver_create(const char *fservName, Oid fdwOid); ++extern void sepgsql_fserver_alter(Oid fservOid); ++extern void sepgsql_fserver_drop(Oid fservOid, bool cascade); ++extern void sepgsql_fserver_grant(Oid fservOid); ++ ++extern Oid sepgsql_user_mapping_create(Oid mappedRoleId, Oid fservOid); ++extern void sepgsql_user_mapping_alter(Oid umapOid); ++extern void sepgsql_user_mapping_drop(Oid umapOid, bool cascade); ++ ++/* ++ * row-level access controls ++ */ ++#define SEPGSQL_ROWLV_FILTER 1 ++#define SEPGSQL_ROWLV_ABORT 2 ++#define SEPGSQL_ROWLV_BYPASS 3 ++ ++extern int sepgsql_rowlv_get_mode(void); ++extern int sepgsql_rowlv_set_mode(int new_mode); ++extern void sepgsql_rowlv_add_policy(PlannerInfo *root, Scan *plan); ++extern uint32 sepgsql_rowlv_permissions(RangeTblEntry *rte); ++ ++extern void sepgsql_proxy_queries(List *queryList); ++ ++extern void sepgsql_tuple_insert(Relation rel, HeapTuple tuple); ++extern void sepgsql_tuple_update(Relation rel, ItemPointer otid, HeapTuple newtup); ++ ++extern Datum sepgsql_tuple_perms(PG_FUNCTION_ARGS); ++ ++#endif /* SEPGSQL_HOOKS_H */ +diff --git a/src/include/sepgsql/sepgsql.h b/src/include/sepgsql/sepgsql.h +new file mode 100644 +index 0000000..ce65466 +--- /dev/null ++++ b/src/include/sepgsql/sepgsql.h +@@ -0,0 +1,298 @@ ++/* ++ * sepgsql/sepgsql.h ++ * ++ * Header of SE-PostgreSQL Internal ++ * ++ * Copyright (C) 2006-2010, NEC Corporation ++ * KaiGai Kohei ++ */ ++#ifndef SEPGSQL_H ++#define SEPGSQL_H ++ ++#include "utils/snapshot.h" ++ ++/* GUC : sepostgresql */ ++extern int sepostgresql_mode; ++ ++#define SEPGSQL_MODE_DEFAULT 1 ++#define SEPGSQL_MODE_ENFORCING 2 ++#define SEPGSQL_MODE_PERMISSIVE 3 ++#define SEPGSQL_MODE_INTERNAL 4 ++#define SEPGSQL_MODE_DISABLED 5 ++ ++/* GUC: sepostgresql_mcstrans */ ++extern bool sepgsql_mcstrans; ++ ++/* GUC: sepostgresql_debug_audit */ ++extern bool sepgsql_debug_audit; ++ ++/* Objject classes and permissions internally used */ ++enum SepgsqlClasses ++{ ++ SEPG_CLASS_PROCESS = 0, ++ SEPG_CLASS_FILE, ++ SEPG_CLASS_DIR, ++ SEPG_CLASS_LNK_FILE, ++ SEPG_CLASS_CHR_FILE, ++ SEPG_CLASS_BLK_FILE, ++ SEPG_CLASS_SOCK_FILE, ++ SEPG_CLASS_FIFO_FILE, ++ SEPG_CLASS_DB_DATABASE, ++ SEPG_CLASS_DB_SCHEMA, ++ SEPG_CLASS_DB_TABLE, ++ SEPG_CLASS_DB_VIEW, ++ SEPG_CLASS_DB_SEQUENCE, ++ SEPG_CLASS_DB_PROCEDURE, ++ SEPG_CLASS_DB_COLUMN, ++ SEPG_CLASS_DB_TUPLE, ++ SEPG_CLASS_DB_BLOB, ++ SEPG_CLASS_DB_LANGUAGE, ++ SEPG_CLASS_MAX, ++}; ++ ++#define SEPG_PROCESS__TRANSITION (1<<0) ++ ++#define SEPG_FILE__READ (1<<0) ++#define SEPG_FILE__WRITE (1<<1) ++#define SEPG_FILE__CREATE (1<<2) ++#define SEPG_FILE__GETATTR (1<<3) ++ ++#define SEPG_DIR__READ (SEPG_FILE__READ) ++#define SEPG_DIR__WRITE (SEPG_FILE__WRITE) ++#define SEPG_DIR__CREATE (SEPG_FILE__CREATE) ++#define SEPG_DIR__GETATTR (SEPG_FILE__GETATTR) ++ ++#define SEPG_LNK_FILE__READ (SEPG_FILE__READ) ++#define SEPG_LNK_FILE__WRITE (SEPG_FILE__WRITE) ++#define SEPG_LNK_FILE__CREATE (SEPG_FILE__CREATE) ++#define SEPG_LNK_FILE__GETATTR (SEPG_FILE__GETATTR) ++ ++#define SEPG_CHR_FILE__READ (SEPG_FILE__READ) ++#define SEPG_CHR_FILE__WRITE (SEPG_FILE__WRITE) ++#define SEPG_CHR_FILE__CREATE (SEPG_FILE__CREATE) ++#define SEPG_CHR_FILE__GETATTR (SEPG_FILE__GETATTR) ++ ++#define SEPG_BLK_FILE__READ (SEPG_FILE__READ) ++#define SEPG_BLK_FILE__WRITE (SEPG_FILE__WRITE) ++#define SEPG_BLK_FILE__CREATE (SEPG_FILE__CREATE) ++#define SEPG_BLK_FILE__GETATTR (SEPG_FILE__GETATTR) ++ ++#define SEPG_SOCK_FILE__READ (SEPG_FILE__READ) ++#define SEPG_SOCK_FILE__WRITE (SEPG_FILE__WRITE) ++#define SEPG_SOCK_FILE__CREATE (SEPG_FILE__CREATE) ++#define SEPG_SOCK_FILE__GETATTR (SEPG_FILE__GETATTR) ++ ++#define SEPG_FIFO_FILE__READ (SEPG_FILE__READ) ++#define SEPG_FIFO_FILE__WRITE (SEPG_FILE__WRITE) ++#define SEPG_FIFO_FILE__CREATE (SEPG_FILE__CREATE) ++#define SEPG_FIFO_FILE__GETATTR (SEPG_FILE__GETATTR) ++ ++#define SEPG_DB_DATABASE__CREATE (1<<0) ++#define SEPG_DB_DATABASE__DROP (1<<1) ++#define SEPG_DB_DATABASE__GETATTR (1<<2) ++#define SEPG_DB_DATABASE__SETATTR (1<<3) ++#define SEPG_DB_DATABASE__RELABELFROM (1<<4) ++#define SEPG_DB_DATABASE__RELABELTO (1<<5) ++#define SEPG_DB_DATABASE__ACCESS (1<<6) ++#define SEPG_DB_DATABASE__LOAD_MODULE (1<<7) ++ ++#define SEPG_DB_SCHEMA__CREATE (SEPG_DB_DATABASE__CREATE) ++#define SEPG_DB_SCHEMA__DROP (SEPG_DB_DATABASE__DROP) ++#define SEPG_DB_SCHEMA__GETATTR (SEPG_DB_DATABASE__GETATTR) ++#define SEPG_DB_SCHEMA__SETATTR (SEPG_DB_DATABASE__SETATTR) ++#define SEPG_DB_SCHEMA__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) ++#define SEPG_DB_SCHEMA__RELABELTO (SEPG_DB_DATABASE__RELABELTO) ++#define SEPG_DB_SCHEMA__SEARCH (1<<6) ++#define SEPG_DB_SCHEMA__ADD_NAME (1<<7) ++#define SEPG_DB_SCHEMA__REMOVE_NAME (1<<8) ++ ++#define SEPG_DB_TABLE__CREATE (SEPG_DB_DATABASE__CREATE) ++#define SEPG_DB_TABLE__DROP (SEPG_DB_DATABASE__DROP) ++#define SEPG_DB_TABLE__GETATTR (SEPG_DB_DATABASE__GETATTR) ++#define SEPG_DB_TABLE__SETATTR (SEPG_DB_DATABASE__SETATTR) ++#define SEPG_DB_TABLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) ++#define SEPG_DB_TABLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) ++#define SEPG_DB_TABLE__SELECT (1<<6) ++#define SEPG_DB_TABLE__UPDATE (1<<7) ++#define SEPG_DB_TABLE__INSERT (1<<8) ++#define SEPG_DB_TABLE__DELETE (1<<9) ++#define SEPG_DB_TABLE__LOCK (1<<10) ++#define SEPG_DB_TABLE__INDEXON (1<<11) ++ ++#define SEPG_DB_SEQUENCE__CREATE (SEPG_DB_DATABASE__CREATE) ++#define SEPG_DB_SEQUENCE__DROP (SEPG_DB_DATABASE__DROP) ++#define SEPG_DB_SEQUENCE__GETATTR (SEPG_DB_DATABASE__GETATTR) ++#define SEPG_DB_SEQUENCE__SETATTR (SEPG_DB_DATABASE__SETATTR) ++#define SEPG_DB_SEQUENCE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) ++#define SEPG_DB_SEQUENCE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) ++#define SEPG_DB_SEQUENCE__GET_VALUE (1<<6) ++#define SEPG_DB_SEQUENCE__NEXT_VALUE (1<<7) ++#define SEPG_DB_SEQUENCE__SET_VALUE (1<<8) ++ ++#define SEPG_DB_VIEW__CREATE (SEPG_DB_DATABASE__CREATE) ++#define SEPG_DB_VIEW__DROP (SEPG_DB_DATABASE__DROP) ++#define SEPG_DB_VIEW__GETATTR (SEPG_DB_DATABASE__GETATTR) ++#define SEPG_DB_VIEW__SETATTR (SEPG_DB_DATABASE__SETATTR) ++#define SEPG_DB_VIEW__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) ++#define SEPG_DB_VIEW__RELABELTO (SEPG_DB_DATABASE__RELABELTO) ++#define SEPG_DB_VIEW__EXPAND (1<<6) ++ ++#define SEPG_DB_PROCEDURE__CREATE (SEPG_DB_DATABASE__CREATE) ++#define SEPG_DB_PROCEDURE__DROP (SEPG_DB_DATABASE__DROP) ++#define SEPG_DB_PROCEDURE__GETATTR (SEPG_DB_DATABASE__GETATTR) ++#define SEPG_DB_PROCEDURE__SETATTR (SEPG_DB_DATABASE__SETATTR) ++#define SEPG_DB_PROCEDURE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) ++#define SEPG_DB_PROCEDURE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) ++#define SEPG_DB_PROCEDURE__EXECUTE (1<<6) ++#define SEPG_DB_PROCEDURE__ENTRYPOINT (1<<7) ++#define SEPG_DB_PROCEDURE__INSTALL (1<<8) ++ ++#define SEPG_DB_COLUMN__CREATE (SEPG_DB_DATABASE__CREATE) ++#define SEPG_DB_COLUMN__DROP (SEPG_DB_DATABASE__DROP) ++#define SEPG_DB_COLUMN__GETATTR (SEPG_DB_DATABASE__GETATTR) ++#define SEPG_DB_COLUMN__SETATTR (SEPG_DB_DATABASE__SETATTR) ++#define SEPG_DB_COLUMN__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) ++#define SEPG_DB_COLUMN__RELABELTO (SEPG_DB_DATABASE__RELABELTO) ++#define SEPG_DB_COLUMN__SELECT (1<<6) ++#define SEPG_DB_COLUMN__UPDATE (1<<7) ++#define SEPG_DB_COLUMN__INSERT (1<<8) ++ ++#define SEPG_DB_TUPLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) ++#define SEPG_DB_TUPLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) ++#define SEPG_DB_TUPLE__SELECT (SEPG_DB_DATABASE__GETATTR) ++#define SEPG_DB_TUPLE__UPDATE (SEPG_DB_DATABASE__SETATTR) ++#define SEPG_DB_TUPLE__INSERT (SEPG_DB_DATABASE__CREATE) ++#define SEPG_DB_TUPLE__DELETE (SEPG_DB_DATABASE__DROP) ++ ++#define SEPG_DB_BLOB__CREATE (SEPG_DB_DATABASE__CREATE) ++#define SEPG_DB_BLOB__DROP (SEPG_DB_DATABASE__DROP) ++#define SEPG_DB_BLOB__GETATTR (SEPG_DB_DATABASE__GETATTR) ++#define SEPG_DB_BLOB__SETATTR (SEPG_DB_DATABASE__SETATTR) ++#define SEPG_DB_BLOB__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) ++#define SEPG_DB_BLOB__RELABELTO (SEPG_DB_DATABASE__RELABELTO) ++#define SEPG_DB_BLOB__READ (1<<6) ++#define SEPG_DB_BLOB__WRITE (1<<7) ++#define SEPG_DB_BLOB__IMPORT (1<<8) ++#define SEPG_DB_BLOB__EXPORT (1<<9) ++ ++#define SEPG_DB_LANGUAGE__CREATE (SEPG_DB_DATABASE__CREATE) ++#define SEPG_DB_LANGUAGE__DROP (SEPG_DB_DATABASE__DROP) ++#define SEPG_DB_LANGUAGE__GETATTR (SEPG_DB_DATABASE__GETATTR) ++#define SEPG_DB_LANGUAGE__SETATTR (SEPG_DB_DATABASE__SETATTR) ++#define SEPG_DB_LANGUAGE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM) ++#define SEPG_DB_LANGUAGE__RELABELTO (SEPG_DB_DATABASE__RELABELTO) ++#define SEPG_DB_LANGUAGE__IMPLEMENTE (1<<6) ++#define SEPG_DB_LANGUAGE__EXECUTE (1<<7) ++ ++/* ++ * sepgsql_sid_t : alternative representation of security context ++ */ ++typedef struct { ++ Oid relid; ++ Oid secid; ++} sepgsql_sid_t; ++ ++struct av_decision; ++ ++/* ++ * selinux.c ++ */ ++extern bool sepgsql_is_enabled(void); ++extern bool sepgsql_get_enforce(void); ++extern const char *sepgsql_show_mode(void); ++ ++extern Size sepgsql_shmem_size(void); ++ ++extern void sepgsql_audit_log(bool denied, ++ char *scontext, ++ char *tcontext, ++ uint16 tclass, ++ uint32 audited, ++ const char *audit_name); ++extern void sepgsql_compute_avd(char *scontext, ++ char *tcontext, ++ uint16 tclass, ++ struct av_decision *avd); ++extern bool sepgsql_compute_perms(char *scontext, ++ char *tcontext, ++ uint16 tclass, ++ uint32 required, ++ const char *audit_name, ++ bool abort); ++extern char *sepgsql_compute_create(char *scontext, ++ char *tcontext, ++ uint16 tclass); ++extern bool sepgsql_client_perms(sepgsql_sid_t tsid, ++ uint16 tclass, ++ uint32 required, ++ const char *audit_name, ++ bool abort); ++extern sepgsql_sid_t sepgsql_client_create_secid(sepgsql_sid_t tsid, ++ uint16 tclass, ++ Oid nrelid); ++extern char *sepgsql_client_create_label(sepgsql_sid_t tsid, ++ uint16 tclass); ++extern void sepgsql_avc_worker_main(void); ++ ++/* ++ * avc.c ++ */ ++extern Size sepgsql_shmem_size(void); ++extern void sepgsql_avc_init(void); ++extern void sepgsql_avc_switch(const char *scontext); ++ ++ ++/* ++ * label.c ++ */ ++extern sepgsql_sid_t sepgsql_move_secid(Oid dst_relid, sepgsql_sid_t ssid); ++ ++extern sepgsql_sid_t sepgsql_get_default_database_secid(Oid templateOid); ++extern sepgsql_sid_t sepgsql_get_default_schema_secid(Oid databaseOid); ++extern sepgsql_sid_t sepgsql_get_default_table_secid(Oid namespaceOid); ++extern sepgsql_sid_t sepgsql_get_default_sequence_secid(Oid namespaceOid); ++extern sepgsql_sid_t sepgsql_get_default_view_secid(Oid namespaceOid); ++extern sepgsql_sid_t sepgsql_get_default_proc_secid(Oid namespaceOid); ++extern sepgsql_sid_t sepgsql_get_default_column_secid(Oid tableOid); ++extern sepgsql_sid_t sepgsql_get_default_tuple_secid(Oid tableOid); ++extern sepgsql_sid_t sepgsql_get_default_blob_secid(Oid databaseOid); ++extern Oid sepgsql_get_default_secid(Relation rel, HeapTuple tuple); ++ ++extern void sepgsql_initial_labeling(void); ++ ++extern char *sepgsql_mcstrans_out(char *label); ++extern char *sepgsql_mcstrans_in(char *label); ++extern char *sepgsql_rawlabel_out(char *label); ++extern char *sepgsql_rawlabel_in(char *label); ++ ++/* ++ * sepgsql_(object)_common ++ */ ++extern bool sepgsql_database_common(Oid datOid, uint32 required, bool abort); ++extern bool sepgsql_schema_common(Oid nspOid, uint32 required, bool abort); ++extern bool sepgsql_relation_common(Oid relOid, uint32 required, bool abort); ++extern bool sepgsql_attribute_common(Oid relOid, AttrNumber attno, ++ uint32 required, bool abort); ++extern bool sepgsql_proc_common(Oid procOid, uint32 required, bool abort); ++extern bool sepgsql_type_common(Oid typeOid, uint32 required, bool abort); ++extern bool sepgsql_cast_common(Oid srcTypeOid, Oid dstTypeOid, ++ uint32 required, bool abort); ++extern bool sepgsql_tablespace_common(Oid tspaceOid, uint32 required, bool abort); ++extern bool sepgsql_operator_common(Oid operOid, uint32 required, bool abort); ++extern bool sepgsql_opclass_common(Oid opcOid, uint32 required, bool abort); ++extern bool sepgsql_opfamily_common(Oid opfOid, uint32 required, bool abort); ++extern bool sepgsql_role_common(Oid roleOid, uint32 required, bool abort); ++extern bool sepgsql_largeobejct_common(Oid loid, Snapshot snapshot, ++ uint32 required, bool abort); ++extern bool sepgsql_conversion_common(Oid convOid, uint32 required, bool abort); ++extern bool sepgsql_largeobject_common(Oid loid, Snapshot snapshot, ++ uint32 required, bool abort); ++extern bool sepgsql_ts_config_common(Oid confOid, uint32 required, bool abort); ++extern bool sepgsql_ts_dict_common(Oid dictOid, uint32 required, bool abort); ++extern bool sepgsql_ts_parser_common(Oid parseOid, uint32 required, bool abort); ++extern bool sepgsql_ts_template_common(Oid templateOid, uint32 required, bool abort); ++extern bool sepgsql_fdw_common(Oid fdwOid, uint32 required, bool abort); ++extern bool sepgsql_fserver_common(Oid fservOid, uint32 required, bool abort); ++extern bool sepgsql_user_mapping_common(Oid umapOid, uint32 required, bool abort); ++ ++#endif /* SEPGSQL_H */ +diff --git a/src/include/storage/large_object.h b/src/include/storage/large_object.h +index 43a61f3..6385b5c 100644 +--- a/src/include/storage/large_object.h ++++ b/src/include/storage/large_object.h +@@ -70,7 +70,7 @@ typedef struct LargeObjectDesc + + /* inversion stuff in inv_api.c */ + extern void close_lo_relation(bool isCommit); +-extern Oid inv_create(Oid lobjId); ++extern Oid inv_create(Oid lobjId, Oid securityId); + extern LargeObjectDesc *inv_open(Oid lobjId, int flags, MemoryContext mcxt); + extern void inv_close(LargeObjectDesc *obj_desc); + extern int inv_drop(Oid lobjId); +diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h +index 4eece8b..4176eac 100644 +--- a/src/include/storage/lwlock.h ++++ b/src/include/storage/lwlock.h +@@ -70,6 +70,7 @@ typedef enum LWLockId + RelationMappingLock, + AsyncCtlLock, + AsyncQueueLock, ++ SepgsqlAvcLock, + /* Individual lock IDs end here */ + FirstBufMappingLock, + FirstLockMgrLock = FirstBufMappingLock + NUM_BUFFER_PARTITIONS, +diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h +index c22c65a..5b94283 100644 +--- a/src/include/utils/guc.h ++++ b/src/include/utils/guc.h +@@ -166,6 +166,7 @@ extern bool log_btree_build_stats; + + extern PGDLLIMPORT bool check_function_bodies; + extern bool default_with_oids; ++extern bool default_with_secids; + extern bool SQL_inheritance; + + extern int log_min_error_statement; +diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h +index 2f19e5c..6744782 100644 +--- a/src/include/utils/syscache.h ++++ b/src/include/utils/syscache.h +@@ -101,6 +101,8 @@ extern bool SearchSysCacheExists(int cacheId, + Datum key1, Datum key2, Datum key3, Datum key4); + extern Oid GetSysCacheOid(int cacheId, + Datum key1, Datum key2, Datum key3, Datum key4); ++extern Oid GetSysCacheSecid(int cacheId, ++ Datum key1, Datum key2, Datum key3, Datum key4); + + extern HeapTuple SearchSysCacheAttName(Oid relid, const char *attname); + extern HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname); +@@ -154,6 +156,15 @@ extern struct catclist *SearchSysCacheList(int cacheId, int nkeys, + #define GetSysCacheOid4(cacheId, key1, key2, key3, key4) \ + GetSysCacheOid(cacheId, key1, key2, key3, key4) + ++#define GetSysCacheSecid1(cacheId, key1) \ ++ GetSysCacheSecid(cacheId, key1, 0, 0, 0) ++#define GetSysCacheSecid2(cacheId, key1, key2) \ ++ GetSysCacheSecid(cacheId, key1, key2, 0, 0) ++#define GetSysCacheSecid3(cacheId, key1, key2, key3) \ ++ GetSysCacheSecid(cacheId, key1, key2, key3, 0) ++#define GetSysCacheSecid4(cacheId, key1, key2, key3, key4) \ ++ GetSysCacheSecid(cacheId, key1, key2, key3, key4) ++ + #define SearchSysCacheList1(cacheId, key1) \ + SearchSysCacheList(cacheId, 1, key1, 0, 0, 0) + #define SearchSysCacheList2(cacheId, key1, key2) \ +diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c +index 656ea73..2ce4e94 100644 +--- a/src/pl/plpgsql/src/pl_comp.c ++++ b/src/pl/plpgsql/src/pl_comp.c +@@ -1936,7 +1936,7 @@ build_row_from_vars(PLpgSQL_variable **vars, int numvars) + + row = palloc0(sizeof(PLpgSQL_row)); + row->dtype = PLPGSQL_DTYPE_ROW; +- row->rowtupdesc = CreateTemplateTupleDesc(numvars, false); ++ row->rowtupdesc = CreateTemplateTupleDesc(numvars, false, false); + row->nfields = numvars; + row->fieldnames = palloc(numvars * sizeof(char *)); + row->varnos = palloc(numvars * sizeof(int)); +diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out +index 1d9e110..9596b0b 100644 +--- a/src/test/regress/expected/sanity_check.out ++++ b/src/test/regress/expected/sanity_check.out +@@ -114,6 +114,7 @@ SELECT relname, relhasindex + pg_pltemplate | t + pg_proc | t + pg_rewrite | t ++ pg_seclabel | t + pg_shdepend | t + pg_shdescription | t + pg_statistic | t +@@ -153,7 +154,7 @@ SELECT relname, relhasindex + timetz_tbl | f + tinterval_tbl | f + varchar_tbl | f +-(142 rows) ++(143 rows) + + -- + -- another sanity check: every system catalog that has OIDs should have diff --git a/sepostgresql-fedora-prefix.patch b/sepostgresql-fedora-prefix.patch index a9dd24b..98cd3b2 100644 --- a/sepostgresql-fedora-prefix.patch +++ b/sepostgresql-fedora-prefix.patch @@ -1,8 +1,8 @@ -Index: sepgsql/src/Makefile.global.in -=================================================================== ---- sepgsql/src/Makefile.global.in (revision 2237) -+++ sepgsql/src/Makefile.global.in (working copy) -@@ -75,14 +75,14 @@ +diff --git a/src/Makefile.global.in b/src/Makefile.global.in +index 0e3bed5..aee6064 100644 +--- a/src/Makefile.global.in ++++ b/src/Makefile.global.in +@@ -74,14 +74,14 @@ bindir := @bindir@ datadir := @datadir@ ifeq "$(findstring pgsql, $(datadir))" "" ifeq "$(findstring postgres, $(datadir))" "" @@ -19,7 +19,7 @@ Index: sepgsql/src/Makefile.global.in endif endif -@@ -91,7 +91,7 @@ +@@ -90,7 +90,7 @@ libdir := @libdir@ pkglibdir = $(libdir) ifeq "$(findstring pgsql, $(pkglibdir))" "" ifeq "$(findstring postgres, $(pkglibdir))" "" @@ -28,7 +28,7 @@ Index: sepgsql/src/Makefile.global.in endif endif -@@ -100,7 +100,7 @@ +@@ -99,7 +99,7 @@ includedir := @includedir@ pkgincludedir = $(includedir) ifeq "$(findstring pgsql, $(pkgincludedir))" "" ifeq "$(findstring postgres, $(pkgincludedir))" "" @@ -37,7 +37,7 @@ Index: sepgsql/src/Makefile.global.in endif endif -@@ -109,7 +109,7 @@ +@@ -108,7 +108,7 @@ mandir := @mandir@ docdir := @docdir@ ifeq "$(findstring pgsql, $(docdir))" "" ifeq "$(findstring postgres, $(docdir))" "" @@ -46,37 +46,55 @@ Index: sepgsql/src/Makefile.global.in endif endif -Index: sepgsql/src/bin/pg_ctl/pg_ctl.c -=================================================================== ---- sepgsql/src/bin/pg_ctl/pg_ctl.c (revision 2237) -+++ sepgsql/src/bin/pg_ctl/pg_ctl.c (working copy) -@@ -643,7 +643,7 @@ - - postmaster_path = pg_malloc(MAXPGPATH); - -- if ((ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR, -+ if ((ret = find_other_exec(argv0, "sepostgres", PG_BACKEND_VERSIONSTR, - postmaster_path)) < 0) - { - char full_path[MAXPGPATH]; -Index: sepgsql/src/bin/initdb/initdb.c -=================================================================== ---- sepgsql/src/bin/initdb/initdb.c (revision 2237) -+++ sepgsql/src/bin/initdb/initdb.c (working copy) -@@ -2763,7 +2763,7 @@ - sprintf(pgdenv, "PGDATA=%s", pg_data); - putenv(pgdenv); +diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c +index 497bdf0..54908f8 100644 +--- a/src/bin/initdb/initdb.c ++++ b/src/bin/initdb/initdb.c +@@ -2722,7 +2722,7 @@ main(int argc, char *argv[]) + */ + putenv("TZ=GMT"); - if ((ret = find_other_exec(argv[0], "postgres", PG_BACKEND_VERSIONSTR, + if ((ret = find_other_exec(argv[0], "sepostgres", PG_BACKEND_VERSIONSTR, backend_exec)) < 0) { char full_path[MAXPGPATH]; -Index: sepgsql/src/bin/pg_dump/pg_dumpall.c -=================================================================== ---- sepgsql/src/bin/pg_dump/pg_dumpall.c (revision 2237) -+++ sepgsql/src/bin/pg_dump/pg_dumpall.c (working copy) -@@ -157,7 +157,7 @@ +diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c +index 814ce97..2550e57 100644 +--- a/src/bin/pg_ctl/pg_ctl.c ++++ b/src/bin/pg_ctl/pg_ctl.c +@@ -654,7 +654,7 @@ do_init(void) + char cmd[MAXPGPATH]; + + if (exec_path == NULL) +- exec_path = find_other_exec_or_die(argv0, "initdb", "initdb (PostgreSQL) " PG_VERSION "\n"); ++ exec_path = find_other_exec_or_die(argv0, "initdb.sepgsql", "initdb (PostgreSQL) " PG_VERSION "\n"); + + if (pgdata_opt == NULL) + pgdata_opt = ""; +@@ -699,7 +699,7 @@ do_start(void) + pgdata_opt = ""; + + if (exec_path == NULL) +- exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR); ++ exec_path = find_other_exec_or_die(argv0, "sepostgres", PG_BACKEND_VERSIONSTR); + + #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE) + if (allow_core_files) +@@ -1069,7 +1069,7 @@ pgwin32_CommandLine(bool registration) + } + else + { +- ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR, ++ ret = find_other_exec(argv0, "sepostgres", PG_BACKEND_VERSIONSTR, + cmdLine); + if (ret != 0) + { +diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c +index 83f1678..a0a9444 100644 +--- a/src/bin/pg_dump/pg_dumpall.c ++++ b/src/bin/pg_dump/pg_dumpall.c +@@ -156,7 +156,7 @@ main(int argc, char *argv[]) } } diff --git a/sepostgresql.init b/sepostgresql.init index 866aaba..1a2cbb6 100644 --- a/sepostgresql.init +++ b/sepostgresql.init @@ -7,7 +7,7 @@ # pidfile: /var/run/postmaster.pid #--------------------------------------------------------------------- -PGVERSION="8.4.1" +PGVERSION="`/bin/rpm --queryformat=%{version} -q sepostgresql`" PGMAJORVERSION=`echo "$PGVERSION" | sed 's/^\([0-9]*\.[0-9a-z]*\).*$/\1/'` # source function library @@ -23,21 +23,18 @@ if [ ${NAME:0:1} = "S" -o ${NAME:0:1} = "K" ]; then fi # set defaults for configurable variables -SEPGSQL_BIN="/usr/bin" +SEPGSQL_CTL="/usr/bin/sepg_ctl" SEPGSQL_DATA="/var/lib/sepgsql/data" SEPGSQL_OPTS="-i -p 5432" SEPGSQL_STARTUP_LOG="/var/lib/sepgsql/pgstartup.log" SEPGSQL_LOG="/var/log/sepostgresql.log" -SEPGSQL_FALLBACK_CONTEXT="user_u:user_r:user_t" # override defaults from /etc/sysconfig/sepostgresql test -f /etc/sysconfig/${NAME} && . /etc/sysconfig/${NAME} -export SEPGSQL_FALLBACK_CONTEXT - # Check that networking is up. test "${NETWORKING}" = "no" && exit 0 -test -f "${SEPGSQL_BIN}/sepostgres" || exit 1 +test -f "/usr/bin/sepostgres" || exit 1 script_result=0 @@ -77,11 +74,10 @@ do_start() { chmod 600 ${SEPGSQL_LOG} test -x /sbin/restorecon && /sbin/restorecon ${SEPGSQL_LOG} - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -c "./sepg_ctl -w -t 10 -l ${SEPGSQL_LOG} -D ${SEPGSQL_DATA} -o '${SEPGSQL_OPTS}' start" \ + /sbin/runuser sepgsql -c "${SEPGSQL_CTL} -w -t 10 -l ${SEPGSQL_LOG} -D ${SEPGSQL_DATA} -o '${SEPGSQL_OPTS}' start" \ >> ${SEPGSQL_STARTUP_LOG} 2>&1 < /dev/null sleep 1 - PID=`/sbin/runuser sepgsql -c "./sepg_ctl -D ${SEPGSQL_DATA} status 2>/dev/null \ + PID=`/sbin/runuser sepgsql -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} status 2>/dev/null \ | sed 's/^.*PID: //g' | sed 's/[^0-9].*$//g'"` if [ ${PIPESTATUS[0]} -eq 0 ]; then echo "$PID" > "/var/run/${NAME}.pid" @@ -96,8 +92,7 @@ do_start() { do_stop() { echo -n $"Stopping ${NAME} service: " - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -c "./sepg_ctl -D ${SEPGSQL_DATA} stop" \ + /sbin/runuser sepgsql -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} stop" \ >> ${SEPGSQL_STARTUP_LOG} 2>&1 < /dev/null ret=$? if [ $ret -eq 0 ]; then @@ -112,8 +107,7 @@ do_stop() { } do_status() { - cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "./sepg_ctl -D ${SEPGSQL_DATA} status" 2>/dev/null \ + /sbin/runuser sepgsql -- -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} status" 2>/dev/null \ | head -1 | sed "s/^sepg_ctl:/${NAME}:/g" if [ ${PIPESTATUS[0]} -ne 0 ]; then @@ -125,18 +119,18 @@ do_status() { do_condrestart() { cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "./sepg_ctl -D ${SEPGSQL_DATA} status" &>/dev/null && do_stop && do_start + /sbin/runuser sepgsql -- -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} status" &>/dev/null && do_stop && do_start } do_condstop() { cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "./sepg_ctl -D ${SEPGSQL_DATA} status" &>/dev/null && do_stop + /sbin/runuser sepgsql -- -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} status" &>/dev/null && do_stop } do_reload() { echo -n $"Reloading ${NAME} service: " cd ${SEPGSQL_BIN} - /sbin/runuser sepgsql -- -c "./sepg_ctl -D ${SEPGSQL_DATA} reload" &>/dev/null < /dev/null + /sbin/runuser sepgsql -- -c "${SEPGSQL_CTL} -D ${SEPGSQL_DATA} reload" &>/dev/null < /dev/null if [ $? -eq 0 ]; then echo_success else @@ -163,8 +157,7 @@ do_initdb() { # cleanup SELinux labeling for "${SEPGSQL_DATA}" test -x /sbin/restorecon && /sbin/restorecon -R "${SEPGSQL_DATA}" # Initialize the database - cd ${SEPGSQL_BIN} - /sbin/runuser -- sepgsql -c "./initdb.sepgsql --enable-selinux --pgdata='${SEPGSQL_DATA}' --auth='ident'" \ + /sbin/runuser -- sepgsql -c "${SEPGSQL_CTL} initdb -o '--enable-selinux --pgdata=${SEPGSQL_DATA} --auth=ident' -D ${SEPGSQL_DATA}" \ >> "${SEPGSQL_STARTUP_LOG}" 2>&1 < /dev/null if [ -f "${SEPGSQL_DATA}/PG_VERSION" ]; then echo_success diff --git a/sepostgresql.spec b/sepostgresql.spec index bdc0765..89789d8 100644 --- a/sepostgresql.spec +++ b/sepostgresql.spec @@ -8,22 +8,24 @@ %define selinux_policy_stores targeted mls %{!?ssl:%define ssl 1} +%{!?beta:%define beta .alpha5} Summary: Security Enhanced PostgreSQL Name: sepostgresql -Version: 8.4.3 -Release: 2582%{?dist} -License: BSD +Version: 9.0.0 +Release: 20100404%{?beta}%{?dist} +License: PostgreSQL Group: Applications/Databases Url: http://code.google.com/p/sepgsql/ Buildroot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) -Source0: ftp://ftp.postgresql.org/pub/source/v%{version}/postgresql-%{version}.tar.bz2 +#XXX - to be revert later +#Source0: ftp://ftp.postgresql.org/pub/source/v%{version}/postgresql-%{version}.tar.bz2 +Source0: postgresql-9.0alpha5.tar.bz2 Source1: sepostgresql.init Source2: sepostgresql.8 Source3: sepostgresql.logrotate Patch0: sepostgresql-fedora-prefix.patch -Patch1: pgsql-01-8.4-blobs.patch -Patch2: pgsql-02-8.4-sepgsql.patch +Patch1: sepostgresql-9.0-fullset.patch BuildRequires: perl glibc-devel bison flex readline-devel zlib-devel >= 1.0.4 BuildRequires: checkpolicy libselinux-devel >= 2.0.80 BuildRequires: selinux-policy >= 3.6.8 @@ -34,7 +36,6 @@ Requires(pre): shadow-utils Requires(post): policycoreutils /sbin/chkconfig Requires(preun): /sbin/chkconfig /sbin/service Requires(postun): policycoreutils -Requires: postgresql-server = %{version} Requires: policycoreutils >= 2.0.16 libselinux >= 2.0.80 Requires: selinux-policy >= 3.6.8 Requires: tzdata logrotate @@ -48,10 +49,11 @@ the operating system. SE-PostgreSQL works as a userspace reference monitor to check any SQL query. %prep -%setup -q -n postgresql-%{version} +#XXX - to be revert later +#%setup -q -n postgresql-%{version} +%setup -q -n postgresql-9.0alpha5 %patch0 -p1 %patch1 -p1 -%patch2 -p1 %build CFLAGS="${CFLAGS:-%optflags}" ; export CFLAGS @@ -65,36 +67,38 @@ CXXFLAGS="${CXXFLAGS:-%optflags}" ; export CXXFLAGS %endif --enable-debug \ --enable-cassert \ - --libdir=%{_libdir}/pgsql \ - --datadir=%{_datadir}/sepgsql \ --with-system-tzdata=/usr/share/zoneinfo # parallel build, if possible +rm -f src/Makefile.custom make %{?_smp_mflags} -touch src/backend/security/sepgsql/policy/sepostgresql-devel.fc -make -C src/backend/security/sepgsql/policy %install rm -rf %{buildroot} make DESTDIR=%{buildroot} install -install -d %{buildroot}%{_datadir}/selinux/packages -install -p -m 644 src/backend/security/sepgsql/policy/sepostgresql-devel.pp \ - %{buildroot}%{_datadir}/selinux/packages - # avoid to conflict with native postgresql package mv %{buildroot}%{_bindir} %{buildroot}%{_bindir}.orig -install -d %{buildroot}%{_bindir} +install -d %{buildroot}%{_bindir}/ mv %{buildroot}%{_bindir}.orig/initdb %{buildroot}%{_bindir}/initdb.sepgsql mv %{buildroot}%{_bindir}.orig/pg_ctl %{buildroot}%{_bindir}/sepg_ctl mv %{buildroot}%{_bindir}.orig/postgres %{buildroot}%{_bindir}/sepostgres mv %{buildroot}%{_bindir}.orig/pg_dump %{buildroot}%{_bindir}/sepg_dump mv %{buildroot}%{_bindir}.orig/pg_dumpall %{buildroot}%{_bindir}/sepg_dumpall +mv %{buildroot}%{_bindir}.orig/pg_restore %{buildroot}%{_bindir}/sepg_restore + +mv %{buildroot}%{_libdir} %{buildroot}%{_libdir}.orig +install -d %{buildroot}%{_libdir}/sepgsql +mv %{buildroot}%{_libdir}.orig/sepgsql/dict_snowball.so \ + %{buildroot}%{_libdir}.orig/sepgsql/plpgsql.so \ + %{buildroot}%{_libdir}.orig/sepgsql/*_and_*.so \ + %{buildroot}%{_libdir}.orig/sepgsql/euc2004_sjis2004.so \ + %{buildroot}%{_libdir}/sepgsql # remove unnecessary files rm -rf %{buildroot}%{_bindir}.orig -rm -rf %{buildroot}%{_libdir} +rm -rf %{buildroot}%{_libdir}.orig rm -rf %{buildroot}%{_includedir} rm -rf %{buildroot}%{_datadir}/doc rm -rf %{buildroot}%{_datadir}/sepgsql/timezone @@ -123,24 +127,13 @@ rm -rf %{buildroot} %pre getent group sepgsql >/dev/null || groupadd -r sepgsql getent passwd sepgsql >/dev/null || \ - useradd -r -g sepgsql -d %{_localstatedir}/lib/sepgsql -s /bin/bash \ - -c "SE-PostgreSQL server" sepgsql + useradd -r -g sepgsql -s /bin/bash -c "SE-PostgreSQL" sepgsql exit 0 %post /sbin/chkconfig --add %{name} /sbin/ldconfig -for store in %{selinux_policy_stores} -do - # clean up legacy policy module (now it is unnecessary) - %{_sbindir}/semodule -s ${store} -r sepostgresql >& /dev/null || : - if %{_sbindir}/semodule -s ${store} -l 2>/dev/null | grep -Eq "^sepostgresql-devel"; then - %{_sbindir}/semodule -s ${store} \ - -i %{_datadir}/selinux/packages/sepostgresql-devel.pp >& /dev/null || : - fi -done - # Fix up non-standard file contexts /sbin/fixfiles -R %{name} restore || : /sbin/restorecon -R %{_localstatedir}/lib/sepgsql || : @@ -157,12 +150,9 @@ if [ $1 -ge 1 ]; then # rpm -U case /sbin/service %{name} condrestart >/dev/null 2>&1 || : fi if [ $1 -eq 0 ]; then # rpm -e case - for store in %{selinux_policy_stores} - do - %{_sbindir}/semodule -s ${store} -r sepostgresql-devel >& /dev/null || : - done /sbin/fixfiles -R %{name} restore || : - test -d %{_localstatedir}/lib/sepgsql && /sbin/restorecon -R %{_localstatedir}/lib/sepgsql || : + test -d %{_localstatedir}/lib/sepgsql && \ + /sbin/restorecon -R %{_localstatedir}/lib/sepgsql || : fi %files @@ -175,6 +165,8 @@ fi %{_bindir}/sepostgres %{_bindir}/sepg_dump %{_bindir}/sepg_dumpall +%{_bindir}/sepg_restore +%{_libdir}/sepgsql/*.so %{_mandir}/man8/sepostgresql.* %dir %{_datadir}/sepgsql %{_datadir}/sepgsql/postgres.bki @@ -188,12 +180,14 @@ fi %{_datadir}/sepgsql/conversion_create.sql %{_datadir}/sepgsql/information_schema.sql %{_datadir}/sepgsql/sql_features.txt -%attr(644,root,root) %{_datadir}/selinux/packages/sepostgresql-devel.pp %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/data %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/backups %changelog +* Sun Apr 4 2010 KaiGai Kohei - 9.0.0-20100404 +- upgrade base version 8.4.3->9.0alpha5 + * Thu Mar 18 2010 KaiGai Kohei - 8.4.3-2582 - upgrade base version 8.4.2->8.4.3 diff --git a/sources b/sources index 6b61e74..130572c 100644 --- a/sources +++ b/sources @@ -1,2 +1 @@ -d738227e2f1f742d2f2d4ab56496c5c6 postgresql-8.4.2.tar.bz2 -7f70e7b140fb190f268837255582b07e postgresql-8.4.3.tar.bz2 +df7a869e7a1fdbe5c5ffc3928eb3d234 postgresql-9.0alpha5.tar.bz2