*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 209,214 ****
--- 209,219 ----
+ pg_seclabel
+ security labels on local database objects
+
+
+ pg_shdependdependencies on shared objects
***************
*** 4227,4232 ****
--- 4232,4322 ----
+
+ pg_seclabel
+
+
+ pg_seclabel
+
+
+
+ The catalog pg_seclabel stores the security
+ label of database objects. This information allows external security
+ providers to apply label based mandatory access controls.
+
+
+
+ When external security providers with label based mandatory access
+ control are installed, its security label shall be assigned on
+ creation of database obejcts.
+ (Please note that only relations are supported right now.)
+
+
+ The security labels shall be automatically cleaned up when the database
+ object being labeled is dropped.
+
+
+ See also SECURITY LABEL,
+ which provides a functionality to relabel a certain database object,
+ as long as user has enough privileges.
+
+
+
+ pg_seclabel Columns
+
+
+
+
+ Name
+ Type
+ References
+ Description
+
+
+
+
+
+ reloid
+ oid
+ pg_class.oid
+ The OID of the system catalog this object appears in
+
+
+
+ objoid
+ oid
+ any OID column
+ The OID of the object this security label assigned on
+
+
+
+ subid
+ int4
+
+ For a security label on a table column, this is the column number
+ (the objoid and classoid
+ refer to the table itself). For all other object types, this column is
+ zero
+
+
+
+
+ tag
+ text
+
+ identifier of external security provider
+
+
+
+ label
+ text
+
+ security label in text format
+
+
+
+
+ pg_shdepend
*** /dev/null
--- b/doc/src/sgml/esp.sgml
***************
*** 0 ****
--- 1,249 ----
+
+ External Security Provider
+
+ External security provider (ESP) is a plugin which makes access control
+ decision based on its security model and policy.
+
+
+ PostgreSQL version 9.1 or later provides a set of
+ facilities to enhance access control features using ESP, in addition to the
+ default database privilege mechanism introduced
+ as the .
+
+
+ This chapter introduces brief overview of ESP concept and corresponding
+ features, but it does not introduce details of individual ESP plugins.
+ If you need to know something about a certain ESP plugin, please reference
+ documentation of the plugin.
+
+
+
+ Overview
+
+ The ESP concept was designed to integrate various kind of security
+ models into PostgreSQL.
+
+ It allows third-party modules to perform as security provider which
+ makes access control decision on accesses to database objects;
+ such as tables, functions and so on.
+
+ Please note that it never replaces anything in the default database
+ privilege mechanism. It just installs additional access control stuffs.
+
+
+ Access control is a mechanism that decides what actions are allowed
+ or denied on a pair of certain user and object to be referenced,
+ then applies the decision on any requests come from clients.
+
+
+ The default database privilege mechanism makes its access control
+ decision based on the authenticated user identifier and permissions
+ of database objects to be referenced.
+
+
+ Here are some cases that we hope to make and apply access control
+ decisions based on a different basis from the default one.
+
+ For example, one significant goal of ESP is integration of mandatory
+ access control that only allows security administrator to set up
+ access rights of database objects, unlike the default one which
+ allows owner of them to set up their access rights.
+
+
+ At the implementation level, PostgreSQL 9.1
+ or later provides a series of security hooks which are put on strategic
+ points of core routines; such as a routine that checks permissions of
+ tables and columns for the supplied DML statement.
+
+
+ ESP modules shall be invoked via the security hooks, then it can make
+ its access control decision based on the security model and supplied
+ information about user's request; such as OID of tables to be referenced.
+
+
+ Expected behaviors are depending on every security hooks.
+
+ One hook may assume ESP raises an error, if access control violation.
+ One other hook may assume ESP returns a bool value which informs the
+ caller routine whether its decision was 'allowed' or 'denied'.
+
+
+ These hooks shall be filled up when we load plugins.
+
+ Administrator can add a configuration of
+ shared_preload_libraries on which we specify a few
+ plugins to be loaded on starting up the server process, as follows:
+
+
+ shared_preload_libraries = 'sepgsql' # (change requires restart)
+
+
+ You should never use local_preload_libraries instead,
+ even if the plugin is well verified without any vulnerabilities, because
+ it can be overridden by GUC variable settings passed in startup packet.
+
+
+ Please note that ESP framework has quite-limited coverage of access control
+ compared to the default database privilege mechanism right now.
+ In this release, it only hooks on execution of DML, a part of DDL and
+ post client authentication process.
+
+
+
+
+ Mandatory Access Control
+
+ It is a major of ESP to support mandatory access control (MAC) policy
+ in PostgreSQL.
+
+
+ Unlike discretionary access control (DAC), only a security administrator
+ is allowed to control centralized MAC policy and access rights on
+ individual objects; it means any other users don't have ability to change
+ the access rights on database objects, even if they have ownership of the
+ object.
+
+
+ This characteristic enables to confine classified information in certain
+ domains, even if owner of data tries to leak it somewhere, because the
+ owner cannot change its access rights as he like.
+
+
+ Here is a a traditional rule for instance. It prevents people who can
+ read both of classified and unclassified data object to write unclassified
+ data object. It means infomation moves only single direction; from
+ unclassified to classified. Since this rule is applied to everybody,
+ noboby can leak classified information into unclassified ones, even if
+ a malicious internal tries to do.
+
+
+ MAC is designed to tackle such a strict security requirement.
+
+
+
+ Security Label
+
+ In the default database privileges, GRANT and
+ REVOKE commands allow superusers and owner of the
+ database obejcts to set up access permissions, then it makes access
+ control decision based on these properties.
+
+
+ On the other hand, MAC model also has a property that characterizes
+ database objects from the viewpoint of MAC. A typical MAC feature uses
+ security label to identify the objects. It is a short text with a format
+ according to the security model.
+
+
+ The following examples are security label in SELinux.
+ It contains all the needed properties to make access control decision
+ from the viewpoint of SELinux, like a pair of access permissions and
+ owner identifier of the database object.
+
+ dbadm_u:system_r:postgresql_t:s0
+
+ system_u:object_r:sepgsql_table_t:s0:c0
+
+
+
+ It also means MAC model cannot make its access control decision on accesses
+ to database objects without security labels. So, we need to assign a certain
+ security label on database objects to be referenced.
+
+
+ In addition, MAC model also represents privilege set of user as a security
+ label, instead of user identifier. Mostly, security label of the users are
+ assigned according to the result of authentication.
+
+
+ In other words, MAC mechanism is something like a function which returns
+ a binary state ('allowed' or 'denied') for the supplied actions and
+ security labels of user and object to be referenced.
+
+
+ DAC mechanism (ie; the default database privilege mechanism) is also like
+ a function which returns a binary state for the supplied actions, user
+ identifier and permissions on the object to be referenced, so they are not
+ fundamentally difference.
+
+
+
+ Management of security label
+
+ As we introduced above, MAC mechanism needs both of user and object to be
+ labeled, to make its access control decision.
+
+
+ For database objects, PostgreSQL provides
+ a facility that enables to assign a security label on them.
+
+ When an ESP plugin of MAC is installed, it shall assign a default security
+ label of a new database object on its creation time.
+
+ In addition, user can relabel security label of database objects using
+ command later, as long as this
+ operation is allowed by security mechanisms.
+
+
+ The following example creates a new table tbl on the
+ system with SELinux support using ESP.
+
+ postgres=> CREATE TABLE tbl (x int, y text);
+ CREATE TABLE
+ postgres=> SELECT * FROM pg_seclabel WHERE objoid = 'tbl'::regclass and subid=0;
+ reloid | objoid | subid | tag | label
+ --------+--------+-------+---------+--------------------------------------
+ 1259 | 24600 | 0 | selinux | system_u:object_r:sepgsql_table_t:s0
+ (1 row)
+
+ It shows us that system_u:object_r:sepgsql_table_t:s0
+ was assigned on the creation time of table tbl.
+
+ postgres=> SECURITY LABEL ON TABLE tbl IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+ SECURITY LABEL
+ postgres=> SELECT * FROM pg_seclabel WHERE objoid = 'tbl'::regclass and subid=0;
+ reloid | objoid | subid | tag | label
+ --------+--------+-------+---------+-----------------------------------------
+ 1259 | 24600 | 0 | selinux | system_u:object_r:sepgsql_ro_table_t:s0
+ (1 row)
+
+ It also shows us SECURITY LABEL command allows to relabel
+ the table to system_u:object_r:sepgsql_ro_table_t:s0.
+
+
+ The
+
+ pg_seclabel
+
+ is a system catalog to store
+ security labels, and ESP plugins shall reference the catalog to fetch
+ them on making its access control decisions.
+
+
+ On the other hand, the way to assign a security label of user is depending
+ on the type of ESP plugin.
+
+ Perhaps, one plugin may associates a security label with authenticated
+ database user, and other plugin assigns a security label which is retrieved
+ from the peer process using system API.
+
+ So, PostgreSQL does not constrain ESP plugins
+ a certain way to retrive security label of users.
+ It provides a hook just after the database authentication, ESP plugin can
+ assign a security label on the current session with its own way.
+
+
+ When we backup and restore databases, security labels are also properties
+ of database objects to be handled correctly.
+
+ The pg_dump and pg_dumpall support
+ --security-label option that enables to include
+ security label of the database objects into archives.
+
+ And the pg_restore also supports
+ --no-security-label option that enables to ignore
+ security labels, even if the archives contains labels.
+
+
+
+
*** a/doc/src/sgml/external-projects.sgml
--- b/doc/src/sgml/external-projects.sgml
***************
*** 250,254 ****
--- 250,266 ----
pgAdmin III>,
and there are several commercially available ones as well.
+
+
+ The introduces how PostgreSQL>
+ integrate additional security features using external security
+ providers.
+
+
+ SE-PostgreSQL
+ is an external security provider which
+ applies mandatory access control based on the centralized
+ security policy of operation system.
+
*** a/doc/src/sgml/filelist.sgml
--- b/doc/src/sgml/filelist.sgml
***************
*** 46,51 ****
--- 46,52 ----
+
*** a/doc/src/sgml/postgres.sgml
--- b/doc/src/sgml/postgres.sgml
***************
*** 150,155 ****
--- 150,156 ----
&config;
&client-auth;
&user-manag;
+ &esp;
&manage-ag;
&charset;
&maintenance;
*** a/doc/src/sgml/ref/allfiles.sgml
--- b/doc/src/sgml/ref/allfiles.sgml
***************
*** 132,137 **** Complete list of usable sgml source files in this directory.
--- 132,138 ----
+
*** a/doc/src/sgml/ref/pg_dump.sgml
--- b/doc/src/sgml/ref/pg_dump.sgml
***************
*** 778,783 **** PostgreSQL documentation
--- 778,793 ----
+
+
+
+
+
+ With this option, it also outputs security labels of database
+ objects to be dumped, if labeled.
+
+
+
*** a/doc/src/sgml/ref/pg_dumpall.sgml
--- b/doc/src/sgml/ref/pg_dumpall.sgml
***************
*** 493,498 **** PostgreSQL documentation
--- 493,507 ----
+
+
+
+
+ With this option, it also outputs security labels of database
+ objects to be dumped, if labeled.
+
+
+
*** a/doc/src/sgml/ref/pg_restore.sgml
--- b/doc/src/sgml/ref/pg_restore.sgml
***************
*** 329,334 ****
--- 329,347 ----
+
+
+
+ Do not output commands to relabel database objects,
+ even if the archive contains them.
+ With this option, all objects will be created with a default
+ security label, or without any labels if no label based
+ security feature is not installed.
+
+
+
+
+
*** /dev/null
--- b/doc/src/sgml/ref/seclabel.sgml
***************
*** 0 ****
--- 1,123 ----
+
+
+ SECURITY LABEL
+ 7
+ SQL - Language Statements
+
+
+
+ SECURITY LABEL
+ relabel the security label of an object
+
+
+
+ SECURITY LABEL
+
+
+
+
+ SECURITY LABEL [ FOR 'esp_tag' ] ON
+ {
+ TABLE object_name |
+ COLUMN table_name.column_name |
+ SEQUENCE object_name |
+ VIEW object_name
+ } IS 'security_label';
+
+
+
+
+ Description
+
+
+ SECURITY LABEL relabels a security label of a database object.
+
+
+
+ We can assign individual security labels on a certain database object for
+ each security providers, using SECURITY LABEL command.
+
+
+ Security labels are automatically assigned when the object is created,
+ and also automatically dropped when the object is dropped.
+
+
+
+
+
+ Parameters
+
+
+ object_name
+ table_name
+ table_name.column_name
+
+
+ The name of the object to be relabeled. Names of tables, columns,
+ sequences and views can be schema-qualified.
+
+
+
+
+
+ security_label
+
+
+ The new security label as a string literal.
+
+
+ It shall be validated by one of the label based security features,
+ in addition to its permission checks relabeling on the specified
+ database objects.
+
+
+
+
+
+ esp_tag
+
+
+ The identifier string of external security provider.
+
+
+ When we install just one provider, we can omit this clause because
+ it is obvious which provider shall handle the given security label.
+ Elsewhere, when we install two or more providers concurrently,
+ we need to identify a certain external security provider.
+
+
+
+
+
+
+
+ Notes
+
+ This feature requires one label based mandatory access control feature
+ to be installed at least, because a security label is specific for
+ each providers, so it has to be validated when we relabel it.
+
+
+
+
+ Examples
+
+
+ Relabel a security label on the table to 'system_u:object_r:sepgsql_table_t:s0'.
+
+
+ SECURITY LABEL FOR 'selinux' ON TABLE mytable IS 'system_u:object_r:sepgsql_table_t:s0';
+
+
+
+
+
+ Compatibility
+
+ There is no SECURITY LABEL command in the SQL standard.
+
+
+
+
+
+
*** a/doc/src/sgml/reference.sgml
--- b/doc/src/sgml/reference.sgml
***************
*** 160,165 ****
--- 160,166 ----
&rollbackPrepared;
&rollbackTo;
&savepoint;
+ &securityLabel;
&select;
&selectInto;
&set;
*** a/src/backend/catalog/Makefile
--- b/src/backend/catalog/Makefile
***************
*** 38,44 **** POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
pg_ts_parser.h pg_ts_template.h \
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
! pg_default_acl.h \
toasting.h indexing.h \
)
--- 38,44 ----
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
pg_ts_parser.h pg_ts_template.h \
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
! pg_default_acl.h pg_seclabel.h \
toasting.h indexing.h \
)
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 57,62 ****
--- 57,63 ----
#include "commands/defrem.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
+ #include "commands/seclabel.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
***************
*** 1010,1015 **** deleteOneObject(const ObjectAddress *object, Relation depRel)
--- 1011,1023 ----
DeleteComments(object->objectId, object->classId, object->objectSubId);
/*
+ * Delete any security labels associated with this object. (This is also
+ * a convenient place to do it instead of having every object type know
+ * to do it.)
+ */
+ DeleteSecurityLabel(object);
+
+ /*
* CommandCounterIncrement here to ensure that preceding changes are all
* visible to the next deletion step.
*/
*** a/src/backend/commands/Makefile
--- b/src/backend/commands/Makefile
***************
*** 17,23 **** 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 \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \
! schemacmds.o sequence.o tablecmds.o tablespace.o trigger.o \
tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
variable.o view.o
--- 17,23 ----
dbcommands.o define.o discard.o explain.o foreigncmds.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \
! schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
variable.o view.o
*** /dev/null
--- b/src/backend/commands/seclabel.c
***************
*** 0 ****
--- 1,441 ----
+ /* -------------------------------------------------------------------------
+ *
+ * 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/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"
+
+ /*
+ * GetSecurityLabel
+ *
+ * It tries to look up a security label entry for the given OID of
+ * the catalog, object itself and sub identifier (if needed) from
+ * the pg_selabel system catalog.
+ * It can return NULL, if no valid entry. Elsewhere, it returns
+ * a security label of the specified database object.
+ */
+ char *
+ GetSecurityLabel(const ObjectAddress *object, const char *tag)
+ {
+ 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_reloid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->classId));
+ ScanKeyInit(&keys[1],
+ Anum_pg_seclabel_objoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+ ScanKeyInit(&keys[2],
+ Anum_pg_seclabel_subid,
+ BTEqualStrategyNumber, F_INT4EQ,
+ Int32GetDatum(object->objectSubId));
+ ScanKeyInit(&keys[3],
+ Anum_pg_seclabel_tag,
+ BTEqualStrategyNumber, F_TEXTEQ,
+ CStringGetTextDatum(tag));
+
+ 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
+ *
+ * It tries to insert/update/delete a security label for the given OID
+ * of the catalog, object itself and sub identifier (if needed) on the
+ * pg_seclabel system catalog.
+ * If given 'seclabel' is NULL, it tries to delete the specified entry.
+ * Elsewhere, it tries to insert (if no specified entry now) or updata
+ * security label of the specified entry.
+ */
+ void
+ SetSecurityLabel(const ObjectAddress *object,
+ const char *tag, const char *seclabel)
+ {
+ 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];
+
+ Assert(!IsSharedRelation(object->classId));
+
+ ScanKeyInit(&keys[0],
+ Anum_pg_seclabel_reloid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->classId));
+ ScanKeyInit(&keys[1],
+ Anum_pg_seclabel_objoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+ ScanKeyInit(&keys[2],
+ Anum_pg_seclabel_subid,
+ BTEqualStrategyNumber, F_INT4EQ,
+ Int32GetDatum(object->objectSubId));
+ ScanKeyInit(&keys[3],
+ Anum_pg_seclabel_tag,
+ BTEqualStrategyNumber, F_TEXTEQ,
+ CStringGetTextDatum(tag));
+
+ pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
+
+ scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
+ SnapshotNow, 4, keys);
+
+ oldtup = systable_getnext(scan);
+ if (HeapTupleIsValid(oldtup))
+ {
+ if (seclabel != NULL)
+ {
+ /*
+ * update the specified security label entry
+ */
+ memset(nulls, false, sizeof(nulls));
+ memset(replaces, false, sizeof(replaces));
+
+ replaces[Anum_pg_seclabel_label - 1] = true;
+ values[Anum_pg_seclabel_label - 1]
+ = CStringGetTextDatum(seclabel);
+
+ newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_seclabel),
+ values, nulls, replaces);
+ simple_heap_update(pg_seclabel, &oldtup->t_self, newtup);
+
+ CatalogUpdateIndexes(pg_seclabel, newtup);
+
+ heap_freetuple(newtup);
+ }
+ else
+ {
+ /*
+ * when seclabel = NULL, it means to remove the matched
+ * entry from pg_seclabel.
+ */
+ simple_heap_delete(pg_seclabel, &oldtup->t_self);
+ }
+ }
+ else if (seclabel != NULL)
+ {
+ /*
+ * insert a new security label entry
+ */
+ memset(nulls, false, sizeof(nulls));
+ values[Anum_pg_seclabel_reloid - 1] = ObjectIdGetDatum(object->classId);
+ values[Anum_pg_seclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
+ values[Anum_pg_seclabel_subid - 1] = Int32GetDatum(object->objectSubId);
+ values[Anum_pg_seclabel_tag - 1] = CStringGetTextDatum(tag);
+ values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(seclabel);
+
+ newtup = heap_form_tuple(RelationGetDescr(pg_seclabel),
+ values, nulls);
+ simple_heap_insert(pg_seclabel, newtup);
+
+ CatalogUpdateIndexes(pg_seclabel, newtup);
+
+ heap_freetuple(newtup);
+ }
+ systable_endscan(scan);
+
+ heap_close(pg_seclabel, RowExclusiveLock);
+ }
+
+ /*
+ * DeleteSecurityLabel
+ *
+ * It tries to delete entries of security labels for given OID of
+ * the catalog, object itself and sub identifier (if needed) on
+ * the pg_seclabel system catalog.
+ * If given 'objectSubId' is 0, all the security labels matching
+ * with classId and objectId will be removed.
+ */
+ void
+ DeleteSecurityLabel(const ObjectAddress *object)
+ {
+ Relation pg_seclabel;
+ ScanKeyData keys[3];
+ SysScanDesc scan;
+ HeapTuple oldtup;
+ int nkeys = 2;
+
+ /*
+ * right now, we have obviously nothing to do on shared database
+ * object deletion
+ */
+ if (IsSharedRelation(object->classId))
+ return;
+
+ ScanKeyInit(&keys[0],
+ Anum_pg_seclabel_reloid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->classId));
+ ScanKeyInit(&keys[1],
+ Anum_pg_seclabel_objoid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+ if (object->objectSubId != 0)
+ {
+ ScanKeyInit(&keys[2],
+ Anum_pg_seclabel_subid,
+ BTEqualStrategyNumber, F_INT4EQ,
+ Int32GetDatum(object->objectSubId));
+ nkeys = 3;
+ }
+
+ pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
+
+ scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
+ SnapshotNow, nkeys, keys);
+ while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
+ {
+ simple_heap_delete(pg_seclabel, &oldtup->t_self);
+ }
+ systable_endscan(scan);
+
+ heap_close(pg_seclabel, RowExclusiveLock);
+ }
+
+ /*
+ * check_relation_relabel
+ *
+ * It checks whether the user is allowed to relabel this relation
+ */
+ static void
+ check_relation_relabel(int objtype, Relation relation)
+ {
+ /*
+ * check object ownership
+ */
+ if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+ RelationGetRelationName(relation));
+
+ /*
+ * next, verify that the relation type matches the intent
+ */
+ switch (objtype)
+ {
+ case OBJECT_TABLE:
+ case OBJECT_COLUMN:
+ if (relation->rd_rel->relkind != RELKIND_RELATION)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a table",
+ RelationGetRelationName(relation))));
+ break;
+
+ case OBJECT_SEQUENCE:
+ if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a sequence",
+ RelationGetRelationName(relation))));
+ break;
+
+ case OBJECT_VIEW:
+ if (relation->rd_rel->relkind != RELKIND_VIEW)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a view",
+ RelationGetRelationName(relation))));
+ break;
+ }
+ }
+
+ /*
+ * Registration of an external security provider hook
+ */
+ static List *esp_relabel_hook_list = NIL;
+
+ typedef struct
+ {
+ const char *tag;
+ check_object_relabel_type hook;
+ } esp_relabel_hook_entry;
+
+ void
+ register_object_relabel_hook(const char *tag, check_object_relabel_type hook)
+ {
+ esp_relabel_hook_entry *entry;
+ MemoryContext oldcxt;
+
+ oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+ entry = palloc(sizeof(esp_relabel_hook_entry));
+ entry->tag = pstrdup(tag);
+ entry->hook = hook;
+
+ esp_relabel_hook_list = lappend(esp_relabel_hook_list, entry);
+
+ MemoryContextSwitchTo(oldcxt);
+ }
+
+ /*
+ * ExecSecLabelStmt
+ *
+ * SECURITY LABEL [FOR ] ON IS
+ */
+ void
+ ExecSecLabelStmt(SecLabelStmt *stmt)
+ {
+ esp_relabel_hook_entry *entry;
+ ObjectAddress address;
+ Relation relation;
+ ListCell *cell;
+ const char *tag = NULL;
+
+ /*
+ * SECURITY LABEL statement needs one label based security feature
+ * being available at least.
+ */
+ if (list_length(esp_relabel_hook_list) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("No label based security is available now")));
+
+ /*
+ * Determine what ESP needs to own the supplied label
+ */
+ if (!stmt->tag)
+ {
+ /*
+ * User can omit FOR clause, only when one ESP is
+ * installed, because it is obvious what ESP needs to own the
+ * supplied security label.
+ * But we prohibit to omit it when multiple ESPs are installed.
+ */
+ if (list_length(esp_relabel_hook_list) > 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("No FOR clause in spite of multiple "
+ "label based security features")));
+ entry = linitial(esp_relabel_hook_list);
+ }
+ else
+ {
+ /*
+ * If user explicitly specified a security provider,
+ * it has to be installed of course.
+ */
+ foreach (cell, esp_relabel_hook_list)
+ {
+ entry = lfirst(cell);
+
+ if (strcmp(stmt->tag, entry->tag) == 0)
+ goto found;
+ }
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("No label based security feature for \"%s\"",
+ stmt->tag)));
+ }
+ found:
+ Assert(entry != NULL);
+ tag = entry->tag;
+
+ /*
+ * Translate the parser representation which identifies this object
+ * into 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 DROP operations.
+ */
+ 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:
+ case OBJECT_COLUMN:
+ check_relation_relabel(stmt->objtype, relation);
+ break;
+
+ default:
+ elog(ERROR, "unrecognized object type: %d",
+ (int)stmt->objtype);
+ }
+
+ /*
+ * Privilege and validation checks by external security provider
+ */
+ foreach (cell, esp_relabel_hook_list)
+ {
+ entry = lfirst(cell);
+
+ Assert(entry->hook);
+ /*
+ * If the supplied FOR clause is not matched with
+ * this entry, we call the security hook without new security
+ * label. The ESP shall check the privilege to update one of
+ * properties of the supecified database object.
+ */
+ if (strcmp(tag, entry->tag) == 0)
+ (*entry->hook)(&address, stmt->seclabel);
+ else
+ (*entry->hook)(&address, NULL);
+ }
+
+ /*
+ * Do actual relabeling.
+ */
+ SetSecurityLabel(&address, tag, stmt->seclabel);
+
+ /*
+ * 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);
+ }
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 2607,2612 **** _copyCommentStmt(CommentStmt *from)
--- 2607,2626 ----
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(tag);
+ COPY_STRING_FIELD(seclabel);
+
+ return newnode;
+ }
+
static FetchStmt *
_copyFetchStmt(FetchStmt *from)
{
***************
*** 3958,3963 **** copyObject(void *from)
--- 3972,3980 ----
case T_CommentStmt:
retval = _copyCommentStmt(from);
break;
+ case T_SecLabelStmt:
+ retval = _copySecLabelStmt(from);
+ break;
case T_FetchStmt:
retval = _copyFetchStmt(from);
break;
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 1164,1169 **** _equalCommentStmt(CommentStmt *a, CommentStmt *b)
--- 1164,1181 ----
}
static bool
+ _equalSecLabelStmt(SecLabelStmt *a, SecLabelStmt *b)
+ {
+ COMPARE_SCALAR_FIELD(objtype);
+ COMPARE_NODE_FIELD(objname);
+ COMPARE_NODE_FIELD(objargs);
+ COMPARE_STRING_FIELD(tag);
+ COMPARE_STRING_FIELD(seclabel);
+
+ return true;
+ }
+
+ static bool
_equalFetchStmt(FetchStmt *a, FetchStmt *b)
{
COMPARE_SCALAR_FIELD(direction);
***************
*** 2624,2629 **** equal(void *a, void *b)
--- 2636,2644 ----
case T_CommentStmt:
retval = _equalCommentStmt(a, b);
break;
+ case T_SecLabelStmt:
+ retval = _equalSecLabelStmt(a, b);
+ break;
case T_FetchStmt:
retval = _equalFetchStmt(a, b);
break;
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 204,210 **** static TypeName *TableFuncTypeName(List *columns);
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt
RuleActionStmt RuleActionStmtOrEmpty RuleStmt
! SelectStmt TransactionStmt TruncateStmt
UnlistenStmt UpdateStmt VacuumStmt
VariableResetStmt VariableSetStmt VariableShowStmt
ViewStmt CheckPointStmt CreateConversionStmt
--- 204,210 ----
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt
RuleActionStmt RuleActionStmtOrEmpty RuleStmt
! SecLabelStmt SelectStmt TransactionStmt TruncateStmt
UnlistenStmt UpdateStmt VacuumStmt
VariableResetStmt VariableSetStmt VariableShowStmt
ViewStmt CheckPointStmt CreateConversionStmt
***************
*** 422,427 **** static TypeName *TableFuncTypeName(List *columns);
--- 422,429 ----
%type OptTableSpace OptConsTableSpace OptTableSpaceOwner
%type opt_check_option
+ %type label_item opt_esp
+
%type xml_attribute_el
%type xml_attribute_list xml_attributes
%type xml_root_version opt_xml_root_standalone
***************
*** 499,505 **** static TypeName *TableFuncTypeName(List *columns);
KEY
! LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
LOCATION LOCK_P LOGIN_P
--- 501,507 ----
KEY
! LABEL LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
LOCATION LOCK_P LOGIN_P
***************
*** 737,742 **** stmt :
--- 739,745 ----
| RevokeStmt
| RevokeRoleStmt
| RuleStmt
+ | SecLabelStmt
| SelectStmt
| TransactionStmt
| TruncateStmt
***************
*** 4327,4332 **** comment_text:
--- 4330,4390 ----
| NULL_P { $$ = NULL; }
;
+
+ /*****************************************************************************
+ *
+ * ALTER THING name SECURITY LABEL TO label
+ *
+ *****************************************************************************/
+
+ SecLabelStmt: SECURITY LABEL opt_esp ON TABLE any_name IS label_item
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+
+ n->objtype = OBJECT_TABLE;
+ n->objname = $6;
+ n->tag = $3;
+ n->seclabel = $8;
+ $$ = (Node *)n;
+ }
+ | SECURITY LABEL opt_esp ON COLUMN any_name IS label_item
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+
+ n->objtype = OBJECT_COLUMN;
+ n->objname = $6;
+ n->tag = $3;
+ n->seclabel = $8;
+ $$ = (Node *)n;
+ }
+ | SECURITY LABEL opt_esp ON SEQUENCE any_name IS label_item
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+
+ n->objtype = OBJECT_SEQUENCE;
+ n->objname = $6;
+ n->tag = $3;
+ n->seclabel = $8;
+ $$ = (Node *)n;
+ }
+ | SECURITY LABEL opt_esp ON VIEW any_name IS label_item
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+
+ n->objtype = OBJECT_VIEW;
+ n->objname = $6;
+ n->tag = $3;
+ n->seclabel = $8;
+ $$ = (Node *)n;
+ }
+ ;
+
+ label_item: Sconst { $$ = $1; }
+
+ opt_esp: FOR Sconst { $$ = $2; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
/*****************************************************************************
*
* QUERY:
***************
*** 10993,10998 **** unreserved_keyword:
--- 11051,11057 ----
| INVOKER
| ISOLATION
| KEY
+ | LABEL
| LANGUAGE
| LARGE_P
| LAST_P
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 218,223 **** check_xact_readonly(Node *parsetree)
--- 218,224 ----
case T_AlterUserMappingStmt:
case T_DropUserMappingStmt:
case T_AlterTableSpaceOptionsStmt:
+ case T_SecLabelStmt:
PreventCommandIfReadOnly(CreateCommandTag(parsetree));
break;
default:
***************
*** 663,668 **** standard_ProcessUtility(Node *parsetree,
--- 664,673 ----
CommentObject((CommentStmt *) parsetree);
break;
+ case T_SecLabelStmt:
+ ExecSecLabelStmt((SecLabelStmt *) parsetree);
+ break;
+
case T_CopyStmt:
{
uint64 processed;
***************
*** 1592,1597 **** CreateCommandTag(Node *parsetree)
--- 1597,1606 ----
tag = "COMMENT";
break;
+ case T_SecLabelStmt:
+ tag = "SECURITY LABEL";
+ break;
+
case T_CopyStmt:
tag = "COPY";
break;
***************
*** 2314,2319 **** GetCommandLogLevel(Node *parsetree)
--- 2323,2332 ----
lev = LOGSTMT_DDL;
break;
+ case T_SecLabelStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_CopyStmt:
if (((CopyStmt *) parsetree)->is_from)
lev = LOGSTMT_MOD;
*** a/src/bin/pg_dump/pg_backup.h
--- b/src/bin/pg_dump/pg_backup.h
***************
*** 103,108 **** typedef struct _restoreOptions
--- 103,109 ----
* restore */
int use_setsessauth;/* Use SET SESSION AUTHORIZATION commands
* instead of OWNER TO */
+ int skip_seclabel; /* Skip security label entries */
char *superuser; /* Username to use as superuser */
char *use_role; /* Issue SET ROLE to this */
int dataOnly;
*** a/src/bin/pg_dump/pg_backup_archiver.c
--- b/src/bin/pg_dump/pg_backup_archiver.c
***************
*** 2275,2280 **** _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
--- 2275,2284 ----
if ((!include_acls || ropt->aclsSkip) && _tocEntryIsACL(te))
return 0;
+ /* If it's security labels, maybe ignore it */
+ if (ropt->skip_seclabel && strcmp(te->desc, "LABEL") == 0)
+ return 0;
+
/* Ignore DATABASE entry unless we should create it */
if (!ropt->createDB && strcmp(te->desc, "DATABASE") == 0)
return 0;
***************
*** 2341,2346 **** _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
--- 2345,2352 ----
(strcmp(te->desc, "ACL") == 0 &&
strncmp(te->tag, "LARGE OBJECT ", 13) == 0) ||
(strcmp(te->desc, "COMMENT") == 0 &&
+ strncmp(te->tag, "LARGE OBJECT ", 13) == 0) ||
+ (strcmp(te->desc, "LABEL") == 0 &&
strncmp(te->tag, "LARGE OBJECT ", 13) == 0))
res = res & REQ_DATA;
else
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 125,130 **** static int binary_upgrade = 0;
--- 125,131 ----
static int disable_dollar_quoting = 0;
static int dump_inserts = 0;
static int column_inserts = 0;
+ static int security_label = 0;
static void help(const char *progname);
***************
*** 183,188 **** static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
--- 184,194 ----
const char *tag, const char *nspname, const char *owner,
const char *acls);
+ static void dumpSecLabel(Archive *fout,
+ CatalogId objCatId, DumpId objDumpId,
+ const char *type, const char *target,
+ const char *nspname, const char *owner);
+
static void getDependencies(void);
static void getDomainConstraints(TypeInfo *tyinfo);
static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
***************
*** 300,305 **** main(int argc, char **argv)
--- 306,312 ----
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
{"role", required_argument, NULL, 3},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
+ {"security-label", no_argument, &security_label, 1},
{NULL, 0, NULL, 0}
};
***************
*** 448,453 **** main(int argc, char **argv)
--- 455,462 ----
outputNoTablespaces = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
+ else if (strcmp(optarg, "security-label") == 0)
+ security_label = 1;
else
{
fprintf(stderr,
***************
*** 643,648 **** main(int argc, char **argv)
--- 652,666 ----
do_sql_command(g_conn, "SET quote_all_identifiers = true");
/*
+ * Disables security label support if server version < v9.1.x
+ */
+ if (security_label && g_fout->remoteVersion < 90100)
+ {
+ write_msg(NULL, "Server does not support security labels\n");
+ security_label = 0;
+ }
+
+ /*
* Start serializable transaction to dump consistent data.
*/
do_sql_command(g_conn, "BEGIN");
***************
*** 839,844 **** help(const char *progname)
--- 857,863 ----
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
+ printf(_(" --security-label also dump security labels\n"));
printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n"));
***************
*** 10435,10440 **** dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
--- 10454,10564 ----
}
/*
+ * dumpSecLabel
+ *
+ * It dumps 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 catalogId which is lookup key for pg_seclabel, and dumpId
+ * for the object.
+ * If a matching pg_seclabel entry is found, it is dumped.
+ */
+ static void
+ dumpSecLabel(Archive *fout, CatalogId objCatId, DumpId objDumpId,
+ const char *type, const char *target,
+ const char *nspname, const char *owner)
+ {
+ PGresult *res;
+ PQExpBuffer lquery;
+ PQExpBuffer cquery;
+ PQExpBuffer tgbuf;
+ int i_attname;
+ int i_tag;
+ int i_label;
+ int i, ntups;
+
+ /* do nothing, if security label dump is not enabled */
+ if (!security_label)
+ return;
+
+ /* --data-only skips security labels *except* large object */
+ if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
+ return;
+
+ /*
+ * Fetch security labels associated with the object
+ */
+ lquery = createPQExpBuffer();
+ cquery = createPQExpBuffer();
+ tgbuf = createPQExpBuffer();
+
+ appendPQExpBuffer(lquery,
+ "SELECT a.attname, s.tag, s.label"
+ " FROM pg_catalog.pg_seclabel s"
+ " LEFT OUTER JOIN"
+ " pg_catalog.pg_attribute a"
+ " ON s.objoid = a.attrelid AND"
+ " s.subid = a.attnum"
+ " WHERE reloid = %u AND objoid = %u",
+ objCatId.tableoid, objCatId.oid);
+
+ res = PQexec(g_conn, lquery->data);
+ check_sql_result(res, g_conn, lquery->data, PGRES_TUPLES_OK);
+
+ i_attname = PQfnumber(res, "attname");
+ i_tag = PQfnumber(res, "tag");
+ i_label = PQfnumber(res, "label");
+
+ ntups = PQntuples(res);
+
+ for (i = 0; i < ntups; i++)
+ {
+ if (strcmp(type, "TABLE") == 0 &&
+ !PQgetisnull(res, i, i_attname))
+ {
+ appendPQExpBuffer(cquery,
+ "SECURITY LABEL FOR '%s'"
+ " ON COLUMN %s.%s IS '%s';\n",
+ PQgetvalue(res, i, i_tag),
+ target,
+ fmtId(PQgetvalue(res, i, i_attname)),
+ PQgetvalue(res, i, i_label));
+ continue;
+ }
+
+ /*
+ * a.attname can be available only when type = "TABLE",
+ * so we expect it will be always NULL. Elsewhere, we assume
+ * it as a data corruption, so simply ignored.
+ */
+ if (!PQgetisnull(res, i, i_attname))
+ continue;
+
+ appendPQExpBuffer(cquery,
+ "SECURITY LABEL FOR '%s' ON %s %s IS '%s';\n",
+ PQgetvalue(res, i, i_tag),
+ type, target,
+ PQgetvalue(res, i, i_label));
+ }
+ PQclear(res);
+
+ if (cquery->len > 0)
+ {
+ appendPQExpBuffer(tgbuf, "%s %s", type, target);
+ ArchiveEntry(fout, nilCatalogId, createDumpId(),
+ tgbuf->data, nspname, NULL, owner,
+ false, "LABEL", SECTION_NONE,
+ cquery->data, "", NULL,
+ &(objDumpId), 1,
+ NULL, NULL);
+ }
+ destroyPQExpBuffer(lquery);
+ destroyPQExpBuffer(cquery);
+ destroyPQExpBuffer(tgbuf);
+ }
+
+ /*
* dumpTable
* write out to fout the declarations (not data) of a user-defined table
*/
***************
*** 10458,10463 **** dumpTable(Archive *fout, TableInfo *tbinfo)
--- 10582,10594 ----
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
tbinfo->relacl);
+ /* Handle the security label here */
+ dumpSecLabel(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+ (tbinfo->relkind == RELKIND_SEQUENCE ? "SEQUENCE" :
+ (tbinfo->relkind == RELKIND_VIEW ? "VIEW" : "TABLE")),
+ namecopy,
+ tbinfo->dobj.namespace->dobj.name,
+ tbinfo->rolname);
/*
* Handle column ACLs, if any. Note: we pull these with a separate
* query rather than trying to fetch them during getTableAttrs, so
*** a/src/bin/pg_dump/pg_dumpall.c
--- b/src/bin/pg_dump/pg_dumpall.c
***************
*** 69,74 **** static int disable_triggers = 0;
--- 69,75 ----
static int inserts = 0;
static int no_tablespaces = 0;
static int use_setsessauth = 0;
+ static int security_label = 0;
static int server_version;
static FILE *OPF;
***************
*** 133,138 **** main(int argc, char *argv[])
--- 134,140 ----
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
{"role", required_argument, NULL, 3},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
+ {"security-label", no_argument, &security_label, 1},
{NULL, 0, NULL, 0}
};
***************
*** 286,291 **** main(int argc, char *argv[])
--- 288,295 ----
no_tablespaces = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
+ else if (strcmp(optarg, "security-label") == 0)
+ security_label = 1;
else
{
fprintf(stderr,
***************
*** 371,376 **** main(int argc, char *argv[])
--- 375,382 ----
appendPQExpBuffer(pgdumpopts, " --quote-all-identifiers");
if (use_setsessauth)
appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
+ if (security_label)
+ appendPQExpBuffer(pgdumpopts, " --security-label");
/*
* If there was a database specified on the command line, use that,
***************
*** 567,572 **** help(void)
--- 573,579 ----
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
+ printf(_(" --security-label also dump security labels\n"));
printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n"));
*** a/src/bin/pg_dump/pg_restore.c
--- b/src/bin/pg_dump/pg_restore.c
***************
*** 76,81 **** main(int argc, char **argv)
--- 76,82 ----
static int no_data_for_failed_tables = 0;
static int outputNoTablespaces = 0;
static int use_setsessauth = 0;
+ static int skip_seclabel = 0;
struct option cmdopts[] = {
{"clean", 0, NULL, 'c'},
***************
*** 116,121 **** main(int argc, char **argv)
--- 117,123 ----
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
{"role", required_argument, NULL, 2},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
+ {"no-security-label", no_argument, &skip_seclabel, 1},
{NULL, 0, NULL, 0}
};
***************
*** 262,267 **** main(int argc, char **argv)
--- 264,271 ----
outputNoTablespaces = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
+ else if (strcmp(optarg, "no-security-label") == 0)
+ skip_seclabel = 1;
else
{
fprintf(stderr,
***************
*** 337,342 **** main(int argc, char **argv)
--- 341,347 ----
opts->noDataForFailedTables = no_data_for_failed_tables;
opts->noTablespace = outputNoTablespaces;
opts->use_setsessauth = use_setsessauth;
+ opts->skip_seclabel = skip_seclabel;
if (opts->formatName)
{
***************
*** 442,447 **** usage(const char *progname)
--- 447,453 ----
" do not restore data of tables that could not be\n"
" created\n"));
printf(_(" --no-tablespaces do not restore tablespace assignments\n"));
+ printf(_(" --no-security-label do not restore security labels\n"));
printf(_(" --role=ROLENAME do SET ROLE before restore\n"));
printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n"
*** a/src/include/catalog/indexing.h
--- b/src/include/catalog/indexing.h
***************
*** 281,286 **** DECLARE_UNIQUE_INDEX(pg_default_acl_oid_index, 828, on pg_default_acl using btre
--- 281,289 ----
DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops));
#define DbRoleSettingDatidRolidIndexId 2965
+ DECLARE_UNIQUE_INDEX(pg_seclabel_object_index, 3038, on pg_seclabel using btree(reloid oid_ops, objoid oid_ops, subid int4_ops, tag text_ops));
+ #define SecLabelObjectIndexId 3038
+
/* last step of initialization script: build the indexes declared above */
BUILD_INDICES
*** /dev/null
--- b/src/include/catalog/pg_seclabel.h
***************
*** 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 reloid; /* OID of table containing the object */
+ Oid objoid; /* OID of the object itself */
+ int4 subid; /* column number, or 0 if not used */
+ text tag; /* identifier of external security 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_reloid 1
+ #define Anum_pg_seclabel_objoid 2
+ #define Anum_pg_seclabel_subid 3
+ #define Anum_pg_seclabel_tag 4
+ #define Anum_pg_seclabel_label 5
+
+ #endif /* PG_SECLABEL_H */
*** a/src/include/catalog/toasting.h
--- b/src/include/catalog/toasting.h
***************
*** 45,50 **** DECLARE_TOAST(pg_constraint, 2832, 2833);
--- 45,51 ----
DECLARE_TOAST(pg_description, 2834, 2835);
DECLARE_TOAST(pg_proc, 2836, 2837);
DECLARE_TOAST(pg_rewrite, 2838, 2839);
+ DECLARE_TOAST(pg_seclabel, 3039, 3040);
DECLARE_TOAST(pg_statistic, 2840, 2841);
DECLARE_TOAST(pg_trigger, 2336, 2337);
*** /dev/null
--- b/src/include/commands/seclabel.h
***************
*** 0 ****
--- 1,36 ----
+ /*
+ * 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 *tag);
+ extern void SetSecurityLabel(const ObjectAddress *object,
+ const char *tag,
+ const char *seclabel);
+ 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_object_relabel_hook(const char *tag,
+ check_object_relabel_type hook);
+
+ #endif /* SECLABEL_H */
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
***************
*** 347,352 **** typedef enum NodeTag
--- 347,353 ----
T_AlterUserMappingStmt,
T_DropUserMappingStmt,
T_AlterTableSpaceOptionsStmt,
+ T_SecLabelStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 1850,1855 **** typedef struct CommentStmt
--- 1850,1869 ----
} CommentStmt;
/* ----------------------
+ * SECURITY LABEL Statemetn
+ * ----------------------
+ */
+ 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 *tag; /* Identifier of ESP, if specified */
+ char *seclabel; /* New security label to be assigned */
+ } SecLabelStmt;
+
+ /* ----------------------
* Declare Cursor Statement
*
* Note: the "query" field of DeclareCursorStmt is only used in the raw grammar
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
***************
*** 208,213 **** PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
--- 208,214 ----
PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
+ PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD)
PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
*** a/src/include/utils/errcodes.h
--- b/src/include/utils/errcodes.h
***************
*** 260,265 ****
--- 260,266 ----
#define ERRCODE_DATATYPE_MISMATCH MAKE_SQLSTATE('4','2', '8','0','4')
#define ERRCODE_INDETERMINATE_DATATYPE MAKE_SQLSTATE('4','2', 'P','1','8')
#define ERRCODE_WRONG_OBJECT_TYPE MAKE_SQLSTATE('4','2', '8','0','9')
+ #define ERRCODE_INVALID_SECLABEL MAKE_SQLSTATE('4','2', 'P','2','1')
/*
* Note: for ERRCODE purposes, we divide namable objects into these categories:
* databases, schemas, prepared statements, cursors, tables, columns,
*** a/src/test/regress/expected/sanity_check.out
--- b/src/test/regress/expected/sanity_check.out
***************
*** 114,119 **** SELECT relname, relhasindex
--- 114,120 ----
pg_pltemplate | t
pg_proc | t
pg_rewrite | t
+ pg_seclabel | t
pg_shdepend | t
pg_shdescription | t
pg_statistic | t
***************
*** 153,159 **** SELECT relname, relhasindex
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (142 rows)
--
-- another sanity check: every system catalog that has OIDs should have
--- 154,160 ----
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (143 rows)
--
-- another sanity check: every system catalog that has OIDs should have