PostgreSQL Source Code git master
Loading...
Searching...
No Matches
policy.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup.h"
#include "access/htup_details.h"
#include "access/relation.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_policy.h"
#include "catalog/pg_type.h"
#include "commands/policy.h"
#include "miscadmin.h"
#include "nodes/pg_list.h"
#include "parser/parse_clause.h"
#include "parser/parse_collate.h"
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rowsecurity.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for policy.c:

Go to the source code of this file.

Functions

static void RangeVarCallbackForPolicy (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
static char parse_policy_command (const char *cmd_name)
 
static Datumpolicy_role_list_to_array (List *roles, int *num_roles)
 
void RelationBuildRowSecurity (Relation relation)
 
void RemovePolicyById (Oid policy_id)
 
bool RemoveRoleFromObjectPolicy (Oid roleid, Oid classid, Oid policy_id)
 
ObjectAddress CreatePolicy (CreatePolicyStmt *stmt)
 
ObjectAddress AlterPolicy (AlterPolicyStmt *stmt)
 
ObjectAddress rename_policy (RenameStmt *stmt)
 
Oid get_relation_policy_oid (Oid relid, const char *policy_name, bool missing_ok)
 
bool relation_has_policies (Relation rel)
 

Function Documentation

◆ AlterPolicy()

ObjectAddress AlterPolicy ( AlterPolicyStmt stmt)

Definition at line 780 of file policy.c.

781{
787 int nitems = 0;
791 Node *qual = NULL;
792 Node *with_check_qual = NULL;
793 ScanKeyData skey[2];
798 bool isnull[Natts_pg_policy];
800 ObjectAddress target;
803 char polcmd;
804 bool polcmd_isnull;
805 int i;
806
807 /* Parse role_ids */
808 if (stmt->roles != NULL)
809 {
812 }
813
814 /* Get id of table. Also handles permissions checks. */
816 0,
818 stmt);
819
821
822 /* Parse the using policy clause */
823 if (stmt->qual)
824 {
827
830 NULL, false, false);
831
832 addNSItemToQuery(qual_pstate, nsitem, false, true, true);
833
836 "POLICY");
837
838 /* Fix up collation information */
840
841 qual_parse_rtable = qual_pstate->p_rtable;
843 }
844
845 /* Parse the with-check policy clause */
846 if (stmt->with_check)
847 {
850
853 NULL, false, false);
854
855 addNSItemToQuery(with_check_pstate, nsitem, false, true, true);
856
857 with_check_qual = transformWhereClause(with_check_pstate,
858 stmt->with_check,
860 "POLICY");
861
862 /* Fix up collation information */
864
867 }
868
869 /* zero-clear */
870 memset(values, 0, sizeof(values));
871 memset(replaces, 0, sizeof(replaces));
872 memset(isnull, 0, sizeof(isnull));
873
874 /* Find policy to update. */
876
877 /* Set key - policy's relation id. */
878 ScanKeyInit(&skey[0],
882
883 /* Set key - policy's name. */
884 ScanKeyInit(&skey[1],
887 CStringGetDatum(stmt->policy_name));
888
891 skey);
892
894
895 /* Check that the policy is found, raise an error if not. */
899 errmsg("policy \"%s\" for table \"%s\" does not exist",
900 stmt->policy_name,
902
903 /* Get policy command */
908 polcmd = DatumGetChar(polcmd_datum);
909
910 /*
911 * If the command is SELECT or DELETE then WITH CHECK should be NULL.
912 */
913 if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
914 && stmt->with_check != NULL)
917 errmsg("only USING expression allowed for SELECT, DELETE")));
918
919 /*
920 * If the command is INSERT then WITH CHECK should be the only expression
921 * provided.
922 */
923 if ((polcmd == ACL_INSERT_CHR)
924 && stmt->qual != NULL)
927 errmsg("only WITH CHECK expression allowed for INSERT")));
928
930
931 if (role_ids != NULL)
932 {
935 }
936 else
937 {
938 Oid *roles;
940 bool attr_isnull;
942
943 /*
944 * We need to pull the set of roles this policy applies to from what's
945 * in the catalog, so that we can recreate the dependencies correctly
946 * for the policy.
947 */
948
951 &attr_isnull);
953
955
956 roles = (Oid *) ARR_DATA_PTR(policy_roles);
957
959
961
962 for (i = 0; i < nitems; i++)
963 role_oids[i] = ObjectIdGetDatum(roles[i]);
964 }
965
966 if (qual != NULL)
967 {
971 }
972 else
973 {
975 bool attr_isnull;
976
977 /*
978 * We need to pull the USING expression and build the range table for
979 * the policy from what's in the catalog, so that we can recreate the
980 * dependencies correctly for the policy.
981 */
982
983 /* Check if the policy has a USING expr */
986 &attr_isnull);
987 if (!attr_isnull)
988 {
989 char *qual_value;
991
992 /* parsestate is built just to build the range table */
994
996 qual = stringToNode(qual_value);
997
998 /* Add this rel to the parsestate's rangetable, for dependencies */
1001 NULL, false, false);
1002
1003 qual_parse_rtable = qual_pstate->p_rtable;
1005 }
1006 }
1007
1008 if (with_check_qual != NULL)
1009 {
1012 = CStringGetTextDatum(nodeToString(with_check_qual));
1013 }
1014 else
1015 {
1017 bool attr_isnull;
1018
1019 /*
1020 * We need to pull the WITH CHECK expression and build the range table
1021 * for the policy from what's in the catalog, so that we can recreate
1022 * the dependencies correctly for the policy.
1023 */
1024
1025 /* Check if the policy has a WITH CHECK expr */
1028 &attr_isnull);
1029 if (!attr_isnull)
1030 {
1031 char *with_check_value;
1033
1034 /* parsestate is built just to build the range table */
1036
1038 with_check_qual = stringToNode(with_check_value);
1039
1040 /* Add this rel to the parsestate's rangetable, for dependencies */
1044 NULL, false, false);
1045
1048 }
1049 }
1050
1053 values, isnull, replaces);
1055
1056 /* Update Dependencies. */
1058
1059 /* Record Dependencies */
1060 target.classId = RelationRelationId;
1061 target.objectId = table_id;
1062 target.objectSubId = 0;
1063
1064 myself.classId = PolicyRelationId;
1065 myself.objectId = policy_id;
1066 myself.objectSubId = 0;
1067
1069
1071
1074
1075 /* Register role dependencies */
1077 target.classId = AuthIdRelationId;
1078 target.objectSubId = 0;
1079 for (i = 0; i < nitems; i++)
1080 {
1082 /* no dependency if public */
1083 if (target.objectId != ACL_ID_PUBLIC)
1086 }
1087
1089
1091
1092 /* Invalidate Relation Cache */
1094
1095 /* Clean up. */
1099
1100 return myself;
1101}
#define ACL_SELECT_CHR
Definition acl.h:138
#define ACL_DELETE_CHR
Definition acl.h:140
#define ACL_INSERT_CHR
Definition acl.h:137
#define ACL_ID_PUBLIC
Definition acl.h:46
#define DatumGetArrayTypePCopy(X)
Definition array.h:262
#define ARR_DATA_PTR(a)
Definition array.h:322
#define ARR_DIMS(a)
Definition array.h:294
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define TextDatumGetCString(d)
Definition builtins.h:99
#define Assert(condition)
Definition c.h:1002
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
@ DEPENDENCY_AUTO
Definition dependency.h:34
@ DEPENDENCY_NORMAL
Definition dependency.h:33
@ SHARED_DEPENDENCY_POLICY
Definition dependency.h:83
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_array(type, count)
Definition fe_memutils.h:91
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1118
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static void * GETSTRUCT(const HeapTupleData *tuple)
#define nitems(x)
Definition indent.h:31
#define stmt
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CacheInvalidateRelcache(Relation relation)
Definition inval.c:1632
int i
Definition isn.c:77
#define NoLock
Definition lockdefs.h:34
#define AccessExclusiveLock
Definition lockdefs.h:43
#define AccessShareLock
Definition lockdefs.h:36
#define RowExclusiveLock
Definition lockdefs.h:38
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition namespace.c:442
static char * errmsg
#define InvokeObjectPostAlterHook(classId, objectId, subId)
char * nodeToString(const void *obj)
Definition outfuncs.c:811
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
void assign_expr_collations(ParseState *pstate, Node *expr)
void free_parsestate(ParseState *pstate)
Definition parse_node.c:72
ParseState * make_parsestate(ParseState *parentParseState)
Definition parse_node.c:39
@ EXPR_KIND_POLICY
Definition parse_node.h:79
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, LOCKMODE lockmode, Alias *alias, bool inh, bool inFromCl)
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition pg_depend.c:51
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition pg_depend.c:314
#define NIL
Definition pg_list.h:68
END_CATALOG_STRUCT typedef FormData_pg_policy * Form_pg_policy
Definition pg_policy.h:55
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
void recordSharedDependencyOn(ObjectAddress *depender, ObjectAddress *referenced, SharedDependencyType deptype)
static void RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition policy.c:64
static Datum * policy_role_list_to_array(List *roles, int *num_roles)
Definition policy.c:149
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static char DatumGetChar(Datum X)
Definition postgres.h:122
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
#define PointerGetDatum(X)
Definition postgres.h:354
unsigned int Oid
static int fb(int x)
void * stringToNode(const char *str)
Definition read.c:90
#define RelationGetDescr(relation)
Definition rel.h:542
#define RelationGetRelationName(relation)
Definition rel.h:550
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:48
#define BTEqualStrategyNumber
Definition stratnum.h:31
Definition pg_list.h:54
Definition nodes.h:133
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40

