From 463f2625a5fb183b6a8925ccde98bb3889f921d9 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Wed, 20 Jul 2011 13:18:24 -0400 Subject: [PATCH] Support SECURITY LABEL on databases, tablespaces, and roles. This requires a new shared catalog, pg_shseclabel. Along the way, fix the security_label regression tests so that they don't monkey with the labels of any pre-existing objects. This is unlikely to matter in practice, since only the label for the "dummy" provider was being manipulated. But this way still seems cleaner. KaiGai Kohei, with fairly extensive hacking by me. --- doc/src/sgml/catalogs.sgml | 78 ++++++++ doc/src/sgml/ref/security_label.sgml | 3 + src/backend/catalog/Makefile | 2 +- src/backend/catalog/catalog.c | 3 + src/backend/catalog/system_views.sql | 32 ++- src/backend/commands/dbcommands.c | 5 +- src/backend/commands/seclabel.c | 183 +++++++++++++++++- src/backend/commands/tablespace.c | 4 +- src/backend/commands/user.c | 4 +- src/backend/parser/gram.y | 3 + src/bin/pg_dump/dumputils.c | 44 +++++ src/bin/pg_dump/dumputils.h | 4 + src/bin/pg_dump/pg_dump.c | 18 ++ src/bin/pg_dump/pg_dumpall.c | 56 ++++-- src/include/catalog/catversion.h | 2 +- src/include/catalog/indexing.h | 3 + src/include/catalog/pg_shseclabel.h | 41 ++++ src/include/commands/seclabel.h | 1 + src/test/regress/expected/rules.out | 6 +- src/test/regress/expected/sanity_check.out | 3 +- src/test/regress/input/security_label.source | 35 +++- src/test/regress/output/security_label.source | 45 ++++- 22 files changed, 534 insertions(+), 41 deletions(-) create mode 100644 src/include/catalog/pg_shseclabel.h diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index a5ae7c9e91..5e5f8a7554 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -238,6 +238,11 @@ comments on shared objects + + pg_shseclabel + security labels on shared database objects + + pg_statistic planner statistics @@ -4681,6 +4686,12 @@ way to view security labels, see . + + See also pg_shseclabel, + which performs a similar function for security labels of database objects + that are shared across a database cluster. + + <structname>pg_seclabel</structname> Columns @@ -4959,6 +4970,73 @@ + + <structname>pg_shseclabel</structname> + + + pg_shseclabel + + + + The catalog pg_shseclabel stores security + lables on shared database objects. Security labels can be manipulated + with the command. For an easier + way to view security labels, see . + + + + See also pg_seclabel, + which performs a similar function for security labels involving objects + within a single database. + + + + Unlike most system catalogs, pg_shseclabel + is shared across all databases of a cluster: there is only one + copy of pg_shseclabel per cluster, not + one per database. + + +
+ <structname>pg_shseclabel</structname> Columns + + + + Name + Type + References + Description + + + + + objoid + oid + any OID column + The OID of the object this security label pertains to + + + classoid + oid + pg_class.oid + The OID of the system catalog this object appears in + + + provider + name + + The label provider associated with this label. + + + label + text + + The security label applied to this object. + + + +
+ <structname>pg_statistic</structname> diff --git a/doc/src/sgml/ref/security_label.sgml b/doc/src/sgml/ref/security_label.sgml index 13b62e22aa..a9eda21b72 100644 --- a/doc/src/sgml/ref/security_label.sgml +++ b/doc/src/sgml/ref/security_label.sgml @@ -26,13 +26,16 @@ SECURITY LABEL [ FOR provider ] ON TABLE object_name | COLUMN table_name.column_name | AGGREGATE agg_name (agg_type [, ...] ) | + DATABASE object_name | DOMAIN object_name | FOREIGN TABLE object_name FUNCTION function_name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) | LARGE OBJECT large_object_oid | [ PROCEDURAL ] LANGUAGE object_name | + ROLE object_name | SCHEMA object_name | SEQUENCE object_name | + TABLESPACE object_name | TYPE object_name | VIEW object_name } IS 'label' diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 3a834618d2..7e0b7d65a8 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -39,7 +39,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ pg_ts_parser.h pg_ts_template.h pg_extension.h \ pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ pg_foreign_table.h \ - pg_default_acl.h pg_seclabel.h pg_collation.h \ + pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h \ toasting.h indexing.h \ ) diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index cbce0072de..9d568b5273 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -34,6 +34,7 @@ #include "catalog/pg_db_role_setting.h" #include "catalog/pg_shdepend.h" #include "catalog/pg_shdescription.h" +#include "catalog/pg_shseclabel.h" #include "catalog/pg_tablespace.h" #include "catalog/toasting.h" #include "miscadmin.h" @@ -380,6 +381,7 @@ IsSharedRelation(Oid relationId) relationId == PLTemplateRelationId || relationId == SharedDescriptionRelationId || relationId == SharedDependRelationId || + relationId == SharedSecLabelRelationId || relationId == TableSpaceRelationId || relationId == DbRoleSettingRelationId) return true; @@ -394,6 +396,7 @@ IsSharedRelation(Oid relationId) relationId == SharedDescriptionObjIndexId || relationId == SharedDependDependerIndexId || relationId == SharedDependReferenceIndexId || + relationId == SharedSecLabelObjectIndexId || relationId == TablespaceOidIndexId || relationId == TablespaceNameIndexId || relationId == DbRoleSettingDatidRolidIndexId) diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 325d4523e6..2253ca83a7 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -283,7 +283,37 @@ FROM pg_seclabel l JOIN pg_namespace nsp ON l.classoid = nsp.tableoid AND l.objoid = nsp.oid WHERE - l.objsubid = 0; + l.objsubid = 0 +UNION ALL +SELECT + l.objoid, l.classoid, 0::int4 AS objsubid, + 'database'::text AS objtype, + NULL::oid AS objnamespace, + quote_ident(dat.datname) AS objname, + l.provider, l.label +FROM + pg_shseclabel l + JOIN pg_database dat ON l.classoid = dat.tableoid AND l.objoid = dat.oid +UNION ALL +SELECT + l.objoid, l.classoid, 0::int4 AS objsubid, + 'tablespace'::text AS objtype, + NULL::oid AS objnamespace, + quote_ident(spc.spcname) AS objname, + l.provider, l.label +FROM + pg_shseclabel l + JOIN pg_tablespace spc ON l.classoid = spc.tableoid AND l.objoid = spc.oid +UNION ALL +SELECT + l.objoid, l.classoid, 0::int4 AS objsubid, + 'role'::text AS objtype, + NULL::oid AS objnamespace, + quote_ident(rol.rolname) AS objname, + l.provider, l.label +FROM + pg_shseclabel l + JOIN pg_authid rol ON l.classoid = rol.tableoid AND l.objoid = rol.oid; CREATE VIEW pg_settings AS SELECT * FROM pg_show_all_settings() AS A; diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index f319eb539c..93240efbd7 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -39,6 +39,7 @@ #include "catalog/pg_tablespace.h" #include "commands/comment.h" #include "commands/dbcommands.h" +#include "commands/seclabel.h" #include "commands/tablespace.h" #include "mb/pg_wchar.h" #include "miscadmin.h" @@ -822,9 +823,11 @@ dropdb(const char *dbname, bool missing_ok) ReleaseSysCache(tup); /* - * Delete any comments associated with the database. + * Delete any comments or security labels associated with + * the database. */ DeleteSharedComments(db_id, DatabaseRelationId); + DeleteSharedSecurityLabel(db_id, DatabaseRelationId); /* * Remove settings associated with this database diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c index 6e7e9c2976..0041734b62 100644 --- a/src/backend/commands/seclabel.c +++ b/src/backend/commands/seclabel.c @@ -16,6 +16,7 @@ #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_seclabel.h" +#include "catalog/pg_shseclabel.h" #include "commands/seclabel.h" #include "miscadmin.h" #include "utils/acl.h" @@ -24,6 +25,7 @@ #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/rel.h" +#include "utils/syscache.h" #include "utils/tqual.h" typedef struct @@ -135,8 +137,56 @@ ExecSecLabelStmt(SecLabelStmt *stmt) } /* - * GetSecurityLabel returns the security label for a database object for a - * given provider, or NULL if there is no such label. + * GetSharedSecurityLabel returns the security label for a shared object for + * a given provider, or NULL if there is no such label. + */ +static char * +GetSharedSecurityLabel(const ObjectAddress *object, const char *provider) +{ + Relation pg_shseclabel; + ScanKeyData keys[3]; + SysScanDesc scan; + HeapTuple tuple; + Datum datum; + bool isnull; + char *seclabel = NULL; + + ScanKeyInit(&keys[0], + Anum_pg_shseclabel_objoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + ScanKeyInit(&keys[1], + Anum_pg_shseclabel_classoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->classId)); + ScanKeyInit(&keys[2], + Anum_pg_shseclabel_provider, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(provider)); + + pg_shseclabel = heap_open(SharedSecLabelRelationId, AccessShareLock); + + scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true, + SnapshotNow, 3, keys); + + tuple = systable_getnext(scan); + if (HeapTupleIsValid(tuple)) + { + datum = heap_getattr(tuple, Anum_pg_shseclabel_label, + RelationGetDescr(pg_shseclabel), &isnull); + if (!isnull) + seclabel = TextDatumGetCString(datum); + } + systable_endscan(scan); + + heap_close(pg_shseclabel, AccessShareLock); + + return seclabel; +} + +/* + * GetSecurityLabel returns the security label for a shared or database object + * for a given provider, or NULL if there is no such label. */ char * GetSecurityLabel(const ObjectAddress *object, const char *provider) @@ -149,8 +199,11 @@ GetSecurityLabel(const ObjectAddress *object, const char *provider) bool isnull; char *seclabel = NULL; - Assert(!IsSharedRelation(object->classId)); + /* Shared objects have their own security label catalog. */ + if (IsSharedRelation(object->classId)) + return GetSharedSecurityLabel(object, provider); + /* Must be an unshared object, so examine pg_seclabel. */ ScanKeyInit(&keys[0], Anum_pg_seclabel_objoid, BTEqualStrategyNumber, F_OIDEQ, @@ -188,6 +241,84 @@ GetSecurityLabel(const ObjectAddress *object, const char *provider) return seclabel; } +/* + * SetSharedSecurityLabel is a helper function of SetSecurityLabel to + * handle shared database objects. + */ +static void +SetSharedSecurityLabel(const ObjectAddress *object, + const char *provider, const char *label) +{ + Relation pg_shseclabel; + ScanKeyData keys[4]; + SysScanDesc scan; + HeapTuple oldtup; + HeapTuple newtup = NULL; + Datum values[Natts_pg_shseclabel]; + bool nulls[Natts_pg_shseclabel]; + bool replaces[Natts_pg_shseclabel]; + + /* Prepare to form or update a tuple, if necessary. */ + memset(nulls, false, sizeof(nulls)); + memset(replaces, false, sizeof(replaces)); + values[Anum_pg_shseclabel_objoid - 1] = ObjectIdGetDatum(object->objectId); + values[Anum_pg_shseclabel_classoid - 1] = ObjectIdGetDatum(object->classId); + values[Anum_pg_shseclabel_provider - 1] = CStringGetTextDatum(provider); + if (label != NULL) + values[Anum_pg_shseclabel_label - 1] = CStringGetTextDatum(label); + + /* Use the index to search for a matching old tuple */ + ScanKeyInit(&keys[0], + Anum_pg_shseclabel_objoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + ScanKeyInit(&keys[1], + Anum_pg_shseclabel_classoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->classId)); + ScanKeyInit(&keys[2], + Anum_pg_shseclabel_provider, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(provider)); + + pg_shseclabel = heap_open(SharedSecLabelRelationId, RowExclusiveLock); + + scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true, + SnapshotNow, 3, keys); + + oldtup = systable_getnext(scan); + if (HeapTupleIsValid(oldtup)) + { + if (label == NULL) + simple_heap_delete(pg_shseclabel, &oldtup->t_self); + else + { + replaces[Anum_pg_shseclabel_label - 1] = true; + newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_shseclabel), + values, nulls, replaces); + simple_heap_update(pg_shseclabel, &oldtup->t_self, newtup); + } + } + systable_endscan(scan); + + /* If we didn't find an old tuple, insert a new one */ + if (newtup == NULL && label != NULL) + { + newtup = heap_form_tuple(RelationGetDescr(pg_shseclabel), + values, nulls); + simple_heap_insert(pg_shseclabel, newtup); + } + + /* Update indexes, if necessary */ + if (newtup != NULL) + { + CatalogUpdateIndexes(pg_shseclabel, newtup); + heap_freetuple(newtup); + } + + heap_close(pg_shseclabel, RowExclusiveLock); +} + /* * SetSecurityLabel attempts to set the security label for the specified * provider on the specified object to the given value. NULL means that any @@ -206,8 +337,12 @@ SetSecurityLabel(const ObjectAddress *object, bool nulls[Natts_pg_seclabel]; bool replaces[Natts_pg_seclabel]; - /* Security labels on shared objects are not supported. */ - Assert(!IsSharedRelation(object->classId)); + /* Shared objects have their own security label catalog. */ + if (IsSharedRelation(object->classId)) + { + SetSharedSecurityLabel(object, provider, label); + return; + } /* Prepare to form or update a tuple, if necessary. */ memset(nulls, false, sizeof(nulls)); @@ -275,6 +410,38 @@ SetSecurityLabel(const ObjectAddress *object, heap_close(pg_seclabel, RowExclusiveLock); } +/* + * DeleteSharedSecurityLabel is a helper function of DeleteSecurityLabel + * to handle shared database objects. + */ +void +DeleteSharedSecurityLabel(Oid objectId, Oid classId) +{ + Relation pg_shseclabel; + ScanKeyData skey[2]; + SysScanDesc scan; + HeapTuple oldtup; + + ScanKeyInit(&skey[0], + Anum_pg_shseclabel_objoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + ScanKeyInit(&skey[1], + Anum_pg_shseclabel_classoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + + pg_shseclabel = heap_open(SharedSecLabelRelationId, RowExclusiveLock); + + scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true, + SnapshotNow, 2, skey); + while (HeapTupleIsValid(oldtup = systable_getnext(scan))) + simple_heap_delete(pg_shseclabel, &oldtup->t_self); + systable_endscan(scan); + + heap_close(pg_shseclabel, RowExclusiveLock); +} + /* * DeleteSecurityLabel removes all security labels for an object (and any * sub-objects, if applicable). @@ -288,9 +455,13 @@ DeleteSecurityLabel(const ObjectAddress *object) HeapTuple oldtup; int nkeys; - /* Security labels on shared objects are not supported. */ + /* Shared objects have their own security label catalog. */ if (IsSharedRelation(object->classId)) + { + Assert(object->objectSubId == 0); + DeleteSharedSecurityLabel(object->objectId, object->classId); return; + } ScanKeyInit(&skey[0], Anum_pg_seclabel_objoid, diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 3024dc4b64..09ecabb772 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -63,6 +63,7 @@ #include "catalog/pg_tablespace.h" #include "commands/comment.h" #include "commands/defrem.h" +#include "commands/seclabel.h" #include "commands/tablespace.h" #include "miscadmin.h" #include "postmaster/bgwriter.h" @@ -448,9 +449,10 @@ DropTableSpace(DropTableSpaceStmt *stmt) heap_endscan(scandesc); /* - * Remove any comments on this tablespace. + * Remove any comments or security labels on this tablespace. */ DeleteSharedComments(tablespaceoid, TableSpaceRelationId); + DeleteSharedSecurityLabel(tablespaceoid, TableSpaceRelationId); /* * Remove dependency on owner. diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 871bda7cc5..0367b200fe 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -24,6 +24,7 @@ #include "catalog/pg_db_role_setting.h" #include "commands/comment.h" #include "commands/dbcommands.h" +#include "commands/seclabel.h" #include "commands/user.h" #include "libpq/md5.h" #include "miscadmin.h" @@ -1000,9 +1001,10 @@ DropRole(DropRoleStmt *stmt) systable_endscan(sscan); /* - * Remove any comments on this role. + * Remove any comments or security labels on this role. */ DeleteSharedComments(roleid, AuthIdRelationId); + DeleteSharedSecurityLabel(roleid, AuthIdRelationId); /* * Remove settings for this role. diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 72260320c3..ac094aa5f3 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -5068,11 +5068,14 @@ opt_provider: FOR ColId_or_Sconst { $$ = $2; } security_label_type: COLUMN { $$ = OBJECT_COLUMN; } + | DATABASE { $$ = OBJECT_DATABASE; } | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; } | SCHEMA { $$ = OBJECT_SCHEMA; } | SEQUENCE { $$ = OBJECT_SEQUENCE; } | TABLE { $$ = OBJECT_TABLE; } | DOMAIN_P { $$ = OBJECT_TYPE; } + | ROLE { $$ = OBJECT_ROLE; } + | TABLESPACE { $$ = OBJECT_TABLESPACE; } | TYPE_P { $$ = OBJECT_TYPE; } | VIEW { $$ = OBJECT_VIEW; } ; diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index 6e5e625e6d..acce7f82fa 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -1166,3 +1166,47 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, return added_clause; #undef WHEREAND } + +/* + * buildShSecLabelQuery + * + * Build a query to retrieve security labels for a shared object. + */ +void +buildShSecLabelQuery(PGconn *conn, const char *catalog_name, uint32 objectId, + PQExpBuffer sql) +{ + appendPQExpBuffer(sql, + "SELECT provider, label FROM pg_catalog.pg_shseclabel " + "WHERE classoid = '%s'::pg_catalog.regclass AND " + "objoid = %u", catalog_name, objectId); +} + +/* + * emitShSecLabels + * + * Format security label data retrieved by the query generated in + * buildShSecLabelQuery. + */ +void +emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer, + const char *target, const char *objname) +{ + int i; + + for (i = 0; i < PQntuples(res); i++) + { + char *provider = PQgetvalue(res, i, 0); + char *label = PQgetvalue(res, i, 1); + + /* must use fmtId result before calling it again */ + appendPQExpBuffer(buffer, + "SECURITY LABEL FOR %s ON %s", + fmtId(provider), target); + appendPQExpBuffer(buffer, + " %s IS ", + fmtId(objname)); + appendStringLiteralConn(buffer, label, conn); + appendPQExpBuffer(buffer, ";\n"); + } +} diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h index 44d90669b6..40bbc81ae8 100644 --- a/src/bin/pg_dump/dumputils.h +++ b/src/bin/pg_dump/dumputils.h @@ -47,5 +47,9 @@ extern bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule); +extern void buildShSecLabelQuery(PGconn *conn, const char *catalog_name, + uint32 objectId, PQExpBuffer sql); +extern void emitShSecLabels(PGconn *conn, PGresult *res, + PQExpBuffer buffer, const char *target, const char *objname); #endif /* DUMPUTILS_H */ diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 9e69b0fc52..f2ee57cabd 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -2048,6 +2048,24 @@ dumpDatabase(Archive *AH) PQclear(res); + /* Dump shared security label. */ + if (!no_security_labels && g_fout->remoteVersion >= 90200) + { + PQExpBuffer seclabelQry = createPQExpBuffer(); + + buildShSecLabelQuery(g_conn, "pg_database", dbCatId.oid, seclabelQry); + res = PQexec(g_conn, seclabelQry->data); + check_sql_result(res, g_conn, seclabelQry->data, PGRES_TUPLES_OK); + resetPQExpBuffer(seclabelQry); + emitShSecLabels(g_conn, res, seclabelQry, "DATABASE", datname); + if (strlen(seclabelQry->data)) + ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL, + dba, false, "SECURITY LABEL", SECTION_NONE, + seclabelQry->data, "", NULL, + &dbDumpId, 1, NULL, NULL); + destroyPQExpBuffer(seclabelQry); + } + destroyPQExpBuffer(dbQry); destroyPQExpBuffer(delQry); destroyPQExpBuffer(creaQry); diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index b3ad2eac29..b5f64e8d68 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -52,6 +52,9 @@ static void dumpTimestamp(char *msg); static void doShellQuoting(PQExpBuffer buf, const char *str); static int runPgDump(const char *dbname); +static void buildShSecLabels(PGconn *conn, const char *catalog_name, + uint32 objectId, PQExpBuffer buffer, + const char *target, const char *objname); static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport, const char *pguser, enum trivalue prompt_password, bool fail_on_error); static PGresult *executeQuery(PGconn *conn, const char *query); @@ -718,15 +721,15 @@ dumpRoles(PGconn *conn) for (i = 0; i < PQntuples(res); i++) { const char *rolename; + Oid auth_oid; + auth_oid = atooid(PQgetvalue(res, i, i_oid)); rolename = PQgetvalue(res, i, i_rolname); resetPQExpBuffer(buf); if (binary_upgrade) { - Oid auth_oid = atooid(PQgetvalue(res, i, i_oid)); - appendPQExpBuffer(buf, "\n-- For binary upgrade, must preserve pg_authid.oid\n"); appendPQExpBuffer(buf, "SELECT binary_upgrade.set_next_pg_authid_oid('%u'::pg_catalog.oid);\n\n", @@ -796,6 +799,10 @@ dumpRoles(PGconn *conn) appendPQExpBuffer(buf, ";\n"); } + if (!no_security_labels && server_version >= 90200) + buildShSecLabels(conn, "pg_authid", auth_oid, + buf, "ROLE", rolename); + fprintf(OPF, "%s", buf->data); if (server_version >= 70300) @@ -981,7 +988,7 @@ dumpTablespaces(PGconn *conn) * pg_xxx) */ if (server_version >= 90000) - res = executeQuery(conn, "SELECT spcname, " + res = executeQuery(conn, "SELECT oid, spcname, " "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " "spclocation, spcacl, " "array_to_string(spcoptions, ', ')," @@ -990,7 +997,7 @@ dumpTablespaces(PGconn *conn) "WHERE spcname !~ '^pg_' " "ORDER BY 1"); else if (server_version >= 80200) - res = executeQuery(conn, "SELECT spcname, " + res = executeQuery(conn, "SELECT oid, spcname, " "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " "spclocation, spcacl, null, " "pg_catalog.shobj_description(oid, 'pg_tablespace') " @@ -998,7 +1005,7 @@ dumpTablespaces(PGconn *conn) "WHERE spcname !~ '^pg_' " "ORDER BY 1"); else - res = executeQuery(conn, "SELECT spcname, " + res = executeQuery(conn, "SELECT oid, spcname, " "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " "spclocation, spcacl, " "null, null " @@ -1012,12 +1019,13 @@ dumpTablespaces(PGconn *conn) for (i = 0; i < PQntuples(res); i++) { PQExpBuffer buf = createPQExpBuffer(); - char *spcname = PQgetvalue(res, i, 0); - char *spcowner = PQgetvalue(res, i, 1); - char *spclocation = PQgetvalue(res, i, 2); - char *spcacl = PQgetvalue(res, i, 3); - char *spcoptions = PQgetvalue(res, i, 4); - char *spccomment = PQgetvalue(res, i, 5); + uint32 spcoid = atooid(PQgetvalue(res, i, 0)); + char *spcname = PQgetvalue(res, i, 1); + char *spcowner = PQgetvalue(res, i, 2); + char *spclocation = PQgetvalue(res, i, 3); + char *spcacl = PQgetvalue(res, i, 4); + char *spcoptions = PQgetvalue(res, i, 5); + char *spccomment = PQgetvalue(res, i, 6); char *fspcname; /* needed for buildACLCommands() */ @@ -1051,6 +1059,10 @@ dumpTablespaces(PGconn *conn) appendPQExpBuffer(buf, ";\n"); } + if (!no_security_labels && server_version >= 90200) + buildShSecLabels(conn, "pg_tablespace", spcoid, + buf, "TABLESPACE", fspcname); + fprintf(OPF, "%s", buf->data); free(fspcname); @@ -1615,6 +1627,28 @@ runPgDump(const char *dbname) return ret; } +/* + * buildShSecLabels + * + * Build SECURITY LABEL command(s) for an shared object + * + * The caller has to provide object type and identifier to select security + * labels from pg_seclabels system view. + */ +static void +buildShSecLabels(PGconn *conn, const char *catalog_name, uint32 objectId, + PQExpBuffer buffer, const char *target, const char *objname) +{ + PQExpBuffer sql = createPQExpBuffer(); + PGresult *res; + + buildShSecLabelQuery(conn, catalog_name, objectId, sql); + res = executeQuery(conn, sql->data); + emitShSecLabels(conn, res, buffer, target, objname); + + PQclear(res); + destroyPQExpBuffer(sql); +} /* * Make a database connection with the given parameters. An diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 57becb4fe5..2fadf30792 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201107171 +#define CATALOG_VERSION_NO 201107201 #endif diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 4118e64542..9a8e6ffc8a 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -294,6 +294,9 @@ DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_rol DECLARE_UNIQUE_INDEX(pg_seclabel_object_index, 3597, on pg_seclabel using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops, provider text_ops)); #define SecLabelObjectIndexId 3597 +DECLARE_UNIQUE_INDEX(pg_shseclabel_object_index, 3593, on pg_shseclabel using btree(objoid oid_ops, classoid oid_ops, provider text_ops)); +#define SharedSecLabelObjectIndexId 3593 + DECLARE_UNIQUE_INDEX(pg_extension_oid_index, 3080, on pg_extension using btree(oid oid_ops)); #define ExtensionOidIndexId 3080 diff --git a/src/include/catalog/pg_shseclabel.h b/src/include/catalog/pg_shseclabel.h new file mode 100644 index 0000000000..8533eac6d0 --- /dev/null +++ b/src/include/catalog/pg_shseclabel.h @@ -0,0 +1,41 @@ +/* ------------------------------------------------------------------------- + * + * pg_shseclabel.h + * definition of the system "security label" relation (pg_shseclabel) + * + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------- + */ +#ifndef PG_SHSECLABEL_H +#define PG_SHSECLABEL_H + +#include "catalog/genbki.h" + +/* ---------------- + * pg_shseclabel definition. cpp turns this into + * typedef struct FormData_pg_shseclabel + * ---------------- + */ +#define SharedSecLabelRelationId 3592 + +CATALOG(pg_shseclabel,3592) BKI_SHARED_RELATION BKI_WITHOUT_OIDS +{ + Oid objoid; /* OID of the shared object itself */ + Oid classoid; /* OID of table containing the shared object */ + text provider; /* name of label provider */ + text label; /* security label of the object */ +} FormData_pg_shseclabel; + +/* ---------------- + * compiler constants for pg_shseclabel + * ---------------- + */ +#define Natts_pg_shseclabel 4 +#define Anum_pg_shseclabel_objoid 1 +#define Anum_pg_shseclabel_classoid 2 +#define Anum_pg_shseclabel_provider 3 +#define Anum_pg_shseclabel_label 4 + +#endif /* PG_SHSECLABEL_H */ diff --git a/src/include/commands/seclabel.h b/src/include/commands/seclabel.h index 06ce602d7d..1a0282c8ca 100644 --- a/src/include/commands/seclabel.h +++ b/src/include/commands/seclabel.h @@ -21,6 +21,7 @@ extern char *GetSecurityLabel(const ObjectAddress *object, extern void SetSecurityLabel(const ObjectAddress *object, const char *provider, const char *label); extern void DeleteSecurityLabel(const ObjectAddress *object); +extern void DeleteSharedSecurityLabel(Oid objectId, Oid classId); /* * Statement and ESP hook support diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 336df52db8..454e1f98e4 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1276,8 +1276,8 @@ drop table cchild; -- Check that ruleutils are working -- SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname; - viewname | definition ----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + viewname | definition +---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath); pg_available_extension_versions | SELECT e.name, e.version, (x.extname IS NOT NULL) AS installed, e.superuser, e.relocatable, e.schema, e.requires, e.comment FROM (pg_available_extension_versions() e(name, version, superuser, relocatable, schema, requires, comment) LEFT JOIN pg_extension x ON (((e.name = x.extname) AND (e.version = x.extversion)))); pg_available_extensions | SELECT e.name, e.default_version, x.extversion AS installed_version, e.comment FROM (pg_available_extensions() e(name, default_version, comment) LEFT JOIN pg_extension x ON ((e.name = x.extname))); @@ -1289,7 +1289,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem pg_prepared_xacts | SELECT p.transaction, p.gid, p.prepared, u.rolname AS owner, d.datname AS database FROM ((pg_prepared_xact() p(transaction, gid, prepared, ownerid, dbid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid))); pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolreplication, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, s.setconfig AS rolconfig, pg_authid.oid FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))); pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name); - pg_seclabels | (((((SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (rel.relkind = 'r'::"char") THEN 'table'::text WHEN (rel.relkind = 'v'::"char") THEN 'view'::text WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text WHEN (rel.relkind = 'f'::"char") THEN 'foreign table'::text ELSE NULL::text END AS objtype, rel.relnamespace AS objnamespace, CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid = 0) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'column'::text AS objtype, rel.relnamespace AS objnamespace, ((CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END || '.'::text) || (att.attname)::text) AS objname, l.provider, l.label FROM (((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid <> 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (pro.proisagg = true) THEN 'aggregate'::text WHEN (pro.proisagg = false) THEN 'function'::text ELSE NULL::text END AS objtype, pro.pronamespace AS objnamespace, (((CASE WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text)) END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid)))) JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text ELSE 'type'::text END AS objtype, typ.typnamespace AS objnamespace, CASE WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid)))) JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'large object'::text AS objtype, NULL::oid AS objnamespace, (l.objoid)::text AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid))) WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0))) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'language'::text AS objtype, NULL::oid AS objnamespace, quote_ident((lan.lanname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'schema'::text AS objtype, nsp.oid AS objnamespace, quote_ident((nsp.nspname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid)))) WHERE (l.objsubid = 0); + pg_seclabels | ((((((((SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (rel.relkind = 'r'::"char") THEN 'table'::text WHEN (rel.relkind = 'v'::"char") THEN 'view'::text WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text WHEN (rel.relkind = 'f'::"char") THEN 'foreign table'::text ELSE NULL::text END AS objtype, rel.relnamespace AS objnamespace, CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid = 0) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'column'::text AS objtype, rel.relnamespace AS objnamespace, ((CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END || '.'::text) || (att.attname)::text) AS objname, l.provider, l.label FROM (((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid <> 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (pro.proisagg = true) THEN 'aggregate'::text WHEN (pro.proisagg = false) THEN 'function'::text ELSE NULL::text END AS objtype, pro.pronamespace AS objnamespace, (((CASE WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text)) END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid)))) JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text ELSE 'type'::text END AS objtype, typ.typnamespace AS objnamespace, CASE WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid)))) JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'large object'::text AS objtype, NULL::oid AS objnamespace, (l.objoid)::text AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid))) WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0))) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'language'::text AS objtype, NULL::oid AS objnamespace, quote_ident((lan.lanname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'schema'::text AS objtype, nsp.oid AS objnamespace, quote_ident((nsp.nspname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'database'::text AS objtype, NULL::oid AS objnamespace, quote_ident((dat.datname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_database dat ON (((l.classoid = dat.tableoid) AND (l.objoid = dat.oid))))) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'tablespace'::text AS objtype, NULL::oid AS objnamespace, quote_ident((spc.spcname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_tablespace spc ON (((l.classoid = spc.tableoid) AND (l.objoid = spc.oid))))) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'role'::text AS objtype, NULL::oid AS objnamespace, quote_ident((rol.rolname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_authid rol ON (((l.classoid = rol.tableoid) AND (l.objoid = rol.oid)))); pg_settings | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val, a.enumvals, a.boot_val, a.reset_val, a.sourcefile, a.sourceline FROM pg_show_all_settings() a(name, setting, unit, category, short_desc, extra_desc, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, sourcefile, sourceline); pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolreplication AS userepl, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, s.setconfig AS useconfig FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))) WHERE pg_authid.rolcanlogin; pg_stat_activity | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_hostname, s.client_port, s.backend_start, s.xact_start, s.query_start, s.waiting, s.current_query FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, application_name, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_hostname, client_port), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid)); diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index ab9e891788..d42b0ea045 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -120,6 +120,7 @@ SELECT relname, relhasindex pg_seclabel | t pg_shdepend | t pg_shdescription | t + pg_shseclabel | t pg_statistic | t pg_tablespace | t pg_trigger | t @@ -157,7 +158,7 @@ SELECT relname, relhasindex timetz_tbl | f tinterval_tbl | f varchar_tbl | f -(146 rows) +(147 rows) -- -- another sanity check: every system catalog that has OIDs should have diff --git a/src/test/regress/input/security_label.source b/src/test/regress/input/security_label.source index 810a721ca8..70771d7596 100644 --- a/src/test/regress/input/security_label.source +++ b/src/test/regress/input/security_label.source @@ -12,7 +12,7 @@ DROP TABLE IF EXISTS seclabel_tbl1; DROP TABLE IF EXISTS seclabel_tbl2; DROP TABLE IF EXISTS seclabel_tbl3; -CREATE USER seclabel_user1; +CREATE USER seclabel_user1 WITH CREATEROLE; CREATE USER seclabel_user2; CREATE TABLE seclabel_tbl1 (a int, b text); @@ -34,6 +34,11 @@ SECURITY LABEL FOR 'dummy' ON TABLE seclabel_tbl1 IS 'classified'; -- fail SECURITY LABEL ON TABLE seclabel_tbl1 IS '...invalid label...'; -- fail SECURITY LABEL ON TABLE seclabel_tbl3 IS 'unclassified'; -- fail +SECURITY LABEL ON ROLE seclabel_user1 IS 'classified'; -- fail +SECURITY LABEL FOR 'dummy' ON ROLE seclabel_user1 IS 'classified'; -- fail +SECURITY LABEL ON ROLE seclabel_user1 IS '...invalid label...'; -- fail +SECURITY LABEL ON ROLE seclabel_user3 IS 'unclassified'; -- fail + -- Load dummy external security provider LOAD '@libdir@/dummy_seclabel@DLSUFFIX@'; @@ -55,21 +60,38 @@ SET SESSION AUTHORIZATION seclabel_user2; SECURITY LABEL ON TABLE seclabel_tbl1 IS 'unclassified'; -- fail SECURITY LABEL ON TABLE seclabel_tbl2 IS 'classified'; -- OK +-- +-- Test for shared database object +-- +SET SESSION AUTHORIZATION seclabel_user1; + +SECURITY LABEL ON ROLE seclabel_user1 IS 'classified'; -- OK +SECURITY LABEL ON ROLE seclabel_user1 IS '...invalid label...'; -- fail +SECURITY LABEL FOR 'dummy' ON ROLE seclabel_user2 IS 'unclassified'; -- OK +SECURITY LABEL FOR 'unknown_seclabel' ON ROLE seclabel_user1 IS 'unclassified'; -- fail +SECURITY LABEL ON ROLE seclabel_user1 IS 'secret'; -- fail (not superuser) +SECURITY LABEL ON ROLE seclabel_user3 IS 'unclassified'; -- fail (not found) + +SET SESSION AUTHORIZATION seclabel_user2; +SECURITY LABEL ON ROLE seclabel_user2 IS 'unclassified'; -- fail (not privileged) + +RESET SESSION AUTHORIZATION; + +-- +-- Test for various types of object +-- RESET SESSION AUTHORIZATION; SECURITY LABEL ON TABLE seclabel_tbl1 IS 'top secret'; -- OK 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 +CREATE SCHEMA seclabel_test; +SECURITY LABEL ON SCHEMA seclabel_test 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; @@ -78,6 +100,7 @@ DROP TABLE seclabel_tbl1; DROP TABLE seclabel_tbl2; DROP USER seclabel_user1; DROP USER seclabel_user2; +DROP SCHEMA seclabel_test; -- make sure we don't have any leftovers SELECT objtype, objname, provider, label FROM pg_seclabels diff --git a/src/test/regress/output/security_label.source b/src/test/regress/output/security_label.source index 4bc803d694..6994d19c2e 100644 --- a/src/test/regress/output/security_label.source +++ b/src/test/regress/output/security_label.source @@ -8,7 +8,7 @@ DROP ROLE IF EXISTS seclabel_user2; DROP TABLE IF EXISTS seclabel_tbl1; DROP TABLE IF EXISTS seclabel_tbl2; DROP TABLE IF EXISTS seclabel_tbl3; -CREATE USER seclabel_user1; +CREATE USER seclabel_user1 WITH CREATEROLE; CREATE USER seclabel_user2; CREATE TABLE seclabel_tbl1 (a int, b text); CREATE TABLE seclabel_tbl2 (x int, y text); @@ -29,6 +29,14 @@ SECURITY LABEL ON TABLE seclabel_tbl1 IS '...invalid label...'; -- fail ERROR: no security label providers have been loaded SECURITY LABEL ON TABLE seclabel_tbl3 IS 'unclassified'; -- fail ERROR: no security label providers have been loaded +SECURITY LABEL ON ROLE seclabel_user1 IS 'classified'; -- fail +ERROR: no security label providers have been loaded +SECURITY LABEL FOR 'dummy' ON ROLE seclabel_user1 IS 'classified'; -- fail +ERROR: security label provider "dummy" is not loaded +SECURITY LABEL ON ROLE seclabel_user1 IS '...invalid label...'; -- fail +ERROR: no security label providers have been loaded +SECURITY LABEL ON ROLE seclabel_user3 IS 'unclassified'; -- fail +ERROR: no security label providers have been loaded -- Load dummy external security provider LOAD '@abs_builddir@/dummy_seclabel@DLSUFFIX@'; -- @@ -52,13 +60,34 @@ SET SESSION AUTHORIZATION seclabel_user2; SECURITY LABEL ON TABLE seclabel_tbl1 IS 'unclassified'; -- fail ERROR: must be owner of relation seclabel_tbl1 SECURITY LABEL ON TABLE seclabel_tbl2 IS 'classified'; -- OK +-- +-- Test for shared database object +-- +SET SESSION AUTHORIZATION seclabel_user1; +SECURITY LABEL ON ROLE seclabel_user1 IS 'classified'; -- OK +SECURITY LABEL ON ROLE seclabel_user1 IS '...invalid label...'; -- fail +ERROR: '...invalid label...' is not a valid security label +SECURITY LABEL FOR 'dummy' ON ROLE seclabel_user2 IS 'unclassified'; -- OK +SECURITY LABEL FOR 'unknown_seclabel' ON ROLE seclabel_user1 IS 'unclassified'; -- fail +ERROR: security label provider "unknown_seclabel" is not loaded +SECURITY LABEL ON ROLE seclabel_user1 IS 'secret'; -- fail (not superuser) +ERROR: only superuser can set 'secret' label +SECURITY LABEL ON ROLE seclabel_user3 IS 'unclassified'; -- fail (not found) +ERROR: role "seclabel_user3" does not exist +SET SESSION AUTHORIZATION seclabel_user2; +SECURITY LABEL ON ROLE seclabel_user2 IS 'unclassified'; -- fail (not privileged) +ERROR: must have CREATEROLE privilege +RESET SESSION AUTHORIZATION; +-- +-- Test for various types of object +-- RESET SESSION AUTHORIZATION; SECURITY LABEL ON TABLE seclabel_tbl1 IS 'top secret'; -- OK SECURITY LABEL ON VIEW seclabel_view1 IS 'classified'; -- OK 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 +CREATE SCHEMA seclabel_test; +SECURITY LABEL ON SCHEMA seclabel_test IS 'unclassified'; -- OK SELECT objtype, objname, provider, label FROM pg_seclabels ORDER BY objtype, objname; objtype | objname | provider | label @@ -66,15 +95,14 @@ SELECT objtype, objname, provider, label FROM pg_seclabels column | seclabel_tbl1.a | dummy | unclassified domain | seclabel_domain | dummy | classified function | seclabel_four() | dummy | classified - language | plpgsql | dummy | unclassified - schema | public | dummy | unclassified + role | seclabel_user1 | dummy | classified + role | seclabel_user2 | dummy | unclassified + schema | seclabel_test | dummy | unclassified table | seclabel_tbl1 | dummy | top secret table | seclabel_tbl2 | dummy | classified view | seclabel_view1 | dummy | classified -(8 rows) +(9 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; @@ -83,6 +111,7 @@ DROP TABLE seclabel_tbl1; DROP TABLE seclabel_tbl2; DROP USER seclabel_user1; DROP USER seclabel_user2; +DROP SCHEMA seclabel_test; -- make sure we don't have any leftovers SELECT objtype, objname, provider, label FROM pg_seclabels ORDER BY objtype, objname;