aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/policy.c')
-rw-r--r--src/backend/commands/policy.c155
1 files changed, 82 insertions, 73 deletions
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 9b79d886332..d98da0dd506 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -28,10 +28,10 @@
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/pg_list.h"
-#include "optimizer/clauses.h"
#include "parser/parse_clause.h"
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
+#include "rewrite/rewriteManip.h"
#include "rewrite/rowsecurity.h"
#include "storage/lock.h"
#include "utils/acl.h"
@@ -109,10 +109,10 @@ parse_policy_command(const char *cmd_name)
char cmd;
if (!cmd_name)
- elog(ERROR, "unrecognized command");
+ elog(ERROR, "unrecognized policy command");
if (strcmp(cmd_name, "all") == 0)
- cmd = 0;
+ cmd = '*';
else if (strcmp(cmd_name, "select") == 0)
cmd = ACL_SELECT_CHR;
else if (strcmp(cmd_name, "insert") == 0)
@@ -122,7 +122,7 @@ parse_policy_command(const char *cmd_name)
else if (strcmp(cmd_name, "delete") == 0)
cmd = ACL_DELETE_CHR;
else
- elog(ERROR, "unrecognized command");
+ elog(ERROR, "unrecognized policy command");
return cmd;
}
@@ -190,44 +190,54 @@ policy_role_list_to_array(List *roles)
}
/*
- * Load row security policy from the catalog, and keep it in
- * the relation cache.
+ * Load row security policy from the catalog, and store it in
+ * the relation's relcache entry.
+ *
+ * We will always set up some kind of policy here. If no explicit policies
+ * are found then an implicit default-deny policy is created.
*/
void
RelationBuildRowSecurity(Relation relation)
{
- Relation catalog;
- ScanKeyData skey;
- SysScanDesc sscan;
- HeapTuple tuple;
- MemoryContext oldcxt;
- MemoryContext rscxt = NULL;
- RowSecurityDesc *rsdesc = NULL;
-
- catalog = heap_open(PolicyRelationId, AccessShareLock);
+ MemoryContext rscxt;
+ MemoryContext oldcxt = CurrentMemoryContext;
+ RowSecurityDesc * volatile rsdesc = NULL;
- ScanKeyInit(&skey,
- Anum_pg_policy_polrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(RelationGetRelid(relation)));
+ /*
+ * Create a memory context to hold everything associated with this
+ * relation's row security policy. This makes it easy to clean up
+ * during a relcache flush.
+ */
+ rscxt = AllocSetContextCreate(CacheMemoryContext,
+ "row security descriptor",
+ ALLOCSET_SMALL_MINSIZE,
+ ALLOCSET_SMALL_INITSIZE,
+ ALLOCSET_SMALL_MAXSIZE);
- sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
- NULL, 1, &skey);
+ /*
+ * Since rscxt lives under CacheMemoryContext, it is long-lived. Use
+ * a PG_TRY block to ensure it'll get freed if we fail partway through.
+ */
PG_TRY();
{
- /*
- * Set up our memory context- we will always set up some kind of
- * policy here. If no explicit policies are found then an implicit
- * default-deny policy is created.
- */
- rscxt = AllocSetContextCreate(CacheMemoryContext,
- "row security descriptor",
- ALLOCSET_SMALL_MINSIZE,
- ALLOCSET_SMALL_INITSIZE,
- ALLOCSET_SMALL_MAXSIZE);
+ Relation catalog;
+ ScanKeyData skey;
+ SysScanDesc sscan;
+ HeapTuple tuple;
+
rsdesc = MemoryContextAllocZero(rscxt, sizeof(RowSecurityDesc));
rsdesc->rscxt = rscxt;
+ catalog = heap_open(PolicyRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ Anum_pg_policy_polrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(RelationGetRelid(relation)));
+
+ sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
+ NULL, 1, &skey);
+
/*
* Loop through the row level security policies for this relation, if
* any.
@@ -236,7 +246,7 @@ RelationBuildRowSecurity(Relation relation)
{
Datum value_datum;
char cmd_value;
- ArrayType *roles;
+ Datum roles_datum;
char *qual_value;
Expr *qual_expr;
char *with_check_value;
@@ -244,29 +254,33 @@ RelationBuildRowSecurity(Relation relation)
char *policy_name_value;
Oid policy_id;
bool isnull;
- RowSecurityPolicy *policy = NULL;
+ RowSecurityPolicy *policy;
- oldcxt = MemoryContextSwitchTo(rscxt);
+ /*
+ * Note: all the pass-by-reference data we collect here is either
+ * still stored in the tuple, or constructed in the caller's
+ * short-lived memory context. We must copy it into rscxt
+ * explicitly below.
+ */
/* Get policy command */
value_datum = heap_getattr(tuple, Anum_pg_policy_polcmd,
RelationGetDescr(catalog), &isnull);
- if (isnull)
- cmd_value = 0;
- else
- cmd_value = DatumGetChar(value_datum);
+ Assert(!isnull);
+ cmd_value = DatumGetChar(value_datum);
/* Get policy name */
value_datum = heap_getattr(tuple, Anum_pg_policy_polname,
RelationGetDescr(catalog), &isnull);
Assert(!isnull);
- policy_name_value = DatumGetCString(value_datum);
+ policy_name_value = NameStr(*(DatumGetName(value_datum)));
/* Get policy roles */
- value_datum = heap_getattr(tuple, Anum_pg_policy_polroles,
+ roles_datum = heap_getattr(tuple, Anum_pg_policy_polroles,
RelationGetDescr(catalog), &isnull);
- Assert(!isnull);
- roles = DatumGetArrayTypeP(value_datum);
+ /* shouldn't be null, but initdb doesn't mark it so, so check */
+ if (isnull)
+ elog(ERROR, "unexpected null value in pg_policy.polroles");
/* Get policy qual */
value_datum = heap_getattr(tuple, Anum_pg_policy_polqual,
@@ -282,7 +296,6 @@ RelationBuildRowSecurity(Relation relation)
/* Get WITH CHECK qual */
value_datum = heap_getattr(tuple, Anum_pg_policy_polwithcheck,
RelationGetDescr(catalog), &isnull);
-
if (!isnull)
{
with_check_value = TextDatumGetCString(value_datum);
@@ -293,27 +306,33 @@ RelationBuildRowSecurity(Relation relation)
policy_id = HeapTupleGetOid(tuple);
+ /* Now copy everything into the cache context */
+ MemoryContextSwitchTo(rscxt);
+
policy = palloc0(sizeof(RowSecurityPolicy));
- policy->policy_name = policy_name_value;
+ policy->policy_name = pstrdup(policy_name_value);
policy->policy_id = policy_id;
- policy->cmd = cmd_value;
- policy->roles = roles;
+ policy->polcmd = cmd_value;
+ policy->roles = DatumGetArrayTypePCopy(roles_datum);
policy->qual = copyObject(qual_expr);
policy->with_check_qual = copyObject(with_check_qual);
- policy->hassublinks = contain_subplans((Node *) qual_expr) ||
- contain_subplans((Node *) with_check_qual);
+ policy->hassublinks = checkExprHasSubLink((Node *) qual_expr) ||
+ checkExprHasSubLink((Node *) with_check_qual);
rsdesc->policies = lcons(policy, rsdesc->policies);
MemoryContextSwitchTo(oldcxt);
+ /* clean up some (not all) of the junk ... */
if (qual_expr != NULL)
pfree(qual_expr);
-
if (with_check_qual != NULL)
pfree(with_check_qual);
}
+ systable_endscan(sscan);
+ heap_close(catalog, AccessShareLock);
+
/*
* Check if no policies were added
*
@@ -324,17 +343,17 @@ RelationBuildRowSecurity(Relation relation)
*/
if (rsdesc->policies == NIL)
{
- RowSecurityPolicy *policy = NULL;
+ RowSecurityPolicy *policy;
Datum role;
- oldcxt = MemoryContextSwitchTo(rscxt);
+ MemoryContextSwitchTo(rscxt);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
policy = palloc0(sizeof(RowSecurityPolicy));
policy->policy_name = pstrdup("default-deny policy");
policy->policy_id = InvalidOid;
- policy->cmd = '\0';
+ policy->polcmd = '*';
policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true,
'i');
policy->qual = (Expr *) makeConst(BOOLOID, -1, InvalidOid,
@@ -350,15 +369,14 @@ RelationBuildRowSecurity(Relation relation)
}
PG_CATCH();
{
- if (rscxt != NULL)
- MemoryContextDelete(rscxt);
+ /* Delete rscxt, first making sure it isn't active */
+ MemoryContextSwitchTo(oldcxt);
+ MemoryContextDelete(rscxt);
PG_RE_THROW();
}
PG_END_TRY();
- systable_endscan(sscan);
- heap_close(catalog, AccessShareLock);
-
+ /* Success --- attach the policy descriptor to the relcache entry */
relation->rd_rsdesc = rsdesc;
}
@@ -555,27 +573,20 @@ CreatePolicy(CreatePolicyStmt *stmt)
stmt->policy_name, RelationGetRelationName(target_table))));
values[Anum_pg_policy_polrelid - 1] = ObjectIdGetDatum(table_id);
- values[Anum_pg_policy_polname - 1]
- = DirectFunctionCall1(namein, CStringGetDatum(stmt->policy_name));
-
- if (polcmd)
- values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd);
- else
- isnull[Anum_pg_policy_polcmd - 1] = true;
-
+ values[Anum_pg_policy_polname - 1] = DirectFunctionCall1(namein,
+ CStringGetDatum(stmt->policy_name));
+ values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd);
values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
/* Add qual if present. */
if (qual)
- values[Anum_pg_policy_polqual - 1]
- = CStringGetTextDatum(nodeToString(qual));
+ values[Anum_pg_policy_polqual - 1] = CStringGetTextDatum(nodeToString(qual));
else
isnull[Anum_pg_policy_polqual - 1] = true;
/* Add WITH CHECK qual if present */
if (with_check_qual)
- values[Anum_pg_policy_polwithcheck - 1]
- = CStringGetTextDatum(nodeToString(with_check_qual));
+ values[Anum_pg_policy_polwithcheck - 1] = CStringGetTextDatum(nodeToString(with_check_qual));
else
isnull[Anum_pg_policy_polwithcheck - 1] = true;
@@ -738,10 +749,8 @@ AlterPolicy(AlterPolicyStmt *stmt)
cmd_datum = heap_getattr(policy_tuple, Anum_pg_policy_polcmd,
RelationGetDescr(pg_policy_rel),
&polcmd_isnull);
- if (polcmd_isnull)
- polcmd = 0;
- else
- polcmd = DatumGetChar(cmd_datum);
+ Assert(!polcmd_isnull);
+ polcmd = DatumGetChar(cmd_datum);
/*
* If the command is SELECT or DELETE then WITH CHECK should be NULL.