pgsql-v9.2-shared-security-label.v5.patch
application/octet-stream
Filename: pgsql-v9.2-shared-security-label.v5.patch
Type: application/octet-stream
Part: 0
contrib/sepgsql/Makefile | 2 +-
contrib/sepgsql/database.c | 105 ++++++++++++++++++
contrib/sepgsql/hooks.c | 5 +
contrib/sepgsql/label.c | 23 +++-
contrib/sepgsql/schema.c | 18 ++--
contrib/sepgsql/sepgsql.h | 6 +
doc/src/sgml/catalogs.sgml | 65 +++++++++++
doc/src/sgml/ref/security_label.sgml | 3 +
src/backend/catalog/Makefile | 2 +-
src/backend/catalog/catalog.c | 3 +
src/backend/catalog/system_views.sql | 32 +++++-
src/backend/commands/dbcommands.c | 5 +-
src/backend/commands/seclabel.c | 147 ++++++++++++++++++++++++-
src/backend/commands/tablespace.c | 4 +-
src/backend/commands/user.c | 5 +-
src/backend/parser/gram.y | 3 +
src/backend/utils/cache/syscache.c | 12 ++
src/bin/pg_dump/pg_dumpall.c | 108 ++++++++++++++-----
src/include/catalog/indexing.h | 3 +
src/include/catalog/pg_shseclabel.h | 41 +++++++
src/include/commands/seclabel.h | 1 +
src/include/utils/syscache.h | 1 +
src/test/regress/expected/rules.out | 6 +-
src/test/regress/expected/sanity_check.out | 3 +-
src/test/regress/input/security_label.source | 32 +++++-
src/test/regress/output/security_label.source | 62 +++++++++--
26 files changed, 631 insertions(+), 66 deletions(-)
diff --git a/contrib/sepgsql/Makefile b/contrib/sepgsql/Makefile
index bc995dd..6f77239 100644
--- a/contrib/sepgsql/Makefile
+++ b/contrib/sepgsql/Makefile
@@ -2,7 +2,7 @@
MODULE_big = sepgsql
OBJS = hooks.o selinux.o label.o dml.o \
- schema.o relation.o proc.o
+ database.o schema.o relation.o proc.o
DATA_built = sepgsql.sql
REGRESS = label dml misc
EXTRA_CLEAN = -r tmp *.pp sepgsql-regtest.if sepgsql-regtest.fc
diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c
new file mode 100644
index 0000000..efac6a2
--- /dev/null
+++ b/contrib/sepgsql/database.c
@@ -0,0 +1,105 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/database.c
+ *
+ * Routines corresponding to database objects
+ *
+ * Copyright (c) 2010-2011, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "catalog/dependency.h"
+#include "catalog/pg_database.h"
+#include "commands/seclabel.h"
+#include "miscadmin.h"
+#include "utils/lsyscache.h"
+
+#include "sepgsql.h"
+
+/*
+ * sepgsql_database_post_create
+ *
+ * This routine assigns a default security label on a newly defined
+ * database
+ */
+void
+sepgsql_database_post_create(Oid databaseId)
+{
+ char *scontext = sepgsql_get_client_label();
+ char *tcontext;
+ char *ncontext;
+ ObjectAddress object;
+
+ /*
+ * Compute a default security label when we create a new database
+ * object according to the specified template database.
+ *
+ * FIXME - In correctly, we'd like to inherit security label of
+ * the template database object, however, we cannot see which was
+ * used to as a template. So, we need a facility to deliver an
+ * opaque datum from the prep-creation hook in the future fixups.
+ */
+ object.classId = DatabaseRelationId;
+ object.objectId = TemplateDbOid;
+ object.objectSubId = 0;
+ tcontext = GetSecurityLabel(&object, SEPGSQL_LABEL_TAG);
+
+ ncontext = sepgsql_compute_create(scontext, tcontext,
+ SEPG_CLASS_DB_DATABASE);
+
+ /*
+ * Assign the default security label on a new database
+ */
+ object.classId = DatabaseRelationId;
+ object.objectId = databaseId;
+ object.objectSubId = 0;
+
+ SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
+
+ pfree(ncontext);
+ pfree(tcontext);
+}
+
+/*
+ * sepgsql_database_relabel
+ *
+ * It checks privileges to relabel the supplied database
+ * by the `seclabel'.
+ */
+void
+sepgsql_database_relabel(Oid databaseId, const char *seclabel)
+{
+ char *scontext = sepgsql_get_client_label();
+ char *tcontext;
+ char *audit_name;
+
+ audit_name = getObjectDescriptionOids(DatabaseRelationId, databaseId);
+
+ /*
+ * check db_database:{setattr relabelfrom} permission
+ */
+ tcontext = sepgsql_get_label(DatabaseRelationId, databaseId, 0);
+
+ sepgsql_check_perms(scontext,
+ tcontext,
+ SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__SETATTR |
+ SEPG_DB_DATABASE__RELABELFROM,
+ audit_name,
+ true);
+
+ /*
+ * check db_database:{relabelto} permission
+ */
+ sepgsql_check_perms(scontext,
+ seclabel,
+ SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__RELABELTO,
+ audit_name,
+ true);
+
+ pfree(tcontext);
+ pfree(audit_name);
+}
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index 7797ccb..ca0d5f4 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -12,6 +12,7 @@
#include "catalog/objectaccess.h"
#include "catalog/pg_class.h"
+#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "commands/seclabel.h"
@@ -125,6 +126,10 @@ sepgsql_object_access(ObjectAccessType access,
case OAT_POST_CREATE:
switch (classId)
{
+ case DatabaseRelationId:
+ sepgsql_database_post_create(objectId);
+ break;
+
case NamespaceRelationId:
sepgsql_schema_post_create(objectId);
break;
diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c
index 669ee35..c0503f7 100644
--- a/contrib/sepgsql/label.c
+++ b/contrib/sepgsql/label.c
@@ -17,6 +17,7 @@
#include "catalog/indexing.h"
#include "catalog/pg_attribute.h"
#include "catalog/pg_class.h"
+#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "commands/dbcommands.h"
@@ -121,6 +122,9 @@ sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel)
*/
switch (object->classId)
{
+ case DatabaseRelationId:
+ sepgsql_database_relabel(object->objectId, seclabel);
+ break;
case NamespaceRelationId:
sepgsql_schema_relabel(object->objectId, seclabel);
break;
@@ -315,6 +319,7 @@ exec_object_restorecon(struct selabel_handle * sehnd, Oid catalogId)
SnapshotNow, 0, NULL);
while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
{
+ Form_pg_database datForm;
Form_pg_namespace nspForm;
Form_pg_class relForm;
Form_pg_attribute attForm;
@@ -330,6 +335,19 @@ exec_object_restorecon(struct selabel_handle * sehnd, Oid catalogId)
*/
switch (catalogId)
{
+ case DatabaseRelationId:
+ datForm = (Form_pg_database) GETSTRUCT(tuple);
+
+ objtype = SELABEL_DB_DATABASE;
+
+ objname = quote_object_name(NameStr(datForm->datname),
+ NULL, NULL, NULL);
+
+ object.classId = DatabaseRelationId;
+ object.objectId = HeapTupleGetOid(tuple);
+ object.objectSubId = 0;
+ break;
+
case NamespaceRelationId:
nspForm = (Form_pg_namespace) GETSTRUCT(tuple);
@@ -506,10 +524,7 @@ sepgsql_restorecon(PG_FUNCTION_ARGS)
errmsg("SELinux: failed to initialize labeling handle: %m")));
PG_TRY();
{
- /*
- * Right now, we have no support labeling on the shared database
- * objects, such as database, role, or tablespace.
- */
+ exec_object_restorecon(sehnd, DatabaseRelationId);
exec_object_restorecon(sehnd, NamespaceRelationId);
exec_object_restorecon(sehnd, RelationRelationId);
exec_object_restorecon(sehnd, AttributeRelationId);
diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c
index 0de8997..131a4f6 100644
--- a/contrib/sepgsql/schema.c
+++ b/contrib/sepgsql/schema.c
@@ -11,8 +11,10 @@
#include "postgres.h"
#include "catalog/dependency.h"
+#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "commands/seclabel.h"
+#include "miscadmin.h"
#include "utils/lsyscache.h"
#include "sepgsql.h"
@@ -32,16 +34,15 @@ sepgsql_schema_post_create(Oid namespaceId)
ObjectAddress object;
/*
- * FIXME: Right now, we assume pg_database object has a fixed security
- * label, because pg_seclabel does not support to store label of shared
- * database objects.
+ * Compute a default security label when we create a new schema
+ * object under the working database.
*/
- tcontext = "system_u:object_r:sepgsql_db_t:s0";
+ object.classId = DatabaseRelationId;
+ object.objectId = MyDatabaseId;
+ object.objectSubId = 0;
+
+ tcontext = GetSecurityLabel(&object, SEPGSQL_LABEL_TAG);
- /*
- * Compute a default security label when we create a new schema object
- * under the working database.
- */
ncontext = sepgsql_compute_create(scontext, tcontext,
SEPG_CLASS_DB_SCHEMA);
@@ -54,6 +55,7 @@ sepgsql_schema_post_create(Oid namespaceId)
SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
pfree(ncontext);
+ pfree(tcontext);
}
/*
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index 71688ab..5045ddd 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -267,6 +267,12 @@ extern Datum sepgsql_restorecon(PG_FUNCTION_ARGS);
extern bool sepgsql_dml_privileges(List *rangeTabls, bool abort);
/*
+ * database.c
+ */
+extern void sepgsql_database_post_create(Oid databaseId);
+extern void sepgsql_database_relabel(Oid databaseId, const char *seclabel);
+
+/*
* schema.c
*/
extern void sepgsql_schema_post_create(Oid namespaceId);
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index d4a1d36..80fc227 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -239,6 +239,11 @@
</row>
<row>
+ <entry><link linkend="catalog-pg-shseclabel"><structname>pg_shseclabel</structname></link></entry>
+ <entry>security labels on shared database objects</entry>
+ </row>
+
+ <row>
<entry><link linkend="catalog-pg-statistic"><structname>pg_statistic</structname></link></entry>
<entry>planner statistics</entry>
</row>
@@ -4680,6 +4685,13 @@
<xref linkend="sql-security-label"> statement.
</para>
+ <para>
+ See also <link linkend="catalog-pg-shseclabel"><structname>pg_shseclabel</structname></link>,
+ which performs a similar function for security labels of database objects that
+ are shared across a database cluster.
+ </para>
+
+
<table>
<title><structname>pg_seclabel</structname> Columns</title>
@@ -4958,6 +4970,59 @@
</sect1>
+ <sect1 id="catalog-pg-shseclabel">
+ <title><structname>pg_shseclabel</structname></title>
+
+ <indexterm zone="catalog-pg-shseclabel">
+ <primary>pg_shseclabel</primary>
+ </indexterm>
+
+ <para>
+ The catalog <structname>pg_shseclabel</structname> stores security
+ labels on shared database objects across a database cluster.
+ See the <xref linkend="sql-security-label"> statement.
+ </para>
+
+ <table>
+ <title><structname>pg_shseclabel</structname> Columns</title>
+ <tgroup cols="4">
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Type</entry>
+ <entry>References</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><structfield>objoid</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry>any OID column</entry>
+ <entry>The OID of the object this security label pertains to</entry>
+ </row>
+ <row>
+ <entry><structfield>classoid</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
+ <entry>The OID of the system catalog this object appears in</entry>
+ </row>
+ <row>
+ <entry><structfield>provider</structfield></entry>
+ <entry><type>name</type></entry>
+ <entry></entry>
+ <entry>The label provider associated with this label.</entry>
+ </row>
+ <row>
+ <entry><structfield>label</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry></entry>
+ <entry>The security label applied to this object.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
<sect1 id="catalog-pg-statistic">
<title><structname>pg_statistic</structname></title>
diff --git a/doc/src/sgml/ref/security_label.sgml b/doc/src/sgml/ref/security_label.sgml
index 8a01b94..78e3f45 100644
--- a/doc/src/sgml/ref/security_label.sgml
+++ b/doc/src/sgml/ref/security_label.sgml
@@ -26,13 +26,16 @@ SECURITY LABEL [ FOR <replaceable class="PARAMETER">provider</replaceable> ] ON
TABLE <replaceable class="PARAMETER">object_name</replaceable> |
COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable> [, ...] ) |
+ DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
FOREIGN TABLE <replaceable class="PARAMETER">object_name</replaceable>
FUNCTION <replaceable class="PARAMETER">function_name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) |
LARGE OBJECT <replaceable class="PARAMETER">large_object_oid</replaceable> |
[ PROCEDURAL ] LANGUAGE <replaceable class="PARAMETER">object_name</replaceable> |
+ ROLE <replaceable class="PARAMETER">object_name</replaceable> |
SCHEMA <replaceable class="PARAMETER">object_name</replaceable> |
SEQUENCE <replaceable class="PARAMETER">object_name</replaceable> |
+ TABLESPACE <replaceable class="PARAMETER">object_name</replaceable> |
TYPE <replaceable class="PARAMETER">object_name</replaceable> |
VIEW <replaceable class="PARAMETER">object_name</replaceable>
} IS '<replaceable class="PARAMETER">label</replaceable>'
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 3a83461..7e0b7d6 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -39,7 +39,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_ts_parser.h pg_ts_template.h pg_extension.h \
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
pg_foreign_table.h \
- pg_default_acl.h pg_seclabel.h pg_collation.h \
+ pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h \
toasting.h indexing.h \
)
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index cbce007..9d568b5 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -34,6 +34,7 @@
#include "catalog/pg_db_role_setting.h"
#include "catalog/pg_shdepend.h"
#include "catalog/pg_shdescription.h"
+#include "catalog/pg_shseclabel.h"
#include "catalog/pg_tablespace.h"
#include "catalog/toasting.h"
#include "miscadmin.h"
@@ -380,6 +381,7 @@ IsSharedRelation(Oid relationId)
relationId == PLTemplateRelationId ||
relationId == SharedDescriptionRelationId ||
relationId == SharedDependRelationId ||
+ relationId == SharedSecLabelRelationId ||
relationId == TableSpaceRelationId ||
relationId == DbRoleSettingRelationId)
return true;
@@ -394,6 +396,7 @@ IsSharedRelation(Oid relationId)
relationId == SharedDescriptionObjIndexId ||
relationId == SharedDependDependerIndexId ||
relationId == SharedDependReferenceIndexId ||
+ relationId == SharedSecLabelObjectIndexId ||
relationId == TablespaceOidIndexId ||
relationId == TablespaceNameIndexId ||
relationId == DbRoleSettingDatidRolidIndexId)
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 325d452..2253ca8 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -283,7 +283,37 @@ FROM
pg_seclabel l
JOIN pg_namespace nsp ON l.classoid = nsp.tableoid AND l.objoid = nsp.oid
WHERE
- l.objsubid = 0;
+ l.objsubid = 0
+UNION ALL
+SELECT
+ l.objoid, l.classoid, 0::int4 AS objsubid,
+ 'database'::text AS objtype,
+ NULL::oid AS objnamespace,
+ quote_ident(dat.datname) AS objname,
+ l.provider, l.label
+FROM
+ pg_shseclabel l
+ JOIN pg_database dat ON l.classoid = dat.tableoid AND l.objoid = dat.oid
+UNION ALL
+SELECT
+ l.objoid, l.classoid, 0::int4 AS objsubid,
+ 'tablespace'::text AS objtype,
+ NULL::oid AS objnamespace,
+ quote_ident(spc.spcname) AS objname,
+ l.provider, l.label
+FROM
+ pg_shseclabel l
+ JOIN pg_tablespace spc ON l.classoid = spc.tableoid AND l.objoid = spc.oid
+UNION ALL
+SELECT
+ l.objoid, l.classoid, 0::int4 AS objsubid,
+ 'role'::text AS objtype,
+ NULL::oid AS objnamespace,
+ quote_ident(rol.rolname) AS objname,
+ l.provider, l.label
+FROM
+ pg_shseclabel l
+ JOIN pg_authid rol ON l.classoid = rol.tableoid AND l.objoid = rol.oid;
CREATE VIEW pg_settings AS
SELECT * FROM pg_show_all_settings() AS A;
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index f319eb5..93240ef 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -39,6 +39,7 @@
#include "catalog/pg_tablespace.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
+#include "commands/seclabel.h"
#include "commands/tablespace.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
@@ -822,9 +823,11 @@ dropdb(const char *dbname, bool missing_ok)
ReleaseSysCache(tup);
/*
- * Delete any comments associated with the database.
+ * Delete any comments or security labels associated with
+ * the database.
*/
DeleteSharedComments(db_id, DatabaseRelationId);
+ DeleteSharedSecurityLabel(db_id, DatabaseRelationId);
/*
* Remove settings associated with this database
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 6e7e9c2..d6ee067 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -16,6 +16,7 @@
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_seclabel.h"
+#include "catalog/pg_shseclabel.h"
#include "commands/seclabel.h"
#include "miscadmin.h"
#include "utils/acl.h"
@@ -24,6 +25,7 @@
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
+#include "utils/syscache.h"
#include "utils/tqual.h"
typedef struct
@@ -149,7 +151,24 @@ GetSecurityLabel(const ObjectAddress *object, const char *provider)
bool isnull;
char *seclabel = NULL;
- Assert(!IsSharedRelation(object->classId));
+ /* Special handling for shared database objects */
+ if (IsSharedRelation(object->classId))
+ {
+ tuple = SearchSysCache3(SHSECLABELOID,
+ ObjectIdGetDatum(object->objectId),
+ ObjectIdGetDatum(object->classId),
+ CStringGetDatum(provider));
+ if (HeapTupleIsValid(tuple))
+ {
+ datum = SysCacheGetAttr(SHSECLABELOID, tuple,
+ Anum_pg_shseclabel_label, &isnull);
+ if (!isnull)
+ seclabel = TextDatumGetCString(datum);
+
+ ReleaseSysCache(tuple);
+ }
+ return seclabel;
+ }
ScanKeyInit(&keys[0],
Anum_pg_seclabel_objoid,
@@ -188,6 +207,86 @@ GetSecurityLabel(const ObjectAddress *object, const char *provider)
return seclabel;
}
+/*
+ * SetSharedSecurityLabel is a helper function of SetSecurityLabel to
+ * handle shared database objects.
+ */
+static void
+SetSharedSecurityLabel(const ObjectAddress *object,
+ const char *provider, const char *label)
+{
+ Relation pg_shseclabel;
+ ScanKeyData keys[4];
+ SysScanDesc scan;
+ HeapTuple oldtup;
+ HeapTuple newtup = NULL;
+ NameData name;
+ Datum values[Natts_pg_shseclabel];
+ bool nulls[Natts_pg_shseclabel];
+ bool replaces[Natts_pg_shseclabel];
+
+ /* Prepare to form or update a tuple, if necessary. */
+ memset(nulls, false, sizeof(nulls));
+ memset(replaces, false, sizeof(replaces));
+ namestrcpy(&name, provider);
+ values[Anum_pg_shseclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
+ values[Anum_pg_shseclabel_classoid - 1] = ObjectIdGetDatum(object->classId);
+ values[Anum_pg_shseclabel_provider - 1] = NameGetDatum(&name);
+ if (label != NULL)
+ values[Anum_pg_shseclabel_label - 1] = CStringGetTextDatum(label);
+
+ /* Use the index to search for a matching old tuple */
+ ScanKeyInit(&keys[0],
+ Anum_pg_shseclabel_objoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+ ScanKeyInit(&keys[1],
+ Anum_pg_shseclabel_classoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->classId));
+ ScanKeyInit(&keys[2],
+ Anum_pg_shseclabel_provider,
+ BTEqualStrategyNumber, F_NAMEEQ,
+ NameGetDatum(provider));
+
+ pg_shseclabel = heap_open(SharedSecLabelRelationId, RowExclusiveLock);
+
+ scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
+ SnapshotNow, 3, keys);
+
+ oldtup = systable_getnext(scan);
+ if (HeapTupleIsValid(oldtup))
+ {
+ if (label == NULL)
+ simple_heap_delete(pg_shseclabel, &oldtup->t_self);
+ else
+ {
+ replaces[Anum_pg_shseclabel_label - 1] = true;
+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_shseclabel),
+ values, nulls, replaces);
+ simple_heap_update(pg_shseclabel, &oldtup->t_self, newtup);
+ }
+ }
+ systable_endscan(scan);
+
+ /* If we didn't find an old tuple, insert a new one */
+ if (newtup == NULL && label != NULL)
+ {
+ newtup = heap_form_tuple(RelationGetDescr(pg_shseclabel),
+ values, nulls);
+ simple_heap_insert(pg_shseclabel, newtup);
+ }
+
+ /* Update indexes, if necessary */
+ if (newtup != NULL)
+ {
+ CatalogUpdateIndexes(pg_shseclabel, newtup);
+ heap_freetuple(newtup);
+ }
+
+ heap_close(pg_shseclabel, RowExclusiveLock);
+}
+
/*
* SetSecurityLabel attempts to set the security label for the specified
* provider on the specified object to the given value. NULL means that any
@@ -206,8 +305,12 @@ SetSecurityLabel(const ObjectAddress *object,
bool nulls[Natts_pg_seclabel];
bool replaces[Natts_pg_seclabel];
- /* Security labels on shared objects are not supported. */
- Assert(!IsSharedRelation(object->classId));
+ /* Special handling for security labels on shared objects */
+ if (IsSharedRelation(object->classId))
+ {
+ SetSharedSecurityLabel(object, provider, label);
+ return;
+ }
/* Prepare to form or update a tuple, if necessary. */
memset(nulls, false, sizeof(nulls));
@@ -276,6 +379,38 @@ SetSecurityLabel(const ObjectAddress *object,
}
/*
+ * DeleteSharedSecurityLabel is a helper function of DeleteSecurityLabel
+ * to handle shared database objects.
+ */
+void
+DeleteSharedSecurityLabel(Oid objectId, Oid classId)
+{
+ Relation pg_shseclabel;
+ ScanKeyData skey[2];
+ SysScanDesc scan;
+ HeapTuple oldtup;
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_shseclabel_objoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(objectId));
+ ScanKeyInit(&skey[1],
+ Anum_pg_shseclabel_classoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(classId));
+
+ pg_shseclabel = heap_open(SharedSecLabelRelationId, RowExclusiveLock);
+
+ scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
+ SnapshotNow, 2, skey);
+ while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
+ simple_heap_delete(pg_shseclabel, &oldtup->t_self);
+ systable_endscan(scan);
+
+ heap_close(pg_shseclabel, RowExclusiveLock);
+}
+
+/*
* DeleteSecurityLabel removes all security labels for an object (and any
* sub-objects, if applicable).
*/
@@ -288,9 +423,13 @@ DeleteSecurityLabel(const ObjectAddress *object)
HeapTuple oldtup;
int nkeys;
- /* Security labels on shared objects are not supported. */
+ /* Special handling for security labels on shared objects */
if (IsSharedRelation(object->classId))
+ {
+ Assert(object->objectSubId == 0);
+ DeleteSharedSecurityLabel(object->objectId, object->classId);
return;
+ }
ScanKeyInit(&skey[0],
Anum_pg_seclabel_objoid,
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 3024dc4..09ecabb 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -63,6 +63,7 @@
#include "catalog/pg_tablespace.h"
#include "commands/comment.h"
#include "commands/defrem.h"
+#include "commands/seclabel.h"
#include "commands/tablespace.h"
#include "miscadmin.h"
#include "postmaster/bgwriter.h"
@@ -448,9 +449,10 @@ DropTableSpace(DropTableSpaceStmt *stmt)
heap_endscan(scandesc);
/*
- * Remove any comments on this tablespace.
+ * Remove any comments or security labels on this tablespace.
*/
DeleteSharedComments(tablespaceoid, TableSpaceRelationId);
+ DeleteSharedSecurityLabel(tablespaceoid, TableSpaceRelationId);
/*
* Remove dependency on owner.
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 838d6eb..e1cfc85 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -24,6 +24,7 @@
#include "catalog/pg_db_role_setting.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
+#include "commands/seclabel.h"
#include "commands/user.h"
#include "libpq/md5.h"
#include "miscadmin.h"
@@ -894,6 +895,7 @@ DropRole(DropRoleStmt *stmt)
char *detail_log;
SysScanDesc sscan;
Oid roleid;
+ ObjectAddress address;
tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
if (!HeapTupleIsValid(tuple))
@@ -1000,9 +1002,10 @@ DropRole(DropRoleStmt *stmt)
systable_endscan(sscan);
/*
- * Remove any comments on this role.
+ * Remove any comments or security labels on this role.
*/
DeleteSharedComments(roleid, AuthIdRelationId);
+ DeleteSharedSecurityLabel(roleid, AuthIdRelationId);
/*
* Remove settings for this role.
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7226032..ac094aa 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5068,11 +5068,14 @@ opt_provider: FOR ColId_or_Sconst { $$ = $2; }
security_label_type:
COLUMN { $$ = OBJECT_COLUMN; }
+ | DATABASE { $$ = OBJECT_DATABASE; }
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
| SCHEMA { $$ = OBJECT_SCHEMA; }
| SEQUENCE { $$ = OBJECT_SEQUENCE; }
| TABLE { $$ = OBJECT_TABLE; }
| DOMAIN_P { $$ = OBJECT_TYPE; }
+ | ROLE { $$ = OBJECT_ROLE; }
+ | TABLESPACE { $$ = OBJECT_TABLESPACE; }
| TYPE_P { $$ = OBJECT_TYPE; }
| VIEW { $$ = OBJECT_VIEW; }
;
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 99e5f1d..fd71a21 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -44,6 +44,7 @@
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
+#include "catalog/pg_shseclabel.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_ts_config.h"
@@ -587,6 +588,17 @@ static const struct cachedesc cacheinfo[] = {
},
1024
},
+ {SharedSecLabelRelationId, /* SHSECLABELOID */
+ SharedSecLabelObjectIndexId,
+ 3,
+ {
+ Anum_pg_shseclabel_objoid,
+ Anum_pg_shseclabel_classoid,
+ Anum_pg_shseclabel_provider,
+ 0
+ },
+ 256
+ },
{StatisticRelationId, /* STATRELATTINH */
StatisticRelidAttnumInhIndexId,
3,
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index b3ad2ea..b88ebbd 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -52,6 +52,9 @@ static void dumpTimestamp(char *msg);
static void doShellQuoting(PQExpBuffer buf, const char *str);
static int runPgDump(const char *dbname);
+static void buildShSecLabels(PGconn *conn, const char *objtype,
+ uint32 objectId, PQExpBuffer buffer,
+ const char *target, const char *objname);
static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
const char *pguser, enum trivalue prompt_password, bool fail_on_error);
static PGresult *executeQuery(PGconn *conn, const char *query);
@@ -718,15 +721,15 @@ dumpRoles(PGconn *conn)
for (i = 0; i < PQntuples(res); i++)
{
const char *rolename;
+ Oid auth_oid;
+ auth_oid = atooid(PQgetvalue(res, i, i_oid));
rolename = PQgetvalue(res, i, i_rolname);
resetPQExpBuffer(buf);
if (binary_upgrade)
{
- Oid auth_oid = atooid(PQgetvalue(res, i, i_oid));
-
appendPQExpBuffer(buf, "\n-- For binary upgrade, must preserve pg_authid.oid\n");
appendPQExpBuffer(buf,
"SELECT binary_upgrade.set_next_pg_authid_oid('%u'::pg_catalog.oid);\n\n",
@@ -796,6 +799,10 @@ dumpRoles(PGconn *conn)
appendPQExpBuffer(buf, ";\n");
}
+ if (!no_security_labels && server_version >= 90200)
+ buildShSecLabels(conn, "role", auth_oid,
+ buf, "ROLE", fmtId(rolename));
+
fprintf(OPF, "%s", buf->data);
if (server_version >= 70300)
@@ -981,7 +988,7 @@ dumpTablespaces(PGconn *conn)
* pg_xxx)
*/
if (server_version >= 90000)
- res = executeQuery(conn, "SELECT spcname, "
+ res = executeQuery(conn, "SELECT oid, spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"spclocation, spcacl, "
"array_to_string(spcoptions, ', '),"
@@ -990,7 +997,7 @@ dumpTablespaces(PGconn *conn)
"WHERE spcname !~ '^pg_' "
"ORDER BY 1");
else if (server_version >= 80200)
- res = executeQuery(conn, "SELECT spcname, "
+ res = executeQuery(conn, "SELECT oid, spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"spclocation, spcacl, null, "
"pg_catalog.shobj_description(oid, 'pg_tablespace') "
@@ -998,7 +1005,7 @@ dumpTablespaces(PGconn *conn)
"WHERE spcname !~ '^pg_' "
"ORDER BY 1");
else
- res = executeQuery(conn, "SELECT spcname, "
+ res = executeQuery(conn, "SELECT oid, spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"spclocation, spcacl, "
"null, null "
@@ -1012,12 +1019,13 @@ dumpTablespaces(PGconn *conn)
for (i = 0; i < PQntuples(res); i++)
{
PQExpBuffer buf = createPQExpBuffer();
- char *spcname = PQgetvalue(res, i, 0);
- char *spcowner = PQgetvalue(res, i, 1);
- char *spclocation = PQgetvalue(res, i, 2);
- char *spcacl = PQgetvalue(res, i, 3);
- char *spcoptions = PQgetvalue(res, i, 4);
- char *spccomment = PQgetvalue(res, i, 5);
+ uint32 spcoid = atooid(PQgetvalue(res, i, 0));
+ char *spcname = PQgetvalue(res, i, 1);
+ char *spcowner = PQgetvalue(res, i, 2);
+ char *spclocation = PQgetvalue(res, i, 3);
+ char *spcacl = PQgetvalue(res, i, 4);
+ char *spcoptions = PQgetvalue(res, i, 5);
+ char *spccomment = PQgetvalue(res, i, 6);
char *fspcname;
/* needed for buildACLCommands() */
@@ -1051,6 +1059,10 @@ dumpTablespaces(PGconn *conn)
appendPQExpBuffer(buf, ";\n");
}
+ if (!no_security_labels && server_version >= 90200)
+ buildShSecLabels(conn, "tablespace", spcoid,
+ buf, "TABLESPACE", fspcname);
+
fprintf(OPF, "%s", buf->data);
free(fspcname);
@@ -1178,7 +1190,7 @@ dumpCreateDB(PGconn *conn)
/* Now collect all the information about databases to dump */
if (server_version >= 80400)
res = executeQuery(conn,
- "SELECT datname, "
+ "SELECT d.oid, 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, "
@@ -1188,7 +1200,7 @@ dumpCreateDB(PGconn *conn)
"WHERE datallowconn ORDER BY 1");
else if (server_version >= 80100)
res = executeQuery(conn,
- "SELECT datname, "
+ "SELECT d.oid, 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, "
@@ -1198,7 +1210,7 @@ dumpCreateDB(PGconn *conn)
"WHERE datallowconn ORDER BY 1");
else if (server_version >= 80000)
res = executeQuery(conn,
- "SELECT datname, "
+ "SELECT d.oid, 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, "
@@ -1208,7 +1220,7 @@ dumpCreateDB(PGconn *conn)
"WHERE datallowconn ORDER BY 1");
else if (server_version >= 70300)
res = executeQuery(conn,
- "SELECT datname, "
+ "SELECT d.oid, 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, "
@@ -1218,7 +1230,7 @@ dumpCreateDB(PGconn *conn)
"WHERE datallowconn ORDER BY 1");
else if (server_version >= 70100)
res = executeQuery(conn,
- "SELECT datname, "
+ "SELECT d.oid, 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'))), "
@@ -1235,7 +1247,7 @@ dumpCreateDB(PGconn *conn)
* with getting a NULL by not printing any OWNER clause.
*/
res = executeQuery(conn,
- "SELECT datname, "
+ "SELECT d.oid, 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, "
@@ -1248,16 +1260,17 @@ dumpCreateDB(PGconn *conn)
for (i = 0; i < PQntuples(res); i++)
{
- char *dbname = PQgetvalue(res, i, 0);
- char *dbowner = PQgetvalue(res, i, 1);
- char *dbencoding = PQgetvalue(res, i, 2);
- char *dbcollate = PQgetvalue(res, i, 3);
- char *dbctype = PQgetvalue(res, i, 4);
- uint32 dbfrozenxid = atooid(PQgetvalue(res, i, 5));
- char *dbistemplate = PQgetvalue(res, i, 6);
- char *dbacl = PQgetvalue(res, i, 7);
- char *dbconnlimit = PQgetvalue(res, i, 8);
- char *dbtablespace = PQgetvalue(res, i, 9);
+ uint32 dboid = atooid(PQgetvalue(res, i, 0));
+ char *dbname = PQgetvalue(res, i, 1);
+ char *dbowner = PQgetvalue(res, i, 2);
+ char *dbencoding = PQgetvalue(res, i, 3);
+ char *dbcollate = PQgetvalue(res, i, 4);
+ char *dbctype = PQgetvalue(res, i, 5);
+ uint32 dbfrozenxid = atooid(PQgetvalue(res, i, 6));
+ char *dbistemplate = PQgetvalue(res, i, 7);
+ char *dbacl = PQgetvalue(res, i, 8);
+ char *dbconnlimit = PQgetvalue(res, i, 9);
+ char *dbtablespace = PQgetvalue(res, i, 10);
char *fdbname;
fdbname = strdup(fmtId(dbname));
@@ -1344,6 +1357,10 @@ dumpCreateDB(PGconn *conn)
exit(1);
}
+ if (!no_security_labels && server_version >= 90200)
+ buildShSecLabels(conn, "database", dboid,
+ buf, "DATABASE", fdbname);
+
fprintf(OPF, "%s", buf->data);
if (server_version >= 70300)
@@ -1615,6 +1632,43 @@ runPgDump(const char *dbname)
return ret;
}
+/*
+ * buildShSecLabels
+ *
+ * Build SECURITY LABEL command(s) for an shared object
+ *
+ * The caller has to provide object type and identifier to select security
+ * labels from pg_seclabels system view.
+ */
+static void
+buildShSecLabels(PGconn *conn, const char *objtype, uint32 objectId,
+ PQExpBuffer buffer, const char *target, const char *objname)
+{
+ PQExpBuffer sql = createPQExpBuffer();
+ PGresult *res;
+ int i;
+
+ appendPQExpBuffer(sql,
+ "SELECT provider, label FROM pg_seclabels "
+ "WHERE objtype = '%s' AND objoid = %u",
+ objtype, objectId);
+
+ res = executeQuery(conn, sql->data);
+
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ char *provider = PQgetvalue(res, i, 0);
+ char *label = PQgetvalue(res, i, 1);
+
+ appendPQExpBuffer(buffer,
+ "SECURITY LABEL FOR %s ON %s %s IS ",
+ fmtId(provider), target, objname);
+ appendStringLiteralConn(buffer, label, conn);
+ appendPQExpBuffer(buffer, ";\n");
+ }
+ PQclear(res);
+ destroyPQExpBuffer(sql);
+}
/*
* Make a database connection with the given parameters. An
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index 4118e64..27500ce 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -294,6 +294,9 @@ DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_rol
DECLARE_UNIQUE_INDEX(pg_seclabel_object_index, 3597, on pg_seclabel using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops, provider text_ops));
#define SecLabelObjectIndexId 3597
+DECLARE_UNIQUE_INDEX(pg_shseclabel_object_index, 3593, on pg_shseclabel using btree(objoid oid_ops, classoid oid_ops, provider name_ops));
+#define SharedSecLabelObjectIndexId 3593
+
DECLARE_UNIQUE_INDEX(pg_extension_oid_index, 3080, on pg_extension using btree(oid oid_ops));
#define ExtensionOidIndexId 3080
diff --git a/src/include/catalog/pg_shseclabel.h b/src/include/catalog/pg_shseclabel.h
new file mode 100644
index 0000000..87ef4c6
--- /dev/null
+++ b/src/include/catalog/pg_shseclabel.h
@@ -0,0 +1,41 @@
+/* -------------------------------------------------------------------------
+ *
+ * pg_shseclabel.h
+ * definition of the system "security label" relation (pg_shseclabel)
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * -------------------------------------------------------------------------
+ */
+#ifndef PG_SHSECLABEL_H
+#define PG_SHSECLABEL_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ * pg_shseclabel definition. cpp turns this into
+ * typedef struct FormData_pg_shseclabel
+ * ----------------
+ */
+#define SharedSecLabelRelationId 3592
+
+CATALOG(pg_shseclabel,3592) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
+{
+ Oid objoid; /* OID of the shared object itself */
+ Oid classoid; /* OID of table containing the shared object */
+ NameData provider; /* name of label provider */
+ text label; /* security label of the object */
+} FormData_pg_shseclabel;
+
+/* ----------------
+ * compiler constants for pg_shseclabel
+ * ----------------
+ */
+#define Natts_pg_shseclabel 4
+#define Anum_pg_shseclabel_objoid 1
+#define Anum_pg_shseclabel_classoid 2
+#define Anum_pg_shseclabel_provider 3
+#define Anum_pg_shseclabel_label 4
+
+#endif /* PG_SHSECLABEL_H */
diff --git a/src/include/commands/seclabel.h b/src/include/commands/seclabel.h
index 06ce602..1a0282c 100644
--- a/src/include/commands/seclabel.h
+++ b/src/include/commands/seclabel.h
@@ -21,6 +21,7 @@ extern char *GetSecurityLabel(const ObjectAddress *object,
extern void SetSecurityLabel(const ObjectAddress *object,
const char *provider, const char *label);
extern void DeleteSecurityLabel(const ObjectAddress *object);
+extern void DeleteSharedSecurityLabel(Oid objectId, Oid classId);
/*
* Statement and ESP hook support
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 55d2230..780744b 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -73,6 +73,7 @@ enum SysCacheIdentifier
RELNAMENSP,
RELOID,
RULERELNAME,
+ SHSECLABELOID,
STATRELATTINH,
TABLESPACEOID,
TSCONFIGMAP,
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 20cdc39..63253dc 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1276,8 +1276,8 @@ drop table cchild;
-- Check that ruleutils are working
--
SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
- viewname | definition
----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ viewname | definition
+---------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
pg_available_extension_versions | SELECT e.name, e.version, (x.extname IS NOT NULL) AS installed, e.superuser, e.relocatable, e.schema, e.requires, e.comment FROM (pg_available_extension_versions() e(name, version, superuser, relocatable, schema, requires, comment) LEFT JOIN pg_extension x ON (((e.name = x.extname) AND (e.version = x.extversion))));
pg_available_extensions | SELECT e.name, e.default_version, x.extversion AS installed_version, e.comment FROM (pg_available_extensions() e(name, default_version, comment) LEFT JOIN pg_extension x ON ((e.name = x.extname)));
@@ -1289,7 +1289,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
pg_prepared_xacts | SELECT p.transaction, p.gid, p.prepared, u.rolname AS owner, d.datname AS database FROM ((pg_prepared_xact() p(transaction, gid, prepared, ownerid, dbid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid)));
pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolreplication, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, s.setconfig AS rolconfig, pg_authid.oid FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid))));
pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
- pg_seclabels | (((((SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (rel.relkind = 'r'::"char") THEN 'table'::text WHEN (rel.relkind = 'v'::"char") THEN 'view'::text WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text WHEN (rel.relkind = 'f'::"char") THEN 'foreign table'::text ELSE NULL::text END AS objtype, rel.relnamespace AS objnamespace, CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid = 0) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'column'::text AS objtype, rel.relnamespace AS objnamespace, ((CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END || '.'::text) || (att.attname)::text) AS objname, l.provider, l.label FROM (((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid <> 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (pro.proisagg = true) THEN 'aggregate'::text WHEN (pro.proisagg = false) THEN 'function'::text ELSE NULL::text END AS objtype, pro.pronamespace AS objnamespace, (((CASE WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text)) END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid)))) JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text ELSE 'type'::text END AS objtype, typ.typnamespace AS objnamespace, CASE WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid)))) JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'large object'::text AS objtype, NULL::oid AS objnamespace, (l.objoid)::text AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid))) WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0))) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'language'::text AS objtype, NULL::oid AS objnamespace, quote_ident((lan.lanname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'schema'::text AS objtype, nsp.oid AS objnamespace, quote_ident((nsp.nspname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid)))) WHERE (l.objsubid = 0);
+ pg_seclabels | ((((((((SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (rel.relkind = 'r'::"char") THEN 'table'::text WHEN (rel.relkind = 'v'::"char") THEN 'view'::text WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text WHEN (rel.relkind = 'f'::"char") THEN 'foreign table'::text ELSE NULL::text END AS objtype, rel.relnamespace AS objnamespace, CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid = 0) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'column'::text AS objtype, rel.relnamespace AS objnamespace, ((CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END || '.'::text) || (att.attname)::text) AS objname, l.provider, l.label FROM (((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid <> 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (pro.proisagg = true) THEN 'aggregate'::text WHEN (pro.proisagg = false) THEN 'function'::text ELSE NULL::text END AS objtype, pro.pronamespace AS objnamespace, (((CASE WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text)) END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid)))) JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text ELSE 'type'::text END AS objtype, typ.typnamespace AS objnamespace, CASE WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid)))) JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'large object'::text AS objtype, NULL::oid AS objnamespace, (l.objoid)::text AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid))) WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0))) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'language'::text AS objtype, NULL::oid AS objnamespace, quote_ident((lan.lanname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'schema'::text AS objtype, nsp.oid AS objnamespace, quote_ident((nsp.nspname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'database'::text AS objtype, NULL::oid AS objnamespace, quote_ident((dat.datname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_database dat ON (((l.classoid = dat.tableoid) AND (l.objoid = dat.oid))))) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'tablespace'::text AS objtype, NULL::oid AS objnamespace, quote_ident((spc.spcname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_tablespace spc ON (((l.classoid = spc.tableoid) AND (l.objoid = spc.oid))))) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'role'::text AS objtype, NULL::oid AS objnamespace, quote_ident((rol.rolname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_authid rol ON (((l.classoid = rol.tableoid) AND (l.objoid = rol.oid))));
pg_settings | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val, a.enumvals, a.boot_val, a.reset_val, a.sourcefile, a.sourceline FROM pg_show_all_settings() a(name, setting, unit, category, short_desc, extra_desc, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, sourcefile, sourceline);
pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolreplication AS userepl, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, s.setconfig AS useconfig FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))) WHERE pg_authid.rolcanlogin;
pg_stat_activity | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_hostname, s.client_port, s.backend_start, s.xact_start, s.query_start, s.waiting, s.current_query FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, application_name, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_hostname, client_port), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index ab9e891..d42b0ea 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -120,6 +120,7 @@ SELECT relname, relhasindex
pg_seclabel | t
pg_shdepend | t
pg_shdescription | t
+ pg_shseclabel | t
pg_statistic | t
pg_tablespace | t
pg_trigger | t
@@ -157,7 +158,7 @@ SELECT relname, relhasindex
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
-(146 rows)
+(147 rows)
--
-- another sanity check: every system catalog that has OIDs should have
diff --git a/src/test/regress/input/security_label.source b/src/test/regress/input/security_label.source
index 810a721..e556d23 100644
--- a/src/test/regress/input/security_label.source
+++ b/src/test/regress/input/security_label.source
@@ -12,7 +12,7 @@ DROP TABLE IF EXISTS seclabel_tbl1;
DROP TABLE IF EXISTS seclabel_tbl2;
DROP TABLE IF EXISTS seclabel_tbl3;
-CREATE USER seclabel_user1;
+CREATE USER seclabel_user1 WITH CREATEROLE;
CREATE USER seclabel_user2;
CREATE TABLE seclabel_tbl1 (a int, b text);
@@ -34,6 +34,11 @@ SECURITY LABEL FOR 'dummy' ON TABLE seclabel_tbl1 IS 'classified'; -- fail
SECURITY LABEL ON TABLE seclabel_tbl1 IS '...invalid label...'; -- fail
SECURITY LABEL ON TABLE seclabel_tbl3 IS 'unclassified'; -- fail
+SECURITY LABEL ON ROLE seclabel_user1 IS 'classified'; -- fail
+SECURITY LABEL FOR 'dummy' ON ROLE seclabel_user1 IS 'classified'; -- fail
+SECURITY LABEL ON ROLE seclabel_user1 IS '...invalid label...'; -- fail
+SECURITY LABEL ON ROLE seclabel_user3 IS 'unclassified'; -- fail
+
-- Load dummy external security provider
LOAD '@libdir@/dummy_seclabel@DLSUFFIX@';
@@ -55,6 +60,26 @@ SET SESSION AUTHORIZATION seclabel_user2;
SECURITY LABEL ON TABLE seclabel_tbl1 IS 'unclassified'; -- fail
SECURITY LABEL ON TABLE seclabel_tbl2 IS 'classified'; -- OK
+--
+-- Test for shared database object
+--
+SET SESSION AUTHORIZATION seclabel_user1;
+
+SECURITY LABEL ON ROLE seclabel_user1 IS 'classified'; -- OK
+SECURITY LABEL ON ROLE seclabel_user1 IS '...invalid label...'; -- fail
+SECURITY LABEL FOR 'dummy' ON ROLE seclabel_user2 IS 'unclassified'; -- OK
+SECURITY LABEL FOR 'unknown_seclabel' ON ROLE seclabel_user1 IS 'unclassified'; -- fail
+SECURITY LABEL ON ROLE seclabel_user1 IS 'secret'; -- fail (not superuser)
+SECURITY LABEL ON ROLE seclabel_user3 IS 'unclassified'; -- fail (not found)
+
+SET SESSION AUTHORIZATION seclabel_user2;
+SECURITY LABEL ON ROLE seclabel_user2 IS 'unclassified'; -- fail (not privileged)
+
+RESET SESSION AUTHORIZATION;
+
+--
+-- Test for various types of object
+--
RESET SESSION AUTHORIZATION;
SECURITY LABEL ON TABLE seclabel_tbl1 IS 'top secret'; -- OK
@@ -63,12 +88,17 @@ SECURITY LABEL ON FUNCTION seclabel_four() IS 'classified'; -- OK
SECURITY LABEL ON DOMAIN seclabel_domain IS 'classified'; -- OK
SECURITY LABEL ON LANGUAGE plpgsql IS 'unclassified'; -- OK
SECURITY LABEL ON SCHEMA public IS 'unclassified'; -- OK
+SECURITY LABEL ON DATABASE postgres IS 'secret'; -- OK
+SECURITY LABEL ON TABLESPACE pg_default IS 'classified'; -- OK
SELECT objtype, objname, provider, label FROM pg_seclabels
ORDER BY objtype, objname;
+-- clean up labels
SECURITY LABEL ON LANGUAGE plpgsql IS NULL; -- OK
SECURITY LABEL ON SCHEMA public IS NULL; -- OK
+SECURITY LABEL ON DATABASE postgres IS NULL; -- OK
+SECURITY LABEL ON TABLESPACE pg_default IS NULL; -- OK
-- clean up objects
DROP FUNCTION seclabel_four();
diff --git a/src/test/regress/output/security_label.source b/src/test/regress/output/security_label.source
index 4bc803d..f713beb 100644
--- a/src/test/regress/output/security_label.source
+++ b/src/test/regress/output/security_label.source
@@ -8,7 +8,7 @@ DROP ROLE IF EXISTS seclabel_user2;
DROP TABLE IF EXISTS seclabel_tbl1;
DROP TABLE IF EXISTS seclabel_tbl2;
DROP TABLE IF EXISTS seclabel_tbl3;
-CREATE USER seclabel_user1;
+CREATE USER seclabel_user1 WITH CREATEROLE;
CREATE USER seclabel_user2;
CREATE TABLE seclabel_tbl1 (a int, b text);
CREATE TABLE seclabel_tbl2 (x int, y text);
@@ -29,6 +29,14 @@ SECURITY LABEL ON TABLE seclabel_tbl1 IS '...invalid label...'; -- fail
ERROR: no security label providers have been loaded
SECURITY LABEL ON TABLE seclabel_tbl3 IS 'unclassified'; -- fail
ERROR: no security label providers have been loaded
+SECURITY LABEL ON ROLE seclabel_user1 IS 'classified'; -- fail
+ERROR: no security label providers have been loaded
+SECURITY LABEL FOR 'dummy' ON ROLE seclabel_user1 IS 'classified'; -- fail
+ERROR: security label provider "dummy" is not loaded
+SECURITY LABEL ON ROLE seclabel_user1 IS '...invalid label...'; -- fail
+ERROR: no security label providers have been loaded
+SECURITY LABEL ON ROLE seclabel_user3 IS 'unclassified'; -- fail
+ERROR: no security label providers have been loaded
-- Load dummy external security provider
LOAD '@abs_builddir@/dummy_seclabel@DLSUFFIX@';
--
@@ -52,6 +60,27 @@ SET SESSION AUTHORIZATION seclabel_user2;
SECURITY LABEL ON TABLE seclabel_tbl1 IS 'unclassified'; -- fail
ERROR: must be owner of relation seclabel_tbl1
SECURITY LABEL ON TABLE seclabel_tbl2 IS 'classified'; -- OK
+--
+-- Test for shared database object
+--
+SET SESSION AUTHORIZATION seclabel_user1;
+SECURITY LABEL ON ROLE seclabel_user1 IS 'classified'; -- OK
+SECURITY LABEL ON ROLE seclabel_user1 IS '...invalid label...'; -- fail
+ERROR: '...invalid label...' is not a valid security label
+SECURITY LABEL FOR 'dummy' ON ROLE seclabel_user2 IS 'unclassified'; -- OK
+SECURITY LABEL FOR 'unknown_seclabel' ON ROLE seclabel_user1 IS 'unclassified'; -- fail
+ERROR: security label provider "unknown_seclabel" is not loaded
+SECURITY LABEL ON ROLE seclabel_user1 IS 'secret'; -- fail (not superuser)
+ERROR: only superuser can set 'secret' label
+SECURITY LABEL ON ROLE seclabel_user3 IS 'unclassified'; -- fail (not found)
+ERROR: role "seclabel_user3" does not exist
+SET SESSION AUTHORIZATION seclabel_user2;
+SECURITY LABEL ON ROLE seclabel_user2 IS 'unclassified'; -- fail (not privileged)
+ERROR: must have CREATEROLE privilege
+RESET SESSION AUTHORIZATION;
+--
+-- Test for various types of object
+--
RESET SESSION AUTHORIZATION;
SECURITY LABEL ON TABLE seclabel_tbl1 IS 'top secret'; -- OK
SECURITY LABEL ON VIEW seclabel_view1 IS 'classified'; -- OK
@@ -59,22 +88,31 @@ SECURITY LABEL ON FUNCTION seclabel_four() IS 'classified'; -- OK
SECURITY LABEL ON DOMAIN seclabel_domain IS 'classified'; -- OK
SECURITY LABEL ON LANGUAGE plpgsql IS 'unclassified'; -- OK
SECURITY LABEL ON SCHEMA public IS 'unclassified'; -- OK
+SECURITY LABEL ON DATABASE postgres IS 'secret'; -- OK
+SECURITY LABEL ON TABLESPACE pg_default IS 'classified'; -- OK
SELECT objtype, objname, provider, label FROM pg_seclabels
ORDER BY objtype, objname;
- objtype | objname | provider | label
-----------+-----------------+----------+--------------
- column | seclabel_tbl1.a | dummy | unclassified
- domain | seclabel_domain | dummy | classified
- function | seclabel_four() | dummy | classified
- language | plpgsql | dummy | unclassified
- schema | public | dummy | unclassified
- table | seclabel_tbl1 | dummy | top secret
- table | seclabel_tbl2 | dummy | classified
- view | seclabel_view1 | dummy | classified
-(8 rows)
+ objtype | objname | provider | label
+------------+-----------------+----------+--------------
+ column | seclabel_tbl1.a | dummy | unclassified
+ database | postgres | dummy | secret
+ domain | seclabel_domain | dummy | classified
+ function | seclabel_four() | dummy | classified
+ language | plpgsql | dummy | unclassified
+ role | seclabel_user1 | dummy | classified
+ role | seclabel_user2 | dummy | unclassified
+ schema | public | dummy | unclassified
+ table | seclabel_tbl1 | dummy | top secret
+ table | seclabel_tbl2 | dummy | classified
+ tablespace | pg_default | dummy | classified
+ view | seclabel_view1 | dummy | classified
+(12 rows)
+-- clean up labels
SECURITY LABEL ON LANGUAGE plpgsql IS NULL; -- OK
SECURITY LABEL ON SCHEMA public IS NULL; -- OK
+SECURITY LABEL ON DATABASE postgres IS NULL; -- OK
+SECURITY LABEL ON TABLESPACE pg_default IS NULL; -- OK
-- clean up objects
DROP FUNCTION seclabel_four();
DROP DOMAIN seclabel_domain;