Add a SECURITY LABEL command.
This is intended as infrastructure to support integration with label-based mandatory access control systems such as SE-Linux. Further changes (mostly hooks) will be needed, but this is a big chunk of it. KaiGai Kohei and Robert Haas
This commit is contained in:
parent
2ce003973d
commit
4d355a8336
@ -15,6 +15,7 @@ SUBDIRS = \
|
|||||||
dblink \
|
dblink \
|
||||||
dict_int \
|
dict_int \
|
||||||
dict_xsyn \
|
dict_xsyn \
|
||||||
|
dummy_seclabel \
|
||||||
earthdistance \
|
earthdistance \
|
||||||
fuzzystrmatch \
|
fuzzystrmatch \
|
||||||
hstore \
|
hstore \
|
||||||
|
14
contrib/dummy_seclabel/Makefile
Normal file
14
contrib/dummy_seclabel/Makefile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# 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
|
49
contrib/dummy_seclabel/dummy_seclabel.c
Normal file
49
contrib/dummy_seclabel/dummy_seclabel.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
@ -208,6 +208,11 @@
|
|||||||
<entry>query rewrite rules</entry>
|
<entry>query rewrite rules</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><link linkend="catalog-pg-seclabel"><structname>pg_seclabel</structname></link></entry>
|
||||||
|
<entry>security labels on database objects</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><link linkend="catalog-pg-shdepend"><structname>pg_shdepend</structname></link></entry>
|
<entry><link linkend="catalog-pg-shdepend"><structname>pg_shdepend</structname></link></entry>
|
||||||
<entry>dependencies on shared objects</entry>
|
<entry>dependencies on shared objects</entry>
|
||||||
@ -4229,6 +4234,77 @@
|
|||||||
</sect1>
|
</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">
|
<sect1 id="catalog-pg-shdepend">
|
||||||
<title><structname>pg_shdepend</structname></title>
|
<title><structname>pg_shdepend</structname></title>
|
||||||
|
|
||||||
@ -5883,6 +5959,11 @@
|
|||||||
<entry>rules</entry>
|
<entry>rules</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><link linkend="view-pg-seclabels"><structname>pg_seclabels</structname></link></entry>
|
||||||
|
<entry>security labels</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><link linkend="view-pg-settings"><structname>pg_settings</structname></link></entry>
|
<entry><link linkend="view-pg-settings"><structname>pg_settings</structname></link></entry>
|
||||||
<entry>parameter settings</entry>
|
<entry>parameter settings</entry>
|
||||||
@ -6791,6 +6872,97 @@
|
|||||||
|
|
||||||
</sect1>
|
</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">
|
<sect1 id="view-pg-settings">
|
||||||
<title><structname>pg_settings</structname></title>
|
<title><structname>pg_settings</structname></title>
|
||||||
|
|
||||||
|
@ -132,6 +132,7 @@ Complete list of usable sgml source files in this directory.
|
|||||||
<!entity rollbackPrepared system "rollback_prepared.sgml">
|
<!entity rollbackPrepared system "rollback_prepared.sgml">
|
||||||
<!entity rollbackTo system "rollback_to.sgml">
|
<!entity rollbackTo system "rollback_to.sgml">
|
||||||
<!entity savepoint system "savepoint.sgml">
|
<!entity savepoint system "savepoint.sgml">
|
||||||
|
<!entity securityLabel system "security_label.sgml">
|
||||||
<!entity select system "select.sgml">
|
<!entity select system "select.sgml">
|
||||||
<!entity selectInto system "select_into.sgml">
|
<!entity selectInto system "select_into.sgml">
|
||||||
<!entity set system "set.sgml">
|
<!entity set system "set.sgml">
|
||||||
|
@ -778,6 +778,16 @@ PostgreSQL documentation
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
@ -493,6 +493,15 @@ PostgreSQL documentation
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
@ -328,6 +328,16 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><option>-P <replaceable class="parameter">function-name(argtype [, ...])</replaceable></option></term>
|
<term><option>-P <replaceable class="parameter">function-name(argtype [, ...])</replaceable></option></term>
|
||||||
<term><option>--function=<replaceable class="parameter">function-name(argtype [, ...])</replaceable></option></term>
|
<term><option>--function=<replaceable class="parameter">function-name(argtype [, ...])</replaceable></option></term>
|
||||||
|
194
doc/src/sgml/ref/security_label.sgml
Normal file
194
doc/src/sgml/ref/security_label.sgml
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
<!--
|
||||||
|
$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>
|
@ -160,6 +160,7 @@
|
|||||||
&rollbackPrepared;
|
&rollbackPrepared;
|
||||||
&rollbackTo;
|
&rollbackTo;
|
||||||
&savepoint;
|
&savepoint;
|
||||||
|
&securityLabel;
|
||||||
&select;
|
&select;
|
||||||
&selectInto;
|
&selectInto;
|
||||||
&set;
|
&set;
|
||||||
|
@ -38,7 +38,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
|
|||||||
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
|
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
|
||||||
pg_ts_parser.h pg_ts_template.h \
|
pg_ts_parser.h pg_ts_template.h \
|
||||||
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.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 \
|
toasting.h indexing.h \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "commands/proclang.h"
|
#include "commands/proclang.h"
|
||||||
#include "commands/schemacmds.h"
|
#include "commands/schemacmds.h"
|
||||||
|
#include "commands/seclabel.h"
|
||||||
#include "commands/tablespace.h"
|
#include "commands/tablespace.h"
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
#include "commands/typecmds.h"
|
#include "commands/typecmds.h"
|
||||||
@ -1004,10 +1005,12 @@ deleteOneObject(const ObjectAddress *object, Relation depRel)
|
|||||||
doDeletion(object);
|
doDeletion(object);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delete any comments associated with this object. (This is a convenient
|
* Delete any comments or security labels associated with this object.
|
||||||
* place to do it instead of having every object type know to do it.)
|
* (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);
|
DeleteComments(object->objectId, object->classId, object->objectSubId);
|
||||||
|
DeleteSecurityLabel(object);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CommandCounterIncrement here to ensure that preceding changes are all
|
* CommandCounterIncrement here to ensure that preceding changes are all
|
||||||
|
@ -160,6 +160,114 @@ CREATE VIEW pg_prepared_xacts AS
|
|||||||
CREATE VIEW pg_prepared_statements AS
|
CREATE VIEW pg_prepared_statements AS
|
||||||
SELECT * FROM pg_prepared_statement() AS P;
|
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
|
CREATE VIEW pg_settings AS
|
||||||
SELECT * FROM pg_show_all_settings() AS A;
|
SELECT * FROM pg_show_all_settings() AS A;
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
|
|||||||
dbcommands.o define.o discard.o explain.o foreigncmds.o functioncmds.o \
|
dbcommands.o define.o discard.o explain.o foreigncmds.o functioncmds.o \
|
||||||
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
|
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
|
||||||
portalcmds.o prepare.o proclang.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 \
|
tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
|
||||||
variable.o view.o
|
variable.o view.o
|
||||||
|
|
||||||
|
387
src/backend/commands/seclabel.c
Normal file
387
src/backend/commands/seclabel.c
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
}
|
@ -2607,6 +2607,20 @@ _copyCommentStmt(CommentStmt *from)
|
|||||||
return newnode;
|
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 *
|
static FetchStmt *
|
||||||
_copyFetchStmt(FetchStmt *from)
|
_copyFetchStmt(FetchStmt *from)
|
||||||
{
|
{
|
||||||
@ -3958,6 +3972,9 @@ copyObject(void *from)
|
|||||||
case T_CommentStmt:
|
case T_CommentStmt:
|
||||||
retval = _copyCommentStmt(from);
|
retval = _copyCommentStmt(from);
|
||||||
break;
|
break;
|
||||||
|
case T_SecLabelStmt:
|
||||||
|
retval = _copySecLabelStmt(from);
|
||||||
|
break;
|
||||||
case T_FetchStmt:
|
case T_FetchStmt:
|
||||||
retval = _copyFetchStmt(from);
|
retval = _copyFetchStmt(from);
|
||||||
break;
|
break;
|
||||||
|
@ -1163,6 +1163,18 @@ _equalCommentStmt(CommentStmt *a, CommentStmt *b)
|
|||||||
return true;
|
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
|
static bool
|
||||||
_equalFetchStmt(FetchStmt *a, FetchStmt *b)
|
_equalFetchStmt(FetchStmt *a, FetchStmt *b)
|
||||||
{
|
{
|
||||||
@ -2624,6 +2636,9 @@ equal(void *a, void *b)
|
|||||||
case T_CommentStmt:
|
case T_CommentStmt:
|
||||||
retval = _equalCommentStmt(a, b);
|
retval = _equalCommentStmt(a, b);
|
||||||
break;
|
break;
|
||||||
|
case T_SecLabelStmt:
|
||||||
|
retval = _equalSecLabelStmt(a, b);
|
||||||
|
break;
|
||||||
case T_FetchStmt:
|
case T_FetchStmt:
|
||||||
retval = _equalFetchStmt(a, b);
|
retval = _equalFetchStmt(a, b);
|
||||||
break;
|
break;
|
||||||
|
@ -205,7 +205,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
|
|||||||
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
|
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
|
||||||
RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt
|
RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt
|
||||||
RuleActionStmt RuleActionStmtOrEmpty RuleStmt
|
RuleActionStmt RuleActionStmtOrEmpty RuleStmt
|
||||||
SelectStmt TransactionStmt TruncateStmt
|
SecLabelStmt SelectStmt TransactionStmt TruncateStmt
|
||||||
UnlistenStmt UpdateStmt VacuumStmt
|
UnlistenStmt UpdateStmt VacuumStmt
|
||||||
VariableResetStmt VariableSetStmt VariableShowStmt
|
VariableResetStmt VariableSetStmt VariableShowStmt
|
||||||
ViewStmt CheckPointStmt CreateConversionStmt
|
ViewStmt CheckPointStmt CreateConversionStmt
|
||||||
@ -335,7 +335,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
|
|||||||
%type <boolean> copy_from
|
%type <boolean> copy_from
|
||||||
|
|
||||||
%type <ival> opt_column event cursor_options opt_hold opt_set_data
|
%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
|
%type <node> fetch_args limit_clause select_limit_value
|
||||||
offset_clause select_offset_value
|
offset_clause select_offset_value
|
||||||
@ -423,6 +423,8 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
|
|||||||
%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
|
%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
|
||||||
%type <list> opt_check_option
|
%type <list> opt_check_option
|
||||||
|
|
||||||
|
%type <str> opt_provider security_label
|
||||||
|
|
||||||
%type <target> xml_attribute_el
|
%type <target> xml_attribute_el
|
||||||
%type <list> xml_attribute_list xml_attributes
|
%type <list> xml_attribute_list xml_attributes
|
||||||
%type <node> xml_root_version opt_xml_root_standalone
|
%type <node> xml_root_version opt_xml_root_standalone
|
||||||
@ -500,7 +502,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
|
|||||||
|
|
||||||
KEY
|
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
|
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
|
||||||
LOCATION LOCK_P LOGIN_P
|
LOCATION LOCK_P LOGIN_P
|
||||||
|
|
||||||
@ -739,6 +741,7 @@ stmt :
|
|||||||
| RevokeStmt
|
| RevokeStmt
|
||||||
| RevokeRoleStmt
|
| RevokeRoleStmt
|
||||||
| RuleStmt
|
| RuleStmt
|
||||||
|
| SecLabelStmt
|
||||||
| SelectStmt
|
| SelectStmt
|
||||||
| TransactionStmt
|
| TransactionStmt
|
||||||
| TruncateStmt
|
| TruncateStmt
|
||||||
@ -4368,6 +4371,92 @@ comment_text:
|
|||||||
| NULL_P { $$ = NULL; }
|
| 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:
|
* QUERY:
|
||||||
@ -11049,6 +11138,7 @@ unreserved_keyword:
|
|||||||
| INVOKER
|
| INVOKER
|
||||||
| ISOLATION
|
| ISOLATION
|
||||||
| KEY
|
| KEY
|
||||||
|
| LABEL
|
||||||
| LANGUAGE
|
| LANGUAGE
|
||||||
| LARGE_P
|
| LARGE_P
|
||||||
| LAST_P
|
| LAST_P
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "commands/prepare.h"
|
#include "commands/prepare.h"
|
||||||
#include "commands/proclang.h"
|
#include "commands/proclang.h"
|
||||||
#include "commands/schemacmds.h"
|
#include "commands/schemacmds.h"
|
||||||
|
#include "commands/seclabel.h"
|
||||||
#include "commands/sequence.h"
|
#include "commands/sequence.h"
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
#include "commands/tablespace.h"
|
#include "commands/tablespace.h"
|
||||||
@ -218,6 +219,7 @@ check_xact_readonly(Node *parsetree)
|
|||||||
case T_AlterUserMappingStmt:
|
case T_AlterUserMappingStmt:
|
||||||
case T_DropUserMappingStmt:
|
case T_DropUserMappingStmt:
|
||||||
case T_AlterTableSpaceOptionsStmt:
|
case T_AlterTableSpaceOptionsStmt:
|
||||||
|
case T_SecLabelStmt:
|
||||||
PreventCommandIfReadOnly(CreateCommandTag(parsetree));
|
PreventCommandIfReadOnly(CreateCommandTag(parsetree));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -663,6 +665,10 @@ standard_ProcessUtility(Node *parsetree,
|
|||||||
CommentObject((CommentStmt *) parsetree);
|
CommentObject((CommentStmt *) parsetree);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_SecLabelStmt:
|
||||||
|
ExecSecLabelStmt((SecLabelStmt *) parsetree);
|
||||||
|
break;
|
||||||
|
|
||||||
case T_CopyStmt:
|
case T_CopyStmt:
|
||||||
{
|
{
|
||||||
uint64 processed;
|
uint64 processed;
|
||||||
@ -1592,6 +1598,10 @@ CreateCommandTag(Node *parsetree)
|
|||||||
tag = "COMMENT";
|
tag = "COMMENT";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_SecLabelStmt:
|
||||||
|
tag = "SECURITY LABEL";
|
||||||
|
break;
|
||||||
|
|
||||||
case T_CopyStmt:
|
case T_CopyStmt:
|
||||||
tag = "COPY";
|
tag = "COPY";
|
||||||
break;
|
break;
|
||||||
@ -2318,6 +2328,10 @@ GetCommandLogLevel(Node *parsetree)
|
|||||||
lev = LOGSTMT_DDL;
|
lev = LOGSTMT_DDL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_SecLabelStmt:
|
||||||
|
lev = LOGSTMT_DDL;
|
||||||
|
break;
|
||||||
|
|
||||||
case T_CopyStmt:
|
case T_CopyStmt:
|
||||||
if (((CopyStmt *) parsetree)->is_from)
|
if (((CopyStmt *) parsetree)->is_from)
|
||||||
lev = LOGSTMT_MOD;
|
lev = LOGSTMT_MOD;
|
||||||
|
@ -103,6 +103,7 @@ typedef struct _restoreOptions
|
|||||||
* restore */
|
* restore */
|
||||||
int use_setsessauth;/* Use SET SESSION AUTHORIZATION commands
|
int use_setsessauth;/* Use SET SESSION AUTHORIZATION commands
|
||||||
* instead of OWNER TO */
|
* instead of OWNER TO */
|
||||||
|
int skip_seclabel; /* Skip security label entries */
|
||||||
char *superuser; /* Username to use as superuser */
|
char *superuser; /* Username to use as superuser */
|
||||||
char *use_role; /* Issue SET ROLE to this */
|
char *use_role; /* Issue SET ROLE to this */
|
||||||
int dataOnly;
|
int dataOnly;
|
||||||
|
@ -2275,6 +2275,10 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
|
|||||||
if ((!include_acls || ropt->aclsSkip) && _tocEntryIsACL(te))
|
if ((!include_acls || ropt->aclsSkip) && _tocEntryIsACL(te))
|
||||||
return 0;
|
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 */
|
/* Ignore DATABASE entry unless we should create it */
|
||||||
if (!ropt->createDB && strcmp(te->desc, "DATABASE") == 0)
|
if (!ropt->createDB && strcmp(te->desc, "DATABASE") == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -2341,6 +2345,8 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
|
|||||||
(strcmp(te->desc, "ACL") == 0 &&
|
(strcmp(te->desc, "ACL") == 0 &&
|
||||||
strncmp(te->tag, "LARGE OBJECT ", 13) == 0) ||
|
strncmp(te->tag, "LARGE OBJECT ", 13) == 0) ||
|
||||||
(strcmp(te->desc, "COMMENT") == 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))
|
strncmp(te->tag, "LARGE OBJECT ", 13) == 0))
|
||||||
res = res & REQ_DATA;
|
res = res & REQ_DATA;
|
||||||
else
|
else
|
||||||
|
@ -70,6 +70,14 @@ typedef struct
|
|||||||
int objsubid; /* subobject (table column #) */
|
int objsubid; /* subobject (table column #) */
|
||||||
} CommentItem;
|
} 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 */
|
/* global decls */
|
||||||
bool g_verbose; /* User wants verbose narration of our
|
bool g_verbose; /* User wants verbose narration of our
|
||||||
@ -125,6 +133,7 @@ static int binary_upgrade = 0;
|
|||||||
static int disable_dollar_quoting = 0;
|
static int disable_dollar_quoting = 0;
|
||||||
static int dump_inserts = 0;
|
static int dump_inserts = 0;
|
||||||
static int column_inserts = 0;
|
static int column_inserts = 0;
|
||||||
|
static int no_security_label = 0;
|
||||||
|
|
||||||
|
|
||||||
static void help(const char *progname);
|
static void help(const char *progname);
|
||||||
@ -141,6 +150,12 @@ static void dumpComment(Archive *fout, const char *target,
|
|||||||
static int findComments(Archive *fout, Oid classoid, Oid objoid,
|
static int findComments(Archive *fout, Oid classoid, Oid objoid,
|
||||||
CommentItem **items);
|
CommentItem **items);
|
||||||
static int collectComments(Archive *fout, 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 dumpDumpableObject(Archive *fout, DumpableObject *dobj);
|
||||||
static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
|
static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
|
||||||
static void dumpType(Archive *fout, TypeInfo *tyinfo);
|
static void dumpType(Archive *fout, TypeInfo *tyinfo);
|
||||||
@ -300,6 +315,7 @@ main(int argc, char **argv)
|
|||||||
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
|
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
|
||||||
{"role", required_argument, NULL, 3},
|
{"role", required_argument, NULL, 3},
|
||||||
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
||||||
|
{"no-security-label", no_argument, &no_security_label, 1},
|
||||||
|
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
@ -448,6 +464,8 @@ main(int argc, char **argv)
|
|||||||
outputNoTablespaces = 1;
|
outputNoTablespaces = 1;
|
||||||
else if (strcmp(optarg, "use-set-session-authorization") == 0)
|
else if (strcmp(optarg, "use-set-session-authorization") == 0)
|
||||||
use_setsessauth = 1;
|
use_setsessauth = 1;
|
||||||
|
else if (strcmp(optarg, "no-security-label") == 0)
|
||||||
|
no_security_label = 1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@ -642,6 +660,12 @@ main(int argc, char **argv)
|
|||||||
if (quote_all_identifiers && g_fout->remoteVersion >= 90100)
|
if (quote_all_identifiers && g_fout->remoteVersion >= 90100)
|
||||||
do_sql_command(g_conn, "SET quote_all_identifiers = true");
|
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.
|
* Start serializable transaction to dump consistent data.
|
||||||
*/
|
*/
|
||||||
@ -839,6 +863,7 @@ help(const char *progname)
|
|||||||
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
|
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
|
||||||
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
|
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
|
||||||
printf(_(" --role=ROLENAME do SET ROLE before dump\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"
|
printf(_(" --use-set-session-authorization\n"
|
||||||
" use SET SESSION AUTHORIZATION commands instead of\n"
|
" use SET SESSION AUTHORIZATION commands instead of\n"
|
||||||
" ALTER OWNER commands to set ownership\n"));
|
" ALTER OWNER commands to set ownership\n"));
|
||||||
@ -2058,6 +2083,11 @@ dumpBlob(Archive *AH, BlobInfo *binfo)
|
|||||||
NULL, binfo->rolname,
|
NULL, binfo->rolname,
|
||||||
binfo->dobj.catId, 0, binfo->dobj.dumpId);
|
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 */
|
/* Dump ACL if any */
|
||||||
if (binfo->blobacl)
|
if (binfo->blobacl)
|
||||||
dumpACL(AH, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
|
dumpACL(AH, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
|
||||||
@ -6569,12 +6599,15 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
|
|||||||
nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
|
nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
/* Dump Schema Comments */
|
/* Dump Schema Comments and Security Labels */
|
||||||
resetPQExpBuffer(q);
|
resetPQExpBuffer(q);
|
||||||
appendPQExpBuffer(q, "SCHEMA %s", qnspname);
|
appendPQExpBuffer(q, "SCHEMA %s", qnspname);
|
||||||
dumpComment(fout, q->data,
|
dumpComment(fout, q->data,
|
||||||
NULL, nspinfo->rolname,
|
NULL, nspinfo->rolname,
|
||||||
nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
|
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",
|
dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
|
||||||
qnspname, NULL, nspinfo->dobj.name, NULL,
|
qnspname, NULL, nspinfo->dobj.name, NULL,
|
||||||
@ -6699,13 +6732,16 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
|
|||||||
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
|
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
/* Dump Type Comments */
|
/* Dump Type Comments and Security Labels */
|
||||||
resetPQExpBuffer(q);
|
resetPQExpBuffer(q);
|
||||||
|
|
||||||
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
|
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
|
||||||
dumpComment(fout, q->data,
|
dumpComment(fout, q->data,
|
||||||
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
|
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
|
||||||
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
|
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);
|
PQclear(res);
|
||||||
destroyPQExpBuffer(q);
|
destroyPQExpBuffer(q);
|
||||||
@ -7075,13 +7111,16 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
|
|||||||
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
|
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
/* Dump Type Comments */
|
/* Dump Type Comments and Security Labels */
|
||||||
resetPQExpBuffer(q);
|
resetPQExpBuffer(q);
|
||||||
|
|
||||||
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
|
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
|
||||||
dumpComment(fout, q->data,
|
dumpComment(fout, q->data,
|
||||||
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
|
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
|
||||||
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
|
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);
|
PQclear(res);
|
||||||
destroyPQExpBuffer(q);
|
destroyPQExpBuffer(q);
|
||||||
@ -7199,13 +7238,16 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
|
|||||||
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
|
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
/* Dump Domain Comments */
|
/* Dump Domain Comments and Security Labels */
|
||||||
resetPQExpBuffer(q);
|
resetPQExpBuffer(q);
|
||||||
|
|
||||||
appendPQExpBuffer(q, "DOMAIN %s", fmtId(tyinfo->dobj.name));
|
appendPQExpBuffer(q, "DOMAIN %s", fmtId(tyinfo->dobj.name));
|
||||||
dumpComment(fout, q->data,
|
dumpComment(fout, q->data,
|
||||||
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
|
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
|
||||||
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
|
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(q);
|
||||||
destroyPQExpBuffer(delq);
|
destroyPQExpBuffer(delq);
|
||||||
@ -7299,13 +7341,16 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
|
|||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
|
|
||||||
/* Dump Type Comments */
|
/* Dump Type Comments and Security Labels */
|
||||||
resetPQExpBuffer(q);
|
resetPQExpBuffer(q);
|
||||||
|
|
||||||
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
|
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
|
||||||
dumpComment(fout, q->data,
|
dumpComment(fout, q->data,
|
||||||
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
|
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
|
||||||
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
|
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);
|
PQclear(res);
|
||||||
destroyPQExpBuffer(q);
|
destroyPQExpBuffer(q);
|
||||||
@ -7623,12 +7668,15 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
|
|||||||
plang->dobj.dependencies, plang->dobj.nDeps,
|
plang->dobj.dependencies, plang->dobj.nDeps,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
/* Dump Proc Lang Comments */
|
/* Dump Proc Lang Comments and Security Labels */
|
||||||
resetPQExpBuffer(defqry);
|
resetPQExpBuffer(defqry);
|
||||||
appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
|
appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
|
||||||
dumpComment(fout, defqry->data,
|
dumpComment(fout, defqry->data,
|
||||||
NULL, "",
|
NULL, "",
|
||||||
plang->dobj.catId, 0, plang->dobj.dumpId);
|
plang->dobj.catId, 0, plang->dobj.dumpId);
|
||||||
|
dumpSecLabel(fout, defqry->data,
|
||||||
|
NULL, "",
|
||||||
|
plang->dobj.catId, 0, plang->dobj.dumpId);
|
||||||
|
|
||||||
if (plang->lanpltrusted)
|
if (plang->lanpltrusted)
|
||||||
dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
|
dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
|
||||||
@ -8184,12 +8232,15 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
finfo->dobj.dependencies, finfo->dobj.nDeps,
|
finfo->dobj.dependencies, finfo->dobj.nDeps,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
/* Dump Function Comments */
|
/* Dump Function Comments and Security Labels */
|
||||||
resetPQExpBuffer(q);
|
resetPQExpBuffer(q);
|
||||||
appendPQExpBuffer(q, "FUNCTION %s", funcsig);
|
appendPQExpBuffer(q, "FUNCTION %s", funcsig);
|
||||||
dumpComment(fout, q->data,
|
dumpComment(fout, q->data,
|
||||||
finfo->dobj.namespace->dobj.name, finfo->rolname,
|
finfo->dobj.namespace->dobj.name, finfo->rolname,
|
||||||
finfo->dobj.catId, 0, finfo->dobj.dumpId);
|
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",
|
dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
|
||||||
funcsig, NULL, funcsig_tag,
|
funcsig, NULL, funcsig_tag,
|
||||||
@ -9687,6 +9738,9 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
|
|||||||
dumpComment(fout, q->data,
|
dumpComment(fout, q->data,
|
||||||
agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
|
agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
|
||||||
agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
|
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
|
* Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
|
||||||
@ -10434,6 +10488,300 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
|
|||||||
destroyPQExpBuffer(sql);
|
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
|
* dumpTable
|
||||||
* write out to fout the declarations (not data) of a user-defined table
|
* write out to fout the declarations (not data) of a user-defined table
|
||||||
@ -10950,6 +11298,9 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
|||||||
/* Dump Table Comments */
|
/* Dump Table Comments */
|
||||||
dumpTableComment(fout, tbinfo, reltypename);
|
dumpTableComment(fout, tbinfo, reltypename);
|
||||||
|
|
||||||
|
/* Dump Table Security Labels */
|
||||||
|
dumpTableSecLabel(fout, tbinfo, reltypename);
|
||||||
|
|
||||||
/* Dump comments on inlined table constraints */
|
/* Dump comments on inlined table constraints */
|
||||||
for (j = 0; j < tbinfo->ncheck; j++)
|
for (j = 0; j < tbinfo->ncheck; j++)
|
||||||
{
|
{
|
||||||
@ -11663,12 +12014,15 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dump Sequence Comments */
|
/* Dump Sequence Comments and Security Labels */
|
||||||
resetPQExpBuffer(query);
|
resetPQExpBuffer(query);
|
||||||
appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
|
appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
|
||||||
dumpComment(fout, query->data,
|
dumpComment(fout, query->data,
|
||||||
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
|
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
|
||||||
tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
|
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)
|
if (!schemaOnly)
|
||||||
|
@ -69,6 +69,7 @@ static int disable_triggers = 0;
|
|||||||
static int inserts = 0;
|
static int inserts = 0;
|
||||||
static int no_tablespaces = 0;
|
static int no_tablespaces = 0;
|
||||||
static int use_setsessauth = 0;
|
static int use_setsessauth = 0;
|
||||||
|
static int no_security_label = 0;
|
||||||
static int server_version;
|
static int server_version;
|
||||||
|
|
||||||
static FILE *OPF;
|
static FILE *OPF;
|
||||||
@ -133,6 +134,7 @@ main(int argc, char *argv[])
|
|||||||
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
|
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
|
||||||
{"role", required_argument, NULL, 3},
|
{"role", required_argument, NULL, 3},
|
||||||
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
||||||
|
{"no-security-label", no_argument, &no_security_label, 1},
|
||||||
|
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
@ -286,6 +288,8 @@ main(int argc, char *argv[])
|
|||||||
no_tablespaces = 1;
|
no_tablespaces = 1;
|
||||||
else if (strcmp(optarg, "use-set-session-authorization") == 0)
|
else if (strcmp(optarg, "use-set-session-authorization") == 0)
|
||||||
use_setsessauth = 1;
|
use_setsessauth = 1;
|
||||||
|
else if (strcmp(optarg, "no-security-label") == 0)
|
||||||
|
no_security_label = 1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@ -371,6 +375,8 @@ main(int argc, char *argv[])
|
|||||||
appendPQExpBuffer(pgdumpopts, " --quote-all-identifiers");
|
appendPQExpBuffer(pgdumpopts, " --quote-all-identifiers");
|
||||||
if (use_setsessauth)
|
if (use_setsessauth)
|
||||||
appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
|
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,
|
* If there was a database specified on the command line, use that,
|
||||||
@ -567,6 +573,7 @@ help(void)
|
|||||||
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
|
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
|
||||||
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
|
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
|
||||||
printf(_(" --role=ROLENAME do SET ROLE before dump\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"
|
printf(_(" --use-set-session-authorization\n"
|
||||||
" use SET SESSION AUTHORIZATION commands instead of\n"
|
" use SET SESSION AUTHORIZATION commands instead of\n"
|
||||||
" ALTER OWNER commands to set ownership\n"));
|
" ALTER OWNER commands to set ownership\n"));
|
||||||
|
@ -76,6 +76,7 @@ main(int argc, char **argv)
|
|||||||
static int no_data_for_failed_tables = 0;
|
static int no_data_for_failed_tables = 0;
|
||||||
static int outputNoTablespaces = 0;
|
static int outputNoTablespaces = 0;
|
||||||
static int use_setsessauth = 0;
|
static int use_setsessauth = 0;
|
||||||
|
static int skip_seclabel = 0;
|
||||||
|
|
||||||
struct option cmdopts[] = {
|
struct option cmdopts[] = {
|
||||||
{"clean", 0, NULL, 'c'},
|
{"clean", 0, NULL, 'c'},
|
||||||
@ -116,6 +117,7 @@ main(int argc, char **argv)
|
|||||||
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
|
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
|
||||||
{"role", required_argument, NULL, 2},
|
{"role", required_argument, NULL, 2},
|
||||||
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
||||||
|
{"no-security-label", no_argument, &skip_seclabel, 1},
|
||||||
|
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
@ -262,6 +264,8 @@ main(int argc, char **argv)
|
|||||||
outputNoTablespaces = 1;
|
outputNoTablespaces = 1;
|
||||||
else if (strcmp(optarg, "use-set-session-authorization") == 0)
|
else if (strcmp(optarg, "use-set-session-authorization") == 0)
|
||||||
use_setsessauth = 1;
|
use_setsessauth = 1;
|
||||||
|
else if (strcmp(optarg, "no-security-label") == 0)
|
||||||
|
skip_seclabel = 1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@ -337,6 +341,7 @@ main(int argc, char **argv)
|
|||||||
opts->noDataForFailedTables = no_data_for_failed_tables;
|
opts->noDataForFailedTables = no_data_for_failed_tables;
|
||||||
opts->noTablespace = outputNoTablespaces;
|
opts->noTablespace = outputNoTablespaces;
|
||||||
opts->use_setsessauth = use_setsessauth;
|
opts->use_setsessauth = use_setsessauth;
|
||||||
|
opts->skip_seclabel = skip_seclabel;
|
||||||
|
|
||||||
if (opts->formatName)
|
if (opts->formatName)
|
||||||
{
|
{
|
||||||
@ -442,6 +447,7 @@ usage(const char *progname)
|
|||||||
" do not restore data of tables that could not be\n"
|
" do not restore data of tables that could not be\n"
|
||||||
" created\n"));
|
" created\n"));
|
||||||
printf(_(" --no-tablespaces do not restore tablespace assignments\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(_(" --role=ROLENAME do SET ROLE before restore\n"));
|
||||||
printf(_(" --use-set-session-authorization\n"
|
printf(_(" --use-set-session-authorization\n"
|
||||||
" use SET SESSION AUTHORIZATION commands instead of\n"
|
" use SET SESSION AUTHORIZATION commands instead of\n"
|
||||||
|
@ -631,8 +631,9 @@ psql_completion(char *text, int start, int end)
|
|||||||
"DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
|
"DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
|
||||||
"GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
|
"GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
|
||||||
"REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
|
"REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
|
||||||
"SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TABLE", "TRUNCATE", "UNLISTEN",
|
"SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
|
||||||
"UPDATE", "VACUUM", "VALUES", "WITH", NULL
|
"TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const backslash_commands[] = {
|
static const char *const backslash_commands[] = {
|
||||||
@ -2193,6 +2194,40 @@ psql_completion(char *text, int start, int end)
|
|||||||
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
|
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 */
|
/* SELECT */
|
||||||
/* naah . . . */
|
/* naah . . . */
|
||||||
|
|
||||||
|
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201009021
|
#define CATALOG_VERSION_NO 201009271
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -281,6 +281,9 @@ DECLARE_UNIQUE_INDEX(pg_default_acl_oid_index, 828, on pg_default_acl using btre
|
|||||||
DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops));
|
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
|
#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 */
|
/* last step of initialization script: build the indexes declared above */
|
||||||
BUILD_INDICES
|
BUILD_INDICES
|
||||||
|
|
||||||
|
43
src/include/catalog/pg_seclabel.h
Normal file
43
src/include/catalog/pg_seclabel.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
@ -45,6 +45,7 @@ DECLARE_TOAST(pg_constraint, 2832, 2833);
|
|||||||
DECLARE_TOAST(pg_description, 2834, 2835);
|
DECLARE_TOAST(pg_description, 2834, 2835);
|
||||||
DECLARE_TOAST(pg_proc, 2836, 2837);
|
DECLARE_TOAST(pg_proc, 2836, 2837);
|
||||||
DECLARE_TOAST(pg_rewrite, 2838, 2839);
|
DECLARE_TOAST(pg_rewrite, 2838, 2839);
|
||||||
|
DECLARE_TOAST(pg_seclabel, 3039, 3040);
|
||||||
DECLARE_TOAST(pg_statistic, 2840, 2841);
|
DECLARE_TOAST(pg_statistic, 2840, 2841);
|
||||||
DECLARE_TOAST(pg_trigger, 2336, 2337);
|
DECLARE_TOAST(pg_trigger, 2336, 2337);
|
||||||
|
|
||||||
|
35
src/include/commands/seclabel.h
Normal file
35
src/include/commands/seclabel.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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 */
|
@ -347,6 +347,7 @@ typedef enum NodeTag
|
|||||||
T_AlterUserMappingStmt,
|
T_AlterUserMappingStmt,
|
||||||
T_DropUserMappingStmt,
|
T_DropUserMappingStmt,
|
||||||
T_AlterTableSpaceOptionsStmt,
|
T_AlterTableSpaceOptionsStmt,
|
||||||
|
T_SecLabelStmt,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TAGS FOR PARSE TREE NODES (parsenodes.h)
|
* TAGS FOR PARSE TREE NODES (parsenodes.h)
|
||||||
|
@ -1850,6 +1850,20 @@ typedef struct CommentStmt
|
|||||||
char *comment; /* Comment to insert, or NULL to remove */
|
char *comment; /* Comment to insert, or NULL to remove */
|
||||||
} CommentStmt;
|
} 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
|
* Declare Cursor Statement
|
||||||
*
|
*
|
||||||
|
@ -209,6 +209,7 @@ PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
|
|||||||
PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
|
PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
|
PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
|
||||||
PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
|
PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
|
||||||
|
PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
|
PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
|
PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
|
PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
|
||||||
|
@ -107,9 +107,9 @@ installdirs-tests: installdirs
|
|||||||
$(MKDIR_P) $(patsubst $(srcdir)/%/,'$(DESTDIR)$(pkglibdir)/regress/%',$(sort $(dir $(regress_data_files))))
|
$(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)
|
refint$(DLSUFFIX): $(top_builddir)/contrib/spi/refint$(DLSUFFIX)
|
||||||
cp $< $@
|
cp $< $@
|
||||||
@ -117,12 +117,17 @@ refint$(DLSUFFIX): $(top_builddir)/contrib/spi/refint$(DLSUFFIX)
|
|||||||
autoinc$(DLSUFFIX): $(top_builddir)/contrib/spi/autoinc$(DLSUFFIX)
|
autoinc$(DLSUFFIX): $(top_builddir)/contrib/spi/autoinc$(DLSUFFIX)
|
||||||
cp $< $@
|
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
|
$(top_builddir)/contrib/spi/refint$(DLSUFFIX): $(top_srcdir)/contrib/spi/refint.c
|
||||||
$(MAKE) -C $(top_builddir)/contrib/spi refint$(DLSUFFIX)
|
$(MAKE) -C $(top_builddir)/contrib/spi refint$(DLSUFFIX)
|
||||||
|
|
||||||
$(top_builddir)/contrib/spi/autoinc$(DLSUFFIX): $(top_srcdir)/contrib/spi/autoinc.c
|
$(top_builddir)/contrib/spi/autoinc$(DLSUFFIX): $(top_srcdir)/contrib/spi/autoinc.c
|
||||||
$(MAKE) -C $(top_builddir)/contrib/spi autoinc$(DLSUFFIX)
|
$(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
|
# Tablespace setup
|
||||||
|
|
||||||
@ -171,7 +176,8 @@ bigcheck: all
|
|||||||
|
|
||||||
clean distclean maintainer-clean: clean-lib
|
clean distclean maintainer-clean: clean-lib
|
||||||
# things built by `all' target
|
# 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
|
# things created by various check targets
|
||||||
rm -f $(output_files) $(input_files)
|
rm -f $(output_files) $(input_files)
|
||||||
rm -rf testtablespace
|
rm -rf testtablespace
|
||||||
|
1
src/test/regress/expected/.gitignore
vendored
1
src/test/regress/expected/.gitignore
vendored
@ -5,4 +5,5 @@
|
|||||||
/largeobject.out
|
/largeobject.out
|
||||||
/largeobject_1.out
|
/largeobject_1.out
|
||||||
/misc.out
|
/misc.out
|
||||||
|
/security_label.out
|
||||||
/tablespace.out
|
/tablespace.out
|
||||||
|
@ -1276,8 +1276,8 @@ drop table cchild;
|
|||||||
-- Check that ruleutils are working
|
-- Check that ruleutils are working
|
||||||
--
|
--
|
||||||
SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
|
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);
|
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_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_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);
|
||||||
@ -1287,6 +1287,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_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_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_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_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_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));
|
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));
|
||||||
@ -1333,7 +1334,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
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))));
|
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);
|
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;
|
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
|
SELECT tablename, rulename, definition FROM pg_rules
|
||||||
ORDER BY tablename, rulename;
|
ORDER BY tablename, rulename;
|
||||||
|
@ -114,6 +114,7 @@ SELECT relname, relhasindex
|
|||||||
pg_pltemplate | t
|
pg_pltemplate | t
|
||||||
pg_proc | t
|
pg_proc | t
|
||||||
pg_rewrite | t
|
pg_rewrite | t
|
||||||
|
pg_seclabel | t
|
||||||
pg_shdepend | t
|
pg_shdepend | t
|
||||||
pg_shdescription | t
|
pg_shdescription | t
|
||||||
pg_statistic | t
|
pg_statistic | t
|
||||||
@ -153,7 +154,7 @@ SELECT relname, relhasindex
|
|||||||
timetz_tbl | f
|
timetz_tbl | f
|
||||||
tinterval_tbl | f
|
tinterval_tbl | f
|
||||||
varchar_tbl | f
|
varchar_tbl | f
|
||||||
(142 rows)
|
(143 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- another sanity check: every system catalog that has OIDs should have
|
-- another sanity check: every system catalog that has OIDs should have
|
||||||
|
84
src/test/regress/input/security_label.source
Normal file
84
src/test/regress/input/security_label.source
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
--
|
||||||
|
-- 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;
|
92
src/test/regress/output/security_label.source
Normal file
92
src/test/regress/output/security_label.source
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
--
|
||||||
|
-- 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)
|
||||||
|
|
@ -76,7 +76,7 @@ ignore: random
|
|||||||
# ----------
|
# ----------
|
||||||
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: 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
|
test: misc
|
||||||
# rules cannot run concurrently with any test that creates a view
|
# rules cannot run concurrently with any test that creates a view
|
||||||
test: rules
|
test: rules
|
||||||
|
@ -88,6 +88,7 @@ test: delete
|
|||||||
test: namespace
|
test: namespace
|
||||||
test: prepared_xacts
|
test: prepared_xacts
|
||||||
test: privileges
|
test: privileges
|
||||||
|
test: security_label
|
||||||
test: misc
|
test: misc
|
||||||
test: rules
|
test: rules
|
||||||
test: select_views
|
test: select_views
|
||||||
|
1
src/test/regress/sql/.gitignore
vendored
1
src/test/regress/sql/.gitignore
vendored
@ -4,4 +4,5 @@
|
|||||||
/create_function_2.sql
|
/create_function_2.sql
|
||||||
/largeobject.sql
|
/largeobject.sql
|
||||||
/misc.sql
|
/misc.sql
|
||||||
|
/security_label.sql
|
||||||
/tablespace.sql
|
/tablespace.sql
|
||||||
|
Loading…
x
Reference in New Issue
Block a user