*** a/doc/src/sgml/ref/initdb.sgml
--- b/doc/src/sgml/ref/initdb.sgml
***************
*** 152,157 **** PostgreSQL documentation
--- 152,170 ----
+
+
+
+
+ This option enables the shared catalog tables security, by adding
+ row level security policies on all eligible shared catalog tables.
+ With this option, multi-tenancy in PostgreSQL is supported at
+ database level.
+
+
+
+
+
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 3436,3441 **** ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
--- 3436,3450 ----
{
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
+ /*
+ * ALTER table on sytem catalog tables is possible only when user specifies
+ * CATALOG SECURITY on system catalog tables. To avoid an error in the
+ * AlterTableCreateToastTable function for system catalog tables, the system
+ * catalog tables are ignored for the toast table creation.
+ */
+ if (!IsUnderPostmaster && IsSharedRelation(tab->relid))
+ continue;
+
if (tab->relkind == RELKIND_RELATION ||
tab->relkind == RELKIND_MATVIEW)
AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
*** a/src/backend/utils/misc/rls.c
--- b/src/backend/utils/misc/rls.c
***************
*** 58,67 **** check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
bool relforcerowsecurity;
Oid user_id = checkAsUser ? checkAsUser : GetUserId();
- /* Nothing to do for built-in relations */
- if (relid < FirstNormalObjectId)
- return RLS_NONE;
-
tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tuple))
return RLS_NONE;
--- 58,63 ----
*** a/src/bin/initdb/initdb.c
--- b/src/bin/initdb/initdb.c
***************
*** 132,137 **** static bool do_sync = true;
--- 132,138 ----
static bool sync_only = false;
static bool show_setting = false;
static bool data_checksums = false;
+ static bool shared_catalog_security = false;
static char *xlog_dir = "";
***************
*** 186,191 **** static char *authwarning = NULL;
--- 187,193 ----
*/
static const char *boot_options = "-F";
static const char *backend_options = "--single -F -O -c search_path=pg_catalog -c exit_on_error=true";
+ static const char *catalog_security_options = "--single -F -O -c search_path=pg_catalog -c exit_on_error=true -c allow_system_table_mods=true";
static const char *subdirs[] = {
"global",
***************
*** 255,260 **** static void setup_dictionary(void);
--- 257,263 ----
static void setup_privileges(void);
static void set_info_version(void);
static void setup_schema(void);
+ static void setup_shared_catalog_security(void);
static void load_plpgsql(void);
static void vacuum_db(void);
static void make_template0(void);
***************
*** 2252,2257 **** setup_schema(void)
--- 2255,2356 ----
}
/*
+ * setup shared catalog security by defining policies
+ */
+ static void
+ setup_shared_catalog_security(void)
+ {
+ PG_CMD_DECL;
+ const char **line;
+ static const char *pg_shared_catalog_security_setup[] = {
+ /* AuthMemRelationId */
+ "create policy pg_auth_members_read_own_data on pg_auth_members for select using"
+ " (pg_has_role(roleid, 'any') AND pg_has_role(member, 'any'));\n",
+
+ "alter table pg_auth_members enable row level security;\n",
+
+ /* AuthIdRelationId */
+ "create policy pg_authid_read_own_data on pg_authid for select using"
+ " (pg_has_role(oid, 'any'));\n",
+
+ "alter table pg_authid enable row level security;\n",
+
+ /* DatabaseRelationId */
+ "create policy pg_database_read_own_data on pg_database for select using"
+ " ((oid < 16384) OR has_database_privilege(oid,'any'));\n",
+
+ "alter table pg_database enable row level security;\n",
+
+ /* DbRoleSettingRelationId */
+ "create policy pg_db_role_setting_read_own_data on pg_db_role_setting for select using"
+ " (pg_has_role(setrole, 'any') AND has_database_privilege(setdatabase,'any'));\n",
+
+ "alter table pg_database enable row level security;\n",
+
+ /* PLTemplateRelationId */
+ /*
+ * Currently there is no policy needed for this table, so
+ * leave it as it is.
+ */
+
+ /* ReplicationOriginRelationId */
+ /*
+ * Currently there is no policy needed for this table, so
+ * leave it as it is.
+ */
+
+ /* SharedDependRelationId */
+ "create policy pg_shdepend_read_own_data on pg_shdepend for select using"
+ " ((classid = 1262 AND has_database_privilege(objid, 'any'))"
+ " OR (classid = 1260 AND pg_has_role(objid, 'any'))"
+ " OR (classid = 1213 AND has_tablespace_privilege(objid, 'any')));\n",
+
+ "alter table pg_shdepend enable row level security;\n",
+
+ /* SharedDescriptionRelationId */
+ "create policy pg_shdescription_read_own_data on pg_shdescription for select using"
+ " ((classoid = 1262 AND has_database_privilege(objoid, 'any'))"
+ " OR (classoid = 1260 AND pg_has_role(objoid, 'any'))"
+ " OR (classoid = 1213 AND has_tablespace_privilege(objoid, 'any')));\n",
+
+ "alter table pg_shdescription enable row level security;\n",
+
+ /* SharedSecLabelRelationId */
+ "create policy pg_shseclabel_read_own_data on pg_shseclabel for select using"
+ " ((classoid = 1262 AND has_database_privilege(objoid, 'any'))"
+ " OR (classoid = 1260 AND pg_has_role(objoid, 'any'))"
+ " OR (classoid = 1213 AND has_tablespace_privilege(objoid, 'any')));\n",
+
+ "alter table pg_shseclabel enable row level security;\n",
+
+ /* TableSpaceRelationId */
+ "create policy pg_tablespace_read_own_data on pg_tablespace for select using"
+ " ((oid < 16384) OR has_tablespace_privilege(oid, 'any'));\n",
+
+ "alter table pg_tablespace enable row level security;\n",
+
+ NULL
+ };
+
+ fputs(_("creating shared catalog security policy ... "), stdout);
+ fflush(stdout);
+
+ snprintf(cmd, sizeof(cmd),
+ "\"%s\" %s template1 >%s",
+ backend_exec, catalog_security_options,
+ DEVNULL);
+
+ PG_CMD_OPEN;
+
+ for (line = pg_shared_catalog_security_setup; *line != NULL; line++)
+ PG_CMD_PUTS(*line);
+
+ PG_CMD_CLOSE;
+
+ check_ok();
+ }
+
+ /*
* load PL/pgsql server-side language
*/
static void
***************
*** 2768,2773 **** usage(const char *progname)
--- 2867,2874 ----
printf(_("\nLess commonly used options:\n"));
printf(_(" -d, --debug generate lots of debugging output\n"));
printf(_(" -k, --data-checksums use data page checksums\n"));
+ printf(_(" -C, --shared-catalog-security\n"
+ " use shared catalog security\n"));
printf(_(" -L DIRECTORY where to find the input files\n"));
printf(_(" -n, --noclean do not clean up after errors\n"));
printf(_(" -N, --nosync do not wait for changes to be written safely to disk\n"));
***************
*** 3365,3370 **** initialize_data_directory(void)
--- 3466,3474 ----
setup_schema();
+ if (shared_catalog_security)
+ setup_shared_catalog_security();
+
load_plpgsql();
vacuum_db();
***************
*** 3405,3410 **** main(int argc, char *argv[])
--- 3509,3515 ----
{"sync-only", no_argument, NULL, 'S'},
{"xlogdir", required_argument, NULL, 'X'},
{"data-checksums", no_argument, NULL, 'k'},
+ {"shared-catalog-security", no_argument, NULL, 'C' },
{NULL, 0, NULL, 0}
};
***************
*** 3445,3451 **** main(int argc, char *argv[])
/* process command-line options */
! while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", long_options, &option_index)) != -1)
{
switch (c)
{
--- 3550,3556 ----
/* process command-line options */
! while ((c = getopt_long(argc, argv, "dD:E:kCL:nNU:WA:sST:X:", long_options, &option_index)) != -1)
{
switch (c)
{
***************
*** 3497,3502 **** main(int argc, char *argv[])
--- 3602,3610 ----
case 'k':
data_checksums = true;
break;
+ case 'C':
+ shared_catalog_security = true;
+ break;
case 'L':
share_path = pg_strdup(optarg);
break;