References AccessExclusiveLock, AccessShareLock, ACL_DELETE_CHR, ACL_ID_PUBLIC, ACL_INSERT_CHR, ACL_SELECT_CHR, addNSItemToQuery(), addRangeTableEntryForRelation(), ARR_DATA_PTR, ARR_DIMS, Assert, assign_expr_collations(), BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), ObjectAddress::classId, construct_array_builtin(), CStringGetDatum(), CStringGetTextDatum, DatumGetArrayTypePCopy, DatumGetChar(), DatumGetObjectId(), deleteDependencyRecordsFor(), deleteSharedDependencyRecordsFor(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, ereport, errcode(), errmsg, ERROR, EXPR_KIND_POLICY, fb(), Form_pg_policy, free_parsestate(), GETSTRUCT(), heap_freetuple(), heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, i, InvokeObjectPostAlterHook, make_parsestate(), NIL, nitems, nodeToString(), NoLock, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, palloc_array, PointerGetDatum, policy_role_list_to_array(), RangeVarCallbackForPolicy(), RangeVarGetRelidExtended(), recordDependencyOn(), recordDependencyOnExpr(), recordSharedDependencyOn(), relation_close(), relation_open(), RelationGetDescr, RelationGetRelationName, RowExclusiveLock, ScanKeyInit(), SHARED_DEPENDENCY_POLICY, stmt, stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, transformWhereClause(), and values.

Referenced by ProcessUtilitySlow().

◆ CreatePolicy()

ObjectAddress CreatePolicy ( CreatePolicyStmt stmt)

Definition at line 581 of file policy.c.

582{
587 char polcmd;
589 int nitems = 0;
594 Node *qual;
595 Node *with_check_qual;
596 ScanKeyData skey[2];
600 bool isnull[Natts_pg_policy];
601 ObjectAddress target;
603 int i;
604
605 /* Parse command */
606 polcmd = parse_policy_command(stmt->cmd_name);
607
608 /*
609 * If the command is SELECT or DELETE then WITH CHECK should be NULL.
610 */
611 if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
612 && stmt->with_check != NULL)
615 errmsg("WITH CHECK cannot be applied to SELECT or DELETE")));
616
617 /*
618 * If the command is INSERT then WITH CHECK should be the only expression
619 * provided.
620 */
621 if (polcmd == ACL_INSERT_CHR && stmt->qual != NULL)
624 errmsg("only WITH CHECK expression allowed for INSERT")));
625
626 /* Collect role ids */
629
630 /* Parse the supplied clause */
633
634 /* zero-clear */
635 memset(values, 0, sizeof(values));
636 memset(isnull, 0, sizeof(isnull));
637
638 /* Get id of table. Also handles permissions checks. */
640 0,
642 stmt);
643
644 /* Open target_table to build quals. No additional lock is necessary. */
646
647 /* Add for the regular security quals */
650 NULL, false, false);
651 addNSItemToQuery(qual_pstate, nsitem, false, true, true);
652
653 /* Add for the with-check quals */
656 NULL, false, false);
657 addNSItemToQuery(with_check_pstate, nsitem, false, true, true);
658
660 stmt->qual,
662 "POLICY");
663
664 with_check_qual = transformWhereClause(with_check_pstate,
665 stmt->with_check,
667 "POLICY");
668
669 /* Fix up collation information */
672
673 /* Open pg_policy catalog */
675
676 /* Set key - policy's relation id. */
677 ScanKeyInit(&skey[0],
681
682 /* Set key - policy's name. */
683 ScanKeyInit(&skey[1],
686 CStringGetDatum(stmt->policy_name));
687
690 skey);
691
693
694 /* Complain if the policy name already exists for the table */
698 errmsg("policy \"%s\" for table \"%s\" already exists",
699 stmt->policy_name, RelationGetRelationName(target_table))));
700
706 CStringGetDatum(stmt->policy_name));
710
711 /* Add qual if present. */
712 if (qual)
714 else
715 isnull[Anum_pg_policy_polqual - 1] = true;
716
717 /* Add WITH CHECK qual if present */
718 if (with_check_qual)
720 else
721 isnull[Anum_pg_policy_polwithcheck - 1] = true;
722
724 isnull);
725
727
728 /* Record Dependencies */
730 target.objectId = table_id;
731 target.objectSubId = 0;
732
733 myself.classId = PolicyRelationId;
734 myself.objectId = policy_id;
735 myself.objectSubId = 0;
736
738
739 recordDependencyOnExpr(&myself, qual, qual_pstate->p_rtable,
741
742 recordDependencyOnExpr(&myself, with_check_qual,
744
745 /* Register role dependencies */
746 target.classId = AuthIdRelationId;
747 target.objectSubId = 0;
748 for (i = 0; i < nitems; i++)
749 {
751 /* no dependency if public */
752 if (target.objectId != ACL_ID_PUBLIC)
755 }
756
758
759 /* Invalidate Relation Cache */
761
762 /* Clean up. */
769
770 return myself;
771}
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:475
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:688
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
Datum namein(PG_FUNCTION_ARGS)
Definition name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
static char parse_policy_command(const char *cmd_name)
Definition policy.c:120
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30

References AccessExclusiveLock, AccessShareLock, ACL_DELETE_CHR, ACL_ID_PUBLIC, ACL_INSERT_CHR, ACL_SELECT_CHR, addNSItemToQuery(), addRangeTableEntryForRelation(), assign_expr_collations(), BoolGetDatum(), BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleInsert(), CharGetDatum(), ObjectAddress::classId, construct_array_builtin(), CStringGetDatum(), CStringGetTextDatum, DatumGetObjectId(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, EXPR_KIND_POLICY, fb(), free_parsestate(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, InvokeObjectPostCreateHook, make_parsestate(), namein(), nitems, nodeToString(), NoLock, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, parse_policy_command(), PointerGetDatum, policy_role_list_to_array(), RangeVarCallbackForPolicy(), RangeVarGetRelidExtended(), recordDependencyOn(), recordDependencyOnExpr(), recordSharedDependencyOn(), relation_close(), relation_open(), RelationGetDescr, RelationGetRelationName, RowExclusiveLock, ScanKeyInit(), SHARED_DEPENDENCY_POLICY, stmt, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), transformWhereClause(), and values.

Referenced by ProcessUtilitySlow().

◆ get_relation_policy_oid()

Oid get_relation_policy_oid ( Oid  relid,
const char policy_name,
bool  missing_ok 
)

Definition at line 1216 of file policy.c.

1217{
1219 ScanKeyData skey[2];
1223
1225
1226 /* Add key - policy's relation id. */
1227 ScanKeyInit(&skey[0],
1230 ObjectIdGetDatum(relid));
1231
1232 /* Add key - policy's name. */
1233 ScanKeyInit(&skey[1],
1236 CStringGetDatum(policy_name));
1237
1240 skey);
1241
1243
1245 {
1246 if (!missing_ok)
1247 ereport(ERROR,
1249 errmsg("policy \"%s\" for table \"%s\" does not exist",
1250 policy_name, get_rel_name(relid))));
1251
1253 }
1254 else
1256
1257 /* Clean up. */
1260
1261 return policy_oid;
1262}
char * get_rel_name(Oid relid)
Definition lsyscache.c:2242
#define InvalidOid

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum(), ereport, errcode(), errmsg, ERROR, fb(), Form_pg_policy, get_rel_name(), GETSTRUCT(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by get_object_address_relobject().

◆ parse_policy_command()

static char parse_policy_command ( const char cmd_name)
static

Definition at line 120 of file policy.c.

121{
122 char polcmd;
123
124 if (!cmd_name)
125 elog(ERROR, "unrecognized policy command");
126
127 if (strcmp(cmd_name, "all") == 0)
128 polcmd = '*';
129 else if (strcmp(cmd_name, "select") == 0)
130 polcmd = ACL_SELECT_CHR;
131 else if (strcmp(cmd_name, "insert") == 0)
132 polcmd = ACL_INSERT_CHR;
133 else if (strcmp(cmd_name, "update") == 0)
134 polcmd = ACL_UPDATE_CHR;
135 else if (strcmp(cmd_name, "delete") == 0)
136 polcmd = ACL_DELETE_CHR;
137 else
138 elog(ERROR, "unrecognized policy command");
139
140 return polcmd;
141}
#define ACL_UPDATE_CHR
Definition acl.h:139
#define elog(elevel,...)
Definition elog.h:228

References ACL_DELETE_CHR, ACL_INSERT_CHR, ACL_SELECT_CHR, ACL_UPDATE_CHR, elog, ERROR, and fb().

Referenced by CreatePolicy().

◆ policy_role_list_to_array()

static Datum * policy_role_list_to_array ( List roles,
int num_roles 
)
static

Definition at line 149 of file policy.c.

150{
152 ListCell *cell;
153 int i = 0;
154
155 /* Handle no roles being passed in as being for public */
156 if (roles == NIL)
157 {
158 *num_roles = 1;
161
162 return role_oids;
163 }
164
165 *num_roles = list_length(roles);
166 role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
167
168 foreach(cell, roles)
169 {
170 RoleSpec *spec = lfirst(cell);
171
172 /*
173 * PUBLIC covers all roles, so it only makes sense alone.
174 */
175 if (spec->roletype == ROLESPEC_PUBLIC)
176 {
177 if (*num_roles != 1)
178 {
181 errmsg("ignoring specified roles other than PUBLIC"),
182 errhint("All roles are members of the PUBLIC role.")));
183 *num_roles = 1;
184 }
186
187 return role_oids;
188 }
189 else
190 role_oids[i++] =
192 }
193
194 return role_oids;
195}
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition acl.c:5642
int errhint(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:37
void * palloc(Size size)
Definition mcxt.c:1390
@ ROLESPEC_PUBLIC
Definition parsenodes.h:427
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152

References ACL_ID_PUBLIC, ereport, errcode(), errhint(), errmsg, fb(), get_rolespec_oid(), i, lfirst, list_length(), NIL, ObjectIdGetDatum(), palloc(), palloc_array, ROLESPEC_PUBLIC, and WARNING.

Referenced by AlterPolicy(), and CreatePolicy().

◆ RangeVarCallbackForPolicy()

static void RangeVarCallbackForPolicy ( const RangeVar rv,
Oid  relid,
Oid  oldrelid,
void arg 
)
static

Definition at line 64 of file policy.c.

66{
67 HeapTuple tuple;
69 char relkind;
70
72 if (!HeapTupleIsValid(tuple))
73 return;
74
76 relkind = classform->relkind;
77
78 /* Must own relation. */
81
82 /*
83 * Conflict log tables are used internally for logical replication
84 * conflict logging and should not be modified directly, as it could
85 * disrupt conflict logging.
86 */
90 errmsg("cannot create policy on conflict log table \"%s\"",
91 rv->relname),
92 errdetail("Conflict log tables are system-managed tables for logical replication conflicts.")));
93
94 /* No system table modifications unless explicitly allowed. */
98 errmsg("permission denied: \"%s\" is a system catalog",
99 rv->relname)));
100
101 /* Relation type MUST be a table. */
102 if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
105 errmsg("\"%s\" is not a table", rv->relname)));
106
107 ReleaseSysCache(tuple);
108}
@ ACLCHECK_NOT_OWNER
Definition acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4156
bool IsConflictLogTableClass(Form_pg_class reltuple)
Definition catalog.c:242
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition catalog.c:86
int errdetail(const char *fmt,...) pg_attribute_printf(1
bool allowSystemTableMods
Definition globals.c:132
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2317
Oid GetUserId(void)
Definition miscinit.c:470
ObjectType get_relkind_objtype(char relkind)
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
char * relname
Definition primnodes.h:84
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221

References aclcheck_error(), ACLCHECK_NOT_OWNER, allowSystemTableMods, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), get_rel_relkind(), get_relkind_objtype(), GETSTRUCT(), GetUserId(), HeapTupleIsValid, IsConflictLogTableClass(), IsSystemClass(), object_ownercheck(), ObjectIdGetDatum(), ReleaseSysCache(), RangeVar::relname, and SearchSysCache1().

