diff options
author | Stephen Frost <sfrost@snowman.net> | 2014-11-27 01:06:36 -0500 |
---|---|---|
committer | Stephen Frost <sfrost@snowman.net> | 2014-11-27 01:15:57 -0500 |
commit | 143b39c1855f8a22f474f20354ee5ee5d2f4d266 (patch) | |
tree | 3633add36a9bb7a6a035d94077f6245e71f93acd /src/backend | |
parent | 1812ee5767a25a36e7002be8a3a032357d3fe4e2 (diff) | |
download | postgresql-143b39c1855f8a22f474f20354ee5ee5d2f4d266.tar.gz postgresql-143b39c1855f8a22f474f20354ee5ee5d2f4d266.zip |
Rename pg_rowsecurity -> pg_policy and other fixes
As pointed out by Robert, we should really have named pg_rowsecurity
pg_policy, as the objects stored in that catalog are policies. This
patch fixes that and updates the column names to start with 'pol' to
match the new catalog name.
The security consideration for COPY with row level security, also
pointed out by Robert, has also been addressed by remembering and
re-checking the OID of the relation initially referenced during COPY
processing, to make sure it hasn't changed under us by the time we
finish planning out the query which has been built.
Robert and Alvaro also commented on missing OCLASS and OBJECT entries
for POLICY (formerly ROWSECURITY or POLICY, depending) in various
places. This patch fixes that too, which also happens to add the
ability to COMMENT on policies.
In passing, attempt to improve the consistency of messages, comments,
and documentation as well. This removes various incarnations of
'row-security', 'row-level security', 'Row-security', etc, in favor
of 'policy', 'row level security' or 'row_security' as appropriate.
Happy Thanksgiving!
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/Makefile | 2 | ||||
-rw-r--r-- | src/backend/catalog/dependency.c | 11 | ||||
-rw-r--r-- | src/backend/catalog/objectaddress.c | 58 | ||||
-rw-r--r-- | src/backend/catalog/system_views.sql | 18 | ||||
-rw-r--r-- | src/backend/commands/copy.c | 48 | ||||
-rw-r--r-- | src/backend/commands/event_trigger.c | 2 | ||||
-rw-r--r-- | src/backend/commands/functioncmds.c | 6 | ||||
-rw-r--r-- | src/backend/commands/policy.c | 317 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 19 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 2 | ||||
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 2 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 8 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 11 | ||||
-rw-r--r-- | src/backend/rewrite/rewriteHandler.c | 4 | ||||
-rw-r--r-- | src/backend/rewrite/rowsecurity.c | 14 | ||||
-rw-r--r-- | src/backend/utils/cache/plancache.c | 8 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 4 |
18 files changed, 310 insertions, 230 deletions
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index b257b02ff5c..a403c643600 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_config.h pg_ts_config_map.h pg_ts_dict.h \ 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_rowsecurity.h \ + pg_foreign_table.h pg_policy.h \ pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h pg_range.h \ toasting.h indexing.h \ ) diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index f338acf827d..8ba5123c101 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -43,9 +43,9 @@ #include "catalog/pg_opclass.h" #include "catalog/pg_operator.h" #include "catalog/pg_opfamily.h" +#include "catalog/pg_policy.h" #include "catalog/pg_proc.h" #include "catalog/pg_rewrite.h" -#include "catalog/pg_rowsecurity.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" #include "catalog/pg_ts_config.h" @@ -156,7 +156,8 @@ static const Oid object_classes[MAX_OCLASS] = { UserMappingRelationId, /* OCLASS_USER_MAPPING */ DefaultAclRelationId, /* OCLASS_DEFACL */ ExtensionRelationId, /* OCLASS_EXTENSION */ - EventTriggerRelationId /* OCLASS_EVENT_TRIGGER */ + EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */ + PolicyRelationId /* OCLASS_POLICY */ }; @@ -1251,7 +1252,7 @@ doDeletion(const ObjectAddress *object, int flags) RemoveEventTriggerById(object->objectId); break; - case OCLASS_ROWSECURITY: + case OCLASS_POLICY: RemovePolicyById(object->objectId); break; @@ -2361,8 +2362,8 @@ getObjectClass(const ObjectAddress *object) case EventTriggerRelationId: return OCLASS_EVENT_TRIGGER; - case RowSecurityRelationId: - return OCLASS_ROWSECURITY; + case PolicyRelationId: + return OCLASS_POLICY; } /* shouldn't get here */ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index b69b75bcc2e..e261307e9d5 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -42,7 +42,7 @@ #include "catalog/pg_opfamily.h" #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" -#include "catalog/pg_rowsecurity.h" +#include "catalog/pg_policy.h" #include "catalog/pg_rewrite.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" @@ -346,11 +346,11 @@ static const ObjectPropertyType ObjectProperty[] = false }, { - RowSecurityRelationId, - RowSecurityOidIndexId, + PolicyRelationId, + PolicyOidIndexId, -1, -1, - Anum_pg_rowsecurity_rsecpolname, + Anum_pg_policy_polname, InvalidAttrNumber, InvalidAttrNumber, InvalidAttrNumber, @@ -998,7 +998,7 @@ get_object_address_relobject(ObjectType objtype, List *objname, address.objectSubId = 0; break; case OBJECT_POLICY: - address.classId = RowSecurityRelationId; + address.classId = PolicyRelationId; address.objectId = relation ? get_relation_policy_oid(reloid, depname, missing_ok) : InvalidOid; @@ -2189,38 +2189,38 @@ getObjectDescription(const ObjectAddress *object) break; } - case OCLASS_ROWSECURITY: + case OCLASS_POLICY: { - Relation rsec_rel; + Relation policy_rel; ScanKeyData skey[1]; SysScanDesc sscan; HeapTuple tuple; - Form_pg_rowsecurity form_rsec; + Form_pg_policy form_policy; - rsec_rel = heap_open(RowSecurityRelationId, AccessShareLock); + policy_rel = heap_open(PolicyRelationId, AccessShareLock); ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->objectId)); - sscan = systable_beginscan(rsec_rel, RowSecurityOidIndexId, + sscan = systable_beginscan(policy_rel, PolicyOidIndexId, true, NULL, 1, skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for row-security relation %u", + elog(ERROR, "cache lookup failed for policy %u", object->objectId); - form_rsec = (Form_pg_rowsecurity) GETSTRUCT(tuple); + form_policy = (Form_pg_policy) GETSTRUCT(tuple); appendStringInfo(&buffer, _("policy %s on "), - NameStr(form_rsec->rsecpolname)); - getRelationDescription(&buffer, form_rsec->rsecrelid); + NameStr(form_policy->polname)); + getRelationDescription(&buffer, form_policy->polrelid); systable_endscan(sscan); - heap_close(rsec_rel, AccessShareLock); + heap_close(policy_rel, AccessShareLock); break; } @@ -2635,6 +2635,10 @@ getObjectTypeDescription(const ObjectAddress *object) appendStringInfoString(&buffer, "event trigger"); break; + case OCLASS_POLICY: + appendStringInfoString(&buffer, "policy"); + break; + default: appendStringInfo(&buffer, "unrecognized %u", object->classId); break; @@ -3119,6 +3123,30 @@ getObjectIdentity(const ObjectAddress *object) break; } + case OCLASS_POLICY: + { + Relation polDesc; + HeapTuple tup; + Form_pg_policy policy; + + polDesc = heap_open(PolicyRelationId, AccessShareLock); + + tup = get_catalog_object_by_oid(polDesc, object->objectId); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for policy %u", + object->objectId); + + policy = (Form_pg_policy) GETSTRUCT(tup); + + appendStringInfo(&buffer, "%s on ", + quote_identifier(NameStr(policy->polname))); + getRelationIdentity(&buffer, policy->polrelid); + + heap_close(polDesc, AccessShareLock); + break; + } + case OCLASS_SCHEMA: { char *nspname; diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index a819952c75d..22b8ceef622 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -67,30 +67,30 @@ CREATE VIEW pg_policies AS SELECT N.nspname AS schemaname, C.relname AS tablename, - rs.rsecpolname AS policyname, + pol.polname AS policyname, CASE - WHEN rs.rsecroles = '{0}' THEN + WHEN pol.polroles = '{0}' THEN string_to_array('public', '') ELSE ARRAY ( SELECT rolname FROM pg_catalog.pg_authid - WHERE oid = ANY (rs.rsecroles) ORDER BY 1 + WHERE oid = ANY (pol.polroles) ORDER BY 1 ) END AS roles, - CASE WHEN rs.rseccmd IS NULL THEN 'ALL' ELSE - CASE rs.rseccmd + CASE WHEN pol.polcmd IS NULL THEN 'ALL' ELSE + CASE pol.polcmd WHEN 'r' THEN 'SELECT' WHEN 'a' THEN 'INSERT' WHEN 'u' THEN 'UPDATE' WHEN 'd' THEN 'DELETE' END END AS cmd, - pg_catalog.pg_get_expr(rs.rsecqual, rs.rsecrelid) AS qual, - pg_catalog.pg_get_expr(rs.rsecwithcheck, rs.rsecrelid) AS with_check - FROM pg_catalog.pg_rowsecurity rs - JOIN pg_catalog.pg_class C ON (C.oid = rs.rsecrelid) + pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS qual, + pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS with_check + FROM pg_catalog.pg_policy pol + JOIN pg_catalog.pg_class C ON (C.oid = pol.polrelid) LEFT JOIN pg_catalog.pg_namespace N ON (N.oid = C.relnamespace); CREATE VIEW pg_rules AS diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 83e8f891222..08abe141f41 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -282,12 +282,13 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0"; /* non-export function prototypes */ static CopyState BeginCopy(bool is_from, Relation rel, Node *raw_query, - const char *queryString, List *attnamelist, List *options); + const char *queryString, const Oid queryRelId, List *attnamelist, + List *options); static void EndCopy(CopyState cstate); static void ClosePipeToProgram(CopyState cstate); static CopyState BeginCopyTo(Relation rel, Node *query, const char *queryString, - const char *filename, bool is_program, List *attnamelist, - List *options); + const Oid queryRelId, const char *filename, bool is_program, + List *attnamelist, List *options); static void EndCopyTo(CopyState cstate); static uint64 DoCopyTo(CopyState cstate); static uint64 CopyTo(CopyState cstate); @@ -843,7 +844,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) ExecCheckRTPerms(list_make1(rte), true); /* - * Permission check for row security. + * Permission check for row security policies. * * check_enable_rls will ereport(ERROR) if the user has requested * something invalid and will otherwise indicate if we should enable @@ -866,7 +867,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) if (is_from) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("COPY FROM not supported with row security."), + errmsg("COPY FROM not supported with row level security."), errhint("Use direct INSERT statements instead."))); /* Build target list */ @@ -886,7 +887,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) target->location = 1; /* Build FROM clause */ - from = makeRangeVar(NULL, RelationGetRelationName(rel), 1); + from = stmt->relation; /* Build query */ select = makeNode(SelectStmt); @@ -895,8 +896,6 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) query = (Node*) select; - relid = InvalidOid; - /* Close the handle to the relation as it is no longer needed. */ heap_close(rel, (is_from ? RowExclusiveLock : AccessShareLock)); rel = NULL; @@ -926,7 +925,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) } else { - cstate = BeginCopyTo(rel, query, queryString, + cstate = BeginCopyTo(rel, query, queryString, relid, stmt->filename, stmt->is_program, stmt->attlist, stmt->options); *processed = DoCopyTo(cstate); /* copy from database to file */ @@ -1304,6 +1303,7 @@ BeginCopy(bool is_from, Relation rel, Node *raw_query, const char *queryString, + const Oid queryRelId, List *attnamelist, List *options) { @@ -1395,6 +1395,30 @@ BeginCopy(bool is_from, plan = planner(query, 0, NULL); /* + * If we were passed in a relid, make sure we got the same one back + * after planning out the query. It's possible that it changed between + * when we checked the policies on the table and decided to use a query + * and now. + */ + if (queryRelId != InvalidOid) + { + Oid relid = linitial_oid(plan->relationOids); + + /* + * There should only be one relationOid in this case, since we will + * only get here when we have changed the command for the user from + * a "COPY relation TO" to "COPY (SELECT * FROM relation) TO", to + * allow row level security policies to be applied. + */ + Assert(list_length(plan->relationOids) == 1); + + if (relid != queryRelId) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("relation referenced by COPY statement has changed"))); + } + + /* * Use a snapshot with an updated command ID to ensure this query sees * results of any previously executed queries. */ @@ -1595,6 +1619,7 @@ static CopyState BeginCopyTo(Relation rel, Node *query, const char *queryString, + const Oid queryRelId, const char *filename, bool is_program, List *attnamelist, @@ -1636,7 +1661,8 @@ BeginCopyTo(Relation rel, RelationGetRelationName(rel)))); } - cstate = BeginCopy(false, rel, query, queryString, attnamelist, options); + cstate = BeginCopy(false, rel, query, queryString, queryRelId, attnamelist, + options); oldcontext = MemoryContextSwitchTo(cstate->copycontext); if (pipe) @@ -2565,7 +2591,7 @@ BeginCopyFrom(Relation rel, MemoryContext oldcontext; bool volatile_defexprs; - cstate = BeginCopy(true, rel, NULL, NULL, attnamelist, options); + cstate = BeginCopy(true, rel, NULL, NULL, InvalidOid, attnamelist, options); oldcontext = MemoryContextSwitchTo(cstate->copycontext); /* Initialize state variables */ diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 1b8c94bcfdf..6a3002f5268 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -997,7 +997,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass) case OCLASS_USER_MAPPING: case OCLASS_DEFACL: case OCLASS_EXTENSION: - case OCLASS_ROWSECURITY: + case OCLASS_POLICY: return true; case MAX_OCLASS: diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 470db5705cc..d3a59aa3567 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -904,9 +904,9 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) ReleaseSysCache(languageTuple); /* - * Only superuser is allowed to create leakproof functions because it - * possibly allows unprivileged users to reference invisible tuples to be - * filtered out using views for row-level security. + * Only superuser is allowed to create leakproof functions because leakproof + * functions can see tuples which have not yet been filtered out by security + * barrier views or row level security policies. */ if (isLeakProof && !superuser()) ereport(ERROR, diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c index 10d230ef431..290c826a680 100644 --- a/src/backend/commands/policy.c +++ b/src/backend/commands/policy.c @@ -22,7 +22,7 @@ #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/objectaccess.h" -#include "catalog/pg_rowsecurity.h" +#include "catalog/pg_policy.h" #include "catalog/pg_type.h" #include "commands/policy.h" #include "miscadmin.h" @@ -46,8 +46,8 @@ static void RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg); -static char parse_row_security_command(const char *cmd_name); -static ArrayType* rls_role_list_to_array(List *roles); +static char parse_policy_command(const char *cmd_name); +static ArrayType* policy_role_list_to_array(List *roles); /* * Callback to RangeVarGetRelidExtended(). @@ -95,7 +95,7 @@ RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid, } /* - * parse_row_security_command - + * parse_policy_command - * helper function to convert full command strings to their char * representation. * @@ -104,7 +104,7 @@ RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid, * */ static char -parse_row_security_command(const char *cmd_name) +parse_policy_command(const char *cmd_name) { char cmd; @@ -128,7 +128,7 @@ parse_row_security_command(const char *cmd_name) } /* - * rls_role_list_to_array + * policy_role_list_to_array * helper function to convert a list of role names in to an array of * role ids. * @@ -138,7 +138,7 @@ parse_row_security_command(const char *cmd_name) * roles - the list of role names to convert. */ static ArrayType * -rls_role_list_to_array(List *roles) +policy_role_list_to_array(List *roles) { ArrayType *role_ids; Datum *temp_array; @@ -190,7 +190,7 @@ rls_role_list_to_array(List *roles) } /* - * Load row-security policy from the catalog, and keep it in + * Load row security policy from the catalog, and keep it in * the relation cache. */ void @@ -204,14 +204,14 @@ RelationBuildRowSecurity(Relation relation) MemoryContext rscxt = NULL; RowSecurityDesc *rsdesc = NULL; - catalog = heap_open(RowSecurityRelationId, AccessShareLock); + catalog = heap_open(PolicyRelationId, AccessShareLock); ScanKeyInit(&skey, - Anum_pg_rowsecurity_rsecrelid, + Anum_pg_policy_polrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); - sscan = systable_beginscan(catalog, RowSecurityRelidPolnameIndexId, true, + sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true, NULL, 1, &skey); PG_TRY(); { @@ -221,7 +221,7 @@ RelationBuildRowSecurity(Relation relation) * default-deny policy is created. */ rscxt = AllocSetContextCreate(CacheMemoryContext, - "Row-security descriptor", + "row security descriptor", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); @@ -229,7 +229,7 @@ RelationBuildRowSecurity(Relation relation) rsdesc->rscxt = rscxt; /* - * Loop through the row-level security entries for this relation, if + * Loop through the row level security policies for this relation, if * any. */ while (HeapTupleIsValid(tuple = systable_getnext(sscan))) @@ -249,7 +249,7 @@ RelationBuildRowSecurity(Relation relation) oldcxt = MemoryContextSwitchTo(rscxt); /* Get policy command */ - value_datum = heap_getattr(tuple, Anum_pg_rowsecurity_rseccmd, + value_datum = heap_getattr(tuple, Anum_pg_policy_polcmd, RelationGetDescr(catalog), &isnull); if (isnull) cmd_value = 0; @@ -257,19 +257,19 @@ RelationBuildRowSecurity(Relation relation) cmd_value = DatumGetChar(value_datum); /* Get policy name */ - value_datum = heap_getattr(tuple, Anum_pg_rowsecurity_rsecpolname, + value_datum = heap_getattr(tuple, Anum_pg_policy_polname, RelationGetDescr(catalog), &isnull); Assert(!isnull); policy_name_value = DatumGetCString(value_datum); /* Get policy roles */ - value_datum = heap_getattr(tuple, Anum_pg_rowsecurity_rsecroles, + value_datum = heap_getattr(tuple, Anum_pg_policy_polroles, RelationGetDescr(catalog), &isnull); Assert(!isnull); roles = DatumGetArrayTypeP(value_datum); /* Get policy qual */ - value_datum = heap_getattr(tuple, Anum_pg_rowsecurity_rsecqual, + value_datum = heap_getattr(tuple, Anum_pg_policy_polqual, RelationGetDescr(catalog), &isnull); if (!isnull) { @@ -280,7 +280,7 @@ RelationBuildRowSecurity(Relation relation) qual_expr = NULL; /* Get WITH CHECK qual */ - value_datum = heap_getattr(tuple, Anum_pg_rowsecurity_rsecwithcheck, + value_datum = heap_getattr(tuple, Anum_pg_policy_polwithcheck, RelationGetDescr(catalog), &isnull); if (!isnull) @@ -295,7 +295,7 @@ RelationBuildRowSecurity(Relation relation) policy = palloc0(sizeof(RowSecurityPolicy)); policy->policy_name = policy_name_value; - policy->rsecid = policy_id; + policy->policy_id = policy_id; policy->cmd = cmd_value; policy->roles = roles; policy->qual = copyObject(qual_expr); @@ -317,7 +317,7 @@ RelationBuildRowSecurity(Relation relation) /* * Check if no policies were added * - * If no policies exist in pg_rowsecurity for this relation, then we + * If no policies exist in pg_policy for this relation, then we * need to create a single default-deny policy. We use InvalidOid for * the Oid to indicate that this is the default-deny policy (we may * decide to ignore the default policy if an extension adds policies). @@ -333,7 +333,7 @@ RelationBuildRowSecurity(Relation relation) policy = palloc0(sizeof(RowSecurityPolicy)); policy->policy_name = pstrdup("default-deny policy"); - policy->rsecid = InvalidOid; + policy->policy_id = InvalidOid; policy->cmd = '\0'; policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true, 'i'); @@ -364,22 +364,22 @@ RelationBuildRowSecurity(Relation relation) /* * RemovePolicyById - - * remove a row-security policy by its OID. If a policy does not exist with - * the provided oid, then an error is raised. + * remove a policy by its OID. If a policy does not exist with the provided + * oid, then an error is raised. * - * policy_id - the oid of the row-security policy. + * policy_id - the oid of the policy. */ void RemovePolicyById(Oid policy_id) { - Relation pg_rowsecurity_rel; + Relation pg_policy_rel; SysScanDesc sscan; ScanKeyData skey[1]; HeapTuple tuple; Oid relid; Relation rel; - pg_rowsecurity_rel = heap_open(RowSecurityRelationId, RowExclusiveLock); + pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock); /* * Find the policy to delete. @@ -389,19 +389,19 @@ RemovePolicyById(Oid policy_id) BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(policy_id)); - sscan = systable_beginscan(pg_rowsecurity_rel, RowSecurityOidIndexId, true, + sscan = systable_beginscan(pg_policy_rel, PolicyOidIndexId, true, NULL, 1, skey); tuple = systable_getnext(sscan); /* If the policy exists, then remove it, otherwise raise an error. */ if (!HeapTupleIsValid(tuple)) - elog(ERROR, "could not find tuple for row-security %u", policy_id); + elog(ERROR, "could not find tuple for policy %u", policy_id); /* * Open and exclusive-lock the relation the policy belong to. */ - relid = ((Form_pg_rowsecurity) GETSTRUCT(tuple))->rsecrelid; + relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid; rel = heap_open(relid, AccessExclusiveLock); if (rel->rd_rel->relkind != RELKIND_RELATION) @@ -416,7 +416,7 @@ RemovePolicyById(Oid policy_id) errmsg("permission denied: \"%s\" is a system catalog", RelationGetRelationName(rel)))); - simple_heap_delete(pg_rowsecurity_rel, &tuple->t_self); + simple_heap_delete(pg_policy_rel, &tuple->t_self); systable_endscan(sscan); heap_close(rel, AccessExclusiveLock); @@ -424,9 +424,8 @@ RemovePolicyById(Oid policy_id) /* * Note that, unlike some of the other flags in pg_class, relrowsecurity * is not just an indication of if policies exist. When relrowsecurity - * is set (which can be done directly by the user or indirectly by creating - * a policy on the table), then all access to the relation must be through - * a policy. If no policy is defined for the relation then a default-deny + * is set by a user, then all access to the relation must be through a + * policy. If no policy is defined for the relation then a default-deny * policy is created and all records are filtered (except for queries from * the owner). */ @@ -434,7 +433,7 @@ RemovePolicyById(Oid policy_id) CacheInvalidateRelcache(rel); /* Clean up */ - heap_close(pg_rowsecurity_rel, RowExclusiveLock); + heap_close(pg_policy_rel, RowExclusiveLock); } /* @@ -446,11 +445,11 @@ RemovePolicyById(Oid policy_id) Oid CreatePolicy(CreatePolicyStmt *stmt) { - Relation pg_rowsecurity_rel; - Oid rowsec_id; + Relation pg_policy_rel; + Oid policy_id; Relation target_table; Oid table_id; - char rseccmd; + char polcmd; ArrayType *role_ids; ParseState *qual_pstate; ParseState *with_check_pstate; @@ -459,19 +458,19 @@ CreatePolicy(CreatePolicyStmt *stmt) Node *with_check_qual; ScanKeyData skey[2]; SysScanDesc sscan; - HeapTuple rsec_tuple; - Datum values[Natts_pg_rowsecurity]; - bool isnull[Natts_pg_rowsecurity]; + HeapTuple policy_tuple; + Datum values[Natts_pg_policy]; + bool isnull[Natts_pg_policy]; ObjectAddress target; ObjectAddress myself; /* Parse command */ - rseccmd = parse_row_security_command(stmt->cmd); + polcmd = parse_policy_command(stmt->cmd); /* * If the command is SELECT or DELETE then WITH CHECK should be NULL. */ - if ((rseccmd == ACL_SELECT_CHR || rseccmd == ACL_DELETE_CHR) + if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR) && stmt->with_check != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -481,14 +480,14 @@ CreatePolicy(CreatePolicyStmt *stmt) * If the command is INSERT then WITH CHECK should be the only expression * provided. */ - if (rseccmd == ACL_INSERT_CHR && stmt->qual != NULL) + if (polcmd == ACL_INSERT_CHR && stmt->qual != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("only WITH CHECK expression allowed for INSERT"))); /* Collect role ids */ - role_ids = rls_role_list_to_array(stmt->roles); + role_ids = policy_role_list_to_array(stmt->roles); /* Parse the supplied clause */ qual_pstate = make_parsestate(NULL); @@ -527,74 +526,74 @@ CreatePolicy(CreatePolicyStmt *stmt) EXPR_KIND_WHERE, "POLICY"); - /* Open pg_rowsecurity catalog */ - pg_rowsecurity_rel = heap_open(RowSecurityRelationId, RowExclusiveLock); + /* Open pg_policy catalog */ + pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock); - /* Set key - row security relation id. */ + /* Set key - policy's relation id. */ ScanKeyInit(&skey[0], - Anum_pg_rowsecurity_rsecrelid, + Anum_pg_policy_polrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(table_id)); - /* Set key - row security policy name. */ + /* Set key - policy's name. */ ScanKeyInit(&skey[1], - Anum_pg_rowsecurity_rsecpolname, + Anum_pg_policy_polname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(stmt->policy_name)); - sscan = systable_beginscan(pg_rowsecurity_rel, - RowSecurityRelidPolnameIndexId, true, NULL, 2, + sscan = systable_beginscan(pg_policy_rel, + PolicyPolrelidPolnameIndexId, true, NULL, 2, skey); - rsec_tuple = systable_getnext(sscan); + policy_tuple = systable_getnext(sscan); /* Complain if the policy name already exists for the table */ - if (HeapTupleIsValid(rsec_tuple)) + if (HeapTupleIsValid(policy_tuple)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("policy \"%s\" for relation \"%s\" already exists", stmt->policy_name, RelationGetRelationName(target_table)))); - values[Anum_pg_rowsecurity_rsecrelid - 1] = ObjectIdGetDatum(table_id); - values[Anum_pg_rowsecurity_rsecpolname - 1] + values[Anum_pg_policy_polrelid - 1] = ObjectIdGetDatum(table_id); + values[Anum_pg_policy_polname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->policy_name)); - if (rseccmd) - values[Anum_pg_rowsecurity_rseccmd - 1] = CharGetDatum(rseccmd); + if (polcmd) + values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd); else - isnull[Anum_pg_rowsecurity_rseccmd - 1] = true; + isnull[Anum_pg_policy_polcmd - 1] = true; - values[Anum_pg_rowsecurity_rsecroles - 1] = PointerGetDatum(role_ids); + values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids); /* Add qual if present. */ if (qual) - values[Anum_pg_rowsecurity_rsecqual - 1] + values[Anum_pg_policy_polqual - 1] = CStringGetTextDatum(nodeToString(qual)); else - isnull[Anum_pg_rowsecurity_rsecqual - 1] = true; + isnull[Anum_pg_policy_polqual - 1] = true; /* Add WITH CHECK qual if present */ if (with_check_qual) - values[Anum_pg_rowsecurity_rsecwithcheck - 1] + values[Anum_pg_policy_polwithcheck - 1] = CStringGetTextDatum(nodeToString(with_check_qual)); else - isnull[Anum_pg_rowsecurity_rsecwithcheck - 1] = true; + isnull[Anum_pg_policy_polwithcheck - 1] = true; - rsec_tuple = heap_form_tuple(RelationGetDescr(pg_rowsecurity_rel), values, - isnull); + policy_tuple = heap_form_tuple(RelationGetDescr(pg_policy_rel), values, + isnull); - rowsec_id = simple_heap_insert(pg_rowsecurity_rel, rsec_tuple); + policy_id = simple_heap_insert(pg_policy_rel, policy_tuple); /* Update Indexes */ - CatalogUpdateIndexes(pg_rowsecurity_rel, rsec_tuple); + CatalogUpdateIndexes(pg_policy_rel, policy_tuple); /* Record Dependencies */ target.classId = RelationRelationId; target.objectId = table_id; target.objectSubId = 0; - myself.classId = RowSecurityRelationId; - myself.objectId = rowsec_id; + myself.classId = PolicyRelationId; + myself.objectId = policy_id; myself.objectSubId = 0; recordDependencyOn(&myself, &target, DEPENDENCY_AUTO); @@ -609,14 +608,14 @@ CreatePolicy(CreatePolicyStmt *stmt) CacheInvalidateRelcache(target_table); /* Clean up. */ - heap_freetuple(rsec_tuple); + heap_freetuple(policy_tuple); free_parsestate(qual_pstate); free_parsestate(with_check_pstate); systable_endscan(sscan); relation_close(target_table, NoLock); - heap_close(pg_rowsecurity_rel, RowExclusiveLock); + heap_close(pg_policy_rel, RowExclusiveLock); - return rowsec_id; + return policy_id; } /* @@ -628,8 +627,8 @@ CreatePolicy(CreatePolicyStmt *stmt) Oid AlterPolicy(AlterPolicyStmt *stmt) { - Relation pg_rowsecurity_rel; - Oid rowsec_id; + Relation pg_policy_rel; + Oid policy_id; Relation target_table; Oid table_id; ArrayType *role_ids = NULL; @@ -639,20 +638,20 @@ AlterPolicy(AlterPolicyStmt *stmt) Node *with_check_qual = NULL; ScanKeyData skey[2]; SysScanDesc sscan; - HeapTuple rsec_tuple; + HeapTuple policy_tuple; HeapTuple new_tuple; - Datum values[Natts_pg_rowsecurity]; - bool isnull[Natts_pg_rowsecurity]; - bool replaces[Natts_pg_rowsecurity]; + Datum values[Natts_pg_policy]; + bool isnull[Natts_pg_policy]; + bool replaces[Natts_pg_policy]; ObjectAddress target; ObjectAddress myself; Datum cmd_datum; - char rseccmd; - bool rseccmd_isnull; + char polcmd; + bool polcmd_isnull; /* Parse role_ids */ if (stmt->roles != NULL) - role_ids = rls_role_list_to_array(stmt->roles); + role_ids = policy_role_list_to_array(stmt->roles); /* Get id of table. Also handles permissions checks. */ table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock, @@ -662,7 +661,7 @@ AlterPolicy(AlterPolicyStmt *stmt) target_table = relation_open(table_id, NoLock); - /* Parse the row-security clause */ + /* Parse the using policy clause */ if (stmt->qual) { RangeTblEntry *rte; @@ -675,13 +674,13 @@ AlterPolicy(AlterPolicyStmt *stmt) qual = transformWhereClause(qual_pstate, copyObject(stmt->qual), EXPR_KIND_WHERE, - "ROW SECURITY"); + "POLICY"); qual_parse_rtable = qual_pstate->p_rtable; free_parsestate(qual_pstate); } - /* Parse the with-check row-security clause */ + /* Parse the with-check policy clause */ if (stmt->with_check) { RangeTblEntry *rte; @@ -695,7 +694,7 @@ AlterPolicy(AlterPolicyStmt *stmt) with_check_qual = transformWhereClause(with_check_pstate, copyObject(stmt->with_check), EXPR_KIND_WHERE, - "ROW SECURITY"); + "POLICY"); with_check_parse_rtable = with_check_pstate->p_rtable; free_parsestate(with_check_pstate); @@ -707,28 +706,28 @@ AlterPolicy(AlterPolicyStmt *stmt) memset(isnull, 0, sizeof(isnull)); /* Find policy to update. */ - pg_rowsecurity_rel = heap_open(RowSecurityRelationId, RowExclusiveLock); + pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock); - /* Set key - row security relation id. */ + /* Set key - policy's relation id. */ ScanKeyInit(&skey[0], - Anum_pg_rowsecurity_rsecrelid, + Anum_pg_policy_polrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(table_id)); - /* Set key - row security policy name. */ + /* Set key - policy's name. */ ScanKeyInit(&skey[1], - Anum_pg_rowsecurity_rsecpolname, + Anum_pg_policy_polname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(stmt->policy_name)); - sscan = systable_beginscan(pg_rowsecurity_rel, - RowSecurityRelidPolnameIndexId, true, NULL, 2, + sscan = systable_beginscan(pg_policy_rel, + PolicyPolrelidPolnameIndexId, true, NULL, 2, skey); - rsec_tuple = systable_getnext(sscan); + policy_tuple = systable_getnext(sscan); /* Check that the policy is found, raise an error if not. */ - if (!HeapTupleIsValid(rsec_tuple)) + if (!HeapTupleIsValid(policy_tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("policy \"%s\" on table \"%s\" does not exist", @@ -736,18 +735,18 @@ AlterPolicy(AlterPolicyStmt *stmt) RelationGetRelationName(target_table)))); /* Get policy command */ - cmd_datum = heap_getattr(rsec_tuple, Anum_pg_rowsecurity_rseccmd, - RelationGetDescr(pg_rowsecurity_rel), - &rseccmd_isnull); - if (rseccmd_isnull) - rseccmd = 0; + cmd_datum = heap_getattr(policy_tuple, Anum_pg_policy_polcmd, + RelationGetDescr(pg_policy_rel), + &polcmd_isnull); + if (polcmd_isnull) + polcmd = 0; else - rseccmd = DatumGetChar(cmd_datum); + polcmd = DatumGetChar(cmd_datum); /* * If the command is SELECT or DELETE then WITH CHECK should be NULL. */ - if ((rseccmd == ACL_SELECT_CHR || rseccmd == ACL_DELETE_CHR) + if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR) && stmt->with_check != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -757,52 +756,52 @@ AlterPolicy(AlterPolicyStmt *stmt) * If the command is INSERT then WITH CHECK should be the only * expression provided. */ - if ((rseccmd == ACL_INSERT_CHR) + if ((polcmd == ACL_INSERT_CHR) && stmt->qual != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("only WITH CHECK expression allowed for INSERT"))); - rowsec_id = HeapTupleGetOid(rsec_tuple); + policy_id = HeapTupleGetOid(policy_tuple); if (role_ids != NULL) { - replaces[Anum_pg_rowsecurity_rsecroles - 1] = true; - values[Anum_pg_rowsecurity_rsecroles - 1] = PointerGetDatum(role_ids); + replaces[Anum_pg_policy_polroles - 1] = true; + values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids); } if (qual != NULL) { - replaces[Anum_pg_rowsecurity_rsecqual - 1] = true; - values[Anum_pg_rowsecurity_rsecqual - 1] + replaces[Anum_pg_policy_polqual - 1] = true; + values[Anum_pg_policy_polqual - 1] = CStringGetTextDatum(nodeToString(qual)); } if (with_check_qual != NULL) { - replaces[Anum_pg_rowsecurity_rsecwithcheck - 1] = true; - values[Anum_pg_rowsecurity_rsecwithcheck - 1] + replaces[Anum_pg_policy_polwithcheck - 1] = true; + values[Anum_pg_policy_polwithcheck - 1] = CStringGetTextDatum(nodeToString(with_check_qual)); } - new_tuple = heap_modify_tuple(rsec_tuple, - RelationGetDescr(pg_rowsecurity_rel), + new_tuple = heap_modify_tuple(policy_tuple, + RelationGetDescr(pg_policy_rel), values, isnull, replaces); - simple_heap_update(pg_rowsecurity_rel, &new_tuple->t_self, new_tuple); + simple_heap_update(pg_policy_rel, &new_tuple->t_self, new_tuple); /* Update Catalog Indexes */ - CatalogUpdateIndexes(pg_rowsecurity_rel, new_tuple); + CatalogUpdateIndexes(pg_policy_rel, new_tuple); /* Update Dependencies. */ - deleteDependencyRecordsFor(RowSecurityRelationId, rowsec_id, false); + deleteDependencyRecordsFor(PolicyRelationId, policy_id, false); /* Record Dependencies */ target.classId = RelationRelationId; target.objectId = table_id; target.objectSubId = 0; - myself.classId = RowSecurityRelationId; - myself.objectId = rowsec_id; + myself.classId = PolicyRelationId; + myself.objectId = policy_id; myself.objectSubId = 0; recordDependencyOn(&myself, &target, DEPENDENCY_AUTO); @@ -820,9 +819,9 @@ AlterPolicy(AlterPolicyStmt *stmt) /* Clean up. */ systable_endscan(sscan); relation_close(target_table, NoLock); - heap_close(pg_rowsecurity_rel, RowExclusiveLock); + heap_close(pg_policy_rel, RowExclusiveLock); - return rowsec_id; + return policy_id; } /* @@ -832,13 +831,13 @@ AlterPolicy(AlterPolicyStmt *stmt) Oid rename_policy(RenameStmt *stmt) { - Relation pg_rowsecurity_rel; + Relation pg_policy_rel; Relation target_table; Oid table_id; Oid opoloid; ScanKeyData skey[2]; SysScanDesc sscan; - HeapTuple rsec_tuple; + HeapTuple policy_tuple; /* Get id of table. Also handles permissions checks. */ table_id = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock, @@ -848,74 +847,74 @@ rename_policy(RenameStmt *stmt) target_table = relation_open(table_id, NoLock); - pg_rowsecurity_rel = heap_open(RowSecurityRelationId, RowExclusiveLock); + pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock); /* First pass -- check for conflict */ - /* Add key - row security relation id. */ + /* Add key - policy's relation id. */ ScanKeyInit(&skey[0], - Anum_pg_rowsecurity_rsecrelid, + Anum_pg_policy_polrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(table_id)); - /* Add key - row security policy name. */ + /* Add key - policy's name. */ ScanKeyInit(&skey[1], - Anum_pg_rowsecurity_rsecpolname, + Anum_pg_policy_polname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(stmt->newname)); - sscan = systable_beginscan(pg_rowsecurity_rel, - RowSecurityRelidPolnameIndexId, true, NULL, 2, + sscan = systable_beginscan(pg_policy_rel, + PolicyPolrelidPolnameIndexId, true, NULL, 2, skey); if (HeapTupleIsValid(systable_getnext(sscan))) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("row-policy \"%s\" for table \"%s\" already exists", + errmsg("policy \"%s\" for table \"%s\" already exists", stmt->newname, RelationGetRelationName(target_table)))); systable_endscan(sscan); /* Second pass -- find existing policy and update */ - /* Add key - row security relation id. */ + /* Add key - policy's relation id. */ ScanKeyInit(&skey[0], - Anum_pg_rowsecurity_rsecrelid, + Anum_pg_policy_polrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(table_id)); - /* Add key - row security policy name. */ + /* Add key - policy's name. */ ScanKeyInit(&skey[1], - Anum_pg_rowsecurity_rsecpolname, + Anum_pg_policy_polname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(stmt->subname)); - sscan = systable_beginscan(pg_rowsecurity_rel, - RowSecurityRelidPolnameIndexId, true, NULL, 2, + sscan = systable_beginscan(pg_policy_rel, + PolicyPolrelidPolnameIndexId, true, NULL, 2, skey); - rsec_tuple = systable_getnext(sscan); + policy_tuple = systable_getnext(sscan); /* Complain if we did not find the policy */ - if (!HeapTupleIsValid(rsec_tuple)) + if (!HeapTupleIsValid(policy_tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("row-policy \"%s\" for table \"%s\" does not exist", + errmsg("policy \"%s\" for table \"%s\" does not exist", stmt->subname, RelationGetRelationName(target_table)))); - opoloid = HeapTupleGetOid(rsec_tuple); + opoloid = HeapTupleGetOid(policy_tuple); - rsec_tuple = heap_copytuple(rsec_tuple); + policy_tuple = heap_copytuple(policy_tuple); - namestrcpy(&((Form_pg_rowsecurity) GETSTRUCT(rsec_tuple))->rsecpolname, + namestrcpy(&((Form_pg_policy) GETSTRUCT(policy_tuple))->polname, stmt->newname); - simple_heap_update(pg_rowsecurity_rel, &rsec_tuple->t_self, rsec_tuple); + simple_heap_update(pg_policy_rel, &policy_tuple->t_self, policy_tuple); /* keep system catalog indexes current */ - CatalogUpdateIndexes(pg_rowsecurity_rel, rsec_tuple); + CatalogUpdateIndexes(pg_policy_rel, policy_tuple); - InvokeObjectPostAlterHook(RowSecurityRelationId, - HeapTupleGetOid(rsec_tuple), 0); + InvokeObjectPostAlterHook(PolicyRelationId, + HeapTupleGetOid(policy_tuple), 0); /* * Invalidate relation's relcache entry so that other backends (and @@ -926,7 +925,7 @@ rename_policy(RenameStmt *stmt) /* Clean up. */ systable_endscan(sscan); - heap_close(pg_rowsecurity_rel, RowExclusiveLock); + heap_close(pg_policy_rel, RowExclusiveLock); relation_close(target_table, NoLock); return opoloid; @@ -941,33 +940,33 @@ rename_policy(RenameStmt *stmt) Oid get_relation_policy_oid(Oid relid, const char *policy_name, bool missing_ok) { - Relation pg_rowsecurity_rel; + Relation pg_policy_rel; ScanKeyData skey[2]; SysScanDesc sscan; - HeapTuple rsec_tuple; + HeapTuple policy_tuple; Oid policy_oid; - pg_rowsecurity_rel = heap_open(RowSecurityRelationId, AccessShareLock); + pg_policy_rel = heap_open(PolicyRelationId, AccessShareLock); - /* Add key - row security relation id. */ + /* Add key - policy's relation id. */ ScanKeyInit(&skey[0], - Anum_pg_rowsecurity_rsecrelid, + Anum_pg_policy_polrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); - /* Add key - row security policy name. */ + /* Add key - policy's name. */ ScanKeyInit(&skey[1], - Anum_pg_rowsecurity_rsecpolname, + Anum_pg_policy_polname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(policy_name)); - sscan = systable_beginscan(pg_rowsecurity_rel, - RowSecurityRelidPolnameIndexId, true, NULL, 2, + sscan = systable_beginscan(pg_policy_rel, + PolicyPolrelidPolnameIndexId, true, NULL, 2, skey); - rsec_tuple = systable_getnext(sscan); + policy_tuple = systable_getnext(sscan); - if (!HeapTupleIsValid(rsec_tuple)) + if (!HeapTupleIsValid(policy_tuple)) { if (!missing_ok) ereport(ERROR, @@ -978,11 +977,11 @@ get_relation_policy_oid(Oid relid, const char *policy_name, bool missing_ok) policy_oid = InvalidOid; } else - policy_oid = HeapTupleGetOid(rsec_tuple); + policy_oid = HeapTupleGetOid(policy_tuple); /* Clean up. */ systable_endscan(sscan); - heap_close(pg_rowsecurity_rel, AccessShareLock); + heap_close(pg_policy_rel, AccessShareLock); return policy_oid; } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 56294552e71..2333e1bed92 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -37,7 +37,6 @@ #include "catalog/pg_inherits_fn.h" #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" -#include "catalog/pg_rowsecurity.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" @@ -7986,6 +7985,24 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, colName))); break; + case OCLASS_POLICY: + + /* + * A policy can depend on a column because the column is + * specified in the policy's USING or WITH CHECK qual + * expressions. It might be possible to rewrite and recheck + * the policy expression, but punt for now. It's certainly + * easy enough to remove and recreate the policy; still, + * FIXME someday. + */ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot alter type of a column used in a policy definition"), + errdetail("%s depends on column \"%s\"", + getObjectDescription(&foundObject), + colName))); + break; + case OCLASS_DEFAULT: /* diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index a753b207008..c499486f016 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -502,7 +502,7 @@ ExecutorRewind(QueryDesc *queryDesc) * Returns true if permissions are adequate. Otherwise, throws an appropriate * error if ereport_on_violation is true, or simply returns false otherwise. * - * Note that this does NOT address row-level security policies (aka: RLS). If + * Note that this does NOT address row level security policies (aka: RLS). If * rows will be returned to the user as a result of this permission check * passing, then RLS also needs to be consulted (and check_enable_rls()). * diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index c97355e8fda..25f30676f02 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1171,7 +1171,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, /* * If the subquery has the "security_barrier" flag, it means the subquery - * originated from a view that must enforce row-level security. Then we + * originated from a view that must enforce row level security. Then we * must not push down quals that contain leaky functions. (Ideally this * would be checked inside subquery_is_pushdown_safe, but since we don't * currently pass the RTE to that function, we must do it here.) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index fb74d6bf1f4..f752ecc16a5 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -177,7 +177,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) glob->lastPHId = 0; glob->lastRowMarkId = 0; glob->transientPlan = false; - glob->has_rls = false; + glob->hasRowSecurity = false; /* Determine what fraction of the plan is likely to be scanned */ if (cursorOptions & CURSOR_OPT_FAST_PLAN) @@ -255,7 +255,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) result->relationOids = glob->relationOids; result->invalItems = glob->invalItems; result->nParamExec = glob->nParamExec; - result->has_rls = glob->has_rls; + result->hasRowSecurity = glob->hasRowSecurity; return result; } @@ -1208,7 +1208,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) * This may add new security barrier subquery RTEs to the rangetable. */ expand_security_quals(root, tlist); - root->glob->has_rls = parse->hasRowSecurity; + root->glob->hasRowSecurity = parse->hasRowSecurity; /* * Locate any window functions in the tlist. (We don't need to look diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index e630d0b6d81..4d3fbca5969 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -2109,7 +2109,7 @@ extract_query_dependencies(Node *query, glob.type = T_PlannerGlobal; glob.relationOids = NIL; glob.invalItems = NIL; - glob.has_rls = false; + glob.hasRowSecurity = false; MemSet(&root, 0, sizeof(root)); root.type = T_PlannerInfo; @@ -2119,7 +2119,7 @@ extract_query_dependencies(Node *query, *relationOids = glob.relationOids; *invalItems = glob.invalItems; - *hasRowSecurity = glob.has_rls; + *hasRowSecurity = glob.hasRowSecurity; } static bool @@ -2135,8 +2135,8 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context) Query *query = (Query *) node; ListCell *lc; - /* Collect row-security information */ - context->glob->has_rls = query->hasRowSecurity; + /* Collect row security information */ + context->glob->hasRowSecurity = query->hasRowSecurity; if (query->commandType == CMD_UTILITY) { diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index bd180e7e87b..7e48958ae85 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -5535,7 +5535,7 @@ opt_restart_seqs: * COMMENT ON [ [ CONVERSION | COLLATION | DATABASE | DOMAIN | * EXTENSION | EVENT TRIGGER | FOREIGN DATA WRAPPER | * FOREIGN TABLE | INDEX | [PROCEDURAL] LANGUAGE | - * MATERIALIZED VIEW | ROLE | SCHEMA | SEQUENCE | + * MATERIALIZED VIEW | POLICY | ROLE | SCHEMA | SEQUENCE | * SERVER | TABLE | TABLESPACE | * TEXT SEARCH CONFIGURATION | TEXT SEARCH DICTIONARY | * TEXT SEARCH PARSER | TEXT SEARCH TEMPLATE | TYPE | @@ -5601,6 +5601,15 @@ CommentStmt: n->comment = $8; $$ = (Node *) n; } + | COMMENT ON POLICY name ON any_name IS comment_text + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = OBJECT_POLICY; + n->objname = lappend($6, makeString($4)); + n->objargs = NIL; + n->comment = $8; + $$ = (Node *) n; + } | COMMENT ON RULE name ON any_name IS comment_text { CommentStmt *n = makeNode(CommentStmt); diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index e7021509017..ad983c7158b 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -1715,7 +1715,7 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown) } } /* - * If the RTE has row-security quals, apply them and recurse into the + * If the RTE has row security quals, apply them and recurse into the * securityQuals. */ if (prepend_row_security_policies(parsetree, rte, rt_index)) @@ -1727,7 +1727,7 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown) if (list_member_oid(activeRIRs, RelationGetRelid(rel))) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("infinite recursion detected in row-security policy for relation \"%s\"", + errmsg("infinite recursion detected in policy for relation \"%s\"", RelationGetRelationName(rel)))); /* diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c index 66c358cdec9..6c232dcf9ae 100644 --- a/src/backend/rewrite/rowsecurity.c +++ b/src/backend/rewrite/rowsecurity.c @@ -1,6 +1,6 @@ /* * rewrite/rowsecurity.c - * Routines to support policies for row-level security. + * Routines to support policies for row level security (aka RLS). * * Policies in PostgreSQL provide a mechanism to limit what records are * returned to a user and what records a user is permitted to add to a table. @@ -38,7 +38,7 @@ #include "access/sysattr.h" #include "catalog/pg_class.h" #include "catalog/pg_inherits_fn.h" -#include "catalog/pg_rowsecurity.h" +#include "catalog/pg_policy.h" #include "catalog/pg_type.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -72,8 +72,8 @@ static bool check_role_for_policy(ArrayType *policy_roles, Oid user_id); row_security_policy_hook_type row_security_policy_hook = NULL; /* - * Check the given RTE to see whether it's already had row-security quals - * expanded and, if not, prepend any row-security rules from built-in or + * Check the given RTE to see whether it's already had row security quals + * expanded and, if not, prepend any row security rules from built-in or * plug-in sources to the securityQuals. The security quals are rewritten (for * view expansion, etc) before being added to the RTE. * @@ -154,14 +154,14 @@ prepend_row_security_policies(Query* root, RangeTblEntry* rte, int rt_index) /* * Check if this is only the default-deny policy. * - * Normally, if the table has row-security enabled but there are + * Normally, if the table has row security enabled but there are * no policies, we use a default-deny policy and not allow anything. * However, when an extension uses the hook to add their own * policies, we don't want to include the default deny policy or * there won't be any way for a user to use an extension exclusively * for the policies to be used. */ - if (((RowSecurityPolicy *) linitial(rowsec_policies))->rsecid + if (((RowSecurityPolicy *) linitial(rowsec_policies))->policy_id == InvalidOid) defaultDeny = true; @@ -353,7 +353,7 @@ pull_row_security_policies(CmdType cmd, Relation relation, Oid user_id) policy = palloc0(sizeof(RowSecurityPolicy)); policy->policy_name = pstrdup("default-deny policy"); - policy->rsecid = InvalidOid; + policy->policy_id = InvalidOid; policy->cmd = '\0'; policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true, 'i'); diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index d85ea1bbd3a..c537fe3236c 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -207,7 +207,7 @@ CreateCachedPlan(Node *raw_parse_tree, plansource->generic_cost = -1; plansource->total_custom_cost = 0; plansource->num_custom_plans = 0; - plansource->has_rls = false; + plansource->hasRowSecurity = false; plansource->rowSecurityDisabled = (security_context & SECURITY_ROW_LEVEL_DISABLED) != 0; plansource->row_security_env = row_security; @@ -383,7 +383,7 @@ CompleteCachedPlan(CachedPlanSource *plansource, extract_query_dependencies((Node *) querytree_list, &plansource->relationOids, &plansource->invalItems, - &plansource->has_rls); + &plansource->hasRowSecurity); /* * Also save the current search_path in the query_context. (This @@ -617,7 +617,7 @@ RevalidateCachedQuery(CachedPlanSource *plansource) */ if (plansource->is_valid && !plansource->rowSecurityDisabled - && plansource->has_rls + && plansource->hasRowSecurity && (plansource->planUserId != GetUserId() || plansource->row_security_env != row_security)) plansource->is_valid = false; @@ -766,7 +766,7 @@ RevalidateCachedQuery(CachedPlanSource *plansource) extract_query_dependencies((Node *) qlist, &plansource->relationOids, &plansource->invalItems, - &plansource->has_rls); + &plansource->hasRowSecurity); /* * Also save the current search_path in the query_context. (This should diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index c80ef3c6f89..79244e56865 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -866,7 +866,7 @@ equalPolicy(RowSecurityPolicy *policy1, RowSecurityPolicy *policy2) if (policy2 == NULL) return false; - if (policy1->rsecid != policy2->rsecid) + if (policy1->policy_id != policy2->policy_id) return false; if (policy1->cmd != policy2->cmd) return false; @@ -3439,7 +3439,7 @@ RelationCacheInitializePhase3(void) * they are not preserved in the cache. Note that we can never NOT * have a policy while relrowsecurity is true, * RelationBuildRowSecurity will create a single default-deny policy - * if there is no policy defined in pg_rowsecurity. + * if there is no policy defined in pg_policy. */ if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL) { |