178 lines
4.9 KiB
C
178 lines
4.9 KiB
C
/*--------------------------------------------------------------------------
|
|
*
|
|
* test_rls_hooks.c
|
|
* Code for testing RLS hooks.
|
|
*
|
|
* Copyright (c) 2015-2019, PostgreSQL Global Development Group
|
|
*
|
|
* IDENTIFICATION
|
|
* src/test/modules/test_rls_hooks/test_rls_hooks.c
|
|
*
|
|
* -------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
#include "fmgr.h"
|
|
#include "miscadmin.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/parse_clause.h"
|
|
#include "parser/parse_collate.h"
|
|
#include "parser/parse_node.h"
|
|
#include "parser/parse_relation.h"
|
|
#include "rewrite/rowsecurity.h"
|
|
#include "test_rls_hooks.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/rel.h"
|
|
#include "utils/relcache.h"
|
|
|
|
PG_MODULE_MAGIC;
|
|
|
|
/* Saved hook values in case of unload */
|
|
static row_security_policy_hook_type prev_row_security_policy_hook_permissive = NULL;
|
|
static row_security_policy_hook_type prev_row_security_policy_hook_restrictive = NULL;
|
|
|
|
void _PG_init(void);
|
|
void _PG_fini(void);
|
|
|
|
/* Install hooks */
|
|
void
|
|
_PG_init(void)
|
|
{
|
|
/* Save values for unload */
|
|
prev_row_security_policy_hook_permissive = row_security_policy_hook_permissive;
|
|
prev_row_security_policy_hook_restrictive = row_security_policy_hook_restrictive;
|
|
|
|
/* Set our hooks */
|
|
row_security_policy_hook_permissive = test_rls_hooks_permissive;
|
|
row_security_policy_hook_restrictive = test_rls_hooks_restrictive;
|
|
}
|
|
|
|
/* Uninstall hooks */
|
|
void
|
|
_PG_fini(void)
|
|
{
|
|
row_security_policy_hook_permissive = prev_row_security_policy_hook_permissive;
|
|
row_security_policy_hook_restrictive = prev_row_security_policy_hook_restrictive;
|
|
}
|
|
|
|
/*
|
|
* Return permissive policies to be added
|
|
*/
|
|
List *
|
|
test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
|
|
{
|
|
List *policies = NIL;
|
|
RowSecurityPolicy *policy = palloc0(sizeof(RowSecurityPolicy));
|
|
Datum role;
|
|
FuncCall *n;
|
|
Node *e;
|
|
ColumnRef *c;
|
|
ParseState *qual_pstate;
|
|
RangeTblEntry *rte;
|
|
|
|
if (strcmp(RelationGetRelationName(relation), "rls_test_permissive") != 0 &&
|
|
strcmp(RelationGetRelationName(relation), "rls_test_both") != 0)
|
|
return NIL;
|
|
|
|
qual_pstate = make_parsestate(NULL);
|
|
|
|
rte = addRangeTableEntryForRelation(qual_pstate, relation, AccessShareLock,
|
|
NULL, false, false);
|
|
addRTEtoQuery(qual_pstate, rte, false, true, true);
|
|
|
|
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
|
|
|
|
policy->policy_name = pstrdup("extension policy");
|
|
policy->polcmd = '*';
|
|
policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true, 'i');
|
|
|
|
/*
|
|
* policy->qual = (Expr *) makeConst(BOOLOID, -1, InvalidOid,
|
|
* sizeof(bool), BoolGetDatum(true), false, true);
|
|
*/
|
|
|
|
n = makeFuncCall(list_make2(makeString("pg_catalog"),
|
|
makeString("current_user")), NIL, 0);
|
|
|
|
c = makeNode(ColumnRef);
|
|
c->fields = list_make1(makeString("username"));
|
|
c->location = 0;
|
|
|
|
e = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", (Node *) n, (Node *) c, 0);
|
|
|
|
policy->qual = (Expr *) transformWhereClause(qual_pstate, copyObject(e),
|
|
EXPR_KIND_POLICY,
|
|
"POLICY");
|
|
/* Fix up collation information */
|
|
assign_expr_collations(qual_pstate, (Node *) policy->qual);
|
|
|
|
policy->with_check_qual = copyObject(policy->qual);
|
|
policy->hassublinks = false;
|
|
|
|
policies = list_make1(policy);
|
|
|
|
return policies;
|
|
}
|
|
|
|
/*
|
|
* Return restrictive policies to be added
|
|
*
|
|
* Note that a permissive policy must exist or the default-deny policy
|
|
* will be included and nothing will be visible. If no filtering should
|
|
* be done except for the restrictive policy, then a single "USING (true)"
|
|
* permissive policy can be used; see the regression tests.
|
|
*/
|
|
List *
|
|
test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
|
|
{
|
|
List *policies = NIL;
|
|
RowSecurityPolicy *policy = palloc0(sizeof(RowSecurityPolicy));
|
|
Datum role;
|
|
FuncCall *n;
|
|
Node *e;
|
|
ColumnRef *c;
|
|
ParseState *qual_pstate;
|
|
RangeTblEntry *rte;
|
|
|
|
|
|
if (strcmp(RelationGetRelationName(relation), "rls_test_restrictive") != 0 &&
|
|
strcmp(RelationGetRelationName(relation), "rls_test_both") != 0)
|
|
return NIL;
|
|
|
|
qual_pstate = make_parsestate(NULL);
|
|
|
|
rte = addRangeTableEntryForRelation(qual_pstate, relation, AccessShareLock,
|
|
NULL, false, false);
|
|
addRTEtoQuery(qual_pstate, rte, false, true, true);
|
|
|
|
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
|
|
|
|
policy->policy_name = pstrdup("extension policy");
|
|
policy->polcmd = '*';
|
|
policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true, 'i');
|
|
|
|
n = makeFuncCall(list_make2(makeString("pg_catalog"),
|
|
makeString("current_user")), NIL, 0);
|
|
|
|
c = makeNode(ColumnRef);
|
|
c->fields = list_make1(makeString("supervisor"));
|
|
c->location = 0;
|
|
|
|
e = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", (Node *) n, (Node *) c, 0);
|
|
|
|
policy->qual = (Expr *) transformWhereClause(qual_pstate, copyObject(e),
|
|
EXPR_KIND_POLICY,
|
|
"POLICY");
|
|
/* Fix up collation information */
|
|
assign_expr_collations(qual_pstate, (Node *) policy->qual);
|
|
|
|
policy->with_check_qual = copyObject(policy->qual);
|
|
policy->hassublinks = false;
|
|
|
|
policies = list_make1(policy);
|
|
|
|
return policies;
|
|
}
|