Referenced by AlterPolicy(), CreatePolicy(), and rename_policy().

◆ relation_has_policies()

◆ RelationBuildRowSecurity()

void RelationBuildRowSecurity ( Relation  relation)

Definition at line 205 of file policy.c.

206{
207 MemoryContext rscxt;
213 HeapTuple tuple;
214
215 /*
216 * Create a memory context to hold everything associated with this
217 * relation's row security policy. This makes it easy to clean up during
218 * a relcache flush. However, to cover the possibility of an error
219 * partway through, we don't make the context long-lived till we're done.
220 */
222 "row security descriptor",
225 RelationGetRelationName(relation));
226
228 rsdesc->rscxt = rscxt;
229
230 /*
231 * Now scan pg_policy for RLS policies associated with this relation.
232 * Because we use the index on (polrelid, polname), we should consistently
233 * visit the rel's policies in name order, at least when system indexes
234 * aren't disabled. This simplifies equalRSDesc().
235 */
237
242
244 NULL, 1, &skey);
245
246 while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
247 {
250 Datum datum;
251 bool isnull;
252 char *str_value;
253
255
256 /*
257 * Note: we must be sure that pass-by-reference data gets copied into
258 * rscxt. We avoid making that context current over wider spans than
259 * we have to, though.
260 */
261
262 /* Get policy command */
263 policy->polcmd = policy_form->polcmd;
264
265 /* Get policy, permissive or restrictive */
266 policy->permissive = policy_form->polpermissive;
267
268 /* Get policy name */
269 policy->policy_name =
270 MemoryContextStrdup(rscxt, NameStr(policy_form->polname));
271
272 /* Get policy roles */
274 RelationGetDescr(catalog), &isnull);
275 /* shouldn't be null, but let's check for luck */
276 if (isnull)
277 elog(ERROR, "unexpected null value in pg_policy.polroles");
279 policy->roles = DatumGetArrayTypePCopy(datum);
281
282 /* Get policy qual */
284 RelationGetDescr(catalog), &isnull);
285 if (!isnull)
286 {
289 policy->qual = (Expr *) stringToNode(str_value);
292 }
293 else
294 policy->qual = NULL;
295
296 /* Get WITH CHECK qual */
298 RelationGetDescr(catalog), &isnull);
299 if (!isnull)
300 {
303 policy->with_check_qual = (Expr *) stringToNode(str_value);
306 }
307 else
308 policy->with_check_qual = NULL;
309
310 /* We want to cache whether there are SubLinks in these expressions */
311 policy->hassublinks = checkExprHasSubLink((Node *) policy->qual) ||
312 checkExprHasSubLink((Node *) policy->with_check_qual);
313
314 /*
315 * Add this object to list. For historical reasons, the list is built
316 * in reverse order.
317 */
319 rsdesc->policies = lcons(policy, rsdesc->policies);
321 }
322
325
326 /*
327 * Success. Reparent the descriptor's memory context under
328 * CacheMemoryContext so that it will live indefinitely, then attach the
329 * policy descriptor to the relcache entry.
330 */
332
333 relation->rd_rsdesc = rsdesc;
334}
#define NameStr(name)
Definition c.h:894
List * lcons(void *datum, List *list)
Definition list.c:495
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition mcxt.c:1897
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1269
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition mcxt.c:689
void pfree(void *pointer)
Definition mcxt.c:1619
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
MemoryContext CacheMemoryContext
Definition mcxt.c:170
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition memutils.h:170
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition memutils.h:101
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
bool checkExprHasSubLink(Node *node)
struct RowSecurityDesc * rd_rsdesc
Definition rel.h:119

