dblink \
dict_int \
dict_xsyn \
+ dummy_seclabel \
earthdistance \
fuzzystrmatch \
hstore \
--- /dev/null
+# contrib/dummy_seclabel/Makefile
+
+MODULES = dummy_seclabel
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/dummy_seclabel
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
--- /dev/null
+/*
+ * dummy_seclabel.c
+ *
+ * Dummy security label provider.
+ *
+ * This module does not provide anything worthwhile from a security
+ * perspective, but allows regression testing independent of platform-specific
+ * features like SELinux.
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ */
+#include "postgres.h"
+
+#include "commands/seclabel.h"
+#include "miscadmin.h"
+
+PG_MODULE_MAGIC;
+
+/* Entrypoint of the module */
+void _PG_init(void);
+
+static void
+dummy_object_relabel(const ObjectAddress *object, const char *seclabel)
+{
+ if (seclabel == NULL ||
+ strcmp(seclabel, "unclassified") == 0 ||
+ strcmp(seclabel, "classified") == 0)
+ return;
+
+ if (strcmp(seclabel, "secret") == 0 ||
+ strcmp(seclabel, "top secret") == 0)
+ {
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser can set '%s' label", seclabel)));
+ return;
+ }
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_NAME),
+ errmsg("'%s' is not a valid security label", seclabel)));
+}
+
+void
+_PG_init(void)
+{
+ register_label_provider("dummy", dummy_object_relabel);
+}
<entry>query rewrite rules</entry>
</row>
+ <row>
+ <entry><link linkend="catalog-pg-seclabel"><structname>pg_seclabel</structname></link></entry>
+ <entry>security labels on database objects</entry>
+ </row>
+
<row>
<entry><link linkend="catalog-pg-shdepend"><structname>pg_shdepend</structname></link></entry>
<entry>dependencies on shared objects</entry>
</sect1>
+ <sect1 id="catalog-pg-seclabel">
+ <title><structname>pg_seclabel</structname></title>
+
+ <indexterm zone="catalog-pg-seclabel">
+ <primary>pg_seclabel</primary>
+ </indexterm>
+
+ <para>
+ The catalog <structname>pg_seclabel</structname> stores security
+ labels on database objects. See the
+ <xref linkend="sql-security-label"> statement.
+ </para>
+
+ <table>
+ <title><structname>pg_seclabel</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>objsubid</structfield></entry>
+ <entry><type>int4</type></entry>
+ <entry></entry>
+ <entry>
+ For a security label on a table column, this is the column number (the
+ <structfield>objoid</> and <structfield>classoid</> refer to
+ the table itself). For all other object types, this column is
+ zero.
+ </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-shdepend">
<title><structname>pg_shdepend</structname></title>
<entry>rules</entry>
</row>
+ <row>
+ <entry><link linkend="view-pg-seclabels"><structname>pg_seclabels</structname></link></entry>
+ <entry>security labels</entry>
+ </row>
+
<row>
<entry><link linkend="view-pg-settings"><structname>pg_settings</structname></link></entry>
<entry>parameter settings</entry>
</sect1>
+ <sect1 id="view-pg-seclabels">
+ <title><structname>pg_seclabels</structname></title>
+
+ <indexterm zone="view-pg-seclabels">
+ <primary>pg_seclabels</primary>
+ </indexterm>
+
+ <para>
+ The view <structname>pg_seclabels</structname> provides information about
+ security labels. It as an easier-to-query version of the
+ <link linkend="catalog-pg-seclabel"><structname>pg_seclabel</></> catalog.
+ </para>
+
+ <table>
+ <title><structname>pg_seclabels</> 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>objsubid</structfield></entry>
+ <entry><type>int4</type></entry>
+ <entry></entry>
+ <entry>
+ For a security label on a table column, this is the column number (the
+ <structfield>objoid</> and <structfield>classoid</> refer to
+ the table itself). For all other object types, this column is
+ zero.
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>objtype</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry></entry>
+ <entry>
+ The type of object to which this label applies, as text.
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>objnamespace</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-namespace"><structname>pg_namespace</structname></link>.oid</literal></entry>
+ <entry>
+ The OID of the namespace for this object, if applicable;
+ otherwise NULL.
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>objname</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry></entry>
+ <entry>
+ The name of the object to which this label applies, as text.
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>provider</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry><literal><link linkend="catalog-pg-seclabel"><structname>pg_seclabel</structname></link>.provider</literal></entry>
+ <entry>The label provider associated with this label.</entry>
+ </row>
+ <row>
+ <entry><structfield>label</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry><literal><link linkend="catalog-pg-seclabel"><structname>pg_seclabel</structname></link>.label</literal></entry>
+ <entry>The security label applied to this object.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
<sect1 id="view-pg-settings">
<title><structname>pg_settings</structname></title>
<!entity rollbackPrepared system "rollback_prepared.sgml">
<!entity rollbackTo system "rollback_to.sgml">
<!entity savepoint system "savepoint.sgml">
+<!entity securityLabel system "security_label.sgml">
<!entity select system "select.sgml">
<!entity selectInto system "select_into.sgml">
<!entity set system "set.sgml">
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><option>--security-label</option></term>
+ <listitem>
+ <para>
+ With this option, it also outputs security labels of database
+ objects to be dumped, if labeled.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
</refsect1>
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--security-label</option></term>
+ <listitem>
+ <para>
+ With this option, it also outputs security labels of database
+ objects to be dumped, if labeled.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
</refsect1>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-security-label</option></term>
+ <listitem>
+ <para>
+ Do not output commands to restore security labels,
+ even if the archive contains them.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>-P <replaceable class="parameter">function-name(argtype [, ...])</replaceable></option></term>
<term><option>--function=<replaceable class="parameter">function-name(argtype [, ...])</replaceable></option></term>
--- /dev/null
+<!--
+$PostgreSQL$
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-SECURITY-LABEL">
+ <refmeta>
+ <refentrytitle>SECURITY LABEL</refentrytitle>
+ <manvolnum>7</manvolnum>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>SECURITY LABEL</refname>
+ <refpurpose>define or change a security label applied to an object</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-security-label">
+ <primary>SECURITY LABEL</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+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> [, ...] ) |
+ DOMAIN <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> |
+ SCHEMA <replaceable class="PARAMETER">object_name</replaceable> |
+ SEQUENCE <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>'
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>SECURITY LABEL</command> applies a security label to a database
+ object. An arbitrary number of security labels, one per label provider, can
+ be associated with a given database object. Label providers are loadable
+ modules which register themselves by using the function
+ <function>register_label_provider</>.
+ </para>
+
+ <note>
+ <para>
+ <function>register_label_provider</> is not an SQL function; it can
+ only be called from C code loaded into the backend.
+ </para>
+ </note>
+
+ <para>
+ The label provider determines whether a given a label is valid and whether
+ it is permissible to assign that label to a given object. The meaning of a
+ given label is likewise at the discretion of the label provider.
+ <productname>PostgreSQL</> places no restrictions on whether or how a
+ label provider must interpret security labels; it merely provides a
+ mechanism for storing them. In practice, this facility is intended to allow
+ integration with label-based mandatory access control (MAC) systems such as
+ <productname>SE-Linux</>. Such systems make all access control decisions
+ based on object labels, rather than traditional discretionary access control
+ (DAC) concepts such as users and groups.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="parameter">object_name</replaceable></term>
+ <term><replaceable class="parameter">table_name.column_name</replaceable></term>
+ <term><replaceable class="parameter">agg_name</replaceable></term>
+ <term><replaceable class="parameter">function_name</replaceable></term>
+ <listitem>
+ <para>
+ The name of the object to be commented. Names of tables,
+ aggregates, domains, functions, sequences, types, and views can
+ be schema-qualified.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">provider</replaceable></term>
+ <listitem>
+ <para>
+ The name of the provider with which this label is to be associated. The
+ named provider must be loaded and must consent to the proposed labeling
+ operation. If exactly one provider is loaded, the provider name may be
+ omitted for brevity.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">argmode</replaceable></term>
+
+ <listitem>
+ <para>
+ The mode of a function argument: <literal>IN</>, <literal>OUT</>,
+ <literal>INOUT</>, or <literal>VARIADIC</>.
+ If omitted, the default is <literal>IN</>.
+ Note that <command>COMMENT ON FUNCTION</command> does not actually pay
+ any attention to <literal>OUT</> arguments, since only the input
+ arguments are needed to determine the function's identity.
+ So it is sufficient to list the <literal>IN</>, <literal>INOUT</>,
+ and <literal>VARIADIC</> arguments.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">argname</replaceable></term>
+
+ <listitem>
+ <para>
+ The name of a function argument.
+ Note that <command>COMMENT ON FUNCTION</command> does not actually pay
+ any attention to argument names, since only the argument data
+ types are needed to determine the function's identity.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">argtype</replaceable></term>
+
+ <listitem>
+ <para>
+ The data type(s) of the function's arguments (optionally
+ schema-qualified), if any.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">large_object_oid</replaceable></term>
+ <listitem>
+ <para>
+ The OID of the large object.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>PROCEDURAL</literal></term>
+
+ <listitem>
+ <para>
+ This is a noise word.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">label</replaceable></term>
+ <listitem>
+ <para>
+ The new security label, written as a string literal; or <literal>NULL</>
+ to drop the security label.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ The following example shows how the security label of a table might
+ be changed.
+
+<programlisting>
+SECURITY LABEL FOR selinux ON TABLE mytable IS 'system_u:object_r:sepgsql_table_t:s0';
+</programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+ <para>
+ There is no <command>SECURITY LABEL</command> command in the SQL standard.
+ </para>
+ </refsect1>
+</refentry>
&rollbackPrepared;
&rollbackTo;
&savepoint;
+ &securityLabel;
&select;
&selectInto;
&set;
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
pg_ts_parser.h pg_ts_template.h \
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
- pg_default_acl.h \
+ pg_default_acl.h pg_seclabel.h \
toasting.h indexing.h \
)
#include "commands/defrem.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
+#include "commands/seclabel.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
doDeletion(object);
/*
- * Delete any comments associated with this object. (This is a convenient
- * place to do it instead of having every object type know to do it.)
+ * Delete any comments or security labels associated with this object.
+ * (This is a convenient place to do these things, rather than having every
+ * object type know to do it.)
*/
DeleteComments(object->objectId, object->classId, object->objectSubId);
+ DeleteSecurityLabel(object);
/*
* CommandCounterIncrement here to ensure that preceding changes are all
CREATE VIEW pg_prepared_statements AS
SELECT * FROM pg_prepared_statement() AS P;
+CREATE VIEW pg_seclabels AS
+SELECT
+ l.objoid, l.classoid, l.objsubid,
+ CASE WHEN rel.relkind = 'r' THEN 'table'::text
+ WHEN rel.relkind = 'v' THEN 'view'::text
+ WHEN rel.relkind = 'S' THEN 'sequence'::text END AS objtype,
+ rel.relnamespace AS objnamespace,
+ CASE WHEN pg_table_is_visible(rel.oid)
+ THEN quote_ident(rel.relname)
+ ELSE quote_ident(nsp.nspname) || '.' || quote_ident(rel.relname)
+ 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)
+ ELSE quote_ident(nsp.nspname) || '.' || quote_ident(rel.relname)
+ END || '.' || att.attname 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
+ END AS objtype,
+ pro.pronamespace AS objnamespace,
+ CASE WHEN pg_function_is_visible(pro.oid)
+ THEN quote_ident(pro.proname)
+ ELSE quote_ident(nsp.nspname) || '.' || quote_ident(pro.proname)
+ END || '(' || pg_catalog.pg_get_function_arguments(pro.oid) || ')' 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' 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)
+ ELSE quote_ident(nsp.nspname) || '.' || quote_ident(typ.typname)
+ 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_catalog.pg_largeobject'::regclass 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) 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) 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;
+
CREATE VIEW pg_settings AS
SELECT * FROM pg_show_all_settings() AS A;
dbcommands.o define.o discard.o explain.o foreigncmds.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \
- schemacmds.o sequence.o tablecmds.o tablespace.o trigger.o \
+ schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
variable.o view.o
--- /dev/null
+/* -------------------------------------------------------------------------
+ *
+ * seclabel.c
+ * routines to support security label feature.
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catalog.h"
+#include "catalog/indexing.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_seclabel.h"
+#include "commands/seclabel.h"
+#include "miscadmin.h"
+#include "utils/acl.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/tqual.h"
+
+/*
+ * For most object types, the permissions-checking logic is simple enough
+ * that it makes sense to just include it in CommentObject(). However,
+ * attributes require a bit more checking.
+ */
+static void CheckAttributeSecLabel(Relation relation);
+
+typedef struct
+{
+ const char *provider_name;
+ check_object_relabel_type hook;
+} LabelProvider;
+
+static List *label_provider_list = NIL;
+
+/*
+ * ExecSecLabelStmt --
+ *
+ * Apply a security label to a database object.
+ */
+void
+ExecSecLabelStmt(SecLabelStmt *stmt)
+{
+ LabelProvider *provider = NULL;
+ ObjectAddress address;
+ Relation relation;
+ ListCell *lc;
+
+ /*
+ * Find the named label provider, or if none specified, check whether
+ * there's exactly one, and if so use it.
+ */
+ if (stmt->provider == NULL)
+ {
+ if (label_provider_list == NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("security label providers have been loaded")));
+ if (lnext(list_head(label_provider_list)) != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("must specify provider when multiple security label providers have been loaded")));
+ provider = (LabelProvider *) linitial(label_provider_list);
+ }
+ else
+ {
+ foreach (lc, label_provider_list)
+ {
+ LabelProvider *lp = lfirst(lc);
+
+ if (strcmp(stmt->provider, lp->provider_name) == 0)
+ {
+ provider = lp;
+ break;
+ }
+ }
+ if (provider == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("security label provider \"%s\" is not loaded",
+ stmt->provider)));
+ }
+
+ /*
+ * Translate the parser representation which identifies this object
+ * into an ObjectAddress. get_object_address() will throw an error if
+ * the object does not exist, and will also acquire a lock on the
+ * target to guard against concurrent modifications.
+ */
+ address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
+ &relation, ShareUpdateExclusiveLock);
+
+ /* Privilege and integrity checks. */
+ switch (stmt->objtype)
+ {
+ case OBJECT_SEQUENCE:
+ case OBJECT_TABLE:
+ case OBJECT_VIEW:
+ if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+ RelationGetRelationName(relation));
+ break;
+ case OBJECT_COLUMN:
+ CheckAttributeSecLabel(relation);
+ break;
+ case OBJECT_TYPE:
+ if (!pg_type_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
+ format_type_be(address.objectId));
+ break;
+ case OBJECT_AGGREGATE:
+ case OBJECT_FUNCTION:
+ if (!pg_proc_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+ NameListToString(stmt->objname));
+ break;
+ case OBJECT_SCHEMA:
+ if (!pg_namespace_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
+ strVal(linitial(stmt->objname)));
+ break;
+ case OBJECT_LANGUAGE:
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to comment on procedural language")));
+ break;
+ case OBJECT_LARGEOBJECT:
+ if (!pg_largeobject_ownercheck(address.objectId, GetUserId()))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be owner of large object %u",
+ address.objectId)));
+ break;
+ default:
+ elog(ERROR, "unrecognized object type: %d",
+ (int) stmt->objtype);
+ }
+
+ /* Provider gets control here, may throw ERROR to veto new label. */
+ (*provider->hook)(&address, stmt->label);
+
+ /* Apply new label. */
+ SetSecurityLabel(&address, provider->provider_name, stmt->label);
+
+ /*
+ * If get_object_address() opened the relation for us, we close it to keep
+ * the reference count correct - but we retain any locks acquired by
+ * get_object_address() until commit time, to guard against concurrent
+ * activity.
+ */
+ if (relation != NULL)
+ relation_close(relation, NoLock);
+}
+
+/*
+ * GetSecurityLabel returns the security label for a database object for a
+ * given provider, or NULL if there is no such label.
+ */
+char *
+GetSecurityLabel(const ObjectAddress *object, const char *provider)
+{
+ Relation pg_seclabel;
+ ScanKeyData keys[4];
+ SysScanDesc scan;
+ HeapTuple tuple;
+ Datum datum;
+ bool isnull;
+ char *seclabel = NULL;
+
+ Assert(!IsSharedRelation(object->classId));
+
+ ScanKeyInit(&keys[0],
+ Anum_pg_seclabel_objoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+ ScanKeyInit(&keys[1],
+ Anum_pg_seclabel_classoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->classId));
+ ScanKeyInit(&keys[2],
+ Anum_pg_seclabel_objsubid,
+ BTEqualStrategyNumber, F_INT4EQ,
+ Int32GetDatum(object->objectSubId));
+ ScanKeyInit(&keys[3],
+ Anum_pg_seclabel_provider,
+ BTEqualStrategyNumber, F_TEXTEQ,
+ CStringGetTextDatum(provider));
+
+ pg_seclabel = heap_open(SecLabelRelationId, AccessShareLock);
+
+ scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
+ SnapshotNow, 4, keys);
+
+ tuple = systable_getnext(scan);
+ if (HeapTupleIsValid(tuple))
+ {
+ datum = heap_getattr(tuple, Anum_pg_seclabel_label,
+ RelationGetDescr(pg_seclabel), &isnull);
+ if (!isnull)
+ seclabel = TextDatumGetCString(datum);
+ }
+ systable_endscan(scan);
+
+ heap_close(pg_seclabel, AccessShareLock);
+
+ return seclabel;
+}
+
+/*
+ * SetSecurityLabel attempts to set the security label for the specified
+ * provider on the specified object to the given value. NULL means that any
+ * any existing label should be deleted.
+ */
+void
+SetSecurityLabel(const ObjectAddress *object,
+ const char *provider, const char *label)
+{
+ Relation pg_seclabel;
+ ScanKeyData keys[4];
+ SysScanDesc scan;
+ HeapTuple oldtup;
+ HeapTuple newtup = NULL;
+ Datum values[Natts_pg_seclabel];
+ bool nulls[Natts_pg_seclabel];
+ bool replaces[Natts_pg_seclabel];
+
+ /* Security labels on shared objects are not supported. */
+ Assert(!IsSharedRelation(object->classId));
+
+ /* Prepare to form or update a tuple, if necessary. */
+ memset(nulls, false, sizeof(nulls));
+ memset(replaces, false, sizeof(replaces));
+ values[Anum_pg_seclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
+ values[Anum_pg_seclabel_classoid - 1] = ObjectIdGetDatum(object->classId);
+ values[Anum_pg_seclabel_objsubid - 1] = Int32GetDatum(object->objectSubId);
+ values[Anum_pg_seclabel_provider - 1] = CStringGetTextDatum(provider);
+ if (label != NULL)
+ values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(label);
+
+ /* Use the index to search for a matching old tuple */
+ ScanKeyInit(&keys[0],
+ Anum_pg_seclabel_objoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+ ScanKeyInit(&keys[1],
+ Anum_pg_seclabel_classoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->classId));
+ ScanKeyInit(&keys[2],
+ Anum_pg_seclabel_objsubid,
+ BTEqualStrategyNumber, F_INT4EQ,
+ Int32GetDatum(object->objectSubId));
+ ScanKeyInit(&keys[3],
+ Anum_pg_seclabel_provider,
+ BTEqualStrategyNumber, F_TEXTEQ,
+ CStringGetTextDatum(provider));
+
+ pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
+
+ scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
+ SnapshotNow, 4, keys);
+
+ oldtup = systable_getnext(scan);
+ if (HeapTupleIsValid(oldtup))
+ {
+ if (label == NULL)
+ simple_heap_delete(pg_seclabel, &oldtup->t_self);
+ else
+ {
+ replaces[Anum_pg_seclabel_label - 1] = true;
+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_seclabel),
+ values, nulls, replaces);
+ simple_heap_update(pg_seclabel, &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_seclabel),
+ values, nulls);
+ simple_heap_insert(pg_seclabel, newtup);
+ }
+
+ /* Update indexes, if necessary */
+ if (newtup != NULL)
+ {
+ CatalogUpdateIndexes(pg_seclabel, newtup);
+ heap_freetuple(newtup);
+ }
+
+ heap_close(pg_seclabel, RowExclusiveLock);
+}
+
+/*
+ * DeleteSecurityLabel removes all security labels for an object (and any
+ * sub-objects, if applicable).
+ */
+void
+DeleteSecurityLabel(const ObjectAddress *object)
+{
+ Relation pg_seclabel;
+ ScanKeyData skey[3];
+ SysScanDesc scan;
+ HeapTuple oldtup;
+ int nkeys;
+
+ /* Security labels on shared objects are not supported. */
+ if (IsSharedRelation(object->classId))
+ return;
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_seclabel_objoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+ ScanKeyInit(&skey[1],
+ Anum_pg_seclabel_classoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->classId));
+ if (object->objectSubId != 0)
+ {
+ ScanKeyInit(&skey[2],
+ Anum_pg_seclabel_objsubid,
+ BTEqualStrategyNumber, F_INT4EQ,
+ Int32GetDatum(object->objectSubId));
+ nkeys = 3;
+ }
+ else
+ nkeys = 2;
+
+ pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
+
+ scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
+ SnapshotNow, nkeys, skey);
+ while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
+ simple_heap_delete(pg_seclabel, &oldtup->t_self);
+ systable_endscan(scan);
+
+ heap_close(pg_seclabel, RowExclusiveLock);
+}
+
+/*
+ * Check whether the user is allowed to comment on an attribute of the
+ * specified relation.
+ */
+static void
+CheckAttributeSecLabel(Relation relation)
+{
+ if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+ RelationGetRelationName(relation));
+
+ /*
+ * Allow security labels only on columns of tables, views, and composite
+ * types (which are the only relkinds for which pg_dump will dump labels).
+ */
+ if (relation->rd_rel->relkind != RELKIND_RELATION &&
+ relation->rd_rel->relkind != RELKIND_VIEW &&
+ relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a table, view, or composite type",
+ RelationGetRelationName(relation))));
+}
+
+void
+register_label_provider(const char *provider_name, check_object_relabel_type hook)
+{
+ LabelProvider *provider;
+ MemoryContext oldcxt;
+
+ oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+ provider = palloc(sizeof(LabelProvider));
+ provider->provider_name = pstrdup(provider_name);
+ provider->hook = hook;
+ label_provider_list = lappend(label_provider_list, provider);
+ MemoryContextSwitchTo(oldcxt);
+}
return newnode;
}
+static SecLabelStmt *
+_copySecLabelStmt(SecLabelStmt *from)
+{
+ SecLabelStmt *newnode = makeNode(SecLabelStmt);
+
+ COPY_SCALAR_FIELD(objtype);
+ COPY_NODE_FIELD(objname);
+ COPY_NODE_FIELD(objargs);
+ COPY_STRING_FIELD(provider);
+ COPY_STRING_FIELD(label);
+
+ return newnode;
+}
+
static FetchStmt *
_copyFetchStmt(FetchStmt *from)
{
case T_CommentStmt:
retval = _copyCommentStmt(from);
break;
+ case T_SecLabelStmt:
+ retval = _copySecLabelStmt(from);
+ break;
case T_FetchStmt:
retval = _copyFetchStmt(from);
break;
return true;
}
+static bool
+_equalSecLabelStmt(SecLabelStmt *a, SecLabelStmt *b)
+{
+ COMPARE_SCALAR_FIELD(objtype);
+ COMPARE_NODE_FIELD(objname);
+ COMPARE_NODE_FIELD(objargs);
+ COMPARE_STRING_FIELD(provider);
+ COMPARE_STRING_FIELD(label);
+
+ return true;
+}
+
static bool
_equalFetchStmt(FetchStmt *a, FetchStmt *b)
{
case T_CommentStmt:
retval = _equalCommentStmt(a, b);
break;
+ case T_SecLabelStmt:
+ retval = _equalSecLabelStmt(a, b);
+ break;
case T_FetchStmt:
retval = _equalFetchStmt(a, b);
break;
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt
RuleActionStmt RuleActionStmtOrEmpty RuleStmt
- SelectStmt TransactionStmt TruncateStmt
+ SecLabelStmt SelectStmt TransactionStmt TruncateStmt
UnlistenStmt UpdateStmt VacuumStmt
VariableResetStmt VariableSetStmt VariableShowStmt
ViewStmt CheckPointStmt CreateConversionStmt
%type <boolean> copy_from
%type <ival> opt_column event cursor_options opt_hold opt_set_data
-%type <objtype> reindex_type drop_type comment_type
+%type <objtype> reindex_type drop_type comment_type security_label_type
%type <node> fetch_args limit_clause select_limit_value
offset_clause select_offset_value
%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
%type <list> opt_check_option
+%type <str> opt_provider security_label
+
%type <target> xml_attribute_el
%type <list> xml_attribute_list xml_attributes
%type <node> xml_root_version opt_xml_root_standalone
KEY
- LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
+ LABEL LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
LOCATION LOCK_P LOGIN_P
| RevokeStmt
| RevokeRoleStmt
| RuleStmt
+ | SecLabelStmt
| SelectStmt
| TransactionStmt
| TruncateStmt
| NULL_P { $$ = NULL; }
;
+
+/*****************************************************************************
+ *
+ * SECURITY LABEL [FOR <provider>] ON <object> IS <label>
+ *
+ * As with COMMENT ON, <object> can refer to various types of database
+ * objects (e.g. TABLE, COLUMN, etc.).
+ *
+ *****************************************************************************/
+
+SecLabelStmt:
+ SECURITY LABEL opt_provider ON security_label_type any_name
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = $5;
+ n->objname = $6;
+ n->objargs = NIL;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON AGGREGATE func_name aggr_args
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_AGGREGATE;
+ n->objname = $6;
+ n->objargs = $7;
+ n->label = $9;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON FUNCTION func_name func_args
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_FUNCTION;
+ n->objname = $6;
+ n->objargs = extractArgTypes($7);
+ n->label = $9;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON LARGE_P OBJECT_P NumericOnly
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_LARGEOBJECT;
+ n->objname = list_make1($7);
+ n->objargs = NIL;
+ n->label = $9;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON opt_procedural LANGUAGE any_name
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_LANGUAGE;
+ n->objname = $7;
+ n->objargs = NIL;
+ n->label = $9;
+ $$ = (Node *) n;
+ }
+ ;
+
+opt_provider: FOR ColId_or_Sconst { $$ = $2; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+security_label_type:
+ COLUMN { $$ = OBJECT_COLUMN; }
+ | SCHEMA { $$ = OBJECT_SCHEMA; }
+ | SEQUENCE { $$ = OBJECT_SEQUENCE; }
+ | TABLE { $$ = OBJECT_TABLE; }
+ | DOMAIN_P { $$ = OBJECT_TYPE; }
+ | TYPE_P { $$ = OBJECT_TYPE; }
+ | VIEW { $$ = OBJECT_VIEW; }
+ ;
+
+security_label: Sconst { $$ = $1; }
+ | NULL_P { $$ = NULL; }
+ ;
+
/*****************************************************************************
*
* QUERY:
| INVOKER
| ISOLATION
| KEY
+ | LABEL
| LANGUAGE
| LARGE_P
| LAST_P
#include "commands/prepare.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
+#include "commands/seclabel.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
case T_AlterUserMappingStmt:
case T_DropUserMappingStmt:
case T_AlterTableSpaceOptionsStmt:
+ case T_SecLabelStmt:
PreventCommandIfReadOnly(CreateCommandTag(parsetree));
break;
default:
CommentObject((CommentStmt *) parsetree);
break;
+ case T_SecLabelStmt:
+ ExecSecLabelStmt((SecLabelStmt *) parsetree);
+ break;
+
case T_CopyStmt:
{
uint64 processed;
tag = "COMMENT";
break;
+ case T_SecLabelStmt:
+ tag = "SECURITY LABEL";
+ break;
+
case T_CopyStmt:
tag = "COPY";
break;
lev = LOGSTMT_DDL;
break;
+ case T_SecLabelStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_CopyStmt:
if (((CopyStmt *) parsetree)->is_from)
lev = LOGSTMT_MOD;
* restore */
int use_setsessauth;/* Use SET SESSION AUTHORIZATION commands
* instead of OWNER TO */
+ int skip_seclabel; /* Skip security label entries */
char *superuser; /* Username to use as superuser */
char *use_role; /* Issue SET ROLE to this */
int dataOnly;
if ((!include_acls || ropt->aclsSkip) && _tocEntryIsACL(te))
return 0;
+ /* If it's security labels, maybe ignore it */
+ if (ropt->skip_seclabel && strcmp(te->desc, "SECURITY LABEL") == 0)
+ return 0;
+
/* Ignore DATABASE entry unless we should create it */
if (!ropt->createDB && strcmp(te->desc, "DATABASE") == 0)
return 0;
(strcmp(te->desc, "ACL") == 0 &&
strncmp(te->tag, "LARGE OBJECT ", 13) == 0) ||
(strcmp(te->desc, "COMMENT") == 0 &&
+ strncmp(te->tag, "LARGE OBJECT ", 13) == 0) ||
+ (strcmp(te->desc, "SECURITY LABEL") == 0 &&
strncmp(te->tag, "LARGE OBJECT ", 13) == 0))
res = res & REQ_DATA;
else
int objsubid; /* subobject (table column #) */
} CommentItem;
+typedef struct
+{
+ const char *provider; /* label provider of this security label */
+ const char *label; /* security label for an object */
+ Oid classoid; /* object class (catalog OID) */
+ Oid objoid; /* object OID */
+ int objsubid; /* subobject (table column #) */
+} SecLabelItem;
/* global decls */
bool g_verbose; /* User wants verbose narration of our
static int disable_dollar_quoting = 0;
static int dump_inserts = 0;
static int column_inserts = 0;
+static int no_security_label = 0;
static void help(const char *progname);
static int findComments(Archive *fout, Oid classoid, Oid objoid,
CommentItem **items);
static int collectComments(Archive *fout, CommentItem **items);
+static void dumpSecLabel(Archive *fout, const char *target,
+ const char *namespace, const char *owner,
+ CatalogId catalogId, int subid, DumpId dumpId);
+static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
+ SecLabelItem **items);
+static int collectSecLabels(Archive *fout, SecLabelItem **items);
static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
static void dumpType(Archive *fout, TypeInfo *tyinfo);
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
{"role", required_argument, NULL, 3},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
+ {"no-security-label", no_argument, &no_security_label, 1},
{NULL, 0, NULL, 0}
};
outputNoTablespaces = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
+ else if (strcmp(optarg, "no-security-label") == 0)
+ no_security_label = 1;
else
{
fprintf(stderr,
if (quote_all_identifiers && g_fout->remoteVersion >= 90100)
do_sql_command(g_conn, "SET quote_all_identifiers = true");
+ /*
+ * Disables security label support if server version < v9.1.x
+ */
+ if (!no_security_label && g_fout->remoteVersion < 90100)
+ no_security_label = 1;
+
/*
* Start serializable transaction to dump consistent data.
*/
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
+ printf(_(" --no-security-label do not dump security label assignments\n"));
printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n"));
NULL, binfo->rolname,
binfo->dobj.catId, 0, binfo->dobj.dumpId);
+ /* Dump security label if any */
+ dumpSecLabel(AH, cquery->data,
+ NULL, binfo->rolname,
+ binfo->dobj.catId, 0, binfo->dobj.dumpId);
+
/* Dump ACL if any */
if (binfo->blobacl)
dumpACL(AH, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
NULL, NULL);
- /* Dump Schema Comments */
+ /* Dump Schema Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "SCHEMA %s", qnspname);
dumpComment(fout, q->data,
NULL, nspinfo->rolname,
nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
+ dumpSecLabel(fout, q->data,
+ NULL, nspinfo->rolname,
+ nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
qnspname, NULL, nspinfo->dobj.name, NULL,
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
NULL, NULL);
- /* Dump Type Comments */
+ /* Dump Type Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
dumpComment(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ dumpSecLabel(fout, q->data,
+ tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+ tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
PQclear(res);
destroyPQExpBuffer(q);
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
NULL, NULL);
- /* Dump Type Comments */
+ /* Dump Type Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
dumpComment(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ dumpSecLabel(fout, q->data,
+ tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+ tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
PQclear(res);
destroyPQExpBuffer(q);
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
NULL, NULL);
- /* Dump Domain Comments */
+ /* Dump Domain Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "DOMAIN %s", fmtId(tyinfo->dobj.name));
dumpComment(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ dumpSecLabel(fout, q->data,
+ tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+ tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
NULL, NULL);
- /* Dump Type Comments */
+ /* Dump Type Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
dumpComment(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ dumpSecLabel(fout, q->data,
+ tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+ tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
PQclear(res);
destroyPQExpBuffer(q);
plang->dobj.dependencies, plang->dobj.nDeps,
NULL, NULL);
- /* Dump Proc Lang Comments */
+ /* Dump Proc Lang Comments and Security Labels */
resetPQExpBuffer(defqry);
appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
dumpComment(fout, defqry->data,
NULL, "",
plang->dobj.catId, 0, plang->dobj.dumpId);
+ dumpSecLabel(fout, defqry->data,
+ NULL, "",
+ plang->dobj.catId, 0, plang->dobj.dumpId);
if (plang->lanpltrusted)
dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
finfo->dobj.dependencies, finfo->dobj.nDeps,
NULL, NULL);
- /* Dump Function Comments */
+ /* Dump Function Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "FUNCTION %s", funcsig);
dumpComment(fout, q->data,
finfo->dobj.namespace->dobj.name, finfo->rolname,
finfo->dobj.catId, 0, finfo->dobj.dumpId);
+ dumpSecLabel(fout, q->data,
+ finfo->dobj.namespace->dobj.name, finfo->rolname,
+ finfo->dobj.catId, 0, finfo->dobj.dumpId);
dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
funcsig, NULL, funcsig_tag,
dumpComment(fout, q->data,
agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+ dumpSecLabel(fout, q->data,
+ agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
+ agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
/*
* Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
destroyPQExpBuffer(sql);
}
+/*
+ * dumpSecLabel
+ *
+ * This routine is used to dump any security labels associated with the
+ * object handed to this routine. The routine takes a constant character
+ * string for the target part of the security-label command, plus
+ * the namespace and owner of the object (for labeling the ArchiveEntry),
+ * plus catalog ID and subid which are the lookup key for pg_seclabel,
+ * plus the dump ID for the object (for setting a dependency).
+ * If a matching pg_seclabel entry is found, it is dumped.
+ *
+ * Note: although this routine takes a dumpId for dependency purposes,
+ * that purpose is just to mark the dependency in the emitted dump file
+ * for possible future use by pg_restore. We do NOT use it for determining
+ * ordering of the label in the dump file, because this routine is called
+ * after dependency sorting occurs. This routine should be called just after
+ * calling ArchiveEntry() for the specified object.
+ */
+static void
+dumpSecLabel(Archive *fout, const char *target,
+ const char *namespace, const char *owner,
+ CatalogId catalogId, int subid, DumpId dumpId)
+{
+ SecLabelItem *labels;
+ int nlabels;
+ int i;
+ PQExpBuffer query;
+
+ /* do nothing, if --no-security-label is supplied */
+ if (no_security_label)
+ return;
+
+ /* Comments are schema not data ... except blob comments are data */
+ if (strncmp(target, "LARGE OBJECT ", 13) != 0)
+ {
+ if (dataOnly)
+ return;
+ }
+ else
+ {
+ if (schemaOnly)
+ return;
+ }
+
+ /* Search for security labels associated with catalogId, using table */
+ nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
+
+ query = createPQExpBuffer();
+
+ for (i = 0; i < nlabels; i++)
+ {
+ /*
+ * Ignore label entries for which the subid doesn't match.
+ */
+ if (labels[i].objsubid != subid)
+ continue;
+
+ appendPQExpBuffer(query,
+ "SECURITY LABEL FOR %s ON %s IS ",
+ fmtId(labels[i].provider), target);
+ appendStringLiteralAH(query, labels[i].label, fout);
+ appendPQExpBuffer(query, ";\n");
+ }
+
+ if (query->len > 0)
+ {
+ ArchiveEntry(fout, nilCatalogId, createDumpId(),
+ target, namespace, NULL, owner,
+ false, "SECURITY LABEL", SECTION_NONE,
+ query->data, "", NULL,
+ &(dumpId), 1,
+ NULL, NULL);
+ }
+ destroyPQExpBuffer(query);
+}
+
+/*
+ * dumpTableSecLabel
+ *
+ * As above, but dump security label for both the specified table (or view)
+ * and its columns.
+ */
+static void
+dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
+{
+ SecLabelItem *labels;
+ int nlabels;
+ int i;
+ PQExpBuffer query;
+ PQExpBuffer target;
+
+ /* do nothing, if --no-security-label is supplied */
+ if (no_security_label)
+ return;
+
+ /* SecLabel are SCHEMA not data */
+ if (dataOnly)
+ return;
+
+ /* Search for comments associated with relation, using table */
+ nlabels = findSecLabels(fout,
+ tbinfo->dobj.catId.tableoid,
+ tbinfo->dobj.catId.oid,
+ &labels);
+
+ /* If comments exist, build SECURITY LABEL statements */
+ if (nlabels <= 0)
+ return;
+
+ query = createPQExpBuffer();
+ target = createPQExpBuffer();
+
+ for (i = 0; i < nlabels; i++)
+ {
+ const char *colname;
+ const char *provider = labels[i].provider;
+ const char *label = labels[i].label;
+ int objsubid = labels[i].objsubid;
+
+ resetPQExpBuffer(target);
+ if (objsubid == 0)
+ {
+ appendPQExpBuffer(target, "%s %s", reltypename,
+ fmtId(tbinfo->dobj.name));
+ }
+ else
+ {
+ colname = getAttrName(objsubid, tbinfo);
+ appendPQExpBuffer(target, "COLUMN %s.%s",
+ fmtId(tbinfo->dobj.name),
+ fmtId(colname));
+ }
+ appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
+ fmtId(provider), target->data);
+ appendStringLiteralAH(query, label, fout);
+ appendPQExpBuffer(query, ";\n");
+ }
+ if (query->len > 0)
+ {
+ resetPQExpBuffer(target);
+ appendPQExpBuffer(target, "%s %s", reltypename,
+ fmtId(tbinfo->dobj.name));
+ ArchiveEntry(fout, nilCatalogId, createDumpId(),
+ target->data,
+ tbinfo->dobj.namespace->dobj.name,
+ NULL, tbinfo->rolname,
+ false, "SECURITY LABEL", SECTION_NONE,
+ query->data, "", NULL,
+ &(tbinfo->dobj.dumpId), 1,
+ NULL, NULL);
+ }
+ destroyPQExpBuffer(query);
+ destroyPQExpBuffer(target);
+}
+
+/*
+ * findSecLabels
+ *
+ * Find the security label(s), if any, associated with the given object.
+ * All the objsubid values associated with the given classoid/objoid are
+ * found with one search.
+ */
+static int
+findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
+{
+ /* static storage for table of security labels */
+ static SecLabelItem *labels = NULL;
+ static int nlabels = -1;
+
+ SecLabelItem *middle = NULL;
+ SecLabelItem *low;
+ SecLabelItem *high;
+ int nmatch;
+
+ /* Get security labels if we didn't already */
+ if (nlabels < 0)
+ nlabels = collectSecLabels(fout, &labels);
+
+ /*
+ * Do binary search to find some item matching the object.
+ */
+ low = &labels[0];
+ high = &labels[nlabels - 1];
+ while (low <= high)
+ {
+ middle = low + (high - low) / 2;
+
+ if (classoid < middle->classoid)
+ high = middle - 1;
+ else if (classoid > middle->classoid)
+ low = middle + 1;
+ else if (objoid < middle->objoid)
+ high = middle - 1;
+ else if (objoid > middle->objoid)
+ low = middle + 1;
+ else
+ break; /* found a match */
+ }
+
+ if (low > high) /* no matches */
+ {
+ *items = NULL;
+ return 0;
+ }
+
+ /*
+ * Now determine how many items match the object. The search loop
+ * invariant still holds: only items between low and high inclusive could
+ * match.
+ */
+ nmatch = 1;
+ while (middle > low)
+ {
+ if (classoid != middle[-1].classoid ||
+ objoid != middle[-1].objoid)
+ break;
+ middle--;
+ nmatch++;
+ }
+
+ *items = middle;
+
+ middle += nmatch;
+ while (middle <= high)
+ {
+ if (classoid != middle->classoid ||
+ objoid != middle->objoid)
+ break;
+ middle++;
+ nmatch++;
+ }
+
+ return nmatch;
+}
+
+/*
+ * collectSecLabels
+ *
+ * Construct a table of all security labels available for database objects.
+ * It's much faster to pull them all at once.
+ *
+ * The table is sorted by classoid/objid/objsubid for speed in lookup.
+ */
+static int
+collectSecLabels(Archive *fout, SecLabelItem **items)
+{
+ PGresult *res;
+ PQExpBuffer query;
+ int i_label;
+ int i_provider;
+ int i_classoid;
+ int i_objoid;
+ int i_objsubid;
+ int ntups;
+ int i;
+ SecLabelItem *labels;
+
+ query = createPQExpBuffer();
+
+ appendPQExpBuffer(query,
+ "SELECT label, provider, classoid, objoid, objsubid "
+ "FROM pg_catalog.pg_seclabel "
+ "ORDER BY classoid, objoid, objsubid");
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ /* Construct lookup table containing OIDs in numeric form */
+ i_label = PQfnumber(res, "label");
+ i_provider = PQfnumber(res, "provider");
+ i_classoid = PQfnumber(res, "classoid");
+ i_objoid = PQfnumber(res, "objoid");
+ i_objsubid = PQfnumber(res, "objsubid");
+
+ ntups = PQntuples(res);
+
+ labels = (SecLabelItem *) malloc(ntups * sizeof(SecLabelItem));
+
+ for (i = 0; i < ntups; i++)
+ {
+ labels[i].label = PQgetvalue(res, i, i_label);
+ labels[i].provider = PQgetvalue(res, i, i_provider);
+ labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
+ labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
+ labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
+ }
+
+ /* Do NOT free the PGresult since we are keeping pointers into it */
+ destroyPQExpBuffer(query);
+
+ *items = labels;
+ return ntups;
+}
+
/*
* dumpTable
* write out to fout the declarations (not data) of a user-defined table
/* Dump Table Comments */
dumpTableComment(fout, tbinfo, reltypename);
+ /* Dump Table Security Labels */
+ dumpTableSecLabel(fout, tbinfo, reltypename);
+
/* Dump comments on inlined table constraints */
for (j = 0; j < tbinfo->ncheck; j++)
{
}
}
- /* Dump Sequence Comments */
+ /* Dump Sequence Comments and Security Labels */
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
dumpComment(fout, query->data,
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+ dumpSecLabel(fout, query->data,
+ tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+ tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
}
if (!schemaOnly)
static int inserts = 0;
static int no_tablespaces = 0;
static int use_setsessauth = 0;
+static int no_security_label = 0;
static int server_version;
static FILE *OPF;
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
{"role", required_argument, NULL, 3},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
+ {"no-security-label", no_argument, &no_security_label, 1},
{NULL, 0, NULL, 0}
};
no_tablespaces = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
+ else if (strcmp(optarg, "no-security-label") == 0)
+ no_security_label = 1;
else
{
fprintf(stderr,
appendPQExpBuffer(pgdumpopts, " --quote-all-identifiers");
if (use_setsessauth)
appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
+ if (no_security_label)
+ appendPQExpBuffer(pgdumpopts, " --no-security-label");
/*
* If there was a database specified on the command line, use that,
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
+ printf(_(" --no-security-label do not dump security label assignments\n"));
printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n"));
static int no_data_for_failed_tables = 0;
static int outputNoTablespaces = 0;
static int use_setsessauth = 0;
+ static int skip_seclabel = 0;
struct option cmdopts[] = {
{"clean", 0, NULL, 'c'},
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
{"role", required_argument, NULL, 2},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
+ {"no-security-label", no_argument, &skip_seclabel, 1},
{NULL, 0, NULL, 0}
};
outputNoTablespaces = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
+ else if (strcmp(optarg, "no-security-label") == 0)
+ skip_seclabel = 1;
else
{
fprintf(stderr,
opts->noDataForFailedTables = no_data_for_failed_tables;
opts->noTablespace = outputNoTablespaces;
opts->use_setsessauth = use_setsessauth;
+ opts->skip_seclabel = skip_seclabel;
if (opts->formatName)
{
" do not restore data of tables that could not be\n"
" created\n"));
printf(_(" --no-tablespaces do not restore tablespace assignments\n"));
+ printf(_(" --no-security-label do not restore security labels\n"));
printf(_(" --role=ROLENAME do SET ROLE before restore\n"));
printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n"
"DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
"GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
"REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
- "SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TABLE", "TRUNCATE", "UNLISTEN",
- "UPDATE", "VACUUM", "VALUES", "WITH", NULL
+ "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
+ "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
+ NULL
};
static const char *const backslash_commands[] = {
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
}
+/* SECURITY LABEL */
+ else if (pg_strcasecmp(prev_wd, "SECURITY") == 0)
+ COMPLETE_WITH_CONST("LABEL");
+ else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 &&
+ pg_strcasecmp(prev_wd, "LABEL") == 0)
+ {
+ static const char *const list_SECURITY_LABEL_preposition[] =
+ {"ON", "FOR"};
+ COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition);
+ }
+ else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 &&
+ pg_strcasecmp(prev3_wd, "LABEL") == 0 &&
+ pg_strcasecmp(prev2_wd, "FOR") == 0)
+ COMPLETE_WITH_CONST("ON");
+ else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 &&
+ pg_strcasecmp(prev2_wd, "LABEL") == 0 &&
+ pg_strcasecmp(prev_wd, "ON") == 0) ||
+ (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
+ pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
+ pg_strcasecmp(prev3_wd, "FOR") == 0 &&
+ pg_strcasecmp(prev_wd, "ON") == 0))
+ {
+ static const char *const list_SECURITY_LABEL[] =
+ {"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN",
+ "AGGREGATE", "FUNCTION", "DOMAIN", "LARGE OBJECT",
+ NULL};
+
+ COMPLETE_WITH_LIST(list_SECURITY_LABEL);
+ }
+ else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
+ pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
+ pg_strcasecmp(prev3_wd, "ON") == 0)
+ COMPLETE_WITH_CONST("IS");
+
/* SELECT */
/* naah . . . */
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201009021
+#define CATALOG_VERSION_NO 201009271
#endif
DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops));
#define DbRoleSettingDatidRolidIndexId 2965
+DECLARE_UNIQUE_INDEX(pg_seclabel_object_index, 3038, on pg_seclabel using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops, provider text_ops));
+#define SecLabelObjectIndexId 3038
+
/* last step of initialization script: build the indexes declared above */
BUILD_INDICES
--- /dev/null
+/* -------------------------------------------------------------------------
+ *
+ * pg_seclabel.h
+ * definition of the system "security label" relation (pg_seclabel)
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * -------------------------------------------------------------------------
+ */
+#ifndef PG_SECLABEL_H
+#define PG_SECLABEL_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ * pg_seclabel definition. cpp turns this into
+ * typedef struct FormData_pg_seclabel
+ * ----------------
+ */
+#define SecLabelRelationId 3037
+
+CATALOG(pg_seclabel,3037) BKI_WITHOUT_OIDS
+{
+ Oid objoid; /* OID of the object itself */
+ Oid classoid; /* OID of table containing the object */
+ int4 objsubid; /* column number, or 0 if not used */
+ text provider; /* name of label provider */
+ text label; /* security label of the object */
+} FormData_pg_seclabel;
+
+/* ----------------
+ * compiler constants for pg_seclabel
+ * ----------------
+ */
+#define Natts_pg_seclabel 5
+#define Anum_pg_seclabel_objoid 1
+#define Anum_pg_seclabel_classoid 2
+#define Anum_pg_seclabel_objsubid 3
+#define Anum_pg_seclabel_provider 4
+#define Anum_pg_seclabel_label 5
+
+#endif /* PG_SECLABEL_H */
DECLARE_TOAST(pg_description, 2834, 2835);
DECLARE_TOAST(pg_proc, 2836, 2837);
DECLARE_TOAST(pg_rewrite, 2838, 2839);
+DECLARE_TOAST(pg_seclabel, 3039, 3040);
DECLARE_TOAST(pg_statistic, 2840, 2841);
DECLARE_TOAST(pg_trigger, 2336, 2337);
--- /dev/null
+/*
+ * seclabel.h
+ *
+ * Prototypes for functions in commands/seclabel.c
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ */
+#ifndef SECLABEL_H
+#define SECLABEL_H
+
+#include "catalog/objectaddress.h"
+#include "nodes/primnodes.h"
+#include "nodes/parsenodes.h"
+
+/*
+ * Internal APIs
+ */
+extern char *GetSecurityLabel(const ObjectAddress *object,
+ const char *provider);
+extern void SetSecurityLabel(const ObjectAddress *object,
+ const char *provider, const char *label);
+extern void DeleteSecurityLabel(const ObjectAddress *object);
+
+/*
+ * Statement and ESP hook support
+ */
+extern void ExecSecLabelStmt(SecLabelStmt *stmt);
+
+typedef void (*check_object_relabel_type)(const ObjectAddress *object,
+ const char *seclabel);
+extern void register_label_provider(const char *provider,
+ check_object_relabel_type hook);
+
+#endif /* SECLABEL_H */
T_AlterUserMappingStmt,
T_DropUserMappingStmt,
T_AlterTableSpaceOptionsStmt,
+ T_SecLabelStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
char *comment; /* Comment to insert, or NULL to remove */
} CommentStmt;
+/* ----------------------
+ * SECURITY LABEL Statement
+ * ----------------------
+ */
+typedef struct SecLabelStmt
+{
+ NodeTag type;
+ ObjectType objtype; /* Object's type */
+ List *objname; /* Qualified name of the object */
+ List *objargs; /* Arguments if needed (eg, for functions) */
+ char *provider; /* Label provider (or NULL) */
+ char *label; /* New security label to be assigned */
+} SecLabelStmt;
+
/* ----------------------
* Declare Cursor Statement
*
PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
+PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD)
PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
$(MKDIR_P) $(patsubst $(srcdir)/%/,'$(DESTDIR)$(pkglibdir)/regress/%',$(sort $(dir $(regress_data_files))))
-# Get some extra C modules from contrib/spi...
+# Get some extra C modules from contrib/spi and contrib/dummy_seclabel...
-all: refint$(DLSUFFIX) autoinc$(DLSUFFIX)
+all: refint$(DLSUFFIX) autoinc$(DLSUFFIX) dummy_seclabel$(DLSUFFIX)
refint$(DLSUFFIX): $(top_builddir)/contrib/spi/refint$(DLSUFFIX)
cp $< $@
autoinc$(DLSUFFIX): $(top_builddir)/contrib/spi/autoinc$(DLSUFFIX)
cp $< $@
+dummy_seclabel$(DLSUFFIX): $(top_builddir)/contrib/dummy_seclabel/dummy_seclabel$(DLSUFFIX)
+ cp $< $@
+
$(top_builddir)/contrib/spi/refint$(DLSUFFIX): $(top_srcdir)/contrib/spi/refint.c
$(MAKE) -C $(top_builddir)/contrib/spi refint$(DLSUFFIX)
$(top_builddir)/contrib/spi/autoinc$(DLSUFFIX): $(top_srcdir)/contrib/spi/autoinc.c
$(MAKE) -C $(top_builddir)/contrib/spi autoinc$(DLSUFFIX)
+$(top_builddir)/contrib/dummy_seclabel/dummy_seclabel$(DLSUFFIX): $(top_builddir)/contrib/dummy_seclabel/dummy_seclabel.c
+ $(MAKE) -C $(top_builddir)/contrib/dummy_seclabel dummy_seclabel$(DLSUFFIX)
# Tablespace setup
clean distclean maintainer-clean: clean-lib
# things built by `all' target
- rm -f $(OBJS) refint$(DLSUFFIX) autoinc$(DLSUFFIX) pg_regress_main.o pg_regress.o pg_regress$(X)
+ rm -f $(OBJS) refint$(DLSUFFIX) autoinc$(DLSUFFIX) dummy_seclabel$(DLSUFFIX)
+ rm -f pg_regress_main.o pg_regress.o pg_regress$(X)
# things created by various check targets
rm -f $(output_files) $(input_files)
rm -rf testtablespace
/largeobject.out
/largeobject_1.out
/misc.out
+/security_label.out
/tablespace.out
-- 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_cursors | SELECT c.name, c.statement, c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
pg_group | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
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.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 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_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.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_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_port), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
shoelace_obsolete | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
street | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
toyemp | SELECT emp.name, emp.age, emp.location, (12 * emp.salary) AS annualsal FROM emp;
-(55 rows)
+(56 rows)
SELECT tablename, rulename, definition FROM pg_rules
ORDER BY tablename, rulename;
pg_pltemplate | t
pg_proc | t
pg_rewrite | t
+ pg_seclabel | t
pg_shdepend | t
pg_shdescription | t
pg_statistic | t
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
-(142 rows)
+(143 rows)
--
-- another sanity check: every system catalog that has OIDs should have
--- /dev/null
+--
+-- Test for facilities of security label
+--
+
+-- initial setups
+SET client_min_messages TO 'warning';
+
+DROP ROLE IF EXISTS seclabel_user1;
+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_user2;
+
+CREATE TABLE seclabel_tbl1 (a int, b text);
+CREATE TABLE seclabel_tbl2 (x int, y text);
+CREATE VIEW seclabel_view1 AS SELECT * FROM seclabel_tbl2;
+CREATE FUNCTION seclabel_four() RETURNS integer AS $$SELECT 4$$ language sql;
+CREATE DOMAIN seclabel_domain AS text;
+
+ALTER TABLE seclabel_tbl1 OWNER TO seclabel_user1;
+ALTER TABLE seclabel_tbl2 OWNER TO seclabel_user2;
+
+RESET client_min_messages;
+
+--
+-- Test of SECURITY LABEL statement without a plugin
+--
+SECURITY LABEL ON TABLE seclabel_tbl1 IS 'classified'; -- fail
+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
+
+-- Load dummy external security provider
+LOAD '@libdir@/dummy_seclabel@DLSUFFIX@';
+
+--
+-- Test of SECURITY LABEL statement with a plugin
+--
+SET SESSION AUTHORIZATION seclabel_user1;
+
+SECURITY LABEL ON TABLE seclabel_tbl1 IS 'classified'; -- OK
+SECURITY LABEL ON COLUMN seclabel_tbl1.a IS 'unclassified'; -- OK
+SECURITY LABEL ON TABLE seclabel_tbl1 IS '...invalid label...'; -- fail
+SECURITY LABEL FOR 'dummy' ON TABLE seclabel_tbl1 IS 'unclassified'; -- OK
+SECURITY LABEL FOR 'unknown_seclabel' ON TABLE seclabel_tbl1 IS 'classified'; -- fail
+SECURITY LABEL ON TABLE seclabel_tbl2 IS 'unclassified'; -- fail (not owner)
+SECURITY LABEL ON TABLE seclabel_tbl1 IS 'secret'; -- fail (not superuser)
+SECURITY LABEL ON TABLE seclabel_tbl3 IS 'unclassified'; -- fail (not found)
+
+SET SESSION AUTHORIZATION seclabel_user2;
+SECURITY LABEL ON TABLE seclabel_tbl1 IS 'unclassified'; -- fail
+SECURITY LABEL ON TABLE seclabel_tbl2 IS 'classified'; -- OK
+
+RESET SESSION AUTHORIZATION;
+
+SECURITY LABEL ON TABLE seclabel_tbl1 IS 'top secret'; -- OK
+SECURITY LABEL ON VIEW seclabel_view1 IS 'classified'; -- OK
+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
+
+SELECT objtype, objname, provider, label FROM pg_seclabels
+ ORDER BY objtype, objname;
+
+SECURITY LABEL ON LANGUAGE plpgsql IS NULL; -- OK
+SECURITY LABEL ON SCHEMA public IS NULL; -- OK
+
+-- clean up objects
+DROP FUNCTION seclabel_four();
+DROP DOMAIN seclabel_domain;
+DROP VIEW seclabel_view1;
+DROP TABLE seclabel_tbl1;
+DROP TABLE seclabel_tbl2;
+DROP USER seclabel_user1;
+DROP USER seclabel_user2;
+
+-- make sure we don't have any leftovers
+SELECT objtype, objname, provider, label FROM pg_seclabels
+ ORDER BY objtype, objname;
--- /dev/null
+--
+-- Test for facilities of security label
+--
+-- initial setups
+SET client_min_messages TO 'warning';
+DROP ROLE IF EXISTS seclabel_user1;
+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_user2;
+CREATE TABLE seclabel_tbl1 (a int, b text);
+CREATE TABLE seclabel_tbl2 (x int, y text);
+CREATE VIEW seclabel_view1 AS SELECT * FROM seclabel_tbl2;
+CREATE FUNCTION seclabel_four() RETURNS integer AS $$SELECT 4$$ language sql;
+CREATE DOMAIN seclabel_domain AS text;
+ALTER TABLE seclabel_tbl1 OWNER TO seclabel_user1;
+ALTER TABLE seclabel_tbl2 OWNER TO seclabel_user2;
+RESET client_min_messages;
+--
+-- Test of SECURITY LABEL statement without a plugin
+--
+SECURITY LABEL ON TABLE seclabel_tbl1 IS 'classified'; -- fail
+ERROR: security label providers have been loaded
+SECURITY LABEL FOR 'dummy' ON TABLE seclabel_tbl1 IS 'classified'; -- fail
+ERROR: security label provider "dummy" is not loaded
+SECURITY LABEL ON TABLE seclabel_tbl1 IS '...invalid label...'; -- fail
+ERROR: security label providers have been loaded
+SECURITY LABEL ON TABLE seclabel_tbl3 IS 'unclassified'; -- fail
+ERROR: security label providers have been loaded
+-- Load dummy external security provider
+LOAD '@abs_builddir@/dummy_seclabel@DLSUFFIX@';
+--
+-- Test of SECURITY LABEL statement with a plugin
+--
+SET SESSION AUTHORIZATION seclabel_user1;
+SECURITY LABEL ON TABLE seclabel_tbl1 IS 'classified'; -- OK
+SECURITY LABEL ON COLUMN seclabel_tbl1.a IS 'unclassified'; -- OK
+SECURITY LABEL ON TABLE seclabel_tbl1 IS '...invalid label...'; -- fail
+ERROR: '...invalid label...' is not a valid security label
+SECURITY LABEL FOR 'dummy' ON TABLE seclabel_tbl1 IS 'unclassified'; -- OK
+SECURITY LABEL FOR 'unknown_seclabel' ON TABLE seclabel_tbl1 IS 'classified'; -- fail
+ERROR: security label provider "unknown_seclabel" is not loaded
+SECURITY LABEL ON TABLE seclabel_tbl2 IS 'unclassified'; -- fail (not owner)
+ERROR: must be owner of relation seclabel_tbl2
+SECURITY LABEL ON TABLE seclabel_tbl1 IS 'secret'; -- fail (not superuser)
+ERROR: only superuser can set 'secret' label
+SECURITY LABEL ON TABLE seclabel_tbl3 IS 'unclassified'; -- fail (not found)
+ERROR: relation "seclabel_tbl3" does not exist
+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
+RESET SESSION AUTHORIZATION;
+SECURITY LABEL ON TABLE seclabel_tbl1 IS 'top secret'; -- OK
+SECURITY LABEL ON VIEW seclabel_view1 IS 'classified'; -- OK
+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
+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)
+
+SECURITY LABEL ON LANGUAGE plpgsql IS NULL; -- OK
+SECURITY LABEL ON SCHEMA public IS NULL; -- OK
+-- clean up objects
+DROP FUNCTION seclabel_four();
+DROP DOMAIN seclabel_domain;
+DROP VIEW seclabel_view1;
+DROP TABLE seclabel_tbl1;
+DROP TABLE seclabel_tbl2;
+DROP USER seclabel_user1;
+DROP USER seclabel_user2;
+-- make sure we don't have any leftovers
+SELECT objtype, objname, provider, label FROM pg_seclabels
+ ORDER BY objtype, objname;
+ objtype | objname | provider | label
+---------+---------+----------+-------
+(0 rows)
+
# ----------
test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete
-test: privileges
+test: privileges security_label
test: misc
# rules cannot run concurrently with any test that creates a view
test: rules
test: namespace
test: prepared_xacts
test: privileges
+test: security_label
test: misc
test: rules
test: select_views
/create_function_2.sql
/largeobject.sql
/misc.sql
+/security_label.sql
/tablespace.sql