SECURITY LABEL on shared database object
I signed up to do a review on $subject patch for the commitfest. In
order to do that, I want to get SELinux and contrib/sepgsql properly set
up so that I can test. I ran into a problem when trying to do:
cd contrib/sepgsql
make install (succeeds)
make installcheck (fails)
I get this:
============== creating database "contrib_regression" ==============
ERROR: could not determine which collation to use for string
comparison
HINT: Use the COLLATE clause to set the collation explicitly.
command failed: "/usr/local/pgsql-head/bin/psql" -X -c "CREATE
DATABASE \"contrib_regression\" TEMPLATE=template0" "postgres"
make: *** [installcheck] Error 2
So I installed sepgsql into the postgres database anyway and do this:
postgres=# SELECT sepgsql_restorecon(NULL);
ERROR: could not determine which collation to use for string
comparison
HINT: Use the COLLATE clause to set the collation explicitly.
Ok, so now I go look at the docs to figure out what exactly a "COLLATE
clause" is. Only searching the online docs brings up no hits on the
keyword COLLATE". Google brings me to TODO wiki page:
http://wiki.postgresql.org/wiki/Todo:Collate
But that isn't much help either. Grepping the source gets hits in 9.1
and master. So I guess:
1) COLLATE clause is a new feature in 9.1?
2) The doc search feature on postgresql.org does not search the 9.1
documentation?
I looked in the 9.1 docs in SQL Commands->SELECT and could find no
reference to COLLATE. Can anyone point me to some documentation that
would explain what that error message means and how to resolve it?
Thanks,
Joe
--
Joe Conway
credativ LLC: http://www.credativ.us
Linux, PostgreSQL, and general Open Source
Training, Service, Consulting, & 24x7 Support
On 06/29/2011 04:18 PM, Joe Conway wrote:
1) COLLATE clause is a new feature in 9.1?
2) The doc search feature on postgresql.org does not search the 9.1
documentation?I looked in the 9.1 docs in SQL Commands->SELECT and could find no
reference to COLLATE. Can anyone point me to some documentation that
would explain what that error message means and how to resolve it?
A little more information. It seems that sepgsql_restorecon calls
GetSecurityLabel in the backend. Here's the backtrace:
8<-----------------
#0 errfinish (dummy=0) at elog.c:374
#1 0x00000000007b7c70 in varstr_cmp (arg1=0x7faeb724efa9 "selinux",
len1=7, arg2=0x16a1d8c "selinux~", len2=7, collid=0) at varlena.c:1312
#2 0x00000000007b7f01 in text_cmp (arg1=0x7faeb724efa8, arg2=0x16a1d88,
collid=0) at varlena.c:1468
#3 0x00000000007b8424 in bttextcmp (fcinfo=0x7ffff08e2b30) at
varlena.c:1610
#4 0x0000000000819c93 in FunctionCall2Coll (flinfo=0x7ffff08e30a0,
collation=0, arg1=140388373688232, arg2=23731592) at fmgr.c:1319
#5 0x000000000049a905 in _bt_compare (rel=0x7faeb6f71540, keysz=3,
scankey=0x7ffff08e3090, page=0x7faeb724cfc0 "", offnum=1) at nbtsearch.c:406
#6 0x000000000049a2c6 in _bt_binsrch (rel=0x7faeb6f71540, buf=74,
keysz=3, scankey=0x7ffff08e3000, nextkey=0 '\000') at nbtsearch.c:285
#7 0x000000000049b17b in _bt_first (scan=0x169ce28,
dir=ForwardScanDirection) at nbtsearch.c:877
#8 0x0000000000498971 in btgettuple (fcinfo=0x7ffff08e3af0) at nbtree.c:315
#9 0x0000000000819c93 in FunctionCall2Coll (flinfo=0x168e0d8,
collation=0, arg1=23711272, arg2=1) at fmgr.c:1319
#10 0x000000000048eeed in index_getnext (scan=0x169ce28,
direction=ForwardScanDirection) at indexam.c:487
#11 0x000000000048da81 in systable_getnext (sysscan=0x16a1020) at
genam.c:315
#12 0x00000000007fa322 in SearchCatCache (cache=0x1613700, v1=1,
v2=1262, v3=23731592, v4=0) at catcache.c:1201
#13 0x00000000008091c0 in SearchSysCache (cacheId=44, key1=1, key2=1262,
key3=23731592, key4=0) at syscache.c:859
#14 0x00000000005a7016 in GetSecurityLabel (object=0x7ffff08e43d0,
provider=0x7faeb9713830 "selinux") at seclabel.c:157
8<-----------------
The third key passed to SearchSysCache is CStringGetTextDatum(provider).
Ultimately FunctionCall2Coll gets called with collation == 0 and
varstr_cmp fails due to the ambiguity.
Is there something new that should be used in place of
CStringGetTextDatum that would convey a collation here?
Joe
--
Joe Conway
credativ LLC: http://www.credativ.us
Linux, PostgreSQL, and general Open Source
Training, Service, Consulting, & 24x7 Support
On 06/29/2011 05:34 PM, Joe Conway wrote:
The third key passed to SearchSysCache is CStringGetTextDatum(provider).
Ultimately FunctionCall2Coll gets called with collation == 0 and
varstr_cmp fails due to the ambiguity.Is there something new that should be used in place of
CStringGetTextDatum that would convey a collation here?
(Sorry about replying to myself again...)
In fmgr.h we have:
8<-------------------------
/* These macros allow the collation argument to be omitted (with a
default of
* InvalidOid, ie, no collation). They exist mostly for backwards
* compatibility of source code.
*/
#define DirectFunctionCall1(func, arg1) \
DirectFunctionCall1Coll(func, InvalidOid, arg1)
#define DirectFunctionCall2(func, arg1, arg2) \
DirectFunctionCall2Coll(func, InvalidOid, arg1, arg2)
#define DirectFunctionCall3(func, arg1, arg2, arg3) \
DirectFunctionCall3Coll(func, InvalidOid, arg1, arg2, arg3)
[...]
8<--------------------------
Perhaps instead of InvalidOid here we should be using DEFAULT_COLLATION_OID?
Joe
--
Joe Conway
credativ LLC: http://www.credativ.us
Linux, PostgreSQL, and general Open Source
Training, Service, Consulting, & 24x7 Support
Thanks for your reviewing, and Sorry for this debugging burden.
The origin of matter is, as you mentioned, collation to be used for system
catalog scan when we reference it via syscache.
So, the following chunk should be added, as I did in the userspace access
vector patch - part.1.
The attached patch is fixed version.
@@ -934,8 +935,7 @@ CatalogCacheInitializeCache(CatCache *cache)
/* Fill in sk_strategy as well --- always standard equality */
cache->cc_skey[i].sk_strategy = BTEqualStrategyNumber;
cache->cc_skey[i].sk_subtype = InvalidOid;
- /* Currently, there are no catcaches on collation-aware data types */
- cache->cc_skey[i].sk_collation = InvalidOid;
+ cache->cc_skey[i].sk_collation = DEFAULT_COLLATION_OID;
CACHE4_elog(DEBUG2, "CatalogCacheInitializeCache %s %d %p",
cache->cc_relname,
Thanks,
2011/6/30 Joe Conway <mail@joeconway.com>:
I signed up to do a review on $subject patch for the commitfest. In
order to do that, I want to get SELinux and contrib/sepgsql properly set
up so that I can test. I ran into a problem when trying to do:cd contrib/sepgsql
make install (succeeds)
make installcheck (fails)I get this:
============== creating database "contrib_regression" ==============
ERROR: could not determine which collation to use for string
comparison
HINT: Use the COLLATE clause to set the collation explicitly.
command failed: "/usr/local/pgsql-head/bin/psql" -X -c "CREATE
DATABASE \"contrib_regression\" TEMPLATE=template0" "postgres"
make: *** [installcheck] Error 2So I installed sepgsql into the postgres database anyway and do this:
postgres=# SELECT sepgsql_restorecon(NULL);
ERROR: could not determine which collation to use for string
comparison
HINT: Use the COLLATE clause to set the collation explicitly.Ok, so now I go look at the docs to figure out what exactly a "COLLATE
clause" is. Only searching the online docs brings up no hits on the
keyword COLLATE". Google brings me to TODO wiki page:http://wiki.postgresql.org/wiki/Todo:Collate
But that isn't much help either. Grepping the source gets hits in 9.1
and master. So I guess:1) COLLATE clause is a new feature in 9.1?
2) The doc search feature on postgresql.org does not search the 9.1
documentation?I looked in the 9.1 docs in SQL Commands->SELECT and could find no
reference to COLLATE. Can anyone point me to some documentation that
would explain what that error message means and how to resolve it?Thanks,
Joe
--
Joe Conway
credativ LLC: http://www.credativ.us
Linux, PostgreSQL, and general Open Source
Training, Service, Consulting, & 24x7 Support
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
pgsql-v9.2-shared-security-label.v3.patchapplication/octet-stream; name=pgsql-v9.2-shared-security-label.v3.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/catcache.c | 4 +-
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 +++++++++--
28 files changed, 636 insertions(+), 68 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 713ee25..7d49def 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>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 51a5567..30992d9 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 62cff8a..adc6d89 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5067,11 +5067,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/catcache.c b/src/backend/utils/cache/catcache.c
index 350e040..68c3fde 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -20,6 +20,7 @@
#include "access/relscan.h"
#include "access/sysattr.h"
#include "access/valid.h"
+#include "catalog/pg_collation.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
@@ -934,8 +935,7 @@ CatalogCacheInitializeCache(CatCache *cache)
/* Fill in sk_strategy as well --- always standard equality */
cache->cc_skey[i].sk_strategy = BTEqualStrategyNumber;
cache->cc_skey[i].sk_subtype = InvalidOid;
- /* Currently, there are no catcaches on collation-aware data types */
- cache->cc_skey[i].sk_collation = InvalidOid;
+ cache->cc_skey[i].sk_collation = DEFAULT_COLLATION_OID;
CACHE4_elog(DEBUG2, "CatalogCacheInitializeCache %s %d %p",
cache->cc_relname,
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..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;
Kohei KaiGai <kaigai@kaigai.gr.jp> writes:
The origin of matter is, as you mentioned, collation to be used for system
catalog scan when we reference it via syscache.
So, the following chunk should be added, as I did in the userspace access
vector patch - part.1.
@@ -934,8 +935,7 @@ CatalogCacheInitializeCache(CatCache *cache) /* Fill in sk_strategy as well --- always standard equality */ cache->cc_skey[i].sk_strategy = BTEqualStrategyNumber; cache->cc_skey[i].sk_subtype = InvalidOid; - /* Currently, there are no catcaches on collation-aware data types */ - cache->cc_skey[i].sk_collation = InvalidOid; + cache->cc_skey[i].sk_collation = DEFAULT_COLLATION_OID;
I removed such a hunk from a previous patch of yours, and I don't like
it any better this time. This is just a hack that will result in
masking bugs.
Consider using a non-collation-aware datatype instead, such as NAME.
regards, tom lane
2011/7/2 Tom Lane <tgl@sss.pgh.pa.us>:
Kohei KaiGai <kaigai@kaigai.gr.jp> writes:
The origin of matter is, as you mentioned, collation to be used for system
catalog scan when we reference it via syscache.
So, the following chunk should be added, as I did in the userspace access
vector patch - part.1.@@ -934,8 +935,7 @@ CatalogCacheInitializeCache(CatCache *cache)
/* Fill in sk_strategy as well --- always standard equality */
cache->cc_skey[i].sk_strategy = BTEqualStrategyNumber;
cache->cc_skey[i].sk_subtype = InvalidOid;
- /* Currently, there are no catcaches on collation-aware data types */
- cache->cc_skey[i].sk_collation = InvalidOid;
+ cache->cc_skey[i].sk_collation = DEFAULT_COLLATION_OID;I removed such a hunk from a previous patch of yours, and I don't like
it any better this time. This is just a hack that will result in
masking bugs.Consider using a non-collation-aware datatype instead, such as NAME.
I agree that pg_(sh)seclabel.provider field shall not need more than
NAMEDATALEN.
How about re-define pg_seclabel.provider field also; currently defined as TEXT?
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
The attached patch re-defines pg_shseclabel.provider as NameData,
instead of Text,
and revert changes to catcache.c about collation.
Rest of parts are not changed.
Thanks,
2011/7/2 Kohei KaiGai <kaigai@kaigai.gr.jp>:
2011/7/2 Tom Lane <tgl@sss.pgh.pa.us>:
Kohei KaiGai <kaigai@kaigai.gr.jp> writes:
The origin of matter is, as you mentioned, collation to be used for system
catalog scan when we reference it via syscache.
So, the following chunk should be added, as I did in the userspace access
vector patch - part.1.@@ -934,8 +935,7 @@ CatalogCacheInitializeCache(CatCache *cache)
/* Fill in sk_strategy as well --- always standard equality */
cache->cc_skey[i].sk_strategy = BTEqualStrategyNumber;
cache->cc_skey[i].sk_subtype = InvalidOid;
- /* Currently, there are no catcaches on collation-aware data types */
- cache->cc_skey[i].sk_collation = InvalidOid;
+ cache->cc_skey[i].sk_collation = DEFAULT_COLLATION_OID;I removed such a hunk from a previous patch of yours, and I don't like
it any better this time. This is just a hack that will result in
masking bugs.Consider using a non-collation-aware datatype instead, such as NAME.
I agree that pg_(sh)seclabel.provider field shall not need more than
NAMEDATALEN.How about re-define pg_seclabel.provider field also; currently defined as TEXT?
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
pgsql-v9.2-shared-security-label.v4.patchapplication/octet-stream; name=pgsql-v9.2-shared-security-label.v4.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 | 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/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, 636 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 713ee25..d1924ad 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..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 51a5567..83066ac 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),
+ 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,
@@ -187,6 +206,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
@@ -205,8 +304,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 +378,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 +422,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 62cff8a..adc6d89 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5067,11 +5067,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/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;