1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

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:
Robert Haas
2010-09-27 20:55:27 -04:00
parent 2ce003973d
commit 4d355a8336
42 changed files with 1815 additions and 26 deletions

View File

@ -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_parser.h pg_ts_template.h \
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
pg_default_acl.h \
pg_default_acl.h pg_seclabel.h \
toasting.h indexing.h \
)

View File

@ -57,6 +57,7 @@
#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"
@ -1004,10 +1005,12 @@ deleteOneObject(const ObjectAddress *object, Relation depRel)
doDeletion(object);
/*
* Delete any comments associated with this object. (This is a convenient
* place to do it instead of having every object type know to do it.)
* Delete any comments or security labels associated with this object.
* (This is a convenient place to do these things, rather than having every
* object type know to do it.)
*/
DeleteComments(object->objectId, object->classId, object->objectSubId);
DeleteSecurityLabel(object);
/*
* CommandCounterIncrement here to ensure that preceding changes are all

View File

@ -160,6 +160,114 @@ CREATE VIEW pg_prepared_xacts AS
CREATE VIEW pg_prepared_statements AS
SELECT * FROM pg_prepared_statement() AS P;
CREATE VIEW pg_seclabels AS
SELECT
l.objoid, l.classoid, l.objsubid,
CASE WHEN rel.relkind = 'r' THEN 'table'::text
WHEN rel.relkind = 'v' THEN 'view'::text
WHEN rel.relkind = 'S' THEN 'sequence'::text END AS objtype,
rel.relnamespace AS objnamespace,
CASE WHEN pg_table_is_visible(rel.oid)
THEN quote_ident(rel.relname)
ELSE quote_ident(nsp.nspname) || '.' || quote_ident(rel.relname)
END AS objname,
l.provider, l.label
FROM
pg_seclabel l
JOIN pg_class rel ON l.classoid = rel.tableoid AND l.objoid = rel.oid
JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
WHERE
l.objsubid = 0
UNION ALL
SELECT
l.objoid, l.classoid, l.objsubid,
'column'::text AS objtype,
rel.relnamespace AS objnamespace,
CASE WHEN pg_table_is_visible(rel.oid)
THEN quote_ident(rel.relname)
ELSE quote_ident(nsp.nspname) || '.' || quote_ident(rel.relname)
END || '.' || att.attname AS objname,
l.provider, l.label
FROM
pg_seclabel l
JOIN pg_class rel ON l.classoid = rel.tableoid AND l.objoid = rel.oid
JOIN pg_attribute att
ON rel.oid = att.attrelid AND l.objsubid = att.attnum
JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
WHERE
l.objsubid != 0
UNION ALL
SELECT
l.objoid, l.classoid, l.objsubid,
CASE WHEN pro.proisagg = true THEN 'aggregate'::text
WHEN pro.proisagg = false THEN 'function'::text
END AS objtype,
pro.pronamespace AS objnamespace,
CASE WHEN pg_function_is_visible(pro.oid)
THEN quote_ident(pro.proname)
ELSE quote_ident(nsp.nspname) || '.' || quote_ident(pro.proname)
END || '(' || pg_catalog.pg_get_function_arguments(pro.oid) || ')' AS objname,
l.provider, l.label
FROM
pg_seclabel l
JOIN pg_proc pro ON l.classoid = pro.tableoid AND l.objoid = pro.oid
JOIN pg_namespace nsp ON pro.pronamespace = nsp.oid
WHERE
l.objsubid = 0
UNION ALL
SELECT
l.objoid, l.classoid, l.objsubid,
CASE WHEN typ.typtype = 'd' THEN 'domain'::text
ELSE 'type'::text END AS objtype,
typ.typnamespace AS objnamespace,
CASE WHEN pg_type_is_visible(typ.oid)
THEN quote_ident(typ.typname)
ELSE quote_ident(nsp.nspname) || '.' || quote_ident(typ.typname)
END AS objname,
l.provider, l.label
FROM
pg_seclabel l
JOIN pg_type typ ON l.classoid = typ.tableoid AND l.objoid = typ.oid
JOIN pg_namespace nsp ON typ.typnamespace = nsp.oid
WHERE
l.objsubid = 0
UNION ALL
SELECT
l.objoid, l.classoid, l.objsubid,
'large object'::text AS objtype,
NULL::oid AS objnamespace,
l.objoid::text AS objname,
l.provider, l.label
FROM
pg_seclabel l
JOIN pg_largeobject_metadata lom ON l.objoid = lom.oid
WHERE
l.classoid = 'pg_catalog.pg_largeobject'::regclass AND l.objsubid = 0
UNION ALL
SELECT
l.objoid, l.classoid, l.objsubid,
'language'::text AS objtype,
NULL::oid AS objnamespace,
quote_ident(lan.lanname) AS objname,
l.provider, l.label
FROM
pg_seclabel l
JOIN pg_language lan ON l.classoid = lan.tableoid AND l.objoid = lan.oid
WHERE
l.objsubid = 0
UNION ALL
SELECT
l.objoid, l.classoid, l.objsubid,
'schema'::text AS objtype,
nsp.oid AS objnamespace,
quote_ident(nsp.nspname) AS objname,
l.provider, l.label
FROM
pg_seclabel l
JOIN pg_namespace nsp ON l.classoid = nsp.tableoid AND l.objoid = nsp.oid
WHERE
l.objsubid = 0;
CREATE VIEW pg_settings AS
SELECT * FROM pg_show_all_settings() AS A;

View File

@ -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 \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \
schemacmds.o sequence.o tablecmds.o tablespace.o trigger.o \
schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
variable.o view.o

View 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);
}

View File

@ -2607,6 +2607,20 @@ _copyCommentStmt(CommentStmt *from)
return newnode;
}
static SecLabelStmt *
_copySecLabelStmt(SecLabelStmt *from)
{
SecLabelStmt *newnode = makeNode(SecLabelStmt);
COPY_SCALAR_FIELD(objtype);
COPY_NODE_FIELD(objname);
COPY_NODE_FIELD(objargs);
COPY_STRING_FIELD(provider);
COPY_STRING_FIELD(label);
return newnode;
}
static FetchStmt *
_copyFetchStmt(FetchStmt *from)
{
@ -3958,6 +3972,9 @@ copyObject(void *from)
case T_CommentStmt:
retval = _copyCommentStmt(from);
break;
case T_SecLabelStmt:
retval = _copySecLabelStmt(from);
break;
case T_FetchStmt:
retval = _copyFetchStmt(from);
break;

View File

@ -1163,6 +1163,18 @@ _equalCommentStmt(CommentStmt *a, CommentStmt *b)
return true;
}
static bool
_equalSecLabelStmt(SecLabelStmt *a, SecLabelStmt *b)
{
COMPARE_SCALAR_FIELD(objtype);
COMPARE_NODE_FIELD(objname);
COMPARE_NODE_FIELD(objargs);
COMPARE_STRING_FIELD(provider);
COMPARE_STRING_FIELD(label);
return true;
}
static bool
_equalFetchStmt(FetchStmt *a, FetchStmt *b)
{
@ -2624,6 +2636,9 @@ equal(void *a, void *b)
case T_CommentStmt:
retval = _equalCommentStmt(a, b);
break;
case T_SecLabelStmt:
retval = _equalSecLabelStmt(a, b);
break;
case T_FetchStmt:
retval = _equalFetchStmt(a, b);
break;

View File

@ -205,7 +205,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt
RuleActionStmt RuleActionStmtOrEmpty RuleStmt
SelectStmt TransactionStmt TruncateStmt
SecLabelStmt SelectStmt TransactionStmt TruncateStmt
UnlistenStmt UpdateStmt VacuumStmt
VariableResetStmt VariableSetStmt VariableShowStmt
ViewStmt CheckPointStmt CreateConversionStmt
@ -335,7 +335,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
%type <boolean> copy_from
%type <ival> opt_column event cursor_options opt_hold opt_set_data
%type <objtype> reindex_type drop_type comment_type
%type <objtype> reindex_type drop_type comment_type security_label_type
%type <node> fetch_args limit_clause select_limit_value
offset_clause select_offset_value
@ -423,6 +423,8 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
%type <list> opt_check_option
%type <str> opt_provider security_label
%type <target> xml_attribute_el
%type <list> xml_attribute_list xml_attributes
%type <node> xml_root_version opt_xml_root_standalone
@ -500,7 +502,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
KEY
LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
LABEL LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
LOCATION LOCK_P LOGIN_P
@ -739,6 +741,7 @@ stmt :
| RevokeStmt
| RevokeRoleStmt
| RuleStmt
| SecLabelStmt
| SelectStmt
| TransactionStmt
| TruncateStmt
@ -4368,6 +4371,92 @@ comment_text:
| 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:
@ -11049,6 +11138,7 @@ unreserved_keyword:
| INVOKER
| ISOLATION
| KEY
| LABEL
| LANGUAGE
| LARGE_P
| LAST_P

View File

@ -37,6 +37,7 @@
#include "commands/prepare.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
#include "commands/seclabel.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
@ -218,6 +219,7 @@ check_xact_readonly(Node *parsetree)
case T_AlterUserMappingStmt:
case T_DropUserMappingStmt:
case T_AlterTableSpaceOptionsStmt:
case T_SecLabelStmt:
PreventCommandIfReadOnly(CreateCommandTag(parsetree));
break;
default:
@ -663,6 +665,10 @@ standard_ProcessUtility(Node *parsetree,
CommentObject((CommentStmt *) parsetree);
break;
case T_SecLabelStmt:
ExecSecLabelStmt((SecLabelStmt *) parsetree);
break;
case T_CopyStmt:
{
uint64 processed;
@ -1592,6 +1598,10 @@ CreateCommandTag(Node *parsetree)
tag = "COMMENT";
break;
case T_SecLabelStmt:
tag = "SECURITY LABEL";
break;
case T_CopyStmt:
tag = "COPY";
break;
@ -2318,6 +2328,10 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL;
break;
case T_SecLabelStmt:
lev = LOGSTMT_DDL;
break;
case T_CopyStmt:
if (((CopyStmt *) parsetree)->is_from)
lev = LOGSTMT_MOD;

View File

@ -103,6 +103,7 @@ typedef struct _restoreOptions
* 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;

View File

@ -2275,6 +2275,10 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
if ((!include_acls || ropt->aclsSkip) && _tocEntryIsACL(te))
return 0;
/* If it's security labels, maybe ignore it */
if (ropt->skip_seclabel && strcmp(te->desc, "SECURITY LABEL") == 0)
return 0;
/* Ignore DATABASE entry unless we should create it */
if (!ropt->createDB && strcmp(te->desc, "DATABASE") == 0)
return 0;
@ -2341,6 +2345,8 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
(strcmp(te->desc, "ACL") == 0 &&
strncmp(te->tag, "LARGE OBJECT ", 13) == 0) ||
(strcmp(te->desc, "COMMENT") == 0 &&
strncmp(te->tag, "LARGE OBJECT ", 13) == 0) ||
(strcmp(te->desc, "SECURITY LABEL") == 0 &&
strncmp(te->tag, "LARGE OBJECT ", 13) == 0))
res = res & REQ_DATA;
else

