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;