1 /*-------------------------------------------------------------------------
4 * Routines to check access control permissions.
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/aclchk.c
16 * The xxx_aclmask() functions in this file are wrappers around
17 * acl.c's aclmask() function; see that for basic usage information.
18 * The wrapper functions add object-type-specific lookup capability.
19 * Generally, they will throw error if the object doesn't exist.
21 * The xxx_aclmask_ext() functions add the ability to not throw
22 * error if the object doesn't exist. If their "is_missing" argument
23 * isn't NULL, then when the object isn't found they will set
24 * *is_missing = true and return zero (no privileges) instead of
25 * throwing an error. Caller must initialize *is_missing = false.
27 * The xxx_aclcheck() functions are simplified wrappers around the
28 * corresponding xxx_aclmask() functions, simply returning ACLCHECK_OK
29 * if any of the privileges specified in "mode" are held, and otherwise
30 * a suitable error code (in practice, always ACLCHECK_NO_PRIV).
31 * Again, they will throw error if the object doesn't exist.
33 * The xxx_aclcheck_ext() functions add the ability to not throw
34 * error if the object doesn't exist. Their "is_missing" argument
35 * works similarly to the xxx_aclmask_ext() functions.
37 *-------------------------------------------------------------------------
41 #include "access/genam.h"
42 #include "access/heapam.h"
43 #include "access/htup_details.h"
44 #include "access/sysattr.h"
45 #include "access/tableam.h"
46 #include "access/xact.h"
47 #include "catalog/binary_upgrade.h"
48 #include "catalog/catalog.h"
49 #include "catalog/dependency.h"
50 #include "catalog/indexing.h"
51 #include "catalog/objectaccess.h"
52 #include "catalog/pg_aggregate.h"
53 #include "catalog/pg_am.h"
54 #include "catalog/pg_authid.h"
55 #include "catalog/pg_cast.h"
56 #include "catalog/pg_class.h"
57 #include "catalog/pg_collation.h"
58 #include "catalog/pg_conversion.h"
59 #include "catalog/pg_database.h"
60 #include "catalog/pg_default_acl.h"
61 #include "catalog/pg_event_trigger.h"
62 #include "catalog/pg_extension.h"
63 #include "catalog/pg_foreign_data_wrapper.h"
64 #include "catalog/pg_foreign_server.h"
65 #include "catalog/pg_init_privs.h"
66 #include "catalog/pg_language.h"
67 #include "catalog/pg_largeobject.h"
68 #include "catalog/pg_largeobject_metadata.h"
69 #include "catalog/pg_namespace.h"
70 #include "catalog/pg_opclass.h"
71 #include "catalog/pg_operator.h"
72 #include "catalog/pg_opfamily.h"
73 #include "catalog/pg_parameter_acl.h"
74 #include "catalog/pg_proc.h"
75 #include "catalog/pg_statistic_ext.h"
76 #include "catalog/pg_subscription.h"
77 #include "catalog/pg_tablespace.h"
78 #include "catalog/pg_transform.h"
79 #include "catalog/pg_ts_config.h"
80 #include "catalog/pg_ts_dict.h"
81 #include "catalog/pg_ts_parser.h"
82 #include "catalog/pg_ts_template.h"
83 #include "catalog/pg_type.h"
84 #include "commands/dbcommands.h"
85 #include "commands/defrem.h"
86 #include "commands/event_trigger.h"
87 #include "commands/extension.h"
88 #include "commands/proclang.h"
89 #include "commands/tablespace.h"
90 #include "foreign/foreign.h"
91 #include "miscadmin.h"
92 #include "nodes/makefuncs.h"
93 #include "parser/parse_func.h"
94 #include "parser/parse_type.h"
95 #include "utils/acl.h"
96 #include "utils/aclchk_internal.h"
97 #include "utils/builtins.h"
98 #include "utils/fmgroids.h"
99 #include "utils/guc.h"
100 #include "utils/lsyscache.h"
101 #include "utils/rel.h"
102 #include "utils/syscache.h"
105 * Internal format used by ALTER DEFAULT PRIVILEGES.
109 Oid roleid
; /* owning role */
110 Oid nspid
; /* namespace, or InvalidOid if none */
111 /* remaining fields are same as in InternalGrant: */
118 DropBehavior behavior
;
119 } InternalDefaultACL
;
122 * When performing a binary-upgrade, pg_dump will call a function to set
123 * this variable to let us know that we need to populate the pg_init_privs
124 * table for the GRANT/REVOKE commands while this variable is set to true.
126 bool binary_upgrade_record_init_privs
= false;
128 static void ExecGrantStmt_oids(InternalGrant
*istmt
);
129 static void ExecGrant_Relation(InternalGrant
*istmt
);
130 static void ExecGrant_common(InternalGrant
*istmt
, Oid classid
, AclMode default_privs
,
131 void (*object_check
) (InternalGrant
*istmt
, HeapTuple tuple
));
132 static void ExecGrant_Language_check(InternalGrant
*istmt
, HeapTuple tuple
);
133 static void ExecGrant_Largeobject(InternalGrant
*istmt
);
134 static void ExecGrant_Type_check(InternalGrant
*istmt
, HeapTuple tuple
);
135 static void ExecGrant_Parameter(InternalGrant
*istmt
);
137 static void SetDefaultACLsInSchemas(InternalDefaultACL
*iacls
, List
*nspnames
);
138 static void SetDefaultACL(InternalDefaultACL
*iacls
);
140 static List
*objectNamesToOids(ObjectType objtype
, List
*objnames
,
142 static List
*objectsInSchemaToOids(ObjectType objtype
, List
*nspnames
);
143 static List
*getRelationsInNamespace(Oid namespaceId
, char relkind
);
144 static void expand_col_privileges(List
*colnames
, Oid table_oid
,
145 AclMode this_privileges
,
146 AclMode
*col_privileges
,
147 int num_col_privileges
);
148 static void expand_all_col_privileges(Oid table_oid
, Form_pg_class classForm
,
149 AclMode this_privileges
,
150 AclMode
*col_privileges
,
151 int num_col_privileges
);
152 static AclMode
string_to_privilege(const char *privname
);
153 static const char *privilege_to_string(AclMode privilege
);
154 static AclMode
restrict_and_check_grant(bool is_grant
, AclMode avail_goptions
,
155 bool all_privs
, AclMode privileges
,
156 Oid objectId
, Oid grantorId
,
157 ObjectType objtype
, const char *objname
,
158 AttrNumber att_number
, const char *colname
);
159 static AclMode
pg_aclmask(ObjectType objtype
, Oid object_oid
, AttrNumber attnum
,
160 Oid roleid
, AclMode mask
, AclMaskHow how
);
161 static AclMode
object_aclmask(Oid classid
, Oid objectid
, Oid roleid
,
162 AclMode mask
, AclMaskHow how
);
163 static AclMode
object_aclmask_ext(Oid classid
, Oid objectid
, Oid roleid
,
164 AclMode mask
, AclMaskHow how
,
166 static AclMode
pg_attribute_aclmask(Oid table_oid
, AttrNumber attnum
,
167 Oid roleid
, AclMode mask
, AclMaskHow how
);
168 static AclMode
pg_attribute_aclmask_ext(Oid table_oid
, AttrNumber attnum
,
169 Oid roleid
, AclMode mask
,
170 AclMaskHow how
, bool *is_missing
);
171 static AclMode
pg_class_aclmask_ext(Oid table_oid
, Oid roleid
,
172 AclMode mask
, AclMaskHow how
,
174 static AclMode
pg_parameter_acl_aclmask(Oid acl_oid
, Oid roleid
,
175 AclMode mask
, AclMaskHow how
);
176 static AclMode
pg_largeobject_aclmask_snapshot(Oid lobj_oid
, Oid roleid
,
177 AclMode mask
, AclMaskHow how
, Snapshot snapshot
);
178 static AclMode
pg_namespace_aclmask_ext(Oid nsp_oid
, Oid roleid
,
179 AclMode mask
, AclMaskHow how
,
181 static AclMode
pg_type_aclmask_ext(Oid type_oid
, Oid roleid
,
182 AclMode mask
, AclMaskHow how
,
184 static void recordExtensionInitPriv(Oid objoid
, Oid classoid
, int objsubid
,
186 static void recordExtensionInitPrivWorker(Oid objoid
, Oid classoid
, int objsubid
,
191 * If is_grant is true, adds the given privileges for the list of
192 * grantees to the existing old_acl. If is_grant is false, the
193 * privileges for the given grantees are removed from old_acl.
195 * NB: the original old_acl is pfree'd.
198 merge_acl_with_grant(Acl
*old_acl
, bool is_grant
,
199 bool grant_option
, DropBehavior behavior
,
200 List
*grantees
, AclMode privileges
,
201 Oid grantorId
, Oid ownerId
)
207 modechg
= is_grant
? ACL_MODECHG_ADD
: ACL_MODECHG_DEL
;
216 aclitem
.ai_grantee
= lfirst_oid(j
);
219 * Grant options can only be granted to individual roles, not PUBLIC.
220 * The reason is that if a user would re-grant a privilege that he
221 * held through PUBLIC, and later the user is removed, the situation
222 * is impossible to clean up.
224 if (is_grant
&& grant_option
&& aclitem
.ai_grantee
== ACL_ID_PUBLIC
)
226 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
227 errmsg("grant options can only be granted to roles")));
229 aclitem
.ai_grantor
= grantorId
;
232 * The asymmetry in the conditions here comes from the spec. In
233 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
234 * to grant both the basic privilege and its grant option. But in
235 * REVOKE, plain revoke revokes both the basic privilege and its grant
236 * option, while REVOKE GRANT OPTION revokes only the option.
238 ACLITEM_SET_PRIVS_GOPTIONS(aclitem
,
239 (is_grant
|| !grant_option
) ? privileges
: ACL_NO_RIGHTS
,
240 (!is_grant
|| grant_option
) ? privileges
: ACL_NO_RIGHTS
);
242 newer_acl
= aclupdate(new_acl
, &aclitem
, modechg
, ownerId
, behavior
);
244 /* avoid memory leak when there are many grantees */
253 * Restrict the privileges to what we can actually grant, and emit
254 * the standards-mandated warning and error messages.
257 restrict_and_check_grant(bool is_grant
, AclMode avail_goptions
, bool all_privs
,
258 AclMode privileges
, Oid objectId
, Oid grantorId
,
259 ObjectType objtype
, const char *objname
,
260 AttrNumber att_number
, const char *colname
)
262 AclMode this_privileges
;
268 whole_mask
= ACL_ALL_RIGHTS_COLUMN
;
271 whole_mask
= ACL_ALL_RIGHTS_RELATION
;
273 case OBJECT_SEQUENCE
:
274 whole_mask
= ACL_ALL_RIGHTS_SEQUENCE
;
276 case OBJECT_DATABASE
:
277 whole_mask
= ACL_ALL_RIGHTS_DATABASE
;
279 case OBJECT_FUNCTION
:
280 whole_mask
= ACL_ALL_RIGHTS_FUNCTION
;
282 case OBJECT_LANGUAGE
:
283 whole_mask
= ACL_ALL_RIGHTS_LANGUAGE
;
285 case OBJECT_LARGEOBJECT
:
286 whole_mask
= ACL_ALL_RIGHTS_LARGEOBJECT
;
289 whole_mask
= ACL_ALL_RIGHTS_SCHEMA
;
291 case OBJECT_TABLESPACE
:
292 whole_mask
= ACL_ALL_RIGHTS_TABLESPACE
;
295 whole_mask
= ACL_ALL_RIGHTS_FDW
;
297 case OBJECT_FOREIGN_SERVER
:
298 whole_mask
= ACL_ALL_RIGHTS_FOREIGN_SERVER
;
300 case OBJECT_EVENT_TRIGGER
:
301 elog(ERROR
, "grantable rights not supported for event triggers");
302 /* not reached, but keep compiler quiet */
303 return ACL_NO_RIGHTS
;
305 whole_mask
= ACL_ALL_RIGHTS_TYPE
;
307 case OBJECT_PARAMETER_ACL
:
308 whole_mask
= ACL_ALL_RIGHTS_PARAMETER_ACL
;
311 elog(ERROR
, "unrecognized object type: %d", objtype
);
312 /* not reached, but keep compiler quiet */
313 return ACL_NO_RIGHTS
;
317 * If we found no grant options, consider whether to issue a hard error.
318 * Per spec, having any privilege at all on the object will get you by
321 if (avail_goptions
== ACL_NO_RIGHTS
)
323 if (pg_aclmask(objtype
, objectId
, att_number
, grantorId
,
324 whole_mask
| ACL_GRANT_OPTION_FOR(whole_mask
),
325 ACLMASK_ANY
) == ACL_NO_RIGHTS
)
327 if (objtype
== OBJECT_COLUMN
&& colname
)
328 aclcheck_error_col(ACLCHECK_NO_PRIV
, objtype
, objname
, colname
);
330 aclcheck_error(ACLCHECK_NO_PRIV
, objtype
, objname
);
335 * Restrict the operation to what we can actually grant or revoke, and
336 * issue a warning if appropriate. (For REVOKE this isn't quite what the
337 * spec says to do: the spec seems to want a warning only if no privilege
338 * bits actually change in the ACL. In practice that behavior seems much
339 * too noisy, as well as inconsistent with the GRANT case.)
341 this_privileges
= privileges
& ACL_OPTION_TO_PRIVS(avail_goptions
);
344 if (this_privileges
== 0)
346 if (objtype
== OBJECT_COLUMN
&& colname
)
348 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED
),
349 errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
353 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED
),
354 errmsg("no privileges were granted for \"%s\"",
357 else if (!all_privs
&& this_privileges
!= privileges
)
359 if (objtype
== OBJECT_COLUMN
&& colname
)
361 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED
),
362 errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
366 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED
),
367 errmsg("not all privileges were granted for \"%s\"",
373 if (this_privileges
== 0)
375 if (objtype
== OBJECT_COLUMN
&& colname
)
377 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED
),
378 errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
382 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED
),
383 errmsg("no privileges could be revoked for \"%s\"",
386 else if (!all_privs
&& this_privileges
!= privileges
)
388 if (objtype
== OBJECT_COLUMN
&& colname
)
390 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED
),
391 errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
395 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED
),
396 errmsg("not all privileges could be revoked for \"%s\"",
401 return this_privileges
;
405 * Called to execute the utility commands GRANT and REVOKE
408 ExecuteGrantStmt(GrantStmt
*stmt
)
412 const char *errormsg
;
413 AclMode all_privileges
;
419 grantor
= get_rolespec_oid(stmt
->grantor
, false);
422 * Currently, this clause is only for SQL compatibility, not very
423 * interesting otherwise.
425 if (grantor
!= GetUserId())
427 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
428 errmsg("grantor must be current user")));
432 * Turn the regular GrantStmt into the InternalGrant form.
434 istmt
.is_grant
= stmt
->is_grant
;
435 istmt
.objtype
= stmt
->objtype
;
437 /* Collect the OIDs of the target objects */
438 switch (stmt
->targtype
)
440 case ACL_TARGET_OBJECT
:
441 istmt
.objects
= objectNamesToOids(stmt
->objtype
, stmt
->objects
,
444 case ACL_TARGET_ALL_IN_SCHEMA
:
445 istmt
.objects
= objectsInSchemaToOids(stmt
->objtype
, stmt
->objects
);
447 /* ACL_TARGET_DEFAULTS should not be seen here */
449 elog(ERROR
, "unrecognized GrantStmt.targtype: %d",
450 (int) stmt
->targtype
);
453 /* all_privs to be filled below */
454 /* privileges to be filled below */
455 istmt
.col_privs
= NIL
; /* may get filled below */
456 istmt
.grantees
= NIL
; /* filled below */
457 istmt
.grant_option
= stmt
->grant_option
;
458 istmt
.behavior
= stmt
->behavior
;
461 * Convert the RoleSpec list into an Oid list. Note that at this point we
462 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
463 * there shouldn't be any additional work needed to support this case.
465 foreach(cell
, stmt
->grantees
)
467 RoleSpec
*grantee
= (RoleSpec
*) lfirst(cell
);
470 switch (grantee
->roletype
)
472 case ROLESPEC_PUBLIC
:
473 grantee_uid
= ACL_ID_PUBLIC
;
476 grantee_uid
= get_rolespec_oid(grantee
, false);
479 istmt
.grantees
= lappend_oid(istmt
.grantees
, grantee_uid
);
483 * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
484 * bitmask. Note: objtype can't be OBJECT_COLUMN.
486 switch (stmt
->objtype
)
491 * Because this might be a sequence, we test both relation and
492 * sequence bits, and later do a more limited test when we know
495 all_privileges
= ACL_ALL_RIGHTS_RELATION
| ACL_ALL_RIGHTS_SEQUENCE
;
496 errormsg
= gettext_noop("invalid privilege type %s for relation");
498 case OBJECT_SEQUENCE
:
499 all_privileges
= ACL_ALL_RIGHTS_SEQUENCE
;
500 errormsg
= gettext_noop("invalid privilege type %s for sequence");
502 case OBJECT_DATABASE
:
503 all_privileges
= ACL_ALL_RIGHTS_DATABASE
;
504 errormsg
= gettext_noop("invalid privilege type %s for database");
507 all_privileges
= ACL_ALL_RIGHTS_TYPE
;
508 errormsg
= gettext_noop("invalid privilege type %s for domain");
510 case OBJECT_FUNCTION
:
511 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
512 errormsg
= gettext_noop("invalid privilege type %s for function");
514 case OBJECT_LANGUAGE
:
515 all_privileges
= ACL_ALL_RIGHTS_LANGUAGE
;
516 errormsg
= gettext_noop("invalid privilege type %s for language");
518 case OBJECT_LARGEOBJECT
:
519 all_privileges
= ACL_ALL_RIGHTS_LARGEOBJECT
;
520 errormsg
= gettext_noop("invalid privilege type %s for large object");
523 all_privileges
= ACL_ALL_RIGHTS_SCHEMA
;
524 errormsg
= gettext_noop("invalid privilege type %s for schema");
526 case OBJECT_PROCEDURE
:
527 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
528 errormsg
= gettext_noop("invalid privilege type %s for procedure");
531 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
532 errormsg
= gettext_noop("invalid privilege type %s for routine");
534 case OBJECT_TABLESPACE
:
535 all_privileges
= ACL_ALL_RIGHTS_TABLESPACE
;
536 errormsg
= gettext_noop("invalid privilege type %s for tablespace");
539 all_privileges
= ACL_ALL_RIGHTS_TYPE
;
540 errormsg
= gettext_noop("invalid privilege type %s for type");
543 all_privileges
= ACL_ALL_RIGHTS_FDW
;
544 errormsg
= gettext_noop("invalid privilege type %s for foreign-data wrapper");
546 case OBJECT_FOREIGN_SERVER
:
547 all_privileges
= ACL_ALL_RIGHTS_FOREIGN_SERVER
;
548 errormsg
= gettext_noop("invalid privilege type %s for foreign server");
550 case OBJECT_PARAMETER_ACL
:
551 all_privileges
= ACL_ALL_RIGHTS_PARAMETER_ACL
;
552 errormsg
= gettext_noop("invalid privilege type %s for parameter");
555 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
556 (int) stmt
->objtype
);
557 /* keep compiler quiet */
558 all_privileges
= ACL_NO_RIGHTS
;
562 if (stmt
->privileges
== NIL
)
564 istmt
.all_privs
= true;
567 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
568 * depending on the object type
570 istmt
.privileges
= ACL_NO_RIGHTS
;
574 istmt
.all_privs
= false;
575 istmt
.privileges
= ACL_NO_RIGHTS
;
577 foreach(cell
, stmt
->privileges
)
579 AccessPriv
*privnode
= (AccessPriv
*) lfirst(cell
);
583 * If it's a column-level specification, we just set it aside in
584 * col_privs for the moment; but insist it's for a relation.
588 if (stmt
->objtype
!= OBJECT_TABLE
)
590 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
591 errmsg("column privileges are only valid for relations")));
592 istmt
.col_privs
= lappend(istmt
.col_privs
, privnode
);
596 if (privnode
->priv_name
== NULL
) /* parser mistake? */
597 elog(ERROR
, "AccessPriv node must specify privilege or columns");
598 priv
= string_to_privilege(privnode
->priv_name
);
600 if (priv
& ~((AclMode
) all_privileges
))
602 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
603 errmsg(errormsg
, privilege_to_string(priv
))));
605 istmt
.privileges
|= priv
;
609 ExecGrantStmt_oids(&istmt
);
615 * Internal entry point for granting and revoking privileges.
618 ExecGrantStmt_oids(InternalGrant
*istmt
)
620 switch (istmt
->objtype
)
623 case OBJECT_SEQUENCE
:
624 ExecGrant_Relation(istmt
);
626 case OBJECT_DATABASE
:
627 ExecGrant_common(istmt
, DatabaseRelationId
, ACL_ALL_RIGHTS_DATABASE
, NULL
);
631 ExecGrant_common(istmt
, TypeRelationId
, ACL_ALL_RIGHTS_TYPE
, ExecGrant_Type_check
);
634 ExecGrant_common(istmt
, ForeignDataWrapperRelationId
, ACL_ALL_RIGHTS_FDW
, NULL
);
636 case OBJECT_FOREIGN_SERVER
:
637 ExecGrant_common(istmt
, ForeignServerRelationId
, ACL_ALL_RIGHTS_FOREIGN_SERVER
, NULL
);
639 case OBJECT_FUNCTION
:
640 case OBJECT_PROCEDURE
:
642 ExecGrant_common(istmt
, ProcedureRelationId
, ACL_ALL_RIGHTS_FUNCTION
, NULL
);
644 case OBJECT_LANGUAGE
:
645 ExecGrant_common(istmt
, LanguageRelationId
, ACL_ALL_RIGHTS_LANGUAGE
, ExecGrant_Language_check
);
647 case OBJECT_LARGEOBJECT
:
648 ExecGrant_Largeobject(istmt
);
651 ExecGrant_common(istmt
, NamespaceRelationId
, ACL_ALL_RIGHTS_SCHEMA
, NULL
);
653 case OBJECT_TABLESPACE
:
654 ExecGrant_common(istmt
, TableSpaceRelationId
, ACL_ALL_RIGHTS_TABLESPACE
, NULL
);
656 case OBJECT_PARAMETER_ACL
:
657 ExecGrant_Parameter(istmt
);
660 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
661 (int) istmt
->objtype
);
665 * Pass the info to event triggers about the just-executed GRANT. Note
666 * that we prefer to do it after actually executing it, because that gives
667 * the functions a chance to adjust the istmt with privileges actually
670 if (EventTriggerSupportsObjectType(istmt
->objtype
))
671 EventTriggerCollectGrant(istmt
);
677 * Turn a list of object names of a given type into an Oid list.
679 * XXX: This function doesn't take any sort of locks on the objects whose
680 * names it looks up. In the face of concurrent DDL, we might easily latch
681 * onto an old version of an object, causing the GRANT or REVOKE statement
685 objectNamesToOids(ObjectType objtype
, List
*objnames
, bool is_grant
)
690 Assert(objnames
!= NIL
);
695 case OBJECT_SEQUENCE
:
696 foreach(cell
, objnames
)
698 RangeVar
*relvar
= (RangeVar
*) lfirst(cell
);
701 relOid
= RangeVarGetRelid(relvar
, NoLock
, false);
702 objects
= lappend_oid(objects
, relOid
);
705 case OBJECT_DATABASE
:
706 foreach(cell
, objnames
)
708 char *dbname
= strVal(lfirst(cell
));
711 dbid
= get_database_oid(dbname
, false);
712 objects
= lappend_oid(objects
, dbid
);
717 foreach(cell
, objnames
)
719 List
*typname
= (List
*) lfirst(cell
);
722 oid
= typenameTypeId(NULL
, makeTypeNameFromNameList(typname
));
723 objects
= lappend_oid(objects
, oid
);
726 case OBJECT_FUNCTION
:
727 foreach(cell
, objnames
)
729 ObjectWithArgs
*func
= (ObjectWithArgs
*) lfirst(cell
);
732 funcid
= LookupFuncWithArgs(OBJECT_FUNCTION
, func
, false);
733 objects
= lappend_oid(objects
, funcid
);
736 case OBJECT_LANGUAGE
:
737 foreach(cell
, objnames
)
739 char *langname
= strVal(lfirst(cell
));
742 oid
= get_language_oid(langname
, false);
743 objects
= lappend_oid(objects
, oid
);
746 case OBJECT_LARGEOBJECT
:
747 foreach(cell
, objnames
)
749 Oid lobjOid
= oidparse(lfirst(cell
));
751 if (!LargeObjectExists(lobjOid
))
753 (errcode(ERRCODE_UNDEFINED_OBJECT
),
754 errmsg("large object %u does not exist",
757 objects
= lappend_oid(objects
, lobjOid
);
761 foreach(cell
, objnames
)
763 char *nspname
= strVal(lfirst(cell
));
766 oid
= get_namespace_oid(nspname
, false);
767 objects
= lappend_oid(objects
, oid
);
770 case OBJECT_PROCEDURE
:
771 foreach(cell
, objnames
)
773 ObjectWithArgs
*func
= (ObjectWithArgs
*) lfirst(cell
);
776 procid
= LookupFuncWithArgs(OBJECT_PROCEDURE
, func
, false);
777 objects
= lappend_oid(objects
, procid
);
781 foreach(cell
, objnames
)
783 ObjectWithArgs
*func
= (ObjectWithArgs
*) lfirst(cell
);
786 routid
= LookupFuncWithArgs(OBJECT_ROUTINE
, func
, false);
787 objects
= lappend_oid(objects
, routid
);
790 case OBJECT_TABLESPACE
:
791 foreach(cell
, objnames
)
793 char *spcname
= strVal(lfirst(cell
));
796 spcoid
= get_tablespace_oid(spcname
, false);
797 objects
= lappend_oid(objects
, spcoid
);
801 foreach(cell
, objnames
)
803 char *fdwname
= strVal(lfirst(cell
));
804 Oid fdwid
= get_foreign_data_wrapper_oid(fdwname
, false);
806 objects
= lappend_oid(objects
, fdwid
);
809 case OBJECT_FOREIGN_SERVER
:
810 foreach(cell
, objnames
)
812 char *srvname
= strVal(lfirst(cell
));
813 Oid srvid
= get_foreign_server_oid(srvname
, false);
815 objects
= lappend_oid(objects
, srvid
);
818 case OBJECT_PARAMETER_ACL
:
819 foreach(cell
, objnames
)
822 * In this code we represent a GUC by the OID of its entry in
823 * pg_parameter_acl, which we have to manufacture here if it
824 * doesn't exist yet. (That's a hack for sure, but it avoids
825 * messing with all the GRANT/REVOKE infrastructure that
826 * expects to use OIDs for object identities.) However, if
827 * this is a REVOKE, we can instead just ignore any GUCs that
828 * don't have such an entry, as they must not have any
829 * privileges needing removal.
831 char *parameter
= strVal(lfirst(cell
));
832 Oid parameterId
= ParameterAclLookup(parameter
, true);
834 if (!OidIsValid(parameterId
) && is_grant
)
836 parameterId
= ParameterAclCreate(parameter
);
839 * Prevent error when processing duplicate objects, and
840 * make this new entry visible so that ExecGrant_Parameter
843 CommandCounterIncrement();
845 if (OidIsValid(parameterId
))
846 objects
= lappend_oid(objects
, parameterId
);
850 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
858 * objectsInSchemaToOids
860 * Find all objects of a given type in specified schemas, and make a list
861 * of their Oids. We check USAGE privilege on the schemas, but there is
862 * no privilege checking on the individual objects here.
865 objectsInSchemaToOids(ObjectType objtype
, List
*nspnames
)
870 foreach(cell
, nspnames
)
872 char *nspname
= strVal(lfirst(cell
));
876 namespaceId
= LookupExplicitNamespace(nspname
, false);
881 objs
= getRelationsInNamespace(namespaceId
, RELKIND_RELATION
);
882 objects
= list_concat(objects
, objs
);
883 objs
= getRelationsInNamespace(namespaceId
, RELKIND_VIEW
);
884 objects
= list_concat(objects
, objs
);
885 objs
= getRelationsInNamespace(namespaceId
, RELKIND_MATVIEW
);
886 objects
= list_concat(objects
, objs
);
887 objs
= getRelationsInNamespace(namespaceId
, RELKIND_FOREIGN_TABLE
);
888 objects
= list_concat(objects
, objs
);
889 objs
= getRelationsInNamespace(namespaceId
, RELKIND_PARTITIONED_TABLE
);
890 objects
= list_concat(objects
, objs
);
892 case OBJECT_SEQUENCE
:
893 objs
= getRelationsInNamespace(namespaceId
, RELKIND_SEQUENCE
);
894 objects
= list_concat(objects
, objs
);
896 case OBJECT_FUNCTION
:
897 case OBJECT_PROCEDURE
:
907 ScanKeyInit(&key
[keycount
++],
908 Anum_pg_proc_pronamespace
,
909 BTEqualStrategyNumber
, F_OIDEQ
,
910 ObjectIdGetDatum(namespaceId
));
912 if (objtype
== OBJECT_FUNCTION
)
913 /* includes aggregates and window functions */
914 ScanKeyInit(&key
[keycount
++],
915 Anum_pg_proc_prokind
,
916 BTEqualStrategyNumber
, F_CHARNE
,
917 CharGetDatum(PROKIND_PROCEDURE
));
918 else if (objtype
== OBJECT_PROCEDURE
)
919 ScanKeyInit(&key
[keycount
++],
920 Anum_pg_proc_prokind
,
921 BTEqualStrategyNumber
, F_CHAREQ
,
922 CharGetDatum(PROKIND_PROCEDURE
));
924 rel
= table_open(ProcedureRelationId
, AccessShareLock
);
925 scan
= table_beginscan_catalog(rel
, keycount
, key
);
927 while ((tuple
= heap_getnext(scan
, ForwardScanDirection
)) != NULL
)
929 Oid oid
= ((Form_pg_proc
) GETSTRUCT(tuple
))->oid
;
931 objects
= lappend_oid(objects
, oid
);
935 table_close(rel
, AccessShareLock
);
939 /* should not happen */
940 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
949 * getRelationsInNamespace
951 * Return Oid list of relations in given namespace filtered by relation kind
954 getRelationsInNamespace(Oid namespaceId
, char relkind
)
956 List
*relations
= NIL
;
963 Anum_pg_class_relnamespace
,
964 BTEqualStrategyNumber
, F_OIDEQ
,
965 ObjectIdGetDatum(namespaceId
));
967 Anum_pg_class_relkind
,
968 BTEqualStrategyNumber
, F_CHAREQ
,
969 CharGetDatum(relkind
));
971 rel
= table_open(RelationRelationId
, AccessShareLock
);
972 scan
= table_beginscan_catalog(rel
, 2, key
);
974 while ((tuple
= heap_getnext(scan
, ForwardScanDirection
)) != NULL
)
976 Oid oid
= ((Form_pg_class
) GETSTRUCT(tuple
))->oid
;
978 relations
= lappend_oid(relations
, oid
);
982 table_close(rel
, AccessShareLock
);
989 * ALTER DEFAULT PRIVILEGES statement
992 ExecAlterDefaultPrivilegesStmt(ParseState
*pstate
, AlterDefaultPrivilegesStmt
*stmt
)
994 GrantStmt
*action
= stmt
->action
;
995 InternalDefaultACL iacls
;
997 List
*rolespecs
= NIL
;
998 List
*nspnames
= NIL
;
999 DefElem
*drolespecs
= NULL
;
1000 DefElem
*dnspnames
= NULL
;
1001 AclMode all_privileges
;
1002 const char *errormsg
;
1004 /* Deconstruct the "options" part of the statement */
1005 foreach(cell
, stmt
->options
)
1007 DefElem
*defel
= (DefElem
*) lfirst(cell
);
1009 if (strcmp(defel
->defname
, "schemas") == 0)
1012 errorConflictingDefElem(defel
, pstate
);
1015 else if (strcmp(defel
->defname
, "roles") == 0)
1018 errorConflictingDefElem(defel
, pstate
);
1022 elog(ERROR
, "option \"%s\" not recognized", defel
->defname
);
1026 nspnames
= (List
*) dnspnames
->arg
;
1028 rolespecs
= (List
*) drolespecs
->arg
;
1030 /* Prepare the InternalDefaultACL representation of the statement */
1031 /* roleid to be filled below */
1032 /* nspid to be filled in SetDefaultACLsInSchemas */
1033 iacls
.is_grant
= action
->is_grant
;
1034 iacls
.objtype
= action
->objtype
;
1035 /* all_privs to be filled below */
1036 /* privileges to be filled below */
1037 iacls
.grantees
= NIL
; /* filled below */
1038 iacls
.grant_option
= action
->grant_option
;
1039 iacls
.behavior
= action
->behavior
;
1042 * Convert the RoleSpec list into an Oid list. Note that at this point we
1043 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
1044 * there shouldn't be any additional work needed to support this case.
1046 foreach(cell
, action
->grantees
)
1048 RoleSpec
*grantee
= (RoleSpec
*) lfirst(cell
);
1051 switch (grantee
->roletype
)
1053 case ROLESPEC_PUBLIC
:
1054 grantee_uid
= ACL_ID_PUBLIC
;
1057 grantee_uid
= get_rolespec_oid(grantee
, false);
1060 iacls
.grantees
= lappend_oid(iacls
.grantees
, grantee_uid
);
1064 * Convert action->privileges, a list of privilege strings, into an
1067 switch (action
->objtype
)
1070 all_privileges
= ACL_ALL_RIGHTS_RELATION
;
1071 errormsg
= gettext_noop("invalid privilege type %s for relation");
1073 case OBJECT_SEQUENCE
:
1074 all_privileges
= ACL_ALL_RIGHTS_SEQUENCE
;
1075 errormsg
= gettext_noop("invalid privilege type %s for sequence");
1077 case OBJECT_FUNCTION
:
1078 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
1079 errormsg
= gettext_noop("invalid privilege type %s for function");
1081 case OBJECT_PROCEDURE
:
1082 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
1083 errormsg
= gettext_noop("invalid privilege type %s for procedure");
1085 case OBJECT_ROUTINE
:
1086 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
1087 errormsg
= gettext_noop("invalid privilege type %s for routine");
1090 all_privileges
= ACL_ALL_RIGHTS_TYPE
;
1091 errormsg
= gettext_noop("invalid privilege type %s for type");
1094 all_privileges
= ACL_ALL_RIGHTS_SCHEMA
;
1095 errormsg
= gettext_noop("invalid privilege type %s for schema");
1098 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
1099 (int) action
->objtype
);
1100 /* keep compiler quiet */
1101 all_privileges
= ACL_NO_RIGHTS
;
1105 if (action
->privileges
== NIL
)
1107 iacls
.all_privs
= true;
1110 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1111 * depending on the object type
1113 iacls
.privileges
= ACL_NO_RIGHTS
;
1117 iacls
.all_privs
= false;
1118 iacls
.privileges
= ACL_NO_RIGHTS
;
1120 foreach(cell
, action
->privileges
)
1122 AccessPriv
*privnode
= (AccessPriv
*) lfirst(cell
);
1127 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1128 errmsg("default privileges cannot be set for columns")));
1130 if (privnode
->priv_name
== NULL
) /* parser mistake? */
1131 elog(ERROR
, "AccessPriv node must specify privilege");
1132 priv
= string_to_privilege(privnode
->priv_name
);
1134 if (priv
& ~((AclMode
) all_privileges
))
1136 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1137 errmsg(errormsg
, privilege_to_string(priv
))));
1139 iacls
.privileges
|= priv
;
1143 if (rolespecs
== NIL
)
1145 /* Set permissions for myself */
1146 iacls
.roleid
= GetUserId();
1148 SetDefaultACLsInSchemas(&iacls
, nspnames
);
1152 /* Look up the role OIDs and do permissions checks */
1155 foreach(rolecell
, rolespecs
)
1157 RoleSpec
*rolespec
= lfirst(rolecell
);
1159 iacls
.roleid
= get_rolespec_oid(rolespec
, false);
1161 if (!has_privs_of_role(GetUserId(), iacls
.roleid
))
1163 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1164 errmsg("permission denied to change default privileges")));
1166 SetDefaultACLsInSchemas(&iacls
, nspnames
);
1172 * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
1174 * All fields of *iacls except nspid were filled already
1177 SetDefaultACLsInSchemas(InternalDefaultACL
*iacls
, List
*nspnames
)
1179 if (nspnames
== NIL
)
1181 /* Set database-wide permissions if no schema was specified */
1182 iacls
->nspid
= InvalidOid
;
1184 SetDefaultACL(iacls
);
1188 /* Look up the schema OIDs and set permissions for each one */
1191 foreach(nspcell
, nspnames
)
1193 char *nspname
= strVal(lfirst(nspcell
));
1195 iacls
->nspid
= get_namespace_oid(nspname
, false);
1198 * We used to insist that the target role have CREATE privileges
1199 * on the schema, since without that it wouldn't be able to create
1200 * an object for which these default privileges would apply.
1201 * However, this check proved to be more confusing than helpful,
1202 * and it also caused certain database states to not be
1203 * dumpable/restorable, since revoking CREATE doesn't cause
1204 * default privileges for the schema to go away. So now, we just
1205 * allow the ALTER; if the user lacks CREATE he'll find out when
1206 * he tries to create an object.
1209 SetDefaultACL(iacls
);
1216 * Create or update a pg_default_acl entry
1219 SetDefaultACL(InternalDefaultACL
*iacls
)
1221 AclMode this_privileges
= iacls
->privileges
;
1235 rel
= table_open(DefaultAclRelationId
, RowExclusiveLock
);
1238 * The default for a global entry is the hard-wired default ACL for the
1239 * particular object type. The default for non-global entries is an empty
1240 * ACL. This must be so because global entries replace the hard-wired
1241 * defaults, while others are added on.
1243 if (!OidIsValid(iacls
->nspid
))
1244 def_acl
= acldefault(iacls
->objtype
, iacls
->roleid
);
1246 def_acl
= make_empty_acl();
1249 * Convert ACL object type to pg_default_acl object type and handle
1252 switch (iacls
->objtype
)
1255 objtype
= DEFACLOBJ_RELATION
;
1256 if (iacls
->all_privs
&& this_privileges
== ACL_NO_RIGHTS
)
1257 this_privileges
= ACL_ALL_RIGHTS_RELATION
;
1260 case OBJECT_SEQUENCE
:
1261 objtype
= DEFACLOBJ_SEQUENCE
;
1262 if (iacls
->all_privs
&& this_privileges
== ACL_NO_RIGHTS
)
1263 this_privileges
= ACL_ALL_RIGHTS_SEQUENCE
;
1266 case OBJECT_FUNCTION
:
1267 objtype
= DEFACLOBJ_FUNCTION
;
1268 if (iacls
->all_privs
&& this_privileges
== ACL_NO_RIGHTS
)
1269 this_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
1273 objtype
= DEFACLOBJ_TYPE
;
1274 if (iacls
->all_privs
&& this_privileges
== ACL_NO_RIGHTS
)
1275 this_privileges
= ACL_ALL_RIGHTS_TYPE
;
1279 if (OidIsValid(iacls
->nspid
))
1281 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1282 errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
1283 objtype
= DEFACLOBJ_NAMESPACE
;
1284 if (iacls
->all_privs
&& this_privileges
== ACL_NO_RIGHTS
)
1285 this_privileges
= ACL_ALL_RIGHTS_SCHEMA
;
1289 elog(ERROR
, "unrecognized object type: %d",
1290 (int) iacls
->objtype
);
1291 objtype
= 0; /* keep compiler quiet */
1295 /* Search for existing row for this object type in catalog */
1296 tuple
= SearchSysCache3(DEFACLROLENSPOBJ
,
1297 ObjectIdGetDatum(iacls
->roleid
),
1298 ObjectIdGetDatum(iacls
->nspid
),
1299 CharGetDatum(objtype
));
1301 if (HeapTupleIsValid(tuple
))
1306 aclDatum
= SysCacheGetAttr(DEFACLROLENSPOBJ
, tuple
,
1307 Anum_pg_default_acl_defaclacl
,
1310 old_acl
= DatumGetAclPCopy(aclDatum
);
1312 old_acl
= NULL
; /* this case shouldn't happen, probably */
1321 if (old_acl
!= NULL
)
1324 * We need the members of both old and new ACLs so we can correct the
1325 * shared dependency information. Collect data before
1326 * merge_acl_with_grant throws away old_acl.
1328 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1332 /* If no or null entry, start with the default ACL value */
1333 old_acl
= aclcopy(def_acl
);
1334 /* There are no old member roles according to the catalogs */
1340 * Generate new ACL. Grantor of rights is always the same as the target
1343 new_acl
= merge_acl_with_grant(old_acl
,
1345 iacls
->grant_option
,
1353 * If the result is the same as the default value, we do not need an
1354 * explicit pg_default_acl entry, and should in fact remove the entry if
1355 * it exists. Must sort both arrays to compare properly.
1357 aclitemsort(new_acl
);
1358 aclitemsort(def_acl
);
1359 if (aclequal(new_acl
, def_acl
))
1361 /* delete old entry, if indeed there is one */
1364 ObjectAddress myself
;
1367 * The dependency machinery will take care of removing all
1368 * associated dependency entries. We use DROP_RESTRICT since
1369 * there shouldn't be anything depending on this entry.
1371 myself
.classId
= DefaultAclRelationId
;
1372 myself
.objectId
= ((Form_pg_default_acl
) GETSTRUCT(tuple
))->oid
;
1373 myself
.objectSubId
= 0;
1375 performDeletion(&myself
, DROP_RESTRICT
, 0);
1380 Datum values
[Natts_pg_default_acl
] = {0};
1381 bool nulls
[Natts_pg_default_acl
] = {0};
1382 bool replaces
[Natts_pg_default_acl
] = {0};
1387 /* insert new entry */
1388 defAclOid
= GetNewOidWithIndex(rel
, DefaultAclOidIndexId
,
1389 Anum_pg_default_acl_oid
);
1390 values
[Anum_pg_default_acl_oid
- 1] = ObjectIdGetDatum(defAclOid
);
1391 values
[Anum_pg_default_acl_defaclrole
- 1] = ObjectIdGetDatum(iacls
->roleid
);
1392 values
[Anum_pg_default_acl_defaclnamespace
- 1] = ObjectIdGetDatum(iacls
->nspid
);
1393 values
[Anum_pg_default_acl_defaclobjtype
- 1] = CharGetDatum(objtype
);
1394 values
[Anum_pg_default_acl_defaclacl
- 1] = PointerGetDatum(new_acl
);
1396 newtuple
= heap_form_tuple(RelationGetDescr(rel
), values
, nulls
);
1397 CatalogTupleInsert(rel
, newtuple
);
1401 defAclOid
= ((Form_pg_default_acl
) GETSTRUCT(tuple
))->oid
;
1403 /* update existing entry */
1404 values
[Anum_pg_default_acl_defaclacl
- 1] = PointerGetDatum(new_acl
);
1405 replaces
[Anum_pg_default_acl_defaclacl
- 1] = true;
1407 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(rel
),
1408 values
, nulls
, replaces
);
1409 CatalogTupleUpdate(rel
, &newtuple
->t_self
, newtuple
);
1412 /* these dependencies don't change in an update */
1415 /* dependency on role */
1416 recordDependencyOnOwner(DefaultAclRelationId
, defAclOid
,
1419 /* dependency on namespace */
1420 if (OidIsValid(iacls
->nspid
))
1422 ObjectAddress myself
,
1425 myself
.classId
= DefaultAclRelationId
;
1426 myself
.objectId
= defAclOid
;
1427 myself
.objectSubId
= 0;
1429 referenced
.classId
= NamespaceRelationId
;
1430 referenced
.objectId
= iacls
->nspid
;
1431 referenced
.objectSubId
= 0;
1433 recordDependencyOn(&myself
, &referenced
, DEPENDENCY_AUTO
);
1438 * Update the shared dependency ACL info
1440 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1442 updateAclDependencies(DefaultAclRelationId
,
1445 noldmembers
, oldmembers
,
1446 nnewmembers
, newmembers
);
1449 InvokeObjectPostCreateHook(DefaultAclRelationId
, defAclOid
, 0);
1451 InvokeObjectPostAlterHook(DefaultAclRelationId
, defAclOid
, 0);
1454 if (HeapTupleIsValid(tuple
))
1455 ReleaseSysCache(tuple
);
1457 table_close(rel
, RowExclusiveLock
);
1459 /* prevent error when processing duplicate objects */
1460 CommandCounterIncrement();
1465 * RemoveRoleFromObjectACL
1467 * Used by shdepDropOwned to remove mentions of a role in ACLs
1470 RemoveRoleFromObjectACL(Oid roleid
, Oid classid
, Oid objid
)
1472 if (classid
== DefaultAclRelationId
)
1474 InternalDefaultACL iacls
;
1475 Form_pg_default_acl pg_default_acl_tuple
;
1477 ScanKeyData skey
[1];
1481 /* first fetch info needed by SetDefaultACL */
1482 rel
= table_open(DefaultAclRelationId
, AccessShareLock
);
1484 ScanKeyInit(&skey
[0],
1485 Anum_pg_default_acl_oid
,
1486 BTEqualStrategyNumber
, F_OIDEQ
,
1487 ObjectIdGetDatum(objid
));
1489 scan
= systable_beginscan(rel
, DefaultAclOidIndexId
, true,
1492 tuple
= systable_getnext(scan
);
1494 if (!HeapTupleIsValid(tuple
))
1495 elog(ERROR
, "could not find tuple for default ACL %u", objid
);
1497 pg_default_acl_tuple
= (Form_pg_default_acl
) GETSTRUCT(tuple
);
1499 iacls
.roleid
= pg_default_acl_tuple
->defaclrole
;
1500 iacls
.nspid
= pg_default_acl_tuple
->defaclnamespace
;
1502 switch (pg_default_acl_tuple
->defaclobjtype
)
1504 case DEFACLOBJ_RELATION
:
1505 iacls
.objtype
= OBJECT_TABLE
;
1507 case DEFACLOBJ_SEQUENCE
:
1508 iacls
.objtype
= OBJECT_SEQUENCE
;
1510 case DEFACLOBJ_FUNCTION
:
1511 iacls
.objtype
= OBJECT_FUNCTION
;
1513 case DEFACLOBJ_TYPE
:
1514 iacls
.objtype
= OBJECT_TYPE
;
1516 case DEFACLOBJ_NAMESPACE
:
1517 iacls
.objtype
= OBJECT_SCHEMA
;
1520 /* Shouldn't get here */
1521 elog(ERROR
, "unexpected default ACL type: %d",
1522 (int) pg_default_acl_tuple
->defaclobjtype
);
1526 systable_endscan(scan
);
1527 table_close(rel
, AccessShareLock
);
1529 iacls
.is_grant
= false;
1530 iacls
.all_privs
= true;
1531 iacls
.privileges
= ACL_NO_RIGHTS
;
1532 iacls
.grantees
= list_make1_oid(roleid
);
1533 iacls
.grant_option
= false;
1534 iacls
.behavior
= DROP_CASCADE
;
1537 SetDefaultACL(&iacls
);
1541 InternalGrant istmt
;
1545 case RelationRelationId
:
1546 /* it's OK to use TABLE for a sequence */
1547 istmt
.objtype
= OBJECT_TABLE
;
1549 case DatabaseRelationId
:
1550 istmt
.objtype
= OBJECT_DATABASE
;
1552 case TypeRelationId
:
1553 istmt
.objtype
= OBJECT_TYPE
;
1555 case ProcedureRelationId
:
1556 istmt
.objtype
= OBJECT_ROUTINE
;
1558 case LanguageRelationId
:
1559 istmt
.objtype
= OBJECT_LANGUAGE
;
1561 case LargeObjectRelationId
:
1562 istmt
.objtype
= OBJECT_LARGEOBJECT
;
1564 case NamespaceRelationId
:
1565 istmt
.objtype
= OBJECT_SCHEMA
;
1567 case TableSpaceRelationId
:
1568 istmt
.objtype
= OBJECT_TABLESPACE
;
1570 case ForeignServerRelationId
:
1571 istmt
.objtype
= OBJECT_FOREIGN_SERVER
;
1573 case ForeignDataWrapperRelationId
:
1574 istmt
.objtype
= OBJECT_FDW
;
1576 case ParameterAclRelationId
:
1577 istmt
.objtype
= OBJECT_PARAMETER_ACL
;
1580 elog(ERROR
, "unexpected object class %u", classid
);
1583 istmt
.is_grant
= false;
1584 istmt
.objects
= list_make1_oid(objid
);
1585 istmt
.all_privs
= true;
1586 istmt
.privileges
= ACL_NO_RIGHTS
;
1587 istmt
.col_privs
= NIL
;
1588 istmt
.grantees
= list_make1_oid(roleid
);
1589 istmt
.grant_option
= false;
1590 istmt
.behavior
= DROP_CASCADE
;
1592 ExecGrantStmt_oids(&istmt
);
1598 * expand_col_privileges
1600 * OR the specified privilege(s) into per-column array entries for each
1601 * specified attribute. The per-column array is indexed starting at
1602 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1605 expand_col_privileges(List
*colnames
, Oid table_oid
,
1606 AclMode this_privileges
,
1607 AclMode
*col_privileges
,
1608 int num_col_privileges
)
1612 foreach(cell
, colnames
)
1614 char *colname
= strVal(lfirst(cell
));
1617 attnum
= get_attnum(table_oid
, colname
);
1618 if (attnum
== InvalidAttrNumber
)
1620 (errcode(ERRCODE_UNDEFINED_COLUMN
),
1621 errmsg("column \"%s\" of relation \"%s\" does not exist",
1622 colname
, get_rel_name(table_oid
))));
1623 attnum
-= FirstLowInvalidHeapAttributeNumber
;
1624 if (attnum
<= 0 || attnum
>= num_col_privileges
)
1625 elog(ERROR
, "column number out of range"); /* safety check */
1626 col_privileges
[attnum
] |= this_privileges
;
1631 * expand_all_col_privileges
1633 * OR the specified privilege(s) into per-column array entries for each valid
1634 * attribute of a relation. The per-column array is indexed starting at
1635 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1638 expand_all_col_privileges(Oid table_oid
, Form_pg_class classForm
,
1639 AclMode this_privileges
,
1640 AclMode
*col_privileges
,
1641 int num_col_privileges
)
1643 AttrNumber curr_att
;
1645 Assert(classForm
->relnatts
- FirstLowInvalidHeapAttributeNumber
< num_col_privileges
);
1646 for (curr_att
= FirstLowInvalidHeapAttributeNumber
+ 1;
1647 curr_att
<= classForm
->relnatts
;
1653 if (curr_att
== InvalidAttrNumber
)
1656 /* Views don't have any system columns at all */
1657 if (classForm
->relkind
== RELKIND_VIEW
&& curr_att
< 0)
1660 attTuple
= SearchSysCache2(ATTNUM
,
1661 ObjectIdGetDatum(table_oid
),
1662 Int16GetDatum(curr_att
));
1663 if (!HeapTupleIsValid(attTuple
))
1664 elog(ERROR
, "cache lookup failed for attribute %d of relation %u",
1665 curr_att
, table_oid
);
1667 isdropped
= ((Form_pg_attribute
) GETSTRUCT(attTuple
))->attisdropped
;
1669 ReleaseSysCache(attTuple
);
1671 /* ignore dropped columns */
1675 col_privileges
[curr_att
- FirstLowInvalidHeapAttributeNumber
] |= this_privileges
;
1680 * This processes attributes, but expects to be called from
1681 * ExecGrant_Relation, not directly from ExecuteGrantStmt.
1684 ExecGrant_Attribute(InternalGrant
*istmt
, Oid relOid
, const char *relname
,
1685 AttrNumber attnum
, Oid ownerId
, AclMode col_privileges
,
1686 Relation attRelation
, const Acl
*old_rel_acl
)
1688 HeapTuple attr_tuple
;
1689 Form_pg_attribute pg_attribute_tuple
;
1696 AclMode avail_goptions
;
1699 Datum values
[Natts_pg_attribute
] = {0};
1700 bool nulls
[Natts_pg_attribute
] = {0};
1701 bool replaces
[Natts_pg_attribute
] = {0};
1707 attr_tuple
= SearchSysCache2(ATTNUM
,
1708 ObjectIdGetDatum(relOid
),
1709 Int16GetDatum(attnum
));
1710 if (!HeapTupleIsValid(attr_tuple
))
1711 elog(ERROR
, "cache lookup failed for attribute %d of relation %u",
1713 pg_attribute_tuple
= (Form_pg_attribute
) GETSTRUCT(attr_tuple
);
1716 * Get working copy of existing ACL. If there's no ACL, substitute the
1719 aclDatum
= SysCacheGetAttr(ATTNUM
, attr_tuple
, Anum_pg_attribute_attacl
,
1723 old_acl
= acldefault(OBJECT_COLUMN
, ownerId
);
1724 /* There are no old member roles according to the catalogs */
1730 old_acl
= DatumGetAclPCopy(aclDatum
);
1731 /* Get the roles mentioned in the existing ACL */
1732 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1736 * In select_best_grantor we should consider existing table-level ACL bits
1737 * as well as the per-column ACL. Build a new ACL that is their
1738 * concatenation. (This is a bit cheap and dirty compared to merging them
1739 * properly with no duplications, but it's all we need here.)
1741 merged_acl
= aclconcat(old_rel_acl
, old_acl
);
1743 /* Determine ID to do the grant as, and available grant options */
1744 select_best_grantor(GetUserId(), col_privileges
,
1745 merged_acl
, ownerId
,
1746 &grantorId
, &avail_goptions
);
1751 * Restrict the privileges to what we can actually grant, and emit the
1752 * standards-mandated warning and error messages. Note: we don't track
1753 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1754 * each column; we just approximate it by whether all the possible
1755 * privileges are specified now. Since the all_privs flag only determines
1756 * whether a warning is issued, this seems close enough.
1759 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1760 (col_privileges
== ACL_ALL_RIGHTS_COLUMN
),
1762 relOid
, grantorId
, OBJECT_COLUMN
,
1764 NameStr(pg_attribute_tuple
->attname
));
1769 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
1770 istmt
->grant_option
,
1771 istmt
->behavior
, istmt
->grantees
,
1772 col_privileges
, grantorId
,
1776 * We need the members of both old and new ACLs so we can correct the
1777 * shared dependency information.
1779 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1781 /* finished building new ACL value, now insert it */
1784 * If the updated ACL is empty, we can set attacl to null, and maybe even
1785 * avoid an update of the pg_attribute row. This is worth testing because
1786 * we'll come through here multiple times for any relation-level REVOKE,
1787 * even if there were never any column GRANTs. Note we are assuming that
1788 * the "default" ACL state for columns is empty.
1790 if (ACL_NUM(new_acl
) > 0)
1792 values
[Anum_pg_attribute_attacl
- 1] = PointerGetDatum(new_acl
);
1797 nulls
[Anum_pg_attribute_attacl
- 1] = true;
1798 need_update
= !isNull
;
1800 replaces
[Anum_pg_attribute_attacl
- 1] = true;
1804 newtuple
= heap_modify_tuple(attr_tuple
, RelationGetDescr(attRelation
),
1805 values
, nulls
, replaces
);
1807 CatalogTupleUpdate(attRelation
, &newtuple
->t_self
, newtuple
);
1809 /* Update initial privileges for extensions */
1810 recordExtensionInitPriv(relOid
, RelationRelationId
, attnum
,
1811 ACL_NUM(new_acl
) > 0 ? new_acl
: NULL
);
1813 /* Update the shared dependency ACL info */
1814 updateAclDependencies(RelationRelationId
, relOid
, attnum
,
1816 noldmembers
, oldmembers
,
1817 nnewmembers
, newmembers
);
1822 ReleaseSysCache(attr_tuple
);
1826 * This processes both sequences and non-sequences.
1829 ExecGrant_Relation(InternalGrant
*istmt
)
1832 Relation attRelation
;
1835 relation
= table_open(RelationRelationId
, RowExclusiveLock
);
1836 attRelation
= table_open(AttributeRelationId
, RowExclusiveLock
);
1838 foreach(cell
, istmt
->objects
)
1840 Oid relOid
= lfirst_oid(cell
);
1842 Form_pg_class pg_class_tuple
;
1844 AclMode this_privileges
;
1845 AclMode
*col_privileges
;
1846 int num_col_privileges
;
1847 bool have_col_privileges
;
1854 ListCell
*cell_colprivs
;
1856 tuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(relOid
));
1857 if (!HeapTupleIsValid(tuple
))
1858 elog(ERROR
, "cache lookup failed for relation %u", relOid
);
1859 pg_class_tuple
= (Form_pg_class
) GETSTRUCT(tuple
);
1861 /* Not sensible to grant on an index */
1862 if (pg_class_tuple
->relkind
== RELKIND_INDEX
||
1863 pg_class_tuple
->relkind
== RELKIND_PARTITIONED_INDEX
)
1865 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1866 errmsg("\"%s\" is an index",
1867 NameStr(pg_class_tuple
->relname
))));
1869 /* Composite types aren't tables either */
1870 if (pg_class_tuple
->relkind
== RELKIND_COMPOSITE_TYPE
)
1872 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1873 errmsg("\"%s\" is a composite type",
1874 NameStr(pg_class_tuple
->relname
))));
1876 /* Used GRANT SEQUENCE on a non-sequence? */
1877 if (istmt
->objtype
== OBJECT_SEQUENCE
&&
1878 pg_class_tuple
->relkind
!= RELKIND_SEQUENCE
)
1880 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1881 errmsg("\"%s\" is not a sequence",
1882 NameStr(pg_class_tuple
->relname
))));
1884 /* Adjust the default permissions based on object type */
1885 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
1887 if (pg_class_tuple
->relkind
== RELKIND_SEQUENCE
)
1888 this_privileges
= ACL_ALL_RIGHTS_SEQUENCE
;
1890 this_privileges
= ACL_ALL_RIGHTS_RELATION
;
1893 this_privileges
= istmt
->privileges
;
1896 * The GRANT TABLE syntax can be used for sequences and non-sequences,
1897 * so we have to look at the relkind to determine the supported
1898 * permissions. The OR of table and sequence permissions were already
1901 if (istmt
->objtype
== OBJECT_TABLE
)
1903 if (pg_class_tuple
->relkind
== RELKIND_SEQUENCE
)
1906 * For backward compatibility, just throw a warning for
1907 * invalid sequence permissions when using the non-sequence
1910 if (this_privileges
& ~((AclMode
) ACL_ALL_RIGHTS_SEQUENCE
))
1913 * Mention the object name because the user needs to know
1914 * which operations succeeded. This is required because
1915 * WARNING allows the command to continue.
1918 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1919 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1920 NameStr(pg_class_tuple
->relname
))));
1921 this_privileges
&= (AclMode
) ACL_ALL_RIGHTS_SEQUENCE
;
1926 if (this_privileges
& ~((AclMode
) ACL_ALL_RIGHTS_RELATION
))
1929 * USAGE is the only permission supported by sequences but
1930 * not by non-sequences. Don't mention the object name
1931 * because we didn't in the combined TABLE | SEQUENCE
1935 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1936 errmsg("invalid privilege type %s for table",
1943 * Set up array in which we'll accumulate any column privilege bits
1944 * that need modification. The array is indexed such that entry [0]
1945 * corresponds to FirstLowInvalidHeapAttributeNumber.
1947 num_col_privileges
= pg_class_tuple
->relnatts
- FirstLowInvalidHeapAttributeNumber
+ 1;
1948 col_privileges
= (AclMode
*) palloc0(num_col_privileges
* sizeof(AclMode
));
1949 have_col_privileges
= false;
1952 * If we are revoking relation privileges that are also column
1953 * privileges, we must implicitly revoke them from each column too,
1954 * per SQL spec. (We don't need to implicitly add column privileges
1955 * during GRANT because the permissions-checking code always checks
1956 * both relation and per-column privileges.)
1958 if (!istmt
->is_grant
&&
1959 (this_privileges
& ACL_ALL_RIGHTS_COLUMN
) != 0)
1961 expand_all_col_privileges(relOid
, pg_class_tuple
,
1962 this_privileges
& ACL_ALL_RIGHTS_COLUMN
,
1964 num_col_privileges
);
1965 have_col_privileges
= true;
1969 * Get owner ID and working copy of existing ACL. If there's no ACL,
1970 * substitute the proper default.
1972 ownerId
= pg_class_tuple
->relowner
;
1973 aclDatum
= SysCacheGetAttr(RELOID
, tuple
, Anum_pg_class_relacl
,
1977 switch (pg_class_tuple
->relkind
)
1979 case RELKIND_SEQUENCE
:
1980 old_acl
= acldefault(OBJECT_SEQUENCE
, ownerId
);
1983 old_acl
= acldefault(OBJECT_TABLE
, ownerId
);
1986 /* There are no old member roles according to the catalogs */
1992 old_acl
= DatumGetAclPCopy(aclDatum
);
1993 /* Get the roles mentioned in the existing ACL */
1994 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1997 /* Need an extra copy of original rel ACL for column handling */
1998 old_rel_acl
= aclcopy(old_acl
);
2001 * Handle relation-level privileges, if any were specified
2003 if (this_privileges
!= ACL_NO_RIGHTS
)
2005 AclMode avail_goptions
;
2009 Datum values
[Natts_pg_class
] = {0};
2010 bool nulls
[Natts_pg_class
] = {0};
2011 bool replaces
[Natts_pg_class
] = {0};
2016 /* Determine ID to do the grant as, and available grant options */
2017 select_best_grantor(GetUserId(), this_privileges
,
2019 &grantorId
, &avail_goptions
);
2021 switch (pg_class_tuple
->relkind
)
2023 case RELKIND_SEQUENCE
:
2024 objtype
= OBJECT_SEQUENCE
;
2027 objtype
= OBJECT_TABLE
;
2032 * Restrict the privileges to what we can actually grant, and emit
2033 * the standards-mandated warning and error messages.
2036 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2037 istmt
->all_privs
, this_privileges
,
2038 relOid
, grantorId
, objtype
,
2039 NameStr(pg_class_tuple
->relname
),
2045 new_acl
= merge_acl_with_grant(old_acl
,
2047 istmt
->grant_option
,
2055 * We need the members of both old and new ACLs so we can correct
2056 * the shared dependency information.
2058 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2060 /* finished building new ACL value, now insert it */
2061 replaces
[Anum_pg_class_relacl
- 1] = true;
2062 values
[Anum_pg_class_relacl
- 1] = PointerGetDatum(new_acl
);
2064 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
),
2065 values
, nulls
, replaces
);
2067 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2069 /* Update initial privileges for extensions */
2070 recordExtensionInitPriv(relOid
, RelationRelationId
, 0, new_acl
);
2072 /* Update the shared dependency ACL info */
2073 updateAclDependencies(RelationRelationId
, relOid
, 0,
2075 noldmembers
, oldmembers
,
2076 nnewmembers
, newmembers
);
2082 * Handle column-level privileges, if any were specified or implied.
2083 * We first expand the user-specified column privileges into the
2084 * array, and then iterate over all nonempty array entries.
2086 foreach(cell_colprivs
, istmt
->col_privs
)
2088 AccessPriv
*col_privs
= (AccessPriv
*) lfirst(cell_colprivs
);
2090 if (col_privs
->priv_name
== NULL
)
2091 this_privileges
= ACL_ALL_RIGHTS_COLUMN
;
2093 this_privileges
= string_to_privilege(col_privs
->priv_name
);
2095 if (this_privileges
& ~((AclMode
) ACL_ALL_RIGHTS_COLUMN
))
2097 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
2098 errmsg("invalid privilege type %s for column",
2099 privilege_to_string(this_privileges
))));
2101 if (pg_class_tuple
->relkind
== RELKIND_SEQUENCE
&&
2102 this_privileges
& ~((AclMode
) ACL_SELECT
))
2105 * The only column privilege allowed on sequences is SELECT.
2106 * This is a warning not error because we do it that way for
2107 * relation-level privileges.
2110 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
2111 errmsg("sequence \"%s\" only supports SELECT column privileges",
2112 NameStr(pg_class_tuple
->relname
))));
2114 this_privileges
&= (AclMode
) ACL_SELECT
;
2117 expand_col_privileges(col_privs
->cols
, relOid
,
2120 num_col_privileges
);
2121 have_col_privileges
= true;
2124 if (have_col_privileges
)
2128 for (i
= 0; i
< num_col_privileges
; i
++)
2130 if (col_privileges
[i
] == ACL_NO_RIGHTS
)
2132 ExecGrant_Attribute(istmt
,
2134 NameStr(pg_class_tuple
->relname
),
2135 i
+ FirstLowInvalidHeapAttributeNumber
,
2144 pfree(col_privileges
);
2146 ReleaseSysCache(tuple
);
2148 /* prevent error when processing duplicate objects */
2149 CommandCounterIncrement();
2152 table_close(attRelation
, RowExclusiveLock
);
2153 table_close(relation
, RowExclusiveLock
);
2157 ExecGrant_common(InternalGrant
*istmt
, Oid classid
, AclMode default_privs
,
2158 void (*object_check
) (InternalGrant
*istmt
, HeapTuple tuple
))
2164 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2165 istmt
->privileges
= default_privs
;
2167 cacheid
= get_object_catcache_oid(classid
);
2169 relation
= table_open(classid
, RowExclusiveLock
);
2171 foreach(cell
, istmt
->objects
)
2173 Oid objectid
= lfirst_oid(cell
);
2177 AclMode avail_goptions
;
2178 AclMode this_privileges
;
2185 Datum
*values
= palloc0_array(Datum
, RelationGetDescr(relation
)->natts
);
2186 bool *nulls
= palloc0_array(bool, RelationGetDescr(relation
)->natts
);
2187 bool *replaces
= palloc0_array(bool, RelationGetDescr(relation
)->natts
);
2193 tuple
= SearchSysCache1(cacheid
, ObjectIdGetDatum(objectid
));
2194 if (!HeapTupleIsValid(tuple
))
2195 elog(ERROR
, "cache lookup failed for %s %u", get_object_class_descr(classid
), objectid
);
2198 * Additional object-type-specific checks
2201 object_check(istmt
, tuple
);
2204 * Get owner ID and working copy of existing ACL. If there's no ACL,
2205 * substitute the proper default.
2207 ownerId
= DatumGetObjectId(SysCacheGetAttrNotNull(cacheid
,
2209 get_object_attnum_owner(classid
)));
2210 aclDatum
= SysCacheGetAttr(cacheid
,
2212 get_object_attnum_acl(classid
),
2216 old_acl
= acldefault(get_object_type(classid
, objectid
), ownerId
);
2217 /* There are no old member roles according to the catalogs */
2223 old_acl
= DatumGetAclPCopy(aclDatum
);
2224 /* Get the roles mentioned in the existing ACL */
2225 noldmembers
= aclmembers(old_acl
, &oldmembers
);
2228 /* Determine ID to do the grant as, and available grant options */
2229 select_best_grantor(GetUserId(), istmt
->privileges
,
2231 &grantorId
, &avail_goptions
);
2233 nameDatum
= SysCacheGetAttrNotNull(cacheid
, tuple
,
2234 get_object_attnum_name(classid
));
2237 * Restrict the privileges to what we can actually grant, and emit the
2238 * standards-mandated warning and error messages.
2241 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2242 istmt
->all_privs
, istmt
->privileges
,
2243 objectid
, grantorId
, get_object_type(classid
, objectid
),
2244 NameStr(*DatumGetName(nameDatum
)),
2250 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
2251 istmt
->grant_option
, istmt
->behavior
,
2252 istmt
->grantees
, this_privileges
,
2253 grantorId
, ownerId
);
2256 * We need the members of both old and new ACLs so we can correct the
2257 * shared dependency information.
2259 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2261 /* finished building new ACL value, now insert it */
2262 replaces
[get_object_attnum_acl(classid
) - 1] = true;
2263 values
[get_object_attnum_acl(classid
) - 1] = PointerGetDatum(new_acl
);
2265 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
2268 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2270 /* Update initial privileges for extensions */
2271 recordExtensionInitPriv(objectid
, classid
, 0, new_acl
);
2273 /* Update the shared dependency ACL info */
2274 updateAclDependencies(classid
,
2277 noldmembers
, oldmembers
,
2278 nnewmembers
, newmembers
);
2280 ReleaseSysCache(tuple
);
2284 /* prevent error when processing duplicate objects */
2285 CommandCounterIncrement();
2288 table_close(relation
, RowExclusiveLock
);
2292 ExecGrant_Language_check(InternalGrant
*istmt
, HeapTuple tuple
)
2294 Form_pg_language pg_language_tuple
;
2296 pg_language_tuple
= (Form_pg_language
) GETSTRUCT(tuple
);
2298 if (!pg_language_tuple
->lanpltrusted
)
2300 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
2301 errmsg("language \"%s\" is not trusted",
2302 NameStr(pg_language_tuple
->lanname
)),
2303 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2304 "because only superusers can use untrusted languages.")));
2308 ExecGrant_Largeobject(InternalGrant
*istmt
)
2313 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2314 istmt
->privileges
= ACL_ALL_RIGHTS_LARGEOBJECT
;
2316 relation
= table_open(LargeObjectMetadataRelationId
,
2319 foreach(cell
, istmt
->objects
)
2321 Oid loid
= lfirst_oid(cell
);
2322 Form_pg_largeobject_metadata form_lo_meta
;
2323 char loname
[NAMEDATALEN
];
2326 AclMode avail_goptions
;
2327 AclMode this_privileges
;
2333 Datum values
[Natts_pg_largeobject_metadata
] = {0};
2334 bool nulls
[Natts_pg_largeobject_metadata
] = {0};
2335 bool replaces
[Natts_pg_largeobject_metadata
] = {0};
2340 ScanKeyData entry
[1];
2344 /* There's no syscache for pg_largeobject_metadata */
2345 ScanKeyInit(&entry
[0],
2346 Anum_pg_largeobject_metadata_oid
,
2347 BTEqualStrategyNumber
, F_OIDEQ
,
2348 ObjectIdGetDatum(loid
));
2350 scan
= systable_beginscan(relation
,
2351 LargeObjectMetadataOidIndexId
, true,
2354 tuple
= systable_getnext(scan
);
2355 if (!HeapTupleIsValid(tuple
))
2356 elog(ERROR
, "could not find tuple for large object %u", loid
);
2358 form_lo_meta
= (Form_pg_largeobject_metadata
) GETSTRUCT(tuple
);
2361 * Get owner ID and working copy of existing ACL. If there's no ACL,
2362 * substitute the proper default.
2364 ownerId
= form_lo_meta
->lomowner
;
2365 aclDatum
= heap_getattr(tuple
,
2366 Anum_pg_largeobject_metadata_lomacl
,
2367 RelationGetDescr(relation
), &isNull
);
2370 old_acl
= acldefault(OBJECT_LARGEOBJECT
, ownerId
);
2371 /* There are no old member roles according to the catalogs */
2377 old_acl
= DatumGetAclPCopy(aclDatum
);
2378 /* Get the roles mentioned in the existing ACL */
2379 noldmembers
= aclmembers(old_acl
, &oldmembers
);
2382 /* Determine ID to do the grant as, and available grant options */
2383 select_best_grantor(GetUserId(), istmt
->privileges
,
2385 &grantorId
, &avail_goptions
);
2388 * Restrict the privileges to what we can actually grant, and emit the
2389 * standards-mandated warning and error messages.
2391 snprintf(loname
, sizeof(loname
), "large object %u", loid
);
2393 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2394 istmt
->all_privs
, istmt
->privileges
,
2395 loid
, grantorId
, OBJECT_LARGEOBJECT
,
2401 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
2402 istmt
->grant_option
, istmt
->behavior
,
2403 istmt
->grantees
, this_privileges
,
2404 grantorId
, ownerId
);
2407 * We need the members of both old and new ACLs so we can correct the
2408 * shared dependency information.
2410 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2412 /* finished building new ACL value, now insert it */
2413 replaces
[Anum_pg_largeobject_metadata_lomacl
- 1] = true;
2414 values
[Anum_pg_largeobject_metadata_lomacl
- 1]
2415 = PointerGetDatum(new_acl
);
2417 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
),
2418 values
, nulls
, replaces
);
2420 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2422 /* Update initial privileges for extensions */
2423 recordExtensionInitPriv(loid
, LargeObjectRelationId
, 0, new_acl
);
2425 /* Update the shared dependency ACL info */
2426 updateAclDependencies(LargeObjectRelationId
,
2427 form_lo_meta
->oid
, 0,
2429 noldmembers
, oldmembers
,
2430 nnewmembers
, newmembers
);
2432 systable_endscan(scan
);
2436 /* prevent error when processing duplicate objects */
2437 CommandCounterIncrement();
2440 table_close(relation
, RowExclusiveLock
);
2444 ExecGrant_Type_check(InternalGrant
*istmt
, HeapTuple tuple
)
2446 Form_pg_type pg_type_tuple
;
2448 pg_type_tuple
= (Form_pg_type
) GETSTRUCT(tuple
);
2450 /* Disallow GRANT on dependent types */
2451 if (IsTrueArrayType(pg_type_tuple
))
2453 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
2454 errmsg("cannot set privileges of array types"),
2455 errhint("Set the privileges of the element type instead.")));
2456 if (pg_type_tuple
->typtype
== TYPTYPE_MULTIRANGE
)
2458 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
2459 errmsg("cannot set privileges of multirange types"),
2460 errhint("Set the privileges of the range type instead.")));
2462 /* Used GRANT DOMAIN on a non-domain? */
2463 if (istmt
->objtype
== OBJECT_DOMAIN
&&
2464 pg_type_tuple
->typtype
!= TYPTYPE_DOMAIN
)
2466 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
2467 errmsg("\"%s\" is not a domain",
2468 NameStr(pg_type_tuple
->typname
))));
2472 ExecGrant_Parameter(InternalGrant
*istmt
)
2477 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2478 istmt
->privileges
= ACL_ALL_RIGHTS_PARAMETER_ACL
;
2480 relation
= table_open(ParameterAclRelationId
, RowExclusiveLock
);
2482 foreach(cell
, istmt
->objects
)
2484 Oid parameterId
= lfirst_oid(cell
);
2486 const char *parname
;
2489 AclMode avail_goptions
;
2490 AclMode this_privileges
;
2501 tuple
= SearchSysCache1(PARAMETERACLOID
, ObjectIdGetDatum(parameterId
));
2502 if (!HeapTupleIsValid(tuple
))
2503 elog(ERROR
, "cache lookup failed for parameter ACL %u",
2506 /* We'll need the GUC's name */
2507 nameDatum
= SysCacheGetAttrNotNull(PARAMETERACLOID
, tuple
,
2508 Anum_pg_parameter_acl_parname
);
2509 parname
= TextDatumGetCString(nameDatum
);
2511 /* Treat all parameters as belonging to the bootstrap superuser. */
2512 ownerId
= BOOTSTRAP_SUPERUSERID
;
2515 * Get working copy of existing ACL. If there's no ACL, substitute the
2518 aclDatum
= SysCacheGetAttr(PARAMETERACLOID
, tuple
,
2519 Anum_pg_parameter_acl_paracl
,
2524 old_acl
= acldefault(istmt
->objtype
, ownerId
);
2525 /* There are no old member roles according to the catalogs */
2531 old_acl
= DatumGetAclPCopy(aclDatum
);
2532 /* Get the roles mentioned in the existing ACL */
2533 noldmembers
= aclmembers(old_acl
, &oldmembers
);
2536 /* Determine ID to do the grant as, and available grant options */
2537 select_best_grantor(GetUserId(), istmt
->privileges
,
2539 &grantorId
, &avail_goptions
);
2542 * Restrict the privileges to what we can actually grant, and emit the
2543 * standards-mandated warning and error messages.
2546 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2547 istmt
->all_privs
, istmt
->privileges
,
2548 parameterId
, grantorId
,
2549 OBJECT_PARAMETER_ACL
,
2556 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
2557 istmt
->grant_option
, istmt
->behavior
,
2558 istmt
->grantees
, this_privileges
,
2559 grantorId
, ownerId
);
2562 * We need the members of both old and new ACLs so we can correct the
2563 * shared dependency information.
2565 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2568 * If the new ACL is equal to the default, we don't need the catalog
2569 * entry any longer. Delete it rather than updating it, to avoid
2570 * leaving a degenerate entry.
2572 if (aclequal(new_acl
, acldefault(istmt
->objtype
, ownerId
)))
2574 CatalogTupleDelete(relation
, &tuple
->t_self
);
2578 /* finished building new ACL value, now insert it */
2580 Datum values
[Natts_pg_parameter_acl
] = {0};
2581 bool nulls
[Natts_pg_parameter_acl
] = {0};
2582 bool replaces
[Natts_pg_parameter_acl
] = {0};
2584 replaces
[Anum_pg_parameter_acl_paracl
- 1] = true;
2585 values
[Anum_pg_parameter_acl_paracl
- 1] = PointerGetDatum(new_acl
);
2587 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
),
2588 values
, nulls
, replaces
);
2590 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2593 /* Update initial privileges for extensions */
2594 recordExtensionInitPriv(parameterId
, ParameterAclRelationId
, 0,
2597 /* Update the shared dependency ACL info */
2598 updateAclDependencies(ParameterAclRelationId
, parameterId
, 0,
2600 noldmembers
, oldmembers
,
2601 nnewmembers
, newmembers
);
2603 ReleaseSysCache(tuple
);
2606 /* prevent error when processing duplicate objects */
2607 CommandCounterIncrement();
2610 table_close(relation
, RowExclusiveLock
);
2615 string_to_privilege(const char *privname
)
2617 if (strcmp(privname
, "insert") == 0)
2619 if (strcmp(privname
, "select") == 0)
2621 if (strcmp(privname
, "update") == 0)
2623 if (strcmp(privname
, "delete") == 0)
2625 if (strcmp(privname
, "truncate") == 0)
2626 return ACL_TRUNCATE
;
2627 if (strcmp(privname
, "references") == 0)
2628 return ACL_REFERENCES
;
2629 if (strcmp(privname
, "trigger") == 0)
2631 if (strcmp(privname
, "execute") == 0)
2633 if (strcmp(privname
, "usage") == 0)
2635 if (strcmp(privname
, "create") == 0)
2637 if (strcmp(privname
, "temporary") == 0)
2638 return ACL_CREATE_TEMP
;
2639 if (strcmp(privname
, "temp") == 0)
2640 return ACL_CREATE_TEMP
;
2641 if (strcmp(privname
, "connect") == 0)
2643 if (strcmp(privname
, "set") == 0)
2645 if (strcmp(privname
, "alter system") == 0)
2646 return ACL_ALTER_SYSTEM
;
2647 if (strcmp(privname
, "rule") == 0)
2648 return 0; /* ignore old RULE privileges */
2650 (errcode(ERRCODE_SYNTAX_ERROR
),
2651 errmsg("unrecognized privilege type \"%s\"", privname
)));
2652 return 0; /* appease compiler */
2656 privilege_to_string(AclMode privilege
)
2670 case ACL_REFERENCES
:
2671 return "REFERENCES";
2680 case ACL_CREATE_TEMP
:
2686 case ACL_ALTER_SYSTEM
:
2687 return "ALTER SYSTEM";
2689 elog(ERROR
, "unrecognized privilege: %d", (int) privilege
);
2691 return NULL
; /* appease compiler */
2695 * Standardized reporting of aclcheck permissions failures.
2697 * Note: we do not double-quote the %s's below, because many callers
2698 * supply strings that might be already quoted.
2701 aclcheck_error(AclResult aclerr
, ObjectType objtype
,
2702 const char *objectname
)
2707 /* no error, so return to caller */
2709 case ACLCHECK_NO_PRIV
:
2711 const char *msg
= "???";
2715 case OBJECT_AGGREGATE
:
2716 msg
= gettext_noop("permission denied for aggregate %s");
2718 case OBJECT_COLLATION
:
2719 msg
= gettext_noop("permission denied for collation %s");
2722 msg
= gettext_noop("permission denied for column %s");
2724 case OBJECT_CONVERSION
:
2725 msg
= gettext_noop("permission denied for conversion %s");
2727 case OBJECT_DATABASE
:
2728 msg
= gettext_noop("permission denied for database %s");
2731 msg
= gettext_noop("permission denied for domain %s");
2733 case OBJECT_EVENT_TRIGGER
:
2734 msg
= gettext_noop("permission denied for event trigger %s");
2736 case OBJECT_EXTENSION
:
2737 msg
= gettext_noop("permission denied for extension %s");
2740 msg
= gettext_noop("permission denied for foreign-data wrapper %s");
2742 case OBJECT_FOREIGN_SERVER
:
2743 msg
= gettext_noop("permission denied for foreign server %s");
2745 case OBJECT_FOREIGN_TABLE
:
2746 msg
= gettext_noop("permission denied for foreign table %s");
2748 case OBJECT_FUNCTION
:
2749 msg
= gettext_noop("permission denied for function %s");
2752 msg
= gettext_noop("permission denied for index %s");
2754 case OBJECT_LANGUAGE
:
2755 msg
= gettext_noop("permission denied for language %s");
2757 case OBJECT_LARGEOBJECT
:
2758 msg
= gettext_noop("permission denied for large object %s");
2760 case OBJECT_MATVIEW
:
2761 msg
= gettext_noop("permission denied for materialized view %s");
2763 case OBJECT_OPCLASS
:
2764 msg
= gettext_noop("permission denied for operator class %s");
2766 case OBJECT_OPERATOR
:
2767 msg
= gettext_noop("permission denied for operator %s");
2769 case OBJECT_OPFAMILY
:
2770 msg
= gettext_noop("permission denied for operator family %s");
2772 case OBJECT_PARAMETER_ACL
:
2773 msg
= gettext_noop("permission denied for parameter %s");
2776 msg
= gettext_noop("permission denied for policy %s");
2778 case OBJECT_PROCEDURE
:
2779 msg
= gettext_noop("permission denied for procedure %s");
2781 case OBJECT_PUBLICATION
:
2782 msg
= gettext_noop("permission denied for publication %s");
2784 case OBJECT_ROUTINE
:
2785 msg
= gettext_noop("permission denied for routine %s");
2788 msg
= gettext_noop("permission denied for schema %s");
2790 case OBJECT_SEQUENCE
:
2791 msg
= gettext_noop("permission denied for sequence %s");
2793 case OBJECT_STATISTIC_EXT
:
2794 msg
= gettext_noop("permission denied for statistics object %s");
2796 case OBJECT_SUBSCRIPTION
:
2797 msg
= gettext_noop("permission denied for subscription %s");
2800 msg
= gettext_noop("permission denied for table %s");
2802 case OBJECT_TABLESPACE
:
2803 msg
= gettext_noop("permission denied for tablespace %s");
2805 case OBJECT_TSCONFIGURATION
:
2806 msg
= gettext_noop("permission denied for text search configuration %s");
2808 case OBJECT_TSDICTIONARY
:
2809 msg
= gettext_noop("permission denied for text search dictionary %s");
2812 msg
= gettext_noop("permission denied for type %s");
2815 msg
= gettext_noop("permission denied for view %s");
2817 /* these currently aren't used */
2818 case OBJECT_ACCESS_METHOD
:
2821 case OBJECT_ATTRIBUTE
:
2823 case OBJECT_DEFAULT
:
2825 case OBJECT_DOMCONSTRAINT
:
2826 case OBJECT_PUBLICATION_NAMESPACE
:
2827 case OBJECT_PUBLICATION_REL
:
2830 case OBJECT_TABCONSTRAINT
:
2831 case OBJECT_TRANSFORM
:
2832 case OBJECT_TRIGGER
:
2833 case OBJECT_TSPARSER
:
2834 case OBJECT_TSTEMPLATE
:
2835 case OBJECT_USER_MAPPING
:
2836 elog(ERROR
, "unsupported object type: %d", objtype
);
2840 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
2841 errmsg(msg
, objectname
)));
2844 case ACLCHECK_NOT_OWNER
:
2846 const char *msg
= "???";
2850 case OBJECT_AGGREGATE
:
2851 msg
= gettext_noop("must be owner of aggregate %s");
2853 case OBJECT_COLLATION
:
2854 msg
= gettext_noop("must be owner of collation %s");
2856 case OBJECT_CONVERSION
:
2857 msg
= gettext_noop("must be owner of conversion %s");
2859 case OBJECT_DATABASE
:
2860 msg
= gettext_noop("must be owner of database %s");
2863 msg
= gettext_noop("must be owner of domain %s");
2865 case OBJECT_EVENT_TRIGGER
:
2866 msg
= gettext_noop("must be owner of event trigger %s");
2868 case OBJECT_EXTENSION
:
2869 msg
= gettext_noop("must be owner of extension %s");
2872 msg
= gettext_noop("must be owner of foreign-data wrapper %s");
2874 case OBJECT_FOREIGN_SERVER
:
2875 msg
= gettext_noop("must be owner of foreign server %s");
2877 case OBJECT_FOREIGN_TABLE
:
2878 msg
= gettext_noop("must be owner of foreign table %s");
2880 case OBJECT_FUNCTION
:
2881 msg
= gettext_noop("must be owner of function %s");
2884 msg
= gettext_noop("must be owner of index %s");
2886 case OBJECT_LANGUAGE
:
2887 msg
= gettext_noop("must be owner of language %s");
2889 case OBJECT_LARGEOBJECT
:
2890 msg
= gettext_noop("must be owner of large object %s");
2892 case OBJECT_MATVIEW
:
2893 msg
= gettext_noop("must be owner of materialized view %s");
2895 case OBJECT_OPCLASS
:
2896 msg
= gettext_noop("must be owner of operator class %s");
2898 case OBJECT_OPERATOR
:
2899 msg
= gettext_noop("must be owner of operator %s");
2901 case OBJECT_OPFAMILY
:
2902 msg
= gettext_noop("must be owner of operator family %s");
2904 case OBJECT_PROCEDURE
:
2905 msg
= gettext_noop("must be owner of procedure %s");
2907 case OBJECT_PUBLICATION
:
2908 msg
= gettext_noop("must be owner of publication %s");
2910 case OBJECT_ROUTINE
:
2911 msg
= gettext_noop("must be owner of routine %s");
2913 case OBJECT_SEQUENCE
:
2914 msg
= gettext_noop("must be owner of sequence %s");
2916 case OBJECT_SUBSCRIPTION
:
2917 msg
= gettext_noop("must be owner of subscription %s");
2920 msg
= gettext_noop("must be owner of table %s");
2923 msg
= gettext_noop("must be owner of type %s");
2926 msg
= gettext_noop("must be owner of view %s");
2929 msg
= gettext_noop("must be owner of schema %s");
2931 case OBJECT_STATISTIC_EXT
:
2932 msg
= gettext_noop("must be owner of statistics object %s");
2934 case OBJECT_TABLESPACE
:
2935 msg
= gettext_noop("must be owner of tablespace %s");
2937 case OBJECT_TSCONFIGURATION
:
2938 msg
= gettext_noop("must be owner of text search configuration %s");
2940 case OBJECT_TSDICTIONARY
:
2941 msg
= gettext_noop("must be owner of text search dictionary %s");
2945 * Special cases: For these, the error message talks
2946 * about "relation", because that's where the
2947 * ownership is attached. See also
2948 * check_object_ownership().
2953 case OBJECT_TABCONSTRAINT
:
2954 case OBJECT_TRIGGER
:
2955 msg
= gettext_noop("must be owner of relation %s");
2957 /* these currently aren't used */
2958 case OBJECT_ACCESS_METHOD
:
2961 case OBJECT_ATTRIBUTE
:
2963 case OBJECT_DEFAULT
:
2965 case OBJECT_DOMCONSTRAINT
:
2966 case OBJECT_PARAMETER_ACL
:
2967 case OBJECT_PUBLICATION_NAMESPACE
:
2968 case OBJECT_PUBLICATION_REL
:
2970 case OBJECT_TRANSFORM
:
2971 case OBJECT_TSPARSER
:
2972 case OBJECT_TSTEMPLATE
:
2973 case OBJECT_USER_MAPPING
:
2974 elog(ERROR
, "unsupported object type: %d", objtype
);
2978 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
2979 errmsg(msg
, objectname
)));
2983 elog(ERROR
, "unrecognized AclResult: %d", (int) aclerr
);
2990 aclcheck_error_col(AclResult aclerr
, ObjectType objtype
,
2991 const char *objectname
, const char *colname
)
2996 /* no error, so return to caller */
2998 case ACLCHECK_NO_PRIV
:
3000 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
3001 errmsg("permission denied for column \"%s\" of relation \"%s\"",
3002 colname
, objectname
)));
3004 case ACLCHECK_NOT_OWNER
:
3005 /* relation msg is OK since columns don't have separate owners */
3006 aclcheck_error(aclerr
, objtype
, objectname
);
3009 elog(ERROR
, "unrecognized AclResult: %d", (int) aclerr
);
3016 * Special common handling for types: use element type instead of array type,
3020 aclcheck_error_type(AclResult aclerr
, Oid typeOid
)
3022 Oid element_type
= get_element_type(typeOid
);
3024 aclcheck_error(aclerr
, OBJECT_TYPE
, format_type_be(element_type
? element_type
: typeOid
));
3029 * Relay for the various pg_*_mask routines depending on object kind
3032 pg_aclmask(ObjectType objtype
, Oid object_oid
, AttrNumber attnum
, Oid roleid
,
3033 AclMode mask
, AclMaskHow how
)
3039 pg_class_aclmask(object_oid
, roleid
, mask
, how
) |
3040 pg_attribute_aclmask(object_oid
, attnum
, roleid
, mask
, how
);
3042 case OBJECT_SEQUENCE
:
3043 return pg_class_aclmask(object_oid
, roleid
, mask
, how
);
3044 case OBJECT_DATABASE
:
3045 return object_aclmask(DatabaseRelationId
, object_oid
, roleid
, mask
, how
);
3046 case OBJECT_FUNCTION
:
3047 return object_aclmask(ProcedureRelationId
, object_oid
, roleid
, mask
, how
);
3048 case OBJECT_LANGUAGE
:
3049 return object_aclmask(LanguageRelationId
, object_oid
, roleid
, mask
, how
);
3050 case OBJECT_LARGEOBJECT
:
3051 return pg_largeobject_aclmask_snapshot(object_oid
, roleid
,
3053 case OBJECT_PARAMETER_ACL
:
3054 return pg_parameter_acl_aclmask(object_oid
, roleid
, mask
, how
);
3056 return object_aclmask(NamespaceRelationId
, object_oid
, roleid
, mask
, how
);
3057 case OBJECT_STATISTIC_EXT
:
3058 elog(ERROR
, "grantable rights not supported for statistics objects");
3059 /* not reached, but keep compiler quiet */
3060 return ACL_NO_RIGHTS
;
3061 case OBJECT_TABLESPACE
:
3062 return object_aclmask(TableSpaceRelationId
, object_oid
, roleid
, mask
, how
);
3064 return object_aclmask(ForeignDataWrapperRelationId
, object_oid
, roleid
, mask
, how
);
3065 case OBJECT_FOREIGN_SERVER
:
3066 return object_aclmask(ForeignServerRelationId
, object_oid
, roleid
, mask
, how
);
3067 case OBJECT_EVENT_TRIGGER
:
3068 elog(ERROR
, "grantable rights not supported for event triggers");
3069 /* not reached, but keep compiler quiet */
3070 return ACL_NO_RIGHTS
;
3072 return object_aclmask(TypeRelationId
, object_oid
, roleid
, mask
, how
);
3074 elog(ERROR
, "unrecognized object type: %d",
3076 /* not reached, but keep compiler quiet */
3077 return ACL_NO_RIGHTS
;
3082 /* ****************************************************************
3083 * Exported routines for examining a user's privileges for various objects
3085 * See aclmask() for a description of the common API for these functions.
3087 * Note: we give lookup failure the full ereport treatment because the
3088 * has_xxx_privilege() family of functions allow users to pass any random
3089 * OID to these functions.
3090 * ****************************************************************
3094 * Generic routine for examining a user's privileges for an object
3097 object_aclmask(Oid classid
, Oid objectid
, Oid roleid
,
3098 AclMode mask
, AclMaskHow how
)
3100 return object_aclmask_ext(classid
, objectid
, roleid
, mask
, how
, NULL
);
3104 * Generic routine for examining a user's privileges for an object,
3108 object_aclmask_ext(Oid classid
, Oid objectid
, Oid roleid
,
3109 AclMode mask
, AclMaskHow how
,
3123 case NamespaceRelationId
:
3124 return pg_namespace_aclmask_ext(objectid
, roleid
, mask
, how
,
3126 case TypeRelationId
:
3127 return pg_type_aclmask_ext(objectid
, roleid
, mask
, how
,
3131 /* Even more special cases */
3132 Assert(classid
!= RelationRelationId
); /* should use pg_class_acl* */
3133 Assert(classid
!= LargeObjectMetadataRelationId
); /* should use
3134 * pg_largeobject_acl* */
3136 /* Superusers bypass all permission checking. */
3137 if (superuser_arg(roleid
))
3141 * Get the object's ACL from its catalog
3144 cacheid
= get_object_catcache_oid(classid
);
3146 tuple
= SearchSysCache1(cacheid
, ObjectIdGetDatum(objectid
));
3147 if (!HeapTupleIsValid(tuple
))
3149 if (is_missing
!= NULL
)
3151 /* return "no privileges" instead of throwing an error */
3157 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3158 errmsg("%s with OID %u does not exist",
3159 get_object_class_descr(classid
), objectid
)));
3162 ownerId
= DatumGetObjectId(SysCacheGetAttrNotNull(cacheid
,
3164 get_object_attnum_owner(classid
)));
3166 aclDatum
= SysCacheGetAttr(cacheid
, tuple
, get_object_attnum_acl(classid
),
3170 /* No ACL, so build default ACL */
3171 acl
= acldefault(get_object_type(classid
, objectid
), ownerId
);
3172 aclDatum
= (Datum
) 0;
3176 /* detoast ACL if necessary */
3177 acl
= DatumGetAclP(aclDatum
);
3180 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
3182 /* if we have a detoasted copy, free it */
3183 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3186 ReleaseSysCache(tuple
);
3192 * Routine for examining a user's privileges for a column
3194 * Note: this considers only privileges granted specifically on the column.
3195 * It is caller's responsibility to take relation-level privileges into account
3196 * as appropriate. (For the same reason, we have no special case for
3197 * superuser-ness here.)
3200 pg_attribute_aclmask(Oid table_oid
, AttrNumber attnum
, Oid roleid
,
3201 AclMode mask
, AclMaskHow how
)
3203 return pg_attribute_aclmask_ext(table_oid
, attnum
, roleid
,
3208 * Routine for examining a user's privileges for a column, with is_missing
3211 pg_attribute_aclmask_ext(Oid table_oid
, AttrNumber attnum
, Oid roleid
,
3212 AclMode mask
, AclMaskHow how
, bool *is_missing
)
3215 HeapTuple classTuple
;
3217 Form_pg_class classForm
;
3218 Form_pg_attribute attributeForm
;
3225 * First, get the column's ACL from its pg_attribute entry
3227 attTuple
= SearchSysCache2(ATTNUM
,
3228 ObjectIdGetDatum(table_oid
),
3229 Int16GetDatum(attnum
));
3230 if (!HeapTupleIsValid(attTuple
))
3232 if (is_missing
!= NULL
)
3234 /* return "no privileges" instead of throwing an error */
3240 (errcode(ERRCODE_UNDEFINED_COLUMN
),
3241 errmsg("attribute %d of relation with OID %u does not exist",
3242 attnum
, table_oid
)));
3245 attributeForm
= (Form_pg_attribute
) GETSTRUCT(attTuple
);
3247 /* Check dropped columns, too */
3248 if (attributeForm
->attisdropped
)
3250 if (is_missing
!= NULL
)
3252 /* return "no privileges" instead of throwing an error */
3254 ReleaseSysCache(attTuple
);
3259 (errcode(ERRCODE_UNDEFINED_COLUMN
),
3260 errmsg("attribute %d of relation with OID %u does not exist",
3261 attnum
, table_oid
)));
3264 aclDatum
= SysCacheGetAttr(ATTNUM
, attTuple
, Anum_pg_attribute_attacl
,
3268 * Here we hard-wire knowledge that the default ACL for a column grants no
3269 * privileges, so that we can fall out quickly in the very common case
3270 * where attacl is null.
3274 ReleaseSysCache(attTuple
);
3279 * Must get the relation's ownerId from pg_class. Since we already found
3280 * a pg_attribute entry, the only likely reason for this to fail is that a
3281 * concurrent DROP of the relation committed since then (which could only
3282 * happen if we don't have lock on the relation). Treat that similarly to
3283 * not finding the attribute entry.
3285 classTuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(table_oid
));
3286 if (!HeapTupleIsValid(classTuple
))
3288 ReleaseSysCache(attTuple
);
3289 if (is_missing
!= NULL
)
3291 /* return "no privileges" instead of throwing an error */
3297 (errcode(ERRCODE_UNDEFINED_TABLE
),
3298 errmsg("relation with OID %u does not exist",
3301 classForm
= (Form_pg_class
) GETSTRUCT(classTuple
);
3303 ownerId
= classForm
->relowner
;
3305 ReleaseSysCache(classTuple
);
3307 /* detoast column's ACL if necessary */
3308 acl
= DatumGetAclP(aclDatum
);
3310 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
3312 /* if we have a detoasted copy, free it */
3313 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3316 ReleaseSysCache(attTuple
);
3322 * Exported routine for examining a user's privileges for a table
3325 pg_class_aclmask(Oid table_oid
, Oid roleid
,
3326 AclMode mask
, AclMaskHow how
)
3328 return pg_class_aclmask_ext(table_oid
, roleid
, mask
, how
, NULL
);
3332 * Routine for examining a user's privileges for a table, with is_missing
3335 pg_class_aclmask_ext(Oid table_oid
, Oid roleid
, AclMode mask
,
3336 AclMaskHow how
, bool *is_missing
)
3340 Form_pg_class classForm
;
3347 * Must get the relation's tuple from pg_class
3349 tuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(table_oid
));
3350 if (!HeapTupleIsValid(tuple
))
3352 if (is_missing
!= NULL
)
3354 /* return "no privileges" instead of throwing an error */
3360 (errcode(ERRCODE_UNDEFINED_TABLE
),
3361 errmsg("relation with OID %u does not exist",
3365 classForm
= (Form_pg_class
) GETSTRUCT(tuple
);
3368 * Deny anyone permission to update a system catalog unless
3369 * pg_authid.rolsuper is set.
3371 * As of 7.4 we have some updatable system views; those shouldn't be
3372 * protected in this way. Assume the view rules can take care of
3373 * themselves. ACL_USAGE is if we ever have system sequences.
3375 if ((mask
& (ACL_INSERT
| ACL_UPDATE
| ACL_DELETE
| ACL_TRUNCATE
| ACL_USAGE
)) &&
3376 IsSystemClass(table_oid
, classForm
) &&
3377 classForm
->relkind
!= RELKIND_VIEW
&&
3378 !superuser_arg(roleid
))
3379 mask
&= ~(ACL_INSERT
| ACL_UPDATE
| ACL_DELETE
| ACL_TRUNCATE
| ACL_USAGE
);
3382 * Otherwise, superusers bypass all permission-checking.
3384 if (superuser_arg(roleid
))
3386 ReleaseSysCache(tuple
);
3391 * Normal case: get the relation's ACL from pg_class
3393 ownerId
= classForm
->relowner
;
3395 aclDatum
= SysCacheGetAttr(RELOID
, tuple
, Anum_pg_class_relacl
,
3399 /* No ACL, so build default ACL */
3400 switch (classForm
->relkind
)
3402 case RELKIND_SEQUENCE
:
3403 acl
= acldefault(OBJECT_SEQUENCE
, ownerId
);
3406 acl
= acldefault(OBJECT_TABLE
, ownerId
);
3409 aclDatum
= (Datum
) 0;
3413 /* detoast rel's ACL if necessary */
3414 acl
= DatumGetAclP(aclDatum
);
3417 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
3419 /* if we have a detoasted copy, free it */
3420 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3423 ReleaseSysCache(tuple
);
3426 * Check if ACL_SELECT is being checked and, if so, and not set already as
3427 * part of the result, then check if the user is a member of the
3428 * pg_read_all_data role, which allows read access to all relations.
3430 if (mask
& ACL_SELECT
&& !(result
& ACL_SELECT
) &&
3431 has_privs_of_role(roleid
, ROLE_PG_READ_ALL_DATA
))
3432 result
|= ACL_SELECT
;
3435 * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
3436 * so, and not set already as part of the result, then check if the user
3437 * is a member of the pg_write_all_data role, which allows
3438 * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
3439 * which requires superuser, see above).
3441 if (mask
& (ACL_INSERT
| ACL_UPDATE
| ACL_DELETE
) &&
3442 !(result
& (ACL_INSERT
| ACL_UPDATE
| ACL_DELETE
)) &&
3443 has_privs_of_role(roleid
, ROLE_PG_WRITE_ALL_DATA
))
3444 result
|= (mask
& (ACL_INSERT
| ACL_UPDATE
| ACL_DELETE
));
3450 * Routine for examining a user's privileges for a configuration
3451 * parameter (GUC), identified by GUC name.
3454 pg_parameter_aclmask(const char *name
, Oid roleid
, AclMode mask
, AclMaskHow how
)
3461 /* Superusers bypass all permission checking. */
3462 if (superuser_arg(roleid
))
3465 /* Convert name to the form it should have in pg_parameter_acl... */
3466 parname
= convert_GUC_name_for_parameter_acl(name
);
3467 partext
= cstring_to_text(parname
);
3469 /* ... and look it up */
3470 tuple
= SearchSysCache1(PARAMETERACLNAME
, PointerGetDatum(partext
));
3472 if (!HeapTupleIsValid(tuple
))
3474 /* If no entry, GUC has no permissions for non-superusers */
3475 result
= ACL_NO_RIGHTS
;
3483 aclDatum
= SysCacheGetAttr(PARAMETERACLNAME
, tuple
,
3484 Anum_pg_parameter_acl_paracl
,
3488 /* No ACL, so build default ACL */
3489 acl
= acldefault(OBJECT_PARAMETER_ACL
, BOOTSTRAP_SUPERUSERID
);
3490 aclDatum
= (Datum
) 0;
3494 /* detoast ACL if necessary */
3495 acl
= DatumGetAclP(aclDatum
);
3498 result
= aclmask(acl
, roleid
, BOOTSTRAP_SUPERUSERID
, mask
, how
);
3500 /* if we have a detoasted copy, free it */
3501 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3504 ReleaseSysCache(tuple
);
3514 * Routine for examining a user's privileges for a configuration
3515 * parameter (GUC), identified by the OID of its pg_parameter_acl entry.
3518 pg_parameter_acl_aclmask(Oid acl_oid
, Oid roleid
, AclMode mask
, AclMaskHow how
)
3526 /* Superusers bypass all permission checking. */
3527 if (superuser_arg(roleid
))
3530 /* Get the ACL from pg_parameter_acl */
3531 tuple
= SearchSysCache1(PARAMETERACLOID
, ObjectIdGetDatum(acl_oid
));
3532 if (!HeapTupleIsValid(tuple
))
3534 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3535 errmsg("parameter ACL with OID %u does not exist",
3538 aclDatum
= SysCacheGetAttr(PARAMETERACLOID
, tuple
,
3539 Anum_pg_parameter_acl_paracl
,
3543 /* No ACL, so build default ACL */
3544 acl
= acldefault(OBJECT_PARAMETER_ACL
, BOOTSTRAP_SUPERUSERID
);
3545 aclDatum
= (Datum
) 0;
3549 /* detoast ACL if necessary */
3550 acl
= DatumGetAclP(aclDatum
);
3553 result
= aclmask(acl
, roleid
, BOOTSTRAP_SUPERUSERID
, mask
, how
);
3555 /* if we have a detoasted copy, free it */
3556 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3559 ReleaseSysCache(tuple
);
3565 * Routine for examining a user's privileges for a largeobject
3567 * When a large object is opened for reading, it is opened relative to the
3568 * caller's snapshot, but when it is opened for writing, a current
3569 * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
3570 * takes a snapshot argument so that the permissions check can be made
3571 * relative to the same snapshot that will be used to read the underlying
3572 * data. The caller will actually pass NULL for an instantaneous MVCC
3573 * snapshot, since all we do with the snapshot argument is pass it through
3574 * to systable_beginscan().
3577 pg_largeobject_aclmask_snapshot(Oid lobj_oid
, Oid roleid
,
3578 AclMode mask
, AclMaskHow how
,
3582 Relation pg_lo_meta
;
3583 ScanKeyData entry
[1];
3591 /* Superusers bypass all permission checking. */
3592 if (superuser_arg(roleid
))
3596 * Get the largeobject's ACL from pg_largeobject_metadata
3598 pg_lo_meta
= table_open(LargeObjectMetadataRelationId
,
3601 ScanKeyInit(&entry
[0],
3602 Anum_pg_largeobject_metadata_oid
,
3603 BTEqualStrategyNumber
, F_OIDEQ
,
3604 ObjectIdGetDatum(lobj_oid
));
3606 scan
= systable_beginscan(pg_lo_meta
,
3607 LargeObjectMetadataOidIndexId
, true,
3608 snapshot
, 1, entry
);
3610 tuple
= systable_getnext(scan
);
3611 if (!HeapTupleIsValid(tuple
))
3613 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3614 errmsg("large object %u does not exist", lobj_oid
)));
3616 ownerId
= ((Form_pg_largeobject_metadata
) GETSTRUCT(tuple
))->lomowner
;
3618 aclDatum
= heap_getattr(tuple
, Anum_pg_largeobject_metadata_lomacl
,
3619 RelationGetDescr(pg_lo_meta
), &isNull
);
3623 /* No ACL, so build default ACL */
3624 acl
= acldefault(OBJECT_LARGEOBJECT
, ownerId
);
3625 aclDatum
= (Datum
) 0;
3629 /* detoast ACL if necessary */
3630 acl
= DatumGetAclP(aclDatum
);
3633 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
3635 /* if we have a detoasted copy, free it */
3636 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3639 systable_endscan(scan
);
3641 table_close(pg_lo_meta
, AccessShareLock
);
3647 * Routine for examining a user's privileges for a namespace, with is_missing
3650 pg_namespace_aclmask_ext(Oid nsp_oid
, Oid roleid
,
3651 AclMode mask
, AclMaskHow how
,
3661 /* Superusers bypass all permission checking. */
3662 if (superuser_arg(roleid
))
3666 * If we have been assigned this namespace as a temp namespace, check to
3667 * make sure we have CREATE TEMP permission on the database, and if so act
3668 * as though we have all standard (but not GRANT OPTION) permissions on
3669 * the namespace. If we don't have CREATE TEMP, act as though we have
3670 * only USAGE (and not CREATE) rights.
3672 * This may seem redundant given the check in InitTempTableNamespace, but
3673 * it really isn't since current user ID may have changed since then. The
3674 * upshot of this behavior is that a SECURITY DEFINER function can create
3675 * temp tables that can then be accessed (if permission is granted) by
3676 * code in the same session that doesn't have permissions to create temp
3679 * XXX Would it be safe to ereport a special error message as
3680 * InitTempTableNamespace does? Returning zero here means we'll get a
3681 * generic "permission denied for schema pg_temp_N" message, which is not
3682 * remarkably user-friendly.
3684 if (isTempNamespace(nsp_oid
))
3686 if (object_aclcheck_ext(DatabaseRelationId
, MyDatabaseId
, roleid
,
3687 ACL_CREATE_TEMP
, is_missing
) == ACLCHECK_OK
)
3688 return mask
& ACL_ALL_RIGHTS_SCHEMA
;
3690 return mask
& ACL_USAGE
;
3694 * Get the schema's ACL from pg_namespace
3696 tuple
= SearchSysCache1(NAMESPACEOID
, ObjectIdGetDatum(nsp_oid
));
3697 if (!HeapTupleIsValid(tuple
))
3699 if (is_missing
!= NULL
)
3701 /* return "no privileges" instead of throwing an error */
3707 (errcode(ERRCODE_UNDEFINED_SCHEMA
),
3708 errmsg("schema with OID %u does not exist", nsp_oid
)));
3711 ownerId
= ((Form_pg_namespace
) GETSTRUCT(tuple
))->nspowner
;
3713 aclDatum
= SysCacheGetAttr(NAMESPACEOID
, tuple
, Anum_pg_namespace_nspacl
,
3717 /* No ACL, so build default ACL */
3718 acl
= acldefault(OBJECT_SCHEMA
, ownerId
);
3719 aclDatum
= (Datum
) 0;
3723 /* detoast ACL if necessary */
3724 acl
= DatumGetAclP(aclDatum
);
3727 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
3729 /* if we have a detoasted copy, free it */
3730 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3733 ReleaseSysCache(tuple
);
3736 * Check if ACL_USAGE is being checked and, if so, and not set already as
3737 * part of the result, then check if the user is a member of the
3738 * pg_read_all_data or pg_write_all_data roles, which allow usage access
3741 if (mask
& ACL_USAGE
&& !(result
& ACL_USAGE
) &&
3742 (has_privs_of_role(roleid
, ROLE_PG_READ_ALL_DATA
) ||
3743 has_privs_of_role(roleid
, ROLE_PG_WRITE_ALL_DATA
)))
3744 result
|= ACL_USAGE
;
3749 * Routine for examining a user's privileges for a type, with is_missing
3752 pg_type_aclmask_ext(Oid type_oid
, Oid roleid
, AclMode mask
, AclMaskHow how
,
3757 Form_pg_type typeForm
;
3763 /* Bypass permission checks for superusers */
3764 if (superuser_arg(roleid
))
3768 * Must get the type's tuple from pg_type
3770 tuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(type_oid
));
3771 if (!HeapTupleIsValid(tuple
))
3773 if (is_missing
!= NULL
)
3775 /* return "no privileges" instead of throwing an error */
3781 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3782 errmsg("type with OID %u does not exist",
3785 typeForm
= (Form_pg_type
) GETSTRUCT(tuple
);
3788 * "True" array types don't manage permissions of their own; consult the
3789 * element type instead.
3791 if (IsTrueArrayType(typeForm
))
3793 Oid elttype_oid
= typeForm
->typelem
;
3795 ReleaseSysCache(tuple
);
3797 tuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(elttype_oid
));
3798 if (!HeapTupleIsValid(tuple
))
3800 if (is_missing
!= NULL
)
3802 /* return "no privileges" instead of throwing an error */
3808 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3809 errmsg("type with OID %u does not exist",
3812 typeForm
= (Form_pg_type
) GETSTRUCT(tuple
);
3816 * Likewise, multirange types don't manage their own permissions; consult
3817 * the associated range type. (Note we must do this after the array step
3818 * to get the right answer for arrays of multiranges.)
3820 if (typeForm
->typtype
== TYPTYPE_MULTIRANGE
)
3822 Oid rangetype
= get_multirange_range(typeForm
->oid
);
3824 ReleaseSysCache(tuple
);
3826 tuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(rangetype
));
3827 if (!HeapTupleIsValid(tuple
))
3829 if (is_missing
!= NULL
)
3831 /* return "no privileges" instead of throwing an error */
3837 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3838 errmsg("type with OID %u does not exist",
3841 typeForm
= (Form_pg_type
) GETSTRUCT(tuple
);
3845 * Now get the type's owner and ACL from the tuple
3847 ownerId
= typeForm
->typowner
;
3849 aclDatum
= SysCacheGetAttr(TYPEOID
, tuple
,
3850 Anum_pg_type_typacl
, &isNull
);
3853 /* No ACL, so build default ACL */
3854 acl
= acldefault(OBJECT_TYPE
, ownerId
);
3855 aclDatum
= (Datum
) 0;
3859 /* detoast rel's ACL if necessary */
3860 acl
= DatumGetAclP(aclDatum
);
3863 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
3865 /* if we have a detoasted copy, free it */
3866 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3869 ReleaseSysCache(tuple
);
3875 * Exported generic routine for checking a user's access privileges to an object
3878 object_aclcheck(Oid classid
, Oid objectid
, Oid roleid
, AclMode mode
)
3880 return object_aclcheck_ext(classid
, objectid
, roleid
, mode
, NULL
);
3884 * Exported generic routine for checking a user's access privileges to an
3885 * object, with is_missing
3888 object_aclcheck_ext(Oid classid
, Oid objectid
,
3889 Oid roleid
, AclMode mode
,
3892 if (object_aclmask_ext(classid
, objectid
, roleid
, mode
, ACLMASK_ANY
,
3896 return ACLCHECK_NO_PRIV
;
3900 * Exported routine for checking a user's access privileges to a column
3902 * Returns ACLCHECK_OK if the user has any of the privileges identified by
3903 * 'mode'; otherwise returns a suitable error code (in practice, always
3904 * ACLCHECK_NO_PRIV).
3906 * As with pg_attribute_aclmask, only privileges granted directly on the
3907 * column are considered here.
3910 pg_attribute_aclcheck(Oid table_oid
, AttrNumber attnum
,
3911 Oid roleid
, AclMode mode
)
3913 return pg_attribute_aclcheck_ext(table_oid
, attnum
, roleid
, mode
, NULL
);
3918 * Exported routine for checking a user's access privileges to a column,
3922 pg_attribute_aclcheck_ext(Oid table_oid
, AttrNumber attnum
,
3923 Oid roleid
, AclMode mode
, bool *is_missing
)
3925 if (pg_attribute_aclmask_ext(table_oid
, attnum
, roleid
, mode
,
3926 ACLMASK_ANY
, is_missing
) != 0)
3929 return ACLCHECK_NO_PRIV
;
3933 * Exported routine for checking a user's access privileges to any/all columns
3935 * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
3936 * privileges identified by 'mode' on any non-dropped column in the relation;
3937 * otherwise returns a suitable error code (in practice, always
3938 * ACLCHECK_NO_PRIV).
3940 * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
3941 * privileges identified by 'mode' on each non-dropped column in the relation
3942 * (and there must be at least one such column); otherwise returns a suitable
3943 * error code (in practice, always ACLCHECK_NO_PRIV).
3945 * As with pg_attribute_aclmask, only privileges granted directly on the
3946 * column(s) are considered here.
3948 * Note: system columns are not considered here; there are cases where that
3949 * might be appropriate but there are also cases where it wouldn't.
3952 pg_attribute_aclcheck_all(Oid table_oid
, Oid roleid
, AclMode mode
,
3955 return pg_attribute_aclcheck_all_ext(table_oid
, roleid
, mode
, how
, NULL
);
3959 * Exported routine for checking a user's access privileges to any/all columns,
3963 pg_attribute_aclcheck_all_ext(Oid table_oid
, Oid roleid
,
3964 AclMode mode
, AclMaskHow how
,
3968 HeapTuple classTuple
;
3969 Form_pg_class classForm
;
3972 AttrNumber curr_att
;
3975 * Must fetch pg_class row to get owner ID and number of attributes.
3977 classTuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(table_oid
));
3978 if (!HeapTupleIsValid(classTuple
))
3980 if (is_missing
!= NULL
)
3982 /* return "no privileges" instead of throwing an error */
3984 return ACLCHECK_NO_PRIV
;
3988 (errcode(ERRCODE_UNDEFINED_TABLE
),
3989 errmsg("relation with OID %u does not exist",
3992 classForm
= (Form_pg_class
) GETSTRUCT(classTuple
);
3994 ownerId
= classForm
->relowner
;
3995 nattrs
= classForm
->relnatts
;
3997 ReleaseSysCache(classTuple
);
4000 * Initialize result in case there are no non-dropped columns. We want to
4001 * report failure in such cases for either value of 'how'.
4003 result
= ACLCHECK_NO_PRIV
;
4005 for (curr_att
= 1; curr_att
<= nattrs
; curr_att
++)
4013 attTuple
= SearchSysCache2(ATTNUM
,
4014 ObjectIdGetDatum(table_oid
),
4015 Int16GetDatum(curr_att
));
4018 * Lookup failure probably indicates that the table was just dropped,
4019 * but we'll treat it the same as a dropped column rather than
4022 if (!HeapTupleIsValid(attTuple
))
4025 /* ignore dropped columns */
4026 if (((Form_pg_attribute
) GETSTRUCT(attTuple
))->attisdropped
)
4028 ReleaseSysCache(attTuple
);
4032 aclDatum
= SysCacheGetAttr(ATTNUM
, attTuple
, Anum_pg_attribute_attacl
,
4036 * Here we hard-wire knowledge that the default ACL for a column
4037 * grants no privileges, so that we can fall out quickly in the very
4038 * common case where attacl is null.
4044 /* detoast column's ACL if necessary */
4045 acl
= DatumGetAclP(aclDatum
);
4047 attmask
= aclmask(acl
, roleid
, ownerId
, mode
, ACLMASK_ANY
);
4049 /* if we have a detoasted copy, free it */
4050 if ((Pointer
) acl
!= DatumGetPointer(aclDatum
))
4054 ReleaseSysCache(attTuple
);
4058 result
= ACLCHECK_OK
;
4059 if (how
== ACLMASK_ANY
)
4060 break; /* succeed on any success */
4064 result
= ACLCHECK_NO_PRIV
;
4065 if (how
== ACLMASK_ALL
)
4066 break; /* fail on any failure */
4074 * Exported routine for checking a user's access privileges to a table
4076 * Returns ACLCHECK_OK if the user has any of the privileges identified by
4077 * 'mode'; otherwise returns a suitable error code (in practice, always
4078 * ACLCHECK_NO_PRIV).
4081 pg_class_aclcheck(Oid table_oid
, Oid roleid
, AclMode mode
)
4083 return pg_class_aclcheck_ext(table_oid
, roleid
, mode
, NULL
);
4087 * Exported routine for checking a user's access privileges to a table,
4091 pg_class_aclcheck_ext(Oid table_oid
, Oid roleid
,
4092 AclMode mode
, bool *is_missing
)
4094 if (pg_class_aclmask_ext(table_oid
, roleid
, mode
,
4095 ACLMASK_ANY
, is_missing
) != 0)
4098 return ACLCHECK_NO_PRIV
;
4102 * Exported routine for checking a user's access privileges to a configuration
4103 * parameter (GUC), identified by GUC name.
4106 pg_parameter_aclcheck(const char *name
, Oid roleid
, AclMode mode
)
4108 if (pg_parameter_aclmask(name
, roleid
, mode
, ACLMASK_ANY
) != 0)
4111 return ACLCHECK_NO_PRIV
;
4115 * Exported routine for checking a user's access privileges to a largeobject
4118 pg_largeobject_aclcheck_snapshot(Oid lobj_oid
, Oid roleid
, AclMode mode
,
4121 if (pg_largeobject_aclmask_snapshot(lobj_oid
, roleid
, mode
,
4122 ACLMASK_ANY
, snapshot
) != 0)
4125 return ACLCHECK_NO_PRIV
;
4129 * Generic ownership check for an object
4132 object_ownercheck(Oid classid
, Oid objectid
, Oid roleid
)
4137 /* Superusers bypass all permission checking. */
4138 if (superuser_arg(roleid
))
4141 /* For large objects, the catalog to consult is pg_largeobject_metadata */
4142 if (classid
== LargeObjectRelationId
)
4143 classid
= LargeObjectMetadataRelationId
;
4145 cacheid
= get_object_catcache_oid(classid
);
4148 /* we can get the object's tuple from the syscache */
4151 tuple
= SearchSysCache1(cacheid
, ObjectIdGetDatum(objectid
));
4152 if (!HeapTupleIsValid(tuple
))
4154 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4155 errmsg("%s with OID %u does not exist", get_object_class_descr(classid
), objectid
)));
4157 ownerId
= DatumGetObjectId(SysCacheGetAttrNotNull(cacheid
,
4159 get_object_attnum_owner(classid
)));
4160 ReleaseSysCache(tuple
);
4164 /* for catalogs without an appropriate syscache */
4166 ScanKeyData entry
[1];
4171 rel
= table_open(classid
, AccessShareLock
);
4173 ScanKeyInit(&entry
[0],
4174 get_object_attnum_oid(classid
),
4175 BTEqualStrategyNumber
, F_OIDEQ
,
4176 ObjectIdGetDatum(objectid
));
4178 scan
= systable_beginscan(rel
,
4179 get_object_oid_index(classid
), true,
4182 tuple
= systable_getnext(scan
);
4183 if (!HeapTupleIsValid(tuple
))
4185 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4186 errmsg("%s with OID %u does not exist", get_object_class_descr(classid
), objectid
)));
4188 ownerId
= DatumGetObjectId(heap_getattr(tuple
,
4189 get_object_attnum_owner(classid
),
4190 RelationGetDescr(rel
),
4194 systable_endscan(scan
);
4195 table_close(rel
, AccessShareLock
);
4198 return has_privs_of_role(roleid
, ownerId
);
4202 * Check whether specified role has CREATEROLE privilege (or is a superuser)
4204 * Note: roles do not have owners per se; instead we use this test in
4205 * places where an ownership-like permissions test is needed for a role.
4206 * Be sure to apply it to the role trying to do the operation, not the
4207 * role being operated on! Also note that this generally should not be
4208 * considered enough privilege if the target role is a superuser.
4209 * (We don't handle that consideration here because we want to give a
4210 * separate error message for such cases, so the caller has to deal with it.)
4213 has_createrole_privilege(Oid roleid
)
4215 bool result
= false;
4218 /* Superusers bypass all permission checking. */
4219 if (superuser_arg(roleid
))
4222 utup
= SearchSysCache1(AUTHOID
, ObjectIdGetDatum(roleid
));
4223 if (HeapTupleIsValid(utup
))
4225 result
= ((Form_pg_authid
) GETSTRUCT(utup
))->rolcreaterole
;
4226 ReleaseSysCache(utup
);
4232 has_bypassrls_privilege(Oid roleid
)
4234 bool result
= false;
4237 /* Superusers bypass all permission checking. */
4238 if (superuser_arg(roleid
))
4241 utup
= SearchSysCache1(AUTHOID
, ObjectIdGetDatum(roleid
));
4242 if (HeapTupleIsValid(utup
))
4244 result
= ((Form_pg_authid
) GETSTRUCT(utup
))->rolbypassrls
;
4245 ReleaseSysCache(utup
);
4251 * Fetch pg_default_acl entry for given role, namespace and object type
4252 * (object type must be given in pg_default_acl's encoding).
4253 * Returns NULL if no such entry.
4256 get_default_acl_internal(Oid roleId
, Oid nsp_oid
, char objtype
)
4261 tuple
= SearchSysCache3(DEFACLROLENSPOBJ
,
4262 ObjectIdGetDatum(roleId
),
4263 ObjectIdGetDatum(nsp_oid
),
4264 CharGetDatum(objtype
));
4266 if (HeapTupleIsValid(tuple
))
4271 aclDatum
= SysCacheGetAttr(DEFACLROLENSPOBJ
, tuple
,
4272 Anum_pg_default_acl_defaclacl
,
4275 result
= DatumGetAclPCopy(aclDatum
);
4276 ReleaseSysCache(tuple
);
4283 * Get default permissions for newly created object within given schema
4285 * Returns NULL if built-in system defaults should be used.
4287 * If the result is not NULL, caller must call recordDependencyOnNewAcl
4288 * once the OID of the new object is known.
4291 get_user_default_acl(ObjectType objtype
, Oid ownerId
, Oid nsp_oid
)
4300 * Use NULL during bootstrap, since pg_default_acl probably isn't there
4303 if (IsBootstrapProcessingMode())
4306 /* Check if object type is supported in pg_default_acl */
4310 defaclobjtype
= DEFACLOBJ_RELATION
;
4313 case OBJECT_SEQUENCE
:
4314 defaclobjtype
= DEFACLOBJ_SEQUENCE
;
4317 case OBJECT_FUNCTION
:
4318 defaclobjtype
= DEFACLOBJ_FUNCTION
;
4322 defaclobjtype
= DEFACLOBJ_TYPE
;
4326 defaclobjtype
= DEFACLOBJ_NAMESPACE
;
4333 /* Look up the relevant pg_default_acl entries */
4334 glob_acl
= get_default_acl_internal(ownerId
, InvalidOid
, defaclobjtype
);
4335 schema_acl
= get_default_acl_internal(ownerId
, nsp_oid
, defaclobjtype
);
4337 /* Quick out if neither entry exists */
4338 if (glob_acl
== NULL
&& schema_acl
== NULL
)
4341 /* We need to know the hard-wired default value, too */
4342 def_acl
= acldefault(objtype
, ownerId
);
4344 /* If there's no global entry, substitute the hard-wired default */
4345 if (glob_acl
== NULL
)
4348 /* Merge in any per-schema privileges */
4349 result
= aclmerge(glob_acl
, schema_acl
, ownerId
);
4352 * For efficiency, we want to return NULL if the result equals default.
4353 * This requires sorting both arrays to get an accurate comparison.
4355 aclitemsort(result
);
4356 aclitemsort(def_acl
);
4357 if (aclequal(result
, def_acl
))
4364 * Record dependencies on roles mentioned in a new object's ACL.
4367 recordDependencyOnNewAcl(Oid classId
, Oid objectId
, int32 objsubId
,
4368 Oid ownerId
, Acl
*acl
)
4373 /* Nothing to do if ACL is defaulted */
4377 /* Extract roles mentioned in ACL */
4378 nmembers
= aclmembers(acl
, &members
);
4380 /* Update the shared dependency ACL info */
4381 updateAclDependencies(classId
, objectId
, objsubId
,
4388 * Record initial privileges for the top-level object passed in.
4390 * For the object passed in, this will record its ACL (if any) and the ACLs of
4391 * any sub-objects (eg: columns) into pg_init_privs.
4394 recordExtObjInitPriv(Oid objoid
, Oid classoid
)
4397 * pg_class / pg_attribute
4399 * If this is a relation then we need to see if there are any sub-objects
4400 * (eg: columns) for it and, if so, be sure to call
4401 * recordExtensionInitPrivWorker() for each one.
4403 if (classoid
== RelationRelationId
)
4405 Form_pg_class pg_class_tuple
;
4410 tuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(objoid
));
4411 if (!HeapTupleIsValid(tuple
))
4412 elog(ERROR
, "cache lookup failed for relation %u", objoid
);
4413 pg_class_tuple
= (Form_pg_class
) GETSTRUCT(tuple
);
4416 * Indexes don't have permissions, neither do the pg_class rows for
4417 * composite types. (These cases are unreachable given the
4418 * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
4420 if (pg_class_tuple
->relkind
== RELKIND_INDEX
||
4421 pg_class_tuple
->relkind
== RELKIND_PARTITIONED_INDEX
||
4422 pg_class_tuple
->relkind
== RELKIND_COMPOSITE_TYPE
)
4424 ReleaseSysCache(tuple
);
4429 * If this isn't a sequence then it's possibly going to have
4430 * column-level ACLs associated with it.
4432 if (pg_class_tuple
->relkind
!= RELKIND_SEQUENCE
)
4434 AttrNumber curr_att
;
4435 AttrNumber nattrs
= pg_class_tuple
->relnatts
;
4437 for (curr_att
= 1; curr_att
<= nattrs
; curr_att
++)
4442 attTuple
= SearchSysCache2(ATTNUM
,
4443 ObjectIdGetDatum(objoid
),
4444 Int16GetDatum(curr_att
));
4446 if (!HeapTupleIsValid(attTuple
))
4449 /* ignore dropped columns */
4450 if (((Form_pg_attribute
) GETSTRUCT(attTuple
))->attisdropped
)
4452 ReleaseSysCache(attTuple
);
4456 attaclDatum
= SysCacheGetAttr(ATTNUM
, attTuple
,
4457 Anum_pg_attribute_attacl
,
4460 /* no need to do anything for a NULL ACL */
4463 ReleaseSysCache(attTuple
);
4467 recordExtensionInitPrivWorker(objoid
, classoid
, curr_att
,
4468 DatumGetAclP(attaclDatum
));
4470 ReleaseSysCache(attTuple
);
4474 aclDatum
= SysCacheGetAttr(RELOID
, tuple
, Anum_pg_class_relacl
,
4477 /* Add the record, if any, for the top-level object */
4479 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
4480 DatumGetAclP(aclDatum
));
4482 ReleaseSysCache(tuple
);
4484 else if (classoid
== LargeObjectRelationId
)
4486 /* For large objects, we must consult pg_largeobject_metadata */
4490 ScanKeyData entry
[1];
4495 * Note: this is dead code, given that we don't allow large objects to
4496 * be made extension members. But it seems worth carrying in case
4497 * some future caller of this function has need for it.
4499 relation
= table_open(LargeObjectMetadataRelationId
, RowExclusiveLock
);
4501 /* There's no syscache for pg_largeobject_metadata */
4502 ScanKeyInit(&entry
[0],
4503 Anum_pg_largeobject_metadata_oid
,
4504 BTEqualStrategyNumber
, F_OIDEQ
,
4505 ObjectIdGetDatum(objoid
));
4507 scan
= systable_beginscan(relation
,
4508 LargeObjectMetadataOidIndexId
, true,
4511 tuple
= systable_getnext(scan
);
4512 if (!HeapTupleIsValid(tuple
))
4513 elog(ERROR
, "could not find tuple for large object %u", objoid
);
4515 aclDatum
= heap_getattr(tuple
,
4516 Anum_pg_largeobject_metadata_lomacl
,
4517 RelationGetDescr(relation
), &isNull
);
4519 /* Add the record, if any, for the top-level object */
4521 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
4522 DatumGetAclP(aclDatum
));
4524 systable_endscan(scan
);
4526 /* This will error on unsupported classoid. */
4527 else if (get_object_attnum_acl(classoid
) != InvalidAttrNumber
)
4533 tuple
= SearchSysCache1(get_object_catcache_oid(classoid
),
4534 ObjectIdGetDatum(objoid
));
4535 if (!HeapTupleIsValid(tuple
))
4536 elog(ERROR
, "cache lookup failed for %s %u",
4537 get_object_class_descr(classoid
), objoid
);
4539 aclDatum
= SysCacheGetAttr(get_object_catcache_oid(classoid
), tuple
,
4540 get_object_attnum_acl(classoid
),
4543 /* Add the record, if any, for the top-level object */
4545 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
4546 DatumGetAclP(aclDatum
));
4548 ReleaseSysCache(tuple
);
4553 * For the object passed in, remove its ACL and the ACLs of any object subIds
4554 * from pg_init_privs (via recordExtensionInitPrivWorker()).
4557 removeExtObjInitPriv(Oid objoid
, Oid classoid
)
4560 * If this is a relation then we need to see if there are any sub-objects
4561 * (eg: columns) for it and, if so, be sure to call
4562 * recordExtensionInitPrivWorker() for each one.
4564 if (classoid
== RelationRelationId
)
4566 Form_pg_class pg_class_tuple
;
4569 tuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(objoid
));
4570 if (!HeapTupleIsValid(tuple
))
4571 elog(ERROR
, "cache lookup failed for relation %u", objoid
);
4572 pg_class_tuple
= (Form_pg_class
) GETSTRUCT(tuple
);
4575 * Indexes don't have permissions, neither do the pg_class rows for
4576 * composite types. (These cases are unreachable given the
4577 * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
4579 if (pg_class_tuple
->relkind
== RELKIND_INDEX
||
4580 pg_class_tuple
->relkind
== RELKIND_PARTITIONED_INDEX
||
4581 pg_class_tuple
->relkind
== RELKIND_COMPOSITE_TYPE
)
4583 ReleaseSysCache(tuple
);
4588 * If this isn't a sequence then it's possibly going to have
4589 * column-level ACLs associated with it.
4591 if (pg_class_tuple
->relkind
!= RELKIND_SEQUENCE
)
4593 AttrNumber curr_att
;
4594 AttrNumber nattrs
= pg_class_tuple
->relnatts
;
4596 for (curr_att
= 1; curr_att
<= nattrs
; curr_att
++)
4600 attTuple
= SearchSysCache2(ATTNUM
,
4601 ObjectIdGetDatum(objoid
),
4602 Int16GetDatum(curr_att
));
4604 if (!HeapTupleIsValid(attTuple
))
4607 /* when removing, remove all entries, even dropped columns */
4609 recordExtensionInitPrivWorker(objoid
, classoid
, curr_att
, NULL
);
4611 ReleaseSysCache(attTuple
);
4615 ReleaseSysCache(tuple
);
4618 /* Remove the record, if any, for the top-level object */
4619 recordExtensionInitPrivWorker(objoid
, classoid
, 0, NULL
);
4623 * Record initial ACL for an extension object
4625 * Can be called at any time, we check if 'creating_extension' is set and, if
4626 * not, exit immediately.
4628 * Pass in the object OID, the OID of the class (the OID of the table which
4629 * the object is defined in) and the 'sub' id of the object (objsubid), if
4630 * any. If there is no 'sub' id (they are currently only used for columns of
4631 * tables) then pass in '0'. Finally, pass in the complete ACL to store.
4633 * If an ACL already exists for this object/sub-object then we will replace
4634 * it with what is passed in.
4636 * Passing in NULL for 'new_acl' will result in the entry for the object being
4637 * removed, if one is found.
4640 recordExtensionInitPriv(Oid objoid
, Oid classoid
, int objsubid
, Acl
*new_acl
)
4643 * Generally, we only record the initial privileges when an extension is
4644 * being created, but because we don't actually use CREATE EXTENSION
4645 * during binary upgrades with pg_upgrade, there is a variable to let us
4646 * know that the GRANT and REVOKE statements being issued, while this
4647 * variable is true, are for the initial privileges of the extension
4648 * object and therefore we need to record them.
4650 if (!creating_extension
&& !binary_upgrade_record_init_privs
)
4653 recordExtensionInitPrivWorker(objoid
, classoid
, objsubid
, new_acl
);
4657 * Record initial ACL for an extension object, worker.
4659 * This will perform a wholesale replacement of the entire ACL for the object
4660 * passed in, therefore be sure to pass in the complete new ACL to use.
4662 * Generally speaking, do *not* use this function directly but instead use
4663 * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
4664 * This function does *not* check if 'creating_extension' is set as it is also
4665 * used when an object is added to or removed from an extension via ALTER
4666 * EXTENSION ... ADD/DROP.
4669 recordExtensionInitPrivWorker(Oid objoid
, Oid classoid
, int objsubid
, Acl
*new_acl
)
4677 relation
= table_open(InitPrivsRelationId
, RowExclusiveLock
);
4679 ScanKeyInit(&key
[0],
4680 Anum_pg_init_privs_objoid
,
4681 BTEqualStrategyNumber
, F_OIDEQ
,
4682 ObjectIdGetDatum(objoid
));
4683 ScanKeyInit(&key
[1],
4684 Anum_pg_init_privs_classoid
,
4685 BTEqualStrategyNumber
, F_OIDEQ
,
4686 ObjectIdGetDatum(classoid
));
4687 ScanKeyInit(&key
[2],
4688 Anum_pg_init_privs_objsubid
,
4689 BTEqualStrategyNumber
, F_INT4EQ
,
4690 Int32GetDatum(objsubid
));
4692 scan
= systable_beginscan(relation
, InitPrivsObjIndexId
, true,
4695 /* There should exist only one entry or none. */
4696 oldtuple
= systable_getnext(scan
);
4698 /* If we find an entry, update it with the latest ACL. */
4699 if (HeapTupleIsValid(oldtuple
))
4701 Datum values
[Natts_pg_init_privs
] = {0};
4702 bool nulls
[Natts_pg_init_privs
] = {0};
4703 bool replace
[Natts_pg_init_privs
] = {0};
4705 /* If we have a new ACL to set, then update the row with it. */
4708 values
[Anum_pg_init_privs_initprivs
- 1] = PointerGetDatum(new_acl
);
4709 replace
[Anum_pg_init_privs_initprivs
- 1] = true;
4711 oldtuple
= heap_modify_tuple(oldtuple
, RelationGetDescr(relation
),
4712 values
, nulls
, replace
);
4714 CatalogTupleUpdate(relation
, &oldtuple
->t_self
, oldtuple
);
4718 /* new_acl is NULL, so delete the entry we found. */
4719 CatalogTupleDelete(relation
, &oldtuple
->t_self
);
4724 Datum values
[Natts_pg_init_privs
] = {0};
4725 bool nulls
[Natts_pg_init_privs
] = {0};
4728 * Only add a new entry if the new ACL is non-NULL.
4730 * If we are passed in a NULL ACL and no entry exists, we can just
4731 * fall through and do nothing.
4735 /* No entry found, so add it. */
4736 values
[Anum_pg_init_privs_objoid
- 1] = ObjectIdGetDatum(objoid
);
4737 values
[Anum_pg_init_privs_classoid
- 1] = ObjectIdGetDatum(classoid
);
4738 values
[Anum_pg_init_privs_objsubid
- 1] = Int32GetDatum(objsubid
);
4740 /* This function only handles initial privileges of extensions */
4741 values
[Anum_pg_init_privs_privtype
- 1] =
4742 CharGetDatum(INITPRIVS_EXTENSION
);
4744 values
[Anum_pg_init_privs_initprivs
- 1] = PointerGetDatum(new_acl
);
4746 tuple
= heap_form_tuple(RelationGetDescr(relation
), values
, nulls
);
4748 CatalogTupleInsert(relation
, tuple
);
4752 systable_endscan(scan
);
4754 /* prevent error when processing objects multiple times */
4755 CommandCounterIncrement();
4757 table_close(relation
, RowExclusiveLock
);