View File

@ -70,6 +70,14 @@ typedef struct
int objsubid; /* subobject (table column #) */
} CommentItem;
typedef struct
{
const char *provider; /* label provider of this security label */
const char *label; /* security label for an object */
Oid classoid; /* object class (catalog OID) */
Oid objoid; /* object OID */
int objsubid; /* subobject (table column #) */
} SecLabelItem;
/* global decls */
bool g_verbose; /* User wants verbose narration of our
@ -125,6 +133,7 @@ static int binary_upgrade = 0;
static int disable_dollar_quoting = 0;
static int dump_inserts = 0;
static int column_inserts = 0;
static int no_security_label = 0;
static void help(const char *progname);
@ -141,6 +150,12 @@ static void dumpComment(Archive *fout, const char *target,
static int findComments(Archive *fout, Oid classoid, Oid objoid,
CommentItem **items);
static int collectComments(Archive *fout, CommentItem **items);
static void dumpSecLabel(Archive *fout, const char *target,
const char *namespace, const char *owner,
CatalogId catalogId, int subid, DumpId dumpId);
static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
SecLabelItem **items);
static int collectSecLabels(Archive *fout, SecLabelItem **items);
static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
static void dumpType(Archive *fout, TypeInfo *tyinfo);
@ -300,6 +315,7 @@ main(int argc, char **argv)
{"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
{"role", required_argument, NULL, 3},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{"no-security-label", no_argument, &no_security_label, 1},
{NULL, 0, NULL, 0}
};
@ -448,6 +464,8 @@ main(int argc, char **argv)
outputNoTablespaces = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
else if (strcmp(optarg, "no-security-label") == 0)
no_security_label = 1;
else
{
fprintf(stderr,
@ -642,6 +660,12 @@ main(int argc, char **argv)
if (quote_all_identifiers && g_fout->remoteVersion >= 90100)
do_sql_command(g_conn, "SET quote_all_identifiers = true");
/*
* Disables security label support if server version < v9.1.x
*/
if (!no_security_label && g_fout->remoteVersion < 90100)
no_security_label = 1;
/*
* Start serializable transaction to dump consistent data.
*/
@ -839,6 +863,7 @@ help(const char *progname)
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
printf(_(" --no-security-label do not dump security label assignments\n"));
printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n"));
@ -2058,6 +2083,11 @@ dumpBlob(Archive *AH, BlobInfo *binfo)
NULL, binfo->rolname,
binfo->dobj.catId, 0, binfo->dobj.dumpId);
/* Dump security label if any */
dumpSecLabel(AH, cquery->data,
NULL, binfo->rolname,
binfo->dobj.catId, 0, binfo->dobj.dumpId);
/* Dump ACL if any */
if (binfo->blobacl)
dumpACL(AH, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
@ -6569,12 +6599,15 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
NULL, NULL);
/* Dump Schema Comments */
/* Dump Schema Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "SCHEMA %s", qnspname);
dumpComment(fout, q->data,
NULL, nspinfo->rolname,
nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
dumpSecLabel(fout, q->data,
NULL, nspinfo->rolname,
nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
qnspname, NULL, nspinfo->dobj.name, NULL,
@ -6699,13 +6732,16 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
NULL, NULL);
/* Dump Type Comments */
/* Dump Type Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
dumpComment(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
dumpSecLabel(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
PQclear(res);
destroyPQExpBuffer(q);
@ -7075,13 +7111,16 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
NULL, NULL);
/* Dump Type Comments */
/* Dump Type Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
dumpComment(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
dumpSecLabel(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
PQclear(res);
destroyPQExpBuffer(q);
@ -7199,13 +7238,16 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
NULL, NULL);
/* Dump Domain Comments */
/* Dump Domain Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "DOMAIN %s", fmtId(tyinfo->dobj.name));
dumpComment(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
dumpSecLabel(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
@ -7299,13 +7341,16 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
NULL, NULL);
/* Dump Type Comments */
/* Dump Type Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
dumpComment(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
dumpSecLabel(fout, q->data,
tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
PQclear(res);
destroyPQExpBuffer(q);
@ -7623,12 +7668,15 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
plang->dobj.dependencies, plang->dobj.nDeps,
NULL, NULL);
/* Dump Proc Lang Comments */
/* Dump Proc Lang Comments and Security Labels */
resetPQExpBuffer(defqry);
appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
dumpComment(fout, defqry->data,
NULL, "",
plang->dobj.catId, 0, plang->dobj.dumpId);
dumpSecLabel(fout, defqry->data,
NULL, "",
plang->dobj.catId, 0, plang->dobj.dumpId);
if (plang->lanpltrusted)
dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
@ -8184,12 +8232,15 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
finfo->dobj.dependencies, finfo->dobj.nDeps,
NULL, NULL);
/* Dump Function Comments */
/* Dump Function Comments and Security Labels */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "FUNCTION %s", funcsig);
dumpComment(fout, q->data,
finfo->dobj.namespace->dobj.name, finfo->rolname,
finfo->dobj.catId, 0, finfo->dobj.dumpId);
dumpSecLabel(fout, q->data,
finfo->dobj.namespace->dobj.name, finfo->rolname,
finfo->dobj.catId, 0, finfo->dobj.dumpId);
dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
funcsig, NULL, funcsig_tag,
@ -9687,6 +9738,9 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
dumpComment(fout, q->data,
agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
dumpSecLabel(fout, q->data,
agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
/*
* Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
@ -10434,6 +10488,300 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
destroyPQExpBuffer(sql);
}
/*
* dumpSecLabel
*
* This routine is used to dump any security labels associated with the
* object handed to this routine. The routine takes a constant character
* string for the target part of the security-label command, plus
* the namespace and owner of the object (for labeling the ArchiveEntry),
* plus catalog ID and subid which are the lookup key for pg_seclabel,
* plus the dump ID for the object (for setting a dependency).
* If a matching pg_seclabel entry is found, it is dumped.
*
* Note: although this routine takes a dumpId for dependency purposes,
* that purpose is just to mark the dependency in the emitted dump file
* for possible future use by pg_restore. We do NOT use it for determining
* ordering of the label in the dump file, because this routine is called
* after dependency sorting occurs. This routine should be called just after
* calling ArchiveEntry() for the specified object.
*/
static void
dumpSecLabel(Archive *fout, const char *target,
const char *namespace, const char *owner,
CatalogId catalogId, int subid, DumpId dumpId)
{
SecLabelItem *labels;
int nlabels;
int i;
PQExpBuffer query;
/* do nothing, if --no-security-label is supplied */
if (no_security_label)
return;
/* Comments are schema not data ... except blob comments are data */
if (strncmp(target, "LARGE OBJECT ", 13) != 0)
{
if (dataOnly)
return;
}
else
{
if (schemaOnly)
return;
}
/* Search for security labels associated with catalogId, using table */
nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
query = createPQExpBuffer();
for (i = 0; i < nlabels; i++)
{
/*
* Ignore label entries for which the subid doesn't match.
*/
if (labels[i].objsubid != subid)
continue;
appendPQExpBuffer(query,
"SECURITY LABEL FOR %s ON %s IS ",
fmtId(labels[i].provider), target);
appendStringLiteralAH(query, labels[i].label, fout);
appendPQExpBuffer(query, ";\n");
}
if (query->len > 0)
{
ArchiveEntry(fout, nilCatalogId, createDumpId(),
target, namespace, NULL, owner,
false, "SECURITY LABEL", SECTION_NONE,
query->data, "", NULL,
&(dumpId), 1,
NULL, NULL);
}
destroyPQExpBuffer(query);
}
/*
* dumpTableSecLabel
*
* As above, but dump security label for both the specified table (or view)
* and its columns.
*/
static void
dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
{
SecLabelItem *labels;
int nlabels;
int i;
PQExpBuffer query;
PQExpBuffer target;
/* do nothing, if --no-security-label is supplied */
if (no_security_label)
return;
/* SecLabel are SCHEMA not data */
if (dataOnly)
return;
/* Search for comments associated with relation, using table */
nlabels = findSecLabels(fout,
tbinfo->dobj.catId.tableoid,
tbinfo->dobj.catId.oid,
&labels);
/* If comments exist, build SECURITY LABEL statements */
if (nlabels <= 0)
return;
query = createPQExpBuffer();
target = createPQExpBuffer();
for (i = 0; i < nlabels; i++)
{
const char *colname;
const char *provider = labels[i].provider;
const char *label = labels[i].label;
int objsubid = labels[i].objsubid;
resetPQExpBuffer(target);
if (objsubid == 0)
{
appendPQExpBuffer(target, "%s %s", reltypename,
fmtId(tbinfo->dobj.name));
}
else
{
colname = getAttrName(objsubid, tbinfo);
appendPQExpBuffer(target, "COLUMN %s.%s",
fmtId(tbinfo->dobj.name),
fmtId(colname));
}
appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
fmtId(provider), target->data);
appendStringLiteralAH(query, label, fout);
appendPQExpBuffer(query, ";\n");
}
if (query->len > 0)
{
resetPQExpBuffer(target);
appendPQExpBuffer(target, "%s %s", reltypename,
fmtId(tbinfo->dobj.name));
ArchiveEntry(fout, nilCatalogId, createDumpId(),
target->data,
tbinfo->dobj.namespace->dobj.name,
NULL, tbinfo->rolname,
false, "SECURITY LABEL", SECTION_NONE,
query->data, "", NULL,
&(tbinfo->dobj.dumpId), 1,
NULL, NULL);
}
destroyPQExpBuffer(query);
destroyPQExpBuffer(target);
}
/*
* findSecLabels
*
* Find the security label(s), if any, associated with the given object.
* All the objsubid values associated with the given classoid/objoid are
* found with one search.
*/
static int
findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
{
/* static storage for table of security labels */
static SecLabelItem *labels = NULL;
static int nlabels = -1;
SecLabelItem *middle = NULL;
SecLabelItem *low;
SecLabelItem *high;
int nmatch;
/* Get security labels if we didn't already */
if (nlabels < 0)
nlabels = collectSecLabels(fout, &labels);
/*
* Do binary search to find some item matching the object.
*/
low = &labels[0];
high = &labels[nlabels - 1];
while (low <= high)
{
middle = low + (high - low) / 2;
if (classoid < middle->classoid)
high = middle - 1;
else if (classoid > middle->classoid)
low = middle + 1;
else if (objoid < middle->objoid)
high = middle - 1;
else if (objoid > middle->objoid)
low = middle + 1;
else
break; /* found a match */
}
if (low > high) /* no matches */
{
*items = NULL;
return 0;
}
/*
* Now determine how many items match the object. The search loop
* invariant still holds: only items between low and high inclusive could
* match.
*/
nmatch = 1;
while (middle > low)
{
if (classoid != middle[-1].classoid ||
objoid != middle[-1].objoid)
break;
middle--;
nmatch++;
}
*items = middle;
middle += nmatch;
while (middle <= high)
{
if (classoid != middle->classoid ||
objoid != middle->objoid)
break;
middle++;
nmatch++;
}
return nmatch;
}
/*
* collectSecLabels
*
* Construct a table of all security labels available for database objects.
* It's much faster to pull them all at once.
*
* The table is sorted by classoid/objid/objsubid for speed in lookup.
*/
static int
collectSecLabels(Archive *fout, SecLabelItem **items)
{
PGresult *res;
PQExpBuffer query;
int i_label;
int i_provider;
int i_classoid;
int i_objoid;
int i_objsubid;
int ntups;
int i;
SecLabelItem *labels;
query = createPQExpBuffer();
appendPQExpBuffer(query,
"SELECT label, provider, classoid, objoid, objsubid "
"FROM pg_catalog.pg_seclabel "
"ORDER BY classoid, objoid, objsubid");
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
/* Construct lookup table containing OIDs in numeric form */
i_label = PQfnumber(res, "label");
i_provider = PQfnumber(res, "provider");
i_classoid = PQfnumber(res, "classoid");
i_objoid = PQfnumber(res, "objoid");
i_objsubid = PQfnumber(res, "objsubid");
ntups = PQntuples(res);
labels = (SecLabelItem *) malloc(ntups * sizeof(SecLabelItem));
for (i = 0; i < ntups; i++)
{
labels[i].label = PQgetvalue(res, i, i_label);
labels[i].provider = PQgetvalue(res, i, i_provider);
labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
}
/* Do NOT free the PGresult since we are keeping pointers into it */
destroyPQExpBuffer(query);
*items = labels;
return ntups;
}
/*
* dumpTable
* write out to fout the declarations (not data) of a user-defined table
@ -10950,6 +11298,9 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
/* Dump Table Comments */
dumpTableComment(fout, tbinfo, reltypename);
/* Dump Table Security Labels */
dumpTableSecLabel(fout, tbinfo, reltypename);
/* Dump comments on inlined table constraints */
for (j = 0; j < tbinfo->ncheck; j++)
{
@ -11663,12 +12014,15 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
}
}
/* Dump Sequence Comments */
/* Dump Sequence Comments and Security Labels */
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
dumpComment(fout, query->data,
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
dumpSecLabel(fout, query->data,
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
}
if (!schemaOnly)

View File

@ -69,6 +69,7 @@ static int disable_triggers = 0;
static int inserts = 0;
static int no_tablespaces = 0;
static int use_setsessauth = 0;
static int no_security_label = 0;
static int server_version;
static FILE *OPF;
@ -133,6 +134,7 @@ main(int argc, char *argv[])
{"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
{"role", required_argument, NULL, 3},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{"no-security-label", no_argument, &no_security_label, 1},
{NULL, 0, NULL, 0}
};
@ -286,6 +288,8 @@ main(int argc, char *argv[])
no_tablespaces = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
else if (strcmp(optarg, "no-security-label") == 0)
no_security_label = 1;
else
{
fprintf(stderr,
@ -371,6 +375,8 @@ main(int argc, char *argv[])
appendPQExpBuffer(pgdumpopts, " --quote-all-identifiers");
if (use_setsessauth)
appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
if (no_security_label)
appendPQExpBuffer(pgdumpopts, " --no-security-label");
/*
* If there was a database specified on the command line, use that,
@ -567,6 +573,7 @@ help(void)
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
printf(_(" --no-security-label do not dump security label assignments\n"));
printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n"));

View File

@ -76,6 +76,7 @@ main(int argc, char **argv)
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,6 +117,7 @@ main(int argc, char **argv)
{"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,6 +264,8 @@ main(int argc, char **argv)
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,6 +341,7 @@ main(int argc, char **argv)
opts->noDataForFailedTables = no_data_for_failed_tables;
opts->noTablespace = outputNoTablespaces;
opts->use_setsessauth = use_setsessauth;
opts->skip_seclabel = skip_seclabel;
if (opts->formatName)
{
@ -442,6 +447,7 @@ usage(const char *progname)
" 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"

View File

@ -631,8 +631,9 @@ psql_completion(char *text, int start, int end)
"DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
"GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
"REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
"SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TABLE", "TRUNCATE", "UNLISTEN",
"UPDATE", "VACUUM", "VALUES", "WITH", NULL
"SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
"TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
NULL
};
static const char *const backslash_commands[] = {
@ -2193,6 +2194,40 @@ psql_completion(char *text, int start, int end)
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
}
/* SECURITY LABEL */
else if (pg_strcasecmp(prev_wd, "SECURITY") == 0)
COMPLETE_WITH_CONST("LABEL");
else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 &&
pg_strcasecmp(prev_wd, "LABEL") == 0)
{
static const char *const list_SECURITY_LABEL_preposition[] =
{"ON", "FOR"};
COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition);
}
else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 &&
pg_strcasecmp(prev3_wd, "LABEL") == 0 &&
pg_strcasecmp(prev2_wd, "FOR") == 0)
COMPLETE_WITH_CONST("ON");
else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 &&
pg_strcasecmp(prev2_wd, "LABEL") == 0 &&
pg_strcasecmp(prev_wd, "ON") == 0) ||
(pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
pg_strcasecmp(prev3_wd, "FOR") == 0 &&
pg_strcasecmp(prev_wd, "ON") == 0))
{
static const char *const list_SECURITY_LABEL[] =
{"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN",
"AGGREGATE", "FUNCTION", "DOMAIN", "LARGE OBJECT",
NULL};
COMPLETE_WITH_LIST(list_SECURITY_LABEL);
}
else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
pg_strcasecmp(prev3_wd, "ON") == 0)
COMPLETE_WITH_CONST("IS");
/* SELECT */
/* naah . . . */

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201009021
#define CATALOG_VERSION_NO 201009271
#endif