References AccessShareLock, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, BTEqualStrategyNumber, CacheMemoryContext, checkExprHasSubLink(), CurrentMemoryContext, DatumGetArrayTypePCopy, elog, ERROR, fb(), Form_pg_policy, GETSTRUCT(), heap_getattr(), HeapTupleIsValid, lcons(), MemoryContextAllocZero(), MemoryContextCopyAndSetIdentifier, MemoryContextSetParent(), MemoryContextStrdup(), MemoryContextSwitchTo(), NameStr, ObjectIdGetDatum(), pfree(), RelationData::rd_rsdesc, RelationGetDescr, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and TextDatumGetCString.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

◆ RemovePolicyById()

void RemovePolicyById ( Oid  policy_id)

Definition at line 344 of file policy.c.

345{
348 ScanKeyData skey[1];
349 HeapTuple tuple;
350 Oid relid;
351 Relation rel;
352
354
355 /*
356 * Find the policy to delete.
357 */
358 ScanKeyInit(&skey[0],
362
364 NULL, 1, skey);
365
366 tuple = systable_getnext(sscan);
367
368 /* If the policy exists, then remove it, otherwise raise an error. */
369 if (!HeapTupleIsValid(tuple))
370 elog(ERROR, "could not find tuple for policy %u", policy_id);
371
372 /*
373 * Open and exclusive-lock the relation the policy belongs to. (We need
374 * exclusive lock to lock out queries that might otherwise depend on the
375 * set of policies the rel has; furthermore we've got to hold the lock
376 * till commit.)
377 */
378 relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
379
380 rel = table_open(relid, AccessExclusiveLock);
381 if (rel->rd_rel->relkind != RELKIND_RELATION &&
382 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
385 errmsg("\"%s\" is not a table",
387
391 errmsg("permission denied: \"%s\" is a system catalog",
393
395
397
398 /*
399 * Note that, unlike some of the other flags in pg_class, relrowsecurity
400 * is not just an indication of if policies exist. When relrowsecurity is
401 * set by a user, then all access to the relation must be through a
402 * policy. If no policy is defined for the relation then a default-deny
403 * policy is created and all records are filtered (except for queries from
404 * the owner).
405 */
407
408 table_close(rel, NoLock);
409
410 /* Clean up */
412}
bool IsSystemRelation(Relation relation)
Definition catalog.c:74
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
ItemPointerData t_self
Definition htup.h:65
Form_pg_class rd_rel
Definition rel.h:111

References AccessExclusiveLock, allowSystemTableMods, BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleDelete(), elog, ereport, errcode(), errmsg, ERROR, fb(), Form_pg_policy, GETSTRUCT(), HeapTupleIsValid, IsSystemRelation(), NoLock, ObjectIdGetDatum(), RelationData::rd_rel, RelationGetRelationName, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ RemoveRoleFromObjectPolicy()

bool RemoveRoleFromObjectPolicy ( Oid  roleid,
Oid  classid,
Oid  policy_id 
)

Definition at line 428 of file policy.c.

429{
432 ScanKeyData skey[1];
433 HeapTuple tuple;
434 Oid relid;
437 Oid *roles;
438 int num_roles;
440 bool attr_isnull;
441 bool keep_policy = true;
442 int i,
443 j;
444
445 Assert(classid == PolicyRelationId);
446
448
449 /*
450 * Find the policy to update.
451 */
452 ScanKeyInit(&skey[0],
456
458 NULL, 1, skey);
459
460 tuple = systable_getnext(sscan);
461
462 /* Raise an error if we don't find the policy. */
463 if (!HeapTupleIsValid(tuple))
464 elog(ERROR, "could not find tuple for policy %u", policy_id);
465
466 /* Identify rel the policy belongs to */
467 relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
468
469 /* Get the current set of roles */
473 &attr_isnull);
474
476
478 roles = (Oid *) ARR_DATA_PTR(policy_roles);
480
481 /*
482 * Rebuild the polroles array, without any mentions of the target role.
483 * Ordinarily there'd be exactly one, but we must cope with duplicate
484 * mentions, since CREATE/ALTER POLICY historically have allowed that.
485 */
487 for (i = 0, j = 0; i < num_roles; i++)
488 {
489 if (roles[i] != roleid)
490 role_oids[j++] = ObjectIdGetDatum(roles[i]);
491 }
492 num_roles = j;
493
494 /* If any roles remain, update the policy entry. */
495 if (num_roles > 0)
496 {
499 bool isnull[Natts_pg_policy];
503 ObjectAddress target;
505
506 /* zero-clear */
507 memset(values, 0, sizeof(values));
508 memset(replaces, 0, sizeof(replaces));
509 memset(isnull, 0, sizeof(isnull));
510
511 /* This is the array for the new tuple */
513
516
519 values, isnull, replaces);
521
522 /* Remove all the old shared dependencies (roles) */
524
525 /* Record the new shared dependencies (roles) */
526 myself.classId = PolicyRelationId;
527 myself.objectId = policy_id;
528 myself.objectSubId = 0;
529
530 target.classId = AuthIdRelationId;
531 target.objectSubId = 0;
532 for (i = 0; i < num_roles; i++)
533 {
535 /* no need for dependency on the public role */
536 if (target.objectId != ACL_ID_PUBLIC)
539 }
540
542
544
545 /* Make updates visible */
547
548 /*
549 * Invalidate relcache entry for rel the policy belongs to, to force
550 * redoing any dependent plans. In case of a race condition where the
551 * rel was just dropped, we need do nothing.
552 */
555 {
558 }
559 }
560 else
561 {
562 /* No roles would remain, so drop the policy instead. */
563 keep_policy = false;
564 }
565
566 /* Clean up. */
568
570
571 return keep_policy;
572}
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition inval.c:1666
int j
Definition isn.c:78
void CommandCounterIncrement(void)
Definition xact.c:1130

References ACL_ID_PUBLIC, ARR_DATA_PTR, ARR_DIMS, Assert, BTEqualStrategyNumber, CacheInvalidateRelcacheByTuple(), CatalogTupleUpdate(), ObjectAddress::classId, CommandCounterIncrement(), construct_array_builtin(), DatumGetArrayTypePCopy, DatumGetObjectId(), deleteSharedDependencyRecordsFor(), elog, ERROR, fb(), Form_pg_policy, GETSTRUCT(), heap_freetuple(), heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, i, InvokeObjectPostAlterHook, j, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, palloc_array, PointerGetDatum, recordSharedDependencyOn(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), SHARED_DEPENDENCY_POLICY, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and values.

Referenced by shdepDropOwned().

◆ rename_policy()

ObjectAddress rename_policy ( RenameStmt stmt)

Definition at line 1108 of file policy.c.

1109{
1112 Oid table_id;
1113 Oid opoloid;
1114 ScanKeyData skey[2];
1117 ObjectAddress address;
1118
1119 /* Get id of table. Also handles permissions checks. */
1121 0,
1123 stmt);
1124
1126
1128
1129 /* First pass -- check for conflict */
1130
1131 /* Add key - policy's relation id. */
1132 ScanKeyInit(&skey[0],
1136
1137 /* Add key - policy's name. */
1138 ScanKeyInit(&skey[1],
1141 CStringGetDatum(stmt->newname));
1142
1145 skey);
1146
1148 ereport(ERROR,
1150 errmsg("policy \"%s\" for table \"%s\" already exists",
1152
1154
1155 /* Second pass -- find existing policy and update */
1156 /* Add key - policy's relation id. */
1157 ScanKeyInit(&skey[0],
1161
1162 /* Add key - policy's name. */
1163 ScanKeyInit(&skey[1],
1166 CStringGetDatum(stmt->subname));
1167
1170 skey);
1171
1173
1174 /* Complain if we did not find the policy */
1176 ereport(ERROR,
1178 errmsg("policy \"%s\" for table \"%s\" does not exist",
1180
1182
1184
1186 stmt->newname);
1187
1189
1191
1193
1194 /*
1195 * Invalidate relation's relcache entry so that other backends (and this
1196 * one too!) are sent SI message to make them rebuild relcache entries.
1197 * (Ideally this should happen automatically...)
1198 */
1200
1201 /* Clean up. */
1205
1206 return address;
1207}
HeapTuple heap_copytuple(HeapTuple tuple)
Definition heaptuple.c:686
void namestrcpy(Name name, const char *str)
Definition name.c:233
#define ObjectAddressSet(addr, class_id, object_id)

References AccessExclusiveLock, BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), Form_pg_policy, GETSTRUCT(), heap_copytuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, namestrcpy(), NoLock, ObjectAddressSet, ObjectIdGetDatum(), RangeVarCallbackForPolicy(), RangeVarGetRelidExtended(), relation_close(), relation_open(), RelationGetRelationName, RowExclusiveLock, ScanKeyInit(), stmt, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ExecRenameStmt().