[v9.2] SECURITY LABEL on shared database object
[I noticed my new address was not registered to pgsql-hackers, so try again]
The attached patch enables to assign security labels of shared database object
types (databases, tablespaces, roles).
Like as pg_shdescription doing, it adds a new pg_shseclabel catalog corresponding
to the existing pg_seclabel catalog. Its internal APIs are kept; if and when
(Get|Set|Delete)SecurityLabel is invoked for shared catalogs, it references the
pg_shseclabel instead of the pg_seclabel.
This patch also contains pg_dump support, use cases of contrib/sepgsql, regression
test and updates of sgml documentation.
Thanks,
--
NEC Europe Ltd, SAP Global Competence Center
KaiGai Kohei <kohei.kaigai@eu.nec.com>
Attachments:
pgsql-shared-security-label.1.patchapplication/octet-stream; name=pgsql-shared-security-label.1.patchDownload
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 | 5 +
src/backend/catalog/system_views.sql | 32 +++++-
src/backend/commands/seclabel.c | 176 +++++++++++++++++++++++++-
src/backend/parser/gram.y | 3 +
src/bin/pg_dump/pg_dumpall.c | 108 ++++++++++++----
src/include/catalog/indexing.h | 3 +
src/include/catalog/pg_shseclabel.h | 41 ++++++
src/include/catalog/toasting.h | 3 +
src/test/regress/expected/rules.out | 6 +-
src/test/regress/expected/sanity_check.out | 3 +-
src/test/regress/input/security_label.source | 32 +++++-
20 files changed, 590 insertions(+), 51 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 7b62818..707fad8 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>
@@ -4672,6 +4677,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>
@@ -4950,6 +4962,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>text</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..a8995de 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)
@@ -403,6 +406,8 @@ IsSharedRelation(Oid relationId)
relationId == PgDatabaseToastIndex ||
relationId == PgShdescriptionToastTable ||
relationId == PgShdescriptionToastIndex ||
+ relationId == PgShSecLabelToastTable ||
+ relationId == PgShSecLabelToastIndex ||
relationId == PgDbRoleSettingToastTable ||
relationId == PgDbRoleSettingToastIndex)
return true;
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/seclabel.c b/src/backend/commands/seclabel.c
index 7afb713..63d2818 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"
@@ -134,6 +135,54 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
}
/*
+ * GetSharedSecurityLabel is a helper function of GetSecurityLabel to
+ * handle shared database objects.
+ */
+static char *
+GetSharedSecurityLabel(const ObjectAddress *object, const char *provider)
+{
+ Relation pg_shseclabel;
+ ScanKeyData keys[3];
+ SysScanDesc scan;
+ HeapTuple tuple;
+ Datum datum;
+ bool isnull;
+ char *seclabel = NULL;
+
+ 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_TEXTEQ,
+ CStringGetTextDatum(provider));
+
+ pg_shseclabel = heap_open(SharedSecLabelRelationId, AccessShareLock);
+
+ scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
+ SnapshotNow, 3, keys);
+
+ tuple = systable_getnext(scan);
+ if (HeapTupleIsValid(tuple))
+ {
+ datum = heap_getattr(tuple, Anum_pg_shseclabel_label,
+ RelationGetDescr(pg_shseclabel), &isnull);
+ if (!isnull)
+ seclabel = TextDatumGetCString(datum);
+ }
+ systable_endscan(scan);
+
+ heap_close(pg_shseclabel, AccessShareLock);
+
+ return seclabel;
+}
+
+/*
* GetSecurityLabel returns the security label for a database object for a
* given provider, or NULL if there is no such label.
*/
@@ -148,7 +197,9 @@ 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))
+ return GetSharedSecurityLabel(object, provider);
ScanKeyInit(&keys[0],
Anum_pg_seclabel_objoid,
@@ -187,6 +238,84 @@ 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;
+ 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));
+ values[Anum_pg_shseclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
+ values[Anum_pg_shseclabel_classoid - 1] = ObjectIdGetDatum(object->classId);
+ values[Anum_pg_shseclabel_provider - 1] = CStringGetTextDatum(provider);
+ 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_TEXTEQ,
+ CStringGetTextDatum(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
@@ -205,8 +334,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));
@@ -275,6 +408,38 @@ SetSecurityLabel(const ObjectAddress *object,
}
/*
+ * DeleteSharedSecurityLabel is a helper function of DeleteSecurityLabel
+ * to handle shared database objects.
+ */
+static void
+DeleteSharedSecurityLabel(const ObjectAddress *object)
+{
+ Relation pg_shseclabel;
+ ScanKeyData skey[2];
+ SysScanDesc scan;
+ HeapTuple oldtup;
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_shseclabel_objoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+ ScanKeyInit(&skey[1],
+ Anum_pg_shseclabel_classoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->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).
*/
@@ -287,9 +452,12 @@ 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))
+ {
+ DeleteSharedSecurityLabel(object);
return;
+ }
ScanKeyInit(&skey[0],
Anum_pg_seclabel_objoid,
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index dd95961..6eac2c2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5073,11 +5073,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/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 41a3307..62f6e91 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_label && 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_label && 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_label && 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..9a8e6ff 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 text_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..d1b07da
--- /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 */
+ text 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/catalog/toasting.h b/src/include/catalog/toasting.h
index de3623ac..41cc0a1 100644
--- a/src/include/catalog/toasting.h
+++ b/src/include/catalog/toasting.h
@@ -56,6 +56,9 @@ DECLARE_TOAST(pg_database, 2844, 2845);
DECLARE_TOAST(pg_shdescription, 2846, 2847);
#define PgShdescriptionToastTable 2846
#define PgShdescriptionToastIndex 2847
+DECLARE_TOAST(pg_shseclabel, 3594, 3595);
+#define PgShSecLabelToastTable 3594
+#define PgShSecLabelToastIndex 3595
DECLARE_TOAST(pg_db_role_setting, 2966, 2967);
#define PgDbRoleSettingToastTable 2966
#define PgDbRoleSettingToastIndex 2967
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();
The attached patch is an update revision of security label support
for shared database objects.
It contains bug fixes of cleanups when user drops databases,
tablespaces or roles.
And it also modified to use syscache to reference security label
of shared database objects according to the implementation
discussed in the sepgsql-uavc thread.
2011/5/9 Kohei Kaigai <Kohei.Kaigai@emea.nec.com>:
[I noticed my new address was not registered to pgsql-hackers, so try again]
The attached patch enables to assign security labels of shared database object
types (databases, tablespaces, roles).
Like as pg_shdescription doing, it adds a new pg_shseclabel catalog corresponding
to the existing pg_seclabel catalog. Its internal APIs are kept; if and when
(Get|Set|Delete)SecurityLabel is invoked for shared catalogs, it references the
pg_shseclabel instead of the pg_seclabel.This patch also contains pg_dump support, use cases of contrib/sepgsql, regression
test and updates of sgml documentation.Thanks,
--
NEC Europe Ltd, SAP Global Competence Center
KaiGai Kohei <kohei.kaigai@eu.nec.com>--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
pgsql-v9.2-shared-seclabel.2.patchapplication/octet-stream; name=pgsql-v9.2-shared-seclabel.2.patchDownload
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 | 5 +
src/backend/catalog/system_views.sql | 32 ++++++-
src/backend/commands/dbcommands.c | 5 +-
src/backend/commands/seclabel.c | 145 ++++++++++++++++++++++++-
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/catalog/toasting.h | 3 +
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 +++++++++--
27 files changed, 634 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 8504555..f64d745 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>
@@ -4672,6 +4677,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>
@@ -4950,6 +4962,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>text</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..a8995de 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)
@@ -403,6 +406,8 @@ IsSharedRelation(Oid relationId)
relationId == PgDatabaseToastIndex ||
relationId == PgShdescriptionToastTable ||
relationId == PgShdescriptionToastIndex ||
+ relationId == PgShSecLabelToastTable ||
+ relationId == PgShSecLabelToastIndex ||
relationId == PgDbRoleSettingToastTable ||
relationId == PgDbRoleSettingToastIndex)
return true;
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 7afb713..baa4a04 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"
@@ -23,6 +24,7 @@
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
+#include "utils/syscache.h"
#include "utils/tqual.h"
typedef struct
@@ -148,7 +150,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),
+ CStringGetTextDatum(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,
@@ -187,6 +206,84 @@ 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;
+ 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));
+ values[Anum_pg_shseclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
+ values[Anum_pg_shseclabel_classoid - 1] = ObjectIdGetDatum(object->classId);
+ values[Anum_pg_shseclabel_provider - 1] = CStringGetTextDatum(provider);
+ 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_TEXTEQ,
+ CStringGetTextDatum(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
@@ -205,8 +302,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));
@@ -275,6 +376,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).
*/
@@ -287,9 +420,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 1d39674..e38cd52 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5071,11 +5071,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 75f510c..fa7449d 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..9a8e6ff 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 text_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..d1b07da
--- /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 */
+ text 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/catalog/toasting.h b/src/include/catalog/toasting.h
index de3623ac..41cc0a1 100644
--- a/src/include/catalog/toasting.h
+++ b/src/include/catalog/toasting.h
@@ -56,6 +56,9 @@ DECLARE_TOAST(pg_database, 2844, 2845);
DECLARE_TOAST(pg_shdescription, 2846, 2847);
#define PgShdescriptionToastTable 2846
#define PgShdescriptionToastIndex 2847
+DECLARE_TOAST(pg_shseclabel, 3594, 3595);
+#define PgShSecLabelToastTable 3594
+#define PgShSecLabelToastIndex 3595
DECLARE_TOAST(pg_db_role_setting, 2966, 2967);
#define PgDbRoleSettingToastTable 2966
#define PgDbRoleSettingToastIndex 2967
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;
On Mon, Jun 13, 2011 at 12:24 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
The attached patch is an update revision of security label support
for shared database objects.
I'm kind of unexcited about this whole idea. Adding a shared catalog
for a feature that's only of interest to a small percentage of our
user population seems unfortunate.
Are there any other possible approaches to this problem?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
2011/6/13 Robert Haas <robertmhaas@gmail.com>:
On Mon, Jun 13, 2011 at 12:24 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
The attached patch is an update revision of security label support
for shared database objects.I'm kind of unexcited about this whole idea. Adding a shared catalog
for a feature that's only of interest to a small percentage of our
user population seems unfortunate.Are there any other possible approaches to this problem?
If unexcited about the new shared catalog, one possible idea
is to add a new field to pg_database, pg_tablespace and
pg_authid to store security labels?
The reason why we had pg_seclabel is to avoid massive amount
of modifications to system catalog. But only 3 catalogs to be
modified to support security label on shared object.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
On Mon, Jun 13, 2011 at 1:40 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
2011/6/13 Robert Haas <robertmhaas@gmail.com>:
On Mon, Jun 13, 2011 at 12:24 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
The attached patch is an update revision of security label support
for shared database objects.I'm kind of unexcited about this whole idea. Adding a shared catalog
for a feature that's only of interest to a small percentage of our
user population seems unfortunate.Are there any other possible approaches to this problem?
If unexcited about the new shared catalog, one possible idea
is to add a new field to pg_database, pg_tablespace and
pg_authid to store security labels?The reason why we had pg_seclabel is to avoid massive amount
of modifications to system catalog. But only 3 catalogs to be
modified to support security label on shared object.
I guess maybe my real question here is - what do you plan to do with
those security labels, from a security perspective? For example:
roles. The user's security contect AIUI is passed over from the
remote side; his DAC role doesn't even enter into it from a MAC
perspective. Or does it?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
2011/6/13 Robert Haas <robertmhaas@gmail.com>:
On Mon, Jun 13, 2011 at 1:40 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
2011/6/13 Robert Haas <robertmhaas@gmail.com>:
On Mon, Jun 13, 2011 at 12:24 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
The attached patch is an update revision of security label support
for shared database objects.I'm kind of unexcited about this whole idea. Adding a shared catalog
for a feature that's only of interest to a small percentage of our
user population seems unfortunate.Are there any other possible approaches to this problem?
If unexcited about the new shared catalog, one possible idea
is to add a new field to pg_database, pg_tablespace and
pg_authid to store security labels?The reason why we had pg_seclabel is to avoid massive amount
of modifications to system catalog. But only 3 catalogs to be
modified to support security label on shared object.I guess maybe my real question here is - what do you plan to do with
those security labels, from a security perspective? For example:
roles. The user's security contect AIUI is passed over from the
remote side; his DAC role doesn't even enter into it from a MAC
perspective. Or does it?
The current primary target of security label of shared object is
to acquire control on databases.
It performs as a basis to compute default security label of
underlying objects, and I also plan to control when we open
the connection like ACL_CONNECT.
Right now, we assume any database has "system_u:object_r:sepgsql_db_t:s0",
then the default security label of schema objects are computed.
(See sepgsql_schema_post_create in contrib/sepgsql/schema.c)
Regarding to the pg_tablespace and pg_authid, I have a plan to
control DDL statements on these objects, However, its priority
is not higher than databases or other non-shared objects such
as tables or procedures.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
On Mon, Jun 13, 2011 at 2:33 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
2011/6/13 Robert Haas <robertmhaas@gmail.com>:
On Mon, Jun 13, 2011 at 1:40 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
2011/6/13 Robert Haas <robertmhaas@gmail.com>:
On Mon, Jun 13, 2011 at 12:24 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
The attached patch is an update revision of security label support
for shared database objects.I'm kind of unexcited about this whole idea. Adding a shared catalog
for a feature that's only of interest to a small percentage of our
user population seems unfortunate.Are there any other possible approaches to this problem?
If unexcited about the new shared catalog, one possible idea
is to add a new field to pg_database, pg_tablespace and
pg_authid to store security labels?The reason why we had pg_seclabel is to avoid massive amount
of modifications to system catalog. But only 3 catalogs to be
modified to support security label on shared object.I guess maybe my real question here is - what do you plan to do with
those security labels, from a security perspective? For example:
roles. The user's security contect AIUI is passed over from the
remote side; his DAC role doesn't even enter into it from a MAC
perspective. Or does it?The current primary target of security label of shared object is
to acquire control on databases.
It performs as a basis to compute default security label of
underlying objects, and I also plan to control when we open
the connection like ACL_CONNECT.
Right now, we assume any database has "system_u:object_r:sepgsql_db_t:s0",
then the default security label of schema objects are computed.
(See sepgsql_schema_post_create in contrib/sepgsql/schema.c)Regarding to the pg_tablespace and pg_authid, I have a plan to
control DDL statements on these objects, However, its priority
is not higher than databases or other non-shared objects such
as tables or procedures.
Hmm, OK. I guess what I'm not sure about is - how much should we
worry about the fact that this creates several more shared (and
therefore nailed?) system catalogs? Anyone have an opinion on that?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Excerpts from Robert Haas's message of mar jul 05 10:19:18 -0400 2011:
Hmm, OK. I guess what I'm not sure about is - how much should we
worry about the fact that this creates several more shared (and
therefore nailed?) system catalogs? Anyone have an opinion on that?
"Several"? That would worry me, given that we currently have a small
number (eight currently). If it's just one more, I don't think it's
such a big deal. I'm not sure what you mean by nailed though -- I mean,
for example pg_shdescription is shared but not nailed in the rd_isnailed
sense of the word, AFAICS.
--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
On Tue, Jul 5, 2011 at 10:49 AM, Alvaro Herrera
<alvherre@commandprompt.com> wrote:
Excerpts from Robert Haas's message of mar jul 05 10:19:18 -0400 2011:
Hmm, OK. I guess what I'm not sure about is - how much should we
worry about the fact that this creates several more shared (and
therefore nailed?) system catalogs? Anyone have an opinion on that?"Several"? That would worry me, given that we currently have a small
number (eight currently). If it's just one more, I don't think it's
such a big deal. I'm not sure what you mean by nailed though -- I mean,
for example pg_shdescription is shared but not nailed in the rd_isnailed
sense of the word, AFAICS.
Well, right now the patch has pg_shseclabel, and its index, plus a
toast table and a toast index. Not sure why we want/need the toast
table & index there, but the patch has 'em as of now.
As for whether it needs to be nailed, I'm not sure I understand what
the rules are there. I *think* the rule is that anything that might
need to be consulted before choosing a database must be nailed. If
that's right, we might be able to get by without nailing it, as long
as the label isn't needed during authentication (or its use can be
postponed until after we've connected to a database).
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Tue, Jul 5, 2011 at 10:49 AM, Alvaro Herrera
<alvherre@commandprompt.com> wrote:Excerpts from Robert Haas's message of mar jul 05 10:19:18 -0400 2011:
Hmm, OK. I guess what I'm not sure about is - how much should we
worry about the fact that this creates several more shared (and
therefore nailed?) system catalogs? Anyone have an opinion on that?"Several"? That would worry me, given that we currently have a small
number (eight currently). If it's just one more, I don't think it's
such a big deal. I'm not sure what you mean by nailed though -- I mean,
for example pg_shdescription is shared but not nailed in the rd_isnailed
sense of the word, AFAICS.Well, right now the patch has pg_shseclabel, and its index, plus a
toast table and a toast index. Not sure why we want/need the toast
table & index there, but the patch has 'em as of now.
As a common belief, TEXT is a variable length data type, so pg_shseclabel
need to have its toast table. However, I don't expect the label field get
represented as a reference to external pointer, because average length of
security context is about 40-60 bytes much less than the threshold to
launch toast_save_datum().
Do I need to remove these toast table & index?
As for whether it needs to be nailed, I'm not sure I understand what
the rules are there. I *think* the rule is that anything that might
need to be consulted before choosing a database must be nailed. If
that's right, we might be able to get by without nailing it, as long
as the label isn't needed during authentication (or its use can be
postponed until after we've connected to a database).
In SELinux, all we are doing in the authentication hook is to acquire
security label of the client, without referencing any catalogs.
I also plan to support permission checks on the selected database
in the future, however, I believe its hook should be placed in
CheckMyDatabase() according to the existing checks.
Thanks,
--
NEC Europe Ltd, SAP Global Competence Center
KaiGai Kohei <kohei.kaigai@emea.nec.com>
Excerpts from Kohei Kaigai's message of mar jul 05 11:46:06 -0400 2011:
On Tue, Jul 5, 2011 at 10:49 AM, Alvaro Herrera
<alvherre@commandprompt.com> wrote:Excerpts from Robert Haas's message of mar jul 05 10:19:18 -0400 2011:
Hmm, OK. I guess what I'm not sure about is - how much should we
worry about the fact that this creates several more shared (and
therefore nailed?) system catalogs? Anyone have an opinion on that?"Several"? That would worry me, given that we currently have a small
number (eight currently). If it's just one more, I don't think it's
such a big deal. I'm not sure what you mean by nailed though -- I mean,
for example pg_shdescription is shared but not nailed in the rd_isnailed
sense of the word, AFAICS.Well, right now the patch has pg_shseclabel, and its index, plus a
toast table and a toast index. Not sure why we want/need the toast
table & index there, but the patch has 'em as of now.As a common belief, TEXT is a variable length data type, so pg_shseclabel
need to have its toast table. However, I don't expect the label field get
represented as a reference to external pointer, because average length of
security context is about 40-60 bytes much less than the threshold to
launch toast_save_datum().
Do I need to remove these toast table & index?
We don't have toast tables for pg_database and so on, for example, which
means that datacl cannot go over a few hundred bytes long. I think it
makes sense to not have toast tables for pg_shseclabel. Keep in mind
that the label might be compressed before it's stored out of line, which
gives you quite a bit of actual space. If a security context is over
5000 bytes in length I think you're in trouble :-)
--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
2011/7/5 Alvaro Herrera <alvherre@commandprompt.com>:
Excerpts from Kohei Kaigai's message of mar jul 05 11:46:06 -0400 2011:
On Tue, Jul 5, 2011 at 10:49 AM, Alvaro Herrera
<alvherre@commandprompt.com> wrote:Excerpts from Robert Haas's message of mar jul 05 10:19:18 -0400 2011:
Hmm, OK. I guess what I'm not sure about is - how much should we
worry about the fact that this creates several more shared (and
therefore nailed?) system catalogs? Anyone have an opinion on that?"Several"? That would worry me, given that we currently have a small
number (eight currently). If it's just one more, I don't think it's
such a big deal. I'm not sure what you mean by nailed though -- I mean,
for example pg_shdescription is shared but not nailed in the rd_isnailed
sense of the word, AFAICS.Well, right now the patch has pg_shseclabel, and its index, plus a
toast table and a toast index. Not sure why we want/need the toast
table & index there, but the patch has 'em as of now.As a common belief, TEXT is a variable length data type, so pg_shseclabel
need to have its toast table. However, I don't expect the label field get
represented as a reference to external pointer, because average length of
security context is about 40-60 bytes much less than the threshold to
launch toast_save_datum().
Do I need to remove these toast table & index?We don't have toast tables for pg_database and so on, for example, which
means that datacl cannot go over a few hundred bytes long. I think it
makes sense to not have toast tables for pg_shseclabel. Keep in mind
that the label might be compressed before it's stored out of line, which
gives you quite a bit of actual space. If a security context is over
5000 bytes in length I think you're in trouble :-)
The attached patch removes toast table & index for pg_shseclabel.
The current toasting.h defines toast table & index on pg_database,
pg_shdescription and pg_db_role_setting only.
The pg_authid and pg_tablespace don't have toast table & index
in spite of variable-length field.
So, it might not be a necessary stuff for all the shared relations.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
pgsql-v9.2-shared-security-label.v5.patchapplication/octet-stream; name=pgsql-v9.2-shared-security-label.v5.patchDownload
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;
On Wed, Jul 6, 2011 at 1:25 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
2011/7/5 Alvaro Herrera <alvherre@commandprompt.com>:
Excerpts from Kohei Kaigai's message of mar jul 05 11:46:06 -0400 2011:
On Tue, Jul 5, 2011 at 10:49 AM, Alvaro Herrera
<alvherre@commandprompt.com> wrote:Excerpts from Robert Haas's message of mar jul 05 10:19:18 -0400 2011:
Hmm, OK. I guess what I'm not sure about is - how much should we
worry about the fact that this creates several more shared (and
therefore nailed?) system catalogs? Anyone have an opinion on that?"Several"? That would worry me, given that we currently have a small
number (eight currently). If it's just one more, I don't think it's
such a big deal. I'm not sure what you mean by nailed though -- I mean,
for example pg_shdescription is shared but not nailed in the rd_isnailed
sense of the word, AFAICS.Well, right now the patch has pg_shseclabel, and its index, plus a
toast table and a toast index. Not sure why we want/need the toast
table & index there, but the patch has 'em as of now.As a common belief, TEXT is a variable length data type, so pg_shseclabel
need to have its toast table. However, I don't expect the label field get
represented as a reference to external pointer, because average length of
security context is about 40-60 bytes much less than the threshold to
launch toast_save_datum().
Do I need to remove these toast table & index?We don't have toast tables for pg_database and so on, for example, which
means that datacl cannot go over a few hundred bytes long. I think it
makes sense to not have toast tables for pg_shseclabel. Keep in mind
that the label might be compressed before it's stored out of line, which
gives you quite a bit of actual space. If a security context is over
5000 bytes in length I think you're in trouble :-)The attached patch removes toast table & index for pg_shseclabel.
The current toasting.h defines toast table & index on pg_database,
pg_shdescription and pg_db_role_setting only.
The pg_authid and pg_tablespace don't have toast table & index
in spite of variable-length field.
So, it might not be a necessary stuff for all the shared relations.
I have committed this with fairly extensive revisions. The main
things I changed were:
- The pg_dump/pg_dumpall support was broken for databases and
needlessly inefficient for roles and tablespaces. (Parenthetically,
it is hard to blame anyone for screwing up the code here when it is
spaghetti code to begin with.)
- I did not commit the contrib/sepgsql parts of the patch, as I
haven't reviewed them. I think it would be helpful for you to
resubmit those separately.
- I didn't think it was a good idea to make pg_shseclabel.provider a
name while leaving pg_seclabel.provider as a text field. Surely these
two catalogs need to stay parallel. For the same reason, I didn't
like the idea of installing a syscache for pg_shseclabel while
pg_seclabel soldiers on without one. So for now I ripped out that
logic and instead made it work the old, slow way. I know we need a
better solution here, but I want to come up with a plan that handles
both catalogs symmetrically and then do it all at once, rather than
piecemeal.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company