View File

@ -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));
#define DbRoleSettingDatidRolidIndexId 2965
DECLARE_UNIQUE_INDEX(pg_seclabel_object_index, 3038, on pg_seclabel using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops, provider text_ops));
#define SecLabelObjectIndexId 3038
/* last step of initialization script: build the indexes declared above */
BUILD_INDICES

View 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 */

View File

@ -45,6 +45,7 @@ DECLARE_TOAST(pg_constraint, 2832, 2833);
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);

View 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 */

View File

@ -347,6 +347,7 @@ typedef enum NodeTag
T_AlterUserMappingStmt,
T_DropUserMappingStmt,
T_AlterTableSpaceOptionsStmt,
T_SecLabelStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)

View File

@ -1850,6 +1850,20 @@ typedef struct CommentStmt
char *comment; /* Comment to insert, or NULL to remove */
} CommentStmt;
/* ----------------------
* SECURITY LABEL Statement
* ----------------------
*/
typedef struct SecLabelStmt
{
NodeTag type;
ObjectType objtype; /* Object's type */
List *objname; /* Qualified name of the object */
List *objargs; /* Arguments if needed (eg, for functions) */
char *provider; /* Label provider (or NULL) */
char *label; /* New security label to be assigned */
} SecLabelStmt;
/* ----------------------
* Declare Cursor Statement
*

View File

@ -209,6 +209,7 @@ PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
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)

View File

@ -107,9 +107,9 @@ installdirs-tests: installdirs
$(MKDIR_P) $(patsubst $(srcdir)/%/,'$(DESTDIR)$(pkglibdir)/regress/%',$(sort $(dir $(regress_data_files))))
# Get some extra C modules from contrib/spi...
# Get some extra C modules from contrib/spi and contrib/dummy_seclabel...
all: refint$(DLSUFFIX) autoinc$(DLSUFFIX)
all: refint$(DLSUFFIX) autoinc$(DLSUFFIX) dummy_seclabel$(DLSUFFIX)
refint$(DLSUFFIX): $(top_builddir)/contrib/spi/refint$(DLSUFFIX)
cp $< $@
@ -117,12 +117,17 @@ refint$(DLSUFFIX): $(top_builddir)/contrib/spi/refint$(DLSUFFIX)
autoinc$(DLSUFFIX): $(top_builddir)/contrib/spi/autoinc$(DLSUFFIX)
cp $< $@
dummy_seclabel$(DLSUFFIX): $(top_builddir)/contrib/dummy_seclabel/dummy_seclabel$(DLSUFFIX)
cp $< $@
$(top_builddir)/contrib/spi/refint$(DLSUFFIX): $(top_srcdir)/contrib/spi/refint.c
$(MAKE) -C $(top_builddir)/contrib/spi refint$(DLSUFFIX)
$(top_builddir)/contrib/spi/autoinc$(DLSUFFIX): $(top_srcdir)/contrib/spi/autoinc.c
$(MAKE) -C $(top_builddir)/contrib/spi autoinc$(DLSUFFIX)
$(top_builddir)/contrib/dummy_seclabel/dummy_seclabel$(DLSUFFIX): $(top_builddir)/contrib/dummy_seclabel/dummy_seclabel.c
$(MAKE) -C $(top_builddir)/contrib/dummy_seclabel dummy_seclabel$(DLSUFFIX)
# Tablespace setup
@ -171,7 +176,8 @@ bigcheck: all
clean distclean maintainer-clean: clean-lib
# things built by `all' target
rm -f $(OBJS) refint$(DLSUFFIX) autoinc$(DLSUFFIX) pg_regress_main.o pg_regress.o pg_regress$(X)
rm -f $(OBJS) refint$(DLSUFFIX) autoinc$(DLSUFFIX) dummy_seclabel$(DLSUFFIX)
rm -f pg_regress_main.o pg_regress.o pg_regress$(X)
# things created by various check targets
rm -f $(output_files) $(input_files)
rm -rf testtablespace

View File

@ -5,4 +5,5 @@
/largeobject.out
/largeobject_1.out
/misc.out
/security_label.out
/tablespace.out

View File

@ -1276,8 +1276,8 @@ drop table cchild;
-- Check that ruleutils are working
--
SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
viewname | definition
-----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
viewname | definition
-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
pg_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);
@ -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_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, s.setconfig AS rolconfig, pg_authid.oid FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid))));
pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
pg_seclabels | (((((SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (rel.relkind = 'r'::"char") THEN 'table'::text WHEN (rel.relkind = 'v'::"char") THEN 'view'::text WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text ELSE NULL::text END AS objtype, rel.relnamespace AS objnamespace, CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid = 0) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'column'::text AS objtype, rel.relnamespace AS objnamespace, ((CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END || '.'::text) || (att.attname)::text) AS objname, l.provider, l.label FROM (((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid <> 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (pro.proisagg = true) THEN 'aggregate'::text WHEN (pro.proisagg = false) THEN 'function'::text ELSE NULL::text END AS objtype, pro.pronamespace AS objnamespace, (((CASE WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text)) END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid)))) JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text ELSE 'type'::text END AS objtype, typ.typnamespace AS objnamespace, CASE WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid)))) JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'large object'::text AS objtype, NULL::oid AS objnamespace, (l.objoid)::text AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid))) WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0))) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'language'::text AS objtype, NULL::oid AS objnamespace, quote_ident((lan.lanname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'schema'::text AS objtype, nsp.oid AS objnamespace, quote_ident((nsp.nspname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid)))) WHERE (l.objsubid = 0);
pg_settings | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val, a.enumvals, a.boot_val, a.reset_val, a.sourcefile, a.sourceline FROM pg_show_all_settings() a(name, setting, unit, category, short_desc, extra_desc, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, sourcefile, sourceline);
pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, s.setconfig AS useconfig FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))) WHERE pg_authid.rolcanlogin;
pg_stat_activity | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_port, s.backend_start, s.xact_start, s.query_start, s.waiting, s.current_query FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, application_name, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_port), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
@ -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))));
street | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
toyemp | SELECT emp.name, emp.age, emp.location, (12 * emp.salary) AS annualsal FROM emp;
(55 rows)
(56 rows)
SELECT tablename, rulename, definition FROM pg_rules
ORDER BY tablename, rulename;

View File

@ -114,6 +114,7 @@ SELECT relname, relhasindex
pg_pltemplate | t
pg_proc | t
pg_rewrite | t
pg_seclabel | t
pg_shdepend | t
pg_shdescription | t
pg_statistic | t
@ -153,7 +154,7 @@ SELECT relname, relhasindex
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
(142 rows)
(143 rows)
--
-- another sanity check: every system catalog that has OIDs should have

View 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;

View 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)

View File

@ -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: privileges
test: privileges security_label
test: misc
# rules cannot run concurrently with any test that creates a view
test: rules

View File

@ -88,6 +88,7 @@ test: delete
test: namespace
test: prepared_xacts
test: privileges
test: security_label
test: misc
test: rules
test: select_views

View File

@ -4,4 +4,5 @@
/create_function_2.sql
/largeobject.sql
/misc.sql
/security_label.sql
/tablespace.sql